Resolve recommended-profile Critical and High findings, retain narrow analyzer exceptions, and update the edge-broker WebSocket dependency to a non-vulnerable release.
94 lines
6.1 KiB
JavaScript
94 lines
6.1 KiB
JavaScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { existsSync, readFileSync } from "node:fs";
|
|
import path from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const testDirectory = path.dirname(fileURLToPath(import.meta.url));
|
|
const repoRoot = path.resolve(testDirectory, "../../..");
|
|
|
|
function readRequiredSource(...pathSegments) {
|
|
const sourcePath = path.resolve(repoRoot, ...pathSegments);
|
|
assert.equal(existsSync(sourcePath), true, `Expected config fixture to exist: ${sourcePath}`);
|
|
return readFileSync(sourcePath, "utf8");
|
|
}
|
|
|
|
const baseComposeSource = readRequiredSource("docker-compose.yml");
|
|
const exampleComposeSource = readRequiredSource("docker-compose.example.yml");
|
|
const standaloneProdComposeSource = readRequiredSource("docker-compose.prod.standalone.yml");
|
|
const traefikSource = [
|
|
readRequiredSource("services", "traefik", "traefik.yml"),
|
|
readRequiredSource("services", "traefik", "traefik.prod.yml"),
|
|
].join("\n");
|
|
|
|
function readComposeServiceBlock(composeSource, serviceName) {
|
|
const escapedServiceName = serviceName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
const servicePattern = new RegExp(
|
|
`^[ ]{2}${escapedServiceName}:\\r?\\n([\\s\\S]*?)(?=^[ ]{2}[A-Za-z0-9_-]+:|^volumes:|^networks:|(?![\\s\\S]))`,
|
|
"m"
|
|
);
|
|
const match = composeSource.match(servicePattern);
|
|
assert.ok(match, `Expected docker compose service block for ${serviceName}`);
|
|
return match[0];
|
|
}
|
|
|
|
test("traefik does not expose a dedicated public edge broker port", () => {
|
|
assert.doesNotMatch(traefikSource, /edge-broker:\s*\n\s*address:\s*":4300"/);
|
|
});
|
|
|
|
test("base docker compose routes edge broker traffic through traefik", () => {
|
|
const serviceBlock = readComposeServiceBlock(baseComposeSource, "edge-broker");
|
|
assert.doesNotMatch(serviceBlock, /\n\s+ports:\s*\n[\s\S]*?\n\s+- "4300:4300"/);
|
|
assert.match(serviceBlock, /EDGE_AUTH_MODE:\s*\$\x7bEDGE_AUTH_MODE:-strict\x7d/);
|
|
assert.match(serviceBlock, /EDGE_MANAGER_URL:\s*\$\x7bEDGE_MANAGER_URL:-http:\/\/caddy\x7d/);
|
|
assert.match(serviceBlock, /traefik\.http\.routers\.edge-broker-api\.priority=200/);
|
|
assert.match(serviceBlock, /traefik\.http\.routers\.edge-broker-local\.priority=200/);
|
|
assert.match(serviceBlock, /traefik\.http\.routers\.edge-broker-api\.rule=Host\(`api\.truckwash\.dk`\) && PathPrefix\(`\/edge-broker`\)/);
|
|
assert.match(serviceBlock, /traefik\.http\.routers\.edge-broker-api-io\.rule=Host\(`api\.truckwash\.io`\) && PathPrefix\(`\/edge-broker`\)/);
|
|
assert.match(serviceBlock, /traefik\.http\.routers\.edge-broker-api-v2\.rule=Host\(`api-v2\.truckwash\.io`\) && PathPrefix\(`\/edge-broker`\)/);
|
|
assert.match(serviceBlock, /traefik\.http\.routers\.edge-broker-local\.rule=Host\(`localhost`\) && PathPrefix\(`\/api\/edge-broker`\)/);
|
|
assert.match(serviceBlock, /traefik\.http\.middlewares\.edge-broker-strip\.stripPrefix\.prefixes=\/edge-broker/);
|
|
assert.match(serviceBlock, /traefik\.http\.middlewares\.edge-broker-strip-local\.stripPrefix\.prefixes=\/api\/edge-broker/);
|
|
assert.match(serviceBlock, /traefik\.http\.services\.edge-broker\.loadbalancer\.server\.port=4300/);
|
|
});
|
|
|
|
test("example docker compose routes edge broker traffic through traefik", () => {
|
|
const serviceBlock = readComposeServiceBlock(exampleComposeSource, "edge-broker");
|
|
assert.doesNotMatch(serviceBlock, /\n\s+ports:\s*\n[\s\S]*?\n\s+- "4300:4300"/);
|
|
assert.match(serviceBlock, /EDGE_AUTH_MODE:\s*\$\x7bEDGE_AUTH_MODE:-strict\x7d/);
|
|
assert.match(serviceBlock, /EDGE_MANAGER_URL:\s*\$\x7bEDGE_MANAGER_URL:-http:\/\/caddy\x7d/);
|
|
assert.match(serviceBlock, /traefik\.http\.routers\.edge-broker-api\.rule=Host\(`api\.example\.com`\) && PathPrefix\(`\/edge-broker`\)/);
|
|
assert.match(serviceBlock, /traefik\.http\.routers\.edge-broker-local\.rule=Host\(`localhost`\) && PathPrefix\(`\/api\/edge-broker`\)/);
|
|
assert.match(serviceBlock, /traefik\.http\.services\.edge-broker\.loadbalancer\.server\.port=4300/);
|
|
});
|
|
|
|
test("standalone production compose routes edge broker traffic through traefik", () => {
|
|
const serviceBlock = readComposeServiceBlock(standaloneProdComposeSource, "edge-broker");
|
|
assert.doesNotMatch(serviceBlock, /\n\s+ports:\s*\n[\s\S]*?\n\s+- "4300:4300"/);
|
|
assert.match(serviceBlock, /EDGE_AUTH_MODE:\s*\$\x7bEDGE_AUTH_MODE:-manager\x7d/);
|
|
assert.match(serviceBlock, /EDGE_MANAGER_URL:\s*\$\x7bEDGE_MANAGER_URL:-http:\/\/caddy\x7d/);
|
|
assert.match(serviceBlock, /traefik\.http\.routers\.edge-broker-api\.priority=200/);
|
|
assert.match(serviceBlock, /traefik\.http\.routers\.edge-broker-local\.priority=200/);
|
|
assert.match(serviceBlock, /traefik\.http\.routers\.edge-broker-api\.rule=Host\(`api\.truckwash\.dk`\) && PathPrefix\(`\/edge-broker`\)/);
|
|
assert.match(serviceBlock, /traefik\.http\.routers\.edge-broker-api-io\.rule=Host\(`api\.truckwash\.io`\) && PathPrefix\(`\/edge-broker`\)/);
|
|
assert.match(serviceBlock, /traefik\.http\.routers\.edge-broker-api-v2\.rule=Host\(`api-v2\.truckwash\.io`\) && PathPrefix\(`\/edge-broker`\)/);
|
|
assert.match(serviceBlock, /traefik\.http\.routers\.edge-broker-local\.rule=Host\(`localhost`\) && PathPrefix\(`\/api\/edge-broker`\)/);
|
|
assert.match(serviceBlock, /traefik\.http\.services\.edge-broker\.loadbalancer\.server\.port=4300/);
|
|
});
|
|
|
|
test("compose config does not provide insecure broker secret defaults", () => {
|
|
for (const composeSource of [baseComposeSource, exampleComposeSource]) {
|
|
assert.match(composeSource, /EDGE_BROKER_URL:\s*\$\x7bEDGE_BROKER_URL:-http:\/\/edge-broker:4300\x7d/);
|
|
assert.match(composeSource, /EDGE_BROKER_SHARED_SECRET:\s*\$\x7bEDGE_BROKER_SHARED_SECRET:\?set EDGE_BROKER_SHARED_SECRET in \.env\x7d/);
|
|
}
|
|
});
|
|
|
|
test("base docker compose wires the broker into each php worker", () => {
|
|
for (const serviceName of ["php1", "php2", "php3", "php4", "php5", "php-staging", "php-cron"]) {
|
|
const serviceBlock = readComposeServiceBlock(baseComposeSource, serviceName);
|
|
assert.match(serviceBlock, /\n\s+depends_on:\s*\n[\s\S]*?\n\s+- edge-broker/);
|
|
assert.match(serviceBlock, /EDGE_BROKER_URL:\s*\$\x7bEDGE_BROKER_URL:-http:\/\/edge-broker:4300\x7d/);
|
|
assert.match(serviceBlock, /EDGE_BROKER_SHARED_SECRET:\s*\$\x7bEDGE_BROKER_SHARED_SECRET:\?set EDGE_BROKER_SHARED_SECRET in \.env\x7d/);
|
|
}
|
|
});
|