#!/usr/bin/env node // SPEC: PJ2026-01060505 Workbench Performance; PJ2026-0106 平台运维 import assert from "node:assert/strict"; import { execFile } from "node:child_process"; import { createHash } from "node:crypto"; import { mkdir, readFile, rm, writeFile } from "node:fs/promises"; import path from "node:path"; import { promisify } from "node:util"; import { fileURLToPath } from "node:url"; import { applyRuntimeLaneDeployConfig, defaultEndpointForRuntimeLane, defaultPortForRuntimeLane, isRuntimeLane, runtimeLaneMirrorSpecs, runtimeLaneConfig, versionNameForRuntimeLane } from "../runtime-lane.ts"; import { readStructuredFile } from "../structured-config.mjs"; const execFileAsync = promisify(execFile); const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../.."); const defaultOutDir = "deploy/gitops/node"; const defaultRegistryPrefix = process.env.HWLAB_NODE_REGISTRY_PREFIX || "127.0.0.1:5000/hwlab"; const defaultSourceRepo = process.env.HWLAB_NODE_GIT_URL || "git@github.com:pikasTech/HWLAB.git"; const defaultGitReadUrl = process.env.HWLAB_NODE_GIT_READ_URL || null; const defaultV02GitReadUrl = process.env.HWLAB_V02_GIT_READ_URL || "http://git-mirror-http.devops-infra.svc.cluster.local/pikasTech/HWLAB.git"; const defaultV02GitWriteUrl = process.env.HWLAB_V02_GIT_WRITE_URL || "http://git-mirror-write.devops-infra.svc.cluster.local/pikasTech/HWLAB.git"; const defaultRuntimeLaneGitReadUrl = process.env.HWLAB_RUNTIME_LANE_GIT_READ_URL || "http://gitea-http.devops-infra.svc.cluster.local:3000/mirrors/pikasTech-HWLAB.git"; const defaultRuntimeLaneGitWriteUrl = process.env.HWLAB_RUNTIME_LANE_GIT_WRITE_URL || defaultV02GitWriteUrl; const defaultBranch = process.env.HWLAB_NODE_BRANCH || "node"; const defaultGitopsBranch = process.env.HWLAB_NODE_GITOPS_BRANCH || "node-gitops"; const defaultCatalogPath = process.env.HWLAB_ARTIFACT_CATALOG_PATH || "deploy/artifact-catalog.dev.json"; const defaultRuntimeEndpoint = process.env.HWLAB_NODE_RUNTIME_ENDPOINT || "http://74.48.78.17:17667"; const defaultWebEndpoint = process.env.HWLAB_NODE_WEB_ENDPOINT || "http://74.48.78.17:17666"; const defaultProdRuntimeEndpoint = process.env.HWLAB_NODE_PROD_RUNTIME_ENDPOINT || "http://74.48.78.17:18667"; const defaultProdWebEndpoint = process.env.HWLAB_NODE_PROD_WEB_ENDPOINT || "http://74.48.78.17:18666"; const defaultV02RuntimeEndpoint = process.env.HWLAB_V02_RUNTIME_ENDPOINT || "https://hwlab.74-48-78-17.nip.io"; const defaultV02WebEndpoint = process.env.HWLAB_V02_WEB_ENDPOINT || "https://hwlab.74-48-78-17.nip.io"; const defaultProxyUrl = process.env.HWLAB_NODE_PROXY_URL || "http://127.0.0.1:10808"; const defaultAllProxyUrl = process.env.HWLAB_NODE_ALL_PROXY_URL || "socks5h://127.0.0.1:10808"; const defaultNoProxy = process.env.HWLAB_NODE_NO_PROXY || "hyueapi.com,.hyueapi.com,127.0.0.1,localhost,::1,10.0.0.0/8,10.42.0.0/16,10.43.0.0/16,192.168.0.0/16,.svc,.cluster.local,kubernetes.default.svc,registry.hwlab-ci.svc,hwlab-registry.hwlab-ci.svc,git-mirror-http,git-mirror-http.devops-infra,git-mirror-http.devops-infra.svc,git-mirror-http.devops-infra.svc.cluster.local,git-mirror-write,git-mirror-write.devops-infra,git-mirror-write.devops-infra.svc,git-mirror-write.devops-infra.svc.cluster.local"; const ciToolsRunnerImage = process.env.HWLAB_NODE_CI_TOOLS_IMAGE || "127.0.0.1:5000/hwlab/hwlab-ci-node-tools:node22-alpine-bun-v1"; const buildkitRunnerImage = process.env.HWLAB_NODE_BUILDKIT_IMAGE || "moby/buildkit:rootless"; const defaultDevBaseImage = process.env.HWLAB_NODE_DEV_BASE_IMAGE || "127.0.0.1:5000/hwlab/hwlab-node20-base:20-bookworm-slim"; const defaultServiceIds = Object.freeze([ "hwlab-cloud-api", "hwlab-cloud-web", "hwlab-gateway", "hwlab-edge-proxy", "hwlab-agent-skills" ]); const v02ExtraObservableServices = Object.freeze([ { serviceId: "hwlab-deepseek-proxy", port: 4000, healthPath: "/health/live" } ]); const v02RemovedServiceIds = new Set([ "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" ]); const v02RemovedServiceEnvNames = new Set([ "CODEX_HOME", "OPENAI_API_KEY", "HWLAB_CODE_AGENT_PROVIDER", "HWLAB_CODE_AGENT_MODEL", "HWLAB_CODE_AGENT_OPENAI_BASE_URL", "HWLAB_CODE_AGENT_WORKSPACE", "HWLAB_CODE_AGENT_CODEX_HOME", "HWLAB_CODE_AGENT_CODEX_WORKSPACE", "HWLAB_CODE_AGENT_CODEX_SANDBOX", "HWLAB_CODE_AGENT_CODEX_COMMAND", "HWLAB_CODE_AGENT_CODEX_STDIO_ENABLED", "HWLAB_CODE_AGENT_CODEX_STDIO_SUPERVISOR", "HWLAB_M3_GATEWAY_SIMU_1_URL", "HWLAB_M3_GATEWAY_SIMU_2_URL", "HWLAB_M3_PATCH_PANEL_URL", "HWLAB_GATEWAY_SIMU_URL", "HWLAB_BOX_SIMU_URL", "HWLAB_PATCH_PANEL_URL", "HWLAB_ROUTER_URL", "HWLAB_TUNNEL_CLIENT_URL" ]); const moonBridgeSourceRef = process.env.HWLAB_NODE_MOONBRIDGE_REF || "1b99888d3dae889b79ee602cb875c7907f7e76f2"; const moonBridgeImage = process.env.HWLAB_NODE_MOONBRIDGE_IMAGE || `${defaultRegistryPrefix}/moonbridge:${moonBridgeSourceRef.slice(0, 12)}`; const deepSeekProfileModel = process.env.HWLAB_NODE_DEEPSEEK_PROFILE_MODEL || "deepseek-chat"; const codexApiProfileModel = process.env.HWLAB_NODE_CODEX_API_PROFILE_MODEL || "gpt-5.5"; const codexApiProfileBaseUrl = process.env.HWLAB_NODE_CODEX_API_PROFILE_BASE_URL || "http://127.0.0.1:49280/responses"; const codexApiForwarderPort = process.env.HWLAB_NODE_CODEX_API_FORWARDER_PORT || "49280"; const codexApiForwarderUpstreamBaseUrl = process.env.HWLAB_NODE_CODEX_API_UPSTREAM_BASE_URL || "https://hyueapi.com"; const sourceCommitPattern = /^[a-f0-9]{7,40}$/u; const v02EnvReuseRuntimeMode = "env-reuse-git-mirror-checkout"; function k8sLabelHash(value) { return String(value || "").slice(0, 16); } const primitiveValidationTasks = Object.freeze([ { name: "repo-reports-guard", commands: ["node scripts/repo-reports-guard.mjs"] }, { name: "node-contract-check", commands: [ "node --check scripts/gitops-render.mjs", `node --input-type=module <<'NODE' import { readdirSync, readFileSync, statSync } from "node:fs"; import path from "node:path"; const root = process.cwd(); const ciFileName = "CI" + ".json"; const forbiddenCiFragments = [ "ci" + "-json", "HWLAB_NODE_TEKTON" + "_SINGLE_IMAGE_PUBLISH", "single" + "-dind", "docker" + ":29", "DOCKER" + "_HOST", "Docker" + "-in-Docker", "D" + "IND", "docker" + " push", "--build" + "-backend", "HWLAB_ARTIFACT" + "_BUILD_BACKEND", "--legacy" + "-source-images", "HWLAB_NODE_USE_DEPLOY_IMAGES" + "=0" ]; const scanTargets = [ "scripts/gitops-render.mjs", "scripts/src/runtime-lane.ts", "scripts/artifact-publish.mjs", "scripts/src/ci-plan-lib.mjs", "deploy/gitops/node/tekton" ]; const skipDirs = new Set([".git", "node_modules", ".worktree"]); function walkFiles(relativePath) { const absolutePath = path.join(root, relativePath); let stat; try { stat = statSync(absolutePath); } catch { return []; } if (stat.isFile()) return [relativePath]; if (!stat.isDirectory()) return []; const files = []; for (const entry of readdirSync(absolutePath, { withFileTypes: true })) { if (entry.isDirectory() && skipDirs.has(entry.name)) continue; files.push(...walkFiles(path.join(relativePath, entry.name))); } return files; } const ciFiles = walkFiles(".").filter((filePath) => path.basename(filePath) === ciFileName); const violations = []; for (const filePath of scanTargets.flatMap(walkFiles)) { const text = readFileSync(path.join(root, filePath), "utf8"); for (const fragment of forbiddenCiFragments) { if (text.includes(fragment)) violations.push({ filePath, fragment }); } } if (ciFiles.length || violations.length) { console.error(JSON.stringify({ status: "failed", ciFiles, violations }, null, 2)); process.exit(1); } NODE`, "node --check scripts/artifact-publish.mjs" ] }, { name: "codex-api-forwarder-check", commands: [ "node scripts/run-bun.mjs test cmd/hwlab-codex-api-responses-forwarder/main.test.ts" ] } ]); function proxyEnv() { return [ { name: "HTTP_PROXY", value: defaultProxyUrl }, { name: "HTTPS_PROXY", value: defaultProxyUrl }, { name: "ALL_PROXY", value: defaultAllProxyUrl }, { name: "NO_PROXY", value: defaultNoProxy }, { name: "http_proxy", value: defaultProxyUrl }, { name: "https_proxy", value: defaultProxyUrl }, { name: "all_proxy", value: defaultAllProxyUrl }, { name: "no_proxy", value: defaultNoProxy } ]; } function parseArgs(argv) { const args = { lane: process.env.HWLAB_GITOPS_LANE || "node", nodeId: process.env.HWLAB_NODE_ID || "node", outDir: defaultOutDir, gitopsRoot: defaultOutDir, catalogPath: defaultCatalogPath, imageTagMode: process.env.HWLAB_ARTIFACT_IMAGE_TAG_MODE || "short", registryPrefix: defaultRegistryPrefix, sourceRevision: null, sourceBranch: defaultBranch, gitopsBranch: defaultGitopsBranch, sourceRepo: defaultSourceRepo, gitReadUrl: defaultGitReadUrl, gitWriteUrl: null, runtimeEndpoint: defaultRuntimeEndpoint, webEndpoint: defaultWebEndpoint, prodRuntimeEndpoint: defaultProdRuntimeEndpoint, prodWebEndpoint: defaultProdWebEndpoint, useDeployImages: true, check: false, write: true, help: false }; for (let index = 0; index < argv.length; index += 1) { const arg = argv[index]; if (arg === "--lane") args.lane = readOption(argv, ++index, arg); else if (arg === "--node") args.nodeId = readOption(argv, ++index, arg); else if (arg === "--out") args.outDir = readOption(argv, ++index, arg); else if (arg === "--gitops-root") args.gitopsRoot = readOption(argv, ++index, arg); else if (arg === "--catalog-path") args.catalogPath = readOption(argv, ++index, arg); else if (arg === "--image-tag-mode") args.imageTagMode = readOption(argv, ++index, arg); else if (arg === "--registry-prefix") args.registryPrefix = readOption(argv, ++index, arg).replace(/\/+$/u, ""); else if (arg === "--source-revision") args.sourceRevision = readOption(argv, ++index, arg); else if (arg === "--source-branch") args.sourceBranch = readOption(argv, ++index, arg); else if (arg === "--gitops-branch") args.gitopsBranch = readOption(argv, ++index, arg); else if (arg === "--source-repo") args.sourceRepo = readOption(argv, ++index, arg); else if (arg === "--git-read-url") args.gitReadUrl = readOption(argv, ++index, arg); else if (arg === "--git-write-url") args.gitWriteUrl = readOption(argv, ++index, arg); else if (arg === "--runtime-endpoint") args.runtimeEndpoint = readOption(argv, ++index, arg); else if (arg === "--web-endpoint") args.webEndpoint = readOption(argv, ++index, arg); else if (arg === "--prod-runtime-endpoint") args.prodRuntimeEndpoint = readOption(argv, ++index, arg); else if (arg === "--prod-web-endpoint") args.prodWebEndpoint = readOption(argv, ++index, arg); else if (arg === "--use-deploy-images") args.useDeployImages = true; else if (arg === "--check") { args.check = true; args.write = false; } else if (arg === "--no-write") args.write = false; else if (arg === "--help" || arg === "-h") args.help = true; else throw new Error(`unknown argument ${arg}`); } if (isRuntimeLane(args.lane)) { const versionName = versionNameForRuntimeLane(args.lane); const defaultLaneEndpoint = defaultEndpointForRuntimeLane(args.lane); if (args.sourceBranch === defaultBranch) args.sourceBranch = versionName; if (args.gitopsBranch === defaultGitopsBranch) args.gitopsBranch = `${versionName}-gitops`; if (args.catalogPath === defaultCatalogPath) args.catalogPath = `deploy/artifact-catalog.${args.lane}.json`; if (args.runtimeEndpoint === defaultRuntimeEndpoint) args.runtimeEndpoint = defaultLaneEndpoint; if (args.webEndpoint === defaultWebEndpoint) args.webEndpoint = defaultLaneEndpoint; if (args.imageTagMode === "short") args.imageTagMode = "full"; if (!args.gitReadUrl) args.gitReadUrl = defaultRuntimeLaneGitReadUrl; if (!args.gitWriteUrl) args.gitWriteUrl = defaultRuntimeLaneGitWriteUrl; } if (!args.gitReadUrl) args.gitReadUrl = args.sourceRepo; if (!args.gitWriteUrl) args.gitWriteUrl = args.sourceRepo; assert.ok(args.lane === "node" || isRuntimeLane(args.lane), `unknown lane ${args.lane}`); assert.ok(["short", "full"].includes(args.imageTagMode), `unknown image tag mode ${args.imageTagMode}`); if (isRuntimeLane(args.lane)) { const versionName = versionNameForRuntimeLane(args.lane); assert.equal(args.sourceBranch, versionName, `${args.lane} source branch must be ${versionName}`); assert.equal(args.gitopsBranch, `${versionName}-gitops`, `${args.lane} GitOps branch must be ${versionName}-gitops`); } return args; } function readOption(argv, index, name) { const value = argv[index]; if (!value || value.startsWith("--")) throw new Error(`${name} requires a value`); return value; } function usage() { return [ "usage: node scripts/run-bun.mjs scripts/gitops-render.mjs [options]", "", "Render node-scoped Kubernetes-native CI/CD manifests from built-in Tekton CI primitives, deploy/deploy.yaml, and deploy/k8s/*.", "", "options:", " --lane LANE node or runtime lane such as v02/v03/v04; default: node", ` --node NODE deployment node id from deploy.nodes; runtime lanes default from deploy.lanes..node`, ` --out DIR default: ${defaultOutDir}`, ` --gitops-root DIR path inside GitOps repo; default comes from deploy.nodes..gitopsRoot`, ` --catalog-path PATH default: ${defaultCatalogPath}`, " --image-tag-mode MODE short or full; v02 uses full source commit IDs", ` --source-repo URL default: ${defaultSourceRepo}`, " --git-read-url URL read-only source URL; runtime lanes default to devops-infra git mirror", " --git-write-url URL GitOps write URL; runtime lanes default to devops-infra git mirror write relay", ` --source-branch BRANCH default: ${defaultBranch}`, ` --gitops-branch BRANCH default: ${defaultGitopsBranch}`, " --source-revision SHA source commit used for image tags and runtime annotations; default: git rev-parse HEAD", ` --registry-prefix PREFIX default: ${defaultRegistryPrefix}`, ` --runtime-endpoint URL default: ${defaultRuntimeEndpoint}; runtime lane default is derived from deploy.yaml/public URL`, ` --web-endpoint URL default: ${defaultWebEndpoint}; runtime lane default is derived from deploy.yaml/public URL`, ` --prod-runtime-endpoint URL default: ${defaultProdRuntimeEndpoint}`, ` --prod-web-endpoint URL default: ${defaultProdWebEndpoint}`, " --use-deploy-images default and only supported mode: render workload images from deploy/artifact-catalog.dev.json per service", " --check verify generated files are current without writing", " --no-write plan and print generated file list without writing" ].join("\n"); } function generatedPath(filePath) { return path.isAbsolute(filePath) ? filePath : path.join(repoRoot, filePath); } async function readJson(relativePath) { return readStructuredFile(repoRoot, relativePath); } async function readJsonIfPresent(relativePath, fallback = null) { try { return await readJson(relativePath); } catch (error) { if (error && error.code === "ENOENT") return fallback; throw error; } } async function attachAccessControlEnv(deploy) { const byProfile = {}; for (const [profile, laneConfig] of Object.entries(deploy?.lanes ?? {})) { if (!isRuntimeLane(profile)) continue; const accessControl = laneConfig?.accessControl; if (!accessControl || typeof accessControl !== "object" || Array.isArray(accessControl)) continue; const users = await readConfigRef(accessControl.usersRef, `${profile}.accessControl.usersRef`); const navProfiles = await readConfigRef(accessControl.navProfilesRef, `${profile}.accessControl.navProfilesRef`); const env = accessControlEnvFromConfig({ users, navProfiles }); if (Object.keys(env).length > 0) byProfile[profile] = { "hwlab-cloud-api": env }; } Object.defineProperty(deploy, "__accessControlEnvByProfile", { value: byProfile, enumerable: false, configurable: true }); } async function readConfigRef(ref, label) { assert.equal(typeof ref, "string", `${label} must be a file reference`); const [filePath, fragment = ""] = ref.split("#"); assert.ok(filePath, `${label} must include a file path`); const root = await readJson(filePath); return configFragment(root, fragment || "", label); } function configFragment(value, fragment, label) { const pathText = String(fragment ?? "").replace(/^\//u, ""); if (!pathText) return value; return pathText.split(/[./]/u).filter(Boolean).reduce((current, segment) => { assert.ok(current && typeof current === "object" && Object.hasOwn(current, segment), `${label} fragment is missing ${segment}`); return current[segment]; }, value); } function accessControlEnvFromConfig({ users, navProfiles }) { assert.ok(Array.isArray(users), "accessControl usersRef must resolve to an array"); assert.ok(Array.isArray(navProfiles), "accessControl navProfilesRef must resolve to an array"); const env = {}; const renderedUsers = users.map((user, index) => normalizeAccessControlUser(user, index, env)); const renderedProfiles = navProfiles.map(normalizeNavProfile); env.HWLAB_ACCESS_CONTROL_USERS_JSON = JSON.stringify(renderedUsers); env.HWLAB_ACCESS_CONTROL_NAV_PROFILES_JSON = JSON.stringify(renderedProfiles); return env; } function normalizeAccessControlUser(user, index, env) { assert.ok(user && typeof user === "object" && !Array.isArray(user), `accessControl user ${index} must be an object`); const passwordHashRef = user.passwordHashRef && typeof user.passwordHashRef === "object" && !Array.isArray(user.passwordHashRef) ? user.passwordHashRef : null; const passwordHashEnv = configString(user.passwordHashEnv) || configString(passwordHashRef?.env); const secretRef = configString(passwordHashRef?.secretRef) || secretRefFromParts(passwordHashRef); if (passwordHashEnv && secretRef) env[passwordHashEnv] = `secretRef:${secretRef}`; return { id: requiredAccessConfigString(user.id, `accessControl user ${index}.id`), username: requiredAccessConfigString(user.username, `accessControl user ${index}.username`), displayName: configString(user.displayName) || configString(user.username), email: configString(user.email) || null, role: configString(user.role) === "admin" ? "admin" : "user", status: configString(user.status) === "disabled" ? "disabled" : "active", navProfile: requiredAccessConfigString(user.navProfile, `accessControl user ${index}.navProfile`), passwordHashEnv: passwordHashEnv || null }; } function normalizeNavProfile(profile, index) { assert.ok(profile && typeof profile === "object" && !Array.isArray(profile), `accessControl nav profile ${index} must be an object`); const allowedIds = Array.isArray(profile.allowedIds) ? profile.allowedIds.map(configString).filter(Boolean) : []; assert.ok(allowedIds.length > 0, `accessControl nav profile ${index}.allowedIds must not be empty`); return { id: requiredAccessConfigString(profile.id, `accessControl nav profile ${index}.id`), displayName: configString(profile.displayName) || configString(profile.id), allowedIds }; } function secretRefFromParts(value) { if (!value || typeof value !== "object" || Array.isArray(value)) return ""; const sourceRef = configString(value.sourceRef ?? value.secretName); const targetKey = configString(value.targetKey ?? value.key); return sourceRef && targetKey ? `${sourceRef}/${targetKey}` : ""; } function configString(value) { return typeof value === "string" ? value.trim() : ""; } function requiredAccessConfigString(value, label) { const text = configString(value); assert.ok(text, `${label} is required`); return text; } function optionalObject(value) { return value && typeof value === "object" && !Array.isArray(value) ? value : {}; } async function gitValue(args) { const result = await execFileAsync("git", args, { cwd: repoRoot, timeout: 10000, maxBuffer: 1024 * 1024 }); return result.stdout.trim(); } async function resolveSourceRevision(value) { const revision = value || await gitValue(["rev-parse", "HEAD"]); const full = sourceCommitPattern.test(revision) && revision.length === 40 ? revision : await gitValue(["rev-parse", revision]); assert.match(full, /^[a-f0-9]{40}$/u, "source revision must resolve to a 40-char git commit"); return { full, short: full.slice(0, 7) }; } function jsonManifest(value) { return `${JSON.stringify(value, null, 2)}\n`; } function textFile(value) { return value.endsWith("\n") ? value : `${value}\n`; } function cloneJson(value) { return JSON.parse(JSON.stringify(value)); } function ensureObject(value, name) { assert.ok(value && typeof value === "object" && !Array.isArray(value), `${name} must be an object`); return value; } function asItems(list, name) { assert.equal(list?.kind, "List", `${name} must be a Kubernetes List`); assert.ok(Array.isArray(list.items), `${name}.items must be an array`); return list.items; } function serviceIdForWorkload(item, container) { return ( item?.metadata?.labels?.["hwlab.pikastech.local/service-id"] || item?.spec?.template?.metadata?.labels?.["hwlab.pikastech.local/service-id"] || container?.name ); } function upsertEnv(envList, name, value) { if (!Array.isArray(envList)) return; const existing = envList.find((entry) => entry?.name === name); if (existing) { delete existing.valueFrom; existing.value = value; } else { envList.push({ name, value }); } } function upsertEnvEntry(envList, entry) { if (!Array.isArray(envList) || !entry?.name) return; const existing = envList.find((item) => item?.name === entry.name); if (existing) { delete existing.value; delete existing.valueFrom; Object.assign(existing, cloneJson(entry)); } else { envList.push(cloneJson(entry)); } } function syncCodeAgentWorkspaceInitContainer(initContainers, { image, runtimeCommit, runtimeImageTag }) { const initContainer = Array.isArray(initContainers) ? initContainers.find((entry) => entry?.name === "hwlab-code-agent-workspace-init") : null; if (!initContainer) return; initContainer.image = image; initContainer.imagePullPolicy = "IfNotPresent"; initContainer.env ??= []; upsertEnv(initContainer.env, "HWLAB_WORKSPACE_SOURCE_COMMIT", runtimeCommit); upsertEnv(initContainer.env, "HWLAB_IMAGE", image); upsertEnv(initContainer.env, "HWLAB_IMAGE_TAG", runtimeImageTag); } function annotate(metadata, annotations) { metadata.annotations = { ...(metadata.annotations ?? {}), ...annotations }; } function label(metadata, labels) { metadata.labels = { ...(metadata.labels ?? {}), ...labels }; } function imageFor(registryPrefix, serviceId, imageTag) { return `${registryPrefix}/${serviceId}:${imageTag}`; } function imageTagFromReference(image) { const value = String(image ?? ""); const slashIndex = value.lastIndexOf("/"); const colonIndex = value.lastIndexOf(":"); if (colonIndex <= slashIndex) return null; return value.slice(colonIndex + 1).split("@", 1)[0] || null; } function repositoryFromImage(image) { const value = String(image ?? "").split("@", 1)[0]; const slashIndex = value.lastIndexOf("/"); const colonIndex = value.lastIndexOf(":"); return colonIndex > slashIndex ? value.slice(0, colonIndex) : value; } function digestPinnedImage(image, digest) { if (!/^sha256:[a-f0-9]{64}$/u.test(String(digest ?? ""))) return image; const repository = repositoryFromImage(image); return repository ? `${repository}@${digest}` : image; } function catalogServiceById(catalog, serviceId) { return (catalog?.services ?? []).find((service) => service?.serviceId === serviceId) ?? null; } function v02EnvReuseEnabled(catalog, serviceId, envReuseServiceIds = null) { if (envReuseServiceIds?.has(serviceId)) return true; const service = catalogServiceById(catalog, serviceId); return service?.runtimeMode === v02EnvReuseRuntimeMode || service?.envReuse === true; } function bootShForService(deployService, serviceId) { assert.ok(deployService?.bootSh, `deploy lane bootScripts.${serviceId} is required`); const value = deployService.bootSh; const text = String(value).replaceAll("\\", "/").replace(/^\.\//u, ""); assert.ok(text && !text.startsWith("/") && !text.split("/").includes(".."), `${serviceId} boot script must be repo-relative`); return text; } function envReuseServiceIdsForLane(deploy, lane) { if (!isRuntimeLane(lane)) return new Set(); const configured = deploy?.lanes?.[lane]?.envReuseServices; const allowed = new Set(serviceIdsForLane(lane, deploy)); return new Set((Array.isArray(configured) ? configured : []).filter((serviceId) => allowed.has(serviceId))); } function deployServiceForBoot(deploy, serviceId, lane = "v02") { return { serviceId, bootSh: deploy?.lanes?.[lane]?.bootScripts?.[serviceId] }; } function bootMetadataForService({ args, catalog, deployService, serviceId, source }) { const catalogService = catalogServiceById(catalog, serviceId); const environmentImage = catalogService?.environmentImage ?? imageFor(args.registryPrefix, `${serviceId}-env`, `env-${String(catalogService?.environmentInputHash ?? source.full).slice(0, 12)}`); const environmentDigest = catalogService?.environmentDigest ?? catalogService?.digest ?? null; return { runtimeMode: v02EnvReuseRuntimeMode, environmentImage, environmentDigest, environmentInputHash: catalogService?.environmentInputHash ?? null, codeInputHash: catalogService?.codeInputHash ?? null, bootRepo: catalogService?.bootRepo ?? args.sourceRepo, bootCommit: source.full, bootSh: catalogService?.bootSh ?? bootShForService(deployService, serviceId) }; } function envReuseBootShForContainer({ serviceId, container, defaultBootSh }) { if (serviceId === "hwlab-cloud-api" && container?.name === "hwlab-codex-api-forwarder") { return "deploy/runtime/boot/hwlab-codex-api-responses-forwarder.sh"; } return defaultBootSh; } function applyEnvReuseBootEnv(container, bootMetadata, { sourceBranch, gitReadUrl, bootSh = bootMetadata?.bootSh } = {}) { if (!container || !bootMetadata) return; delete container.command; delete container.args; container.env ??= []; upsertEnv(container.env, "HWLAB_RUNTIME_MODE", bootMetadata.runtimeMode); upsertEnv(container.env, "HWLAB_BOOT_REPO", bootMetadata.bootRepo); upsertEnv(container.env, "HWLAB_BOOT_COMMIT", bootMetadata.bootCommit); upsertEnv(container.env, "HWLAB_BOOT_REF", sourceBranch); upsertEnv(container.env, "HWLAB_BOOT_SH", bootSh); upsertEnv(container.env, "HWLAB_BOOT_READ_URL", gitReadUrl ?? defaultV02GitReadUrl); upsertEnv(container.env, "HWLAB_ENVIRONMENT_IMAGE", bootMetadata.environmentImage ?? ""); upsertEnv(container.env, "HWLAB_ENVIRONMENT_DIGEST", bootMetadata.environmentDigest ?? ""); upsertEnv(container.env, "HWLAB_ENVIRONMENT_INPUT_HASH", bootMetadata.environmentInputHash ?? ""); upsertEnv(container.env, "HWLAB_CODE_INPUT_HASH", bootMetadata.codeInputHash ?? ""); upsertEnv(container.env, "HWLAB_IMAGE_DIGEST", bootMetadata.environmentDigest ?? "unknown"); applyEnvReuseStartupProbe(container); } function applyEnvReuseStartupProbe(container) { const probe = container.readinessProbe ?? container.livenessProbe; if (!probe?.httpGet && !probe?.tcpSocket && !probe?.exec) return; container.startupProbe ??= { ...cloneJson(probe), periodSeconds: 10, timeoutSeconds: Math.max(Number(probe.timeoutSeconds ?? 1), 2), failureThreshold: 30, successThreshold: 1 }; } function applyServiceHealthProbe(container, healthProbe) { if (!healthProbe || typeof healthProbe !== "object" || Array.isArray(healthProbe)) return; for (const [probeName, key] of [["readinessProbe", "readiness"], ["livenessProbe", "liveness"], ["startupProbe", "startup"]]) { const probe = container?.[probeName]; const timing = normalizeProbeTiming(healthProbe[key]); if (!probe || Object.keys(timing).length === 0) continue; Object.assign(probe, timing); } } function applyServiceShutdownDrainLifecycle(container, shutdownDrain) { if (!container || !shutdownDrain || shutdownDrain.enabled !== true) return; const pathValue = typeof shutdownDrain.path === "string" && /^\/[A-Za-z0-9/_:.-]+$/u.test(shutdownDrain.path) ? shutdownDrain.path : "/internal/workbench/drain"; const sleepSeconds = boundedInteger(shutdownDrain.sleepSeconds, 3, 0, 30); const timeoutMs = boundedInteger(shutdownDrain.timeoutMs, 2500, 100, 30000); container.env ??= []; upsertEnv(container.env, "HWLAB_WORKBENCH_SSE_DRAIN_TIMEOUT_MS", String(timeoutMs)); const command = [ 'port="${PORT:-${HWLAB_PORT:-${HWLAB_CLOUD_API_PORT:-6667}}}"', `url="http://127.0.0.1:\${port}${pathValue}"`, '/usr/local/bin/bun -e \'const [url, hostname] = process.argv.slice(2); await fetch(url, { method: "POST", headers: { "x-hwlab-drain-hostname": hostname || "" } }).catch(() => {});\' "$url" "${HOSTNAME:-}" >/dev/null 2>&1 || true', `sleep ${sleepSeconds}` ].join("; "); container.lifecycle ??= {}; container.lifecycle.preStop = { exec: { command: ["sh", "-c", command] } }; } function boundedInteger(value, fallback, minimum, maximum) { const parsed = Number(value); if (!Number.isInteger(parsed)) return fallback; return Math.max(minimum, Math.min(maximum, parsed)); } function normalizeProbeTiming(value) { if (!value || typeof value !== "object" || Array.isArray(value)) return {}; const result = {}; for (const field of ["initialDelaySeconds", "periodSeconds", "timeoutSeconds", "failureThreshold", "successThreshold"]) { const raw = value[field]; const minimum = field === "initialDelaySeconds" ? 0 : 1; if (Number.isInteger(raw) && raw >= minimum) result[field] = raw; } return result; } function useLocalHealthProbe(container, pathValue = "/health") { if (!container) return; for (const probeName of ["readinessProbe", "livenessProbe"]) { const probe = container[probeName]; if (!probe?.httpGet) continue; probe.httpGet.path = pathValue; } } function annotateEnvReusePodTemplate(podMetadata, bootMetadata) { if (!podMetadata || !bootMetadata) return; annotate(podMetadata, { "hwlab.pikastech.local/runtime-mode": bootMetadata.runtimeMode, "hwlab.pikastech.local/boot-repo": bootMetadata.bootRepo, "hwlab.pikastech.local/boot-commit": bootMetadata.bootCommit, "hwlab.pikastech.local/boot-sh": bootMetadata.bootSh, "hwlab.pikastech.local/environment-digest": bootMetadata.environmentDigest ?? "not_published", "hwlab.pikastech.local/environment-input-hash": bootMetadata.environmentInputHash ?? "unknown", "hwlab.pikastech.local/code-input-hash": bootMetadata.codeInputHash ?? "unknown" }); label(podMetadata, { "hwlab.pikastech.local/runtime-mode": bootMetadata.runtimeMode, "hwlab.pikastech.local/boot-commit": bootMetadata.bootCommit }); } function runtimeArtifactForService({ catalog, deploy, serviceId, source, registryPrefix, useDeployImages = false, digestPin = false, envReuseServiceIds = null }) { const catalogService = catalogServiceById(catalog, serviceId); if (v02EnvReuseEnabled(catalog, serviceId, envReuseServiceIds)) { const environmentImage = catalogService?.environmentImage ?? imageFor(registryPrefix, `${serviceId}-env`, `env-${String(catalogService?.environmentInputHash ?? source.full).slice(0, 12)}`); const runtimeImage = digestPin && useDeployImages ? digestPinnedImage(environmentImage, catalogService?.environmentDigest ?? catalogService?.digest) : environmentImage; return { image: runtimeImage, imageTag: imageTagFromReference(environmentImage) ?? source.imageTag ?? source.short, commit: source.full, runtimeMode: v02EnvReuseRuntimeMode, environmentDigest: catalogService?.environmentDigest ?? catalogService?.digest ?? null }; } const fallbackImageTag = source.imageTag ?? source.short; const image = useDeployImages && catalogService?.image ? catalogService.image : imageFor(registryPrefix, serviceId, fallbackImageTag); const runtimeImage = digestPin && useDeployImages ? digestPinnedImage(image, catalogService?.digest) : image; const imageTag = useDeployImages && catalogService?.imageTag ? catalogService.imageTag : imageTagFromReference(image) ?? fallbackImageTag; const commit = useDeployImages ? catalogService?.sourceCommitId ?? catalogService?.commitId ?? imageTag ?? source.full : source.full; return { image: runtimeImage, imageTag, commit }; } function runtimeImageForService(options) { return runtimeArtifactForService(options).image; } function runtimeCommitForService(options) { return runtimeArtifactForService(options).commit; } function runtimeImageTagForService(options) { return runtimeArtifactForService(options).imageTag; } function artifactEnvironment(args) { return isRuntimeLane(args.lane) ? args.lane : "dev"; } function artifactEndpoint(args) { return isRuntimeLane(args.lane) ? args.runtimeEndpoint : defaultRuntimeEndpoint; } function serviceIdsForLane(lane, deploy = null) { return isRuntimeLane(lane) ? runtimeLaneServiceIdsFromDeploy(deploy, lane) : defaultServiceIds; } function serviceIdsForProfile(profile, deploy = null) { return isRuntimeLane(profile) ? runtimeLaneServiceIdsFromDeploy(deploy, profile) : defaultServiceIds; } function runtimeLaneServiceIdsFromDeploy(deploy, lane) { const laneConfig = runtimeLaneConfig(deploy, lane); const serviceIds = uniquePreserveOrder((Array.isArray(laneConfig.envReuseServices) ? laneConfig.envReuseServices : []) .map((item) => String(item ?? "").trim()) .filter(Boolean)); assert.ok(serviceIds.length > 0, `deploy.lanes.${lane}.envReuseServices must not be empty`); return serviceIds; } function v02ServiceIdsFromDeploy(deploy) { return runtimeLaneServiceIdsFromDeploy(deploy, "v02"); } function runtimeLaneObservableServicesForDeploy(deploy, lane) { const laneConfig = runtimeLaneConfig(deploy, lane); const declarations = laneConfig.serviceDeclarations ?? {}; const serviceIds = new Set(runtimeLaneServiceIdsFromDeploy(deploy, lane)); const declared = Object.entries(declarations) .filter(([serviceId, declaration]) => serviceIds.has(serviceId) && declaration?.observable !== false && Number.isInteger(declaration?.healthPort)) .map(([serviceId, declaration]) => ({ serviceId, port: declaration.healthPort, healthPath: declaration.healthPath || "/health/live" })); return [...declared, ...v02ExtraObservableServices]; } function v02ObservableServicesForDeploy(deploy) { return runtimeLaneObservableServicesForDeploy(deploy, "v02"); } function v02ObservableService(deploy, serviceId) { return v02ObservableServicesForDeploy(deploy).find((item) => item.serviceId === serviceId) ?? null; } function runtimeLaneObservableService(deploy, lane, serviceId) { return runtimeLaneObservableServicesForDeploy(deploy, lane).find((item) => item.serviceId === serviceId) ?? null; } function runtimeLaneObservableServiceIdsForDeploy(deploy, lane) { return new Set(runtimeLaneObservableServicesForDeploy(deploy, lane).map((item) => item.serviceId)); } function v02ObservableServiceIdsForDeploy(deploy) { return runtimeLaneObservableServiceIdsForDeploy(deploy, "v02"); } function servicesParamForLane(lane, deploy = null) { return serviceIdsForLane(lane, deploy).join(","); } function uniquePreserveOrder(values) { const seen = new Set(); const result = []; for (const value of values) { if (seen.has(value)) continue; seen.add(value); result.push(value); } return result; } function isV02RemovedServiceId(serviceId) { return v02RemovedServiceIds.has(serviceId); } function artifactCatalogSkeleton({ args, deploy, source }) { const environment = artifactEnvironment(args); const namespace = isRuntimeLane(args.lane) ? namespaceNameForProfile(args.lane) : "hwlab-dev"; const tag = imageTagForSource(args, source); return { catalogVersion: "v1", kind: "hwlab-artifact-catalog", environment, profile: environment, namespace, endpoint: artifactEndpoint(args), commitId: tag, artifactState: "contract-skeleton", publish: { registryPrefix: args.registryPrefix, sourceCommitId: source.full, imageTag: tag, publishedAt: null }, allowedProfiles: [environment], forbiddenProfiles: isRuntimeLane(args.lane) ? ["dev", "prod"] : ["prod"], services: serviceIdsForLane(args.lane, deploy).map((serviceId) => artifactCatalogSkeletonService({ args, deploy, source, serviceId, environment, namespace, tag })) }; } function artifactCatalogSkeletonService({ args, deploy, source, serviceId, environment, namespace, tag }) { const base = { serviceId, profile: environment, namespace, commitId: tag, sourceCommitId: source.full, image: imageFor(args.registryPrefix, serviceId, tag), imageTag: tag, digest: null, buildBackend: "contract-skeleton" }; const envReuseServiceIds = envReuseServiceIdsForLane(deploy, args.lane); if (!envReuseServiceIds.has(serviceId)) return base; const bootSh = bootShForService(deployServiceForBoot(deploy, serviceId, args.lane), serviceId); const environmentImage = imageFor(args.registryPrefix, `${serviceId}-env`, `env-${String(source.full).slice(0, 12)}`); return { ...base, image: environmentImage, imageTag: imageTagFromReference(environmentImage), runtimeMode: v02EnvReuseRuntimeMode, envReuse: true, environmentImage, environmentDigest: null, environmentInputHash: null, bootRepo: args.sourceRepo, bootCommit: source.full, bootSh, codeInputHash: null, bootEnvEvidence: { env: { HWLAB_BOOT_REPO: args.sourceRepo, HWLAB_BOOT_COMMIT: source.full, HWLAB_BOOT_SH: bootSh } } }; } function namespaceNameForProfile(profile) { if (isRuntimeLane(profile)) return `hwlab-${profile}`; return profile === "prod" ? "hwlab-prod" : "hwlab-dev"; } function runtimePathForProfile(profile) { if (isRuntimeLane(profile)) return `runtime-${profile}`; return profile === "prod" ? "runtime-prod" : "runtime-dev"; } function runtimeLabelForProfile(profile) { if (isRuntimeLane(profile)) return profile; return profile === "prod" ? "prod" : "dev"; } function gitopsTargetForProfile(profile) { return isRuntimeLane(profile) ? profile : "node"; } function gitopsRootForArgs(args) { return String(args.gitopsRoot || defaultOutDir).replace(/\/+$/u, ""); } function gitopsPathForProfile(args, profile) { return `${gitopsRootForArgs(args)}/${runtimePathForProfile(profile)}`; } function gitopsPathFor(args, relativePath) { return `${gitopsRootForArgs(args)}/${String(relativePath).replace(/^\/+/, "")}`; } function profileEndpoint(args, profile) { if (isRuntimeLane(profile)) return { runtimeEndpoint: args.runtimeEndpoint, webEndpoint: args.webEndpoint }; return profile === "prod" ? { runtimeEndpoint: args.prodRuntimeEndpoint, webEndpoint: args.prodWebEndpoint } : { runtimeEndpoint: args.runtimeEndpoint, webEndpoint: args.webEndpoint }; } function laneRuntimeProfiles(args) { return isRuntimeLane(args.lane) ? [args.lane] : ["dev", "prod"]; } function laneNames(args) { if (isRuntimeLane(args.lane)) { const namespace = namespaceNameForProfile(args.lane); return { gitopsTarget: args.lane, pipeline: `${namespace}-ci-image-publish`, poller: `${namespace}-branch-poller`, reconciler: `${namespace}-control-plane-reconciler`, serviceAccount: `${namespace}-tekton-runner`, pipelineRunPrefix: `${namespace}-ci-poll-`, runtimeNamespace: namespace, runtimePath: gitopsPathForProfile(args, args.lane), argoApplications: [`argocd/hwlab-node-${args.lane}`] }; } return { gitopsTarget: "node", pipeline: "hwlab-node-ci-image-publish", poller: "hwlab-node-branch-poller", reconciler: "hwlab-node-control-plane-reconciler", serviceAccount: "hwlab-tekton-runner", pipelineRunPrefix: "hwlab-node-ci-poll-", runtimeNamespace: "hwlab-dev", runtimePath: gitopsPathForProfile(args, "dev"), argoApplications: ["argocd/hwlab-node-dev", "argocd/hwlab-node-prod"] }; } function argoApplicationName(profile) { return `hwlab-node-${profile}`; } function imageTagForSource(args, source) { return args.imageTagMode === "full" ? source.full : source.short; } function deepSeekBaseUrl(namespace) { return `http://hwlab-deepseek-proxy.${namespace}.svc.cluster.local:4000/v1/responses`; } function codeAgentNoProxy(namespace) { return [ `${namespace}.svc.cluster.local`, ".svc", ".cluster.local", "hyueapi.com", ".hyueapi.com", "hyui.com", ".hyui.com", "127.0.0.1", "localhost", "::1", "10.0.0.0/8", "10.42.0.0/16", "10.43.0.0/16", "api.minimaxi.com", ".minimaxi.com" ].join(","); } function namespaceScopedHost(value, namespace) { if (typeof value !== "string") return value; return value.replace(/\.hwlab-dev\.svc\.cluster\.local/gu, `.${namespace}.svc.cluster.local`); } function secretNameForProfile(secretName, profile) { if (!isRuntimeLane(profile)) return secretName; if (secretName === "hwlab-cloud-api-dev-db") return `hwlab-cloud-api-${profile}-db`; if (secretName === "hwlab-code-agent-provider") return `hwlab-${profile}-code-agent-provider`; if (secretName === "hwlab-code-agent-codex-auth") return `hwlab-${profile}-code-agent-codex-auth`; if (secretName === "hwlab-opencode-server-auth") return `hwlab-${profile}-opencode-server-auth`; if (secretName === "hwlab-bootstrap-admin") return `hwlab-${profile}-bootstrap-admin`; return secretName; } function secretRefObjectForProfile(secretRef, profile) { const ref = configString(secretRef); const slashIndex = ref.indexOf("/"); assert.ok(slashIndex > 0 && slashIndex < ref.length - 1, `secretRef ${JSON.stringify(secretRef)} must be name/key`); return { name: secretNameForProfile(ref.slice(0, slashIndex), profile), key: ref.slice(slashIndex + 1), optional: true }; } function rewritePodSecretRefs(podSpec, profile) { if (!podSpec || !isRuntimeLane(profile)) return; for (const volume of podSpec.volumes ?? []) { if (volume?.secret?.secretName) volume.secret.secretName = secretNameForProfile(volume.secret.secretName, profile); } } function deployEnvEntry(name, value, namespace, profile = "dev") { if (typeof value === "string" && value.startsWith("secretRef:")) { return { name, valueFrom: { secretKeyRef: secretRefObjectForProfile(value.slice("secretRef:".length), profile) } }; } return { name, value: namespaceScopedHost(value, namespace) }; } function applyDeployEnv(envList, deployService, namespace, profile = "dev") { if (!deployService?.env || typeof deployService.env !== "object" || Array.isArray(deployService.env)) return; for (const [name, value] of Object.entries(deployService.env)) { upsertEnvEntry(envList, deployEnvEntry(name, value, namespace, profile)); } } function applyDeployConfigMapMounts(podSpec, container, deployService) { const mounts = Array.isArray(deployService?.configMapMounts) ? deployService.configMapMounts : []; if (mounts.length === 0 || !podSpec || !container) return; podSpec.volumes ??= []; container.volumeMounts ??= []; for (const mount of mounts) { const name = String(mount?.name ?? "").trim(); const configMapName = String(mount?.configMapName ?? "").trim(); const mountPath = String(mount?.mountPath ?? "").trim(); if (!name || !configMapName || !mountPath) continue; const items = Array.isArray(mount.items) ? mount.items .map((item) => ({ key: String(item?.key ?? "").trim(), path: String(item?.path ?? "").trim() })) .filter((item) => item.key && item.path) : []; const volume = { name, configMap: { name: configMapName } }; if (items.length > 0) volume.configMap.items = items; const existingVolume = podSpec.volumes.find((entry) => entry?.name === name); if (existingVolume) Object.assign(existingVolume, volume); else podSpec.volumes.push(volume); const volumeMount = { name, mountPath, readOnly: mount.readOnly !== false }; const existingMount = container.volumeMounts.find((entry) => entry?.name === name); if (existingMount) Object.assign(existingMount, volumeMount); else container.volumeMounts.push(volumeMount); } } function removeV02LegacySimulatorEnv(envList) { if (!Array.isArray(envList)) return envList; return envList.filter((entry) => !v02RemovedServiceEnvNames.has(entry?.name)); } function removeV02RepoOwnedCodeAgentPodConfig(deploymentSpec, podSpec) { if (!podSpec) return; podSpec.initContainers = (podSpec.initContainers ?? []).filter((entry) => entry?.name !== "hwlab-code-agent-workspace-init"); const removedVolumeNames = new Set([ "hwlab-code-agent-workspace", "hwlab-code-agent-codex-home", "hwlab-code-agent-codex-config", "hwlab-code-agent-codex-auth" ]); podSpec.volumes = (podSpec.volumes ?? []).filter((volume) => !removedVolumeNames.has(volume?.name)); for (const container of podSpec.containers ?? []) { container.volumeMounts = (container.volumeMounts ?? []).filter((mount) => !removedVolumeNames.has(mount?.name)); } if (deploymentSpec?.strategy?.type === "Recreate") delete deploymentSpec.strategy; } function applyDeployServiceReplicas(item, deployService) { if (!(item?.kind === "Deployment" || item?.kind === "StatefulSet")) return; const replicas = deployService?.replicas; if (!Number.isInteger(replicas) || replicas < 0) return; item.spec ??= {}; item.spec.replicas = replicas; } function deployServicesForProfile(deploy, profile) { const allowed = new Set(serviceIdsForProfile(profile, deploy)); const services = new Map((deploy.services ?? []) .filter((service) => allowed.has(service.serviceId)) .map((service) => { const copy = cloneJson(service); copy.env = mergeEnvMaps( copy.env, serviceDeclarationEnvForProfile(deploy, profile, service.serviceId), accessControlEnvForProfile(deploy, profile, service.serviceId), runtimeStoreEnvForProfile(deploy, profile, service.serviceId), workbenchRuntimeClientEnvForProfile(deploy, profile, service.serviceId), workbenchRuntimeFactsQueryEnvForProfile(deploy, profile, service.serviceId), workbenchRuntimeSessionsSummaryEnvForProfile(deploy, profile, service.serviceId), workbenchRuntimePostgresEnvForProfile(deploy, profile, service.serviceId), workbenchRuntimeRedisEnvForProfile(deploy, profile, service.serviceId) ); return [service.serviceId, copy]; })); const laneServices = isRuntimeLane(profile) && Array.isArray(deploy.lanes?.[profile]?.services) ? deploy.lanes[profile].services : []; for (const override of laneServices) { const existing = services.get(override.serviceId) ?? { serviceId: override.serviceId, env: mergeEnvMaps( serviceDeclarationEnvForProfile(deploy, profile, override.serviceId), accessControlEnvForProfile(deploy, profile, override.serviceId), runtimeStoreEnvForProfile(deploy, profile, override.serviceId), workbenchRuntimeClientEnvForProfile(deploy, profile, override.serviceId), workbenchRuntimeFactsQueryEnvForProfile(deploy, profile, override.serviceId), workbenchRuntimeSessionsSummaryEnvForProfile(deploy, profile, override.serviceId), workbenchRuntimePostgresEnvForProfile(deploy, profile, override.serviceId), workbenchRuntimeRedisEnvForProfile(deploy, profile, override.serviceId) ) }; services.set(override.serviceId, { ...existing, ...cloneJson(override), env: mergeEnvMaps(existing.env, override.env) }); } return services; } function accessControlEnvForProfile(deploy, profile, serviceId) { return deploy?.__accessControlEnvByProfile?.[profile]?.[serviceId] ?? {}; } function serviceDeclarationEnvForProfile(deploy, profile, serviceId) { if (!isRuntimeLane(profile)) return {}; const env = deploy?.lanes?.[profile]?.serviceDeclarations?.[serviceId]?.env; if (!env || typeof env !== "object" || Array.isArray(env)) return {}; return cloneJson(env); } function runtimeWorkbenchTraceTimelinePolicy(deploy, profile) { if (!isRuntimeLane(profile)) return null; const traceTimeline = runtimeLaneConfig(deploy, profile)?.workbench?.traceTimeline; if (!traceTimeline || typeof traceTimeline !== "object" || Array.isArray(traceTimeline)) return null; const result = {}; if (typeof traceTimeline.autoExpandRunning === "boolean") result.autoExpandRunning = traceTimeline.autoExpandRunning; if (typeof traceTimeline.autoCollapseTerminal === "boolean") result.autoCollapseTerminal = traceTimeline.autoCollapseTerminal; return Object.keys(result).length > 0 ? result : null; } function runtimeWorkbenchRawHwlabEventWindowPolicy(deploy, profile) { if (!isRuntimeLane(profile)) return null; const policy = runtimeLaneConfig(deploy, profile)?.workbench?.rawHwlabEventWindow; if (!policy || typeof policy !== "object" || Array.isArray(policy)) return null; return { enabled: policy.enabled, maxEntries: policy.maxEntries, maxRetainedBytes: policy.maxRetainedBytes }; } function runtimeAgentObserverPolicy(deploy, profile) { if (!isRuntimeLane(profile)) return null; const policy = runtimeLaneConfig(deploy, profile)?.agentObserver; if (!policy || typeof policy !== "object" || Array.isArray(policy)) return null; return cloneJson(policy); } function runtimeTraceExplorerUrlTemplate(deploy, profile) { if (!isRuntimeLane(profile)) return null; const template = runtimeLaneConfig(deploy, profile)?.observability?.traceExplorerUrlTemplate; return typeof template === "string" && template.trim().length > 0 ? template.trim() : null; } function runtimePrometheusOperatorResourcesEnabled(deploy, profile) { if (!isRuntimeLane(profile)) return true; const enabled = runtimeLaneConfig(deploy, profile)?.observability?.prometheusOperatorResources; return enabled !== false; } function effectiveSecretPlaneNodeId(args = {}) { return gitopsRootNodeId(args.gitopsRoot) ?? String(args.nodeId ?? "").trim().toUpperCase(); } function gitopsRootNodeId(gitopsRoot) { const normalized = String(gitopsRoot ?? "").replaceAll("\\", "/").replace(/\/+$/u, ""); const match = normalized.match(/(?:^|\/)deploy\/gitops\/node\/([^/]+)$/u); return match?.[1] ? match[1].trim().toUpperCase() : null; } function runtimeFrpConfigForProfile(deploy, profile, args = {}) { const fallbackWebRemotePort = isRuntimeLane(profile) ? defaultPortForRuntimeLane(profile) : profile === "prod" ? 18666 : 17666; const fallbackEdgeRemotePort = isRuntimeLane(profile) ? fallbackWebRemotePort + 1 : profile === "prod" ? 18667 : 17667; const baseFrp = isRuntimeLane(profile) ? runtimeLaneConfig(deploy, profile)?.frp : deploy?.frp; const nodeId = effectiveSecretPlaneNodeId(args); const nodeFrp = nodeId ? baseFrp?.nodes?.[nodeId] : null; const frp = nodeFrp && typeof nodeFrp === "object" && !Array.isArray(nodeFrp) ? { ...baseFrp, ...nodeFrp } : baseFrp; const server = frp && typeof frp === "object" && !Array.isArray(frp) ? frp.server : null; const proxies = Array.isArray(frp?.proxies) ? frp.proxies : []; const proxyByEndpoint = new Map(proxies .filter((proxy) => proxy && typeof proxy === "object" && !Array.isArray(proxy)) .map((proxy) => [String(proxy.endpointId || proxy.name || ""), proxy])); const proxyValue = (endpointId, key, fallback) => { const value = proxyByEndpoint.get(endpointId)?.[key]; return typeof value === "string" && value.trim().length > 0 ? value.trim() : fallback; }; const proxyPort = (endpointId, fallback) => { const value = proxyByEndpoint.get(endpointId)?.remotePort; return Number.isInteger(value) ? value : fallback; }; return { serverAddr: typeof server?.address === "string" && server.address.trim().length > 0 ? server.address.trim() : "74.48.78.17", serverPort: Number.isInteger(server?.bindPort) ? server.bindPort : 7000, webRemotePort: proxyPort("frontend", fallbackWebRemotePort), edgeRemotePort: proxyPort("api", fallbackEdgeRemotePort), webProxyName: proxyValue("frontend", "name", null), edgeProxyName: proxyValue("api", "name", null), authSecretName: typeof frp?.auth?.secretName === "string" && frp.auth.secretName.trim().length > 0 ? frp.auth.secretName.trim() : null, authSecretKey: typeof frp?.auth?.secretKey === "string" && frp.auth.secretKey.trim().length > 0 ? frp.auth.secretKey.trim() : null }; } function runtimeStoreEnvForProfile(deploy, profile, serviceId) { if (!isRuntimeLane(profile) || serviceId !== "hwlab-cloud-api") return {}; const postgres = runtimeLaneConfig(deploy, profile)?.runtimeStore?.postgres; if (!postgres || typeof postgres !== "object" || Array.isArray(postgres)) return {}; const env = {}; if (postgres.sslMode === "disable" || postgres.sslMode === "require") env.HWLAB_CLOUD_DB_SSL_MODE = postgres.sslMode; if (Number.isInteger(postgres.poolMax)) env.HWLAB_CLOUD_DB_POOL_MAX = String(postgres.poolMax); if (Number.isInteger(postgres.connectionTimeoutMs)) { env.HWLAB_CLOUD_DB_PROBE_TIMEOUT_MS = String(postgres.connectionTimeoutMs); } if (Number.isInteger(postgres.queryTimeoutMs)) { env.HWLAB_CLOUD_DB_QUERY_TIMEOUT_MS = String(postgres.queryTimeoutMs); } if (Number.isInteger(postgres.queryRetryMaxAttempts)) { env.HWLAB_CLOUD_DB_QUERY_RETRY_MAX_ATTEMPTS = String(postgres.queryRetryMaxAttempts); } if (Number.isInteger(postgres.queryRetryInitialDelayMs)) { env.HWLAB_CLOUD_DB_QUERY_RETRY_INITIAL_DELAY_MS = String(postgres.queryRetryInitialDelayMs); } if (Number.isInteger(postgres.queryRetryMaxDelayMs)) { env.HWLAB_CLOUD_DB_QUERY_RETRY_MAX_DELAY_MS = String(postgres.queryRetryMaxDelayMs); } return env; } function workbenchRuntimeRedisEnvForProfile(deploy, profile, serviceId) { if (!isRuntimeLane(profile) || serviceId !== "hwlab-workbench-runtime") return {}; const redis = workbenchRuntimeRedisConfigForProfile(deploy, profile); if (!redis || typeof redis !== "object" || Array.isArray(redis)) return {}; const env = { HWLAB_WORKBENCH_CACHE_REDIS_ENABLED: booleanEnv(Boolean(redis.enabled)) }; const namespace = typeof redis.namespace === "string" ? redis.namespace.trim() : ""; const serviceName = typeof redis.serviceName === "string" ? redis.serviceName.trim() : ""; const port = Number.isInteger(redis.port) ? redis.port : null; if (namespace) env.HWLAB_WORKBENCH_CACHE_REDIS_NAMESPACE = namespace; if (serviceName) env.HWLAB_WORKBENCH_CACHE_REDIS_SERVICE_NAME = serviceName; if (port !== null) env.HWLAB_WORKBENCH_CACHE_REDIS_PORT = String(port); if (namespace && serviceName && port !== null) { env.HWLAB_WORKBENCH_CACHE_REDIS_URL = `redis://${serviceName}.${namespace}.svc.cluster.local:${port}/0`; } const ttl = redis.ttl ?? {}; if (Number.isInteger(ttl.sessionsSummaryMs)) env.HWLAB_WORKBENCH_CACHE_REDIS_TTL_SESSIONS_SUMMARY_MS = String(ttl.sessionsSummaryMs); if (Number.isInteger(ttl.terminalTurnMs)) env.HWLAB_WORKBENCH_CACHE_REDIS_TTL_TERMINAL_TURN_MS = String(ttl.terminalTurnMs); if (Number.isInteger(ttl.terminalTracePageMs)) env.HWLAB_WORKBENCH_CACHE_REDIS_TTL_TERMINAL_TRACE_PAGE_MS = String(ttl.terminalTracePageMs); if (Number.isInteger(ttl.runningPageMs)) env.HWLAB_WORKBENCH_CACHE_REDIS_TTL_RUNNING_PAGE_MS = String(ttl.runningPageMs); const limits = redis.limits ?? {}; if (Number.isInteger(limits.maxKeyBytes)) env.HWLAB_WORKBENCH_CACHE_REDIS_MAX_KEY_BYTES = String(limits.maxKeyBytes); if (Number.isInteger(limits.maxPayloadBytes)) env.HWLAB_WORKBENCH_CACHE_REDIS_MAX_PAYLOAD_BYTES = String(limits.maxPayloadBytes); const timeouts = redis.timeouts ?? {}; if (Number.isInteger(timeouts.connectMs)) env.HWLAB_WORKBENCH_CACHE_REDIS_CONNECT_TIMEOUT_MS = String(timeouts.connectMs); if (Number.isInteger(timeouts.operationMs)) env.HWLAB_WORKBENCH_CACHE_REDIS_OPERATION_TIMEOUT_MS = String(timeouts.operationMs); const labels = redis.metrics?.labels; if (labels && typeof labels === "object" && !Array.isArray(labels)) { env.HWLAB_WORKBENCH_CACHE_REDIS_METRICS_LABELS = JSON.stringify(labels); } const behavior = redis.unavailableBehavior ?? {}; if (typeof behavior.livenessFailure === "boolean") env.HWLAB_WORKBENCH_CACHE_REDIS_UNAVAILABLE_LIVENESS_FAILURE = booleanEnv(behavior.livenessFailure); if (typeof behavior.readMode === "string") env.HWLAB_WORKBENCH_CACHE_REDIS_UNAVAILABLE_READ_MODE = behavior.readMode; if (typeof behavior.fallbackStateSource === "boolean") env.HWLAB_WORKBENCH_CACHE_REDIS_UNAVAILABLE_FALLBACK_STATE_SOURCE = booleanEnv(behavior.fallbackStateSource); if (typeof redis.disableSwitchEnv === "string" && redis.disableSwitchEnv.trim()) { env[redis.disableSwitchEnv.trim()] = booleanEnv(Boolean(redis.enabled)); } return env; } function workbenchRuntimeClientEnvForProfile(deploy, profile, serviceId) { if (!isRuntimeLane(profile) || serviceId !== "hwlab-cloud-api") return {}; const client = runtimeLaneConfig(deploy, profile)?.workbenchRuntime?.client; if (!client || typeof client !== "object" || Array.isArray(client)) return {}; const env = {}; if (Number.isInteger(client.timeoutMs)) env.HWLAB_WORKBENCH_RUNTIME_TIMEOUT_MS = String(client.timeoutMs); return env; } function workbenchRuntimeFactsQueryEnvForProfile(deploy, profile, serviceId) { if (!isRuntimeLane(profile) || serviceId !== "hwlab-cloud-api") return {}; const factsQuery = runtimeLaneConfig(deploy, profile)?.workbenchRuntime?.factsQuery; if (!factsQuery || typeof factsQuery !== "object" || Array.isArray(factsQuery)) return {}; const env = {}; if (Number.isInteger(factsQuery.maxAttempts)) env.HWLAB_WORKBENCH_FACTS_QUERY_MAX_ATTEMPTS = String(factsQuery.maxAttempts); if (Number.isInteger(factsQuery.backoffBaseMs)) env.HWLAB_WORKBENCH_FACTS_QUERY_BACKOFF_BASE_MS = String(factsQuery.backoffBaseMs); if (Number.isInteger(factsQuery.backoffMaxMs)) env.HWLAB_WORKBENCH_FACTS_QUERY_BACKOFF_MAX_MS = String(factsQuery.backoffMaxMs); return env; } function workbenchRuntimeSessionsSummaryEnvForProfile(deploy, profile, serviceId) { if (!isRuntimeLane(profile) || serviceId !== "hwlab-workbench-runtime") return {}; const sessionsSummary = runtimeLaneConfig(deploy, profile)?.workbenchRuntime?.sessionsSummary; if (!sessionsSummary || typeof sessionsSummary !== "object" || Array.isArray(sessionsSummary)) return {}; const env = {}; if (Number.isInteger(sessionsSummary.maxAttempts)) env.HWLAB_WORKBENCH_SESSIONS_SUMMARY_QUERY_MAX_ATTEMPTS = String(sessionsSummary.maxAttempts); if (Number.isInteger(sessionsSummary.attemptTimeoutMs)) env.HWLAB_WORKBENCH_SESSIONS_SUMMARY_QUERY_ATTEMPT_TIMEOUT_MS = String(sessionsSummary.attemptTimeoutMs); if (Number.isInteger(sessionsSummary.backoffMs)) env.HWLAB_WORKBENCH_SESSIONS_SUMMARY_QUERY_BACKOFF_MS = String(sessionsSummary.backoffMs); return env; } function workbenchRuntimePostgresEnvForProfile(deploy, profile, serviceId) { if (!isRuntimeLane(profile) || serviceId !== "hwlab-workbench-runtime") return {}; const postgres = runtimeLaneConfig(deploy, profile)?.workbenchRuntime?.postgres; if (!postgres || typeof postgres !== "object" || Array.isArray(postgres)) return {}; const env = {}; if (Number.isInteger(postgres.poolMax)) env.HWLAB_WORKBENCH_RUNTIME_DB_POOL_MAX = String(postgres.poolMax); if (Number.isInteger(postgres.queryTimeoutMs)) env.HWLAB_WORKBENCH_RUNTIME_QUERY_TIMEOUT_MS = String(postgres.queryTimeoutMs); if (Number.isInteger(postgres.readyTimeoutMs)) env.HWLAB_WORKBENCH_RUNTIME_READY_TIMEOUT_MS = String(postgres.readyTimeoutMs); return env; } function configObject(value, label) { assert.ok(value && typeof value === "object" && !Array.isArray(value), `${label} must be an object`); return value; } function requiredConfigString(record, key, label) { const value = record[key]; assert.ok(typeof value === "string" && value.length > 0, `${label}.${key} must be a non-empty string`); return value; } function optionalConfigString(record, key, label) { const value = record[key]; if (value === undefined || value === null || value === "") return null; assert.ok(typeof value === "string", `${label}.${key} must be a string when set`); return value; } function requiredConfigPositiveInteger(record, key, label) { const value = record[key]; assert.ok(Number.isInteger(value) && value > 0, `${label}.${key} must be a positive integer`); return value; } function workbenchRuntimeRedisConfigForProfile(deploy, profile) { if (!isRuntimeLane(profile)) return null; const label = `deploy.lanes.${profile}.workbenchRuntime.cache.redis`; const redis = runtimeLaneConfig(deploy, profile)?.workbenchRuntime?.cache?.redis; if (!redis || redis.enabled !== true) return null; configObject(redis, label); const namespace = requiredConfigString(redis, "namespace", label); assert.equal(namespace, namespaceNameForProfile(profile), `${label}.namespace must match ${namespaceNameForProfile(profile)}`); const serviceName = requiredConfigString(redis, "serviceName", label); const image = requiredConfigString(redis, "image", label); const port = requiredConfigPositiveInteger(redis, "port", label); assert.ok(port <= 65535, `${label}.port must be a valid TCP port`); const resources = configObject(redis.resources, `${label}.resources`); configObject(resources.requests, `${label}.resources.requests`); configObject(resources.limits, `${label}.resources.limits`); const memoryPolicy = configObject(redis.memoryPolicy, `${label}.memoryPolicy`); assert.equal(memoryPolicy.persistence, "disabled", `${label}.memoryPolicy.persistence must be disabled`); requiredConfigString(memoryPolicy, "maxMemory", `${label}.memoryPolicy`); requiredConfigString(memoryPolicy, "eviction", `${label}.memoryPolicy`); return redis; } function booleanEnv(value) { return value ? "1" : "0"; } function mergeEnvMaps(...values) { const result = {}; for (const value of values) { if (!value || typeof value !== "object" || Array.isArray(value)) continue; Object.assign(result, value); } return result; } function runtimeNodeIdForProfile(deploy, profile, fallback = "node") { if (!isRuntimeLane(profile)) return fallback; if (typeof fallback === "string" && fallback.trim() && fallback !== "node") return fallback; const nodeId = deploy?.lanes?.[profile]?.node; return typeof nodeId === "string" && nodeId.length > 0 ? nodeId : fallback; } function v02MetricsLabels(serviceId) { return { "hwlab.pikastech.local/monitoring": "enabled", "hwlab.pikastech.local/service-id": serviceId }; } function v02MetricsSidecarVolume(profile = "v02") { return { name: "hwlab-metrics-sidecar", configMap: { name: `hwlab-${profile}-metrics-sidecar` } }; } function v02MetricsSidecarAnnotations(metricsSidecarSha256) { return metricsSidecarSha256 ? { "hwlab.pikastech.local/metrics-sidecar-sha256": metricsSidecarSha256 } : {}; } function v02MetricsSidecarContainer({ deploy, serviceId, namespace, gitopsTarget, profile = "v02" }) { const service = runtimeLaneObservableService(deploy, profile, serviceId); assert.ok(service, `unknown ${profile} observable service ${serviceId}`); const extraMetricsEnv = serviceId === "hwlab-cloud-api" ? [ { name: "HWLAB_METRICS_EXTRA_URL", value: `http://127.0.0.1:${service.port}/v1/web-performance/metrics` }, { name: "HWLAB_METRICS_EXTRA_TIMEOUT_MS", value: "2000" } ] : []; return { name: "hwlab-metrics", image: ciToolsRunnerImage, imagePullPolicy: "IfNotPresent", command: ["node", "/metrics/metrics-sidecar.mjs"], env: [ { name: "HWLAB_METRICS_SERVICE_ID", value: serviceId }, { name: "HWLAB_METRICS_NAMESPACE", value: namespace }, { name: "HWLAB_METRICS_GITOPS_TARGET", value: gitopsTarget }, { name: "HWLAB_METRICS_PORT", value: "9100" }, { name: "HWLAB_METRICS_TARGET_URL", value: `http://127.0.0.1:${service.port}${service.healthPath}` }, { name: "HWLAB_METRICS_TARGET_TIMEOUT_MS", value: "2000" }, ...extraMetricsEnv ], ports: [{ name: "metrics", containerPort: 9100 }], readinessProbe: { httpGet: { path: "/health/live", port: "metrics" }, initialDelaySeconds: 3, periodSeconds: 10 }, livenessProbe: { httpGet: { path: "/health/live", port: "metrics" }, initialDelaySeconds: 10, periodSeconds: 20 }, volumeMounts: [{ name: "hwlab-metrics-sidecar", mountPath: "/metrics", readOnly: true }] }; } function upsertV02MetricsSidecar(podSpec, options) { if (!podSpec || !Array.isArray(podSpec.containers)) return; podSpec.containers = podSpec.containers.filter((container) => container?.name !== "hwlab-metrics"); podSpec.containers.push(v02MetricsSidecarContainer(options)); podSpec.volumes ??= []; podSpec.volumes = podSpec.volumes.filter((volume) => volume?.name !== "hwlab-metrics-sidecar"); podSpec.volumes.push(v02MetricsSidecarVolume(options.profile)); } function upsertV02MetricsPort(service) { service.spec ??= {}; service.spec.ports ??= []; service.spec.ports = service.spec.ports.filter((port) => port?.name !== "metrics"); service.spec.ports.push({ name: "metrics", port: 9100, targetPort: "metrics" }); } function transformWorkloads({ workloads, deploy, catalog, source, sourceBranch = defaultBranch, gitReadUrl, registryPrefix, runtimeEndpoint, webEndpoint, profile = "dev", nodeId = "node", useDeployImages = false, metricsSidecarSha256 = null }) { const result = cloneJson(workloads); const deployServices = deployServicesForProfile(deploy, profile); const namespace = namespaceNameForProfile(profile); const profileLabel = runtimeLabelForProfile(profile); const gitopsTarget = gitopsTargetForProfile(profile); const runtimeLane = isRuntimeLane(profile); const digestPin = runtimeLane; const envReuseServiceIds = envReuseServiceIdsForLane(deploy, profile); const runtimeObservableServiceIds = runtimeLane ? runtimeLaneObservableServiceIdsForDeploy(deploy, profile) : new Set(); const stableRuntimeLabels = { "app.kubernetes.io/part-of": "hwlab", "hwlab.pikastech.local/environment": profileLabel, "hwlab.pikastech.local/profile": profileLabel }; result.items = asItems(result, "workloads").filter((item) => !(runtimeLane && isV02RemovedServiceId(serviceIdForWorkload(item, null)))); for (const item of asItems(result, "workloads")) { item.metadata.namespace = namespace; label(item.metadata, { ...stableRuntimeLabels, "hwlab.pikastech.local/gitops-target": gitopsTarget, "hwlab.pikastech.local/gitops-render-source-commit": source.full, "hwlab.pikastech.local/source-commit": source.full, "unidesk.ai/node-staging": profile === "dev" ? "true" : "false" }); annotate(item.metadata, { "hwlab.pikastech.local/gitops-note": profile === "v02" ? "HWLAB v0.2 GitOps target." : profile === "prod" ? "node PROD GitOps target." : "node DEV GitOps target.", "hwlab.pikastech.local/gitops-render-source-commit": source.full, "hwlab.pikastech.local/source-commit": source.full }); if (item.kind === "Job") { annotate(item.metadata, { "argocd.argoproj.io/sync-options": "Force=true,Replace=true" }); if (item.spec?.suspend === true) { annotate(item.metadata, { "argocd.argoproj.io/ignore-healthcheck": "true" }); } } const podTemplate = item?.spec?.template; if (!podTemplate?.spec?.containers) continue; const templateServiceId = serviceIdForWorkload(item, podTemplate.spec.containers[0]); const templateArtifact = runtimeArtifactForService({ catalog, deploy, serviceId: templateServiceId, source, registryPrefix, useDeployImages, digestPin, envReuseServiceIds }); const templateSourceCommit = runtimeLane ? (templateArtifact.commit ?? source.full) : source.full; const templateArtifactCommit = templateArtifact.commit; label(podTemplate.metadata ??= {}, { ...stableRuntimeLabels, "hwlab.pikastech.local/gitops-target": gitopsTarget, "hwlab.pikastech.local/gitops-render-source-commit": source.full, "hwlab.pikastech.local/source-commit": templateSourceCommit, "hwlab.pikastech.local/artifact-source-commit": templateArtifactCommit }); if (runtimeLane && runtimeObservableServiceIds.has(templateServiceId)) { label(item.metadata, v02MetricsLabels(templateServiceId)); label(podTemplate.metadata, v02MetricsLabels(templateServiceId)); annotate(podTemplate.metadata, v02MetricsSidecarAnnotations(metricsSidecarSha256)); upsertV02MetricsSidecar(podTemplate.spec, { deploy, serviceId: templateServiceId, namespace, gitopsTarget, profile }); } if ((item.kind === "Deployment" || item.kind === "StatefulSet") && item.spec?.selector?.matchLabels) { item.spec.selector.matchLabels = { ...item.spec.selector.matchLabels, ...stableRuntimeLabels }; } annotate(podTemplate.metadata, { "hwlab.pikastech.local/gitops-render-source-commit": source.full, "hwlab.pikastech.local/source-commit": templateSourceCommit, "hwlab.pikastech.local/artifact-source-commit": templateArtifactCommit, "hwlab.pikastech.local/rendered-by": "scripts/gitops-render.mjs" }); for (const container of podTemplate.spec.containers) { if (container.name === "hwlab-metrics") continue; const serviceId = serviceIdForWorkload(item, container); const deployService = deployServices.get(serviceId); if (!deployService) continue; applyDeployServiceReplicas(item, deployService); const artifact = runtimeArtifactForService({ catalog, deploy, serviceId, source, registryPrefix, useDeployImages, digestPin, envReuseServiceIds }); const envReuse = runtimeLane && v02EnvReuseEnabled(catalog, serviceId, envReuseServiceIds); const bootDeployService = envReuse ? deployServiceForBoot(deploy, serviceId, profile) : null; const bootMetadata = envReuse ? bootMetadataForService({ args: { sourceRepo: deploy?.lanes?.[profile]?.sourceRepo || defaultSourceRepo, registryPrefix }, catalog, deployService: bootDeployService, serviceId, source }) : null; const image = artifact.image; const runtimeCommit = artifact.commit; const runtimeImageTag = artifact.imageTag; container.image = image; container.imagePullPolicy = "IfNotPresent"; container.env ??= []; for (const entry of container.env) { if (Object.hasOwn(entry, "value")) entry.value = namespaceScopedHost(entry.value, namespace); } applyDeployEnv(container.env, deployService, namespace, profile); applyDeployConfigMapMounts(podTemplate.spec, container, deployService); if (runtimeLane) container.env = removeV02LegacySimulatorEnv(container.env); upsertEnv(container.env, "HWLAB_ENVIRONMENT", profileLabel); upsertEnv(container.env, "HWLAB_COMMIT_ID", runtimeCommit); upsertEnv(container.env, "HWLAB_IMAGE", image); upsertEnv(container.env, "HWLAB_IMAGE_TAG", runtimeImageTag); if (serviceId === "hwlab-agent-skills") { upsertEnv(container.env, "HWLAB_SKILLS_COMMIT_ID", runtimeCommit); } upsertEnv(container.env, "HWLAB_GITOPS_TARGET", gitopsTarget); upsertEnv(container.env, "HWLAB_GITOPS_PROFILE", profileLabel); upsertEnv(container.env, "HWLAB_GITOPS_SOURCE_COMMIT", runtimeLane ? runtimeCommit : source.full); if (runtimeLane && serviceId === "hwlab-cloud-api") { upsertEnv(container.env, "HWLAB_CODE_AGENT_AGENTRUN_SOURCE_COMMIT", runtimeCommit); } if (bootMetadata) { applyEnvReuseBootEnv(container, bootMetadata, { sourceBranch, gitReadUrl, bootSh: envReuseBootShForContainer({ serviceId, container, defaultBootSh: bootMetadata.bootSh }) }); if (container.name === serviceId) annotateEnvReusePodTemplate(podTemplate.metadata, bootMetadata); } if (runtimeLane && container.name === serviceId) { applyServiceHealthProbe(container, deploy?.lanes?.[profile]?.serviceDeclarations?.[serviceId]?.healthProbe); } if (serviceId === "hwlab-cloud-api" || serviceId === "hwlab-edge-proxy") { upsertEnv(container.env, "HWLAB_PUBLIC_ENDPOINT", runtimeEndpoint); } if (runtimeLane && (serviceId === "hwlab-cloud-api" || serviceId === "hwlab-cloud-web")) { const agentObserverPolicy = runtimeAgentObserverPolicy(deploy, profile); if (agentObserverPolicy) { upsertEnv(container.env, "HWLAB_AGENT_OBSERVER_RETENTION_EVENT_LIMIT", String(agentObserverPolicy.retentionEventLimit)); upsertEnv(container.env, "HWLAB_AGENT_OBSERVER_RETENTION_SCAN_LIMIT", String(agentObserverPolicy.retentionScanLimit)); upsertEnv(container.env, "HWLAB_AGENT_OBSERVER_RETENTION_TIMEOUT_MS", String(agentObserverPolicy.retentionTimeoutMs)); upsertEnv(container.env, "HWLAB_AGENT_OBSERVER_RETENTION_GROUP_PREFIX", String(agentObserverPolicy.retentionGroupPrefix)); upsertEnv(container.env, "HWLAB_AGENT_OBSERVER_SSE_HEARTBEAT_MS", String(agentObserverPolicy.sseHeartbeatMs)); upsertEnv(container.env, "HWLAB_AGENT_OBSERVER_RECONNECT_DELAY_MS", String(agentObserverPolicy.reconnectDelayMs)); upsertEnv(container.env, "HWLAB_AGENT_OBSERVER_BATCH_MAX_EVENTS", String(agentObserverPolicy.batchMaxEvents)); upsertEnv(container.env, "HWLAB_AGENT_OBSERVER_LIVE_BUFFER_LIMIT", String(agentObserverPolicy.liveBufferLimit)); upsertEnv(container.env, "HWLAB_AGENT_OBSERVER_IDENTITY_WINDOW_LIMIT", String(agentObserverPolicy.identityWindowLimit)); upsertEnv(container.env, "HWLAB_AGENT_OBSERVER_REDUCER_EVENT_LIMIT", String(agentObserverPolicy.reducerEventLimit)); upsertEnv(container.env, "HWLAB_AGENT_OBSERVER_REDUCER_ENTITY_LIMIT", String(agentObserverPolicy.reducerEntityLimit)); upsertEnv(container.env, "HWLAB_AGENT_OBSERVER_TREE_NODE_LIMIT", String(agentObserverPolicy.treeNodeLimit)); upsertEnv(container.env, "HWLAB_AGENT_OBSERVER_INSPECTOR_EVENT_TAIL_LIMIT", String(agentObserverPolicy.inspectorEventTailLimit)); upsertEnv(container.env, "HWLAB_AGENT_OBSERVER_VIRTUAL_LIST_WINDOW_LIMIT", String(agentObserverPolicy.virtualListWindowLimit)); upsertEnv(container.env, "HWLAB_AGENT_OBSERVER_CHANGE_HIGHLIGHT_MS", String(agentObserverPolicy.changeHighlightMs)); upsertEnv(container.env, "HWLAB_AGENT_OBSERVER_STALE_AFTER_MS", String(agentObserverPolicy.staleAfterMs)); upsertEnv(container.env, "HWLAB_AGENT_OBSERVER_REDUCED_MOTION", String(agentObserverPolicy.reducedMotion)); if (serviceId === "hwlab-cloud-api") { upsertEnv(container.env, "HWLAB_WORKBENCH_KAFKA_REFRESH_REPLAY_GROUP_PREFIX", String(agentObserverPolicy.retentionGroupPrefix)); upsertEnv(container.env, "HWLAB_WORKBENCH_KAFKA_REFRESH_REPLAY_TIMEOUT_MS", String(agentObserverPolicy.retentionTimeoutMs)); upsertEnv(container.env, "HWLAB_WORKBENCH_KAFKA_REFRESH_REPLAY_SCAN_LIMIT", String(agentObserverPolicy.retentionScanLimit)); upsertEnv(container.env, "HWLAB_WORKBENCH_KAFKA_REFRESH_REPLAY_MATCHED_EVENT_LIMIT", String(agentObserverPolicy.retentionEventLimit)); upsertEnv(container.env, "HWLAB_WORKBENCH_KAFKA_REFRESH_REPLAY_LIVE_BUFFER_LIMIT", String(agentObserverPolicy.liveBufferLimit)); } if (serviceId === "hwlab-cloud-web") { upsertEnv(container.env, "HWLAB_AGENT_OBSERVER_NODE_ID", runtimeNodeIdForProfile(deploy, profile, nodeId)); upsertEnv(container.env, "HWLAB_AGENT_OBSERVER_LANE", profile); } } } if (runtimeLane && serviceId === "hwlab-edge-proxy") { useLocalHealthProbe(container, "/health"); } if (serviceId === "hwlab-cloud-api") { if (runtimeLane) { removeV02RepoOwnedCodeAgentPodConfig(item.spec, podTemplate.spec); applyServiceShutdownDrainLifecycle(container, deployService.shutdownDrain); upsertEnv(container.env, "HWLAB_M3_IO_CONTROL_ENABLED", "false"); upsertEnv(container.env, "HWLAB_CODE_AGENT_AGENTRUN_REPO_URL", gitReadUrl ?? defaultRuntimeLaneGitReadUrl); upsertEnv(container.env, "HWLAB_CODE_AGENT_AGENTRUN_PROVIDER_ID", runtimeNodeIdForProfile(deploy, profile, nodeId)); upsertEnv(container.env, "HWLAB_OPENFGA_MODE", "enforce"); upsertEnv(container.env, "HWLAB_OPENFGA_API_URL", `http://hwlab-openfga.${namespace}.svc.cluster.local:8080`); upsertEnvEntry(container.env, deployEnvEntry("HWLAB_OPENFGA_AUTHN_TOKEN", `secretRef:hwlab-${profile}-openfga/authn-preshared-key`, namespace, profile)); upsertEnv(container.env, "UNIDESK_MAIN_SERVER_IP", "http://74.48.78.17:18081"); } else { syncCodeAgentWorkspaceInitContainer(podTemplate.spec.initContainers, { image, runtimeCommit, runtimeImageTag }); } upsertEnv(container.env, "HWLAB_CODE_AGENT_DEFAULT_PROVIDER_PROFILE", runtimeLane ? (configString(runtimeLaneConfig(deploy, profile)?.opencode?.providerProfile) || "dsflash-go") : "deepseek"); if (runtimeLane) upsertEnv(container.env, "HWLAB_CODE_AGENT_CODEX_STDIO_SUPERVISOR", "repo-owned"); upsertEnv(container.env, "HWLAB_CODE_AGENT_DEEPSEEK_MODEL", deepSeekProfileModel); upsertEnv(container.env, "HWLAB_CODE_AGENT_DEEPSEEK_BASE_URL", deepSeekBaseUrl(namespace)); upsertEnv(container.env, "HWLAB_CODE_AGENT_CODEX_API_MODEL", codexApiProfileModel); upsertEnv(container.env, "HWLAB_CODE_AGENT_CODEX_API_BASE_URL", codexApiProfileBaseUrl); upsertEnv(container.env, "HWLAB_CODE_AGENT_CODEX_API_UPSTREAM_BASE_URL", codexApiForwarderUpstreamBaseUrl); upsertEnv(container.env, "HWLAB_CODE_AGENT_CODEX_API_FORWARDER_PORT", codexApiForwarderPort); upsertEnv(container.env, "HWLAB_PREINSTALLED_SKILLS_DIR", "/app/skills"); upsertEnv(container.env, "HWLAB_USER_SKILLS_DIR", "/data/user-skills"); upsertEnv(container.env, "HWLAB_CODE_AGENT_SKILLS_DIRS", "/app/skills:/data/user-skills"); upsertEnv(container.env, "NO_PROXY", codeAgentNoProxy(namespace)); upsertEnv(container.env, "no_proxy", codeAgentNoProxy(namespace)); } if (serviceId === "hwlab-cloud-web") { upsertEnv(container.env, "HWLAB_API_BASE_URL", `http://hwlab-cloud-api.${namespace}.svc.cluster.local:6667`); upsertEnv(container.env, "HWLAB_PUBLIC_ENDPOINT", webEndpoint); const traceTimelinePolicy = runtimeWorkbenchTraceTimelinePolicy(deploy, profile); if (typeof traceTimelinePolicy?.autoExpandRunning === "boolean") { upsertEnv(container.env, "HWLAB_WORKBENCH_TRACE_AUTO_EXPAND_RUNNING", booleanEnv(traceTimelinePolicy.autoExpandRunning)); } if (typeof traceTimelinePolicy?.autoCollapseTerminal === "boolean") { upsertEnv(container.env, "HWLAB_WORKBENCH_TRACE_AUTO_COLLAPSE_TERMINAL", booleanEnv(traceTimelinePolicy.autoCollapseTerminal)); } const rawHwlabEventWindowPolicy = runtimeWorkbenchRawHwlabEventWindowPolicy(deploy, profile); if (rawHwlabEventWindowPolicy) { upsertEnv(container.env, "HWLAB_WORKBENCH_RAW_HWLAB_EVENT_WINDOW_ENABLED", booleanEnv(rawHwlabEventWindowPolicy.enabled)); upsertEnv(container.env, "HWLAB_WORKBENCH_RAW_HWLAB_EVENT_WINDOW_MAX_ENTRIES", String(rawHwlabEventWindowPolicy.maxEntries)); upsertEnv(container.env, "HWLAB_WORKBENCH_RAW_HWLAB_EVENT_WINDOW_MAX_RETAINED_BYTES", String(rawHwlabEventWindowPolicy.maxRetainedBytes)); } const traceExplorerUrlTemplate = runtimeTraceExplorerUrlTemplate(deploy, profile); if (traceExplorerUrlTemplate) { upsertEnv(container.env, "HWLAB_WORKBENCH_TRACE_EXPLORER_URL_TEMPLATE", traceExplorerUrlTemplate); } } } rewritePodSecretRefs(podTemplate.spec, profile); } return result; } function transformHealthContract(value, namespace, labels, annotations, runtimeEndpoint, webEndpoint, profile = "dev") { const result = transformListNamespace(value, namespace, labels, annotations); if (result.metadata?.name === "hwlab-dev-health-contract") { result.metadata.name = `hwlab-${profile}-health-contract`; } if (result.metadata?.labels && Object.hasOwn(result.metadata.labels, "app.kubernetes.io/name")) { result.metadata.labels["app.kubernetes.io/name"] = `hwlab-${profile}-health-contract`; } if (result.data && typeof result.data === "object") { if (Object.hasOwn(result.data, "endpoint")) result.data.endpoint = runtimeEndpoint; if (Object.hasOwn(result.data, "cloud-web")) { result.data["cloud-web"] = `GET /health/live on ${webEndpoint}; consumes cloud-api only`; } if (Object.hasOwn(result.data, "cloud-api")) { result.data["cloud-api"] = `GET /health/live through ${runtimeEndpoint}`; } if (Object.hasOwn(result.data, "tunnel-client")) { result.data["tunnel-client"] = "disabled for node GitOps; no FRP or production traffic tunnel is required"; } } return result; } function transformListNamespace(value, namespace, labels, annotations) { const result = cloneJson(value); if (result.kind === "List") { for (const item of result.items ?? []) { item.metadata ??= {}; item.metadata.namespace = namespace; label(item.metadata, labels); annotate(item.metadata, annotations); } } else { result.metadata ??= {}; result.metadata.namespace = namespace; label(result.metadata, labels); annotate(result.metadata, annotations); } return result; } function transformServices({ services, namespace, labels, annotations, profile = "dev", deploy = null, nodeId = "node" }) { const observableServiceIds = isRuntimeLane(profile) ? runtimeLaneObservableServiceIdsForDeploy(deploy, profile) : new Set(); const result = transformListNamespace(services, namespace, labels, annotations); if (result.kind === "List") { result.items = (result.items ?? []).filter((item) => !(isRuntimeLane(profile) && isV02RemovedServiceId(serviceIdForWorkload(item, null)))); for (const item of result.items) { const serviceId = serviceIdForWorkload(item, null); if (!isRuntimeLane(profile) || !observableServiceIds.has(serviceId)) continue; label(item.metadata ??= {}, v02MetricsLabels(serviceId)); upsertV02MetricsPort(item); } const nodePublicServices = deploy?.lanes?.[profile]?.publicServices?.nodes?.[nodeId]; assert.ok(nodePublicServices === undefined || Array.isArray(nodePublicServices), `deploy.lanes.${profile}.publicServices.nodes.${nodeId} must be an array`); for (const service of nodePublicServices ?? []) { assert.ok(service && typeof service === "object" && !Array.isArray(service), `deploy.lanes.${profile}.publicServices.nodes.${nodeId} entries must be objects`); assert.ok(typeof service.name === "string" && service.name.length > 0, `deploy.lanes.${profile}.publicServices.nodes.${nodeId}[].name is required`); assert.ok(service.selector && typeof service.selector === "object" && !Array.isArray(service.selector), `deploy.lanes.${profile}.publicServices.nodes.${nodeId}[].selector is required`); for (const key of ["port", "targetPort", "nodePort"]) { assert.ok(Number.isInteger(service[key]) && service[key] > 0, `deploy.lanes.${profile}.publicServices.nodes.${nodeId}[].${key} must be a positive integer`); } result.items.push({ apiVersion: "v1", kind: "Service", metadata: { name: service.name, namespace, labels: { ...labels, "app.kubernetes.io/name": service.name }, annotations: { ...annotations } }, spec: { type: "NodePort", selector: cloneJson(service.selector), ports: [{ name: "http", port: service.port, targetPort: service.targetPort, nodePort: service.nodePort }] } }); } } return result; } function observabilityManifest({ deploy, profile, namespace, labels, annotations, metricsSidecarScript }) { assert.ok(isRuntimeLane(profile), `observability profile must be a runtime lane, got ${profile}`); const includePrometheusOperatorResources = runtimePrometheusOperatorResourcesEnabled(deploy, profile); const baseLabels = { ...labels, "app.kubernetes.io/part-of": "hwlab", "hwlab.pikastech.local/monitoring": "enabled" }; const serviceMonitors = runtimeLaneObservableServicesForDeploy(deploy, profile).map((service) => ({ apiVersion: "monitoring.coreos.com/v1", kind: "ServiceMonitor", metadata: { name: `hwlab-${profile}-${service.serviceId}`, namespace, labels: { ...baseLabels, "hwlab.pikastech.local/service-id": service.serviceId }, annotations }, spec: { namespaceSelector: { matchNames: [namespace] }, selector: { matchLabels: { "hwlab.pikastech.local/gitops-target": profile, "hwlab.pikastech.local/monitoring": "enabled", "hwlab.pikastech.local/service-id": service.serviceId } }, targetLabels: [ "hwlab.pikastech.local/gitops-target", "hwlab.pikastech.local/service-id" ], endpoints: [{ port: "metrics", path: "/metrics", interval: "30s", scrapeTimeout: "10s" }] } })); return { apiVersion: "v1", kind: "List", items: [ { apiVersion: "v1", kind: "ConfigMap", metadata: { name: `hwlab-${profile}-metrics-sidecar`, namespace, labels: baseLabels, annotations }, data: { "metrics-sidecar.mjs": metricsSidecarScript } }, ...(includePrometheusOperatorResources ? serviceMonitors : []), ...(includePrometheusOperatorResources ? [{ apiVersion: "monitoring.coreos.com/v1", kind: "PrometheusRule", metadata: { name: `hwlab-${profile}-observability`, namespace, labels: baseLabels, annotations }, spec: { groups: [{ name: `hwlab-${profile}-observability`, rules: [ { alert: `HWLAB${profile.toUpperCase()}MetricsTargetDown`, expr: `up{namespace="${namespace}"} == 0`, for: "5m", labels: { severity: "warning", lane: profile }, annotations: { summary: `HWLAB ${versionNameForRuntimeLane(profile)} metrics target is down`, description: `Prometheus cannot scrape a HWLAB ${versionNameForRuntimeLane(profile)} metrics target.` } }, { alert: `HWLAB${profile.toUpperCase()}ServiceHealthProbeFailed`, expr: `hwlab_service_health_probe_success{namespace="${namespace}"} == 0`, for: "5m", labels: { severity: "warning", lane: profile }, annotations: { summary: "HWLAB v0.2 service health probe failed", description: "The metrics sidecar cannot reach the service health endpoint inside the pod network." } } ] }] } }] : []) ] }; } export { applyDeployConfigMapMounts, applyDeployEnv, applyDeployServiceReplicas, applyEnvReuseBootEnv, applyEnvReuseStartupProbe, applyRuntimeLaneDeployConfig, argoApplicationName, artifactCatalogSkeleton, artifactEndpoint, artifactEnvironment, asItems, attachAccessControlEnv, annotate, booleanEnv, bootMetadataForService, bootShForService, boundedInteger, buildkitRunnerImage, catalogServiceById, ciToolsRunnerImage, cloneJson, codeAgentNoProxy, codexApiForwarderPort, codexApiForwarderUpstreamBaseUrl, codexApiProfileBaseUrl, codexApiProfileModel, configObject, configString, deepSeekBaseUrl, deepSeekProfileModel, defaultAllProxyUrl, defaultBranch, defaultCatalogPath, defaultDevBaseImage, defaultEndpointForRuntimeLane, defaultGitopsBranch, defaultGitReadUrl, defaultNoProxy, defaultOutDir, defaultPortForRuntimeLane, defaultProdRuntimeEndpoint, defaultProdWebEndpoint, defaultProxyUrl, defaultRegistryPrefix, defaultRuntimeEndpoint, defaultRuntimeLaneGitReadUrl, defaultRuntimeLaneGitWriteUrl, defaultServiceIds, defaultSourceRepo, defaultV02GitReadUrl, defaultV02GitWriteUrl, defaultV02RuntimeEndpoint, defaultV02WebEndpoint, defaultWebEndpoint, deployEnvEntry, deployServiceForBoot, deployServicesForProfile, digestPinnedImage, effectiveSecretPlaneNodeId, ensureObject, envReuseBootShForContainer, envReuseServiceIdsForLane, generatedPath, gitopsPathFor, gitopsPathForProfile, gitopsRootForArgs, gitopsRootNodeId, gitopsTargetForProfile, gitValue, imageFor, imageTagForSource, imageTagFromReference, isRuntimeLane, isV02RemovedServiceId, jsonManifest, k8sLabelHash, label, laneNames, laneRuntimeProfiles, mergeEnvMaps, moonBridgeImage, moonBridgeSourceRef, namespaceNameForProfile, namespaceScopedHost, normalizeAccessControlUser, normalizeNavProfile, normalizeProbeTiming, observabilityManifest, optionalConfigString, optionalObject, parseArgs, primitiveValidationTasks, profileEndpoint, proxyEnv, readConfigRef, readJson, readJsonIfPresent, readOption, readStructuredFile, removeV02LegacySimulatorEnv, repoRoot, removeV02RepoOwnedCodeAgentPodConfig, repositoryFromImage, requiredAccessConfigString, requiredConfigPositiveInteger, requiredConfigString, resolveSourceRevision, rewritePodSecretRefs, runtimeArtifactForService, runtimeCommitForService, runtimeFrpConfigForProfile, runtimeImageForService, runtimeImageTagForService, runtimeLabelForProfile, runtimeLaneConfig, runtimeLaneMirrorSpecs, runtimeLaneObservableService, runtimeLaneObservableServiceIdsForDeploy, runtimeLaneObservableServicesForDeploy, runtimeLaneServiceIdsFromDeploy, runtimeNodeIdForProfile, runtimePathForProfile, runtimePrometheusOperatorResourcesEnabled, runtimeStoreEnvForProfile, runtimeTraceExplorerUrlTemplate, runtimeWorkbenchTraceTimelinePolicy, secretNameForProfile, secretRefFromParts, secretRefObjectForProfile, serviceDeclarationEnvForProfile, serviceIdForWorkload, serviceIdsForLane, serviceIdsForProfile, servicesParamForLane, sourceCommitPattern, syncCodeAgentWorkspaceInitContainer, textFile, transformHealthContract, transformListNamespace, transformServices, transformWorkloads, uniquePreserveOrder, upsertEnv, upsertEnvEntry, upsertV02MetricsPort, upsertV02MetricsSidecar, usage, useLocalHealthProbe, v02EnvReuseEnabled, v02EnvReuseRuntimeMode, v02ExtraObservableServices, v02MetricsLabels, v02MetricsSidecarAnnotations, v02MetricsSidecarContainer, v02MetricsSidecarVolume, v02ObservableService, v02ObservableServiceIdsForDeploy, v02ObservableServicesForDeploy, v02RemovedServiceEnvNames, v02RemovedServiceIds, v02ServiceIdsFromDeploy, versionNameForRuntimeLane, workbenchRuntimeClientEnvForProfile, workbenchRuntimeFactsQueryEnvForProfile, workbenchRuntimePostgresEnvForProfile, workbenchRuntimeRedisConfigForProfile, workbenchRuntimeRedisEnvForProfile, workbenchRuntimeSessionsSummaryEnvForProfile };