Leave a file the controller's manifest writes itself out of genesis's secrets (hq issue 597)
The controller reads its merge window's settings from a file its manifest declares from its settings (MESH_MERGE_WINDOW_FILE, ADR 0276). Step 11 took every MESH_..._FILE for a secret and refused this one as a file nobody writes, so no genesis got past step 11. A _FILE naming a file resource of the module is now the module's own; one naming neither an own-secret nor a file of the module is still refused.
This commit is contained in:
@@ -311,6 +311,17 @@ func secretsByVariableIn(manifest []byte) (map[string]string, error) {
|
|||||||
for name, path := range m.OwnSecrets {
|
for name, path := range m.OwnSecrets {
|
||||||
secretAt[path] = name
|
secretAt[path] = name
|
||||||
}
|
}
|
||||||
|
// **A file the module itself declares is its own, not a secret** (novox/hq issue 597). The
|
||||||
|
// controller reads its merge window's settings from a file its manifest writes from its settings
|
||||||
|
// (MESH_MERGE_WINDOW_FILE, ADR 0276): the mesh writes it with the module's declaration, and there
|
||||||
|
// is nothing for genesis to carry in. Only a `…_FILE` naming neither an own-secret nor a file of
|
||||||
|
// the module is refused.
|
||||||
|
declared := map[string]bool{}
|
||||||
|
for _, r := range m.Resources {
|
||||||
|
if r.Type == "file" && r.Path != "" {
|
||||||
|
declared[r.Path] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
wanted := map[string]string{}
|
wanted := map[string]string{}
|
||||||
for _, r := range m.Resources {
|
for _, r := range m.Resources {
|
||||||
@@ -333,10 +344,13 @@ func secretsByVariableIn(manifest []byte) (map[string]string, error) {
|
|||||||
on = from
|
on = from
|
||||||
}
|
}
|
||||||
secret, named := secretAt[on]
|
secret, named := secretAt[on]
|
||||||
|
if !named && declared[on] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
if !named {
|
if !named {
|
||||||
return nil, fmt.Errorf(
|
return nil, fmt.Errorf(
|
||||||
"the %s module's container reads %s from %s, and no own-secret of that "+
|
"the %s module's container reads %s from %s, and neither an own-secret nor "+
|
||||||
"module writes that file.\n"+
|
"a file of that module writes that file.\n"+
|
||||||
"So the mesh would seal nothing there and the control plane would find "+
|
"So the mesh would seal nothing there and the control plane would find "+
|
||||||
"an empty file where a connection string has to be. The manifest has to "+
|
"an empty file where a connection string has to be. The manifest has to "+
|
||||||
"name the two ends the same, directly or through a mount",
|
"name the two ends the same, directly or through a mount",
|
||||||
|
|||||||
@@ -180,3 +180,85 @@ func TestAProcessFormNamingNoOneReplacementIsRefused(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// theStepNineSecretsOf is what step 9 delivers for a process-form controller manifest: its genesis
|
||||||
|
// container made, pinned, and its secrets read from that container's environment.
|
||||||
|
func theStepNineSecretsOf(t *testing.T, manifest []byte) (map[string]string, error) {
|
||||||
|
t.Helper()
|
||||||
|
form, err := processFormOf(manifest)
|
||||||
|
if err != nil || !form.Found {
|
||||||
|
t.Fatalf("the manifest has no process form: %v", err)
|
||||||
|
}
|
||||||
|
genesis, err := genesisForm(manifest, form, builtImage)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
pinned, _, err := pinImage(genesis, builtImage, "registry.internal:5000/mesh-controller@sha256:"+strings.Repeat("e", 64), ControlPlaneModule)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
return secretsByVariableIn(pinned)
|
||||||
|
}
|
||||||
|
|
||||||
|
// **A file the controller's manifest writes itself is not a secret** (novox/hq issue 597). The merge
|
||||||
|
// window's settings reach the controller in a file its manifest declares from its settings
|
||||||
|
// (MESH_MERGE_WINDOW_FILE, ADR 0276); genesis refused it as a secret nobody writes, and stopped at
|
||||||
|
// step 11 of 24.
|
||||||
|
func TestAFileTheControllersManifestWritesIsNotASecret(t *testing.T) {
|
||||||
|
manifest := strings.Replace(processFormManifest,
|
||||||
|
`{"id": "controller", "type": "process",`,
|
||||||
|
`{"id": "merge-window", "type": "file", "path": "${dir:mesh-state}/merge-window.json", "mode": "0600",
|
||||||
|
"owner": "mesh-controller", "content": "{\"merge-window\": \"${setting:merge-window}\"}\n"},
|
||||||
|
{"id": "controller", "type": "process",`, 1)
|
||||||
|
manifest = strings.Replace(manifest, `"MESH_BUS_NATS_FILE": "${dir:mesh-state}/bus"}`,
|
||||||
|
`"MESH_BUS_NATS_FILE": "${dir:mesh-state}/bus",
|
||||||
|
"MESH_MERGE_WINDOW_FILE": "${dir:mesh-state}/merge-window.json"}`, 1)
|
||||||
|
if !strings.Contains(manifest, "MESH_MERGE_WINDOW_FILE") || !strings.Contains(manifest, `"id": "merge-window"`) {
|
||||||
|
t.Fatal("the fixture was not changed")
|
||||||
|
}
|
||||||
|
wanted, err := theStepNineSecretsOf(t, []byte(manifest))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("step 9 refuses a file the manifest writes itself: %v", err)
|
||||||
|
}
|
||||||
|
if _, asked := wanted["MESH_MERGE_WINDOW"]; asked {
|
||||||
|
t.Errorf("the merge window's settings are delivered as a secret: %v", wanted)
|
||||||
|
}
|
||||||
|
if wanted["MESH_STORE_INVENTORY"] != "inventory" || wanted["MESH_BUS_NATS"] != "bus" {
|
||||||
|
t.Errorf("step 9 delivers %v; the store's and the bus's secrets are still wanted", wanted)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// And a `…_FILE` that neither an own-secret nor a file of the module writes is still refused.
|
||||||
|
func TestAFileNothingOfTheControllerWritesIsStillRefused(t *testing.T) {
|
||||||
|
manifest := strings.Replace(processFormManifest, `"MESH_BUS_NATS_FILE": "${dir:mesh-state}/bus"}`,
|
||||||
|
`"MESH_BUS_NATS_FILE": "${dir:mesh-state}/bus",
|
||||||
|
"MESH_MERGE_WINDOW_FILE": "${dir:mesh-state}/merge-window.json"}`, 1)
|
||||||
|
if _, err := theStepNineSecretsOf(t, []byte(manifest)); err == nil || !strings.Contains(err.Error(), "MESH_MERGE_WINDOW_FILE") {
|
||||||
|
t.Fatalf("a file nothing writes was accepted, or refused without its name: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The controller's own manifest, as the mesh runs it, passes step 9 (issue 597): in a merge check the
|
||||||
|
// node-engine's check has the controller cloned beside it (MESH_CHECK_BESIDE), where it must be; else a
|
||||||
|
// checkout beside this one; else it skips aloud.
|
||||||
|
func TestTheControllersOwnManifestPassesStepNine(t *testing.T) {
|
||||||
|
var manifest []byte
|
||||||
|
if root := os.Getenv("MESH_CHECK_BESIDE"); root != "" {
|
||||||
|
raw, err := os.ReadFile(filepath.Join(root, "mesh-controller", "module.json"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("the controller is not beside this check in MESH_CHECK_BESIDE=%s: %v", root, err)
|
||||||
|
}
|
||||||
|
manifest = raw
|
||||||
|
} else if raw, err := os.ReadFile(filepath.Join("..", "..", "..", "mesh-controller", "module.json")); err == nil {
|
||||||
|
manifest = raw
|
||||||
|
} else {
|
||||||
|
t.Skip("NOT JUDGED: no controller beside this checkout and no MESH_CHECK_BESIDE; the merge check judges it")
|
||||||
|
}
|
||||||
|
wanted, err := theStepNineSecretsOf(t, manifest)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("genesis's step 9 refuses the controller the mesh runs: %v", err)
|
||||||
|
}
|
||||||
|
if wanted["MESH_STORE_INVENTORY"] != "inventory" {
|
||||||
|
t.Errorf("step 9 delivers %v", wanted)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user