Repository navigation
fix(config): bind SP_ENCRYPTION_MASTER_KEY so credentials stop being stored in plaintext - #276
Merged
Merged
Conversation
…stored in plaintext The env provider lowercases and turns every underscore after SP_ into a dot, so SP_ENCRYPTION_MASTER_KEY arrived as "encryption.master.key" and never reached the koanf tag "master_key". Nothing bound it, so the credentials service stayed in disabled mode - and its own remediation message told the operator to set exactly the variable that did not work. Every other multi-word key already has a hand-written applyXxxEnv helper (ACME, rate limiting, PostHog, WhatsApp, scheduling...). Encryption never got one. This adds applyEncryptionEnv for MASTER_KEY, MASTER_KEY_FILE and AUTO_MIGRATE, and registers the three names in manualReaderEnvVars. Three assertions are inverted rather than deleted, because they were right when written: TestRecognizedEnvVars and the envcheck test both asserted the names were NOT recognized, with comments warning that registering them would paper over the bug. The bug is fixed at the source, so recognition now states a fact. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
fclairamb
enabled auto-merge (squash)
August 27, 2026 21:45
Merged
fclairamb
added a commit
that referenced
this pull request
Aug 28, 2026
🤖 I have created a release *beep* *boop* --- ## [0.19.1](v0.19.0...v0.19.1) (2026-08-28) ### Bug Fixes * **config:** bind SP_ENCRYPTION_MASTER_KEY so credentials stop being stored in plaintext ([#276](#276)) ([15615ad](15615ad)) * **deps:** update github.com/dop251/goja digest to 8f1c069 ([#275](#275)) ([550ed79](550ed79)) * **email:** link the check page in incident emails instead of the down host ([#274](#274)) ([0daaf40](0daaf40)) * name the license file LICENSE so pkg.go.dev detects it ([#272](#272)) ([f11d7b6](f11d7b6)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please).
This was referenced Sep 8, 2026
Closed
Closed
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.
The bug
SP_ENCRYPTION_MASTER_KEYnever bound anything. koanf's env provider lowercasesthe name and turns every underscore after
SP_into a dot, so it arrived asencryption.master.keywhile the tag ismaster_key. The credentials servicetherefore stayed in disabled mode and stored secrets in plaintext — while
logging a remediation message naming the exact variable that does not work:
Both lines, same boot, in production. The warning was right and the advice it
contradicted was not.
This is not a new class of problem — it is
project_koanf_env_quirk, and everyother multi-word key already has a hand-written helper:
applyACMEEnv,applyRateLimitingEnv,applyPostHogEnv,applyWhatsAppEnv,applySchedulingEnv,applyEntitlementsEnv. Encryption is the one that nevergot written, and it is the one where the failure mode is silent plaintext
storage rather than a knob that stays at its default.
The fix
applyEncryptionEnvforSP_ENCRYPTION_MASTER_KEY,SP_ENCRYPTION_MASTER_KEY_FILEandSP_ENCRYPTION_AUTO_MIGRATE, called next toapplyACMEEnv, with the three names registered inmanualReaderEnvVarsso thestartup check stops reporting a variable that now binds.
Three inverted assertions, and why they are not being silenced
TestRecognizedEnvVarsandTestCheckEnvironEncryptionMasterKeyWarnsbothasserted these names were not recognized, and both carried a comment saying
that registering them would paper over the bug. That was exactly right while the
binding was broken. The binding is fixed here, so recognition now states a fact
instead of hiding one — the assertions are inverted with that reasoning written
into them, not deleted.
envcheck's package doc, which usedSP_ENCRYPTION_MASTER_KEYas its standing example of a documented-but-unboundname, is updated for the same reason.
Operational note for the hosted deployment
AutoMigratedefaults to true, so supplying a key also sweeps rows still inplaintext at the next start.
Rows encrypted under a key that is no longer available stay unreadable — a
different key cannot recover them.
solidping-prodcurrently reportsencrypted rows present ... checks=4, and no key exists for them anywhere, sothose four checks will need their credentials re-entered by hand. A prod KEK is
already generated and waiting at
gopass k8xp/solidping-prod/encryption/master-key;it starts working the moment this ships.
Test
TestLoadBindsEncryptionMasterKeygoes throughLoad, the path productiontakes. Verified it fails without the fix (
expected: "dGVzdC..." actual: "").it cannot inherit the ambient environment.
go test ./internal/config/... ./internal/envcheck/...green,golangci-lint0 issues,
gofmtclean.🤖 Generated with Claude Code