The send minted a random value for a plain own secret marked issued-by outside and placed it, so a module could not tell "not given" from "given and wrong" (ADR 0228). It now places only a value a person gave: not given is no file, an empty value where a module's file names it, and nothing to restart on, as ADR 0283 decided for a family's member. A value the mesh made for one earlier is not read as given.
121 lines
4.5 KiB
Go
121 lines
4.5 KiB
Go
package main
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/novox/mesh-controller/internal/catalogue"
|
|
)
|
|
|
|
// An own secret issued outside the mesh that nobody gave is never made (novox/hq issue 401, ADR 0228). Seen on
|
|
// 2026-10-10: the send made a random value for the mounts module's smb-credentials and placed it, and the module read
|
|
// it as a credential given and wrong. The send now makes none, places none, and places a value only once a person
|
|
// gave one — and a value the mesh made for it before is not placed either.
|
|
|
|
// anAssistant is a module with a secret the mesh makes and one only an outside party issues.
|
|
func anAssistant() catalogue.Manifest {
|
|
return catalogue.Manifest{Module: "assistant", Version: "1",
|
|
OwnSecrets: catalogue.OwnSecrets{
|
|
"password": {Path: "/var/lib/mesh/assistant/password", Taken: catalogue.TakenAtStart},
|
|
"vendor-key": {Path: "/var/lib/mesh/assistant/vendor-key", Taken: catalogue.TakenAtStart, IssuedBy: catalogue.IssuedOutside},
|
|
},
|
|
Resources: []map[string]any{
|
|
{"id": "state", "type": "directory", "path": "/var/lib/mesh/assistant", "mode": "0700"},
|
|
}}
|
|
}
|
|
|
|
// sentTo composes what a push sends to a machine, on the send path.
|
|
func sentTo(t *testing.T, open *stores, node string) []map[string]any {
|
|
t.Helper()
|
|
plan, settings, err := planFor(t.Context(), open, node)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
declared, err := declarationFor(t.Context(), open, node, plan, settings)
|
|
if err != nil {
|
|
t.Fatalf("the send to %s did not compose: %v", node, err)
|
|
}
|
|
return declared.Resources
|
|
}
|
|
|
|
func placedAt(resources []map[string]any, path string) map[string]any {
|
|
for _, r := range resources {
|
|
if r["path"] == path && r["sealed"] != nil {
|
|
return r
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func TestTheSendMakesNoValueForAnOutsideSecretNobodyGave(t *testing.T) {
|
|
open := aMesh(t)
|
|
ctx := t.Context()
|
|
register(t, open, anAssistant())
|
|
if _, err := assign(ctx, open, "laptop", "assistant"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
sent := sentTo(t, open, "laptop")
|
|
if placedAt(sent, "/var/lib/mesh/assistant/password") == nil {
|
|
t.Fatal("the secret the mesh makes was not placed")
|
|
}
|
|
if got := placedAt(sent, "/var/lib/mesh/assistant/vendor-key"); got != nil {
|
|
t.Fatalf("a secret nobody gave was placed: %v", got)
|
|
}
|
|
if _, held, err := open.inventory.ModuleSecretIfIssued(ctx, "laptop", "assistant", "vendor-key"); err != nil || held {
|
|
t.Fatalf("the send made a value for a secret issued outside the mesh (held %v, %v)", held, err)
|
|
}
|
|
|
|
// A value the mesh made before this rule is not one a person gave: it is not placed.
|
|
if _, err := open.inventory.SecretForModule(ctx, "laptop", "assistant", "vendor-key"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got := placedAt(sentTo(t, open, "laptop"), "/var/lib/mesh/assistant/vendor-key"); got != nil {
|
|
t.Fatalf("a value the mesh made for a secret issued outside was placed: %v", got)
|
|
}
|
|
|
|
// Given, it is placed.
|
|
if err := open.inventory.AcceptSecretForModule(ctx, "laptop", "assistant", "vendor-key", "the vendor's key"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
given, ok, err := open.inventory.GivenOwnSecret(ctx, "laptop", "assistant", "vendor-key")
|
|
if err != nil || !ok || !given.Current {
|
|
t.Fatalf("the value given is not read as given: %+v %v %v", given, ok, err)
|
|
}
|
|
placed := placedAt(sentTo(t, open, "laptop"), "/var/lib/mesh/assistant/vendor-key")
|
|
if placed == nil || placed["sealed"] != given.Sealed {
|
|
t.Fatalf("the value given is placed as %v", placed)
|
|
}
|
|
}
|
|
|
|
// The read paths answer as the send does: a question about the machine composes without the secret nobody gave, and
|
|
// asking writes nothing.
|
|
func TestAQuestionComposesWithoutAnOutsideSecretNobodyGave(t *testing.T) {
|
|
open := aMesh(t)
|
|
ctx := t.Context()
|
|
register(t, open, anAssistant())
|
|
if _, err := assign(ctx, open, "laptop", "assistant"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
pushedBy(t, open, "laptop") // the mesh's own secret is made by the send
|
|
plan, settings, err := planFor(ctx, open, "laptop")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
gens, err := generators(ctx, open)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, choosing := range []Choosing{Reading, Foreseeing} {
|
|
got, err := declarationWith(ctx, open, "laptop", plan, settings, gens, choosing)
|
|
if err != nil {
|
|
t.Fatalf("%v: %v", choosing, err)
|
|
}
|
|
if placedAt(got.Resources, "/var/lib/mesh/assistant/vendor-key") != nil || len(got.foreseen) != 0 {
|
|
t.Fatalf("%v: a secret nobody gave is composed (foreseen %v)", choosing, got.foreseen)
|
|
}
|
|
}
|
|
if _, held, err := open.inventory.ModuleSecretIfIssued(ctx, "laptop", "assistant", "vendor-key"); err != nil || held {
|
|
t.Fatalf("a question made a value (held %v, %v)", held, err)
|
|
}
|
|
}
|