117 lines
6.7 KiB
Markdown
117 lines
6.7 KiB
Markdown
---
|
|
phase: 08-oauth2-1-authorization-server
|
|
plan: 02
|
|
type: execute
|
|
wave: 2
|
|
depends_on: [08-01]
|
|
files_modified:
|
|
- ../fonoteka.go/plugins/golem15/fonoteka/models/oauth_client.go
|
|
- ../fonoteka.go/plugins/golem15/fonoteka/models/oauth_auth_code.go
|
|
- ../fonoteka.go/plugins/golem15/fonoteka/updates/12_oauth_schema_correction.go
|
|
- ../fonoteka.go/plugins/golem15/fonoteka/updates/oauth_schema_correction_test.go
|
|
- ../fonoteka.go/plugins/golem15/fonoteka/classes/auth/oauth_store.go
|
|
- ../fonoteka.go/plugins/golem15/fonoteka/classes/auth/oauth_store_test.go
|
|
autonomous: true
|
|
requirements: [AUTH-05, AUTH-07]
|
|
must_haves:
|
|
truths:
|
|
- "D-07: Public clients and multiple pending authorization requests persist through one transaction-scoped GORM adapter."
|
|
- "D-17: Expiry sweeps delete only expired lifecycle rows and retain unexpired replay evidence."
|
|
artifacts:
|
|
- path: "../fonoteka.go/plugins/golem15/fonoteka/updates/12_oauth_schema_correction.go"
|
|
provides: "Additive nullability and index correction with safe rollback refusal"
|
|
- path: "../fonoteka.go/plugins/golem15/fonoteka/classes/auth/oauth_store.go"
|
|
provides: "GORM transaction-scoped wristband backend"
|
|
key_links:
|
|
- from: "oauth_store.go"
|
|
to: "wristband.Backend"
|
|
via: "WithinTx callback whose methods all use callback *gorm.DB"
|
|
pattern: "WithinTx"
|
|
---
|
|
|
|
<objective>
|
|
Make the existing Postgres schema and app store faithfully represent wristband's client and pending-request state.
|
|
|
|
Purpose: Separate persistence correctness from protocol and route wiring so nullability, indexes, locking, cap serialization, and sweep semantics are independently verifiable.
|
|
Output: Corrected models, additive migration, GORM backend, and real-Postgres tests.
|
|
</objective>
|
|
|
|
<execution_context>
|
|
@/home/jin/.codex/get-shit-done/workflows/execute-plan.md
|
|
@/home/jin/.codex/get-shit-done/templates/summary.md
|
|
</execution_context>
|
|
|
|
<context>
|
|
@.planning/PROJECT.md
|
|
@.planning/ROADMAP.md
|
|
@.planning/STATE.md
|
|
@.planning/phases/08-oauth2-1-authorization-server/08-CONTEXT.md
|
|
@.planning/phases/08-oauth2-1-authorization-server/08-RESEARCH.md
|
|
@.planning/phases/08-oauth2-1-authorization-server/08-01-SUMMARY.md
|
|
</context>
|
|
|
|
<tasks>
|
|
|
|
<task type="auto" tdd="true">
|
|
<name>Task 1: Specify schema and store behavior in compiling RED tests</name>
|
|
<files>../fonoteka.go/plugins/golem15/fonoteka/updates/oauth_schema_correction_test.go, ../fonoteka.go/plugins/golem15/fonoteka/classes/auth/oauth_store_test.go</files>
|
|
<behavior>
|
|
- Public client secret, pending request id/code hash/user id nullability, named indexes, and rollback refusal are proven on real Postgres.
|
|
- Two pending requests coexist; atomic cap/sweep/create cannot exceed the configured cap under contention.
|
|
- Failures emit `PHASE8_RED:persistence` only for absent persistence behavior.
|
|
</behavior>
|
|
<action>D-18: add real-Postgres tests using the existing auth TestMain harness. Compile them against the interfaces from 08-01; use `PHASE8_RED:persistence` assertions for intentionally missing migration/store behavior, and do not use undefined symbols as RED. Include T-08-DCR-FLOOD and transaction-handle tests that detect accidental use of the outer DB.</action>
|
|
<verify>
|
|
<automated>scripts/check-phase8-red.sh persistence bash -lc "cd ../fonoteka.go && go test ./plugins/golem15/fonoteka/classes/auth ./plugins/golem15/fonoteka/updates -run 'TestOAuth(Schema|Store|RegistrationCap)' -count=1"</automated>
|
|
</verify>
|
|
<done>The real-Postgres RED suite compiles, runs named tests, and fails only through the persistence marker.</done>
|
|
</task>
|
|
|
|
<task type="auto" tdd="true">
|
|
<name>Task 2: Correct OAuth schema and implement the transaction-scoped store</name>
|
|
<files>../fonoteka.go/plugins/golem15/fonoteka/models/oauth_client.go, ../fonoteka.go/plugins/golem15/fonoteka/models/oauth_auth_code.go, ../fonoteka.go/plugins/golem15/fonoteka/updates/12_oauth_schema_correction.go, ../fonoteka.go/plugins/golem15/fonoteka/updates/oauth_schema_correction_test.go, ../fonoteka.go/plugins/golem15/fonoteka/classes/auth/oauth_store.go, ../fonoteka.go/plugins/golem15/fonoteka/classes/auth/oauth_store_test.go</files>
|
|
<behavior>
|
|
- Four lifecycle fields are pointers and database nullable; PHP-equivalent operational indexes exist.
|
|
- Down migration refuses when null lifecycle rows would be lost.
|
|
- Every store mutation uses the callback transaction and app-tier `FOR UPDATE` where required.
|
|
</behavior>
|
|
<action>D-07: correct `client_secret_hash`, `request_id`, `code_hash`, and `user_id` model fields to pointers and implement the wristband Backend/Tx adapter without importing GORM into wristband. Add a new gormigrate step rather than editing applied history; drop four NOT NULL constraints, create named indexes idempotently, and fail rollback if null rows exist. Implement atomic DCR sweep/cap/create, exact expired-row sweep, and row-lock-capable lifecycle methods using only the callback `*gorm.DB`. D-17: retain unexpired rotated/revoked refresh rows.</action>
|
|
<verify>
|
|
<automated>cd ../fonoteka.go && go test ./plugins/golem15/fonoteka/classes/auth ./plugins/golem15/fonoteka/updates -run 'TestOAuth(Schema|Store|RegistrationCap|Sweep)' -count=1</automated>
|
|
</verify>
|
|
<done>Postgres can persist public clients and concurrent pending requests, exposes required indexes, serializes DCR cap enforcement, and sweeps only expired rows.</done>
|
|
</task>
|
|
|
|
</tasks>
|
|
|
|
<threat_model>
|
|
## Trust Boundaries
|
|
|
|
| Boundary | Description |
|
|
|----------|-------------|
|
|
| wristband records → GORM | App-agnostic state crosses into persistent rows and locks. |
|
|
|
|
## STRIDE Threat Register
|
|
|
|
| Threat ID | Category | Component | Disposition | Mitigation Plan |
|
|
|-----------|----------|-----------|-------------|-----------------|
|
|
| T-08-DCR-FLOOD | Denial of Service | client store | mitigate | Transactionally serialized cap/sweep/create with contention test. |
|
|
| T-08-CODE-REPLAY | Spoofing | auth-code store | mitigate | App-tier row-lock methods and single transaction handle. |
|
|
| T-08-REFRESH-REPLAY | Spoofing/Elevation | refresh store | mitigate | Preserve replay evidence until expiry and expose locked traversal. |
|
|
| T-08-SC | Tampering | dependencies | mitigate | Existing GORM/Postgres only; no install. |
|
|
</threat_model>
|
|
|
|
<verification>
|
|
- Focused migration/store Postgres tests pass.
|
|
- `rg -n 'clause.Locking' ../fonoteka.go/plugins/golem15/fonoteka/classes/auth/oauth_store.go` finds app-tier locks only.
|
|
</verification>
|
|
|
|
<success_criteria>
|
|
- Schema and store can represent every client/pending/code/refresh lifecycle state.
|
|
- DCR cap and single-use operations have real-Postgres concurrency evidence.
|
|
</success_criteria>
|
|
|
|
<output>
|
|
Create `.planning/phases/08-oauth2-1-authorization-server/08-02-SUMMARY.md` when done.
|
|
</output>
|