feat(secrets): secrets ingest — .env → SOPS/provider secrets + vars (spec 24) - #82
Merged
Conversation
… (spec 24) Add the write half of the secrets boundary and a new envingest pipeline that gets committed .env files out of the repo: - internal/secrets: Pusher capability (SecretEntry/Pusher) on aws-sm/aws-ssm/ infisical (values via stdin/env, never logged argv), a stdin-capable runner (OutputStdin), and SOPS encrypt/decrypt helpers that shell `sops` over stdin (no Go SDK, no plaintext temp file). - internal/envingest: parse (compose-go dotenv) → classify default-deny (glob → name → value heuristics → benign → default secret) → route (sops file / remote Pusher) → encrypt/push → compute secret:// refs → rewrite the target devstack.yaml env block in place via the goccy AST (comment/order preserving) → scaffold a sops provider into workspace.yaml when absent → round-trip verify before deleting → fence .env in .gitignore → delete (or --keep-env). Idempotency via decrypt-and-compare; no flock. - internal/cli: `secrets ingest [<.env>]` with --to/--dest/--service/ --recipient/--secret/--public/--from-host/--prefixed/--keep-env/--dry-run/ --yes/--force/--json + a degradable huh v2 classification wizard gated on prompt.IsInteractive. - Tests: Pusher argv/stdin per provider, classify ladder, AST rewrite/scaffold, full-run leak test, git-tracked refusal, dry-run writes nothing, decrypt- compare idempotency, non-TTY gate routes to the flag path. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements feature #16 / spec 24 —
.envingestion. Built in a parallel worktree, integrated + verified locally (make ci+ determinism green, dry-run smoke-tested).What's here
secrets.Pusher(new write capability;Providerwas Resolve-only):Pushon aws-sm (put-secret-value), aws-ssm (put-parameter --type SecureString), infisical (secrets set) — values via stdin/env, never argv. A stdin-capable runner +SopsEncryptYAML/SopsDecryptBytes(shellsops, no Go SDK, no plaintext temp file).internal/envingest(new): parse (compose-go/v2/dotenv) → classify default-deny (glob → name-token → value-heuristic ladder) → route (SOPS+age default /--to aws-sm|infisical) → encrypt/push → goccy-AST in-placedevstack.yamlrewrite (comment/order-preserving; secrets→secret://refs, non-secrets→inline literals,--from-host→${env}) → scaffold asopsprovider intoworkspace.yaml→ round-trip-resolve before delete →.gitignorefence → delete.env. Decrypt-and-compare idempotency; git-tracked.envrefused; no flock.secrets ingest(internal/cli/secrets_ingest.go): full flag surface (--to/--dest/--service/--recipient/--secret/--public/--from-host/--prefixed/--keep-env/--dry-run/--yes/--force/--json) + a degradable huh v2 classification wizard.Verified
make ci+make determinismgreen; CGO=0 cross-build clean. No-plaintext leak-test (TestRunNoSecretLeak) walks every written file + backups asserting no original secret value. Smoke:secrets ingest .env --dry-runclassifies (DB_PASSWORD/STRIPE_SECRET_KEY→secret,APP_ENV/PORT→config), shows the SOPS destination, writes nothing.Note: end-to-end SOPS encrypt/AWS/Infisical pushes are exercised via mock runners (no
sops/aws/infisicalbinary or creds in CI); a hands-on run with a realsopsinstall is worth a check.🤖 Generated with Claude Code