Skip to content

docs(adr): add ADR-004 (portal key storage) + ADR-005 (CORS deny-cache TTL)#105

Merged
voyvodka merged 1 commit into
mainfrom
docs/adr-portal-audit-decisions
May 11, 2026
Merged

docs(adr): add ADR-004 (portal key storage) + ADR-005 (CORS deny-cache TTL)#105
voyvodka merged 1 commit into
mainfrom
docs/adr-portal-audit-decisions

Conversation

@voyvodka
Copy link
Copy Markdown
Owner

Summary

Tur 5 of the v0.2.0 portal audit follow-up. Locks in two decisions the reviewer agent flagged as "worth recording as ADRs" — both are pure documentation; the behaviour was already shipped in PR #101 (ADR-004 surface) and PR #104 (ADR-005 surface).

ADRs

ADR-004 — Portal Signing Key Storage: Plaintext + Instant Invalidation, No Rotation Grace

  • Plaintext varchar(64) at rest, mirroring the existing SigningSecret column.
  • Instant invalidation on rotate / disable; no grace window for overlapping old + new key validity.
  • One-shot reveal on enable / rotate.
  • Alternatives considered: pgcrypto (defers, doesn't solve the underlying compromise scenario), rotation grace (doubles blast radius of leaked key), external KMS (out of scope for self-hosted reference).
  • Revisit triggers: compliance regimes mandating column-level encryption, recurring host-integration friction, key reuse beyond JWT verification.

ADR-005 — Portal CORS Preflight Deny-Cache TTL

  • 60s default (LookupCacheTtlSeconds reuse); both allow and deny cached.
  • No synchronous invalidation hook from PUT /portal/origins — cache key is origin-scoped, operator action is app-scoped; the bookkeeping cost outweighs the ≤60s staleness.
  • Alternatives considered: per-app invalidation hook, shorter/longer TTL, negative-only cache.
  • Revisit triggers: operator UX complaints about lag, memory pressure from origin-enumeration attacks, richer CORS semantics.

Test plan

  • No code changes — docs only.
  • CHANGELOG entries under Unreleased > Documentation (both ADRs).
  • ADR numbering follows existing convention (adr-NNN-kebab-slug.md).
  • CI green on PR.

…e TTL)

Locks in two v0.2.0 audit decisions that were marked 'worth recording'
in the reviewer agent's punch list. Both are pure documentation —
behaviour was already shipped in PRs #101 and #104.

ADR-004 — Portal Signing Key Storage:
- Plaintext varchar(64) at rest, mirroring the existing SigningSecret
  column. No application-level encryption; relies on operator's
  Postgres deployment posture.
- Instant invalidation on rotate / disable. No grace window for
  overlapping old + new key validity.
- One-shot reveal on enable / rotate; subsequent reads return only
  portalEnabled bool + rotated-at + origins (never the key).
- Documents alternatives (pgcrypto, rotation grace, external KMS)
  and revisit triggers (compliance regimes, host-integration
  friction, key reuse beyond JWT verification).

ADR-005 — Portal CORS Preflight Deny-Cache TTL:
- 60s default (LookupCacheTtlSeconds reuse); cache both allow and
  deny outcomes; key is lowercased-origin scoped.
- No synchronous invalidation hook from PUT /portal/origins:
  cache key is origin-scoped, operator action is app-scoped —
  bookkeeping cost outweighs the <=60s staleness.
- Documents alternatives (per-app invalidation, shorter/longer TTL,
  negative-only cache) and revisit triggers (operator UX complaints,
  memory pressure via origin enumeration).
@voyvodka voyvodka added documentation Documentation improvements api API layer and endpoints labels May 11, 2026
@voyvodka voyvodka enabled auto-merge (squash) May 11, 2026 08:26
@voyvodka voyvodka merged commit e062492 into main May 11, 2026
7 checks passed
@voyvodka voyvodka deleted the docs/adr-portal-audit-decisions branch May 11, 2026 08:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api API layer and endpoints documentation Documentation improvements

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant