This repository is helm-secrets, a Helm plugin implemented mostly in POSIX shell. It decrypts Helm value files on demand, supports secret references through multiple backends, and integrates with Helm downloader and post-renderer plugin mechanisms.
plugin.yamlis the Helm 3 plugin manifest. It registers thesecretscommand and downloader protocols.plugins/helm-secrets-cli,plugins/helm-secrets-getter, andplugins/helm-secrets-post-renderercontain Helm 4 plugin manifests. Helm 4 currently treats CLI, getter, and post-renderer plugins as separate plugin types, so these manifests are split even though Helm 3 can declare the command and downloader protocols together inplugin.yaml. Keep versions and user-facing help synchronized withplugin.yamlandscripts/commands/help.sh.scripts/run.shis the main plugin entrypoint. It initializes globals, loads libraries/backends, parses top-levelhelm secretsoptions, then dispatches to command scripts.scripts/commands/contains subcommands and Helm integration:encrypt.sh,decrypt.sh,edit.shimplement direct file operations.helm.shwraps arbitrary Helm commands, decrypts-f,--values,--set-file, and decrypts literals in--set,--set-string, and--set-json.downloader.shimplementssecrets://,secrets+gpg-import://,secrets+gpg-import-kubernetes://,secrets+age-import://,secrets+age-import-kubernetes://, andsecrets+literal://.post-renderer.shevaluatesvalsreferences in rendered manifests when--evaluate-templatesis enabled.help.shandversion.shprovide user-facing CLI output.
scripts/lib/contains shared shell functions for logging, traps, path handling, backend dispatch, file retrieval, HTTP downloads, and strict variable expansion.scripts/lib/backends/contains in-tree backends:sops.shis the default backend. It can encrypt, decrypt, edit, and detect SOPS-encrypted content.vals.shresolvesref+...references. It does not support encrypt or edit.noop.shpasses files through for tests and non-encrypted workflows._custom.shis a helper contract for out-of-tree backends.
scripts/lib/file/abstracts value source retrieval:local.shhandles normal files.http.shdownloadshttp://andhttps://values withcurlorwget.custom.shdelegates arbitrary*://sources to Helm through a tiny chart inhelm-values-getter.
scripts/wrapper/contains wrapper scripts for Windows and optional automatichelm secretsforwarding.docs/is the wiki-style documentation source. Update docs when CLI flags, environment variables, security behavior, or integration behavior changes.examples/contains sample charts and backend scripts for SOPS, vals, Argo CD, Terraform, and custom backends.tests/contains first-party Bats tests and assets.tests/bats/is vendored/submodule test tooling; do not edit it unless intentionally updating submodules.
- Helm invokes
scripts/run.shthrough a plugin manifest. run.shsetsHELM_BIN,SCRIPT_DIR,TMPDIR, default backend (sops), quiet mode, decrypted file naming settings, and feature flags fromHELM_SECRETS_*environment variables.- It loads
common.sh,expand_vars_strict.sh,file.sh,backend.sh, andhttp.sh, then callsload_secret_backend. - Top-level arguments are parsed before dispatch. Global flags such as
--backend,--backend-args,--quiet,--ignore-missing-values,--evaluate-templates, and--decrypt-secrets-in-tmp-diraffect later command behavior. - Direct commands call backend helpers through
backend.sh. Wrapped Helm commands sourcecommands/helm.sh. helm_wrapperrewrites Helm arguments:- For
-f/--values, it fetches the source, decrypts encrypted files into.decfiles or temp files, and passes decrypted paths to Helm. - For
secrets://...values, prefer passing the protocol URL through to Helm so Helm's downloader plugin handles it directly. Avoid resolvingsecrets://through_file_getin the wrapper unless there is a specific compatibility reason and regression coverage for trailing newlines. - For
--set-file, it decrypts file contents and preserves Helm key prefixes. - For
--set,--set-string, and--set-json, it resolves encrypted literal values and preserves escaped commas, lists, and trailing newlines. - It records generated decrypted files and removes them in
_trap_hook.
- For
- Downloader protocol handling in
downloader.shprints decrypted content to stdout for Helm downloader usage. Key-import protocols initialize temporary GPG homes orSOPS_AGE_KEY_FILEbefore decrypting. - If template evaluation is enabled,
helm.shinjects a Helm post-renderer. Helm 3 invokeshelm secrets post-renderer; Helm 4 uses the separatesecrets-post-rendererplugin because Helm 4 plugin types are split.
Backends are dispatched by name through functions in scripts/lib/backend.sh. A backend named foo must provide:
_foo_backend_is_file_encrypted FILE_foo_backend_is_encryptedreading stdin_foo_backend_encrypt_file TYPE INPUT OUTPUT_foo_backend_decrypt_file TYPE INPUT [OUTPUT]_foo_backend_decrypt_literal VALUE_foo_backend_edit_file TYPE INPUT
In-tree backend selection accepts sops, vals, and noop. Out-of-tree backends can be loaded by file path through --backend or HELM_SECRETS_BACKEND; they normally source scripts/lib/backends/_custom.sh. HELM_SECRETS_ALLOWED_BACKENDS restricts allowed backend names and is tested by the suite.
Backend-specific binary overrides:
HELM_SECRETS_SOPS_PATHor legacyHELM_SECRETS_SOPS_BINHELM_SECRETS_VALS_PATHHELM_SECRETS_CURL_PATHHELM_SECRETS_WGET_PATHHELM_SECRETS_KUBECTL_PATH
HELM_SECRETS_BACKEND,HELM_SECRETS_BACKEND_ARGS,HELM_SECRETS_ALLOWED_BACKENDSHELM_SECRETS_QUIET; defaults totruein Argo CD whenARGOCD_APP_NAMEis presentHELM_SECRETS_DEC_PREFIX,HELM_SECRETS_DEC_SUFFIX,HELM_SECRETS_DEC_DIR,HELM_SECRETS_DEC_TMP_DIRHELM_SECRETS_IGNORE_MISSING_VALUESHELM_SECRETS_EVALUATE_TEMPLATES,HELM_SECRETS_EVALUATE_TEMPLATES_DECODE_SECRETSHELM_SECRETS_DECRYPT_SECRETS_IN_TMP_DIRHELM_SECRETS_LOAD_GPG_KEYSHELM_SECRETS_URL_VARIABLE_EXPANSIONHELM_SECRETS_VALUES_ALLOW_SYMLINKS,HELM_SECRETS_VALUES_ALLOW_ABSOLUTE_PATH,HELM_SECRETS_VALUES_ALLOW_PATH_TRAVERSALHELM_SECRETS_ALLOW_GPG_IMPORT,HELM_SECRETS_ALLOW_GPG_IMPORT_KUBERNETES,HELM_SECRETS_ALLOW_AGE_IMPORT,HELM_SECRETS_ALLOW_AGE_IMPORT_KUBERNETESHELM_SECRETS_KEY_LOCATION_PREFIXHELM_SECRETS_WRAPPER_ENABLED,HELM_SECRETS_HELM_PATH,HELM_SECRET_WSL_INTEROP
When adding a user-visible variable, update scripts/commands/help.sh, Helm 4 CLI help in plugins/helm-secrets-cli/plugin.yaml, docs, and tests.
- First-party plugin scripts under
scripts/are POSIXsh, not Bash. They are tested under dash, ash, bash-as-sh, zsh-as-sh, posh, macOS/bin/sh, Cygwin, and WSL. - Avoid Bash-only syntax in
scripts/**/*.sh: no arrays,[[ ]], process substitution,local,${var//...}, orpipefail. - Files under
tests/, including Bats tests and test helpers, may use Bash syntax because the test suite runs under Bash/Bats. - Preserve careful quoting. This project handles paths with spaces, special characters, Windows paths, WSL path conversion, escaped commas, Helm set lists, and trailing newlines.
- Be cautious with command substitutions: POSIX shells strip trailing newlines. Existing code uses sentinel characters where preserving newlines matters.
pipefailis not available in POSIXsh, so command substitutions need extra care. Multiple commands inside$()are dangerous because only the last command controls the substitution exit code. If a later command must run after a checked command, preserve the status explicitly, for example$(cmd; status=$?; cmd2; exit "$status"). This pattern may not work the same way with pipelines because pipeline status is also limited withoutpipefail.- Do not rely on GNU-only tools unless guarded. macOS
sed -idiffers; use_sed_i. - Keep generated decrypted files cleaned up via traps. Avoid leaving
.decfiles outside explicit inline operations. - Do not edit vendored
tests/bats/**unless the task is to update Bats submodules.
scripts/lib/file.shenforces optional restrictions on symlinks, absolute paths, and..path traversal.scripts/commands/downloader.shcontrols whether GPG/age key imports and Kubernetes key imports are allowed.HELM_SECRETS_KEY_LOCATION_PREFIXrestricts key file locations for import protocols.scripts/lib/file/http.shcan expand environment variables inside URLs only whenHELM_SECRETS_URL_VARIABLE_EXPANSION=true; keep this opt-in.- Avoid logging decrypted secret values. Many tests assert quiet behavior and cleanup.
Use the vendored Bats runner when Bats is not installed:
bash tests/bats/core/bin/bats -r tests/unitRun backend-specific unit suites:
HELM_SECRETS_BACKEND=sops bash tests/bats/core/bin/bats -r tests/unit
HELM_SECRETS_BACKEND=vals bash tests/bats/core/bin/bats -r tests/unitIntegration tests require a reachable Kubernetes cluster:
bash tests/bats/core/bin/bats -r tests/itFocused tests are usually enough while iterating, for example:
bash tests/bats/core/bin/bats tests/unit/template.bats
bash tests/bats/core/bin/bats tests/unit/secret-backends.batsWhen changing wrapper handling for --set, --set-string, --set-json, --set-file, or downloader protocols, run at least one focused vals backend test as well as the default sops path. The default backend skips several vals-specific literal/reference tests, so a local green run with only sops can miss CI failures.
The test suite installs this repo as a Helm plugin into a temporary Helm home, imports test GPG keys from tests/assets/gpg, creates charts under tests/.tmp/cache, and copies value assets into each test temp directory. Unit tests do not require Kubernetes; integration tests cover install/upgrade/diff paths and Kubernetes key-import protocols.
Before running Bats, make sure a gpg-agent is running for the test GPG operations. Terminate it after the tests, for example with gpgconf --kill gpg-agent, so test state does not leak into later runs.
CI runs shell linting and checkbashisms, then unit tests across Linux, macOS, Windows, Cygwin, WSL, multiple shells, Helm 3 and Helm 4, SOPS, and vals. Coverage rewrites env sh to env bash only for bashcov; do not copy that pattern into normal code.
The current CI version pins are in .github/workflows/ci.yaml.
- Keep behavior changes tightly scoped and add/adjust Bats tests near the affected behavior.
- Before committing, run
shfmtandshellcheckon changed shell files. - For new features or bug fixes only, add a line to
CHANGELOG.md. - For CLI behavior, update both Helm 3 and Helm 4 manifests/help text when needed.
- For backend changes, update
docs/Secret Backends.mdand backend tests. - For downloader protocol or Argo CD behavior, update
docs/ArgoCD Integration.md,docs/ARGOCD.md, and relevant template/install tests. - For security defaults or restrictions, update
docs/Security in shared environments.mdand tests aroundHELM_SECRETS_VALUES_ALLOW_*or key import flags. - Maintain LF endings except
scripts/wrapper/run.cmd, which uses CRLF per.editorconfig. - Do not commit generated decrypted files, coverage output, or
tests/.tmpartifacts.