Skip to content

feat(secrets): S2 — SOPS+age provider (offline default) - #31

Merged
gustavobertoi merged 1 commit into
mainfrom
nightly/S2
Jun 29, 2026
Merged

feat(secrets): S2 — SOPS+age provider (offline default)#31
gustavobertoi merged 1 commit into
mainfrom
nightly/S2

Conversation

@gustavobertoi

Copy link
Copy Markdown
Contributor

Chunk S2 (M4)

The offline, no-account "works on a plane" provider — a secrets.Provider decrypting via the sops binary (not the getsops Go SDK, which pulls every cloud-KMS SDK and bloats the static binary).

  • SopsProvider.Resolve groups refs by file and runs sops -d --output-type json <file> once per file (batch), then extracts each ref's dot-path key from the JSON. SOPS_AGE_KEY_FILE is set from the provider config.
  • SopsFactory + RegisterBuiltins(reg) wire it under kind sops (AWS/Infisical register additively, S3/S4). Missing binary / missing key → clear errors.
  • lookupPath walks nested maps, stringifies scalar leaves.

Tests

Fake runner: batch-per-file (2 refs → 1 decrypt), missing-key error, sops-absent error, factory wiring, lookupPath nested/scalar/missing. (sops isn't on the local/CI runner yet; the standard -d --output-type json path + S6's no-leak test exercise it end-to-end once sops is installed.)

Gate

make ci green (race).

🤖 Generated with Claude Code

The "works on a plane" provider: a secrets.Provider that decrypts via the `sops`
binary (NOT the getsops Go SDK, which pulls every cloud-KMS SDK and bloats the
static binary — DECISIONS).

- SopsProvider.Resolve groups refs by file and runs `sops -d --output-type json
  <file>` ONCE per file (batch), then extracts each ref's dot-path key from the
  decrypted JSON. SOPS_AGE_KEY_FILE is set from the provider config so the age
  identity is found regardless of platform default key paths.
- SopsFactory + RegisterBuiltins(reg) wire it under kind "sops"; AWS/Infisical
  register additively (S3/S4). Missing binary / missing key are clear errors.
- lookupPath walks nested maps and stringifies scalar leaves.

Unit-tested with a fake runner: batch-per-file (2 refs → 1 decrypt), missing-key
error, sops-absent error, factory wiring (ageKeyFile), lookupPath nested/scalar/
missing. The real `sops` path is standard `-d --output-type json`; a sops-in-CI
integration + the S6 no-leak test exercise it end to end once sops is on the
runner.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@gustavobertoi
gustavobertoi merged commit 99d3b67 into main Jun 29, 2026
2 checks passed
@gustavobertoi
gustavobertoi deleted the nightly/S2 branch June 29, 2026 15:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant