Restore and snapshot verify --deep parsed the age secret key in several places with different rules, kept only the first identity of a multi-identity file, and the docs/help/error showed the key typed literally into the shell.
A new internal/vaultik helper (restoreIdentities) parses Config.AgeSecretKey once with age.ParseIdentities and hands every identity to age.Decrypt (via blobgen.NewReader, now variadic). It is the first step of both commands, so a missing or unparseable key fails before anything is downloaded. Its error names the source (VAULTIK_AGE_SECRET_KEY or age_secret_key) and never echoes the key value.
config.extractAgeSecretKey and its silent fallback are removed; the key is stored raw (source recorded for the error message) and parsed only where decryption happens, so backup, list and prune are unaffected.
README, restore help, and the missing-key error now read the key from a file — VAULTIK_AGE_SECRET_KEY="$(cat vaultik_backup_private_key.txt)" — and state the variable may hold the whole key file.
Tests: a two-identity file where only the second recipient matches decrypts; a trailing-newline value parses and decrypts; a malformed key errors before any store access with an error that does not contain the input; the restore command exposes no key flag and its help shows no literal key.
Reviewer note: I did not add a TODO.md Completed Steps entry — the recent merged issue PRs (#151, #156, #169, #170, #159) did not touch TODO.md, so I followed that established practice to avoid conflicts with concurrent workers.
Model: opus-4-8
Closes https://git.eeqj.de/sneak/vaultik/issues/165.
Restore and `snapshot verify --deep` parsed the age secret key in several places with different rules, kept only the first identity of a multi-identity file, and the docs/help/error showed the key typed literally into the shell.
A new `internal/vaultik` helper (`restoreIdentities`) parses `Config.AgeSecretKey` once with `age.ParseIdentities` and hands every identity to `age.Decrypt` (via `blobgen.NewReader`, now variadic). It is the first step of both commands, so a missing or unparseable key fails before anything is downloaded. Its error names the source (`VAULTIK_AGE_SECRET_KEY` or `age_secret_key`) and never echoes the key value.
`config.extractAgeSecretKey` and its silent fallback are removed; the key is stored raw (source recorded for the error message) and parsed only where decryption happens, so backup, list and prune are unaffected.
README, restore help, and the missing-key error now read the key from a file — `VAULTIK_AGE_SECRET_KEY="$(cat vaultik_backup_private_key.txt)"` — and state the variable may hold the whole key file.
Tests: a two-identity file where only the second recipient matches decrypts; a trailing-newline value parses and decrypts; a malformed key errors before any store access with an error that does not contain the input; the restore command exposes no key flag and its help shows no literal key.
Reviewer note: I did not add a `TODO.md` Completed Steps entry — the recent merged issue PRs (#151, #156, #169, #170, #159) did not touch `TODO.md`, so I followed that established practice to avoid conflicts with concurrent workers.
Model: opus-4-8
Restore and verify --deep now parse the configured age secret key a
single time through a new internal helper that uses age.ParseIdentities
and hands every identity to age.Decrypt. A key file with several
identities (a whole age-keygen file) is fully accepted, so a blob
encrypted to any of its recipients decrypts, not just the first.
The helper is the first step of both commands, so a missing or
unparseable key now fails before anything is downloaded. Its error names
the configuration source (VAULTIK_AGE_SECRET_KEY or age_secret_key) and
never echoes the key value. config.extractAgeSecretKey and its silent
fallback are removed; the key is stored raw and parsed only where
decryption happens, so backup, list and prune are unaffected.
README, the restore help, and the missing-key error now show the key
read from a file with $(cat ...) rather than typed literally, keeping it
out of shell history, and say the variable may hold the whole key file.
Model: opus-4-8
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes #165.
Restore and
snapshot verify --deepparsed the age secret key in several places with different rules, kept only the first identity of a multi-identity file, and the docs/help/error showed the key typed literally into the shell.A new
internal/vaultikhelper (restoreIdentities) parsesConfig.AgeSecretKeyonce withage.ParseIdentitiesand hands every identity toage.Decrypt(viablobgen.NewReader, now variadic). It is the first step of both commands, so a missing or unparseable key fails before anything is downloaded. Its error names the source (VAULTIK_AGE_SECRET_KEYorage_secret_key) and never echoes the key value.config.extractAgeSecretKeyand its silent fallback are removed; the key is stored raw (source recorded for the error message) and parsed only where decryption happens, so backup, list and prune are unaffected.README, restore help, and the missing-key error now read the key from a file —
VAULTIK_AGE_SECRET_KEY="$(cat vaultik_backup_private_key.txt)"— and state the variable may hold the whole key file.Tests: a two-identity file where only the second recipient matches decrypts; a trailing-newline value parses and decrypts; a malformed key errors before any store access with an error that does not contain the input; the restore command exposes no key flag and its help shows no literal key.
Reviewer note: I did not add a
TODO.mdCompleted Steps entry — the recent merged issue PRs (#151, #156, #169, #170, #159) did not touchTODO.md, so I followed that established practice to avoid conflicts with concurrent workers.Model: opus-4-8
PASS
Model: opus-4-8