package catalogue import ( "strings" "testing" ) // The packet-filter manifest as it was the day the runtime was decided (novox/hq ADR 0175): tools, // served from a container built on the tool runtime's image, with NET_ADMIN so the container could // reach the filter. The exact pattern to-be 38 WP4 moves it off, and the one the gate refuses. const thePacketFilterAsItWas = `{ "module": "nftables", "version": "1", "capabilities": ["firewall", "container-runtime"], "claims": [{"name": "node-packet-filter", "scope": "node", "serves": ["rules", "reload", "remove"]}], "filtering": {"into": "/etc/nftables.conf"}, "resources": [ {"id": "mesh-state", "type": "directory", "mode": "0700", "place": "mesh"}, {"id": "package", "type": "package", "package": "nftables"}, {"id": "unit", "type": "file", "path": "/etc/systemd/system/mesh-filter.service", "content": "[Unit]\nDescription=The mesh's packet filter\n[Service]\nType=oneshot\nExecStart=nft -f /etc/nftables.conf\n", "mode": "0644"}, {"id": "load", "type": "service", "unit": "mesh-filter.service", "state": "running", "boot": "enabled", "restart-on": ["unit"], "reload-on": ["filtering"]}, {"id": "runtime", "type": "container", "name": "mesh-nftables", "network": "host", "capabilities": ["NET_ADMIN"], "volumes": ["${dir:mesh-state}/broker:/run/secrets/broker:ro", "/etc/nftables.conf:/etc/nftables.conf:ro"], "env": {"MESH_BROKER_FILE": "/run/secrets/broker", "MESH_FILTER_FILE": "/etc/nftables.conf"}, "artifact": "runtime"} ], "tools": ["firewall_rules"], "own-secrets": {"broker": "${dir:mesh-state}/broker"}, "build": { "on": [ {"arg": "BUILD_BASE", "module": "mesh-tools", "artifact": "build"}, {"arg": "RUNTIME_BASE", "module": "mesh-tools", "artifact": "runtime"} ], "artifacts": [{"name": "runtime", "kind": "image", "from": "Dockerfile"}] } }` func TestAToolContainerOnTheRuntimeImageIsNamedForWhatItIs(t *testing.T) { m, err := ParseManifest([]byte(thePacketFilterAsItWas)) if err != nil { t.Fatal(err) } // From the repository: the manifest says what it builds on. why := ToolContainerOnTheRuntime(m, nil) if why == "" { t.Fatal("the packet filter's tool container was not recognised from its build") } for _, word := range []string{"nftables", "mesh-tools", "runtime", "ADR 0175", "bundle"} { if !strings.Contains(why, word) { t.Errorf("the refusal does not say %q: %s", word, why) } } // Built: the manifest carries no build, and what it stood on says the same. built, err := m.Resolve([]Built{{Name: "runtime", Kind: ArtifactImage, Reference: ArtifactStoreScheme + "nftables/runtime@" + digest}}) if err != nil { t.Fatal(err) } stoodOn := []string{"anchor.internal:5100/mesh-tools/build@" + digest, "anchor.internal:5100/mesh-tools/runtime@" + digest} if ToolContainerOnTheRuntime(built, stoodOn) == "" { t.Error("the packet filter's tool container was not recognised from what its build stood on") } if ToolContainerOnTheRuntime(built, nil) != "" { t.Error("a built manifest with no record of its base was judged to be on the runtime") } // Each of the three alone is an ordinary module. bundle := m bundle.Resources = m.Resources[:len(m.Resources)-1] if ToolContainerOnTheRuntime(bundle, nil) != "" { t.Error("a module with tools and no container is the pattern the runtime serves, and was refused") } service := m service.Tools = nil if ToolContainerOnTheRuntime(service, nil) != "" { t.Error("a service built against the SDK, declaring no tools, was refused") } elsewhere := m elsewhere.Build = &Build{On: []BuildsOn{{Arg: "NODE_BASE", Image: "node@" + digest}}, Artifacts: m.Build.Artifacts} if ToolContainerOnTheRuntime(elsewhere, nil) != "" { t.Error("a tool container on a public base was refused as though it were on the runtime's") } }