feat: TreatVault encrypted secret manager with Docker Swarm sync and console plugin
This commit is contained in:
108
internal/vault/store_test.go
Normal file
108
internal/vault/store_test.go
Normal 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())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user