Give every new unlocker a directory of its own (closes #71)
check / check (push) Failing after 1s

A passphrase unlocker added to a vault that had one, and a PGP, keychain
or Secure Enclave unlocker added on the same day as another of its type,
were written into the existing unlocker's directory file by file, so a
crash part-way left a current unlocker whose files did not belong
together.

Unlocker directories, keychain items and Secure Enclave keys are now
named with the time to the nanosecond, and secret.WriteDir refuses a
directory that exists. Adding a passphrase unlocker writes the new one,
points current-unlocker at it, and only then removes the vault's other
passphrase unlockers.

Model: opus-5-5
This commit was merged in pull request #99.
This commit is contained in:
2026-10-04 16:58:45 +02:00
parent db7d2c952e
commit 7e4e0f7806
13 changed files with 309 additions and 70 deletions
+8 -8
View File
@@ -3,6 +3,7 @@ package secret
import (
"errors"
"fmt"
"os"
"path/filepath"
"github.com/spf13/afero"
@@ -62,13 +63,12 @@ func TempDirFor(fs afero.Fs, target string) (string, error) {
return dir, nil
}
// WriteDir calls write to write the files of the directory dir. When dir does
// not exist yet, write writes them into a temporary directory from TempDirFor,
// which is then renamed to dir, so that neither a failure nor a crash leaves
// dir half-written; on a failure the temporary directory is removed, and a
// failure to remove it is returned along with the first. A directory cannot be
// renamed over one that has files in it, so when dir already exists, write
// writes into it in place; dir is then never removed.
// WriteDir calls write to write the files of the new directory dir into a
// temporary directory from TempDirFor, which is then renamed to dir, so that
// neither a failure nor a crash leaves dir half-written; on a failure the
// temporary directory is removed, and a failure to remove it is returned
// along with the first. A directory cannot be replaced in one rename, so if
// dir already exists, WriteDir fails without calling write.
func WriteDir(fs afero.Fs, dir string, write func(dir string) error) error {
exists, err := afero.Exists(fs, dir)
if err != nil {
@@ -76,7 +76,7 @@ func WriteDir(fs afero.Fs, dir string, write func(dir string) error) error {
}
if exists {
return write(dir)
return fmt.Errorf("failed to create %s: %w", dir, os.ErrExist)
}
// Create the directory the finished one is renamed into