v0.6 session 1: license boot re-activation (#157) + statestore skeleton (#152) #161

Merged
Cordy merged 1 commit from feat/v06-session1 into main 2026-08-09 03:51:43 +00:00
Owner

Closes #157 and #152.

#157Manager.EnsureKey. The old boot block blind-SetKeyed the configured key — which both failed to be the DR path it looked like AND had a latent bug: a stale config key would clobber a UI-installed or check-in-rotated renewal on every restart. EnsureKey parses the configured key and adopts it only when it reaches further than the installed license (nil/expired current → adopt; later expiry → adopt; otherwise keep, logged either way). Losing the state file now self-heals from config/env; renewals win regardless of which side they came from. Comparator unit-tested across all five orderings; garbage-key rejection tested against a real Manager.

#152internal/statestore. The ADR's skeleton exactly: Store (Load/Save/Delete, ErrNotExist, single-segment name guard), Local (temp+rename, byte-identical to pre-#152 files so posix instances need zero migration), and Backend (age-encrypted whole-object PUTs under /.cairn-state/, <name>.json.age, refuses to operate without recipients/identities per D3, ensure-once prefix mkdir, ADR D2 comment on why no CAS). Tests: local round-trip/idempotence/traversal-rejection; backend round-trip against an in-memory driver proving the raw object is an age file containing no plaintext, that a foreign identity cannot open it, and that deletes are idempotent. Not wired anywhere yet — that is #153, by design.

One breadcrumb left for #153: Backend.Load maps fs.ErrNotExist; the s3 driver's 404 mapping must be verified to match before wiring it.

Closes #157 and #152. **#157 — `Manager.EnsureKey`.** The old boot block blind-`SetKey`ed the configured key — which both failed to be the DR path it looked like AND had a latent bug: a stale config key would clobber a UI-installed or check-in-rotated renewal on every restart. `EnsureKey` parses the configured key and adopts it only when it *reaches further* than the installed license (nil/expired current → adopt; later expiry → adopt; otherwise keep, logged either way). Losing the state file now self-heals from config/env; renewals win regardless of which side they came from. Comparator unit-tested across all five orderings; garbage-key rejection tested against a real Manager. **#152 — `internal/statestore`.** The ADR's skeleton exactly: `Store` (Load/Save/Delete, `ErrNotExist`, single-segment name guard), `Local` (temp+rename, byte-identical to pre-#152 files so posix instances need zero migration), and `Backend` (age-encrypted whole-object PUTs under `/.cairn-state/`, `<name>.json.age`, refuses to operate without recipients/identities per D3, ensure-once prefix mkdir, ADR D2 comment on why no CAS). Tests: local round-trip/idempotence/traversal-rejection; backend round-trip against an in-memory driver proving the raw object is an age file containing no plaintext, that a foreign identity cannot open it, and that deletes are idempotent. Not wired anywhere yet — that is #153, by design. One breadcrumb left for #153: `Backend.Load` maps `fs.ErrNotExist`; the s3 driver's 404 mapping must be verified to match before wiring it.
feat: v0.6 session 1 — license boot re-activation via EnsureKey (#157), statestore skeleton (#152)
All checks were successful
ci / test-and-build (pull_request) Successful in 33s
b5c17662b7
Cordy merged commit bff2f8a430 into main 2026-08-09 03:51:43 +00:00
Cordy deleted branch feat/v06-session1 2026-08-09 03:51:46 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: Cordy/Cairn#161
No description provided.