Seal the stand-in vault box by the resource's id, and set the setting before the machines are assigned in the served-fact tests (issues 1385, 1382)
The live try (build-1792488565282382172) left a stand-in vault box in f35 and yvbpsm: the file was matched by the manifest's path, which the composition fills in for the machine. The seal now matches by the resource's id alone and names any stand-in that is left. The two served-fact tests set the setting before assigning (an assignment resolves the mesh), and the second clears it after.
This commit is contained in:
@@ -89,3 +89,26 @@ func TestTheMachineThatRunsTheBusIsRefusedWhereNoUserHasACredential(t *testing.T
|
||||
t.Fatalf("a bus with users is refused: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// The controller's seal replaces the stand-in box whatever path the resource carries: the path is the manifest's with the
|
||||
// machine's words filled in, not the manifest's own. It failed first, with the path compared (the live try: "composed twice and
|
||||
// still names ... asked of the vault by the next send").
|
||||
func TestTheControllersSealReplacesTheBoxWhateverPathTheFileCarries(t *testing.T) {
|
||||
in, module := aCoreInput(t)
|
||||
d, _, err := compose.ComposeIn(in.Input, "laptop", compose.Foreseeing)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, r := range d.Resources {
|
||||
if _, box := r[catalogue.VaultSealedField]; box {
|
||||
r["path"] = "/home/someone/.var/lib/mesh-provisioner-client/broker"
|
||||
}
|
||||
}
|
||||
sealed, _, err := sealedByTheController(in, "laptop", d, []string{module})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if left := stillForeseen(sealed); len(left) != 0 {
|
||||
t.Fatalf("the declaration still stands in for %v", left)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,15 +262,17 @@ func TestAServedFactThatSaysASettingIsResolvedWithTheSettingInTheInput(t *testin
|
||||
Provides: []catalogue.Offer{{Name: "acme-ca", Scope: catalogue.ScopeMesh}},
|
||||
Serves: map[string]map[string]any{"acme-ca": {"domain": "${setting:domain}"}}})
|
||||
register(t, open, catalogue.Manifest{Module: "route-proxy", Version: "1", Requires: []string{"acme-ca"}})
|
||||
// The setting is there before the machines are assigned: an assignment resolves the mesh, and a served fact that says
|
||||
// ${setting:domain} resolves only with it.
|
||||
if err := open.inventory.KeepSettings(ctx, "", "step-ca", map[string]any{"domain": "example.test"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := assign(ctx, open, "anchor", "step-ca"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := assign(ctx, open, "laptop", "route-proxy"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := open.inventory.SetSettings(ctx, "", "step-ca", map[string]any{"domain": "example.test"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
in, err := readComposeInput(ctx, open)
|
||||
if err != nil {
|
||||
t.Fatalf("the Input cannot be built: %v", err)
|
||||
@@ -301,12 +303,19 @@ func TestAServedFactThatSaysAnUnsetSettingIsRefusedAsTheControllerRefusesIt(t *t
|
||||
Provides: []catalogue.Offer{{Name: "acme-ca", Scope: catalogue.ScopeMesh}},
|
||||
Serves: map[string]map[string]any{"acme-ca": {"domain": "${setting:domain}"}}})
|
||||
register(t, open, catalogue.Manifest{Module: "route-proxy", Version: "1", Requires: []string{"acme-ca"}})
|
||||
// Assigned with the setting there, then the setting is cleared: the mesh the controller holds when someone clears it.
|
||||
if err := open.inventory.KeepSettings(ctx, "", "step-ca", map[string]any{"domain": "example.test"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := assign(ctx, open, "anchor", "step-ca"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := assign(ctx, open, "laptop", "route-proxy"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := open.inventory.ClearSettings(ctx, "", "step-ca"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, _, oldErr := planFor(ctx, open, "laptop")
|
||||
_, newErr := readComposeInput(ctx, open)
|
||||
if (oldErr == nil) != (newErr == nil) {
|
||||
|
||||
@@ -426,10 +426,11 @@ func sealedByTheController(in *meshInput, node string, d compose.Declared, modul
|
||||
if sealed == "" {
|
||||
return d, nil, fmt.Errorf("%s/%s on %s has no seal of the controller's to carry until the vault holds it", w.Module, w.Name, node)
|
||||
}
|
||||
path := in.Catalogue[w.Module].OwnSecrets[w.Name].Path
|
||||
for _, r := range d.Resources {
|
||||
box, isBox := r[catalogue.VaultSealedField]
|
||||
if !isBox || r["id"] != w.Module+"."+catalogue.NeedID(w.Name) || r["path"] != path {
|
||||
// By the resource's id alone: its path is the manifest's with the machine's words filled in, and so is not the
|
||||
// manifest's own.
|
||||
if !isBox || r["id"] != w.Module+"."+catalogue.NeedID(w.Name) {
|
||||
continue
|
||||
}
|
||||
if had, err := compactBox(box); err != nil || had != stood {
|
||||
@@ -439,6 +440,17 @@ func sealedByTheController(in *meshInput, node string, d compose.Declared, modul
|
||||
r["sealed"] = sealed
|
||||
}
|
||||
}
|
||||
// A stand-in box that is left is said by its resource, never sent and never guessed at.
|
||||
for _, r := range d.Resources {
|
||||
if box, has := r[catalogue.VaultSealedField]; has {
|
||||
if had, err := compactBox(box); err == nil && had == stood {
|
||||
if id, _ := r["id"].(string); slices.ContainsFunc(modules, func(m string) bool { return strings.HasPrefix(id, m+".") }) {
|
||||
return d, nil, fmt.Errorf("%s on %s still carries a stand-in for the vault's box, and the controller has "+
|
||||
"no seal of its own for it", id, node)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
d.CoreBoxesWanted = wanted
|
||||
for _, f := range d.Foreseen {
|
||||
module, _, _ := strings.Cut(f, "/")
|
||||
|
||||
Reference in New Issue
Block a user