Introduces an age-encrypted secrets.age file (committed to the repo) as a single source of truth for all production secrets
Only one secret needs to be stored in CI: SECRETS_AGE_KEY (the age private key)
When a secret changes locally, re-run scripts/secrets-encrypt.sh and commit the new secrets.age — CI gets the update on next push with no manual variable editing
The deploy workflow now has a single "Decrypt production secrets" step instead of N individual secret references
## Summary
- Introduces an age-encrypted `secrets.age` file (committed to the repo) as a single source of truth for all production secrets
- Only one secret needs to be stored in CI: `SECRETS_AGE_KEY` (the age private key)
- When a secret changes locally, re-run `scripts/secrets-encrypt.sh` and commit the new `secrets.age` — CI gets the update on next push with no manual variable editing
- The deploy workflow now has a single "Decrypt production secrets" step instead of N individual secret references
## How to migrate
1. Generate a key pair once: `age-keygen -o ~/.config/age/sharedinbox.key && age-keygen -y ~/.config/age/sharedinbox.key > .age-public-key`
2. Copy `secrets.env.example` to `secrets.env`, fill in values
3. Encrypt: `scripts/secrets-encrypt.sh`
4. Commit `secrets.age` and `.age-public-key`
5. Add the private key content to Codeberg as `SECRETS_AGE_KEY` secret
## Test plan
- [ ] `bash scripts/test_secrets.sh` passes (17 tests: encrypt/decrypt round-trip, multi-line values, GITHUB_ENV output, error cases)
- [ ] Pre-commit hooks pass (all checks including `detect-private-key`)
- [ ] `CheckSecrets` function added to Dagger `Check()` pipeline — runs in CI via `task check-dagger`
- [ ] Deploy workflow uses `SECRETS_AGE_KEY` exclusively for production secrets; Dagger access creds unchanged
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
secrets.agefile (committed to the repo) as a single source of truth for all production secretsSECRETS_AGE_KEY(the age private key)scripts/secrets-encrypt.shand commit the newsecrets.age— CI gets the update on next push with no manual variable editingHow to migrate
age-keygen -o ~/.config/age/sharedinbox.key && age-keygen -y ~/.config/age/sharedinbox.key > .age-public-keysecrets.env.exampletosecrets.env, fill in valuesscripts/secrets-encrypt.shsecrets.ageand.age-public-keySECRETS_AGE_KEYsecretTest plan
bash scripts/test_secrets.shpasses (17 tests: encrypt/decrypt round-trip, multi-line values, GITHUB_ENV output, error cases)detect-private-key)CheckSecretsfunction added to DaggerCheck()pipeline — runs in CI viatask check-daggerSECRETS_AGE_KEYexclusively for production secrets; Dagger access creds unchanged🤖 Generated with Claude Code