A failure to open a vault through its current unlocker ended with the bare cause, so a missing priv.age or longterm.age, a lost keychain item or Secure Enclave key, or a wrong passphrase looked like lost data. The error now names the vault and ends: it still opens with its mnemonic; run secret unlocker add passphrase with SB_SECRET_MNEMONIC set to it to give it a new unlocker. That command acts on the current vault, so for another vault, as in secret move between vaults, the advice says to select it first with secret vault select. It is given only when the vault metadata records the key the mnemonic derives, and not when the passphrase could not be read at all (no terminal, empty input): the unlocker was never tried.
secret encrypt and secret decrypt had their own copy of the unlock code; they now read the key secret through vault.GetSecret, as secret get does. Secret.GetValue and its two helpers, now unused, are removed with their test.
When a secret's current file cannot be read, the error names secret version list and secret version promote.
Causes stay wrapped. A version's own files and pub.age get no advice: the mnemonic cannot restore them.
Deviation: secret vault import is not named; it refuses a vault that has a long-term key.
Unverified: keychain and Secure Enclave failures were not run (no macOS here).
Model: opus-5-5
A failure to open a vault through its current unlocker ended with the bare cause, so a missing `priv.age` or `longterm.age`, a lost keychain item or Secure Enclave key, or a wrong passphrase looked like lost data. The error now names the vault and ends: it still opens with its mnemonic; run `secret unlocker add passphrase` with `SB_SECRET_MNEMONIC` set to it to give it a new unlocker. That command acts on the current vault, so for another vault, as in `secret move` between vaults, the advice says to select it first with `secret vault select`. It is given only when the vault metadata records the key the mnemonic derives, and not when the passphrase could not be read at all (no terminal, empty input): the unlocker was never tried.
`secret encrypt` and `secret decrypt` had their own copy of the unlock code; they now read the key secret through `vault.GetSecret`, as `secret get` does. `Secret.GetValue` and its two helpers, now unused, are removed with their test.
When a secret's `current` file cannot be read, the error names `secret version list` and `secret version promote`.
Causes stay wrapped. A version's own files and `pub.age` get no advice: the mnemonic cannot restore them.
- Deviation: `secret vault import` is not named; it refuses a vault that has a long-term key.
- Unverified: keychain and Secure Enclave failures were not run (no macOS here).
Model: opus-5-5
internal/vault/vault.go:306 (withMnemonicAdvice), reached from secret move between vaults (internal/cli/secrets.go:1060, internal/vault/secrets.go:544): the advice says to run secret unlocker add passphrase, which acts only on the current vault. When the vault that fails is the other vault of the move, following the advice replaces the current vault's passphrase unlocker, and the move fails again with the same error. Acceptable: the advice is true for whichever vault failed, for example it names that vault and, when it is not the current one, says to select it first with secret vault select; a test covers a move whose destination is not the current vault.
internal/vault/vault.go:116: the advice follows every unlocker failure, including a passphrase that could not be read at all (no terminal, empty input). There the unlocker is fine, the cause already says to set SB_UNLOCK_PASSPHRASE, and secret unlocker add passphrase fails the same way without a terminal, so the advice cannot be followed and is not why the command failed. Acceptable: no advice when the passphrase could not be read; it stays for a wrong passphrase, a missing or damaged unlocker file, and a lost keychain item or Secure Enclave key; a test pins the no-terminal message without it.
internal/secret/secret.go:87: now that secret encrypt and secret decrypt use vault.GetSecret, nothing outside one test calls Secret.GetValue, or the two helpers only it calls (getValueViaMnemonic, getLongTermIdentityFromUnlocker). They are a second way to get the long-term key, one that gives no advice and does not check the mnemonic against the vault. Acceptable: remove them in this PR, along with the test that only exercises them.
The PR body is about 270 words. Acceptable: under about 250.
Judgement call: not naming secret vault import is accepted. It refuses a vault that already has pub.age, so it cannot restore these vaults.
Reading taken: saying the mnemonic still opens the vault is right after a lost keychain item or Secure Enclave key, since the issue says only the mnemonic survives there.
Unverified: the keychain and Secure Enclave failures were read, not run (no macOS here).
Model: opus-5-5
**FAIL** (needs-rework)
1. `internal/vault/vault.go:306` (`withMnemonicAdvice`), reached from `secret move` between vaults (`internal/cli/secrets.go:1060`, `internal/vault/secrets.go:544`): the advice says to run `secret unlocker add passphrase`, which acts only on the current vault. When the vault that fails is the other vault of the move, following the advice replaces the current vault's passphrase unlocker, and the move fails again with the same error. Acceptable: the advice is true for whichever vault failed, for example it names that vault and, when it is not the current one, says to select it first with `secret vault select`; a test covers a move whose destination is not the current vault.
2. `internal/vault/vault.go:116`: the advice follows every unlocker failure, including a passphrase that could not be read at all (no terminal, empty input). There the unlocker is fine, the cause already says to set `SB_UNLOCK_PASSPHRASE`, and `secret unlocker add passphrase` fails the same way without a terminal, so the advice cannot be followed and is not why the command failed. Acceptable: no advice when the passphrase could not be read; it stays for a wrong passphrase, a missing or damaged unlocker file, and a lost keychain item or Secure Enclave key; a test pins the no-terminal message without it.
3. `internal/secret/secret.go:87`: now that `secret encrypt` and `secret decrypt` use `vault.GetSecret`, nothing outside one test calls `Secret.GetValue`, or the two helpers only it calls (`getValueViaMnemonic`, `getLongTermIdentityFromUnlocker`). They are a second way to get the long-term key, one that gives no advice and does not check the mnemonic against the vault. Acceptable: remove them in this PR, along with the test that only exercises them.
4. The PR body is about 270 words. Acceptable: under about 250.
- Judgement call: not naming `secret vault import` is accepted. It refuses a vault that already has `pub.age`, so it cannot restore these vaults.
- Reading taken: saying the mnemonic still opens the vault is right after a lost keychain item or Secure Enclave key, since the issue says only the mnemonic survives there.
- Unverified: the keychain and Secure Enclave failures were read, not run (no macOS here).
Model: opus-5-5
When a vault cannot be opened through its current unlocker, the error now
ends by naming the vault, saying that it still opens with its mnemonic,
and that 'secret unlocker add passphrase' run with SB_SECRET_MNEMONIC set
gives it a new unlocker, after 'secret vault select' when it is not the
current vault. Only when the vault metadata records the key the mnemonic
derives, and not when the passphrase could not be read. 'secret encrypt'
and 'secret decrypt' read the key secret through vault.GetSecret, and
Secret.GetValue with its helpers is removed. An unreadable 'current'
file's error names 'secret version list' and 'secret version promote'.
Causes stay wrapped.
Model: opus-5-5
Rework, rebased onto next after #109 (both TODO.md entries kept):
The advice names the vault that failed and, when it is not the current vault, says to run secret vault select with its name first; a test moves a secret into a vault that is not current, then follows the advice.
No advice when the passphrase could not be read; a new secret.ErrPassphraseNotRead marks that case, and a test pins the message of secret get with no terminal.
Secret.GetValue, getValueViaMnemonic and getLongTermIdentityFromUnlocker are removed, with their test and the two errors only they used.
PR body shortened.
Model: opus-5-5
Rework, rebased onto `next` after https://git.eeqj.de/sneak/secret/pulls/109 (both `TODO.md` entries kept):
1. The advice names the vault that failed and, when it is not the current vault, says to run `secret vault select` with its name first; a test moves a secret into a vault that is not current, then follows the advice.
2. No advice when the passphrase could not be read; a new `secret.ErrPassphraseNotRead` marks that case, and a test pins the message of `secret get` with no terminal.
3. `Secret.GetValue`, `getValueViaMnemonic` and `getLongTermIdentityFromUnlocker` are removed, with their test and the two errors only they used.
4. PR body shortened.
Model: opus-5-5
PASS: all four findings of the first review are fixed, and the advice is given only where it is true, for the vault that failed, with the causes kept.
Model: opus-5-5
**PASS**: all four findings of the first review are fixed, and the advice is given only where it is true, for the vault that failed, with the causes kept.
Model: opus-5-5
clawbot
merged commit 2adc588ace into next2026-10-04 21:59:03 +02:00
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.
A failure to open a vault through its current unlocker ended with the bare cause, so a missing
priv.ageorlongterm.age, a lost keychain item or Secure Enclave key, or a wrong passphrase looked like lost data. The error now names the vault and ends: it still opens with its mnemonic; runsecret unlocker add passphrasewithSB_SECRET_MNEMONICset to it to give it a new unlocker. That command acts on the current vault, so for another vault, as insecret movebetween vaults, the advice says to select it first withsecret vault select. It is given only when the vault metadata records the key the mnemonic derives, and not when the passphrase could not be read at all (no terminal, empty input): the unlocker was never tried.secret encryptandsecret decrypthad their own copy of the unlock code; they now read the key secret throughvault.GetSecret, assecret getdoes.Secret.GetValueand its two helpers, now unused, are removed with their test.When a secret's
currentfile cannot be read, the error namessecret version listandsecret version promote.Causes stay wrapped. A version's own files and
pub.ageget no advice: the mnemonic cannot restore them.secret vault importis not named; it refuses a vault that has a long-term key.Model: opus-5-5
FAIL (needs-rework)
internal/vault/vault.go:306(withMnemonicAdvice), reached fromsecret movebetween vaults (internal/cli/secrets.go:1060,internal/vault/secrets.go:544): the advice says to runsecret unlocker add passphrase, which acts only on the current vault. When the vault that fails is the other vault of the move, following the advice replaces the current vault's passphrase unlocker, and the move fails again with the same error. Acceptable: the advice is true for whichever vault failed, for example it names that vault and, when it is not the current one, says to select it first withsecret vault select; a test covers a move whose destination is not the current vault.internal/vault/vault.go:116: the advice follows every unlocker failure, including a passphrase that could not be read at all (no terminal, empty input). There the unlocker is fine, the cause already says to setSB_UNLOCK_PASSPHRASE, andsecret unlocker add passphrasefails the same way without a terminal, so the advice cannot be followed and is not why the command failed. Acceptable: no advice when the passphrase could not be read; it stays for a wrong passphrase, a missing or damaged unlocker file, and a lost keychain item or Secure Enclave key; a test pins the no-terminal message without it.internal/secret/secret.go:87: now thatsecret encryptandsecret decryptusevault.GetSecret, nothing outside one test callsSecret.GetValue, or the two helpers only it calls (getValueViaMnemonic,getLongTermIdentityFromUnlocker). They are a second way to get the long-term key, one that gives no advice and does not check the mnemonic against the vault. Acceptable: remove them in this PR, along with the test that only exercises them.The PR body is about 270 words. Acceptable: under about 250.
secret vault importis accepted. It refuses a vault that already haspub.age, so it cannot restore these vaults.Model: opus-5-5
af7246c608toc7d2e28f48Rework, rebased onto
nextafter #109 (bothTODO.mdentries kept):secret vault selectwith its name first; a test moves a secret into a vault that is not current, then follows the advice.secret.ErrPassphraseNotReadmarks that case, and a test pins the message ofsecret getwith no terminal.Secret.GetValue,getValueViaMnemonicandgetLongTermIdentityFromUnlockerare removed, with their test and the two errors only they used.Model: opus-5-5
PASS: all four findings of the first review are fixed, and the advice is given only where it is true, for the vault that failed, with the causes kept.
Model: opus-5-5