#40: log every check-in, persist refusal history, 503 when the store cannot answer #41

Merged
Cordy merged 4 commits from checkin-logging-40 into main 2026-09-06 03:16:18 +00:00
Owner

Closes #40 — the server-side half of the 2026-08 licence-drop incident (client half shipped as Cairn v0.6.133, Cairn#437).

  • Every check-in leaves a log line: checkin ok (id, org, seats, expires, keyReturned) / checkin refused (id, reason, refusal count) / bad-request warns. The incident was unreconstructable because the handler logged nothing.
  • Refusal history persisted on the record: lastRefusedAt / lastRefusedReason / refusalCount in the SQLite data JSON — stamped on every 403 for a known licence, never cleared by later success (a trail, not state), survives store reopen.
  • 503, not 403-unknown, when the store cannot answer honestly: an empty or unreachable store (the mid-redeploy/migration position that refused cairn-enc's healthy licence) now answers 503 — clients treat it as connectivity failure and retry harmlessly. With real licences loaded, unknown ids stay honest 403s (pinned by test).

TDD: 503 + logging tests witnessed red on the runner (empty store answered 403; nothing logged); refusal-history test witnessed compile-red. Full suite green. Note: gofmt -w . also normalised 4 pre-existing lines in accounts.go.

Closes #40 — the server-side half of the 2026-08 licence-drop incident (client half shipped as Cairn v0.6.133, Cairn#437). - **Every check-in leaves a log line**: `checkin ok` (id, org, seats, expires, keyReturned) / `checkin refused` (id, reason, refusal count) / bad-request warns. The incident was unreconstructable because the handler logged nothing. - **Refusal history persisted on the record**: `lastRefusedAt` / `lastRefusedReason` / `refusalCount` in the SQLite `data` JSON — stamped on every 403 for a known licence, never cleared by later success (a trail, not state), survives store reopen. - **503, not 403-unknown, when the store cannot answer honestly**: an empty or unreachable store (the mid-redeploy/migration position that refused cairn-enc's healthy licence) now answers 503 — clients treat it as connectivity failure and retry harmlessly. With real licences loaded, unknown ids stay honest 403s (pinned by test). TDD: 503 + logging tests witnessed red on the runner (empty store answered 403; nothing logged); refusal-history test witnessed compile-red. Full suite green. Note: `gofmt -w .` also normalised 4 pre-existing lines in accounts.go.
Red against main: an empty store answers 403-unknown (exactly what the
2026-08 redeploy did to a healthy licence) and the checkin handler logs
nothing at all, so the incident left no server-side trace.
Compile-red against main: LastRefusedAt/LastRefusedReason/RefusalCount
do not exist yet. Refusals stamp the record and survive a store reopen -
the server-side forensic trail the 2026-08 incident lacked (lastSeen was
one overwritten value and nothing recorded the 403s).
#40: log every check-in, persist refusal history, 503 when the store cannot answer
All checks were successful
ci / test-and-build (pull_request) Successful in 40s
cb2929fc85
Every check-in now leaves a log line (id, outcome, reason, keyReturned); refusals stamp the record with lastRefusedAt/lastRefusedReason/refusalCount, persisted in SQLite and never cleared by success - the server-side forensic trail the 2026-08 incident lacked. A check-in against an empty or unreachable store answers 503 instead of 403-unknown, so a mid-redeploy server can no longer make clients treat a healthy licence as revoked; with real licences loaded, unknown ids stay honest 403s.

TDD: 503 + logging tests witnessed red (empty store answered 403, nothing logged); refusal-history test witnessed compile-red; all green after splice.
Cordy merged commit b7abd3902a into main 2026-09-06 03:16:18 +00:00
Cordy deleted branch checkin-logging-40 2026-09-06 03:16:22 +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-license-server#41
No description provided.