From b692a9528089f722bab1ac2a855a0422c99d981e Mon Sep 17 00:00:00 2001 From: mesh-tools Date: Tue, 20 Oct 2026 09:41:16 +0000 Subject: [PATCH] Read the facts snapshot with mesh-sdk's go/facts, formats 1 and 2, and keep writing format 1 (issue 1390, 3 of 4) The merge gate, the build seat's check and the facts writer import the snapshot's type from mesh-sdk (go/facts), whose reader takes formats 1 and 2 and refuses a newer one. The writer keeps writing format 1 (writtenFormat); moving it to 2 is a release of its own (novox/hq ADR 0456). A test shows the writer writes format 1, carries no grants or bindings, and the reader takes both formats and refuses a newer one. --- .../agent_account_integration_test.go | 2 +- .../compose_equal_integration_test.go | 2 +- cmd/mesh-controller/config_moved_test.go | 2 +- cmd/mesh-controller/facts.go | 9 ++- cmd/mesh-controller/facts_format_test.go | 58 +++++++++++++++++++ cmd/mesh-controller/facts_test.go | 5 +- cmd/mesh-controller/merge_gate.go | 2 +- .../merge_gate_handing_test.go | 2 +- .../merge_gate_integration_test.go | 2 +- cmd/mesh-controller/planner_rules_test.go | 2 +- cmd/mesh-controller/replay867_test.go | 2 +- .../template_integration_test.go | 2 +- internal/builder/check.go | 2 +- internal/builder/check_credential_test.go | 2 +- internal/builder/check_test.go | 2 +- 15 files changed, 81 insertions(+), 15 deletions(-) create mode 100644 cmd/mesh-controller/facts_format_test.go diff --git a/cmd/mesh-controller/agent_account_integration_test.go b/cmd/mesh-controller/agent_account_integration_test.go index 1d615a1c..ece0c1f5 100644 --- a/cmd/mesh-controller/agent_account_integration_test.go +++ b/cmd/mesh-controller/agent_account_integration_test.go @@ -7,8 +7,8 @@ import ( "testing" "time" + snapshot "git.novox.be/novox/mesh-sdk/go/facts" "github.com/novox/mesh-controller/internal/conditions" - snapshot "github.com/novox/mesh-controller/internal/facts" "github.com/novox/mesh-controller/internal/inventory" "github.com/novox/mesh-controller/internal/link" "github.com/novox/mesh-host/rootsearch" diff --git a/cmd/mesh-controller/compose_equal_integration_test.go b/cmd/mesh-controller/compose_equal_integration_test.go index d17249b3..57b62ecd 100644 --- a/cmd/mesh-controller/compose_equal_integration_test.go +++ b/cmd/mesh-controller/compose_equal_integration_test.go @@ -11,7 +11,7 @@ import ( "testing" "git.novox.be/novox/mesh-sdk/go/compose" - snapshot "github.com/novox/mesh-controller/internal/facts" + snapshot "git.novox.be/novox/mesh-sdk/go/facts" ) // 1384: nothing shows the controller's composition and mesh-sdk's compose every node alike on the live facts. This test is diff --git a/cmd/mesh-controller/config_moved_test.go b/cmd/mesh-controller/config_moved_test.go index a0578ede..2692a44e 100644 --- a/cmd/mesh-controller/config_moved_test.go +++ b/cmd/mesh-controller/config_moved_test.go @@ -8,7 +8,7 @@ import ( "testing" "git.novox.be/novox/mesh-sdk/go/catalogue" - snapshot "github.com/novox/mesh-controller/internal/facts" + snapshot "git.novox.be/novox/mesh-sdk/go/facts" "github.com/novox/mesh-controller/internal/link" ) diff --git a/cmd/mesh-controller/facts.go b/cmd/mesh-controller/facts.go index 5d9e9781..f0e5c41c 100644 --- a/cmd/mesh-controller/facts.go +++ b/cmd/mesh-controller/facts.go @@ -18,10 +18,10 @@ import ( "git.novox.be/novox/mesh-sdk/go/catalogue" "git.novox.be/novox/mesh-sdk/go/compose" + snapshot "git.novox.be/novox/mesh-sdk/go/facts" "github.com/novox/mesh-controller/internal/artifacts" "github.com/novox/mesh-controller/internal/broker" "github.com/novox/mesh-controller/internal/builder" - snapshot "github.com/novox/mesh-controller/internal/facts" "github.com/novox/mesh-controller/internal/inventory" "github.com/novox/mesh-controller/internal/link" ) @@ -171,10 +171,15 @@ func factsStore(ctx context.Context, open *stores) (string, error) { return address, nil } +// writtenFormat is the format of the snapshot this controller writes: 1, the format its own reader knew before mesh-sdk's +// go/facts took the type over (issue 1390, novox/hq ADR 0456). The readers (the merge gate, the check) read formats 1 and +// 2; the writer moves to 2, which also carries each machine's grants and bindings, in a later release of its own. +const writtenFormat = 1 + // gatherFacts composes one snapshot from the store: read only, nothing made, nothing sent. func gatherFacts(ctx context.Context, open *stores, busVersion string) (snapshot.Facts, error) { inv := open.inventory - f := snapshot.Facts{Format: snapshot.Format, Taken: time.Now().UTC(), Controller: snapshot.Build{Version: version}} + f := snapshot.Facts{Format: writtenFormat, Taken: time.Now().UTC(), Controller: snapshot.Build{Version: version}} f.Versions.Bus = busVersion storeVersion, err := inv.ServerVersion(ctx) if err != nil { diff --git a/cmd/mesh-controller/facts_format_test.go b/cmd/mesh-controller/facts_format_test.go new file mode 100644 index 00000000..b5583fcd --- /dev/null +++ b/cmd/mesh-controller/facts_format_test.go @@ -0,0 +1,58 @@ +package main + +import ( + "encoding/json" + "strings" + "testing" + "time" + + snapshot "git.novox.be/novox/mesh-sdk/go/facts" +) + +// 1390 (novox/hq ADR 0456): the snapshot this controller writes is format 1, and the reader it shares with the build seat +// (mesh-sdk's go/facts) takes formats 1 and 2 and refuses one newer than it knows. The writer moves to format 2 in a release +// of its own. It failed first with the controller's own reader, which refused format 2 as newer than it knew. +func TestTheWriterWritesFormatOneAndTheReaderTakesBothFormats(t *testing.T) { + if writtenFormat != 1 { + t.Fatalf("the writer writes format %d, not 1", writtenFormat) + } + taken := time.Date(2026, 10, 20, 9, 0, 0, 0, time.UTC) + for format, want := range map[int]bool{1: true, 2: true, 3: false} { + body, err := (snapshot.Facts{Format: format, Taken: taken}).Encode() + if err != nil { + t.Fatal(err) + } + f, err := snapshot.Decode(body) + switch { + case want && err != nil: + t.Errorf("format %d is refused: %v", format, err) + case want && f.Format != format: + t.Errorf("format %d is read as %d", format, f.Format) + case !want && (err == nil || !strings.Contains(err.Error(), "newer")): + t.Errorf("format %d is not refused as newer: %v", format, err) + } + } + // What the writer composes carries no field of format 2: a reader of 1 and of 2 read it alike. + body, err := (snapshot.Facts{Format: writtenFormat, Taken: taken, Machines: []snapshot.Machine{{Name: "abcdef", Length: 6}}}).Encode() + if err != nil { + t.Fatal(err) + } + var raw struct { + Format int `json:"facts"` + Machines []map[string]json.RawMessage `json:"machines"` + } + if err := json.Unmarshal(body, &raw); err != nil { + t.Fatal(err) + } + if raw.Format != 1 { + t.Errorf("the snapshot says format %d", raw.Format) + } + for _, m := range raw.Machines { + if _, has := m["grants"]; has { + t.Error("a format 1 snapshot carries grants") + } + if _, has := m["bindings"]; has { + t.Error("a format 1 snapshot carries bindings") + } + } +} diff --git a/cmd/mesh-controller/facts_test.go b/cmd/mesh-controller/facts_test.go index 8c67d124..c3ce5e34 100644 --- a/cmd/mesh-controller/facts_test.go +++ b/cmd/mesh-controller/facts_test.go @@ -8,7 +8,7 @@ import ( "testing" "git.novox.be/novox/mesh-sdk/go/catalogue" - snapshot "github.com/novox/mesh-controller/internal/facts" + snapshot "git.novox.be/novox/mesh-sdk/go/facts" ) // The facts snapshot (novox/hq to-be 45 §9): composed from the store, every machine under a pseudonym @@ -68,6 +68,9 @@ 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) + } body, err := f.Encode() if err != nil { t.Fatal(err) diff --git a/cmd/mesh-controller/merge_gate.go b/cmd/mesh-controller/merge_gate.go index b04927c2..dad7db22 100644 --- a/cmd/mesh-controller/merge_gate.go +++ b/cmd/mesh-controller/merge_gate.go @@ -22,9 +22,9 @@ import ( "github.com/jackc/pgx/v5" "git.novox.be/novox/mesh-sdk/go/catalogue" + snapshot "git.novox.be/novox/mesh-sdk/go/facts" "github.com/novox/mesh-controller/internal/artifacts" "github.com/novox/mesh-controller/internal/broker" - snapshot "github.com/novox/mesh-controller/internal/facts" "github.com/novox/mesh-controller/internal/inventory" "github.com/novox/mesh-controller/internal/link" "github.com/novox/mesh-controller/internal/store" diff --git a/cmd/mesh-controller/merge_gate_handing_test.go b/cmd/mesh-controller/merge_gate_handing_test.go index 4dfa0c91..318c73ff 100644 --- a/cmd/mesh-controller/merge_gate_handing_test.go +++ b/cmd/mesh-controller/merge_gate_handing_test.go @@ -4,7 +4,7 @@ import ( "testing" "time" - snapshot "github.com/novox/mesh-controller/internal/facts" + snapshot "git.novox.be/novox/mesh-sdk/go/facts" "github.com/novox/mesh-controller/internal/link" ) diff --git a/cmd/mesh-controller/merge_gate_integration_test.go b/cmd/mesh-controller/merge_gate_integration_test.go index 3cc28a22..32965523 100644 --- a/cmd/mesh-controller/merge_gate_integration_test.go +++ b/cmd/mesh-controller/merge_gate_integration_test.go @@ -9,8 +9,8 @@ import ( "testing" "git.novox.be/novox/mesh-sdk/go/catalogue" + snapshot "git.novox.be/novox/mesh-sdk/go/facts" "github.com/novox/mesh-controller/internal/broker" - snapshot "github.com/novox/mesh-controller/internal/facts" "github.com/novox/mesh-controller/internal/inventory" ) diff --git a/cmd/mesh-controller/planner_rules_test.go b/cmd/mesh-controller/planner_rules_test.go index 71d2b71f..fef72bb9 100644 --- a/cmd/mesh-controller/planner_rules_test.go +++ b/cmd/mesh-controller/planner_rules_test.go @@ -9,7 +9,7 @@ import ( "testing" "time" - snapshot "github.com/novox/mesh-controller/internal/facts" + snapshot "git.novox.be/novox/mesh-sdk/go/facts" "github.com/novox/mesh-controller/internal/inventory" "github.com/novox/mesh-controller/internal/link" ) diff --git a/cmd/mesh-controller/replay867_test.go b/cmd/mesh-controller/replay867_test.go index d316075c..879713e3 100644 --- a/cmd/mesh-controller/replay867_test.go +++ b/cmd/mesh-controller/replay867_test.go @@ -20,8 +20,8 @@ import ( "github.com/nats-io/nats.go" "git.novox.be/novox/mesh-sdk/go/catalogue" + meshfacts "git.novox.be/novox/mesh-sdk/go/facts" "github.com/novox/mesh-controller/internal/builder" - meshfacts "github.com/novox/mesh-controller/internal/facts" "github.com/novox/mesh-controller/internal/inventory" "github.com/novox/mesh-controller/internal/link" ) diff --git a/cmd/mesh-controller/template_integration_test.go b/cmd/mesh-controller/template_integration_test.go index 2a239d48..8b847819 100644 --- a/cmd/mesh-controller/template_integration_test.go +++ b/cmd/mesh-controller/template_integration_test.go @@ -10,7 +10,7 @@ import ( "testing" "git.novox.be/novox/mesh-sdk/go/catalogue" - snapshot "github.com/novox/mesh-controller/internal/facts" + snapshot "git.novox.be/novox/mesh-sdk/go/facts" "github.com/novox/mesh-controller/internal/inventory" ) diff --git a/internal/builder/check.go b/internal/builder/check.go index 51896065..06dab4fd 100644 --- a/internal/builder/check.go +++ b/internal/builder/check.go @@ -20,8 +20,8 @@ import ( "sync" "time" + "git.novox.be/novox/mesh-sdk/go/facts" "github.com/novox/mesh-controller/internal/artifacts" - "github.com/novox/mesh-controller/internal/facts" ) // A pull request's merge check, run on the build seat (novox/hq to-be 45 §9, ADR 0237). diff --git a/internal/builder/check_credential_test.go b/internal/builder/check_credential_test.go index f0c63f1c..fd73cf5f 100644 --- a/internal/builder/check_credential_test.go +++ b/internal/builder/check_credential_test.go @@ -11,7 +11,7 @@ import ( "testing" "time" - "github.com/novox/mesh-controller/internal/facts" + "git.novox.be/novox/mesh-sdk/go/facts" ) // **A check's container never sees the forge credential** (novox/hq issue 462): the toolchain container diff --git a/internal/builder/check_test.go b/internal/builder/check_test.go index 3983669f..63aea2a4 100644 --- a/internal/builder/check_test.go +++ b/internal/builder/check_test.go @@ -7,8 +7,8 @@ import ( "testing" "time" + "git.novox.be/novox/mesh-sdk/go/facts" "github.com/novox/mesh-controller/internal/artifacts" - "github.com/novox/mesh-controller/internal/facts" ) // A merge check on the build seat (novox/hq to-be 45 §9), against a real container runtime and a real