Say the mnemonic still opens a vault its unlocker cannot (closes #47)
check / check (push) Failing after 2s

When the vault cannot be opened through its current unlocker, the error
now ends by saying that the vault still opens with its mnemonic, and
that 'secret unlocker add passphrase' run with SB_SECRET_MNEMONIC set
gives it a new unlocker; only when the vault metadata records the key
the mnemonic derives. 'secret encrypt' and 'secret decrypt' read the key
secret through vault.GetSecret, as 'secret get' does, so they say it
too. An unreadable 'current' file's error names 'secret version list'
and 'secret version promote'. Causes stay wrapped.

Model: opus-5-5
This commit is contained in:
2026-10-04 19:04:32 +00:00
parent 1a23fd3125
commit af7246c608
5 changed files with 328 additions and 25 deletions
+22 -2
View File
@@ -98,7 +98,8 @@ func (v *Vault) GetOrDeriveLongTermKey() (*age.X25519Identity, error) {
if err != nil {
secret.Debug("Failed to get current unlocker", "error", err, "vault_name", v.Name)
return nil, fmt.Errorf("failed to get current unlocker: %w", err)
return nil, v.withMnemonicAdvice(
fmt.Errorf("failed to get current unlocker: %w", err))
}
secret.DebugWith("Retrieved current unlocker for vault unlock",
@@ -112,7 +113,7 @@ func (v *Vault) GetOrDeriveLongTermKey() (*age.X25519Identity, error) {
// Other unlockers return their own identity, used to decrypt longterm.age.
ltIdentity, err := v.unlockLongTermKey(unlocker)
if err != nil {
return nil, err
return nil, v.withMnemonicAdvice(err)
}
secret.DebugWith("Successfully obtained long-term identity via unlocker",
@@ -295,3 +296,22 @@ func (v *Vault) unlockLongTermKey(
return ltIdentity, nil
}
// withMnemonicAdvice returns err, a failure to get the long-term key through
// the current unlocker, with advice added: that the mnemonic still opens the
// vault, and how to give it a new unlocker. The advice is added only when the
// vault metadata records the key that the mnemonic derives; a vault created
// without a mnemonic records none, and without its metadata the key cannot
// be derived.
func (v *Vault) withMnemonicAdvice(err error) error {
vaultDir, _ := v.GetDirectory()
metadata, metadataErr := LoadVaultMetadata(v.fs, vaultDir)
if metadataErr != nil || metadata.PublicKeyHash == "" {
return err
}
return fmt.Errorf("%w; the vault still opens with its mnemonic: run "+
"'secret unlocker add passphrase' with %s set to the mnemonic "+
"to give it a new unlocker", err, secret.EnvMnemonic)
}