import assert from "node:assert/strict"; import { spawnSync } from "node:child_process"; import { createHash } from "node:crypto"; import { mkdir, mkdtemp, readFile, readdir, rm, writeFile } from "node:fs/promises"; import os from "node:os"; import path from "node:path"; import test from "node:test"; import { parse as parseYaml } from "yaml"; import { configString } from "./src/gitops-render/core.mjs"; import { opencodeEgressProxyUrlForProfile } from "./src/gitops-render/runtime-manifests.mjs"; import { CLOUD_CORE_MIGRATIONS, CLOUD_TRANSACTIONAL_REALTIME_MIGRATION_ID } from "../internal/db/schema.ts"; function taskByName(pipeline, name) { const task = pipeline.spec.tasks.find((item) => item.name === name); assert.ok(task, `missing task ${name}`); return task; } test("NC01 PaC artifact keeps the runtime GitOps file contract", async () => { const pipelinePath = "ci/pipelines/hwlab-nc01-v03-ci-image-publish.yaml"; const pacSource = await readFile(".tekton/hwlab-nc01-v03-pac.yaml", "utf8"); const pipelineSource = await readFile(pipelinePath, "utf8"); const pipeline = parseYaml(pipelineSource); assert.match(pacSource, new RegExp(`pipelinesascode\\.tekton\\.dev/pipeline: ${pipelinePath.replaceAll("/", "\\/")}`, "u")); const gitopsPromote = taskByName(pipeline, "gitops-promote"); assert.deepEqual(gitopsPromote.taskSpec.volumes, [{ name: "unidesk-runtime-gitops-scripts", configMap: { name: "hwlab-nc01-v03-ci-image-publish-runtime-gitops-scripts", defaultMode: 493 } }]); const promoteStep = gitopsPromote.taskSpec.steps.find((step) => step.name === "promote"); assert.ok(promoteStep, "missing gitops-promote promote step"); assert.equal(promoteStep.image, "127.0.0.1:5000/hwlab/hwlab-ci-node-tools:node22-alpine-bun-v1"); assert.deepEqual(promoteStep.volumeMounts, [{ name: "unidesk-runtime-gitops-scripts", mountPath: "/etc/unidesk-cicd-runtime-gitops", readOnly: true }]); const yamlDependencyBootstrap = [ 'ci_node_deps="${HWLAB_CI_NODE_DEPS:-/opt/hwlab-ci-node-deps/node_modules}"', 'if [ -d "$ci_node_deps" ]; then', ' if [ -d /workspace/source/repo ]; then ci_node_deps_target=/workspace/source/repo/node_modules; else ci_node_deps_target=./node_modules; fi', ' mkdir -p "$ci_node_deps_target"', ' for ci_node_dep in yaml; do if [ -d "$ci_node_deps/$ci_node_dep" ] && [ ! -e "$ci_node_deps_target/$ci_node_dep" ]; then ln -s "$ci_node_deps/$ci_node_dep" "$ci_node_deps_target/$ci_node_dep"; fi; done', "fi" ].join("\n"); const postprocessCommand = "UNIDESK_RUNTIME_GITOPS_OVERLAY_FILE=/etc/unidesk-cicd-runtime-gitops/runtime-gitops-overlay.json node /etc/unidesk-cicd-runtime-gitops/runtime-gitops-postprocess.mjs"; const verifyCommand = "UNIDESK_RUNTIME_GITOPS_OVERLAY_FILE=/etc/unidesk-cicd-runtime-gitops/runtime-gitops-overlay.json node /etc/unidesk-cicd-runtime-gitops/runtime-gitops-verify.mjs"; const runtimeGitopsVerifyMarker = "echo '{\"event\":\"gitops-promote\",\"status\":\"continuing\",\"reason\":\"no-build-no-rollout-plan-gitops-verify\"}' >&2"; const yamlDependencyBootstrapIndex = promoteStep.script.indexOf(yamlDependencyBootstrap); const postprocessIndex = promoteStep.script.indexOf(postprocessCommand); const verifyIndex = promoteStep.script.indexOf(verifyCommand); assert.notEqual(yamlDependencyBootstrapIndex, -1, "missing CI node yaml dependency bootstrap"); assert.ok(postprocessIndex > yamlDependencyBootstrapIndex, "runtime GitOps postprocess must run after yaml is linked into the source workspace"); assert.ok(verifyIndex > postprocessIndex, "runtime GitOps verify must run after postprocess with the same yaml dependency bootstrap"); assert.doesNotMatch(promoteStep.script, /UNIDESK_RUNTIME_GITOPS_OVERLAY_B64/u); assert.doesNotMatch(promoteStep.script, /willRunGitopsPromote/u); assert.equal(promoteStep.script.split(runtimeGitopsVerifyMarker).length - 1, 1, "runtime GitOps verify marker must stay exact and unique"); }); async function collectGeneratedFiles(root) { const files = []; async function walk(dir) { const entries = await readdir(dir, { withFileTypes: true }); for (const entry of entries) { const fullPath = path.join(dir, entry.name); if (entry.isDirectory()) await walk(fullPath); else if (entry.isFile()) files.push(fullPath); } } await walk(root); return files.sort(); } function collectContainersFromItem(item) { const podSpec = item?.spec?.template?.spec ?? item?.spec?.jobTemplate?.spec?.template?.spec ?? item?.spec?.template?.spec; return [ ...(podSpec?.initContainers ?? []), ...(podSpec?.containers ?? []) ]; } function extractRuntimeNoopDecisionScript(gitopsPromoteScript) { const marker = `runtime_noop_decision="$(node - "$runtime_path" "$old_runtime_snapshot" /workspace/source/affected-services.json <<'NODE'\n`; const start = gitopsPromoteScript.indexOf(marker); assert.notEqual(start, -1, "missing runtime no-op decision script"); const rest = gitopsPromoteScript.slice(start + marker.length); const end = rest.indexOf("\nNODE\n)"); assert.notEqual(end, -1, "missing runtime no-op decision terminator"); return rest.slice(0, end); } function runtimeWorkloadsFixture({ runtimeCommit, agentRunBundleCommit }) { return { items: [{ kind: "Deployment", metadata: { name: "hwlab-cloud-api", labels: { "hwlab.pikastech.local/source-commit": runtimeCommit }, annotations: { "hwlab.pikastech.local/boot-commit": runtimeCommit } }, spec: { template: { metadata: { labels: { "hwlab.pikastech.local/source-commit": runtimeCommit, "hwlab.pikastech.local/artifact-source-commit": runtimeCommit }, annotations: { "hwlab.pikastech.local/boot-commit": runtimeCommit } }, spec: { containers: [{ name: "hwlab-cloud-api", env: [ { name: "HWLAB_COMMIT_ID", value: runtimeCommit }, { name: "HWLAB_GITOPS_SOURCE_COMMIT", value: runtimeCommit }, { name: "HWLAB_CODE_AGENT_AGENTRUN_SOURCE_COMMIT", value: agentRunBundleCommit } ] }] } } } }] }; } async function runtimeNoopDecision(gitopsPromoteScript, { oldRuntime, newRuntime }) { const script = extractRuntimeNoopDecisionScript(gitopsPromoteScript); const root = await mkdtemp(path.join(os.tmpdir(), "hwlab-v02-runtime-noop-")); try { const oldDir = path.join(root, "old-runtime"); const newDir = path.join(root, "new-runtime"); const planPath = path.join(root, "affected-services.json"); await mkdir(oldDir, { recursive: true }); await mkdir(newDir, { recursive: true }); await writeFile(path.join(oldDir, "workloads.json"), JSON.stringify(runtimeWorkloadsFixture(oldRuntime), null, 2)); await writeFile(path.join(newDir, "workloads.json"), JSON.stringify(runtimeWorkloadsFixture(newRuntime), null, 2)); await writeFile(planPath, JSON.stringify({ buildServices: [], rolloutServices: [] })); const result = spawnSync(process.execPath, ["-", newDir, oldDir, planPath], { input: script, encoding: "utf8" }); assert.equal(result.status, 0, result.stderr || result.stdout); return result.stdout.trim(); } finally { await rm(root, { recursive: true, force: true }); } } test("opencode APK proxy prefers explicit gitMirror proxyUrl", async () => { assert.equal(configString(" value "), "value"); assert.equal(opencodeEgressProxyUrlForProfile({ lanes: { v03: { gitMirror: { egressProxy: { required: true, proxyUrl: "http://10.42.0.1:10808", namespace: "platform-infra", serviceName: "jd01-host-proxy", port: 10808 } } } } }, "v03"), "http://10.42.0.1:10808"); assert.equal(opencodeEgressProxyUrlForProfile({ lanes: { v03: { gitMirror: { egressProxy: { required: true, namespace: "platform-infra", serviceName: "sub2api-egress-proxy", port: 10808 } } } } }, "v03"), "http://sub2api-egress-proxy.platform-infra.svc.cluster.local:10808"); assert.equal(opencodeEgressProxyUrlForProfile({ lanes: { v03: { gitMirror: { egressProxy: { required: false, proxyUrl: "http://10.42.0.1:10808" } } } } }, "v03"), ""); }); test("v02 render follows TypeScript runtime checks and does not self-patch bootstrap RBAC", async () => { const outDir = await mkdtemp(path.join(os.tmpdir(), "hwlab-v02-render-test-")); try { const head = spawnSync("git", ["rev-parse", "HEAD"], { cwd: process.cwd(), encoding: "utf8" }); assert.equal(head.status, 0, head.stderr || head.stdout); const sourceRevision = head.stdout.trim(); const staleRuntimeFile = path.join(outDir, "runtime-v02", "stale-gateway-simu.yaml"); const staleTektonFile = path.join(outDir, "tekton-v02", "stale-router.yaml"); await mkdir(path.dirname(staleRuntimeFile), { recursive: true }); await mkdir(path.dirname(staleTektonFile), { recursive: true }); await writeFile(staleRuntimeFile, "kind: Service\nmetadata:\n name: hwlab-gateway-simu\n"); await writeFile(staleTektonFile, "hwlab-router\n"); const render = spawnSync(process.execPath, [ "scripts/run-bun.mjs", "scripts/gitops-render.mjs", "--lane", "v02", "--catalog-path", "deploy/artifact-catalog.v02.json", "--image-tag-mode", "full", "--source-branch", "v0.2", "--gitops-branch", "v0.2-gitops", "--out", outDir, "--source-revision", "HEAD" ], { cwd: process.cwd(), encoding: "utf8" }); assert.equal(render.status, 0, render.stderr || render.stdout); await assert.rejects(() => readFile(staleRuntimeFile, "utf8"), { code: "ENOENT" }); await assert.rejects(() => readFile(staleTektonFile, "utf8"), { code: "ENOENT" }); const pipeline = await readFile(path.join(outDir, "tekton-v02", "pipeline.yaml"), "utf8"); const pipelineJson = JSON.parse(pipeline); assert.match(pipeline, /127\.0\.0\.1:5000\/hwlab\/hwlab-ci-node-tools:node22-alpine-bun-v1/u); assert.match(pipeline, /tar -C \/workspace\/source\/repo -cf - \. \| tar -C \/workspace\/service-work\/repo -xo -f -/u); assert.match(pipeline, /node scripts\/run-bun\.mjs test cmd\/hwlab-codex-api-responses-forwarder\/main\.test\.ts/u); assert.doesNotMatch(pipeline, /cmd\/hwlab-codex-api-responses-forwarder\/main\.mjs/u); const runtimeReadySource = await readFile(path.join(process.cwd(), "scripts/ci/runtime-ready.mjs"), "utf8"); assert.match(runtimeReadySource, /process\.exitCode = 1/u); assert.match(runtimeReadySource, /item\.metadata\?\.labels\?\.\["hwlab\.pikastech\.local\/source-commit"\]/u); assert.ok(!pipelineJson.spec.tasks.some((task) => task.name === "runtime-ready")); const planArtifacts = taskByName(pipelineJson, "plan-artifacts"); const planArtifactsScript = planArtifacts.taskSpec.steps[0].script; assert.match(planArtifactsScript, /node scripts\/ci\/restore-artifact-catalog\.mjs/u); assert.match(planArtifactsScript, /HWLAB_GIT_READ_URL="\$\(params\.git-read-url\)"/u); assert.match(planArtifactsScript, /HWLAB_SERVICES="\$\(params\.services\)"/u); assert.match(planArtifactsScript, /rolloutWithoutImageBuildServices/u); assert.match(planArtifactsScript, /serviceReusedCount/u); assert.match(planArtifactsScript, /artifactCatalog: plan\.artifactCatalog/u); assert.ok(planArtifacts.taskSpec.params.some((param) => param.name === "git-read-url")); assert.ok(planArtifacts.taskSpec.params.some((param) => param.name === "gitops-branch")); assert.ok(planArtifacts.params.some((param) => param.name === "lane" && param.value === "$(params.lane)")); assert.ok(pipelineJson.spec.params.some((param) => param.name === "runtime-ready-timeout-ms" && param.default === "60000")); const gitopsPromote = taskByName(pipelineJson, "gitops-promote"); assert.ok(gitopsPromote.taskSpec.results.some((result) => result.name === "runtime-ready-required")); const gitopsPromoteScript = gitopsPromote.taskSpec.steps[0].script; assert.match(gitopsPromoteScript, /if \[ "\$runtime_lane" = "true" \]; then\s+printf 'false' > \/tekton\/results\/runtime-ready-required\s+else\s+printf 'true' > \/tekton\/results\/runtime-ready-required/u); assert.match(gitopsPromoteScript, /runtime-identity-only/u); assert.match(gitopsPromoteScript, /skipped-runtime-unchanged/u); assert.match(gitopsPromoteScript, /printf 'false' > \/tekton\/results\/runtime-ready-required/u); assert.equal(await runtimeNoopDecision(gitopsPromoteScript, { oldRuntime: { runtimeCommit: "1111111111111111111111111111111111111111", agentRunBundleCommit: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" }, newRuntime: { runtimeCommit: "2222222222222222222222222222222222222222", agentRunBundleCommit: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" } }), "runtime-identity-only"); assert.match(gitopsPromoteScript, /argo_hard_refresh_runtime_lane\(\) \{/u); assert.match(gitopsPromoteScript, /ARGO_APPLICATION="hwlab-node-\$lane" ARGO_FIELD_MANAGER="hwlab-\$lane-gitops-promote"/u); assert.match(gitopsPromoteScript, /argocd\.argoproj\.io\/refresh": "hard"/u); assert.match(gitopsPromoteScript, /applications\/" \+ encodeURIComponent\(application\) \+ "\?fieldManager=" \+ encodeURIComponent\(fieldManager\)/u); assert.match(gitopsPromoteScript, /BatchMode=yes/u); assert.match(gitopsPromoteScript, /ConnectTimeout=10/u); assert.match(gitopsPromoteScript, /git_timed "source-head-\$phase" 45 git ls-remote/u); assert.match(gitopsPromoteScript, /"event":"git-ssh-setup","phase":"gitops-promote","status":"skipped"/u); assert.match(gitopsPromoteScript, /source_head_url="\$\(params\.git-read-url\)"/u); assert.match(gitopsPromoteScript, /gitops_write_url="\$\(params\.git-write-url\)"/u); assert.match(gitopsPromoteScript, /git clone --no-checkout "\$gitops_read_url"/u); assert.match(gitopsPromoteScript, /git_timed gitops-push 120 git push origin/u); assert.doesNotMatch(gitopsPromoteScript, /gitops-promote-proxy-preflight/u); assert.doesNotMatch(gitopsPromoteScript, /for tool in node npm git ssh curl timeout/u); const prepareSource = taskByName(pipelineJson, "prepare-source"); assert.ok(prepareSource.taskSpec.params.some((param) => param.name === "git-read-url")); assert.ok(prepareSource.params.some((param) => param.name === "git-read-url" && param.value === "$(params.git-read-url)")); const prepareSourceScript = prepareSource.taskSpec.steps[0].script; assert.match(prepareSourceScript, /git_read_url="\$\(params\.git-read-url\)"/u); assert.match(prepareSourceScript, /"event":"git-ssh-setup","phase":"prepare-source","status":"skipped"/u); assert.match(prepareSourceScript, /git_timed source-clone 180 git clone --branch "\$\(params\.source-branch\)" "\$git_read_url"/u); assert.match(prepareSourceScript, /git_timed catalog-ls-remote 45 git ls-remote --exit-code --heads "\$git_read_url"/u); assert.match(prepareSourceScript, /git remote set-url gitops-catalog "\$git_read_url"/u); assert.match(prepareSourceScript, /"event":"prepare-source-dependencies","status":"skipped","reason":"renderer-dependency-install-disabled","dependency":"yaml"/u); assert.doesNotMatch(prepareSourceScript, /require\.resolve\("yaml"\)/u); assert.doesNotMatch(prepareSourceScript, /npm ci --ignore-scripts --no-audit --prefer-offline/u); assert.doesNotMatch(prepareSourceScript, /bun install --frozen-lockfile --ignore-scripts/u); assert.doesNotMatch(prepareSourceScript, /ci-tools-image-provides-required-node-runtime/u); assert.doesNotMatch(prepareSourceScript, /prepare-source-pre-npm/u); assert.doesNotMatch(prepareSourceScript, /prepare-source-proxy-preflight/u); assert.doesNotMatch(prepareSourceScript, /dependency-curl-probe-start/u); assert.doesNotMatch(planArtifacts.taskSpec.steps[0].script, /plan-artifacts-proxy-preflight/u); const collectArtifacts = taskByName(pipelineJson, "collect-artifacts"); assert.doesNotMatch(collectArtifacts.taskSpec.steps[0].script, /collect-artifacts-proxy-preflight/u); const pipelineGitReadParam = pipelineJson.spec.params.find((param) => param.name === "git-read-url"); assert.equal(pipelineGitReadParam?.default, "http://gitea-http.devops-infra.svc.cluster.local:3000/mirrors/pikasTech-HWLAB.git"); const pipelineGitWriteParam = pipelineJson.spec.params.find((param) => param.name === "git-write-url"); assert.equal(pipelineGitWriteParam?.default, "http://git-mirror-write.devops-infra.svc.cluster.local/pikasTech/HWLAB.git"); const sourceDescriptor = JSON.parse(await readFile(path.join(outDir, "source.json"), "utf8")); assert.equal(sourceDescriptor.gitReadUrl, "http://gitea-http.devops-infra.svc.cluster.local:3000/mirrors/pikasTech-HWLAB.git"); assert.equal(sourceDescriptor.gitWriteUrl, "http://git-mirror-write.devops-infra.svc.cluster.local/pikasTech/HWLAB.git"); const gitMirror = await readFile(path.join(outDir, "devops-infra", "git-mirror.yaml"), "utf8"); assert.match(gitMirror, /"name": "devops-infra"/u); assert.match(gitMirror, /"name": "git-mirror-http"/u); assert.match(gitMirror, /"name": "git-mirror-write"/u); assert.match(gitMirror, /"name": "git-mirror-sync-script"/u); assert.match(gitMirror, /git-receive-pack/u); assert.match(gitMirror, /last-flush\.json/u); assert.match(gitMirror, /last-write\.json/u); assert.match(gitMirror, /ssh:\/\/git@ssh\.github\.com:443\/pikasTech\/HWLAB\.git/u); assert.doesNotMatch(gitMirror, /"kind": "CronJob"/u); assert.doesNotMatch(gitMirror, /"name": "git-mirror-hwlab-sync"/u); const gitMirrorJson = JSON.parse(gitMirror); const gitMirrorConfigMap = gitMirrorJson.items.find((item) => item.kind === "ConfigMap" && item.metadata?.name === "git-mirror-sync-script"); const gitMirrorScripts = gitMirrorConfigMap?.data ?? {}; const gitMirrorScript = gitMirrorScripts["sync.sh"] ?? ""; assert.match(gitMirrorScript, /uploadpack\.allowReachableSHA1InWant true/u); assert.match(gitMirrorScript, /uploadpack\.allowAnySHA1InWant true/u); assert.match(gitMirrorScript, /refs\/heads\/v0\.2:refs\/mirror-stage\/heads\/v0\.2/u); assert.match(gitMirrorScript, /refs\/heads\/v0\.2-gitops:refs\/mirror-stage\/heads\/v0\.2-gitops/u); assert.match(gitMirrorScript, /refs\/heads\/v0\.3:refs\/mirror-stage\/heads\/v0\.3/u); assert.match(gitMirrorScript, /refs\/heads\/v0\.3-gitops:refs\/mirror-stage\/heads\/v0\.3-gitops/u); assert.doesNotMatch(gitMirrorScript, /refs\/heads\/G14:refs\/mirror-stage\/heads\/G14/u); assert.doesNotMatch(gitMirrorScript, /refs\/heads\/G14-gitops:refs\/mirror-stage\/heads\/G14-gitops/u); assert.doesNotMatch(gitMirrorScript, /refs\/heads\/\*:refs\/mirror-stage\/heads\/\*/u); assert.match(gitMirrorScript, /git -C "\$repo_path" update-ref "refs\/heads\/\$name" "\$sha"/u); assert.match(gitMirrorScript, /source_snapshot_ref_prefix='refs\/unidesk\/snapshots\/hwlab-node-runtime'/u); assert.match(gitMirrorScript, /source_stage_ref="\$\{source_snapshot_ref_prefix%\/\}\/\$source_branch\/\$source_sha"/u); assert.match(gitMirrorScript, /git -C "\$repo_path" update-ref "\$source_stage_ref" "\$source_sha"/u); assert.match(gitMirrorScript, /git-mirror-sync-timing/u); assert.match(gitMirrorScript, /emit_timing fetch succeeded/u); assert.match(gitMirrorScript, /emit_timing total succeeded/u); assert.match(gitMirrorScript, /sourceInSync/u); assert.match(gitMirrorScript, /sourceSnapshots/u); assert.match(gitMirrorScript, /refs\/unidesk\/snapshots\/hwlab-node-runtime/u); assert.match(gitMirrorScript, /refs\/mirror-stage\/heads\/v0\.2/u); assert.match(gitMirrorScript, /refs\/mirror-stage\/heads\/v0\.3/u); assert.match(gitMirrorScript, /for gitops_branch in 'v0\.2-gitops' 'v0\.3-gitops'/u); assert.match(gitMirrorScript, /keeps local \$name ahead of GitHub/u); assert.doesNotMatch(gitMirror, /not allowlisted/u); assert.doesNotMatch(gitMirror, /path allowlist/u); assert.doesNotMatch(gitMirror, /outside .* GitOps outputs/u); assert.ok((gitMirrorJson.items || []).every((item) => item.kind !== "Secret")); assert.ok((gitMirrorJson.items || []).every((item) => item.kind !== "CronJob")); assert.ok((gitMirrorJson.items || []).every((item) => !item.data?.["ssh-privatekey"])); const scriptCheckDir = path.join(outDir, "script-check"); await mkdir(scriptCheckDir, { recursive: true }); for (const scriptName of ["http.mjs", "sync.sh", "install-hooks.sh", "flush.sh"]) { assert.ok(gitMirrorScripts[scriptName], `missing git mirror script ${scriptName}`); await writeFile(path.join(scriptCheckDir, scriptName), gitMirrorScripts[scriptName]); } const httpCheck = spawnSync("node", ["--check", path.join(scriptCheckDir, "http.mjs")], { encoding: "utf8" }); assert.equal(httpCheck.status, 0, httpCheck.stderr || httpCheck.stdout); for (const scriptName of ["sync.sh", "install-hooks.sh", "flush.sh"]) { const shellCheck = spawnSync("sh", ["-n", path.join(scriptCheckDir, scriptName)], { encoding: "utf8" }); assert.equal(shellCheck.status, 0, `${scriptName}: ${shellCheck.stderr || shellCheck.stdout}`); } const removedServiceIds = [ "hwlab-agent-mgr", "hwlab-agent-worker", "hwlab-agent-worker-template", "hwlab-code-agent-workspace", "hwlab-router", "hwlab-tunnel-client", "hwlab-gateway-simu", "hwlab-box-simu", "hwlab-patch-panel" ]; for (const serviceId of removedServiceIds) { assert.doesNotMatch(pipeline, new RegExp(`build-${serviceId}`, "u")); } const retainedServiceIds = [ "hwlab-cloud-api", "hwlab-cloud-web", "hwlab-gateway", "hwlab-edge-proxy", "hwlab-agent-skills" ]; for (let index = 0; index < retainedServiceIds.length; index += 1) { const serviceId = retainedServiceIds[index]; const task = taskByName(pipelineJson, `build-${serviceId}`); assert.deepEqual(task.runAfter, ["plan-artifacts"]); assert.deepEqual(task.when, [{ input: `$(tasks.plan-artifacts.results.build-${serviceId})`, operator: "in", values: ["true"] }]); } const collectScript = collectArtifacts.taskSpec.steps[0].script; assert.match(collectScript, /--external-service-report-dir \/workspace\/source\/service-results/u); assert.ok( taskByName(pipelineJson, "build-hwlab-cloud-web").taskSpec.results.some((result) => result.name === "go-base-image-status"), "build task should declare Go base evidence Tekton results so artifact-publish result files are collected" ); const cloudWebBuildScript = taskByName(pipelineJson, "build-hwlab-cloud-web").taskSpec.steps.find((step) => step.name === "publish")?.script ?? ""; assert.match(cloudWebBuildScript, /node scripts\/artifact-publish\.mjs --publish/u); const artifactPublishSource = await readFile("scripts/artifact-publish.mjs", "utf8"); assert.match(artifactPublishSource, /\["run", "--cwd", "web\/hwlab-cloud-web", "check"\]/u); assert.match(artifactPublishSource, /cloud web source check failed before BuildKit image build/u); assert.match(artifactPublishSource, /\/usr\/local\/bin\/hwpod/u); assert.doesNotMatch(artifactPublishSource, /Run bun run --cwd web\/hwlab-cloud-web build, fix the static asset build/u); const workloads = await readFile(path.join(outDir, "runtime-v02", "workloads.yaml"), "utf8"); const workloadsJson = JSON.parse(workloads); const services = await readFile(path.join(outDir, "runtime-v02", "services.yaml"), "utf8"); const servicesJson = JSON.parse(services); const deepseekProxy = JSON.parse(await readFile(path.join(outDir, "runtime-v02", "deepseek-proxy.yaml"), "utf8")); const observability = await readFile(path.join(outDir, "runtime-v02", "observability.yaml"), "utf8"); const observabilityJson = JSON.parse(observability); for (const serviceId of removedServiceIds) { assert.doesNotMatch(workloads, new RegExp(serviceId, "u")); assert.doesNotMatch(services, new RegExp(serviceId, "u")); } const observableRuntimeServiceIds = [ "hwlab-agent-skills", "hwlab-cloud-api", "hwlab-cloud-web", "hwlab-edge-proxy" ]; for (const serviceId of observableRuntimeServiceIds) { const service = servicesJson.items.find((item) => item.kind === "Service" && item.metadata?.name === serviceId); assert.ok(service, `missing observable service ${serviceId}`); assert.equal(service.metadata.labels["hwlab.pikastech.local/monitoring"], "enabled"); assert.ok(service.spec.ports.some((port) => port.name === "metrics" && port.port === 9100 && port.targetPort === "metrics"), `missing metrics port for ${serviceId}`); const workload = workloadsJson.items.find((item) => item.kind === "Deployment" && item.metadata?.name === serviceId); assert.ok(workload, `missing observable workload ${serviceId}`); assert.equal(workload.metadata.labels["hwlab.pikastech.local/monitoring"], "enabled"); 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.match(workload.spec.template.metadata.annotations["hwlab.pikastech.local/metrics-sidecar-sha256"], /^[a-f0-9]{64}$/u); 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)); if (serviceId === "hwlab-cloud-api") { assert.ok(sidecar.env.some((entry) => entry.name === "HWLAB_METRICS_EXTRA_URL" && /\/v1\/web-performance\/metrics$/u.test(entry.value)), "cloud-api sidecar should scrape WebUI performance metrics from loopback"); } else { assert.equal(sidecar.env.some((entry) => entry.name === "HWLAB_METRICS_EXTRA_URL"), false, `unexpected extra metrics target for ${serviceId}`); } if (serviceId === "hwlab-edge-proxy") { const container = workload.spec.template.spec.containers.find((entry) => entry.name === "hwlab-edge-proxy"); assert.equal(container.readinessProbe.httpGet.path, "/health"); assert.equal(container.livenessProbe.httpGet.path, "/health"); } } const deepseekService = deepseekProxy.items.find((item) => item.kind === "Service" && item.metadata?.name === "hwlab-deepseek-proxy"); assert.equal(deepseekService.metadata.labels["hwlab.pikastech.local/monitoring"], "enabled"); assert.ok(deepseekService.spec.ports.some((port) => port.name === "metrics" && port.port === 9100)); const deepseekDeployment = deepseekProxy.items.find((item) => item.kind === "Deployment" && item.metadata?.name === "hwlab-deepseek-proxy"); assert.ok(deepseekDeployment.spec.template.spec.containers.some((container) => container.name === "hwlab-metrics")); assert.equal( deepseekDeployment.spec.template.metadata.annotations["hwlab.pikastech.local/metrics-sidecar-sha256"], workloadsJson.items.find((item) => item.kind === "Deployment" && item.metadata?.name === "hwlab-cloud-api").spec.template.metadata.annotations["hwlab.pikastech.local/metrics-sidecar-sha256"] ); const observabilityItems = observabilityJson.items ?? []; const metricsConfig = observabilityItems.find((item) => item.kind === "ConfigMap" && item.metadata?.name === "hwlab-v02-metrics-sidecar"); assert.ok(metricsConfig, "missing metrics sidecar ConfigMap"); assert.match(metricsConfig.data["metrics-sidecar.mjs"], /hwlab_service_up/u); const serviceMonitors = observabilityItems.filter((item) => item.kind === "ServiceMonitor"); assert.deepEqual(serviceMonitors.map((item) => item.metadata.name).sort(), [ "hwlab-v02-hwlab-agent-skills", "hwlab-v02-hwlab-cloud-api", "hwlab-v02-hwlab-cloud-web", "hwlab-v02-hwlab-deepseek-proxy", "hwlab-v02-hwlab-edge-proxy" ]); for (const monitor of serviceMonitors) { assert.equal(monitor.metadata.namespace, "hwlab-v02"); assert.equal(monitor.metadata.labels["hwlab.pikastech.local/monitoring"], "enabled"); assert.deepEqual(monitor.spec.namespaceSelector.matchNames, ["hwlab-v02"]); assert.equal(monitor.spec.selector.matchLabels["hwlab.pikastech.local/gitops-target"], "v02"); assert.equal(monitor.spec.selector.matchLabels["hwlab.pikastech.local/monitoring"], "enabled"); assert.deepEqual(monitor.spec.endpoints, [{ port: "metrics", path: "/metrics", interval: "30s", scrapeTimeout: "10s" }]); } assert.ok(observabilityItems.some((item) => item.kind === "PrometheusRule" && item.metadata?.name === "hwlab-v02-observability")); assert.match(workloads, /"name": "HWLAB_ACCESS_CONTROL_REQUIRED"[\s\S]{0,80}"value": "1"/u); assert.match(workloads, /"name": "HWLAB_BOOTSTRAP_ADMIN_PASSWORD_HASH"/u); assert.match(workloads, /"name": "hwlab-v02-bootstrap-admin"/u); const cloudApi = workloadsJson.items.find((item) => item.metadata?.name === "hwlab-cloud-api"); assert.ok(cloudApi, "expected v02 hwlab-cloud-api workload"); const cloudApiContainer = cloudApi.spec.template.spec.containers.find((container) => container.name === "hwlab-cloud-api"); const codexForwarder = cloudApi.spec.template.spec.containers.find((container) => container.name === "hwlab-codex-api-forwarder"); assert.ok(cloudApiContainer, "expected cloud-api app container"); assert.ok(codexForwarder, "expected codex API forwarder sidecar"); const cloudApiEnv = cloudApiContainer.env; const cloudApiCommit = cloudApiEnv.find((entry) => entry.name === "HWLAB_COMMIT_ID")?.value; const cloudApiBootEnv = new Map(cloudApiEnv.map((entry) => [entry.name, entry.value])); assert.equal(cloudApiBootEnv.get("HWLAB_RUNTIME_MODE"), "env-reuse-git-mirror-checkout"); assert.equal(cloudApiBootEnv.get("HWLAB_BOOT_SH"), "deploy/runtime/boot/hwlab-cloud-api.sh"); const codexForwarderEnv = new Map(codexForwarder.env.map((entry) => [entry.name, entry.value])); assert.equal(codexForwarder.command, undefined); assert.equal(codexForwarderEnv.get("HWLAB_RUNTIME_MODE"), "env-reuse-git-mirror-checkout"); assert.equal(codexForwarderEnv.get("HWLAB_BOOT_SH"), "deploy/runtime/boot/hwlab-codex-api-responses-forwarder.sh"); assert.equal(codexForwarderEnv.get("HWLAB_BOOT_COMMIT"), cloudApiCommit); assert.equal(codexForwarderEnv.get("HWLAB_BOOT_READ_URL"), "http://gitea-http.devops-infra.svc.cluster.local:3000/mirrors/pikasTech-HWLAB.git"); assert.ok(cloudApiEnv.some((entry) => entry.name === "HWLAB_CODE_AGENT_AGENTRUN_SOURCE_COMMIT" && entry.value === cloudApiCommit)); assert.ok(cloudApiEnv.some((entry) => entry.name === "HWLAB_CODE_AGENT_ADAPTER" && entry.value === "agentrun-v01")); assert.equal(cloudApi.spec.template.spec.initContainers?.some((entry) => entry.name === "hwlab-code-agent-workspace-init"), false); assert.equal(cloudApi.spec.template.spec.volumes?.some((entry) => /code-agent-codex|code-agent-workspace/u.test(entry.name)), false); assert.equal(cloudApiContainer.volumeMounts?.some((entry) => /code-agent-codex|code-agent-workspace/u.test(entry.name)), false); assert.equal(cloudApiEnv.some((entry) => entry.name === "HWLAB_CODE_AGENT_PROVIDER" && entry.value === "codex-stdio"), false); assert.ok(cloudApiEnv.some((entry) => entry.name === "HWLAB_CODE_AGENT_CODEX_STDIO_SUPERVISOR" && entry.value === "repo-owned")); assert.ok(cloudApiEnv.some((entry) => entry.name === "UNIDESK_MAIN_SERVER_IP" && entry.value === "http://74.48.78.17:18081")); assert.ok(cloudApiEnv.some((entry) => entry.name === "HWLAB_KEYCLOAK_ISSUER" && entry.value === "https://auth.74-48-78-17.nip.io/realms/hwlab")); assert.ok(cloudApiEnv.some((entry) => entry.name === "HWLAB_KEYCLOAK_CLIENT_ID" && entry.value === "hwlab-cloud-web")); assert.ok(cloudApiEnv.some((entry) => entry.name === "HWLAB_KEYCLOAK_CLIENT_SECRET" && entry.valueFrom?.secretKeyRef?.name === "hwlab-cloud-web-client" && entry.valueFrom?.secretKeyRef?.key === "client-secret")); assert.ok(cloudApiEnv.some((entry) => entry.name === "HWLAB_OPENFGA_MODE" && entry.value === "enforce")); assert.ok(cloudApiEnv.some((entry) => entry.name === "HWLAB_OPENFGA_API_URL" && entry.value === "http://hwlab-openfga.hwlab-v02.svc.cluster.local:8080")); assert.ok(cloudApiEnv.some((entry) => entry.name === "HWLAB_OPENFGA_AUTHN_TOKEN" && entry.valueFrom?.secretKeyRef?.name === "hwlab-v02-openfga" && entry.valueFrom?.secretKeyRef?.key === "authn-preshared-key")); const deepseekResponsesBridge = deepseekDeployment.spec.template.spec.containers.find((container) => container.name === "responses-bridge"); assert.ok(deepseekResponsesBridge, "expected DeepSeek responses bridge container"); const deepseekBridgeEnv = new Map(deepseekResponsesBridge.env.map((entry) => [entry.name, entry.value])); assert.equal(deepseekResponsesBridge.command, undefined); assert.equal(deepseekBridgeEnv.get("HWLAB_RUNTIME_MODE"), "env-reuse-git-mirror-checkout"); assert.equal(deepseekBridgeEnv.get("HWLAB_BOOT_SH"), "deploy/runtime/boot/hwlab-deepseek-responses-bridge.sh"); assert.equal(deepseekBridgeEnv.get("HWLAB_BOOT_COMMIT"), cloudApiCommit); assert.equal(deepseekBridgeEnv.get("HWLAB_BOOT_READ_URL"), "http://gitea-http.devops-infra.svc.cluster.local:3000/mirrors/pikasTech-HWLAB.git"); assert.equal(workloadsJson.items.some((item) => item.metadata?.labels?.["hwlab.pikastech.local/service-id"] === "hwlab-agent-worker"), false); const kustomization = await readFile(path.join(outDir, "runtime-v02", "kustomization.yaml"), "utf8"); assert.doesNotMatch(kustomization, /code-agent-codex-config/u); assert.match(kustomization, /openfga\.yaml/u); const workloadTemplates = workloadsJson.items.filter((item) => item.spec?.template?.metadata?.labels?.["hwlab.pikastech.local/source-commit"]); assert.ok(workloadTemplates.length > 0, "expected rendered pod-template source labels"); assert.ok(workloadTemplates.some((item) => item.spec.template.metadata.labels["hwlab.pikastech.local/artifact-source-commit"]), "expected artifact source labels on pod templates"); assert.doesNotMatch(workloads, /HWLAB_GATEWAY_SIMU_URL/u); assert.doesNotMatch(workloads, /HWLAB_BOX_SIMU_URL/u); assert.doesNotMatch(workloads, /HWLAB_PATCH_PANEL_URL/u); assert.doesNotMatch(workloads, /HWLAB_ROUTER_URL/u); assert.doesNotMatch(workloads, /HWLAB_TUNNEL_CLIENT_URL/u); assert.doesNotMatch(pipeline, /hwlab-gateway-simu-status/u); assert.doesNotMatch(pipeline, /tasks\.build-hwlab-cloud-api\.results/u); assert.match(pipeline, /--external-service-report-dir \/workspace\/source\/service-results/u); const application = await readFile(path.join(outDir, "argocd", "application-v02.yaml"), "utf8"); assert.match(application, /"prune": true/u); assert.match(application, /gitea-http\.devops-infra\.svc\.cluster\.local:3000\/mirrors\/pikasTech-HWLAB\.git/u); assert.doesNotMatch(application, /git@github\.com:pikasTech\/HWLAB\.git/u); for (const generatedFile of ["deepseek-proxy.yaml", "postgres.yaml", "openfga.yaml", "node-frpc.yaml"]) { const content = await readFile(path.join(outDir, "runtime-v02", generatedFile), "utf8"); assert.match(content, /"hwlab\.pikastech\.local\/source-commit"/u); } const frpc = JSON.parse(await readFile(path.join(outDir, "runtime-v02", "node-frpc.yaml"), "utf8")); const frpcDeployment = frpc.items.find((item) => item.kind === "Deployment"); const frpcConfigLabel = frpcDeployment.spec.template.metadata.labels["hwlab.pikastech.local/config-sha256"]; const frpcConfigAnnotation = frpcDeployment.spec.template.metadata.annotations["hwlab.pikastech.local/config-sha256"]; assert.equal(frpcDeployment.spec.template.spec.hostNetwork, true); assert.equal(frpcDeployment.spec.template.spec.dnsPolicy, "ClusterFirstWithHostNet"); assert.ok(frpcConfigLabel); assert.equal(frpcConfigLabel.length <= 63, true); assert.match(frpcConfigAnnotation, /^[a-f0-9]{64}$/u); assert.equal(frpcConfigAnnotation.startsWith(frpcConfigLabel), true); assert.equal(frpcDeployment.spec.template.metadata.labels["hwlab.pikastech.local/source-commit"], undefined); const postgres = JSON.parse(await readFile(path.join(outDir, "runtime-v02", "postgres.yaml"), "utf8")); const postgresMigrationConfig = postgres.items.find((item) => item.kind === "ConfigMap" && item.metadata?.name === "hwlab-v02-postgres-init"); const postgresStatefulSet = postgres.items.find((item) => item.kind === "StatefulSet"); const postgresMigrationLabel = postgresStatefulSet.spec.template.metadata.labels["hwlab.pikastech.local/migration-sha256"]; const postgresMigrationAnnotation = postgresStatefulSet.spec.template.metadata.annotations["hwlab.pikastech.local/migration-sha256"]; const migrationSources = await Promise.all(CLOUD_CORE_MIGRATIONS.map(async (migration) => ({ ...migration, sql: await readFile(path.join(process.cwd(), migration.path), "utf8") }))); const migrationData = Object.fromEntries(migrationSources.map((migration) => [path.basename(migration.path), migration.sql])); const migrationSha256 = createHash("sha256").update(migrationSources.map((migration) => migration.sql).join("\n")).digest("hex"); assert.deepEqual(postgresMigrationConfig.data, migrationData); assert.deepEqual(Object.keys(postgresMigrationConfig.data), CLOUD_CORE_MIGRATIONS.map((migration) => path.basename(migration.path))); assert.match(postgresMigrationConfig.data["0008_workbench_kafka_realtime.sql"], new RegExp(`'${CLOUD_TRANSACTIONAL_REALTIME_MIGRATION_ID}'`, "u")); assert.ok(postgresMigrationLabel); assert.equal(postgresMigrationLabel.length <= 63, true); assert.match(postgresMigrationAnnotation, /^[a-f0-9]{64}$/u); assert.equal(postgresMigrationAnnotation, migrationSha256); assert.equal(postgresMigrationAnnotation.startsWith(postgresMigrationLabel), true); assert.equal(postgresStatefulSet.spec.template.metadata.labels["hwlab.pikastech.local/source-commit"], undefined); const openfga = JSON.parse(await readFile(path.join(outDir, "runtime-v02", "openfga.yaml"), "utf8")); const openfgaDeployment = openfga.items.find((item) => item.kind === "Deployment" && item.metadata?.name === "hwlab-openfga"); const openfgaService = openfga.items.find((item) => item.kind === "Service" && item.metadata?.name === "hwlab-openfga"); const openfgaMigrate = openfga.items.find((item) => item.kind === "Job" && item.metadata?.name === "hwlab-openfga-migrate"); assert.ok(openfgaDeployment, "expected v02 OpenFGA deployment"); assert.ok(openfgaService, "expected v02 OpenFGA ClusterIP service"); assert.ok(openfgaMigrate, "expected v02 OpenFGA migration job"); assert.equal(openfgaService.spec.type, "ClusterIP"); assert.equal(openfga.items.some((item) => item.kind === "Ingress"), false); assert.equal(openfgaDeployment.spec.template.spec.containers[0].image, "127.0.0.1:5000/hwlab/openfga:v1.17.0"); assert.deepEqual(openfgaDeployment.spec.template.spec.containers[0].args, ["run"]); assert.deepEqual(openfgaMigrate.spec.template.spec.containers[0].args, ["migrate"]); const openfgaEnv = openfgaDeployment.spec.template.spec.containers[0].env; assert.ok(openfgaEnv.some((entry) => entry.name === "OPENFGA_DATASTORE_ENGINE" && entry.value === "postgres")); assert.ok(openfgaEnv.some((entry) => entry.name === "OPENFGA_DATASTORE_URI" && entry.valueFrom?.secretKeyRef?.name === "hwlab-v02-openfga" && entry.valueFrom?.secretKeyRef?.key === "datastore-uri")); assert.ok(openfgaEnv.some((entry) => entry.name === "OPENFGA_AUTHN_METHOD" && entry.value === "preshared")); assert.ok(openfgaEnv.some((entry) => entry.name === "OPENFGA_AUTHN_PRESHARED_KEYS" && entry.valueFrom?.secretKeyRef?.name === "hwlab-v02-openfga" && entry.valueFrom?.secretKeyRef?.key === "authn-preshared-key")); assert.ok(openfgaEnv.some((entry) => entry.name === "OPENFGA_PLAYGROUND_ENABLED" && entry.value === "false")); assert.equal(openfgaDeployment.spec.template.spec.containers[0].readinessProbe.httpGet.path, "/healthz"); assert.equal(openfgaDeployment.spec.template.metadata.labels["hwlab.pikastech.local/source-commit"], sourceRevision); await assert.rejects(() => readFile(path.join(outDir, "tekton-v02", "control-plane-reconciler.yaml"), "utf8"), { code: "ENOENT" }); await assert.rejects(() => readFile(path.join(outDir, "tekton-v02", "poller.yaml"), "utf8"), { code: "ENOENT" }); const pipelineRunSample = await readFile(path.join(outDir, "tekton-v02", "pipelinerun.sample.yaml"), "utf8"); assert.match(pipelineRunSample, /"name": "git-read-url"[\s\S]{0,180}gitea-http\.devops-infra\.svc\.cluster\.local:3000\/mirrors\/pikasTech-HWLAB\.git/u); assert.match(pipelineRunSample, /"name": "git-write-url"[\s\S]{0,140}git-mirror-write\.devops-infra\.svc\.cluster\.local/u); assert.match(pipelineRunSample, /"name": "revision"[\s\S]{0,80}"value": "[0-9a-f]{40}"/u); assert.match(pipelineRunSample, /"name": "source-branch"[\s\S]{0,80}"value": "v0\.2"/u); } finally { await rm(outDir, { recursive: true, force: true }); } }); test("v03 render keeps node identity as data instead of generated structure", async () => { const outDir = await mkdtemp(path.join(os.tmpdir(), "hwlab-v03-render-test-")); const scratchDir = path.join(".tmp", `gitops-render-v03-${process.pid}-${Date.now()}`); const staleCatalogPath = path.join(scratchDir, "artifact-catalog.v03.json"); try { const head = spawnSync("git", ["rev-parse", "HEAD"], { cwd: process.cwd(), encoding: "utf8" }); assert.equal(head.status, 0, head.stderr || head.stdout); const sourceRevision = head.stdout.trim(); const staleRevision = "0".repeat(40); await mkdir(scratchDir, { recursive: true }); await writeFile(staleCatalogPath, JSON.stringify({ catalogVersion: "v1", kind: "hwlab-artifact-catalog", environment: "v03", profile: "v03", namespace: "hwlab-v03", commitId: staleRevision.slice(0, 12), artifactState: "ready", services: [{ serviceId: "hwlab-cloud-api", runtimeMode: "env-reuse-git-mirror-checkout", envReuse: true, sourceCommitId: staleRevision, commitId: staleRevision, image: "127.0.0.1:5000/hwlab/hwlab-cloud-api-env:env-stale", imageTag: "env-stale", digest: `sha256:${"1".repeat(64)}`, environmentImage: "127.0.0.1:5000/hwlab/hwlab-cloud-api-env:env-stale", environmentDigest: `sha256:${"1".repeat(64)}`, environmentInputHash: "e".repeat(64), codeInputHash: "c".repeat(64), bootRepo: "git@github.com:pikasTech/HWLAB.git", bootCommit: staleRevision, bootSh: "deploy/runtime/boot/hwlab-cloud-api.sh" }] }, null, 2)); const render = spawnSync(process.execPath, [ "scripts/run-bun.mjs", "scripts/gitops-render.mjs", "--lane", "v03", "--node", "JD01", "--catalog-path", staleCatalogPath, "--image-tag-mode", "full", "--source-branch", "v0.3", "--gitops-branch", "v0.3-gitops", "--out", outDir, "--source-revision", "HEAD" ], { cwd: process.cwd(), encoding: "utf8" }); assert.equal(render.status, 0, render.stderr || render.stdout); const generatedFiles = await collectGeneratedFiles(outDir); const generatedPaths = generatedFiles.map((filePath) => path.relative(outDir, filePath)); assert.ok(generatedPaths.includes("runtime-v03/node-frpc.yaml")); assert.ok(generatedPaths.includes("argocd/application-v03.yaml")); assert.ok(generatedPaths.includes("tekton-v03/pipeline.yaml")); assert.ok(generatedPaths.includes("runtime-v03/external-postgres.yaml")); assert.ok(generatedPaths.includes("runtime-v03/configmaps.yaml")); assert.ok(generatedPaths.includes("runtime-v03/external-secrets.yaml")); const pipeline = await readFile(path.join(outDir, "tekton-v03", "pipeline.yaml"), "utf8"); const pipelineJson = JSON.parse(pipeline); assert.match(pipeline, /--external-service-report-dir \/workspace\/source\/service-results/u); assert.match(pipeline, /--ci-plan-path \/workspace\/source\/affected-services\.json/u); assert.ok(!pipelineJson.spec.tasks.some((task) => task.name === "runtime-ready")); const gitopsPromote = taskByName(pipelineJson, "gitops-promote"); const gitopsPromoteScript = gitopsPromote.taskSpec.steps[0].script; assert.match(gitopsPromoteScript, /if \[ "\$runtime_lane" = "true" \]; then\s+printf 'false' > \/tekton\/results\/runtime-ready-required\s+else\s+printf 'true' > \/tekton\/results\/runtime-ready-required/u); assert.match(gitopsPromoteScript, /delegated-post-flush-closeout/u); assert.ok(!generatedPaths.includes("runtime-v03/postgres.yaml")); for (const relativePath of generatedPaths) { assert.doesNotMatch(relativePath, /g14/i, `legacy node token leaked into generated path ${relativePath}`); } const workloads = await readFile(path.join(outDir, "runtime-v03", "workloads.yaml"), "utf8"); const workloadsJson = JSON.parse(workloads); const configMapsJson = JSON.parse(await readFile(path.join(outDir, "runtime-v03", "configmaps.yaml"), "utf8")); const externalSecretsJson = JSON.parse(await readFile(path.join(outDir, "runtime-v03", "external-secrets.yaml"), "utf8")); const configMapNames = (configMapsJson.items ?? []).map((item) => item.metadata?.name).sort(); assert.deepEqual(configMapNames, ["hwlab-v03-hwpod-preinstalled-specs", "hwlab-v03-project-management-bootstrap"]); const smokeExternalSecret = (externalSecretsJson.items ?? []).find((item) => item.kind === "ExternalSecret" && item.metadata?.name === "hwlab-secret-plane-smoke"); assert.ok(smokeExternalSecret, "expected v03 secret-plane smoke ExternalSecret"); assert.equal(smokeExternalSecret.metadata?.namespace, "hwlab-v03"); assert.equal(smokeExternalSecret.metadata?.labels?.["hwlab.pikastech.local/secret-plane"], "issue-2277"); assert.equal(smokeExternalSecret.metadata?.annotations?.["hwlab.pikastech.local/secret-plane-issue"], "pikasTech/HWLAB#2277"); assert.equal(smokeExternalSecret.spec?.secretStoreRef?.kind, "ClusterSecretStore"); assert.equal(smokeExternalSecret.spec?.secretStoreRef?.name, "hwlab-secret-plane-vault-cluster"); assert.equal(smokeExternalSecret.spec?.target?.name, "hwlab-secret-plane-smoke"); assert.deepEqual(smokeExternalSecret.spec?.data, [{ secretKey: "password", remoteRef: { key: "hwlab-secret-plane/poc", property: "password" } }]); const cloudApi = (workloadsJson.items ?? []).find((item) => item.kind === "Deployment" && item.metadata?.name === "hwlab-cloud-api"); const cloudApiContainer = collectContainersFromItem(cloudApi).find((container) => container.name === "hwlab-cloud-api"); const cloudApiEnv = new Map((cloudApiContainer?.env ?? []).map((entry) => [entry.name, entry.value])); const cloudApiEnvEntries = new Map((cloudApiContainer?.env ?? []).map((entry) => [entry.name, entry])); assert.equal(cloudApi?.spec?.template?.metadata?.labels?.["hwlab.pikastech.local/source-commit"], sourceRevision); assert.equal(cloudApi?.spec?.template?.metadata?.labels?.["hwlab.pikastech.local/artifact-source-commit"], sourceRevision); assert.equal(cloudApi?.spec?.template?.metadata?.annotations?.["hwlab.pikastech.local/source-commit"], sourceRevision); assert.equal(cloudApi?.spec?.template?.metadata?.annotations?.["hwlab.pikastech.local/boot-commit"], sourceRevision); assert.equal(cloudApiEnv.get("HWLAB_COMMIT_ID"), sourceRevision); assert.equal(cloudApiEnv.get("HWLAB_BOOT_COMMIT"), sourceRevision); assert.equal(cloudApiEnv.get("HWLAB_GITOPS_SOURCE_COMMIT"), sourceRevision); assert.equal(cloudApiEnv.get("HWLAB_CODE_AGENT_AGENTRUN_SOURCE_COMMIT"), sourceRevision); assert.equal(cloudApiEnv.get("HWLAB_CLOUD_DB_SSL_MODE"), "require"); assert.equal(cloudApiEnv.get("HWLAB_KAFKA_ENABLED"), "true"); assert.equal(cloudApiEnv.get("HWLAB_KAFKA_AGENTRUN_EVENT_CONSUME_ENABLED"), "true"); assert.equal(cloudApiEnv.get("HWLAB_KAFKA_DIRECT_PUBLISH_ENABLED"), "true"); assert.equal(cloudApiEnv.get("HWLAB_WORKBENCH_LIVE_KAFKA_SSE_ENABLED"), "true"); assert.equal(cloudApiEnv.get("HWLAB_WORKBENCH_KAFKA_REFRESH_REPLAY_ENABLED"), "true"); assert.equal(cloudApiEnv.get("HWLAB_KAFKA_TRANSACTIONAL_PROJECTOR_ENABLED"), "false"); assert.equal(cloudApiEnv.get("HWLAB_KAFKA_PROJECTION_OUTBOX_RELAY_ENABLED"), "false"); assert.equal(cloudApiEnv.get("HWLAB_WORKBENCH_PROJECTION_REALTIME_ENABLED"), "false"); assert.equal(cloudApiEnv.get("HWLAB_WORKBENCH_KAFKA_DEBUG_REPLAY_ENABLED"), "true"); assert.equal(cloudApiEnv.get("HWLAB_KAFKA_BOOTSTRAP_SERVERS"), "platform-infra-kafka-kafka-bootstrap.platform-infra.svc.cluster.local:9092"); assert.equal(cloudApiEnv.get("HWLAB_KAFKA_STDIO_TOPIC"), "codex-stdio.raw.v1"); assert.equal(cloudApiEnv.get("HWLAB_KAFKA_AGENTRUN_EVENT_TOPIC"), "agentrun.event.v1"); assert.equal(cloudApiEnv.get("HWLAB_KAFKA_EVENT_TOPIC"), "hwlab.event.v1"); assert.equal(cloudApiEnv.get("HWLAB_KAFKA_CLIENT_ID"), "hwlab-v03-cloud-api"); assert.equal(cloudApiEnv.get("HWLAB_KAFKA_AGENTRUN_EVENT_GROUP_ID"), "hwlab-v03-agentrun-event-direct-publish"); assert.equal(cloudApiEnv.get("HWLAB_KAFKA_PROJECTOR_GROUP_ID"), "hwlab-v03-agentrun-event-projector"); assert.equal(cloudApiEnv.get("HWLAB_KAFKA_HWLAB_EVENT_GROUP_ID"), "hwlab-v03-workbench-live-sse"); assert.equal(cloudApiEnv.get("HWLAB_KAFKA_HWLAB_DEBUG_EVENT_TOPIC"), "hwlab.event.debug.v1"); assert.equal(cloudApiEnv.get("HWLAB_KAFKA_HWLAB_DEBUG_GROUP_PREFIX"), "hwlab-v03-workbench-isolated-debug"); assert.equal(cloudApiEnv.get("HWLAB_WORKBENCH_KAFKA_DEBUG_REPLAY_LIMIT"), "200"); assert.equal(cloudApiEnv.get("HWLAB_WORKBENCH_KAFKA_DEBUG_REPLAY_TIMEOUT_MS"), "15000"); assert.equal(cloudApiEnv.has("HWLAB_SESSION_COOKIE_DOMAIN"), false); const cloudWeb = (workloadsJson.items ?? []).find((item) => item.kind === "Deployment" && item.metadata?.name === "hwlab-cloud-web"); const cloudWebContainer = collectContainersFromItem(cloudWeb).find((container) => container.name === "hwlab-cloud-web"); const cloudWebEnv = new Map((cloudWebContainer?.env ?? []).map((entry) => [entry.name, entry.value])); assert.equal(cloudWebEnv.get("HWLAB_WORKBENCH_LIVE_KAFKA_SSE_ENABLED"), "true"); assert.equal(cloudWebEnv.get("HWLAB_WORKBENCH_KAFKA_REFRESH_REPLAY_ENABLED"), "true"); assert.equal(cloudWebEnv.get("HWLAB_WORKBENCH_PROJECTION_REALTIME_ENABLED"), "false"); assert.equal(cloudWebEnv.get("HWLAB_WORKBENCH_KAFKA_DEBUG_REPLAY_ENABLED"), "true"); assert.equal(cloudWebEnv.get("HWLAB_WORKBENCH_RAW_HWLAB_EVENT_WINDOW_ENABLED"), "1"); assert.equal(cloudWebEnv.get("HWLAB_WORKBENCH_RAW_HWLAB_EVENT_WINDOW_MAX_ENTRIES"), "200"); assert.equal(cloudWebEnv.get("HWLAB_WORKBENCH_RAW_HWLAB_EVENT_WINDOW_MAX_RETAINED_BYTES"), "1048576"); assert.match(cloudApiEnv.get("HWLAB_ENVIRONMENT_IMAGE") ?? "", /hwlab-cloud-api-env:env-stale/u); assert.deepEqual(cloudApiEnvEntries.get("HWLAB_SECRET_PLANE_SMOKE")?.valueFrom?.secretKeyRef, { name: "hwlab-secret-plane-smoke", key: "password", optional: true }); assert.ok((cloudApi?.spec?.template?.spec?.volumes ?? []).some((volume) => volume.name === "hwpod-preinstalled-specs" && volume.configMap?.name === "hwlab-v03-hwpod-preinstalled-specs")); assert.ok((cloudApiContainer?.volumeMounts ?? []).some((mount) => mount.name === "hwpod-preinstalled-specs" && mount.mountPath === "/etc/hwlab/hwpod-specs")); assert.ok((cloudApiContainer?.env ?? []).some((entry) => entry.name === "HWLAB_HWPOD_SPEC_REGISTRY_DIRS" && entry.value === "/etc/hwlab/hwpod-specs")); const projectManagement = (workloadsJson.items ?? []).find((item) => item.kind === "Deployment" && item.metadata?.name === "hwlab-project-management"); const projectManagementContainer = collectContainersFromItem(projectManagement).find((container) => container.name === "hwlab-project-management"); assert.ok((projectManagement?.spec?.template?.spec?.volumes ?? []).some((volume) => volume.name === "project-management-bootstrap" && volume.configMap?.name === "hwlab-v03-project-management-bootstrap")); assert.ok((projectManagementContainer?.volumeMounts ?? []).some((mount) => mount.name === "project-management-bootstrap" && mount.mountPath === "/etc/hwlab/project-management")); assert.ok((projectManagementContainer?.env ?? []).some((entry) => entry.name === "HWLAB_PROJECT_MANAGEMENT_BOOTSTRAP_SOURCES_PATH" && entry.value === "/etc/hwlab/project-management/sources.json")); const externalPostgres = JSON.parse(await readFile(path.join(outDir, "runtime-v03", "external-postgres.yaml"), "utf8")); assert.deepEqual((externalPostgres.items ?? []).map((item) => item.kind), ["Service", "EndpointSlice"]); const externalPostgresSlice = (externalPostgres.items ?? []).find((item) => item.kind === "EndpointSlice"); assert.equal(externalPostgresSlice?.metadata?.name, "jd01-pk01-platform-postgres-host"); assert.equal(externalPostgresSlice?.metadata?.labels?.["kubernetes.io/service-name"], "jd01-pk01-platform-postgres"); const deepseekProxy = await readFile(path.join(outDir, "runtime-v03", "deepseek-proxy.yaml"), "utf8"); const deepseekProxyJson = JSON.parse(deepseekProxy); const metricsSidecarConfigMaps = [...(workloadsJson.items ?? []), ...(deepseekProxyJson.items ?? [])] .filter((item) => item.kind === "Deployment") .flatMap((item) => item.spec?.template?.spec?.volumes ?? []) .filter((volume) => volume.name === "hwlab-metrics-sidecar") .map((volume) => volume.configMap?.name); assert.ok(metricsSidecarConfigMaps.length >= 5, "expected v03 observable workloads to mount metrics sidecar config"); assert.deepEqual([...new Set(metricsSidecarConfigMaps)], ["hwlab-v03-metrics-sidecar"]); assert.doesNotMatch(`${workloads}\n${deepseekProxy}`, /hwlab-v02-metrics-sidecar/u); const agentRunNodeEnv = (workloadsJson.items ?? []) .flatMap((item) => collectContainersFromItem(item)) .flatMap((container) => container.env ?? []) .filter((entry) => entry.name === "HWLAB_CODE_AGENT_AGENTRUN_PROVIDER_ID"); assert.ok(agentRunNodeEnv.length > 0, "expected AgentRun provider id env to carry configured node id"); assert.deepEqual([...new Set(agentRunNodeEnv.map((entry) => entry.value))], ["JD01"]); } finally { await rm(outDir, { recursive: true, force: true }); await rm(scratchDir, { recursive: true, force: true }); } }); test("v03 render includes JD01 secret-plane smoke on JD01 gitops root", { timeout: 20000 }, async () => { const outDir = await mkdtemp(path.join(os.tmpdir(), "hwlab-v03-jd01-render-test-")); const scratchDir = path.join(".tmp", `gitops-render-v03-jd01-${process.pid}-${Date.now()}`); const staleCatalogPath = path.join(scratchDir, "artifact-catalog.v03.json"); try { const staleRevision = "0".repeat(40); await mkdir(scratchDir, { recursive: true }); await writeFile(staleCatalogPath, JSON.stringify({ catalogVersion: "v1", kind: "hwlab-artifact-catalog", environment: "v03", profile: "v03", namespace: "hwlab-v03", commitId: staleRevision.slice(0, 12), artifactState: "ready", services: [{ serviceId: "hwlab-cloud-api", runtimeMode: "env-reuse-git-mirror-checkout", envReuse: true, sourceCommitId: staleRevision, commitId: staleRevision, image: "127.0.0.1:5000/hwlab/hwlab-cloud-api-env:env-stale", imageTag: "env-stale", digest: `sha256:${"1".repeat(64)}`, environmentImage: "127.0.0.1:5000/hwlab/hwlab-cloud-api-env:env-stale", environmentDigest: `sha256:${"1".repeat(64)}`, environmentInputHash: "e".repeat(64), codeInputHash: "c".repeat(64), bootRepo: "git@github.com:pikasTech/HWLAB.git", bootCommit: staleRevision, bootSh: "deploy/runtime/boot/hwlab-cloud-api.sh" }] }, null, 2)); const render = spawnSync(process.execPath, [ "scripts/run-bun.mjs", "scripts/gitops-render.mjs", "--lane", "v03", "--catalog-path", staleCatalogPath, "--image-tag-mode", "full", "--source-branch", "v0.3", "--gitops-branch", "v0.3-gitops", "--gitops-root", "deploy/gitops/node/jd01", "--out", outDir, "--source-revision", "HEAD" ], { cwd: process.cwd(), encoding: "utf8" }); assert.equal(render.status, 0, render.stderr || render.stdout); const generatedFiles = await collectGeneratedFiles(outDir); const generatedPaths = generatedFiles.map((filePath) => path.relative(outDir, filePath)); assert.ok(generatedPaths.includes("runtime-v03/kustomization.yaml")); assert.ok(generatedPaths.includes("runtime-v03/workloads.yaml")); assert.ok(generatedPaths.includes("runtime-v03/opencode.yaml")); assert.equal(generatedPaths.includes("runtime-v03/external-secrets.yaml"), true); const kustomization = await readFile(path.join(outDir, "runtime-v03", "kustomization.yaml"), "utf8"); assert.match(kustomization, /external-secrets\.yaml/u); const externalSecretsJson = JSON.parse(await readFile(path.join(outDir, "runtime-v03", "external-secrets.yaml"), "utf8")); const smokeExternalSecret = (externalSecretsJson.items ?? []).find((item) => item.kind === "ExternalSecret" && item.metadata?.name === "hwlab-secret-plane-smoke"); assert.ok(smokeExternalSecret, "expected JD01 v03 secret-plane smoke ExternalSecret"); assert.equal(smokeExternalSecret.metadata?.namespace, "hwlab-v03"); assert.equal(smokeExternalSecret.metadata?.labels?.["hwlab.pikastech.local/secret-plane"], "issue-2277"); assert.equal(smokeExternalSecret.metadata?.annotations?.["hwlab.pikastech.local/secret-plane-issue"], "pikasTech/HWLAB#2277"); assert.equal(smokeExternalSecret.spec?.secretStoreRef?.kind, "ClusterSecretStore"); assert.equal(smokeExternalSecret.spec?.secretStoreRef?.name, "hwlab-secret-plane-vault-cluster"); assert.equal(smokeExternalSecret.spec?.target?.name, "hwlab-secret-plane-smoke"); assert.deepEqual(smokeExternalSecret.spec?.data, [{ secretKey: "password", remoteRef: { key: "hwlab-secret-plane/poc", property: "password" } }]); const workloadsJson = JSON.parse(await readFile(path.join(outDir, "runtime-v03", "workloads.yaml"), "utf8")); const cloudApi = (workloadsJson.items ?? []).find((item) => item.kind === "Deployment" && item.metadata?.name === "hwlab-cloud-api"); const cloudApiContainer = collectContainersFromItem(cloudApi).find((container) => container.name === "hwlab-cloud-api"); const cloudApiEnvEntries = new Map((cloudApiContainer?.env ?? []).map((entry) => [entry.name, entry])); assert.deepEqual(cloudApiEnvEntries.get("HWLAB_SECRET_PLANE_SMOKE")?.valueFrom?.secretKeyRef, { name: "hwlab-secret-plane-smoke", key: "password", optional: true }); const cloudWeb = (workloadsJson.items ?? []).find((item) => item.kind === "Deployment" && item.metadata?.name === "hwlab-cloud-web"); const cloudWebContainer = collectContainersFromItem(cloudWeb).find((container) => container.name === "hwlab-cloud-web"); const cloudWebEnvEntries = new Map((cloudWebContainer?.env ?? []).map((entry) => [entry.name, entry])); assert.equal(cloudWebEnvEntries.get("HWLAB_CLOUD_WEB_OPENCODE_DEFAULT_PROJECT")?.value, "/workspace"); const agentRunNodeEnv = (workloadsJson.items ?? []) .flatMap((item) => collectContainersFromItem(item)) .flatMap((container) => container.env ?? []) .filter((entry) => entry.name === "HWLAB_CODE_AGENT_AGENTRUN_PROVIDER_ID"); assert.ok(agentRunNodeEnv.length > 0, "expected JD01 node id to be inferred from gitops root"); assert.deepEqual([...new Set(agentRunNodeEnv.map((entry) => entry.value))], ["JD01"]); const opencode = JSON.parse(await readFile(path.join(outDir, "runtime-v03", "opencode.yaml"), "utf8")); const opencodeDeployment = (opencode.items ?? []).find((item) => item.kind === "Deployment" && item.metadata?.name === "opencode-server"); assert.ok(opencodeDeployment, "expected opencode-server deployment"); assert.equal(opencodeDeployment.metadata?.annotations?.["hwlab.pikastech.local/opencode-provider-profile"], "gpt.pika"); assert.equal(opencodeDeployment.metadata?.annotations?.["hwlab.pikastech.local/agentrun-provider-secret-ref"], "agentrun-v02/agentrun-v01-provider-gpt-pika"); assert.equal(opencodeDeployment.metadata?.annotations?.["hwlab.pikastech.local/opencode-provider-base-url"], "http://127.0.0.1:4097/v1"); assert.equal(opencodeDeployment.metadata?.annotations?.["hwlab.pikastech.local/opencode-provider-upstream-base-url"], "https://api.pikapython.com/"); assert.equal(opencodeDeployment.metadata?.annotations?.["hwlab.pikastech.local/opencode-image"], "127.0.0.1:5000/hwlab/opencode:1.17.7-git"); assert.equal(opencodeDeployment.metadata?.annotations?.["hwlab.pikastech.local/opencode-provider-proxy-boot-sh"], "deploy/runtime/boot/opencode-provider-proxy.sh"); assert.equal(opencodeDeployment.metadata?.annotations?.["hwlab.pikastech.local/values-printed"], "false"); assert.match(opencodeDeployment.spec?.template?.metadata?.annotations?.["hwlab.pikastech.local/opencode-config-sha256"] ?? "", /^[a-f0-9]{64}$/u); const opencodeGitInit = opencodeDeployment.spec?.template?.spec?.initContainers?.find((container) => container.name === "opencode-workspace-git-init"); assert.ok(opencodeGitInit, "expected opencode workspace git init container"); assert.deepEqual(opencodeGitInit.command, ["/bin/sh", "-ec"]); assert.match(opencodeGitInit.args?.[0] ?? "", /git -C \/workspace init/u); assert.ok(opencodeGitInit.volumeMounts?.some((entry) => entry.name === "workspace" && entry.mountPath === "/workspace")); const opencodeContainer = collectContainersFromItem(opencodeDeployment).find((container) => container.name === "opencode-server"); assert.equal(opencodeContainer?.image, "127.0.0.1:5000/hwlab/opencode:1.17.7-git"); assert.deepEqual(opencodeContainer?.command, ["/bin/sh", "-ec"]); assert.equal(opencodeContainer?.args?.[0], "exec opencode serve --hostname 0.0.0.0 --port 4096"); assert.doesNotMatch(opencodeContainer?.args?.[0] ?? "", /apk add|dl-cdn\.alpinelinux\.org/u, "opencode startup must not depend on runtime apk repository access"); const opencodeEnvEntries = new Map((opencodeContainer?.env ?? []).map((entry) => [entry.name, entry])); assert.equal(opencodeEnvEntries.get("HTTPS_PROXY")?.value, "http://sub2api-egress-proxy.platform-infra.svc.cluster.local:10808"); assert.match(opencodeEnvEntries.get("NO_PROXY")?.value ?? "", /\.svc\.cluster\.local/u); assert.deepEqual(opencodeEnvEntries.get("OPENCODE_GPT_PIKA_API_KEY")?.valueFrom?.secretKeyRef, { name: "hwlab-v03-code-agent-provider", key: "opencode-api-key", optional: true }); const opencodeConfig = JSON.parse(opencodeEnvEntries.get("OPENCODE_CONFIG_CONTENT")?.value ?? "{}"); assert.equal(opencodeConfig.model, "gpt.pika/gpt-5.4-mini"); assert.equal(opencodeConfig.small_model, "gpt.pika/gpt-5.4-mini"); assert.equal(opencodeConfig.provider["gpt.pika"].npm, "@ai-sdk/openai-compatible"); assert.equal(opencodeConfig.provider["gpt.pika"].options.baseURL, "http://127.0.0.1:4097/v1"); assert.equal(opencodeConfig.provider["gpt.pika"].options.apiKey, "{env:OPENCODE_GPT_PIKA_API_KEY}"); assert.equal(opencodeConfig.provider["gpt.pika"].models["gpt-5.4-mini"].reasoning, false); assert.equal(opencodeConfig.provider["gpt.pika"].models["gpt-5.4-mini"].tool_call, true); assert.deepEqual(opencodeConfig.provider["gpt.pika"].models["gpt-5.4-mini"].limit, { context: 1000000, output: 384000 }); const providerProxy = collectContainersFromItem(opencodeDeployment).find((container) => container.name === "opencode-provider-proxy"); assert.ok(providerProxy, "expected provider proxy sidecar"); assert.equal(providerProxy.command, undefined); const providerProxyEnv = new Map((providerProxy.env ?? []).map((entry) => [entry.name, entry.value])); assert.equal(providerProxyEnv.get("HWLAB_BOOT_SH"), "deploy/runtime/boot/opencode-provider-proxy.sh"); assert.equal(providerProxyEnv.get("HWLAB_BOOT_REF"), "v0.3"); assert.match(providerProxyEnv.get("HWLAB_BOOT_READ_URL") ?? "", /pikasTech[-/]HWLAB/u); assert.equal(providerProxyEnv.get("HWLAB_OPENCODE_PROVIDER_PROXY_UPSTREAM_BASE_URL"), "https://api.pikapython.com/"); assert.equal(providerProxyEnv.get("HWLAB_OPENCODE_PROVIDER_PROXY_PUBLIC_BASE_PATH"), "/v1"); assert.equal(providerProxyEnv.get("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT"), "http://otel-collector.platform-infra.svc.cluster.local:4318/v1/traces"); assert.equal(providerProxyEnv.get("OTEL_SERVICE_NAME"), "opencode-provider-proxy"); } finally { await rm(outDir, { recursive: true, force: true }); await rm(scratchDir, { recursive: true, force: true }); } });