feat: TreatVault encrypted secret manager with Docker Swarm sync and console plugin

This commit is contained in:
2026-09-16 16:06:41 -04:00
parent 61a45a4310
commit 63ee4a99e6
25 changed files with 5976 additions and 1 deletions

View File

@@ -0,0 +1,108 @@
package vault
import (
"bytes"
"os"
"path/filepath"
"testing"
"filippo.io/age"
)
func TestStoreEncryptsUpdatesAndDeletesSecrets(t *testing.T) {
identity, err := age.GenerateX25519Identity()
if err != nil {
t.Fatal(err)
}
path := filepath.Join(t.TempDir(), "vault", "secrets.age")
if err := Initialize(path, identity); err != nil {
t.Fatal(err)
}
store := New(path, identity)
first, err := store.Set("database_password", []byte("correct horse battery staple"))
if err != nil {
t.Fatal(err)
}
record := first.Secrets["database_password"]
if record.Revision == "" || string(record.Value) != "correct horse battery staple" {
t.Fatalf("record = %#v", record)
}
encrypted, err := os.ReadFile(path)
if err != nil {
t.Fatal(err)
}
if bytes.Contains(encrypted, []byte("correct horse battery staple")) || bytes.Contains(encrypted, []byte("database_password")) {
t.Fatal("encrypted file contains plaintext secret material")
}
unchanged, err := store.Set("database_password", []byte("correct horse battery staple"))
if err != nil {
t.Fatal(err)
}
if unchanged.Secrets["database_password"].Revision != record.Revision {
t.Fatal("setting the same value changed its revision")
}
rotated, err := store.Set("database_password", []byte("new value"))
if err != nil {
t.Fatal(err)
}
if rotated.Secrets["database_password"].Revision == record.Revision {
t.Fatal("rotating a value did not change its revision")
}
if _, err := store.Delete("database_password"); err != nil {
t.Fatal(err)
}
loaded, err := store.Load()
if err != nil {
t.Fatal(err)
}
if len(loaded.Secrets) != 0 {
t.Fatalf("secrets = %#v", loaded.Secrets)
}
}
func TestStoreRejectsWrongIdentityAndInvalidValues(t *testing.T) {
identity, err := age.GenerateX25519Identity()
if err != nil {
t.Fatal(err)
}
path := filepath.Join(t.TempDir(), "secrets.age")
if err := Initialize(path, identity); err != nil {
t.Fatal(err)
}
store := New(path, identity)
if _, err := store.Set("../unsafe", []byte("value")); err == nil {
t.Fatal("Set() accepted unsafe name")
}
if _, err := store.Set("empty", nil); err == nil {
t.Fatal("Set() accepted empty value")
}
wrongIdentity, err := age.GenerateX25519Identity()
if err != nil {
t.Fatal(err)
}
if _, err := New(path, wrongIdentity).Load(); err == nil {
t.Fatal("Load() succeeded with wrong identity")
}
}
func TestGenerateIdentityDoesNotOverwrite(t *testing.T) {
path := filepath.Join(t.TempDir(), "identity.txt")
recipient, err := GenerateIdentity(path)
if err != nil {
t.Fatal(err)
}
if recipient == "" {
t.Fatal("recipient is empty")
}
if _, err := GenerateIdentity(path); err == nil {
t.Fatal("GenerateIdentity() overwrote existing identity")
}
info, err := os.Stat(path)
if err != nil {
t.Fatal(err)
}
if info.Mode().Perm() != 0o600 {
t.Fatalf("identity permissions = %o", info.Mode().Perm())
}
}