Skip to content

Grant the trace-forward capability from an operator allowlist, not a self-declared role - #9

Open
sumerjohal wants to merge 1 commit into
mainfrom
fix/capability-from-allowlist
Open

sumerjohal wants to merge 1 commit into
mainfrom
fix/capability-from-allowlist

Conversation

@sumerjohal

Copy link
Copy Markdown
Contributor

What

generate_jwt wrote capabilities=["trace-forward"] into the hub token whenever role == "authority". role is a free-text field the user types at open registration (user_schemas.py l.20), so the capability was self-assigned.

The node still demands a verified grant or an authority credential (Gate B) before it discloses anything, so no data leaked on the role alone. But a permission anyone can give themselves is not a permission, and a reader of the token could not tell an accredited authority from a user who typed the word.

Change

  • New capabilities.py: capabilities come only from HUB_AUTHORITY_ACCOUNTS, a comma-separated allowlist of account emails set by the operator. Unset means no account carries the capability.
  • generate_jwt keeps its signature; the role argument is no longer consulted. role remains a descriptive field.
  • README env table and CHANGELOG updated.

Tests

First test suite in this repository, with a CI workflow.

  • test_generate_jwt_ignores_the_role_argument is the control: it calls generate_jwt(..., role="authority") exactly as the login routes do and requires no capabilities claim. It fails against the previous code.
  • test_the_capability_check_can_fire proves the same decode path sees a capability when one is present, so the control cannot pass vacuously.
  • Allowlist parsing: case, whitespace, empty, absent.

Run: python -m pytest tests -q (8 passed).

Operator action on deploy

Set HUB_AUTHORITY_ACCOUNTS to the accredited account emails, or no account will hold trace-forward after this merges. That is the intended default.

Review finding H1, agstack review of 2026-10-08.

Made with Cursor

…ot a self-declared role

generate_jwt wrote capabilities=["trace-forward"] whenever role == "authority",
and role is free text the user types at open registration (user_schemas.py).
The node still demanded a verified grant or authority credential before
disclosing anything, so nothing leaked on the role alone; but a permission
anyone can give themselves is not a permission.

Capabilities now come only from HUB_AUTHORITY_ACCOUNTS, a comma-separated
allowlist of account emails set by the operator. role stays a descriptive
field. generate_jwt keeps its signature; the role argument is not consulted.

tests/test_capabilities.py is the first suite in this repository;
test_generate_jwt_ignores_the_role_argument fails against the previous code.
A CI workflow runs the suite on push and pull request.

Review finding: agstack review H1 (geoid comparison markup, 2026-10-08).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant