Resolve open design questions: write-scoped grants, rollback, purge
Per-question resolution, per best practice rather than deferral: - Push authorization: closed the least-privilege gap where read implied write. vault_grants gained can_write (default true, so nothing existing changes); enforced on push and grant (granting others is itself a mutation of vault membership, so it needs write too, not just read). 'keep grant --read-only' creates a read-only grant. - Version history: not full history (conflates "undo a typo'd push" with "this leaked, stop retaining it" into one mechanism). Retains exactly one previous version as a rollback safety net (vaults.prev_ciphertext/prev_nonce + a vault_grants_previous mirror table so recipients can unwrap it), plus 'keep push --purge' for compromise-driven rotations that explicitly skips retention and wipes any existing previous version too. - Per-secret-key granularity: resolved by NOT building it — documented the escape hatch (split into more vaults) instead of adding partial- decrypt complexity for a problem the existing primitive solves. One more real bug caught during verification: the CLI's --previous flag initially signed a path including its query string, but the server verifies against req.originalUrl with the query stripped — a mismatch that would have made every --previous request fail signature verification. Fixed by splitting the signed path from the request URL in signedFetch, signing only the former. Verified end-to-end with three independent identities: read-only grant correctly blocked from push and from granting others, write access and read-only status both preserved correctly across a rotation, previous- version pull working for a routine push and correctly unavailable to every recipient after a purge push. Also re-verified against a fresh Docker build. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
36
README.md
36
README.md
@@ -102,20 +102,34 @@ npm run cli -- pull myapp/production > .env
|
||||
|
||||
```bash
|
||||
# An existing recipient of a vault can grant a NEW recipient access,
|
||||
# without needing admin rights or re-encrypting the payload:
|
||||
# without needing admin rights or re-encrypting the payload. Read access
|
||||
# by default — add --read-only for a recipient that should only ever
|
||||
# pull, never push (e.g. an automated deploy identity):
|
||||
keep grant myapp/production <new-recipient-id>
|
||||
keep grant myapp/production <deploy-recipient-id> --read-only
|
||||
|
||||
# Revoking is an admin operation — pure metadata deletion, immediate:
|
||||
KEEP_ADMIN_PASSWORD=... keep revoke myapp/production <recipient-id>
|
||||
|
||||
# Revoke only stops FUTURE pulls. If this was a compromise response,
|
||||
# also rotate the actual values:
|
||||
# rotate AND purge — --purge skips retaining the outgoing version as a
|
||||
# rollback, since the whole point of rotating for a leak is that the old
|
||||
# value stops being retrievable by anyone:
|
||||
keep push myapp/production --file .env.production --purge
|
||||
|
||||
# A routine push (no compromise involved) keeps the outgoing version as
|
||||
# a one-step rollback safety net:
|
||||
keep push myapp/production --file .env.production
|
||||
keep pull myapp/production --previous # "oops, undo that last push"
|
||||
|
||||
# See who's touched a vault and when:
|
||||
keep log myapp/production
|
||||
```
|
||||
|
||||
Pushing to an existing vault requires a *write* grant — a read-only
|
||||
recipient can pull but can't push or grant others access. A brand-new
|
||||
vault's first push is always read-write for the pusher.
|
||||
|
||||
## Docker
|
||||
|
||||
```bash
|
||||
@@ -150,13 +164,17 @@ CLI-side: `KEEP_SERVER_URL` (default `http://localhost:3050`),
|
||||
|
||||
## Status
|
||||
|
||||
Implemented: identity, push/pull/grant/revoke/log, admin recipient
|
||||
management, Docker deploy. Verified end-to-end (two independent
|
||||
identities, grant, pull, revoke persisting through a subsequent
|
||||
rotation, malformed-auth rejection) against both a local server and the
|
||||
built Docker image. See [IMPLEMENTATION.md](./IMPLEMENTATION.md) for the
|
||||
full design and its still-open questions (version history, per-secret-key
|
||||
granularity).
|
||||
Implemented: identity, push/pull/grant/revoke/log, read/write grant
|
||||
scoping, one-step rollback with an explicit purge mode for
|
||||
compromise-driven rotations, admin recipient management, Docker deploy.
|
||||
Verified end-to-end — two and three independent identities, read-only
|
||||
grants correctly blocked from push/grant, grants preserved across
|
||||
rotation, previous-version pull working and correctly wiped by
|
||||
`--purge` for every recipient, malformed-auth rejection — against both
|
||||
a local server and the built Docker image. See
|
||||
[IMPLEMENTATION.md](./IMPLEMENTATION.md) for the full design and its
|
||||
resolved decisions (per-secret-key granularity deliberately not built —
|
||||
use multiple vaults instead).
|
||||
|
||||
## License
|
||||
|
||||
|
||||
Reference in New Issue
Block a user