mesh-sdk names no module: the core's credentials are what a manifest says (core-credentials), and the bus's upgrade policy is the one its manifest declares (issue 774, the operator 2026-11-03)
This commit is contained in:
@@ -3,6 +3,7 @@ package catalogue
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@@ -31,4 +32,24 @@ func TestNoCatalogueManifestNamesAmqp(t *testing.T) {
|
||||
filepath.Base(filepath.Dir(path)))
|
||||
}
|
||||
}
|
||||
// Nor does this package name the modules that once had a rule of their own here (issue 774, the operator 2026-11-03):
|
||||
// what each is, its manifest says. mesh-provisioner is also a seat's name, named where the seat is.
|
||||
t.Run("the package names no module", func(t *testing.T) {
|
||||
named := regexp.MustCompile(`"(nats|mesh-provisioner-client|mesh-provisioner)"`)
|
||||
files, _ := filepath.Glob("*.go")
|
||||
for _, f := range files {
|
||||
if strings.HasSuffix(f, "_test.go") {
|
||||
continue
|
||||
}
|
||||
raw, err := os.ReadFile(f)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for i, line := range strings.Split(string(raw), "\n") {
|
||||
if named.MatchString(line) && !strings.Contains(line, "{Name: "+named.FindString(line)+", Scope:") {
|
||||
t.Errorf("%s:%d names a module: %s", f, i+1, strings.TrimSpace(line))
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -4,11 +4,10 @@ import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// CoreCredentialModules are the modules whose own secrets are the core's credentials: the bus, mesh-provisioner and
|
||||
// its client. The node-engine and the controller hold no own secret of a module's. **Fixed here, in the controller's
|
||||
// code, as the clause says** — and the vault keeps the same list (mesh-vault's CoreModules), answering the controller
|
||||
// for these alone.
|
||||
var CoreCredentialModules = []string{"mesh-provisioner", "mesh-provisioner-client", "nats"}
|
||||
// CarriesCoreCredentials says whether a module's own secrets are the core's credentials, as its manifest says
|
||||
// (Manifest.CoreCredentials): the vault seals them to the machine, and the node-engine and the vault hold no list of
|
||||
// such modules.
|
||||
func CarriesCoreCredentials(m Manifest) bool { return m.CoreCredentials }
|
||||
|
||||
// VaultSealedField is the field of a file the vault sealed to its machine (mesh-host's File.VaultSealed).
|
||||
const VaultSealedField = "vault-sealed"
|
||||
|
||||
@@ -84,7 +84,7 @@ type Rendering struct {
|
||||
// makes. Nil on every composition that is sent, and on every other question, which then refuse
|
||||
// a secret not made with a *NotMadeError.
|
||||
Foreseen map[string]map[string]bool
|
||||
// VaultSealed is, for a module on the core's list (CoreCredentialModules), each own secret as the vault sealed it
|
||||
// VaultSealed is, for a module whose manifest says its own secrets are the core's credentials (core-credentials), each own secret as the vault sealed it
|
||||
// to this machine (the mesh's sealed box, as the vault answered it), keyed like Needed (novox/hq ADR 0349 §16,
|
||||
// issue 755). Given only for a machine whose engine opens the box (VaultBoxContract): its file then carries the
|
||||
// box and never the controller's own sealed value. Nil everywhere else, and the composition is as it was.
|
||||
|
||||
@@ -27,5 +27,25 @@ func TestAManifestMaySayWhatItInvokes(t *testing.T) {
|
||||
if strings.Contains(string(back), "core-credentials") != core {
|
||||
t.Errorf("%s written back as %s", raw, back)
|
||||
}
|
||||
if CarriesCoreCredentials(m) != core {
|
||||
t.Errorf("%s: carries the core's credentials %v", raw, !core)
|
||||
}
|
||||
}
|
||||
// And its upgrade policy, which holds for the bus as for any module: providing the bus derives nothing (issue 774).
|
||||
for raw, want := range map[string]string{
|
||||
`{"module":"bus","version":"1","provides":[{"name":"mesh-bus"}],"upgrade":{"policy":"record","why":"its streams"}}`: PolicyRecord + " " + FromModule,
|
||||
`{"module":"bus","version":"1","provides":[{"name":"mesh-bus"}]}`: PolicyRoll + " " + FromDefault,
|
||||
} {
|
||||
m, err := decodeForTest([]byte(raw))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if policy, from, _ := DerivedUpgrade(m); policy+" "+from != want {
|
||||
t.Errorf("%s: derived %s %s, want %s", raw, policy, from, want)
|
||||
}
|
||||
chosen := &PersonPolicy{Policy: PolicyTogether, Why: "w", By: "a person"}
|
||||
if policy, from, _, _ := Upgrade(m, chosen); policy != PolicyTogether || from != FromPerson {
|
||||
t.Errorf("%s: a person's choice gave %s %s", raw, policy, from)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -640,7 +640,7 @@ type Manifest struct {
|
||||
|
||||
// Upgrade is how this module's new builds reach its machines (novox/hq ADR 0236): rolled out one
|
||||
// machine first and gated when unsaid; `together`, or `record` — wait for a person's push — with
|
||||
// why. A person's choice through the `upgrade` verb stands over it; the bus records whatever it says.
|
||||
// why. A person's choice through the `upgrade` verb stands over it. The bus says `record` itself.
|
||||
Upgrade *UpgradePolicy `json:"upgrade,omitempty"`
|
||||
|
||||
// Unhealthy is how loud this module's unhealthy condition is (novox/hq ADR 0355): a warning when unsaid;
|
||||
|
||||
+4
-11
@@ -30,25 +30,19 @@ type UpgradePolicy struct {
|
||||
const (
|
||||
FromPerson = "person"
|
||||
FromModule = "module"
|
||||
FromBus = "the bus"
|
||||
FromData = "irreplaceable data"
|
||||
FromDefault = "default"
|
||||
)
|
||||
|
||||
// DerivedUpgrade is the policy a module's manifest gives it when no person has chosen one, with where
|
||||
// it came from and why (ADR 0236):
|
||||
// it came from and why (ADR 0236), from what the manifest says alone (the operator, 2026-11-03: no module is
|
||||
// treated apart here; the bus says `record` in its own manifest):
|
||||
//
|
||||
// - **the bus is never rolled**: a module that provides the mesh's bus records, whatever it says — its
|
||||
// upgrade is a planned step a person starts (to-be 45 §8);
|
||||
// - a module that says its policy has it;
|
||||
// - a module that keeps irreplaceable data records — sending the previous build cannot undo what a new
|
||||
// one did to data that cannot be had again, so a person takes it, after a backup;
|
||||
// - everything else rolls out, one machine first.
|
||||
func DerivedUpgrade(m Manifest) (policy, from, why string) {
|
||||
if ProvidesBus(m) {
|
||||
return PolicyRecord, FromBus, "the bus is replaced only as a planned step a person starts (`bus upgrade`): " +
|
||||
"its streams are snapshotted first and checked after"
|
||||
}
|
||||
if m.Upgrade != nil && m.Upgrade.Policy != "" {
|
||||
return m.Upgrade.Policy, FromModule, m.Upgrade.Why
|
||||
}
|
||||
@@ -126,11 +120,10 @@ func (p PersonPolicy) Check() error {
|
||||
|
||||
// Upgrade is a module's policy and where it comes from (ADR 0565 clause 7): the one derivation every reader takes,
|
||||
// `mesh-wants.upgrade` and each node agent's judgement of a move alike. A person's choice over the module's word, its
|
||||
// irreplaceable data and the default; the bus is never rolled, whoever says so (ADR 0236). By names the person when one
|
||||
// chose.
|
||||
// irreplaceable data and the default. By names the person when one chose.
|
||||
func Upgrade(m Manifest, chosen *PersonPolicy) (policy, from, why, by string) {
|
||||
policy, from, why = DerivedUpgrade(m)
|
||||
if from == FromBus || chosen == nil {
|
||||
if chosen == nil {
|
||||
return policy, from, why, ""
|
||||
}
|
||||
return chosen.Policy, FromPerson, chosen.Why, chosen.By
|
||||
|
||||
@@ -164,8 +164,9 @@ type ComposedDigest struct {
|
||||
}
|
||||
|
||||
// The upgrade policies and their sources a composition's value names: catalogue.PolicyRoll, PolicyTogether and
|
||||
// PolicyRecord, and catalogue.FromPerson, FromModule, FromBus, FromData and FromDefault, the same words (the compose
|
||||
// package's test holds them equal; this package does not import the catalogue).
|
||||
// PolicyRecord, and catalogue.FromPerson, FromModule, FromData and FromDefault, the same words (the compose package's
|
||||
// test holds them equal; this package does not import the catalogue). "the bus" is the word an older reader derived
|
||||
// for the bus module, still read from a composition it wrote; nothing derives it now.
|
||||
var (
|
||||
composedPolicies = []string{"roll", "together", "record"}
|
||||
composedPolicyFroms = []string{"person", "module", "the bus", "irreplaceable data", "default"}
|
||||
|
||||
Reference in New Issue
Block a user