Skip to content

docs(auth): document JWT-trust mode and complete validation gate - #6755

Open
jonpspri wants to merge 3 commits into
feat/5905-trust-mode-acceptance-suitefrom
docs/5906-trust-mode-docs-gate
Open

docs(auth): document JWT-trust mode and complete validation gate#6755
jonpspri wants to merge 3 commits into
feat/5905-trust-mode-acceptance-suitefrom
docs/5906-trust-mode-docs-gate

Conversation

@jonpspri

@jonpspri jonpspri commented Sep 10, 2026

Copy link
Copy Markdown
Collaborator

Completes Epic 2 (#5885): executable tests for every disabled-with-clear-error row of the feature-mode matrix, the trust-mode documentation sweep, and the validation gate in both modes.

Matrix coverage: 20 tests in tests/unit/mcpgateway/test_trust_mode_disabled_surfaces.py assert BOTH the status code and the exact message for all seven disabled rows (TDD: 17 red first). Only the token-catalog row had landed with #5904; this PR wires the rest, all gated on jwt_trust_mode="jwt-trust" (no default-mode change): password login/register/reset (401), SSO browser login (401), session refresh (401), user management (403, API and admin HTML), invitations and team membership writes (403 via LocalUserRecordRequiredError).

Docs: configuration.md (posture change, disabled surfaces, POST /admin/tokens/trust mint endpoint), rbac.md (trust-mode section), multitenancy.md (cross-tenant group mapping), oauth-design.md (dispatch rule, revocation guarantee, overage policy), AGENTS.md (+4 Security Invariants: dispatch rule; mandatory configured revocation claim, no sid-keyed revocation; admin-claim posture, missing -> non-admin; is_active loss handled at the IdP or blocklist — plus the normalize_token_teams pointer fixed to auth_context.py). .env.example verified complete, zero additions.

Gate (both modes green, JWT_TRUST_MODE=db and =jwt-trust):

  • make ruff interrogate pylint — clean; interrogate 100%; pylint 10.00/10
  • make test — 23401 passed, 879 skipped, 2 xfailed (each mode)
  • make coverage diff-cover — exit 0, fail-under=90 met (717 changed lines)
  • make detect-secrets-scan — exit 0

NOT-RUN-HERE (no live stack in this worktree; evidence captured, runs after merge in the maintainer environment): the docker prod stack bring-up (testing-up requires .env secrets) and make test-mcp-protocol-e2e test-mcp-rbac (all 40 self-skip: gateway not reachable). make test-protocol-compliance does not exist; dropped from the gate per plan.

Risk to existing users: none — every new guard is trust-mode-gated; default mode verified green in the full suite. Also includes docs/plans/security-refactor-jwt-userid-stack-report.md: the dated 25-PR stack report (PR, issue, description per row). Also includes : the dated 25-PR stack report (PR, issue, description per row).

Stack: B.14 of epic #5885 (base: #6753). Final PR of the 24-PR stack.

Closes #5906

@jonpspri
jonpspri added this pull request to stack #6729 September 10, 2026 05:20
@jonpspri
jonpspri marked this pull request as ready for review September 10, 2026 05:20
@jonpspri
jonpspri force-pushed the docs/5906-trust-mode-docs-gate branch from c4f9b93 to 1166227 Compare September 10, 2026 06:23
@jonpspri
jonpspri force-pushed the docs/5906-trust-mode-docs-gate branch from 1166227 to 1e1f3da Compare September 10, 2026 07:53
@jonpspri
jonpspri force-pushed the docs/5906-trust-mode-docs-gate branch 2 times, most recently from 2902cc6 to 1994d61 Compare September 10, 2026 14:20
@jonpspri
jonpspri removed this pull request from stack #6729 September 12, 2026 08:50
@jonpspri
jonpspri force-pushed the docs/5906-trust-mode-docs-gate branch from 1994d61 to b043411 Compare September 12, 2026 09:07
@jonpspri
jonpspri added this pull request to stack #6798 September 12, 2026 09:08
@jonpspri
jonpspri force-pushed the docs/5906-trust-mode-docs-gate branch 2 times, most recently from 2c48c8d to fdbe15b Compare September 12, 2026 09:48
@jonpspri
jonpspri force-pushed the docs/5906-trust-mode-docs-gate branch from fdbe15b to d67460b Compare September 12, 2026 09:52
@jonpspri
jonpspri force-pushed the docs/5906-trust-mode-docs-gate branch from d67460b to 47f4e58 Compare September 12, 2026 16:45
@jonpspri
jonpspri force-pushed the docs/5906-trust-mode-docs-gate branch from 47f4e58 to 682ed8d Compare September 12, 2026 17:20
@jonpspri
jonpspri force-pushed the docs/5906-trust-mode-docs-gate branch from 682ed8d to b431804 Compare September 12, 2026 17:35
@jonpspri
jonpspri force-pushed the docs/5906-trust-mode-docs-gate branch 2 times, most recently from a941d7d to bb99e68 Compare September 12, 2026 18:09
@jonpspri
jonpspri force-pushed the docs/5906-trust-mode-docs-gate branch 2 times, most recently from 688a427 to 42cb1df Compare September 12, 2026 18:52
@jonpspri
jonpspri force-pushed the docs/5906-trust-mode-docs-gate branch 2 times, most recently from 67cc058 to 6b61a6b Compare September 12, 2026 20:00
@jonpspri
jonpspri force-pushed the docs/5906-trust-mode-docs-gate branch from 6b61a6b to e7716d2 Compare September 12, 2026 20:26
@jonpspri
jonpspri force-pushed the docs/5906-trust-mode-docs-gate branch from e7716d2 to 5438258 Compare September 12, 2026 20:49
Extra scope beyond the docs sweep:

- Error-path wiring for the B.2 matrix disabled rows that B.3/B.12 did not
  cover: password login/register/reset (401), SSO browser login (401, at the
  browser callback; the cited service function stays live for the
  default-funnel provisioning path), session-token refresh (401), user
  management in the admin UI and admin API (403), invitations and team
  membership writes for trust-only principals (403 via the new
  LocalUserRecordRequiredError). tests/unit/mcpgateway/
  test_trust_mode_disabled_surfaces.py covers every disabled matrix row and
  asserts status plus message.
- Test-isolation fixes exposed by the two-mode gate: a conftest autouse
  fixture clears the correlation-id contextvar per test (a sync test leaked
  it into the worker root context and broke an A.9 audit lookup), a conftest
  autouse fixture pins jwt_trust_mode=db per test so the suite is hermetic
  when JWT_TRUST_MODE=jwt-trust is exported, test_jwt_trust_config
  test_defaults now removes the ambient JWT_TRUST_MODE it claimed to
  isolate, and the auth_cache key doctest asserts the mode segment against
  settings instead of a hard-coded db.
- Pylint false-positive fix (pre-existing, gate-blocking): inline
  not-callable disables on the two SQLAlchemy func.now() server defaults in
  the external_group_mappings model.
- .secrets.baseline regenerated by make detect-secrets-scan (line drift
  from the doc edits).

Signed-off-by: Jonathan Springer <jps@s390x.com>
@jonpspri
jonpspri force-pushed the docs/5906-trust-mode-docs-gate branch from 5438258 to 9a8e1c9 Compare September 12, 2026 21:11
…ontracts

- auth-token-dispatch.md: document the get_current_user() ingress
  dispatch (external-issuer bearers -> JWKS verifier in trust mode;
  definitive trust-root failure -> 401 fail-closed; non-trust-root ->
  internal funnel) and pin the 200/401/403/404 result semantics with
  the live e2e matrix and the re-pinned barrier test
- configuration.md: compose wiring (commented default-off flags),
  JWT_CLAIM_TEAMS groups-claim collision guard, full provider-setup
  pointer incl. TESTS_DNS_PASSTHROUGH_HOSTS for the Entra E2E suite
- multitenancy.md: dual-write (FK-safe) writer + dual-key reader
  contract; scope-exact cf_role resolution
- rbac.md: strict admin-claim parsing in trust mode
- oauth-design.md: ingress dispatch note in the JWT trust mode section

Signed-off-by: Jonathan Springer <jps@s390x.com>
- trusted_claims.py: drop the Role import left unused after role
  resolution moved to services/role_resolution.py
- role_resolution.py: mark cf_team_id with the repo-standard
  pylint unused-argument disable; it is a documented interface
  parameter (scope context), not dead code
- test_email_users_user_id_migration.py: re-pin DOWN_REVISION to
  5e211ec89cad, the parent bf2998718ea1 has had since the multi-head
  fix; the migration file was correct, the structural test pin was stale

Signed-off-by: Jonathan Springer <jps@s390x.com>
@jonpspri

Copy link
Copy Markdown
Collaborator Author

Requirement note (remediation) — docs and gates

Five doc pages now state the post-fix contracts: ingress dispatch, the 401/403/200/404 result table, dual-write writers, strict admin typing, and Compose wiring.

The six validation gates ran green on this PR: lint and docstring coverage 100%, full suite 23,561 passed, diff coverage 97%, live protocol and RBAC suites, and the secrets scan. The trust-mode live pass ran 7 of 7.

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.

Docs sweep + matrix error-path tests + Epic 2 validation gate

1 participant