Merge pull request 'Readers of the assignments skip an ended or pending one (design 47 milestone 5, issue 1098)' (#357) from feat/chain-on-the-bus into main

This commit was merged in pull request #357.
This commit is contained in:
2026-10-18 02:04:16 +00:00
18 changed files with 236 additions and 31 deletions
+1 -1
View File
@@ -3,7 +3,7 @@ module gitea
go 1.25.0
require (
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261016174426-a4e7f480b3b0
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261018003858-f185aedbf5d6
github.com/nats-io/nats-server/v2 v2.11.17
github.com/nats-io/nats.go v1.51.0
golang.org/x/crypto v0.50.0
+24 -22
View File
@@ -1,27 +1,29 @@
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI=
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0=
github.com/google/go-tpm v0.9.8/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY=
github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo=
github.com/klauspost/compress v1.18.5/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
github.com/klauspost/compress v1.18.5 h1:/h1gH5Ce+VWNLSWqPzOVn6XBO+vJbCNGvjoaGBFW2IE=
github.com/minio/highwayhash v1.0.4/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ=
github.com/minio/highwayhash v1.0.4 h1:asJizugGgchQod2ja9NJlGOWq4s7KsAWr5XUc9Clgl4=
github.com/nats-io/jwt/v2 v2.8.1/go.mod h1:nWnOEEiVMiKHQpnAy4eXlizVEtSfzacZ1Q43LIRavZg=
github.com/nats-io/jwt/v2 v2.8.1 h1:V0xpGuD/N8Mi+fQNDynXohVvp7ZztevW5io8CUWlPmU=
github.com/nats-io/nats.go v1.51.0/go.mod h1:26HypzazeOkyO3/mqd1zZd53STJN0EjCYF9Uy2ZOBno=
github.com/nats-io/nats.go v1.51.0 h1:ByW84XTz6W03GSSsygsZcA+xgKK8vPGaa/FCAAEHnAI=
github.com/nats-io/nats-server/v2 v2.11.17/go.mod h1:B1sFVz4StNosQ903ak4N1G01Fl/9f8e06mXpFIE2K24=
github.com/nats-io/nats-server/v2 v2.11.17 h1:GKEghcFK6A+aFx11Yf1LjgLC3txAwvyhnYzhBIQZA8I=
github.com/nats-io/nkeys v0.4.15/go.mod h1:CpMchTXC9fxA5zrMo4KpySxNjiDVvr8ANOSZdiNfUrs=
github.com/nats-io/nkeys v0.4.15 h1:JACV5jRVO9V856KOapQ7x+EY8Jo3qw1vJt/9Jpwzkk4=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261016174426-a4e7f480b3b0/go.mod h1:GFuZUElBZ9A++mxgIKo97aXXo+kV0uJ/UkbhQPPIbrY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261016174426-a4e7f480b3b0 h1:EK84so3Y8JdFT3BHrzj9cPQQrDUPa/d+IdOGnerlmEI=
golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261016174426-a4e7f480b3b0/go.mod h1:GFuZUElBZ9A++mxgIKo97aXXo+kV0uJ/UkbhQPPIbrY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261018003858-f185aedbf5d6 h1:Sv1Qzix+U1RpaUkw5IbB0IJEyZ+FqgzHmbZrCZkcWf0=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261018003858-f185aedbf5d6/go.mod h1:GFuZUElBZ9A++mxgIKo97aXXo+kV0uJ/UkbhQPPIbrY=
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0=
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI=
github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo=
github.com/google/go-tpm v0.9.8/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY=
github.com/klauspost/compress v1.18.5 h1:/h1gH5Ce+VWNLSWqPzOVn6XBO+vJbCNGvjoaGBFW2IE=
github.com/klauspost/compress v1.18.5/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
github.com/minio/highwayhash v1.0.4 h1:asJizugGgchQod2ja9NJlGOWq4s7KsAWr5XUc9Clgl4=
github.com/minio/highwayhash v1.0.4/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ=
github.com/nats-io/jwt/v2 v2.8.1 h1:V0xpGuD/N8Mi+fQNDynXohVvp7ZztevW5io8CUWlPmU=
github.com/nats-io/jwt/v2 v2.8.1/go.mod h1:nWnOEEiVMiKHQpnAy4eXlizVEtSfzacZ1Q43LIRavZg=
github.com/nats-io/nats-server/v2 v2.11.17 h1:GKEghcFK6A+aFx11Yf1LjgLC3txAwvyhnYzhBIQZA8I=
github.com/nats-io/nats-server/v2 v2.11.17/go.mod h1:B1sFVz4StNosQ903ak4N1G01Fl/9f8e06mXpFIE2K24=
github.com/nats-io/nats.go v1.51.0 h1:ByW84XTz6W03GSSsygsZcA+xgKK8vPGaa/FCAAEHnAI=
github.com/nats-io/nats.go v1.51.0/go.mod h1:26HypzazeOkyO3/mqd1zZd53STJN0EjCYF9Uy2ZOBno=
github.com/nats-io/nkeys v0.4.15 h1:JACV5jRVO9V856KOapQ7x+EY8Jo3qw1vJt/9Jpwzkk4=
github.com/nats-io/nkeys v0.4.15/go.mod h1:CpMchTXC9fxA5zrMo4KpySxNjiDVvr8ANOSZdiNfUrs=
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI=
golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
+1 -1
View File
@@ -2,4 +2,4 @@ module keycloak
go 1.25.0
require git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261016174426-a4e7f480b3b0
require git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261018003858-f185aedbf5d6
+2
View File
@@ -1,2 +1,4 @@
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261016174426-a4e7f480b3b0 h1:EK84so3Y8JdFT3BHrzj9cPQQrDUPa/d+IdOGnerlmEI=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261016174426-a4e7f480b3b0/go.mod h1:GFuZUElBZ9A++mxgIKo97aXXo+kV0uJ/UkbhQPPIbrY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261018003858-f185aedbf5d6 h1:Sv1Qzix+U1RpaUkw5IbB0IJEyZ+FqgzHmbZrCZkcWf0=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261018003858-f185aedbf5d6/go.mod h1:GFuZUElBZ9A++mxgIKo97aXXo+kV0uJ/UkbhQPPIbrY=
@@ -551,3 +551,43 @@ func TestTheVerbsArgumentsAreReadStrictly(t *testing.T) {
t.Errorf("read %+v (%v)", call, err)
}
}
// Issue 1098: a value of the assignments bucket with `ended` set, or with a `state`, is not an assignment: it
// resolves nothing and takes the module's resolved values away, as a removed key does.
func TestAnEndedAssignmentIsNotAnAssignment(t *testing.T) {
c, m := aMesh(t)
m.assign(t, "ace", "dunst")
if r, err := c.Reconcile(); err != nil || len(r.Moved) != 4 {
t.Fatalf("the assignment moved %+v (%v)", r.Moved, err)
}
for _, ended := range []string{`"ended":"2026-10-18T01:00:00Z"`, `"state":"pending"`} {
m.mirror(t, AssignmentsRead, "ace.dunst", `{"node":"ace","module":"dunst","assigned":"2026-10-14T00:00:00Z",`+ended+`}`)
r, err := c.Reconcile()
if err != nil || len(r.Moved) != 4 || !r.Moved[0].Gone {
t.Errorf("%s moved %+v (%v)", ended, r.Moved, err)
}
if e, _ := m.Get(ResolvedState, ResolvedKey("ace", "dunst", "font-size")); e != nil {
t.Errorf("%s: the module keeps its resolved values", ended)
}
m.assign(t, "ace", "dunst")
if r, _ = c.Reconcile(); len(r.Moved) != 4 {
t.Fatalf("the assignment standing again moved %+v", r.Moved)
}
}
}
// Issue 1098: the fields the controller adds to an assignment change nothing, under the same key.
func TestAnAssignmentCarriesBuildCommitAndRolloutWithoutChangingItsKey(t *testing.T) {
c, m := aMesh(t)
m.mirror(t, AssignmentsRead, "ace.dunst", `{"node":"ace","module":"dunst","assigned":"2026-10-14T00:00:00Z",`+
`"build":"b-1","artifact":{"name":"dunst","version":"1.2"},"commit":"abc123","rollout":"r-9",`+
`"since":"2026-10-18T00:00:00Z","ended":"","state":"","future":{"x":1}}`)
r, err := c.Reconcile()
if err != nil || len(r.Moved) != 4 {
t.Fatalf("an assignment with the new fields moved %+v (%v)", r.Moved, err)
}
expect(t, m, "ace", "10", SourceDefault)
if r, _ = c.Reconcile(); len(r.Moved) != 0 {
t.Errorf("a quiet pass moved %+v", r.Moved)
}
}
@@ -121,10 +121,24 @@ type Published struct {
Commit string `json:"commit"`
}
// Assignment is one key of the assignments mirror: a module on a node.
// Assignment is one key of the assignments bucket: a module on a node. The value also carries the build, commit and
// rollout that put it there and more; those are read where they are reported, and an unknown field never fails a
// parse. **Ended** and **State** are set on a value that is not a standing assignment (novox/hq ADR 0408 clause 4):
// it reads exactly as a removed key (issue 1098).
type Assignment struct {
Node string `json:"node"`
Module string `json:"module"`
Node string `json:"node"`
Module string `json:"module"`
Ended json.RawMessage `json:"ended,omitempty"`
State json.RawMessage `json:"state,omitempty"`
}
// Standing is whether the value is a standing assignment: neither ended nor in a state.
func (a Assignment) Standing() bool { return !fieldSet(a.Ended) && !fieldSet(a.State) }
// fieldSet is whether a field of an assignment's value carries something: not absent, null or empty.
func fieldSet(f json.RawMessage) bool {
s := strings.TrimSpace(string(f))
return s != "" && s != "null" && s != `""`
}
// rule is the validation a value is held to, from a module's declaration or a predefined key.
@@ -19,6 +19,9 @@ func (c *Config) sources() (Sources, error) {
if err := json.Unmarshal(raw, &a); err != nil || a.Node == "" || a.Module == "" {
return fmt.Errorf("the assignment %s is not one: %s", key, raw)
}
if !a.Standing() {
return nil // ended or pending: read as a removed key (issue 1098)
}
s.Assignments = append(s.Assignments, a)
return nil
}); err != nil {
@@ -14,6 +14,8 @@ import (
"github.com/nats-io/nats.go"
"github.com/nats-io/nats.go/jetstream"
"git.novox.be/novox/mesh-sdk/go/provider"
)
// The provisioner's client on one node (novox/hq ADR 0349 clauses 4 and 5, design 57 P5, issue 671).
@@ -445,6 +447,9 @@ func (c *Client) take(s *state, u update) []string {
// A kind's answer moves what every module waits on.
return sortedKeys(s.plans)
case AssignmentsBucket:
// A value that is not a standing assignment (ended, or in a state: ADR 0408 clause 4) is read as a removed
// key, so the module leaves the machine as it does when the key goes (issue 1098).
gone = gone || !provider.Standing(e.Value())
// Whom it binds, whichever machine's it is: a provider here listing its consumers is filled again.
var providers []string
if takeBinds(s, key, e.Value(), gone) {
@@ -0,0 +1,58 @@
package main
import (
"encoding/json"
"fmt"
"testing"
"time"
)
// Issue 1098: a value of the assignments bucket with `ended` set takes the module off the node exactly as a removed
// key does, and a value with the fields the controller adds to an assignment (build, commit, rollout, unknown ones)
// is read under the same key.
func TestNatsAnEndedAssignmentTakesAModuleOffTheNodeLikeARemovedKey(t *testing.T) {
b := startBus(t)
heard := b.listen(t)
e := startEngine(t, map[string]string{dunstrc: "owned"})
b.config(t, "dunst", "font-size", "13")
p := dunst(t)
b.assign(t, "dunst", p)
aClient(t, b, e, t.TempDir(), time.Hour)
eventually(t, "the needs are recorded", func() bool { return len(b.keys(t, NeedsBucket, node+".dunst.")) == 2 })
b.put(t, AssignmentsBucket, node+".dunst", fmt.Sprintf(`{"node":%q,"module":"dunst","assigned":"2026-10-14T20:00:00Z",`+
`"build":"b-1","commit":"abc","rollout":"r-1","ended":"2026-10-18T01:00:00Z",`+
`"provisioning":%s}`, node, planJSON(t, p)))
eventually(t, "its needs go", func() bool { return len(b.keys(t, NeedsBucket, node+".dunst.")) == 0 })
eventually(t, "its report goes", func() bool { return len(b.keys(t, AppliedBucket, node+".dunst")) == 0 })
eventually(t, "prov.applied says it is removed", func() bool {
r, _ := heard.last("dunst")
return r.Status == StatusRemoved
})
}
func TestNatsAnAssignmentWithTheNewFieldsIsFilledUnderTheSameKey(t *testing.T) {
b := startBus(t)
e := startEngine(t, map[string]string{dunstrc: "owned"})
b.config(t, "dunst", "font-size", "13")
p := dunst(t)
b.assign(t, "dunst", p)
aClient(t, b, e, t.TempDir(), time.Hour)
eventually(t, "the needs are recorded", func() bool { return len(b.keys(t, NeedsBucket, node+".dunst.")) == 2 })
b.put(t, AssignmentsBucket, node+".dunst", fmt.Sprintf(`{"node":%q,"module":"dunst","assigned":"2026-10-14T20:00:00Z",`+
`"build":"b-1","artifact":{"name":"dunst","version":"1"},"commit":"abc","rollout":"r-1",`+
`"since":"2026-10-18T00:00:00Z","ended":"","state":"","future":1,"provisioning":%s}`, node, planJSON(t, p)))
time.Sleep(300 * time.Millisecond)
if got := b.keys(t, NeedsBucket, node+".dunst."); len(got) != 2 {
t.Errorf("a value with the new fields took the module's needs away: %v", got)
}
}
func planJSON(t *testing.T, p Plan) []byte {
t.Helper()
raw, err := json.Marshal(p)
if err != nil {
t.Fatal(err)
}
return raw
}
+1 -1
View File
@@ -3,7 +3,7 @@ module mesh-provisioner-client
go 1.25.0
require (
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261016174426-a4e7f480b3b0
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261018003858-f185aedbf5d6
github.com/nats-io/nats-server/v2 v2.11.17
github.com/nats-io/nats.go v1.51.0
)
+2
View File
@@ -1,5 +1,7 @@
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261016174426-a4e7f480b3b0 h1:EK84so3Y8JdFT3BHrzj9cPQQrDUPa/d+IdOGnerlmEI=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261016174426-a4e7f480b3b0/go.mod h1:GFuZUElBZ9A++mxgIKo97aXXo+kV0uJ/UkbhQPPIbrY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261018003858-f185aedbf5d6 h1:Sv1Qzix+U1RpaUkw5IbB0IJEyZ+FqgzHmbZrCZkcWf0=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261018003858-f185aedbf5d6/go.mod h1:GFuZUElBZ9A++mxgIKo97aXXo+kV0uJ/UkbhQPPIbrY=
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0=
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI=
github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo=
+30 -1
View File
@@ -75,6 +75,35 @@ const AssignmentsRead = "mesh-controller.assignments"
// AssignmentReader reads one value of the assignments mirror, `<node>.<module>`: nil when there is none.
type AssignmentReader func(key string) ([]byte, error)
// standing wraps an assignment reader so a value that is not a standing assignment reads as a removed key: one with
// `ended` set (the module was taken off its node, novox/hq ADR 0408 clause 4), or with a `state` (a pending one). The
// other fields of a value, new or unknown, change nothing (issue 1098).
func standing(read AssignmentReader) AssignmentReader {
if read == nil {
return nil
}
return func(key string) ([]byte, error) {
raw, err := read(key)
if err != nil || raw == nil {
return raw, err
}
var v struct {
Ended json.RawMessage `json:"ended"`
State json.RawMessage `json:"state"`
}
if json.Unmarshal(raw, &v) == nil && (fieldSet(v.Ended) || fieldSet(v.State)) {
return nil, nil
}
return raw, nil
}
}
// fieldSet is whether a field of an assignment's value carries something: not absent, null or empty.
func fieldSet(f json.RawMessage) bool {
s := strings.TrimSpace(string(f))
return s != "" && s != "null" && s != `""`
}
// Declared is the rule the running vault keeps: a node's provisioner client, for a secret of a module on its node
// that the module's plan there names.
type Declared struct {
@@ -141,7 +170,7 @@ func (d Declared) May(caller, name string) (bool, string) {
if d.Read == nil {
return false, "the vault cannot read the assignments, so it cannot tell what " + node + "'s declaration names"
}
raw, err := d.Read(node + "." + module)
raw, err := standing(d.Read)(node + "." + module)
if err != nil {
return false, fmt.Sprintf(notYetPrefix+"the assignment %s.%s could not be read, so what it names is not known: %v",
node, module, err)
@@ -0,0 +1,43 @@
package main
import "testing"
// Issue 1098: a value of the assignments bucket that is not a standing assignment (one with `ended` set, or with a
// `state`) reads as a removed key, whichever way the vault reads it; the fields the controller adds change nothing.
func TestAnEndedAssignmentIsNotAnAssignmentToTheVault(t *testing.T) {
plan := `"provisioning":{"templates":{"source":"x","digest":"y"},"files":[],"secrets":[{"name":"token"}],` +
`"provisions":[{"provision":"gitea-read","provider":"novox","provider-module":"gitea"},` +
`{"name":"gitea-read","provision":"gitea-read","provider":"novox","provider-module":"gitea"}]}`
head := `{"node":"g14","module":"dunst","assigned":"2026-10-14T20:00:00Z",`
mirror := assignments{
"g14.dunst": head + plan + `}`,
"g14.ended": `{"node":"g14","module":"ended","ended":"2026-10-18T01:00:00Z",` + plan + `}`,
"g14.wait": `{"node":"g14","module":"wait","state":"pending",` + plan + `}`,
"g14.new": `{"node":"g14","module":"new","build":"b1","artifact":{"name":"x","version":"1"},"commit":"c1",` +
`"rollout":"r1","since":"2026-10-18T00:00:00Z","unknown-field":[1],"ended":"","state":"",` + plan + `}`,
}
rule := Declared{Read: mirror.read}
for module, want := range map[string]bool{"dunst": true, "new": true, "ended": false, "wait": false} {
if ok, why := rule.May("provisioner.g14", "own/g14/"+module+"/token"); ok != want {
t.Errorf("own secret of %s: allowed %v (%s), want %v", module, ok, why, want)
}
if ok, why := rule.May("provisioner.g14", "provision/novox/gitea-read/g14/"+module); ok != want {
t.Errorf("credential of %s: allowed %v (%s), want %v", module, ok, why, want)
}
if why := pairRowRefusal(mirror.read, "g14", []string{"pair", "novox", "gitea-read", "g14", module}); (why == "") != want {
t.Errorf("pair row of %s: refusal %q, want allowed %v", module, why, want)
}
}
seen, err := readBindings(Mirror{Keys: mirror.keys, Read: mirror.read})
if err != nil {
t.Fatal(err)
}
for module, want := range map[string]bool{"dunst": true, "new": true, "ended": false, "wait": false} {
if seen.assigned["g14."+module] != want || seen.handed["g14."+module] != want {
t.Errorf("binding of %s: assigned %v, want %v", module, seen.assigned["g14."+module], want)
}
}
if got := seen.bound[pairKey{"novox", "gitea-read"}]; got == nil || len(got.holders) != 2 {
t.Errorf("the bound holders of the provision: %+v", got)
}
}
@@ -223,6 +223,7 @@ func readBindings(m Mirror) (bindings, error) {
if m.Keys == nil || m.Read == nil {
return b, errors.New("the vault cannot read the assignments, so it cannot see who binds a provider")
}
m.Read = standing(m.Read)
keys, err := m.Keys()
if err != nil {
return b, fmt.Errorf("the assignments' keys could not be read: %w", err)
@@ -704,6 +705,7 @@ func sharedRefusal(store *Store, read AssignmentReader, node, provider, provisio
if read == nil {
return "the vault cannot read the assignments, so it cannot tell what " + node + "'s plans name"
}
read = standing(read)
if node == provider && sh.ProviderModule != "" {
for _, m := range strings.Split(sh.ProviderModule, ",") {
if raw, err := read(node + "." + m); err == nil && raw != nil {
@@ -787,6 +789,7 @@ func pairRowRefusal(read AssignmentReader, node string, parts []string) string {
if read == nil {
return "the vault cannot read the assignments, so it cannot tell what " + node + "'s plans name"
}
read = standing(read)
raw, err := read(consumer + "." + module)
if err != nil {
return fmt.Sprintf(notYetPrefix+"the assignment %s.%s could not be read: %v", consumer, module, err)
+1 -1
View File
@@ -3,7 +3,7 @@ module postgres
go 1.25.0
require (
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261016174426-a4e7f480b3b0
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261018003858-f185aedbf5d6
github.com/jackc/pgx/v5 v5.11.0
)
+2
View File
@@ -1,5 +1,7 @@
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261016174426-a4e7f480b3b0 h1:EK84so3Y8JdFT3BHrzj9cPQQrDUPa/d+IdOGnerlmEI=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261016174426-a4e7f480b3b0/go.mod h1:GFuZUElBZ9A++mxgIKo97aXXo+kV0uJ/UkbhQPPIbrY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261018003858-f185aedbf5d6 h1:Sv1Qzix+U1RpaUkw5IbB0IJEyZ+FqgzHmbZrCZkcWf0=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261018003858-f185aedbf5d6/go.mod h1:GFuZUElBZ9A++mxgIKo97aXXo+kV0uJ/UkbhQPPIbrY=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+1 -1
View File
@@ -2,4 +2,4 @@ module route-adapter
go 1.25.0
require git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261016174426-a4e7f480b3b0
require git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261018003858-f185aedbf5d6
+2
View File
@@ -1,2 +1,4 @@
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261016174426-a4e7f480b3b0 h1:EK84so3Y8JdFT3BHrzj9cPQQrDUPa/d+IdOGnerlmEI=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261016174426-a4e7f480b3b0/go.mod h1:GFuZUElBZ9A++mxgIKo97aXXo+kV0uJ/UkbhQPPIbrY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261018003858-f185aedbf5d6 h1:Sv1Qzix+U1RpaUkw5IbB0IJEyZ+FqgzHmbZrCZkcWf0=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261018003858-f185aedbf5d6/go.mod h1:GFuZUElBZ9A++mxgIKo97aXXo+kV0uJ/UkbhQPPIbrY=