|
|
|
|
@@ -70,8 +70,8 @@ must_haves:
|
|
|
|
|
- "D-13: oauthserver:rotate-keys promotes a new key (algorithm from key_algorithm) and retires the previous one, which stays in the JWKS for rotation_grace_hours (default 24); --prune also removes keys past the grace; the output lines match PHP and never contain key material; a scheduled rotation runs only when rotation_interval is set (off by default)."
|
|
|
|
|
- "SC-3: oauthserver:prune runs daily through the framework scheduler and deletes codes, access tokens (expired or revoked), auth requests, refresh tokens and MCP codes older than one day past expiry, and keys past the grace window, printing one count per kind."
|
|
|
|
|
- "D-03, D-08: administrators manage OIDC clients in cabana with stock field types: create generates an oas_ client id and an oas_cs_ secret that is shown exactly once, regenerate-secret is a danger action that invalidates the old secret, the secret hash never appears in a list, form or JSON, redirect URIs are edited one per line, pairwise clients need a resolvable sector, and the client form lists who authorized the client with each user's sub; branding is a singleton form linked from Settings with a logo upload."
|
|
|
|
|
- statement: "D-14: tide fixtures recorded from the PHP plugin (discovery, JWKS, authorize errors and redirects, login handoff, resume, decide, deny, silent consent, token success and errors, userinfo success and 401, authorizations list, revoke and 404) replay against the Go plugin with no difference outside a documented deviations list; the PHP id_token's header members and claim set equal the Go id_token's. The only evidence is TestPHPParityReplay and TestIDTokenShapeParity passing with PHASE194_REQUIRE_PARITY=1 over committed recordings; a skip, the gate's NOT RUN parity line or the skip-parity reply is not evidence, so without recordings this truth stays unproven and the phase verdict is human_needed (or gaps_found), never passed."
|
|
|
|
|
verification: backstop
|
|
|
|
|
- statement: "D-14 (amended 2026-10-19 by the user): the parity harness ships and fails closed: ten spec flows (discovery, JWKS, authorize errors and redirects, login handoff, resume, decide, deny, silent consent, token success and errors, userinfo success and 401, authorizations list, revoke and 404), capture rules, a deviations list whose entries cite a D-number, TestPHPParityReplay and TestIDTokenShapeParity, and a runbook. Without recordings the tests skip with \"no PHP recordings\" and fail with PHASE194_REQUIRE_PARITY=1. Recording the PHP plugin and passing the replay is deferred to the WavePath cutover phase as a preliminary task (`.planning/todos/pending/2026-10-19-record-php-oidc-parity-against-wavepath.md` (g15office govfaqir)); with recordings committed, the replay must pass with only decision-backed deviations. A skip-parity reply does not hold the phase verdict at human_needed."
|
|
|
|
|
verification: automated
|
|
|
|
|
- "SC-4: a security review walks ASVS L1 across wristband's OIDC flavour, the plugin and the sm-user-plugin additions, verifies every T-19.4 mitigation in code and in a test, fixes any gap, and records the result in 19.4-SECURITY-REVIEW.md."
|
|
|
|
|
artifacts:
|
|
|
|
|
- path: "../sm-oauthserver-plugin/console/import_winter.go"
|
|
|
|
|
@@ -136,7 +136,7 @@ This plan's slice (plan 3 of 4, wave 3): the cutover and operations half. An ope
|
|
|
|
|
- Scheduled rotation (CONTEXT discretion): `rotation_interval` empty means off; the README suggests 2160h (90 days) when switched on; an unparseable or non-positive value fails boot naming the key.
|
|
|
|
|
- Parity: the session JWT on both sides comes from a variable (`session_token`): recorded from a human's WavePath login, minted by the Go harness on replay; JWKS `n`, `e`, `x`, `y` and `kid` values, id_token and access token strings, codes and request ids are compared by shape or captured as variables; HTML bodies of rendered pages are not compared (D-14), their status and headers are.
|
|
|
|
|
- D-11 is a one-way door already decided by the user in CONTEXT; it is rated here and not re-gated.
|
|
|
|
|
- Parity skip (D-14): a "skip-parity" reply at Task 5 is an accepted way to finish this plan, never a way to prove D-14. The D-14 truth is a backstop truth whose only evidence is the replay passing with PHASE194_REQUIRE_PARITY=1; after a skip the phase verdict stays human_needed (or gaps_found) until the recording is made.
|
|
|
|
|
- Parity skip (D-14, amended 2026-10-19 by the user): a "skip-parity" reply at Task 5 is an accepted way to finish this plan and the phase. The PHP recording and a green replay with PHASE194_REQUIRE_PARITY=1 move to the WavePath cutover phase as a preliminary task (`.planning/todos/pending/2026-10-19-record-php-oidc-parity-against-wavepath.md` (g15office govfaqir)); WavePath's OIDC provider does not move to the Go plugin until then. In this phase the D-14 truth is the fail-closed harness, so a skip does not hold the phase verdict at human_needed.
|
|
|
|
|
- Context budget (estimate 260k, 7 tasks; size accepted with the four-plan decision): the Task 5 checkpoint splits execution in two, since the executor resumes in a fresh continuation agent. Tasks 1-4 run in the first context; Tasks 6-7 run in the continuation agent. Task 7 (security review) reads everything it needs from disk (the three plans' threat models, the plan 01 and 02 SUMMARYs, the code), so the executor may also give it a fresh agent of its own.
|
|
|
|
|
|
|
|
|
|
## Artifacts this phase produces (this plan)
|
|
|
|
|
@@ -302,7 +302,7 @@ Tests commands_smoke_test.go (Postgres, skip under -short): `TestRotateAndPruneS
|
|
|
|
|
5. Write base_url, client_id, client_secret and session_token into ~/.config/summercms/parity-oauthserver.vars (chmod 600). Do not paste the secret or the token into the chat.
|
|
|
|
|
</instructions>
|
|
|
|
|
<verification>Claude checks the vars file mode, that discovery answers 200 at base_url, and that the export file holds lines for the parity client.</verification>
|
|
|
|
|
<resume-signal>Reply "ready" with the vars file path and the parity user's id, name and email, or "skip-parity" if WavePath cannot be started now (Task 6 then runs its explicit skip check, commits nothing new and records D-14 parity as NOT RUN with a human verification item; D-14 stays unproven and the phase verdict stays human_needed until the recording is made, never passed).</resume-signal>
|
|
|
|
|
<resume-signal>Reply "ready" with the vars file path and the parity user's id, name and email, or "skip-parity" if WavePath cannot be started now (Task 6 then runs its explicit skip check, commits nothing new and records D-14 parity as NOT RUN with a human verification item; the recording is deferred to the WavePath cutover phase per `.planning/todos/pending/2026-10-19-record-php-oidc-parity-against-wavepath.md` (g15office govfaqir), and the phase verdict is not held at human_needed).</resume-signal>
|
|
|
|
|
</task>
|
|
|
|
|
|
|
|
|
|
<task type="auto">
|
|
|
|
|
@@ -316,10 +316,10 @@ Tests commands_smoke_test.go (Postgres, skip under -short): `TestRotateAndPruneS
|
|
|
|
|
</verify>
|
|
|
|
|
<acceptance_criteria>
|
|
|
|
|
- With "ready": all ten flow files exist and every flow file contains a recorded response (`grep -L 'response:' ../sm-oauthserver-plugin/testdata/parity/flows/*.yaml` prints nothing), and every entry in deviations.yaml carries a `reason:` that cites a D-number (`grep -c 'reason:' deviations.yaml` equals `grep -c 'reason:.*D-[0-9]' deviations.yaml`).
|
|
|
|
|
- With "skip-parity": `grep -l 'response:' ../sm-oauthserver-plugin/testdata/parity/flows/*.yaml` prints nothing, and 19.4-03-SUMMARY.md contains `D-14 parity: NOT RUN (skip-parity)` and a `## Human verification pending` section naming TestPHPParityReplay (checked when the SUMMARY is written).
|
|
|
|
|
- With "skip-parity": `grep -l 'response:' ../sm-oauthserver-plugin/testdata/parity/flows/*.yaml` prints nothing, and 19.4-03-SUMMARY.md contains `D-14 parity: NOT RUN (skip-parity)` and a `## Deferred to the WavePath cutover` section naming TestPHPParityReplay and the todo file 2026-10-19-record-php-oidc-parity-against-wavepath.md (checked when the SUMMARY is written).
|
|
|
|
|
- Either reply: `F=$(git -C ../sm-oauthserver-plugin ls-files testdata) && printf '%s\n' "$F" | grep -c '\.vars$'` prints 0.
|
|
|
|
|
</acceptance_criteria>
|
|
|
|
|
<done>With "ready": the relying-party-visible contract of the PHP plugin is recorded and the Go plugin reproduces it, with every difference explained by a decision. With "skip-parity": nothing is recorded, the skip is checked explicitly, and D-14 is carried to verification as an open human item that keeps the verdict at human_needed.</done>
|
|
|
|
|
<done>With "ready": the relying-party-visible contract of the PHP plugin is recorded and the Go plugin reproduces it, with every difference explained by a decision. With "skip-parity": nothing is recorded, the skip is checked explicitly, the harness is proven fail-closed, and the PHP recording is carried to the WavePath cutover phase through the captured todo; the phase verdict is not held at human_needed.</done>
|
|
|
|
|
</task>
|
|
|
|
|
|
|
|
|
|
<task type="auto">
|
|
|
|
|
@@ -370,16 +370,16 @@ Tests commands_smoke_test.go (Postgres, skip under -short): `TestRotateAndPruneS
|
|
|
|
|
- Task 1: TestImportWinterCutoverSmoke (old token, old id_token, old secret, original kids).
|
|
|
|
|
- Task 2: TestClientsAdminSmoke and TestBrandingAdminSmoke.
|
|
|
|
|
- Task 3: TestRotateAndPruneSmoke and TestScheduleSmoke.
|
|
|
|
|
- Task 4 to 6: the parity suite prepared, the PHP plugin recorded after the human starts it, the replay and id_token shape tests green, no secrets under testdata. After a skip-parity reply only the explicit skip branch passes; D-14 stays unproven and goes to verification as a human item.
|
|
|
|
|
- Task 4 to 6: the parity suite prepared, the PHP plugin recorded after the human starts it, the replay and id_token shape tests green, no secrets under testdata. After a skip-parity reply only the explicit skip branch passes; the PHP recording is deferred to the WavePath cutover phase (captured todo), not a human item of this phase.
|
|
|
|
|
- Task 7: the security review document covers every threat; suites green after fixes.
|
|
|
|
|
</verification>
|
|
|
|
|
|
|
|
|
|
<success_criteria>
|
|
|
|
|
- SC-3: the daily prune is scheduled and removes expired codes, tokens, requests and keys.
|
|
|
|
|
- SC-4: an existing issuer, its keys (original kids) and client secrets import so relying parties keep working; the phase has a security review with no open threat.
|
|
|
|
|
- D-14: the Go plugin replays the PHP recordings with only decision-backed deviations. Unmet after skip-parity: the phase verdict is then human_needed (or gaps_found), not passed.
|
|
|
|
|
- D-14 (amended 2026-10-19 by the user): the parity harness ships fail-closed; with recordings, the Go plugin replays them with only decision-backed deviations. After skip-parity the recording is deferred to the WavePath cutover phase (`.planning/todos/pending/2026-10-19-record-php-oidc-parity-against-wavepath.md` (g15office govfaqir)) and the phase can pass.
|
|
|
|
|
</success_criteria>
|
|
|
|
|
|
|
|
|
|
<output>
|
|
|
|
|
Create `.planning/phases/19.4-oidc-provider-on-wristband/19.4-03-SUMMARY.md` when done, with the commits per repository, the human's Task 5 reply (without secrets), the parity result or `D-14 parity: NOT RUN (skip-parity)` with the `## Human verification pending` section from Task 6, the review's fixed and accepted items, which Docker-backed tests ran, and any deviation from this plan's names.
|
|
|
|
|
Create `.planning/phases/19.4-oidc-provider-on-wristband/19.4-03-SUMMARY.md` when done, with the commits per repository, the human's Task 5 reply (without secrets), the parity result or `D-14 parity: NOT RUN (skip-parity)` with the `## Deferred to the WavePath cutover` section from Task 6, the review's fixed and accepted items, which Docker-backed tests ran, and any deviation from this plan's names.
|
|
|
|
|
</output>
|
|
|
|
|
|