mirror of
https://github.com/dtzp555-max/olp.git
synced 2026-07-19 09:45:07 +00:00
docs: D43-B — ADR 0007 multi-key auth design draft (design-only) (#19)
* docs: D43-B — ADR 0007 multi-key auth design draft (design-only, no code change) Phase 2 mainline design ADR. Ratifies the storage / token / manifest / atomic-write / owner-gating / bootstrap / Node-baseline decisions ahead of D44+ implementation D-days. Pure design doc — no .mjs / no tests / 4 files touched. Test count 468 → 468. - docs/adr/0007-multi-key-auth.md (new, ~400 lines): 13 sections covering Context / Decision (Option 2 filesystem manifest + opaque token) / Storage layout / Manifest schema / Token format (olp_+32B base64url, SHA-256 hash) / Atomic write & audit append (manifest lifecycle-only atomic via tmpfile+fsync+rename; audit per-request append with warn+1-retry, no memory buffer at Phase 2) / Owner-vs- guest-vs-anonymous gating (config.json auth.allow_anonymous default false, no env auto-detection) / Audit ndjson schema (no PII) / Bootstrap & recovery (minimal keygen command surface + OLP_OWNER_TOKEN env override with stable __env_owner__ keyId) / Acceptance criteria (11 test surfaces) / Node baseline (Option 1 SQLite port rejection rationale citing engines >=18 + CI 20/24 vs node:sqlite v22.5.0/RC) / Out of scope (Dashboard, quota enforcement, audit query, file locking deferred to Phase 3+) / Future forward (Option 3 hybrid migration trigger + preconditions). - docs/adr/README.md index: added ADR 0007 row with one-paragraph summary covering storage choice + rejection rationale. - docs/v1x-roadmap.md #2: marked PHASE 2 ACTIVE (no longer deferred); "Design ADR (NOT YET RATIFIED)" → "Design ADR (ratified) → ADR 0007"; trigger updated to "already fired 2026-05-25"; code anchors pinned to exact line numbers (cache/store.mjs:77-79/:287, server .mjs:502/:531/:392/:1072/:1101). - CHANGELOG.md Unreleased: D43-B entry per release_kit overlay phase_rolling_mode discipline. Authority: - Phase 2 kickoff handoff (~/.cc-rules/memory/handoffs/2026-05-25-phase-2-kickoff.md, cc-rules d9da966) - OLP v0.1 spec § 4.5 (planning authority for ~/.olp/ layout) - OCP keys.mjs (prior-art for opaque-key + per-key isolation model) - Node node:sqlite docs (https://nodejs.org/api/sqlite.html — Option 1 rejection per ADR 0007 § 11) - CC 开发铁律 v1.6 § 10 — fresh-context opus reviewer required for design ADR per Iron Rule 10 ALIGNMENT.md scope check: this PR introduces a new ADR; per ALIGNMENT.md Rule 1 (Cite First), the ADR itself contains the authority citations its decisions rest on (v0.1 spec § 4.5, OCP keys.mjs, Node docs URL). No provider plugin / entry surface / IR change in this commit. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * docs: D43-B fold-in — ADR 0007 reviewer findings (2 P2 + 3 P3, all polish) Fresh-context opus reviewer (PR #19) returned APPROVE_WITH_MINOR with 2 P2 load-bearing-but-non-blocking findings + 3 P3 polish findings. All five are accepted as suggested; design contract clarified without semantic change. - § 6.2 step 1 (P2 #1) — pin audit serialization to fire AFTER status_code is determined and latency_ms is measured. Makes acceptance criterion #2 (anonymous-401 audit event records the 401 + latency) testable in the way the criterion was written. - § 6.3.5 (P2 #2, new subsection) — explicit "Token validation MUST hit the manifest on every authenticated request (no in-process validation cache at Phase 2)" rule. The acceptance criterion #6 (post-revoke 401 within the next request) was previously enforced only by the test; the rule now belongs to the design contract. Forward-path note documents when a Phase 3+ amendment may add a cache. - § 6.1 atomic-write step 5 follow-up (P3 #3) — document the deliberate omission of directory fsync after rename. Single-process family-scale deployment accepts the tiny rename-loss window under abrupt host crash; future POSIX-strict deployments know where to add the step. - § 9.4 (P3 #4) — declare token-collision between OLP_OWNER_TOKEN and a filesystem-stored key's plaintext as undefined behaviour. Operators MUST NOT reuse plaintext across both surfaces. Phase MAY add startup collision-detection later. - § 10 criterion #4 (P3 #5) — rephrased to assert against the config- driven owner_only_endpoints predicate rather than a hardcoded trimmed payload shape. The test stays stable if an operator removes /health from owner_only_endpoints. CHANGELOG D43-B entry: fold-in bullet added to summarize the 5 fixes. Test count: 468 → 468 (npm test verified locally after fold-in). Authority: PR #19 fresh-context opus reviewer findings; CLAUDE.md release_kit overlay phase_rolling_mode — under Unreleased. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * docs: D43-B fold-in #2 — maintainer text-review findings (1 P1 + 1 P2 + 1 P3) Maintainer (codex) did final text review of PR #19 against the Phase 2 ADR-ratification checklist. Returned 3 findings; all accepted as suggested. Two are contract-level (P1 safety + P2 factual); one is trivial (P3 line-count drift). No semantic change beyond what the findings called out. P1 — § 6.3 / § 6.4 / § 10 #7 — revoke-dominates-touch safety contract Original § 6.3 said touchLastUsed used the same atomic-write pattern as 6.1; § 6.4 said concurrent CLI revoke + touchLastUsed left "both states valid" with "observability-grade" failure mode. Codex correctly identified the bug: a stale manifest snapshot held by the touch path could overwrite a fresh revoke and silently clear revoked_at back to null, breaking acceptance criterion #6 (post-revoke 401 within next request) under concurrent CLI revoke + in-flight server request. The ADR was promising security-grade behavior on a path that was actually last-write-wins. Fix: - § 6.3 rewritten with explicit read-modify-write discipline: touch MUST re-read latest manifest from disk inside the per-key write-lock, NO-OP if revoked_at is non-null, otherwise merge last_used_at preserving all other fields including revoked_at. - § 6.4 reframed from "both states valid" to "revoke dominates touch" safety frame, citing § 6.3 as the load-bearing discipline. The CLI revoke writer always wins the dimension that matters; touch may lose its last_used_at update if it raced. - § 10 criterion #7 expanded to test all three orderings (revoke -> touch, touch -> revoke, interleaved) with the explicit MUST: revoked_at is non-null and equals the revoke writer's timestamp after any interleaving; FAIL if any path produces revoked_at: null. - Forward-path § 6.4 file-locking note updated to clarify §6.3 already holds the contract single-process; flock adds defense-in- depth for rare multi-writer TOCTOU. P2 — § 11 forward path step (1) — Node baseline version history corrected Original wording "Node v22.5.0+ for unflagged but RC; Node TBD for stable" was wrong. v22.5.0 added with --experimental-sqlite flag; v22.12 still required the flag; the module moved past flag-gating in v22.13.0 (LTS) / v23.4.0 (current); entered Release Candidate at v25.7.0 per current docs. Fix: § 11 forward path step (1) rewritten with accurate versions + two Node release-history URLs cited (https://nodejs.org/download/ release/v22.12.0/docs/api/sqlite.html and https://nodejs.org/api/ sqlite.html). Minimum non-flag-gated baseline is now stated as >=22.13.0 (LTS) / >=23.4.0 (current); stable baseline TBD pending Node v25.x+. The rejection-evidence paragraph earlier in § 11 ("v22.12 still required --experimental-sqlite ... current docs mark RC") was already correct and is untouched. P3 — CHANGELOG D43-B line-count corrected Entry said ADR was "~270 lines"; actual file is 420 lines after both fold-ins. Changed to "~420 lines after fold-ins". Phase 2 fold-in #2 bullet enumerates the 3 fixes in this commit; fold-in #1 bullet retained for the opus reviewer round. Test count: 468 / 468 (npm test verified locally after fold-in; design-only doc changes, no test file touched). Authority: PR #19 maintainer text review findings 2026-05-25; CLAUDE.md release_kit overlay phase_rolling_mode — under Unreleased; Node SQLite docs URLs cited in ADR § 11 forward path. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: dtzp555 <dtzp555@gmail.com> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,19 @@ All notable changes to OLP land here. Per `CLAUDE.md` release_kit overlay, this
|
||||
|
||||
## Unreleased
|
||||
|
||||
### D43-B — ADR 0007 multi-key auth design draft (design-only, no code change)
|
||||
|
||||
Phase 2 mainline design ADR. Ratifies the storage / token / manifest / atomic-write / owner-gating / bootstrap / Node-baseline decisions ahead of D44+ implementation D-days. Pure design doc — no `.mjs` / no tests / 4 files touched.
|
||||
|
||||
- `docs/adr/0007-multi-key-auth.md` (new, ~420 lines after fold-ins): 13 sections covering Context / Decision (Option 2 + opaque key) / Storage layout (`~/.olp/keys/<key-id>/manifest.json` + `~/.olp/logs/audit.ndjson`) / Manifest schema (schema_version, token_hash, owner_tier, providers_enabled) / Token format (`olp_<32-byte base64url>`, SHA-256 hash) / Atomic write & audit append (manifest lifecycle-only atomic via tmpfile+fsync+rename; audit per-request append, warn + 1 retry, no memory buffer at Phase 2) / Owner-vs-guest-vs-anonymous gating (config.json `auth.allow_anonymous` default false, no env auto-detection) / Audit ndjson schema (no PII) / Bootstrap & recovery (minimal keygen command surface + `OLP_OWNER_TOKEN` env override with stable `__env_owner__` keyId) / Acceptance criteria (11 test surfaces for D44+) / Node baseline (Option 1 SQLite port rejection rationale citing `engines >=18` + CI 20/24 vs `node:sqlite` v22.5.0 with flag) / Out of scope (Dashboard, quota enforcement, audit query, file locking deferred to Phase 3+) / Future forward (Option 3 hybrid migration trigger + preconditions).
|
||||
- `docs/adr/README.md` index: added ADR 0007 row with one-paragraph summary.
|
||||
- `docs/v1x-roadmap.md` #2: marked **PHASE 2 ACTIVE (no longer deferred)**; "Design ADR (NOT YET RATIFIED)" → "Design ADR (ratified) → ADR 0007"; trigger updated to "already fired 2026-05-25"; code anchors pinned to exact line numbers (cache/store.mjs:77-79/:287, server.mjs:502/:531/:392/:1072/:1101).
|
||||
- `CHANGELOG.md` Unreleased: this entry.
|
||||
- **Fold-in #1 (fresh-context opus reviewer findings, 2 P2 + 3 P3, all polish):** § 6.2 step 1 — pin audit serialization timing to after status_code + latency_ms are known (resolves §10 #2 testability gap); new § 6.3.5 — explicit "no in-process validation cache at Phase 2" rule (resolves §10 #6 implicit-contract gap); § 6.1 — document deliberate omission of directory fsync after rename (single-process trade-off); § 9.4 — token-collision policy between `OLP_OWNER_TOKEN` and filesystem keys declared undefined behaviour; §10 #4 — test rephrased to assert against config-driven `owner_only_endpoints` rather than hardcoded payload shape.
|
||||
- **Fold-in #2 (maintainer text-review findings, 1 P1 + 1 P2 + 1 P3):** § 6.3 rewritten to `last_used_at` revoke-dominates-touch semantics (P1 — fixes safety bug where lazy touch could overwrite revoke and silently clear `revoked_at`, breaking acceptance criterion #6 under concurrent CLI revoke + in-flight server request); § 6.4 reframed from "both states are valid" / "observability-grade" to "revoke dominates touch" with §6.3 as the load-bearing discipline; § 10 criterion #7 expanded to test all three orderings (revoke→touch, touch→revoke, interleaved) with explicit MUST: `revoked_at` non-null after revoke regardless of ordering; § 11 forward path step (1) corrected Node version history — minimum non-flag-gated baseline is v22.13.0 (LTS) / v23.4.0 (current), RC since v25.7.0, stable TBD (previous wording "Node v22.5.0+ for unflagged but RC" was factually wrong per https://nodejs.org/download/release/v22.12.0/docs/api/sqlite.html and https://nodejs.org/api/sqlite.html); this CHANGELOG entry line-count corrected from "~270 lines" to "~420 lines after fold-ins".
|
||||
- **Test count:** 468 → 468 (design-only, no test change).
|
||||
- **Authority:** Phase 2 kickoff handoff (`~/.cc-rules/memory/handoffs/2026-05-25-phase-2-kickoff.md` in cc-rules `d9da966`); OLP v0.1 spec § 4.5 (planning authority for `~/.olp/` layout); OCP `keys.mjs` (prior-art for opaque-key + per-key isolation model); Node `node:sqlite` docs (https://nodejs.org/api/sqlite.html — Option 1 rejection rationale per ADR 0007 § 11); CC 开发铁律 v1.6 § 10 — fresh-context opus reviewer required for design ADR per Iron Rule 10.
|
||||
|
||||
### D43-A — Phase 2 doc alignment (no code change)
|
||||
|
||||
Phase 1 was closed at v0.1.1; this commit aligns documentation surfaces to the Phase 2 reality before D43-B (ADR 0007 draft) lands. Pure doc cleanup; no `.mjs` or test changes.
|
||||
|
||||
Reference in New Issue
Block a user