docs: multi-recipient age encryption (recipients/reencrypt) + bump 0.6.2.0 (EGB-283)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
b09f94c92f
commit
f7576a3eae
5 changed files with 125 additions and 7 deletions
25
CLAUDE.md
25
CLAUDE.md
|
|
@ -16,7 +16,7 @@ cd ~/my-project && ./secrets pull # Pull + decrypt .env* files
|
|||
|
||||
```bash
|
||||
brew install bats-core
|
||||
bats test/ # runs secrets.bats + manifest.bats + migrate.bats
|
||||
bats test/ # runs secrets.bats + manifest.bats + migrate.bats + recipients.bats
|
||||
./test/run-security.sh # security regression subset + operator sign-off (see below)
|
||||
```
|
||||
|
||||
|
|
@ -56,7 +56,7 @@ skips security specialist + red team, and Step 11 skips adversarial review.
|
|||
|
||||
## Architecture
|
||||
|
||||
Single bash script (`secrets`) with subcommands: init, push, pull, list, rm, rekey, verify, migrate.
|
||||
Single bash script (`secrets`) with subcommands: init, push, pull, list, rm, rekey, verify, migrate, recipients, reencrypt.
|
||||
|
||||
- Encryption: `age` with key files (not passphrases — age passphrases are non-scriptable)
|
||||
- Storage: Private git repo at `~/.secrets/`
|
||||
|
|
@ -67,6 +67,24 @@ Single bash script (`secrets`) with subcommands: init, push, pull, list, rm, rek
|
|||
- External files: `.secrets-files` manifest tracks designated keys from files outside the project (e.g. `~/.gradle/gradle.properties`, merged not overwritten — EGB-531) and whole binary files (type `file`, e.g. an Android upload keystore — EGB-652); see below
|
||||
- Workspaces: `--workspaces` flag reads `package.json` workspaces, requires `jq`
|
||||
- Safety: Pre-commit hook rejects plaintext secret files (`.env`, `.dev.vars`, `gradle.properties`)
|
||||
- Multi-recipient (EGB-283): a store-scoped, committed `recipients.txt` (age `-R`
|
||||
format, `# name` comments) lets one store encrypt every blob to N age keys —
|
||||
one per team member. Managed via `secrets recipients add/rm/list`; absence of
|
||||
the file ⇒ legacy single-key behavior (recipients = the pubkey derived from
|
||||
`key.txt`). The file is parsed by us (never `age -R <path>`) into a validated
|
||||
`RECIPIENT_ARGS` array (native age X25519 only, `age1[0-9a-z]{58}`; SSH
|
||||
recipients rejected; symlinked file refused) — same conservative posture as
|
||||
`.secrets-store`/`.secrets-files`. `_load_recipients` populates the array;
|
||||
every encrypt site routes through it. Any recipient change re-encrypts the
|
||||
WHOLE store in one commit via the shared `_reencrypt_all` engine (also used by
|
||||
the new `secrets reencrypt` and by `rekey` on a multi-recipient store, where
|
||||
rekey re-encrypts to the set with NO new keypair; legacy stores keep rekey's
|
||||
generate-new-keypair behavior). `init` seeds `recipients.txt` born-multi.
|
||||
`which` prints `recipients: N`; `verify`/`verify --all` assert each blob's
|
||||
age recipient-stanza count equals `recipients.txt`'s length. Removal takes
|
||||
effect going forward — git history stays readable by an old key, so rotate
|
||||
genuinely-sensitive values. Decryption is unchanged (each member uses their
|
||||
own `key.txt`).
|
||||
- Portability: must run on system bash 3.2 (macOS) — no associative arrays or bash-4 features
|
||||
|
||||
## Project Structure
|
||||
|
|
@ -77,7 +95,8 @@ hooks/pre-commit # Pre-commit hook template
|
|||
test/
|
||||
secrets.bats # bats-core test suite (133 tests)
|
||||
manifest.bats # EGB-677 .secrets.json manifest tests (78 tests)
|
||||
migrate.bats # EGB-703 store-format-v2 migration tests (26 tests)
|
||||
migrate.bats # EGB-703 store-format-v2 migration tests (31 tests)
|
||||
recipients.bats # EGB-283 multi-recipient age encryption tests (30 tests)
|
||||
test_helper.bash # Shared setup/teardown
|
||||
README.md # User-facing documentation
|
||||
CLAUDE.md # This file
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue