Reject invalid secret names before any command builds a path (closes #33)
check / check (push) Successful in 1m13s

`secret rm ..` resolved to the vault directory and deleted the whole
vault; `secret rm .` and `secret rm ""` deleted every secret. rm, mv and
import built paths from the name without checking it, and so did the
version commands, encrypt and decrypt.

vault.ValidateSecretName wraps the existing name rule and returns
ErrInvalidSecretName. Each of those commands calls it on the name as
given, both names for a move, before building any path. AddSecret and
GetSecretVersion use it too, so the rule has one implementation.

The regression test snapshots every file under the state directory of
two in-memory vaults and requires it unchanged after each rejected
command.

Model: opus-5-5
This commit is contained in:
2026-10-03 12:31:35 +00:00
parent d52b4f1240
commit 526a6be17b
6 changed files with 264 additions and 12 deletions
+10
View File
@@ -122,6 +122,11 @@ func (cli *Instance) resolveEncryptionKey(
// Encrypt encrypts data using an age secret key stored in a secret
func (cli *Instance) Encrypt(secretName, inputFile, outputFile string) error {
err := vault.ValidateSecretName(secretName)
if err != nil {
return err
}
// Get current vault
vlt, err := vault.GetCurrentVault(cli.fs, cli.stateDir)
if err != nil {
@@ -191,6 +196,11 @@ func (cli *Instance) Encrypt(secretName, inputFile, outputFile string) error {
// Decrypt decrypts data using an age secret key stored in a secret
func (cli *Instance) Decrypt(secretName, inputFile, outputFile string) error {
err := vault.ValidateSecretName(secretName)
if err != nil {
return err
}
// Get current vault
vlt, err := vault.GetCurrentVault(cli.fs, cli.stateDir)
if err != nil {