diff --git a/internal/dev-entrypoint/metrics-sidecar.mjs b/internal/dev-entrypoint/metrics-sidecar.mjs index 4c1940b4..409b562d 100644 --- a/internal/dev-entrypoint/metrics-sidecar.mjs +++ b/internal/dev-entrypoint/metrics-sidecar.mjs @@ -1,4 +1,5 @@ import { createServer } from "node:http"; +import { realpathSync } from "node:fs"; import { pathToFileURL } from "node:url"; const DEFAULT_PORT = 9100; @@ -119,6 +120,16 @@ export function startMetricsSidecar({ env = process.env } = {}) { return server; } -if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) { +export function isMainModule({ moduleUrl = import.meta.url, argvPath = process.argv[1], realpath = realpathSync } = {}) { + if (!argvPath) return false; + if (moduleUrl === pathToFileURL(argvPath).href) return true; + try { + return moduleUrl === pathToFileURL(realpath(argvPath)).href; + } catch { + return false; + } +} + +if (isMainModule()) { startMetricsSidecar(); } diff --git a/internal/dev-entrypoint/metrics-sidecar.test.mjs b/internal/dev-entrypoint/metrics-sidecar.test.mjs index 348b9b9d..7d84a7de 100644 --- a/internal/dev-entrypoint/metrics-sidecar.test.mjs +++ b/internal/dev-entrypoint/metrics-sidecar.test.mjs @@ -1,7 +1,9 @@ import assert from "node:assert/strict"; import test from "node:test"; -import { buildMetricsText, sanitizeLabelValue } from "./metrics-sidecar.mjs"; +import { pathToFileURL } from "node:url"; + +import { buildMetricsText, isMainModule, sanitizeLabelValue } from "./metrics-sidecar.mjs"; test("metrics text exposes stable HWLAB labels without sensitive identifiers", () => { const text = buildMetricsText({ @@ -23,3 +25,20 @@ test("label sanitization keeps metrics labels low-risk", () => { assert.equal(sanitizeLabelValue("hwlab/cloud api\ntraceId=trc_1"), "hwlab_cloud_api_traceId_trc_1"); assert.equal(sanitizeLabelValue(""), "unknown"); }); + +test("entrypoint detection follows ConfigMap symlink paths", () => { + const realScriptPath = "/var/run/configmaps/hwlab-v02-metrics-sidecar/..2026_06_05/metrics-sidecar.mjs"; + const mountedScriptPath = "/metrics/metrics-sidecar.mjs"; + + assert.equal(isMainModule({ moduleUrl: pathToFileURL(mountedScriptPath).href, argvPath: mountedScriptPath }), true); + assert.equal(isMainModule({ + moduleUrl: pathToFileURL(realScriptPath).href, + argvPath: mountedScriptPath, + realpath: () => realScriptPath + }), true); + assert.equal(isMainModule({ + moduleUrl: pathToFileURL(realScriptPath).href, + argvPath: mountedScriptPath, + realpath: () => "/other/metrics-sidecar.mjs" + }), false); +}); diff --git a/scripts/g14-gitops-render.test.ts b/scripts/g14-gitops-render.test.ts index a8e475b1..e4796edb 100644 --- a/scripts/g14-gitops-render.test.ts +++ b/scripts/g14-gitops-render.test.ts @@ -238,6 +238,7 @@ test("v02 render follows TypeScript runtime checks and does not self-patch boots const sidecar = workload.spec.template.spec.containers.find((container) => container.name === "hwlab-metrics"); assert.ok(sidecar, `missing metrics sidecar for ${serviceId}`); assert.match(sidecar.image, /hwlab-ci-node-tools:node22-alpine-bun-v1/u); + assert.deepEqual(sidecar.command, ["node", "/metrics/metrics-sidecar.mjs"]); assert.ok(sidecar.env.some((entry) => entry.name === "HWLAB_METRICS_SERVICE_ID" && entry.value === serviceId)); assert.ok(sidecar.ports.some((port) => port.name === "metrics" && port.containerPort === 9100)); }