Files
mesh-controller/internal/catalogue/kept_test.go
T
jschoubben e140ed5d0b An operator key, a second seal on every own secret, and the vault keeps the export
novox/hq ADR 0085, amended: the mesh's root secrets — the store's superuser,
the broker's administrator, every secret a module holds for itself — were
sealed to a node key and nothing else, so a lost node took them with it.
Now the mesh records an operator's public sealing key and seals every own
secret to it as well, minted or accepted. The private half is written once
by `operator key new` to a file the operator keeps off the mesh; the mesh
holds one more blob per secret that it cannot open.

`secret recover` opens a secret with that key, to a 0600 file, from the
store or from an export; `secret export` writes every operator-sealed copy
as ciphertext. A module that `keeps` (the vault) is handed that export as a
declared file on its own disk, so recovery survives the store.

Secrets made before the key exists have no operator copy and are said so —
the plaintext was discarded — until each is issued again.
2026-09-20 23:56:49 +02:00

69 lines
2.5 KiB
Go

package catalogue
import (
"strings"
"testing"
)
// A module that keeps the operator-sealed secrets is handed the export as a file, at 0600, and a
// module that does not keep them is handed nothing — the export goes to the vault and nowhere else.
func TestOnlyAModuleThatKeepsGetsTheExport(t *testing.T) {
vault := Manifest{Module: "mesh-vault", Version: "1", Provides: FromAnywhere("secret"),
Keeps: "/var/lib/mesh-vault/root"}
other := Manifest{Module: "zsh", Version: "1", Provides: Offers("shell")}
got, err := Resolve(shelf(vault, other), []string{"mesh-vault", "zsh"},
Node{Name: "anchor", At: "10.0.0.1", Capabilities: map[string]bool{}}, World{})
if err != nil {
t.Fatal(err)
}
kept := &KeptExport{Export: 1, OperatorKey: "OPERATOR", Fingerprint: "sha256:abcd",
Kept: []Kept{{Node: "anchor", Module: "postgres", Name: "superuser", Origin: "accepted", Sealed: "CIPHERTEXT", Key: "OPERATOR"}}}
out, err := got.Declaration(Rendering{Kept: kept})
if err != nil {
t.Fatal(err)
}
var files int
for _, r := range out {
if r["path"] != "/var/lib/mesh-vault/root/export.json" {
continue
}
files++
if r["mode"] != "0600" {
t.Errorf("the export is written at mode %v, and it is the mesh's root secrets, sealed or not", r["mode"])
}
content, _ := r["content"].(string)
for _, want := range []string{`"operator-key": "OPERATOR"`, `"sealed": "CIPHERTEXT"`, `"module": "postgres"`} {
if !strings.Contains(content, want) {
t.Errorf("the export lacks %s:\n%s", want, content)
}
}
if id, _ := r["id"].(string); !strings.Contains(id, "mesh-vault") {
t.Errorf("the export's resource id %q does not carry its module", id)
}
}
if files != 1 {
t.Fatalf("%d export files; one module keeps them", files)
}
// No operator key yet: the vault is declared without the file, not with an empty one.
out, err = got.Declaration(Rendering{})
if err != nil {
t.Fatal(err)
}
for _, r := range out {
if r["path"] == "/var/lib/mesh-vault/root/export.json" {
t.Fatal("an export was written with nothing to export")
}
}
}
func TestKeepsMustBeAnAbsolutePath(t *testing.T) {
_, err := ParseManifest([]byte(`{"module":"mesh-vault","version":"1","keeps":"root"}`))
if err == nil || !strings.Contains(err.Error(), "keeps") {
t.Fatalf("a relative keeps path was not refused: %v", err)
}
if _, err := ParseManifest([]byte(`{"module":"mesh-vault","version":"1","keeps":"/var/lib/mesh-vault/root"}`)); err != nil {
t.Fatalf("an absolute keeps path was refused: %v", err)
}
}