feat(device-edge): add isolated B2 ingress domain

This commit is contained in:
Codex
2026-08-04 11:39:01 +03:00
parent b1a5a26b9a
commit 3bb5e6dc27
35 changed files with 5790 additions and 19 deletions
@@ -0,0 +1,84 @@
import assert from "node:assert/strict";
import { readFile } from "node:fs/promises";
import { dirname, resolve } from "node:path";
import test from "node:test";
import { fileURLToPath } from "node:url";
const devicePlaneRoot = resolve(
dirname(fileURLToPath(import.meta.url)),
"../../..",
);
test("single-NIC ingress source has no host publication and a fixed ipvlan", async () => {
const baseline = await readFile(
resolve(devicePlaneRoot, "docker-compose.device-edge.yml"),
"utf8",
);
const ingress = await readFile(
resolve(devicePlaneRoot, "docker-compose.device-edge.ingress.yml"),
"utf8",
);
assert.match(
baseline,
/DEVICE_EDGE_RELAY_HEALTH_HOST: 127\.0\.0\.1/,
);
assert.doesNotMatch(baseline, /^\s+ports:/m);
assert.doesNotMatch(baseline, /device-edge-control/);
for (const required of [
'DEVICE_EDGE_RELAY_INGRESS_ENABLED: "true"',
"DEVICE_EDGE_RELAY_UPSTREAM_HOST: device-edge-backhaul",
'DEVICE_EDGE_RELAY_UPSTREAM_PORT: "19921"',
"name: nodedc-device-edge-ingress",
"driver: ipvlan",
"parent: enp1s0f0",
"ipvlan_mode: l2",
"ipv4_address: 192.168.71.253",
"subnet: 192.168.68.0/22",
"gateway: 192.168.68.1",
"gw_priority: 100",
]) {
assert.ok(ingress.includes(required), `missing ingress boundary: ${required}`);
}
for (const forbidden of [
"ports:",
"network_mode: host",
"privileged: true",
"DEVICE_EDGE_RELAY_COMMAND",
"0.0.0.0:9921:9921",
]) {
assert.ok(
!ingress.includes(forbidden),
`forbidden ingress boundary: ${forbidden}`,
);
}
});
test("ingress descriptor keeps address approval and router exposure gated", async () => {
const descriptor = JSON.parse(await readFile(
resolve(
devicePlaneRoot,
"deployment/device-edge-ingress-ipvlan-v1.json",
),
"utf8",
));
assert.equal(descriptor.component, "device-edge");
assert.deepEqual(descriptor.selectedServices, ["device-edge-relay"]);
assert.deepEqual(
descriptor.preservedServices,
["device-edge-backhaul", "tailnet"],
);
assert.equal(descriptor.ingressIpv4Approval, "approved-outside-dhcp-pool");
assert.equal(descriptor.hostPortPublication, "disabled");
assert.equal(descriptor.healthPublication, "disabled");
assert.equal(descriptor.privateUpstream, "device-edge-backhaul:19921");
assert.equal(descriptor.protocolInspection, "gateway-owned");
assert.equal(descriptor.discoveryLifecycle, "quarantine");
assert.equal(descriptor.commandTransport, "disabled");
assert.equal(descriptor.gelios, "untouched");
assert.equal(descriptor.amneziaHostFullTunnel, "preserved");
assert.equal(descriptor.routerNatFirewall, "separate-manual-gate");
});
@@ -0,0 +1,95 @@
import assert from "node:assert/strict";
import { createServer, connect } from "node:net";
import test from "node:test";
import { createDeviceEdgeRelayRuntime } from "../src/runtime.mjs";
test("baseline starts only loopback health and no device TCP listener", async () => {
const runtime = createDeviceEdgeRelayRuntime({ healthPort: 0 });
const addresses = await runtime.start();
try {
assert.equal(addresses.tcpAddress, null);
const response = await fetch(
`http://127.0.0.1:${addresses.healthAddress.port}/healthz`,
);
assert.equal(response.status, 200);
const body = await response.json();
assert.equal(body.ingress, "disabled");
assert.equal(body.protocolInspection, "disabled");
assert.equal(body.commandTransport, "disabled");
} finally {
await runtime.stop();
}
});
test("relay is transparent and never emits its own protocol bytes", async () => {
const upstream = await startEchoServer();
const runtime = createDeviceEdgeRelayRuntime({
healthPort: 0,
ingressEnabled: true,
tcpHost: "0.0.0.0",
tcpPort: 0,
upstreamHost: "127.0.0.1",
upstreamPort: upstream.port,
});
const addresses = await runtime.start();
try {
const response = await sendAndCollect(
addresses.tcpAddress.port,
Buffer.from("ff230102030405060708", "hex"),
);
assert.equal(response.toString("hex"), "ff230102030405060708");
assert.equal(runtime.status().totalForwarded, 1);
assert.equal(runtime.status().commandTransport, "disabled");
} finally {
await runtime.stop();
await closeServer(upstream.server);
}
});
test("enabled relay requires a concrete private upstream", () => {
assert.throws(
() => createDeviceEdgeRelayRuntime({
ingressEnabled: true,
tcpHost: "0.0.0.0",
upstreamPort: 19921,
}),
/device_edge_relay_upstream_host_invalid/,
);
});
test("baseline rejects a non-loopback device binding", () => {
assert.throws(
() => createDeviceEdgeRelayRuntime({ tcpHost: "0.0.0.0" }),
/device_edge_relay_baseline_loopback_only/,
);
});
function startEchoServer() {
const server = createServer((socket) => socket.pipe(socket));
return new Promise((resolve, reject) => {
server.once("error", reject);
server.listen(0, "127.0.0.1", () => {
server.off("error", reject);
resolve({ server, port: server.address().port });
});
});
}
function sendAndCollect(port, payload) {
return new Promise((resolve, reject) => {
const chunks = [];
const socket = connect({ host: "127.0.0.1", port }, () => {
socket.end(payload);
});
socket.on("data", (chunk) => chunks.push(chunk));
socket.on("close", () => resolve(Buffer.concat(chunks)));
socket.on("error", reject);
});
}
function closeServer(server) {
return new Promise((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
}