Make an unlocker's ID the name of its directory (closes #98)
check / check (push) Failing after 2s

Keychain and Secure Enclave unlocker IDs were the creation time to the
minute plus the host name, and passphrase unlocker IDs the time to the
minute, so two created within one minute shared an ID, and `unlocker
select`, `unlocker remove` and the selection after `unlocker add` acted on
the older one. Every unlocker's ID is now its directory name, unique in
its vault. PGP unlocker IDs were `pgp-<fingerprint>`; the check that
refuses a second PGP unlocker for one key now compares the fingerprint in
the other unlockers' metadata.

Model: opus-5-5
This commit is contained in:
2026-10-04 18:18:49 +00:00
parent f2f89c8a06
commit 35d73dfdb2
19 changed files with 145 additions and 94 deletions
+10 -12
View File
@@ -697,9 +697,7 @@ func (cli *Instance) addPGPUnlocker(cmd *cobra.Command) error {
}
// Check if this GPG key is already added
expectedID := "pgp-" + fingerprint
exists, err := cli.checkUnlockerExists(vlt, expectedID)
exists, err := cli.pgpUnlockerExists(vlt, fingerprint)
if err != nil {
return fmt.Errorf(
"could not check whether GPG key %s is already an unlocker: %w",
@@ -889,16 +887,16 @@ func (cli *Instance) UnlockerSelect(unlockerID string) error {
return vlt.SelectUnlocker(unlockerID)
}
// checkUnlockerExists reports whether the vault already has an unlocker
// with the given ID. It returns an error, and no answer, when unlockers.d
// or an unlocker's metadata file cannot be read; the caller must then not
// create the unlocker. It reads unlockers.d itself because
// vault.ListUnlockers skips an unlocker it cannot read, which suits
// pgpUnlockerExists reports whether the vault already has a PGP unlocker
// for the GPG key with the given fingerprint. It returns an error, and no
// answer, when unlockers.d or an unlocker's metadata file cannot be read;
// the caller must then not create the unlocker. It reads unlockers.d itself
// because vault.ListUnlockers skips an unlocker it cannot read, which suits
// `unlocker list` but not this check: the skipped unlocker may be the
// duplicate. A directory whose metadata file is missing or corrupt is not
// a working unlocker and is passed over.
func (cli *Instance) checkUnlockerExists(
vlt *vault.Vault, unlockerID string,
func (cli *Instance) pgpUnlockerExists(
vlt *vault.Vault, fingerprint string,
) (bool, error) {
vaultDir, err := vlt.GetDirectory()
if err != nil {
@@ -937,14 +935,14 @@ func (cli *Instance) checkUnlockerExists(
)
}
var metadata secret.UnlockerMetadata
var metadata secret.PGPUnlockerMetadata
err = json.Unmarshal(metadataBytes, &metadata)
if err != nil {
continue
}
if unlockerIDFromDir(cli.fs, unlockerDir, metadata, true) == unlockerID {
if metadata.Type == unlockerTypePGP && metadata.GPGKeyID == fingerprint {
return true, nil
}
}