Parse age_recipients at config load and never echo the entry (closes #153)
check / check (pull_request) Successful in 2m18s

Config.Validate now parses every age_recipients entry with
age.ParseX25519Recipient, so a bad recipient fails at config load instead
of deep in a backup after the snapshot row and tree walk. On failure the
error names the position (age_recipients[N]) and never the value: a
recipient string can itself be a secret key an operator pasted by mistake,
and age's own error quotes its input. An entry starting with
AGE-SECRET-KEY- (compared case-insensitively) gets a specific message.

The remaining parse sites (blobgen.NewWriter, crypto NewEncryptor and
UpdateRecipients), reachable by callers that skip config.Load, likewise
drop the value and age's wrapped error, naming only the position.

test/config.yaml's placeholder second recipient is replaced with a valid
X25519 key so it still loads.

Model: opus-4-8
This commit is contained in:
2026-09-22 10:41:59 +00:00
parent b4654f8e52
commit e0e43548b7
7 changed files with 176 additions and 8 deletions
+17
View File
@@ -108,3 +108,20 @@ func TestWriterDeterministicHash(t *testing.T) {
t.Logf("Encrypted size 1: %d bytes", buf1.Len())
t.Logf("Encrypted size 2: %d bytes", buf2.Len())
}
// TestNewWriterSecretKeyNotEchoed verifies that a secret key mistakenly passed
// as a recipient does not appear in the returned error. A recipient string can
// be sensitive, so the error must name only the position, not the value.
func TestNewWriterSecretKeyNotEchoed(t *testing.T) {
t.Parallel()
secretKey := "AGE-SECRET-KEY-19CR5YSFW59HM4TLD6GX" +
"VEDMZFTVVF7PPHKUT68TXSFPK7APHXA2QS2NJA5"
var buf bytes.Buffer
_, err := blobgen.NewWriter(&buf, 3, []string{secretKey})
require.Error(t, err)
assert.NotContains(t, err.Error(), secretKey,
"error must not echo the recipient value")
}