feat: add --store-sops-age-key flag to allow secret creation - #76
Conversation
There was a problem hiding this comment.
🟢 Approval recommended
The feature is implemented end-to-end with CLI wiring, k8s client support, tests, and docs; remaining feedback is limited to minor error-message/diagnostic improvements.
Pull request overview
Adds an opt-in bootstrap flag to persist the configured SOPS age private key into the cluster as an argocd/sops-age-key Secret so ArgoCD repo-server (e.g., via helm-secrets) can decrypt SOPS-encrypted Helm values in-cluster.
Changes:
- Add
--store-sops-age-keyflag and bootstrap flow to read the age key file and create/updateargocd/sops-age-key. - Add Kubernetes client support + mock + unit test for creating/updating the
sops-age-keySecret. - Update README and CLI bootstrap docs with usage and updated bootstrap step list.
File summaries
| File | Description |
|---|---|
| README.md | Documents the new bootstrap option and updates the “This will” step list. |
| docs/cli/bootstrap.md | Adds the new flag to CLI docs and provides an example invocation. |
| cluster-bootstrap-cli/internal/k8s/secrets.go | Implements CreateSopsAgeKeySecret to create/update argocd/sops-age-key. |
| cluster-bootstrap-cli/internal/k8s/secrets_test.go | Adds idempotency tests for the new Secret creation/update behavior. |
| cluster-bootstrap-cli/internal/k8s/client_mock.go | Extends the mock client + interface to support CreateSopsAgeKeySecret. |
| cluster-bootstrap-cli/cmd/bootstrap.go | Wires --store-sops-age-key into the bootstrap execution path. |
| cluster-bootstrap-cli/cmd/bootstrap_test.go | Verifies the new flag defaults to opt-in (false). |
Review details
- Files reviewed: 7/7 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
🟡 Changes recommended
There is an error-handling bug in runBootstrap where the wrapped bootstrapErr is not returned/reported, causing loss of context and inconsistent stage reporting.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
- Files reviewed: 7/7 changed files
- Comments generated: 1
- Review effort level: Lite
There was a problem hiding this comment.
🔵 Needs a closer look
The implementation looks sound, but the updated CLI docs are ambiguous/misleading about when secrets are created, and the #nosec suppression format may be inconsistent with the repo’s existing lint conventions.
Review details
Suppressed comments (3)
Previously missed (3) — in code that hasn't changed since the last review.
docs/cli/bootstrap.md:60
--age-key-fileis documented as “(SOPS only)”, but it’s also required to supply the key data for--store-sops-age-keyeven when--encryption git-cryptis used. Update the flag descriptions to avoid misleading users.
| `--age-key-file` | `SOPS_AGE_KEY_FILE` env | Path to age private key (SOPS only) |
| `--store-sops-age-key` | `false` | Store the age private key from `--age-key-file` (or `SOPS_AGE_KEY_FILE`) as `sops-age-key` in `argocd`. Use when ArgoCD decrypts SOPS values in-cluster. |
cluster-bootstrap-cli/cmd/bootstrap.go:575
- The
#nosecdirective here uses a comma-separated list (G304,G703), while other suppressions in this repo use a single rule ID. To reduce the chance of the directive not being recognized by your security/lint tooling, keep it consistent and only suppress the rule that applies to this call site.
// The path is deliberately provided by the operator through a CLI flag or
// SOPS_AGE_KEY_FILE; bootstrap must support age keys stored outside the repo.
keyData, err := os.ReadFile(ageKeyFile) // #nosec G304,G703 -- explicit operator-controlled key path
if err != nil {
return false, fmt.Errorf("read SOPS age key file %s: %w", ageKeyFile, err)
docs/cli/bootstrap.md:19
- The step list is a bit ambiguous about when each Secret is created; as written it can read like
sops-age-keyis always created during SOPS bootstrap. Clarify the exact flags/conditions so the docs match the implementation.
1. Loads secrets — decrypts via SOPS (default) or reads plaintext git-crypt files
2. Creates the `argocd` namespace
3. Creates the `repo-ssh-key` Secret with Git SSH credentials
4. Optionally creates `git-crypt-key` or `sops-age-key` Secrets for in-cluster decryption
5. When `--enable-cilium` is set, installs or upgrades Cilium and waits for Helm's workload readiness checks to pass
- Files reviewed: 7/7 changed files
- Comments generated: 0 new
- Review effort level: Lite
# [1.9.0](v1.8.0...v1.9.0) (2026-08-29) ### Features * add --store-sops-age-key flag to allow secret creation ([#76](#76)) ([a914a52](a914a52))
Add --store-sops-age-key to store the configured age private key as argocd/sops-age-key during bootstrap, allowing ArgoCD repo-server to decrypt SOPS-encrypted Helm values in-cluster. Update tests and bootstrap documentation.