fix(08): revise oauth plans after checker feedback
This commit is contained in:
@@ -18,7 +18,7 @@ must_haves:
|
||||
truths:
|
||||
- "D-13: All four raw OAuth routes and five JWT OAuth management routes replay their recorded PHP contracts against Go and count as ported only after passing."
|
||||
- "D-16: A clean recorded lifecycle proves DCR, authorize, consent, token, refresh, replay kill, list, revoke, post-revoke failure, deny, confidential Basic auth, and scope ceiling."
|
||||
- "D-14: The unchanged real fonoteka-mcp process completes discovery, DCR, PKCE, JWT consent, token bootstrap, an MCP tool call, and refresh against the Go backend."
|
||||
- "D-14: The final gate contains a fail-closed unchanged-real-MCP stage for discovery, DCR, PKCE, JWT consent, token bootstrap, tool call, refresh, replay, and revoke."
|
||||
- "D-15: Live vendor connects remain excluded; automated DCR-plus-PKCE evidence is the Phase 8 acceptance boundary."
|
||||
artifacts:
|
||||
- path: "../fonoteka.go/parity/oauth_flow_test.go"
|
||||
@@ -39,10 +39,10 @@ must_haves:
|
||||
---
|
||||
|
||||
<objective>
|
||||
Prove the completed server through recorded PHP parity and the unchanged real MCP client rather than only implementation-local tests.
|
||||
Prove the completed server through recorded PHP parity and assemble the fail-closed unchanged-real-MCP gate that Plan 08-10 executes once at final sign-off.
|
||||
|
||||
Purpose: Turn exact route bytes, lifecycle security semantics, protected-resource discovery ownership, and actual SDK compatibility into one repeatable acceptance gate.
|
||||
Output: Lifecycle fixture/capture policy, projected replay tests, nine ported manifest entries, and `scripts/check-phase8.sh`.
|
||||
Output: Lifecycle fixture/capture policy, projected replay tests, nine ported manifest entries, and a self-validating final `scripts/check-phase8.sh`.
|
||||
</objective>
|
||||
|
||||
## Phase Goal
|
||||
@@ -100,15 +100,15 @@ Unchanged MCP inputs:
|
||||
- The clean lifecycle flow is required and every terminal security action is asserted before routes can be marked ported.
|
||||
- The gate starts real Postgres, Go app, and unchanged Node MCP; it verifies MCP-owned protected-resource metadata and Bearer hint separately from backend-owned metadata and Basic invalid-client challenge.
|
||||
</behavior>
|
||||
<action>D-12: distinguish backend Basic/no-challenge responses from MCP RFC 9728 behavior. D-13: project `mcp-oauth` and `mcp-tools` by stable named step IDs. D-14: declare real Postgres/app/MCP stages with all three environment variables. D-15: keep live vendor connects excluded. D-16: require the full clean lifecycle. D-18: create compiling failing parity tests and a fail-closed gate skeleton before changing fixtures/status. Use `PHASE8_RED:parity-gate` and the shared RED verifier so shell/Go syntax, missing tests, setup failures, and unrelated failures cannot satisfy RED. Plan 08-10 alone adds the security-review validation stage after the review exists. Do not edit or patch MCP or Nuxt.</action>
|
||||
<action>D-12: distinguish backend Basic/no-challenge responses from MCP RFC 9728 behavior. D-13: project `mcp-oauth` and `mcp-tools` by stable named step IDs. D-14: declare real Postgres/app/MCP stages with all three environment variables. D-15: keep live vendor connects excluded. D-16: require the full clean lifecycle. D-18: create compiling `TestPhase8RedParityGate` and a fail-closed gate skeleton before changing fixtures/status. Validate the Go RED with exact package/test/sentinel under `go test -json`. Also add a shell-contract RED self-test whose only allowed failure is exit 86 plus exactly `PHASE8_STAGE:real-mcp:FAIL:PHASE8_RED:real-mcp-stage`; reject any other FAIL/ERROR/PANIC stage, extra sentinel, syntax failure, or zero stage. Plan 08-10 alone adds and executes the complete security-review/final gate. Do not edit or patch MCP or Nuxt.</action>
|
||||
<verify>
|
||||
<automated>scripts/check-phase8-red.sh parity-gate bash -lc "cd ../fonoteka.go && go test ./parity -run 'TestOAuthFlows' -count=1"</automated>
|
||||
<automated>scripts/check-phase8-red.sh go PHASE8_RED:parity-gate git.golem15.com/golem15/fonoteka/parity TestPhase8RedParityGate -- bash -lc "cd ../fonoteka.go && go test -json ./parity -run '^TestPhase8RedParityGate$' -count=1" && scripts/check-phase8-red.sh shell PHASE8_RED:real-mcp-stage real-mcp -- scripts/check-phase8.sh --red-contract real-mcp</automated>
|
||||
</verify>
|
||||
<acceptance_criteria>
|
||||
- `oauth_flow_test.go` names projections for `mcp-oauth`, `mcp-tools`, and the complete `mcp-lifecycle`, and missing expected steps fail.
|
||||
- `scripts/check-phase8.sh` uses `set -euo pipefail`, fail-closed dependency/Docker checks, cleanup traps, and all three MCP environment variables.
|
||||
- The gate distinguishes MCP RFC 9728 metadata/rich Bearer challenge from backend exact Basic invalid-client challenge and unchanged token-surface 401.
|
||||
- Tests/gate fail because the lifecycle fixture/status/evidence is not yet complete, not because of shell or Go syntax errors.
|
||||
- Go RED has no unexpected failing JSON action; shell RED has exactly one expected stage/sentinel and exit 86, with syntax/setup/extra-stage failures rejected.
|
||||
</acceptance_criteria>
|
||||
<done>The acceptance harness demands the exact recorded and real-client lifecycle before any route can be claimed ported.</done>
|
||||
</task>
|
||||
@@ -134,7 +134,7 @@ Unchanged MCP inputs:
|
||||
</behavior>
|
||||
<action>D-16: extend the existing capture script/rules and use the Phase 2 isolated-PHP process to record the locked lifecycle. Issue the confidential client through `fonoteka:oauth-client`; exercise scope ceiling truncation and invalid-scope redirect with `client_secret_basic`. Capture all secret-bearing values with explicit pkce/token/credential categories into the private store, confirm both vars files are 0600, and commit only symbolic variable references. Add full and projected replays through `newConfiguredTarget` with real Postgres. After each of the four raw and five JWT route subtests passes, change only those manifest entries to `status: ported`; keep honest corpus accounting.</action>
|
||||
<verify>
|
||||
<automated>cd ../fonoteka.go && go test ./parity -run 'TestOAuthFlows|TestParityCorpus|TestParityContract' -count=1</automated>
|
||||
<automated>(cd ../fonoteka.go && go test ./parity -run '^TestOAuthFlows$' -count=1)</automated>
|
||||
</verify>
|
||||
<acceptance_criteria>
|
||||
- `mcp-lifecycle.yaml` contains the locked sequence and placeholder references, not recoverable credential values.
|
||||
@@ -146,7 +146,7 @@ Unchanged MCP inputs:
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 3: Complete the real unchanged-MCP phase gate</name>
|
||||
<name>Task 3: Complete and self-validate the final unchanged-MCP gate</name>
|
||||
<files>scripts/check-phase8.sh</files>
|
||||
<read_first>
|
||||
scripts/check-phase8.sh
|
||||
@@ -157,17 +157,17 @@ Unchanged MCP inputs:
|
||||
/media/nvme/dev/golem15/fonoteka/fonoteka-mcp/src/config.ts
|
||||
/media/nvme/dev/golem15/fonoteka/fonoteka-mcp/src/install.ts
|
||||
</read_first>
|
||||
<action>D-14: finish the executable pre-security gate using the existing gate family and installed Node MCP dependencies. Add `--core-smoke` for focused syntax/dependency/service lifecycle feedback and `--pre-security` for the complete wave-boundary gate. Allocate loopback ports, start disposable Postgres and the assembled Go app, start unchanged MCP with all three URLs, and drive SDK discovery/DCR/PKCE/login/consent/token, `/me`, tool, refresh, replay, and revoke. Verify RFC 9728 ownership separately from exact backend Basic/no-challenge responses. Run both modules' vet/test/race, parity/corpus/secret checks, `scripts/check-phase8-ui.mjs`, and unchanged Nuxt/MCP path diffs. Do not require `08-SECURITY-REVIEW.md` in either mode; Plan 08-10 adds the final fail-closed review stage. Preserve cleanup and never print secrets.</action>
|
||||
<action>D-14: finish the executable final gate using the existing gate family and installed Node MCP dependencies. Encode stages for disposable Postgres, assembled Go app, unchanged MCP with all three URLs, SDK discovery/DCR/PKCE/login/consent/token, `/me`, tool, refresh, replay, revoke, both repositories' vet/test/race, parity/corpus/secret checks, full UI harness, and unchanged Nuxt/MCP diffs. Verify RFC 9728 ownership separately from exact backend Basic/no-challenge responses. Add `--contract-self-test` that validates `bash -n`, required stage names/order, cleanup traps, loopback-only allocation, redacted output, expected commands, and unchanged-client path scopes without booting services or running long suites. Do not offer `--pre-security` or any mode that executes the complete gate before 08-10; Plan 08-10 adds the review stage and is the sole complete execution site.</action>
|
||||
<verify>
|
||||
<automated>scripts/check-phase8.sh --core-smoke</automated>
|
||||
<automated>bash -n scripts/check-phase8.sh && scripts/check-phase8.sh --contract-self-test</automated>
|
||||
</verify>
|
||||
<acceptance_criteria>
|
||||
- The gate starts the real unchanged MCP checkout and completes metadata, DCR, PKCE, JWT consent, token, `/me`, one MCP tool call, and refresh against the Go backend.
|
||||
- The gate proves spent refresh replay and connected-app revoke kill the lineage and later access/refresh attempts fail.
|
||||
- Both repositories pass `go vet ./...`, `go test ./...`, and `go test -race ./...`; corpus and secret scans exit 0.
|
||||
- `git -C /media/nvme/dev/golem15/fonoteka/fonoteka-mcp status --short` and the Nuxt equivalent show no Phase 8 diff.
|
||||
- Contract self-test finds required real-MCP lifecycle, replay/revoke, two-repository vet/test/race, parity, UI, secret-scan, security-review, and unchanged-client stages in fail-closed order.
|
||||
- The script has cleanup traps and loopback/service readiness checks, exports all three MCP URLs only to the child process, and redacts every raw secret/token/code/verifier.
|
||||
- No non-final mode can run the complete long suite; `--contract-self-test` performs syntax/source assertions only and is designed for under 30 seconds.
|
||||
- Final execution remains mandatory in 08-10 Task 3 and fails if either unchanged client worktree gains a Phase 8 source diff.
|
||||
</acceptance_criteria>
|
||||
<done>The actual connector stack, including RFC 9728 resource-server behavior, runs unchanged through the complete Go authorization lifecycle.</done>
|
||||
<done>The complete unchanged-client gate is fail-closed, self-validating, and ready for its sole execution at the final blocking checkpoint.</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
@@ -199,13 +199,13 @@ Unchanged MCP inputs:
|
||||
</threat_model>
|
||||
|
||||
<verification>
|
||||
- `cd ../fonoteka.go && go test ./parity -run 'TestOAuthFlows|TestParityCorpus|TestParityContract' -count=1`
|
||||
- `scripts/check-phase8.sh --pre-security` at the Wave 8 boundary; this mode proves the complete lifecycle but intentionally does not require the not-yet-created security review.
|
||||
- `cd ../fonoteka.go && go test ./parity -run '^TestOAuthFlows$' -count=1`
|
||||
- `bash -n scripts/check-phase8.sh && scripts/check-phase8.sh --contract-self-test`; the full gate runs only in 08-10 Task 3.
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- Nine OAuth routes and the full lifecycle replay pass against Go with no leaked fixture secret.
|
||||
- The real unchanged MCP discovers, authorizes, initializes, executes a tool, refreshes, and observes replay/revoke failure.
|
||||
- The final gate encodes the real unchanged-MCP lifecycle and cannot execute incompletely or before the security review.
|
||||
- Resource-server and authorization-server header ownership is proven exactly, not conflated.
|
||||
</success_criteria>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user