2 Commits

Author SHA1 Message Date
Jakub Zych
e562bf6f5b fix(08-10): correct check-phase8-mcp-client.mjs's connected-apps field name and revoke ordering
Two real defects surfaced by the gate's first live run against the real
fonoteka-mcp SDK:

- stage_revoke looked up the connected app by a.name; ConnectedAppsIndex
  actually serializes client_name (confirmed against
  controllers/api/connected_app_controller.go serializeConnectedApp).
- Even with that fixed, stage_revoke ran after stage_replay, by which
  point RevokeLineage's forward walk (presenting the pre-refresh spent
  secret) had already cascade-revoked the live post-refresh access token
  too -- correct, intentional T-08-REFRESH-REPLAY behavior, and the exact
  same effect 08-09-PLAN.md's own mcp-lifecycle fixture ordering already
  documented ('connected-apps would already be empty if list ran after
  replay'). stage_refresh now captures the connected-app id while the
  session is still live; stage_revoke DELETEs that id directly instead of
  re-listing (ConnectedAppsDestroy has no revoked_at filter on its own
  lookup, so this still exercises the real endpoint, idempotently, against
  the id the real MCP-driven session actually owned).
2026-09-24 00:51:28 +02:00
Jakub Zych
e87346f9e3 feat(08-09): complete the fail-closed Phase 8 final unchanged-MCP gate
Fills in every scripts/check-phase8.sh stage skeleton with real logic:
disposable Postgres (docker run + pg_isready), the assembled Go app built
and served against it with a throwaway onboarding-seeded gate account,
the real unchanged fonoteka-mcp process started with all three required
environment variables, and the full scripted SDK lifecycle -- discovery
(MCP's own RFC 9728 401 hint, verified separately from authorization
server metadata), DCR, PKCE authorize, JWT login/consent, token, an MCP
tool call, refresh, replay of the spent refresh token, revoke, and a
post-revoke refresh failure -- delegated to the new
scripts/check-phase8-mcp-client.mjs driver, which resolves the MCP SDK's
auth helpers from fonoteka-mcp's own node_modules (no new dependency,
same pattern as parity/capture_clients.mjs). Both repositories'
vet/test/race, the full parity/corpus/secret-scan gate, the existing
check-phase8-ui.mjs --final-gate UI harness, an unchanged-client git-diff
check for both MCP_ROOT and NUXT_ROOT, and a 08-SECURITY-REVIEW.md
status:verified gate close out the stage list.

--contract-self-test validates structure only (stage names/order,
cleanup trap, loopback-only binding, the three MCP env vars, the
redaction helper, no pre-final full-run flag, read-only unchanged-client
references) in well under 30 seconds -- it boots no services. The
--red-contract self-test from Task 1 is preserved unchanged. run_full_gate
(the no-flag invocation) is 08-10 Task 3's sole execution site; 08-09
never invokes it.
2026-09-23 23:18:15 +02:00