The packet filter is a module too, and it was assigned to nothing
V3 asked whether the machine's networking is what the modules asked for and found no mesh firewall table at all. The firewall is a module — it claims the packet-filter seat, installs the filter and loads the rules — and like networking before it, it had never been assigned to anything. So every rule the mesh generates from module listen declarations had never been applied to any machine in this test. Not open by accident: a mesh where that whole generation has never run. Assigned separately from networking because they answer different questions. One is how machines reach each other; the other is what may reach this one. Claude-Session: https://claude.ai/code/session_01D6qtiYU3P9jk3pnAXyAFyx
This commit is contained in:
+25
-25
@@ -1,13 +1,13 @@
|
|||||||
{
|
{
|
||||||
"scenario": "one-node-mesh",
|
"scenario": "one-node-mesh",
|
||||||
"established": 11,
|
"established": 16,
|
||||||
"of": 20,
|
"of": 20,
|
||||||
"steps": [
|
"steps": [
|
||||||
{
|
{
|
||||||
"code": "R1",
|
"code": "R1",
|
||||||
"title": "a bare machine becomes a mesh of one, raised by the installer",
|
"title": "a bare machine becomes a mesh of one, raised by the installer",
|
||||||
"status": "pass",
|
"status": "pass",
|
||||||
"seconds": 132,
|
"seconds": 140,
|
||||||
"why": ""
|
"why": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -56,14 +56,14 @@
|
|||||||
"code": "P1",
|
"code": "P1",
|
||||||
"title": "the mesh builds the shared base from source",
|
"title": "the mesh builds the shared base from source",
|
||||||
"status": "pass",
|
"status": "pass",
|
||||||
"seconds": 78,
|
"seconds": 74,
|
||||||
"why": ""
|
"why": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"code": "P2",
|
"code": "P2",
|
||||||
"title": "the mesh builds and runs a store of its own",
|
"title": "the mesh builds and runs a store of its own",
|
||||||
"status": "pass",
|
"status": "pass",
|
||||||
"seconds": 50,
|
"seconds": 53,
|
||||||
"why": ""
|
"why": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -77,57 +77,57 @@
|
|||||||
"code": "P4",
|
"code": "P4",
|
||||||
"title": "the mesh rebuilds its own control plane from source",
|
"title": "the mesh rebuilds its own control plane from source",
|
||||||
"status": "pass",
|
"status": "pass",
|
||||||
"seconds": 37,
|
"seconds": 35,
|
||||||
"why": ""
|
"why": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"code": "N1",
|
"code": "N1",
|
||||||
"title": "the mesh puts itself on a private network, and its machine has a name",
|
"title": "the mesh puts itself on a private network, and its machine has a name",
|
||||||
"status": "fail",
|
"status": "pass",
|
||||||
"seconds": 125,
|
"seconds": 6,
|
||||||
"why": "networking is assigned and no machine has a name:\n# Generated by the mesh. Do not edit — this file is replaced whenever a node\n# joins or leaves, and an edit would survive until then and vanish.\n\n127.0.0.1\tlocalhost\n::1\t\tlocalhost ip6-localhost ip6-loopback\n127.0.1.1\tanchor\n"
|
"why": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"code": "U1",
|
"code": "U1",
|
||||||
"title": "the mesh builds a module standing on that base",
|
"title": "the mesh builds a module standing on that base",
|
||||||
"status": "skip",
|
"status": "pass",
|
||||||
"seconds": 0,
|
"seconds": 14,
|
||||||
"why": "not attempted — N1 (the mesh puts itself on a private network, and its machine has a name) did not succeed"
|
"why": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"code": "U2",
|
"code": "U2",
|
||||||
"title": "the mesh runs a broker for that module to talk to",
|
"title": "the mesh runs a broker for that module to talk to",
|
||||||
"status": "skip",
|
"status": "pass",
|
||||||
"seconds": 0,
|
"seconds": 20,
|
||||||
"why": "not attempted — U1 (the mesh builds a module standing on that base) did not succeed"
|
"why": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"code": "U3",
|
"code": "U3",
|
||||||
"title": "the anchor runs the module the mesh built",
|
"title": "the anchor runs the module the mesh built",
|
||||||
"status": "skip",
|
"status": "pass",
|
||||||
"seconds": 0,
|
"seconds": 6,
|
||||||
"why": "not attempted — U2 (the mesh runs a broker for that module to talk to) did not succeed"
|
"why": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"code": "V1",
|
"code": "V1",
|
||||||
"title": "the control plane can describe the mesh, and what it says is true",
|
"title": "the control plane can describe the mesh, and what it says is true",
|
||||||
"status": "skip",
|
"status": "pass",
|
||||||
"seconds": 0,
|
"seconds": 1,
|
||||||
"why": "not attempted — U3 (the anchor runs the module the mesh built) did not succeed"
|
"why": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"code": "V2",
|
"code": "V2",
|
||||||
"title": "the catalogue holds every module this mesh built",
|
"title": "the catalogue holds every module this mesh built",
|
||||||
"status": "skip",
|
"status": "fail",
|
||||||
"seconds": 0,
|
"seconds": 1,
|
||||||
"why": "not attempted — V1 (the control plane can describe the mesh, and what it says is true) did not succeed"
|
"why": "the catalogue does not hold mesh-tools, postgres — the mesh built them and its own record has no trace of it (novox/hq issue 050):\n{\"modules\":[{\"module\":\"amqp-ping\",\"commit\":\"e0c92195d4240841bfcf4b4a9ef869d5afeca331\",\"repository\":\"https://git.novox.be/novox/mesh-catalog.git\",\"path\":\"modules/amqp-ping\"},{\"module\":\"lavinmq\",\"commit\":\"e0c92195d4240841bfcf4b4a9ef869d5afeca331\",\"repository\":\"https://git.novox.be/novox/mesh-catalog.git\",\"path\":\"modules/lavinmq\"},{\"module\":\"mesh-control\",\"commit\":\"5062c36fc9efe159aa9706c0ca2c873351ef1ce0\",\"repository\":\"https://git.novox.be/novox/mesh-control.git\",\"path\":\"\"}]}\n\n+ actual - expected\n\n+ [\n+ 'mesh-tools',\n+ 'postgres'\n+ ]\n- []\n"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"code": "V3",
|
"code": "V3",
|
||||||
"title": "the machine's networking is what the modules asked for",
|
"title": "the machine's networking is what the modules asked for",
|
||||||
"status": "skip",
|
"status": "fail",
|
||||||
"seconds": 0,
|
"seconds": 0,
|
||||||
"why": "not attempted — V1 (the control plane can describe the mesh, and what it says is true) did not succeed"
|
"why": "the mesh's own firewall table is not there:\nError: No such file or directory\nlist table inet mesh\n ^^^^\n"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"code": "E1",
|
"code": "E1",
|
||||||
|
|||||||
@@ -85,6 +85,15 @@ const PROVIDER = { module: "lavinmq", repo: "mesh-catalog", path: "modules/lavin
|
|||||||
*/
|
*/
|
||||||
/** The one word that puts a mesh on a private network and gives its machines names. */
|
/** The one word that puts a mesh on a private network and gives its machines names. */
|
||||||
const NETWORK_MODULE = "networking";
|
const NETWORK_MODULE = "networking";
|
||||||
|
/**
|
||||||
|
* The packet filter, which is a module too and was assigned to nothing.
|
||||||
|
*
|
||||||
|
* The rules are generated from what every module declares it listens on, so a mesh with no filter
|
||||||
|
* is not "open by accident" — it is a mesh where the whole of that generation has never run. It
|
||||||
|
* claims a seat (`the-packet-filter`) because a machine has one of these and two things writing
|
||||||
|
* rules is a coin toss about which survives.
|
||||||
|
*/
|
||||||
|
const FILTER_MODULE = "firewall";
|
||||||
const STORE = { module: "postgres", repo: "mesh-catalog", path: "modules/postgres", container: "mesh-postgres" };
|
const STORE = { module: "postgres", repo: "mesh-catalog", path: "modules/postgres", container: "mesh-postgres" };
|
||||||
const CATALOGUE = { module: "mesh-catalog", repo: "mesh-catalog", path: "modules/mesh-catalog", container: "mesh-catalog" };
|
const CATALOGUE = { module: "mesh-catalog", repo: "mesh-catalog", path: "modules/mesh-catalog", container: "mesh-catalog" };
|
||||||
/** The control plane, rebuilt from its own repository — the step that ends the installer's tenure. */
|
/** The control plane, rebuilt from its own repository — the step that ends the installer's tenure. */
|
||||||
@@ -116,6 +125,7 @@ const STORE_RUNS = "the mesh builds and runs a store of its own";
|
|||||||
const CATALOGUE_RUNS = "the mesh builds and runs its own catalogue";
|
const CATALOGUE_RUNS = "the mesh builds and runs its own catalogue";
|
||||||
const CONTROL_REBUILT = "the mesh rebuilds its own control plane from source";
|
const CONTROL_REBUILT = "the mesh rebuilds its own control plane from source";
|
||||||
const NETWORKED = "the mesh puts itself on a private network, and its machine has a name";
|
const NETWORKED = "the mesh puts itself on a private network, and its machine has a name";
|
||||||
|
const FILTERED = "the machine has a packet filter, loaded from what modules declared";
|
||||||
const MODULE_BUILT = "the mesh builds a module standing on that base";
|
const MODULE_BUILT = "the mesh builds a module standing on that base";
|
||||||
const ANCHOR_RUNS = "the anchor runs the module the mesh built";
|
const ANCHOR_RUNS = "the anchor runs the module the mesh built";
|
||||||
const DESCRIBES = "the control plane can describe the mesh, and what it says is true";
|
const DESCRIBES = "the control plane can describe the mesh, and what it says is true";
|
||||||
@@ -376,6 +386,7 @@ const PLAN: { code: string; title: string }[] = [
|
|||||||
{ code: "P3", title: CATALOGUE_RUNS },
|
{ code: "P3", title: CATALOGUE_RUNS },
|
||||||
{ code: "P4", title: CONTROL_REBUILT },
|
{ code: "P4", title: CONTROL_REBUILT },
|
||||||
{ code: "N1", title: NETWORKED },
|
{ code: "N1", title: NETWORKED },
|
||||||
|
{ code: "N2", title: FILTERED },
|
||||||
{ code: "U1", title: MODULE_BUILT },
|
{ code: "U1", title: MODULE_BUILT },
|
||||||
{ code: "U2", title: NEEDS },
|
{ code: "U2", title: NEEDS },
|
||||||
{ code: "U3", title: ANCHOR_RUNS },
|
{ code: "U3", title: ANCHOR_RUNS },
|
||||||
@@ -623,8 +634,29 @@ before(async () => {
|
|||||||
return `${hosts.trim()}\n\n${modules.trim()}`;
|
return `${hosts.trim()}\n\n${modules.trim()}`;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ---- THE PACKET FILTER -------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Assigned separately from `networking` because they answer different questions: one is how
|
||||||
|
// machines reach each other, the other is what may reach this one. Both were assigned to nothing,
|
||||||
|
// and the second is the more alarming of the two — every rule the mesh generates from module
|
||||||
|
// declarations had never been applied to any machine in this test.
|
||||||
|
await step("N2", FILTERED, NETWORKED, async () => {
|
||||||
|
await mesh(`assign ${CONTROL} ${FILTER_MODULE}`);
|
||||||
|
await mesh(`push ${CONTROL}`, 600_000);
|
||||||
|
const deadline = Date.now() + 180_000;
|
||||||
|
let ruleset = "";
|
||||||
|
while (Date.now() < deadline) {
|
||||||
|
ruleset = (await on(CONTROL, `nft list table inet mesh 2>&1`)).out;
|
||||||
|
if (/chain input/.test(ruleset)) break;
|
||||||
|
await new Promise((r) => setTimeout(r, 5_000));
|
||||||
|
}
|
||||||
|
assert.match(ruleset, /chain input/,
|
||||||
|
`${FILTER_MODULE} is assigned and the machine has no mesh filter:\n${ruleset}`);
|
||||||
|
return ruleset;
|
||||||
|
});
|
||||||
|
|
||||||
// ---- 7..8. SOMETHING TO RUN ---------------------------------------------------------------
|
// ---- 7..8. SOMETHING TO RUN ---------------------------------------------------------------
|
||||||
await step("U1", MODULE_BUILT, NETWORKED, async () => {
|
await step("U1", MODULE_BUILT, FILTERED, async () => {
|
||||||
await registerModule(MODULE.module, resolve(catalogDir, MODULE.module, "module.json"));
|
await registerModule(MODULE.module, resolve(catalogDir, MODULE.module, "module.json"));
|
||||||
const built = await mesh(
|
const built = await mesh(
|
||||||
`build ${forgeUrl(MODULE.repo)} --path ${MODULE.path} --ref ${refFor(MODULE.repo)} --wait 1200s`,
|
`build ${forgeUrl(MODULE.repo)} --path ${MODULE.path} --ref ${refFor(MODULE.repo)} --wait 1200s`,
|
||||||
@@ -863,6 +895,7 @@ for (const name of [
|
|||||||
CATALOGUE_RUNS,
|
CATALOGUE_RUNS,
|
||||||
CONTROL_REBUILT,
|
CONTROL_REBUILT,
|
||||||
NETWORKED,
|
NETWORKED,
|
||||||
|
FILTERED,
|
||||||
MODULE_BUILT,
|
MODULE_BUILT,
|
||||||
NEEDS,
|
NEEDS,
|
||||||
ANCHOR_RUNS,
|
ANCHOR_RUNS,
|
||||||
|
|||||||
Reference in New Issue
Block a user