Add unlock --idle, and packaging/repo.sh for repo.dixon.cx
vault unlock --idle counts the duration from the last command that used the key rather than from the unlock: the agent resets its timer each time it hands the key out. The agent loop no longer needs its own goroutine. packaging/repo.sh builds the dixon-vault .deb, .rpm and Arch packages from a release tag (a clean git archive) with nfpm for amd64, arm64, armv7, 386 and riscv64, then publishes them to the apt, dnf and pacman repositories at repo.dixon.cx: apt-ftparchive with a signed InRelease, createrepo_c (in a Fedora container) with signed RPMs and repomd.xml, and repo-add (in an Arch container) with signed packages and database. Indexes cover every package in the repository, under a lock, so other projects publishing with their copy of the script are kept. The package is dixon-vault because vault is HashiCorp Vault in Arch's [extra] and HashiCorp's own repositories; it conflicts with vault. README, guide and CLAUDE.md point at the repository.
This commit is contained in:
+37
-1
@@ -21,6 +21,8 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/andydixon/vault/internal/pqcrypt"
|
||||
)
|
||||
|
||||
func TestKeyFile(t *testing.T) {
|
||||
@@ -668,7 +670,7 @@ func TestAgent(t *testing.T) {
|
||||
secret = append(secret, id.Seed()...)
|
||||
pr, pw := io.Pipe()
|
||||
stopped := make(chan struct{})
|
||||
go func() { runAgent(sock, "1m", bytes.NewReader(secret), pw); close(stopped) }()
|
||||
go func() { runAgent(sock, "1m", "fixed", bytes.NewReader(secret), pw); close(stopped) }()
|
||||
if msg, _ := io.ReadAll(pr); string(msg) != "ok" {
|
||||
t.Fatalf("agent said %q", msg)
|
||||
}
|
||||
@@ -690,3 +692,37 @@ func TestAgent(t *testing.T) {
|
||||
t.Fatal("agent still running")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAgentIdle(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
t.Setenv("XDG_RUNTIME_DIR", dir)
|
||||
keyPath := filepath.Join(dir, "key")
|
||||
sock, err := agentSocket(keyPath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
id, err := pqcrypt.GeneratePQIdentity()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
secret := binary.BigEndian.AppendUint16(nil, id.SuiteID())
|
||||
secret = append(secret, id.Seed()...)
|
||||
pr, pw := io.Pipe()
|
||||
stopped := make(chan struct{})
|
||||
go func() { runAgent(sock, "400ms", "idle", bytes.NewReader(secret), pw); close(stopped) }()
|
||||
if msg, _ := io.ReadAll(pr); string(msg) != "ok" {
|
||||
t.Fatalf("agent said %q", msg)
|
||||
}
|
||||
// Used every 150ms, it outlives its 400ms by well over twice.
|
||||
for range 7 {
|
||||
time.Sleep(150 * time.Millisecond)
|
||||
if _, err := agentIdentity(keyPath); err != nil {
|
||||
t.Fatal("idle agent expired while in use: ", err)
|
||||
}
|
||||
}
|
||||
select {
|
||||
case <-stopped:
|
||||
case <-time.After(2 * time.Second):
|
||||
t.Fatal("idle agent outlived its idle time")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user