secret vault import cannot succeed on any vault the tool creates, and the mnemonic help points at secret import #139

Open
opened 2026-10-13 00:30:14 +02:00 by clawbot · 1 comment
Collaborator

Severity: major. The command fails in every use: it refuses a vault that has a long-term key, and every vault that secret init or secret vault create makes has one.

What happens. vault import needs an existing vault without pub.age. vault.CreateVault always writes pub.age, because the CLI always gives it a mnemonic, and a vault that does not exist is refused too, so no sequence of commands makes vault import succeed.

SB_SECRET_MNEMONIC=... SB_UNLOCK_PASSPHRASE=x secret vault import default
# Error: vault 'default' already has a long-term key configured
secret vault import other
# Error: vault 'other' does not exist

The help of secret generate mnemonic and the note it prints say to use secret import "to import into an existing vault"; secret import imports a file as a secret and fails without --source.

Where.

// Check if vault already has a public key
pubKeyPath := vaultDir + "/pub.age"
exists, err = afero.Exists(cli.fs, pubKeyPath)
if err != nil {
return "", "", "", fmt.Errorf("failed to check %s: %w", pubKeyPath, err)
}
if exists {
return "", "", "", fmt.Errorf("vault '%s' %w",
vaultName, errVaultHasLongTermKey)
}
(the check),
ltPubKeyPath := filepath.Join(vaultDir, "pub.age")
(pub.age written on every create),
`mnemonic phrase that can be used with 'secret init' ` +
`or 'secret import'.`,
and
fmt.Fprintln(os.Stderr, " secret import (to import into an existing vault)")
.

Correct behaviour is a product decision the README does not settle; it only says the command "Imports a mnemonic phrase into the specified vault". Recommended: remove secret vault import from the code and the README (a mnemonic enters through secret init and secret vault create), and have the generate mnemonic help and note name those two commands. The alternative is to make vault import create the vault.

Definition of done

  • Either the command is gone from the code, the README and the mnemonic help, or secret vault import succeeds on a path the README describes.
  • The generate mnemonic help and note name only commands that accept a mnemonic.
  • A test that fails before the fix: running vault import on a vault made by vault create either succeeds or the command is not found.

Model: fable-5-1

Severity: major. The command fails in every use: it refuses a vault that has a long-term key, and every vault that `secret init` or `secret vault create` makes has one. **What happens.** `vault import` needs an existing vault without `pub.age`. `vault.CreateVault` always writes `pub.age`, because the CLI always gives it a mnemonic, and a vault that does not exist is refused too, so no sequence of commands makes `vault import` succeed. ``` SB_SECRET_MNEMONIC=... SB_UNLOCK_PASSPHRASE=x secret vault import default # Error: vault 'default' already has a long-term key configured secret vault import other # Error: vault 'other' does not exist ``` The help of `secret generate mnemonic` and the note it prints say to use `secret import` "to import into an existing vault"; `secret import` imports a file as a secret and fails without `--source`. **Where.** https://git.eeqj.de/sneak/secret/src/commit/ef0ae90768c8b18a829033b3ebd4cf98fcaeb3d1/internal/cli/vault.go#L358-L369 (the check), https://git.eeqj.de/sneak/secret/src/commit/ef0ae90768c8b18a829033b3ebd4cf98fcaeb3d1/internal/vault/management.go#L189 (`pub.age` written on every create), https://git.eeqj.de/sneak/secret/src/commit/ef0ae90768c8b18a829033b3ebd4cf98fcaeb3d1/internal/cli/generate.go#L45-L46 and https://git.eeqj.de/sneak/secret/src/commit/ef0ae90768c8b18a829033b3ebd4cf98fcaeb3d1/internal/cli/generate.go#L119. **Correct behaviour** is a product decision the README does not settle; it only says the command "Imports a mnemonic phrase into the specified vault". Recommended: remove `secret vault import` from the code and the README (a mnemonic enters through `secret init` and `secret vault create`), and have the `generate mnemonic` help and note name those two commands. The alternative is to make `vault import` create the vault. **Definition of done** - Either the command is gone from the code, the README and the mnemonic help, or `secret vault import` succeeds on a path the README describes. - The `generate mnemonic` help and note name only commands that accept a mnemonic. - A test that fails before the fix: running `vault import` on a vault made by `vault create` either succeeds or the command is not found. Model: fable-5-1
sneak was assigned by clawbot 2026-10-13 00:30:14 +02:00
Author
Collaborator

One more facet, seen on v1.0.0-rc1 while checking this: on a vault directory that has no pub.age (only reachable by making the directory by hand), secret vault import with SB_SECRET_MNEMONIC set but SB_UNLOCK_PASSPHRASE unset writes pub.age and vault-metadata.json first and only then fails with "SB_UNLOCK_PASSPHRASE environment variable not set"; the next run refuses with "already has a long-term key configured", so the vault has a key and no unlocker, and secrets.d is never created, so secret add in it fails with a rename error. If the alternative (keeping the command) is chosen, the passphrase check belongs in vaultImportPreflight before anything is written (

passphraseBuffer := cli.UnlockPassphrase
), and the command must create the vault's directories. Removing the command, as recommended above, makes this moot.

Model: fable-5-1

One more facet, seen on `v1.0.0-rc1` while checking this: on a vault directory that has no `pub.age` (only reachable by making the directory by hand), `secret vault import` with `SB_SECRET_MNEMONIC` set but `SB_UNLOCK_PASSPHRASE` unset writes `pub.age` and `vault-metadata.json` first and only then fails with "SB_UNLOCK_PASSPHRASE environment variable not set"; the next run refuses with "already has a long-term key configured", so the vault has a key and no unlocker, and `secrets.d` is never created, so `secret add` in it fails with a rename error. If the alternative (keeping the command) is chosen, the passphrase check belongs in `vaultImportPreflight` before anything is written (https://git.eeqj.de/sneak/secret/src/commit/ef0ae90768c8b18a829033b3ebd4cf98fcaeb3d1/internal/cli/vault.go#L500), and the command must create the vault's directories. Removing the command, as recommended above, makes this moot. Model: fable-5-1
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/secret#139