Read secret environment variables once per command, then unset them (closes #60)
check / check (push) Failing after 2s

init and vault create put the mnemonic into the process environment for
vault.CreateVault to read back, so every program they ran, gpg included,
inherited it, and SB_SECRET_MNEMONIC and SB_UNLOCK_PASSPHRASE were read
at 13 places and never unset. Each command that may need them now reads
both once, in its RunE, into locked buffers on the CLI Instance, and
unsets them at once. The buffers are passed down: vault.CreateVault
takes the mnemonic, a Vault carries Mnemonic and UnlockPassphrase, and
the PGP, keychain and Secure Enclave unlocker constructors take both;
CreatePGPUnlocker sets them on the vault it loads through SetMnemonic
and SetUnlockPassphrase, new in VaultInterface. README warns against
both variables.

Model: opus-5-5
This commit is contained in:
2026-10-04 13:06:03 +00:00
parent 62967f28d0
commit 66a0714f92
42 changed files with 727 additions and 428 deletions
+12 -5
View File
@@ -41,6 +41,9 @@ func newCryptoCmd(
cli.cmd = cmd
destroySecrets := cli.readSecretEnv()
defer destroySecrets()
return run(cli, args[0], inputFile, outputFile)
},
}
@@ -156,6 +159,8 @@ func (cli *Instance) Encrypt(secretName, inputFile, outputFile string) error {
return err
}
vlt.Mnemonic, vlt.UnlockPassphrase = cli.Mnemonic, cli.UnlockPassphrase
// Get or create the age secret key for this secret
keyBuffer, err := cli.resolveEncryptionKey(vlt, secretName)
if err != nil {
@@ -230,6 +235,8 @@ func (cli *Instance) Decrypt(secretName, inputFile, outputFile string) error {
return err
}
vlt.Mnemonic, vlt.UnlockPassphrase = cli.Mnemonic, cli.UnlockPassphrase
// Check if secret exists
secretObj := secret.NewSecret(vlt, secretName)
@@ -308,13 +315,13 @@ func isValidAgeSecretKey(key string) bool {
return err == nil
}
// getSecretValue retrieves the value of a secret using the appropriate
// unlocker
// getSecretValue retrieves the value of a secret with the vault's mnemonic
// when it has one, else with the current unlocker
func (cli *Instance) getSecretValue(
vlt *vault.Vault, secretObj *secret.Secret,
) (*memguard.LockedBuffer, error) {
if os.Getenv(secret.EnvMnemonic) != "" {
return secretObj.GetValue(nil)
if vlt.Mnemonic != nil {
return secretObj.GetValue(nil, vlt.Mnemonic)
}
unlocker, err := vlt.GetCurrentUnlocker()
@@ -322,5 +329,5 @@ func (cli *Instance) getSecretValue(
return nil, fmt.Errorf("failed to get current unlocker: %w", err)
}
return secretObj.GetValue(unlocker)
return secretObj.GetValue(unlocker, nil)
}