Write the facts snapshot in format 2, with each machine's grants and credential bindings (design 47 R4c-2, issue 1394)

Every reader takes format 2 since R4b (ADR 0456 clause 1), and the assigner's composition check reads the grants and bindings (ADR 0456 clause 2): the writer moves now, names only, never a sealed value.
This commit is contained in:
2026-10-20 18:26:07 +00:00
parent f2d7bc9480
commit b75fb7899e
3 changed files with 69 additions and 22 deletions
+22 -2
View File
@@ -9,6 +9,7 @@ import (
"git.novox.be/novox/mesh-sdk/go/catalogue"
snapshot "git.novox.be/novox/mesh-sdk/go/facts"
"github.com/novox/mesh-controller/internal/inventory"
)
// The facts snapshot (novox/hq to-be 45 §9): composed from the store, every machine under a pseudonym
@@ -55,6 +56,11 @@ func aMeshWithSecrets(t *testing.T) (*stores, []string) {
// Sealed, never kept plain (ADR 0004): the sealed blobs are what the store holds, and none may leave.
secrets = append(secrets, s.ForConsumer, s.ForProvider)
}
// A binding recorded for the consumer on the laptop, to the provider on the anchor.
if err := open.inventory.RecordBindings(ctx, "laptop", []inventory.Binding{{Machine: "laptop", Consumer: "files",
Provision: "s3-bucket", Provider: catalogue.Chosen{Node: "anchor", Module: "objects"}}}); err != nil {
t.Fatal(err)
}
return open, secrets
}
@@ -64,8 +70,8 @@ func TestTheFactsCarryNoSecretNoAddressAndNoName(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if f.Format != 1 {
t.Fatalf("the writer wrote format %d: it keeps format 1 until its own release moves it (issue 1390)", f.Format)
if f.Format != 2 {
t.Fatalf("the writer wrote format %d, not 2 (issue 1394)", f.Format)
}
body, err := f.Encode()
if err != nil {
@@ -89,6 +95,20 @@ func TestTheFactsCarryNoSecretNoAddressAndNoName(t *testing.T) {
}
}
// 1394/AC1: the provider's machine lists the grant, the consumer's machine the binding, machine names scrubbed.
anchorFacts, _ := f.Machine(snapshot.Pseudonym("machine", "anchor"))
laptopFacts, _ := f.Machine(snapshot.Pseudonym("machine", "laptop"))
wantGrant := snapshot.Grant{Provision: "s3-bucket", ConsumerNode: snapshot.Pseudonym("machine", "laptop"), ConsumerModule: "files"}
if len(anchorFacts.Grants) != 1 || anchorFacts.Grants[0] != wantGrant {
t.Errorf("the anchor's grants read as %+v, want %+v", anchorFacts.Grants, wantGrant)
}
wantBinding := snapshot.Binding{ConsumerModule: "files", Provision: "s3-bucket",
ProviderNode: snapshot.Pseudonym("machine", "anchor"), ProviderModule: "objects"}
if len(laptopFacts.Bindings) != 1 || laptopFacts.Bindings[0] != wantBinding {
t.Errorf("the laptop's bindings read as %+v, want %+v", laptopFacts.Bindings, wantBinding)
}
// 1394/AC2: the text scan above ran over a snapshot that holds those rows, so no sealed value is among them.
// What a check needs is there: every machine, its length, its modules, its declaration composing.
if len(f.Machines) != 2 || f.Longest() != len("laptop") {
t.Fatalf("machines %+v, longest %d", f.Machines, f.Longest())