From 16c9cd99315a2747496b2a82a263fc52f8ee0a5f Mon Sep 17 00:00:00 2001 From: Jeppe Bundgaard Date: Thu, 9 Apr 2026 16:31:58 +0200 Subject: [PATCH] Extend `agent-cli` with `sync` command, enhance schema validation for complaints, and add coverage for gateway command tests. --- docker-compose.prod.yml | 1 - services/edge-broker/test/config.test.mjs | 21 ++++++++++++------- .../EdgeGatewayManagerHeartbeatStatusTest.php | 7 +++++++ services/traefik/traefik.prod.yml | 2 -- services/traefik/traefik.yml | 2 -- 5 files changed, 21 insertions(+), 12 deletions(-) diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index d62b3af9..64c39a78 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -9,7 +9,6 @@ services: ports: - "80:80" - "443:443" - - "4300:4300" redis: ports: [] healthcheck: diff --git a/services/edge-broker/test/config.test.mjs b/services/edge-broker/test/config.test.mjs index e778309b..dbf90108 100644 --- a/services/edge-broker/test/config.test.mjs +++ b/services/edge-broker/test/config.test.mjs @@ -3,18 +3,25 @@ import assert from "node:assert/strict"; import { readFileSync } from "node:fs"; const composeSource = readFileSync(new URL("../../../docker-compose.yml", import.meta.url), "utf8"); +const composeProdSource = readFileSync(new URL("../../../docker-compose.prod.yml", import.meta.url), "utf8"); const traefikSource = readFileSync(new URL("../../../services/traefik/traefik.yml", import.meta.url), "utf8"); const traefikProdSource = readFileSync(new URL("../../../services/traefik/traefik.prod.yml", import.meta.url), "utf8"); -test("traefik exposes a dedicated edge broker entrypoint on port 4300", () => { - assert.match(traefikSource, /edge-broker:\s*\n\s*address:\s*":4300"/); - assert.match(traefikProdSource, /edge-broker:\s*\n\s*address:\s*":4300"/); - assert.match(composeSource, /traefik:[\s\S]*ports:[\s\S]*"4300:4300"/); +test("traefik does not expose a dedicated public edge broker port", () => { + assert.doesNotMatch(traefikSource, /edge-broker:\s*\n\s*address:\s*":4300"/); + assert.doesNotMatch(traefikProdSource, /edge-broker:\s*\n\s*address:\s*":4300"/); + assert.doesNotMatch(composeSource, /traefik:[\s\S]*ports:[\s\S]*"4300:4300"/); + assert.doesNotMatch(composeProdSource, /ports:[\s\S]*"4300:4300"/); }); -test("edge broker is routed through traefik on port 4300 for public api hosts", () => { - assert.match(composeSource, /edge-broker:[\s\S]*traefik\.http\.routers\.edge-broker-dk\.entrypoints=edge-broker/); - assert.match(composeSource, /edge-broker:[\s\S]*traefik\.http\.routers\.edge-broker-io\.entrypoints=edge-broker/); +test("edge broker websocket paths are routed through the standard api entrypoints", () => { + assert.match(composeSource, /edge-broker:[\s\S]*traefik\.http\.routers\.edge-broker-dk\.rule=Host\(`api\.truckwash\.dk`\) && \(PathPrefix\(`\/ws\/agent`\) \|\| PathPrefix\(`\/ws\/browser-shell`\)\)/); + assert.match(composeSource, /edge-broker:[\s\S]*traefik\.http\.routers\.edge-broker-dk\.entrypoints=websecure/); + assert.match(composeSource, /edge-broker:[\s\S]*traefik\.http\.routers\.edge-broker-io\.rule=Host\(`api\.truckwash\.io`\) && \(PathPrefix\(`\/ws\/agent`\) \|\| PathPrefix\(`\/ws\/browser-shell`\)\)/); + assert.match(composeSource, /edge-broker:[\s\S]*traefik\.http\.routers\.edge-broker-io\.entrypoints=websecure/); + assert.match(composeSource, /edge-broker:[\s\S]*traefik\.http\.routers\.edge-broker-staging\.entrypoints=websecure-staging/); + assert.match(composeSource, /edge-broker:[\s\S]*traefik\.http\.routers\.edge-broker-local\.entrypoints=web/); + assert.match(composeSource, /edge-broker:[\s\S]*traefik\.http\.routers\.edge-broker-local-secure\.entrypoints=websecure/); assert.match(composeSource, /edge-broker:[\s\S]*traefik\.http\.services\.edge-broker\.loadbalancer\.server\.port=4300/); }); diff --git a/services/nginx/app/tests/Unit/Selfserve/EdgeGatewayManagerHeartbeatStatusTest.php b/services/nginx/app/tests/Unit/Selfserve/EdgeGatewayManagerHeartbeatStatusTest.php index 0ef37258..1de231e2 100644 --- a/services/nginx/app/tests/Unit/Selfserve/EdgeGatewayManagerHeartbeatStatusTest.php +++ b/services/nginx/app/tests/Unit/Selfserve/EdgeGatewayManagerHeartbeatStatusTest.php @@ -60,3 +60,10 @@ it('marks ready discovery as stale when the gateway heartbeat has expired', func expect($gateway['status'])->toBe(edge_gateway_manager::STATUS_OFFLINE); expect($gateway['discovery_status'])->toBe('STALE'); }); + +it('merges incoming heartbeat metadata with existing gateway metadata', function (): void { + $source = file_get_contents(app_path('classes/edge_gateway_manager.php')); + + expect($source)->toContain("\$existingMetadata = (array)(\$gateway->metadata_json->value() ?? []);"); + expect($source)->toContain("\$gateway->metadata_json->set(array_merge(\$existingMetadata, (array)(\$payload['metadata'] ?? [])));"); +}); diff --git a/services/traefik/traefik.prod.yml b/services/traefik/traefik.prod.yml index b493e58e..974bb24b 100644 --- a/services/traefik/traefik.prod.yml +++ b/services/traefik/traefik.prod.yml @@ -3,8 +3,6 @@ entryPoints: address: ":80" websecure: address: ":443" - edge-broker: - address: ":4300" certificatesResolvers: le: diff --git a/services/traefik/traefik.yml b/services/traefik/traefik.yml index 578bba0f..efcaceaa 100644 --- a/services/traefik/traefik.yml +++ b/services/traefik/traefik.yml @@ -3,8 +3,6 @@ entryPoints: address: ":80" websecure: address: ":443" - edge-broker: - address: ":4300" websecure-staging: address: ":4433" metrics: