feat(release-service): add envelope encryption#1990
Conversation
|
Scope checkThis PR changes 786 lines across 13 files. Large PRs are harder to review and more likely to be closed without review. If this scope is intentional, no action needed. A maintainer will review it. If not, please consider splitting this into smaller PRs. See CONTRIBUTING.md for contribution guidelines. |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
emdash-playground | 6438490 | Jul 12 2026, 06:25 PM |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
emdash-demo-do | 6438490 | Jul 12 2026, 06:25 PM |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
emdash-demo-cache | 6438490 | Jul 12 2026, 06:26 PM |
Overlapping PRsThis PR modifies files that are also changed by other open PRs:
This may cause merge conflicts or duplicated work. A maintainer will coordinate. |
There was a problem hiding this comment.
Reviewed the release-service envelope encryption PR statically. This is a focused, well-structured security addition: AES-256-GCM with HKDF-SHA-256 purpose keys, compact versioned JSON envelope, authenticated context covering key version/purpose/table/row ID/owner DID, strict keyring and envelope parsing, old-key reads, idempotent authenticated rotation, non-leaking errors, and binding-based secret injection.
I traced the changed code end-to-end and checked it against the release-service conventions and the repo’s AGENTS.md guidance that applies here. Key observations:
- Key derivation, AEAD parameters, and additional-data binding are correct. The HKDF salt is versioned/fixed; the IKM is a random 32-byte key, so a public salt is acceptable.
- Envelope parsing rejects malformed JSON, extra/duplicate/missing keys, non-canonical serialization, bad lengths, padding, and unsupported versions before any crypto work.
- Context validation correctly enforces owned/unowned/optional-owner semantics and snapshots the context synchronously before async key derivation.
- Old keys remain available for decrypt/rotation; rotation decrypts first and is idempotent when already on the current key.
- Configuration loading fails closed with a distinct
ENCRYPTION_KEYRING_INVALIDissue and no exposure of key material. - Tests were added for round-trips, old-key reads, rotation idempotency, context binding, oversize plaintext, invalid keyrings/envelopes, and runtime mutation of plaintext/context.
- Changeset not needed because only the private
release-serviceapp changed. No admin UI, so Lingui/RTL conventions do not apply. No SQL/locale/API-authorization changes.
I did not find any blocking bugs, regressions, or convention violations. This looks ready to merge.
What does this PR do?
Implements W3.1 application-level encryption for release-service custody data. The versioned compact envelope uses AES-256-GCM with HKDF-SHA-256 purpose keys and authenticated context covering the key version, purpose, table, row ID, and owner DID where available.
Adds strict keyring and envelope validation, old-key reads, idempotent authenticated rotation, bounded inputs, stable non-leaking failures, and a required
ENCRYPTION_KEYRINGWorker secret. Validated configuration is passed into route handlers for the upcoming D1 custody slices.Part of #1908.
Type of change
Checklist
pnpm typecheckpassespnpm lintpassespnpm testpasses (or targeted tests for my change)pnpm formathas been runAI-generated code disclosure
Screenshots / test output
Non-visual change. Verified:
pnpm buildbeforepnpm typecheckpnpm lint,pnpm lint:json, andpnpm formatTry this PR
Open a fresh playground →
A full working EmDash site, deployed from this branch. Each visit gets its own session-scoped sandbox: no login needed and no shared state. Try the admin, edit content, hit the public site.
Tracks
feat/delegated-release-service-17-encryption. Updated automatically when the playground redeploys.