130 lines
4.6 KiB
Go
130 lines
4.6 KiB
Go
package main
|
|
|
|
// The custody ledger the TypeScript vault kept (its client.ts and test/ledger.test.ts), carried over whole:
|
|
// who holds a secret the controller delivered for this vault, since when, and its fingerprint — never the
|
|
// value. Its files are the same JSON, so the ledger on the vault's disk is read as it is.
|
|
|
|
import (
|
|
"encoding/json"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestAFirstDeliveryIsAGrantTheSameAgainNothingANewValueARotation(t *testing.T) {
|
|
l, _ := NewLedger(t.TempDir())
|
|
t0 := time.Date(2026, 9, 20, 10, 0, 0, 0, time.UTC)
|
|
t1 := time.Date(2026, 9, 21, 10, 0, 0, 0, time.UTC)
|
|
|
|
held, outcome, err := l.Record("anchor-redis", "anchor", "first-value", t0)
|
|
if err != nil || outcome != Granted || held.Rotations != 0 || held.Since != t0.Format(isoMillis) ||
|
|
held.Fingerprint != Fingerprint("first-value") {
|
|
t.Fatalf("%+v %s %v", held, outcome, err)
|
|
}
|
|
if _, outcome, _ := l.Record("anchor-redis", "anchor", "first-value", t1); outcome != Unchanged {
|
|
t.Errorf("the same value again is %s", outcome)
|
|
}
|
|
held, outcome, _ = l.Record("anchor-redis", "anchor", "second-value", t1)
|
|
if outcome != Rotated || held.Rotations != 1 || held.Since != t0.Format(isoMillis) || held.Changed != t1.Format(isoMillis) {
|
|
t.Errorf("%+v %s", held, outcome)
|
|
}
|
|
if len(held.History) != 1 || held.History[0].Fingerprint != Fingerprint("first-value") || held.History[0].Until != t1.Format(isoMillis) {
|
|
t.Errorf("history %+v", held.History)
|
|
}
|
|
}
|
|
|
|
func TestTheLedgerHoldsFingerprintsNeverTheValue(t *testing.T) {
|
|
dir := t.TempDir()
|
|
l, _ := NewLedger(dir)
|
|
_, _, _ = l.Record("anchor-redis", "anchor", "the-actual-password", time.Now())
|
|
_, _, _ = l.Record("anchor-redis", "anchor", "the-rotated-password", time.Now())
|
|
entries, _ := os.ReadDir(dir)
|
|
for _, e := range entries {
|
|
raw, _ := os.ReadFile(filepath.Join(dir, e.Name()))
|
|
if strings.Contains(string(raw), "the-actual-password") || strings.Contains(string(raw), "the-rotated-password") {
|
|
t.Errorf("%s holds a value", e.Name())
|
|
}
|
|
info, _ := e.Info()
|
|
if info.Mode().Perm() != 0o600 {
|
|
t.Errorf("%s is %v", e.Name(), info.Mode())
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestDeletingForgetsAHolderAndListingIsByLogin(t *testing.T) {
|
|
l, _ := NewLedger(t.TempDir())
|
|
_, _, _ = l.Record("b-app", "b", "x", time.Now())
|
|
_, _, _ = l.Record("a-app", "a", "y", time.Now())
|
|
if got := logins(l.List()); got != "a-app,b-app" {
|
|
t.Errorf("listed %s", got)
|
|
}
|
|
if !l.Delete("a-app") || l.Delete("a-app") {
|
|
t.Error("deleting found the wrong thing")
|
|
}
|
|
if got := logins(l.List()); got != "b-app" {
|
|
t.Errorf("listed %s", got)
|
|
}
|
|
}
|
|
|
|
func TestALoginIsANameNotAPath(t *testing.T) {
|
|
l, _ := NewLedger(t.TempDir())
|
|
if _, _, err := l.Record("../etc/passwd", "n", "v", time.Now()); err == nil {
|
|
t.Error("a path was taken for a login")
|
|
}
|
|
}
|
|
|
|
// A ledger the TypeScript vault wrote is read as it is.
|
|
func TestALedgerTheTypeScriptVaultWroteIsRead(t *testing.T) {
|
|
dir := t.TempDir()
|
|
written := `{
|
|
"as": "anchor-redis",
|
|
"consumer": "anchor",
|
|
"fingerprint": "sha256:abc",
|
|
"length": 40,
|
|
"since": "2026-09-20T10:00:00.000Z",
|
|
"changed": "2026-09-21T10:00:00.000Z",
|
|
"rotations": 1,
|
|
"history": [{"fingerprint": "sha256:old", "until": "2026-09-21T10:00:00.000Z"}]
|
|
}
|
|
`
|
|
_ = os.WriteFile(filepath.Join(dir, "anchor-redis.json"), []byte(written), 0o600)
|
|
l, _ := NewLedger(dir)
|
|
h, ok := l.Get("anchor-redis")
|
|
if !ok || h.Rotations != 1 || h.Length != 40 || h.History[0].Fingerprint != "sha256:old" {
|
|
t.Fatalf("%+v %v", h, ok)
|
|
}
|
|
}
|
|
|
|
func TestWhatTheMeshDeliversIsFingerprintedNeverReturned(t *testing.T) {
|
|
dir := t.TempDir()
|
|
secret := filepath.Join(dir, "anchor.redis.secret")
|
|
_ = os.WriteFile(secret, []byte("minted-value\n"), 0o600)
|
|
receives := filepath.Join(dir, "mesh.json")
|
|
doc, _ := json.Marshal(map[string]any{"requirement": "secret", "given": []map[string]string{
|
|
{"from": "redis", "node": "anchor", "as": "anchor-redis", "secret": secret},
|
|
{"from": "offer-only", "node": "anchor"},
|
|
}})
|
|
_ = os.WriteFile(receives, doc, 0o600)
|
|
asked, err := Contributions(receives)
|
|
if err != nil || len(asked) != 1 || asked[0].As != "anchor-redis" {
|
|
t.Fatalf("%+v %v", asked, err)
|
|
}
|
|
fp, length, err := DeliveredFingerprint(asked[0])
|
|
if err != nil || fp != Fingerprint("minted-value") || length != len("minted-value") {
|
|
t.Errorf("%s %d %v", fp, length, err)
|
|
}
|
|
if _, _, err := DeliveredFingerprint(Contribution{As: "x", Secret: filepath.Join(dir, "missing")}); err == nil || !strings.Contains(err.Error(), "not readable") {
|
|
t.Errorf("a missing file said %v", err)
|
|
}
|
|
}
|
|
|
|
func logins(hs []Held) string {
|
|
var out []string
|
|
for _, h := range hs {
|
|
out = append(out, h.As)
|
|
}
|
|
return strings.Join(out, ",")
|
|
}
|