fix: reuse agent worker env image in v02 ci

This commit is contained in:
Codex
2026-06-01 22:28:52 +08:00
parent d4c05d7963
commit 0fb8004896
8 changed files with 162 additions and 20 deletions
+2
View File
@@ -136,10 +136,12 @@
"imageTagMode": "full",
"envReuseServices": [
"hwlab-cloud-web",
"hwlab-agent-worker",
"hwlab-device-pod"
],
"bootScripts": {
"hwlab-cloud-web": "deploy/runtime/boot/hwlab-cloud-web.sh",
"hwlab-agent-worker": "deploy/runtime/boot/hwlab-agent-worker.sh",
"hwlab-device-pod": "deploy/runtime/boot/hwlab-device-pod.sh"
},
"services": [
+29
View File
@@ -0,0 +1,29 @@
#!/bin/sh
set -eu
export HWLAB_SERVICE_ID="hwlab-agent-worker"
export HWLAB_RUNTIME_MODE="${HWLAB_RUNTIME_MODE:-env-reuse-git-mirror-checkout}"
export HWLAB_COMMIT_ID="${HWLAB_BOOT_COMMIT:?HWLAB_BOOT_COMMIT is required}"
export HWLAB_REVISION="${HWLAB_BOOT_COMMIT}"
export HWLAB_IMAGE="${HWLAB_ENVIRONMENT_IMAGE:-${HWLAB_IMAGE:-}}"
export HWLAB_IMAGE_DIGEST="${HWLAB_ENVIRONMENT_DIGEST:-${HWLAB_IMAGE_DIGEST:-unknown}}"
bun_bin="${HWLAB_BUN_COMMAND:-}"
if [ -z "$bun_bin" ]; then
if command -v bun >/dev/null 2>&1; then
bun_bin="$(command -v bun)"
elif [ -x /usr/local/bin/bun ]; then
bun_bin="/usr/local/bin/bun"
elif [ -x ./node_modules/.bin/bun ]; then
bun_bin="./node_modules/.bin/bun"
else
echo "hwlab-agent-worker boot failed: bun not found" >&2
exit 127
fi
fi
if [ "$#" -eq 0 ]; then
set -- health
fi
exec "$bun_bin" cmd/hwlab-agent-worker/main.ts "$@"
+2 -2
View File
@@ -115,7 +115,7 @@ devops-infra git mirror 仍是 PipelineRun 和 Argo CD 的集群内读写源。`
5. affected service 通过 BuildKit 发布到 G14 本地 registryreused service 复用 catalog digest。
所有 selected service 的 build TaskRun 都只依赖 `plan-artifacts`,不按 service 串行排队,也不设置 8 并发或其他 Pipeline 级限流。
实际并发由 Tekton controller、G14 节点资源、PVC I/O、BuildKit sidecar 和本地 registry 承载能力决定。
`hwlab-cloud-web``hwlab-device-pod` 必须使用 `env-reuse-git-mirror-checkout`
`hwlab-cloud-web``hwlab-agent-worker``hwlab-device-pod` 必须使用 `env-reuse-git-mirror-checkout`
只有 package/runtime/env 输入变化时才构建 `<service>-env` 镜像。
纯前端源码、Device Pod 源码或 boot code 变化只更新三变量和 GitOps desired state
不再重新构建业务镜像。
@@ -200,7 +200,7 @@ Git 读写都走 `devops-infra` 本地 mirror/relay。读路径用 HTTP mirror c
任何仍需要访问 GitHub canonical remote 的 SSH 操作都必须显式走 G14 proxy。Host SSH config 可以使用 OpenBSD `nc -X connect -x 127.0.0.1:10808 %h %p`Tekton `GIT_SSH_COMMAND`、git-mirror `sync`/`flush` 和其他容器内 `git@github.com``ssh://git@ssh.github.com:443` 路径必须使用 repo-owned Node HTTP CONNECT ProxyCommand,并保留短 `ConnectTimeout``ServerAlive*`。只改 `HTTP_PROXY`/`HTTPS_PROXY` 对 OpenSSH 无效;BusyBox `nc` 不支持 `-X connect`,不得再把 `ssh.github.com:443` 当作等价 proxy 或让 GitHub SSH 直连反复 60s 超时。
env image 复用把系统依赖和业务代码身份分离。`environmentDigest` 表示可复用运行环境,`HWLAB_BOOT_REPO``HWLAB_BOOT_COMMIT``HWLAB_BOOT_SH` 表示本次代码启动身份。code-only 变更只更新 boot metadata 和 runtime identity,不发布新 env image;只有真实 env 输入变化或缺少可复用 env digest 时才进入 env rebuild。`package.json` 只按 dependency/runtime 字段参与 env/runtime hash`scripts` 只属于开发入口,不得因为清理旧门禁脚本而重建所有 service 或重建 env image。
env image 复用把系统依赖和业务代码身份分离。`environmentDigest` 表示可复用运行环境,`HWLAB_BOOT_REPO``HWLAB_BOOT_COMMIT``HWLAB_BOOT_SH` 表示本次代码启动身份。code-only 变更只更新 boot metadata 和 runtime identity,不发布新 env image;只有真实 env 输入变化或缺少可复用 env digest 时才进入 env rebuild。`hwlab-agent-worker` 是 suspended Job template,也必须复用 env imageworker 代码变化只能更新 boot commit 和 Job template identity,不能重新构建 `hwlab-agent-worker` service image。`package.json` 只按 dependency/runtime 字段参与 env/runtime hash`scripts` 只属于开发入口,不得因为清理旧门禁脚本而重建所有 service 或重建 env image。
BuildKit publish 采用 service 级全并行 fan-out。
每个 service build task 拥有独立 BuildKit sidecar、独立 service workdir 和独立 report 文件,均从同一 `plan-artifacts` 结果判断是否需要执行。
@@ -13,6 +13,7 @@
- `cmd/hwlab-agent-worker/main.ts` 提供 CLI 命令 `health``dry-run/smoke`
- `internal/agent/runtime.mjs` 提供 `runLocalWorkerDryRun`,读取 manager 创建的本地 session 状态并写入 evidence。
- Job template 通过 env 注入 `HWLAB_AGENT_SESSION_ID``HWLAB_SKILL_COMMIT_ID``HWLAB_SKILL_VERSION`
- v0.2 CI/CD 中 worker 使用 `env-reuse-git-mirror-checkout`:环境镜像只承载 runtime、依赖、launcher 和 git client,实际 worker 代码由 `HWLAB_BOOT_REPO``HWLAB_BOOT_COMMIT``HWLAB_BOOT_SH=deploy/runtime/boot/hwlab-agent-worker.sh``devops-infra` git mirror checkout 后启动。worker code-only 变更不得触发 `hwlab-agent-worker` service image BuildKit 重建,只允许更新 boot commit 和 Job template identity。
## API 接口说明
@@ -38,6 +39,7 @@
| --- | --- | --- |
| CLI health/dry-run | 已实现 | worker 以 JSON 输出。 |
| suspended Job template | 已实现 | runtime-v02 中存在 `hwlab-agent-worker-template`。 |
| v0.2 env-reuse 启动 | 已实现 | `deploy/runtime/boot/hwlab-agent-worker.sh` 通过 git mirror checkout 后执行 worker CLIcode-only 变更复用 env image。 |
| session-scoped evidence 写入 | 已实现 | 本地 dry-run 覆盖 trace/evidence。 |
| 长驻 HTTP API | 不适用 | worker 不是长驻服务。 |
| 生产调度与真实执行 | 未完全实现 | 当前仍是 skeleton/dry-run 模式。 |
+107 -4
View File
@@ -354,6 +354,98 @@ test("v02 planner marks cloud-web code-only change as env reuse rollout", async
assert.equal(plan.ciCdPlan.noImageBuildReason, "env-reuse-code-only-rollout");
});
test("v02 planner marks agent-worker code-only change as env reuse rollout", async () => {
const repo = await createFixtureRepo({ includeDevicePod: true, includeAgentWorker: true });
const initialSha = (await git(repo, ["rev-parse", "HEAD"])).stdout.trim();
const initialPlan = await createG14CiPlan({
repoRoot: repo,
lane: "v02",
baseRef: "HEAD",
targetRef: initialSha,
artifactCatalogPath: "deploy/artifact-catalog.v02.json",
services: ["hwlab-agent-worker"]
});
const initialWorker = initialPlan.services.find((service) => service.serviceId === "hwlab-agent-worker");
await writeFile(path.join(repo, "deploy/artifact-catalog.v02.json"), JSON.stringify(createCatalogFixture("ready", {
agentWorkerEnvironmentInputHash: initialWorker.environmentInputHash,
agentWorkerCodeInputHash: initialWorker.codeInputHash,
agentWorkerBootCommit: initialPlan.sourceCommitId
}), null, 2));
await git(repo, ["add", "deploy/artifact-catalog.v02.json"]);
await git(repo, ["commit", "-m", "seed v02 worker catalog"]);
await writeFile(path.join(repo, "cmd/hwlab-agent-worker/main.ts"), "console.log('worker v2');\n");
await git(repo, ["add", "."]);
await git(repo, ["commit", "-m", "change agent worker code"]);
const plan = await createG14CiPlan({
repoRoot: repo,
lane: "v02",
baseRef: "HEAD~1",
targetRef: "HEAD",
artifactCatalogPath: "deploy/artifact-catalog.v02.json",
services: ["hwlab-agent-worker"]
});
const worker = plan.services.find((service) => service.serviceId === "hwlab-agent-worker");
assert.equal(worker.runtimeMode, "env-reuse-git-mirror-checkout");
assert.equal(worker.envChanged, false);
assert.equal(worker.codeChanged, true);
assert.equal(worker.buildRequired, false);
assert.equal(worker.bootSh, "deploy/runtime/boot/hwlab-agent-worker.sh");
assert.deepEqual(plan.affectedServices, ["hwlab-agent-worker"]);
assert.deepEqual(plan.rolloutServices, ["hwlab-agent-worker"]);
assert.deepEqual(plan.buildServices, []);
assert.equal(plan.imageBuildRequired, false);
assert.equal(plan.ciCdPlan.noImageBuildReason, "env-reuse-code-only-rollout");
});
test("v02 planner rebuilds agent-worker env image only for runtime dependency changes", async () => {
const repo = await createFixtureRepo({ includeDevicePod: true, includeAgentWorker: true });
const initialSha = (await git(repo, ["rev-parse", "HEAD"])).stdout.trim();
const initialPlan = await createG14CiPlan({
repoRoot: repo,
lane: "v02",
baseRef: "HEAD",
targetRef: initialSha,
artifactCatalogPath: "deploy/artifact-catalog.v02.json",
services: ["hwlab-agent-worker"]
});
const initialWorker = initialPlan.services.find((service) => service.serviceId === "hwlab-agent-worker");
await writeFile(path.join(repo, "deploy/artifact-catalog.v02.json"), JSON.stringify(createCatalogFixture("ready", {
agentWorkerEnvironmentInputHash: initialWorker.environmentInputHash,
agentWorkerCodeInputHash: initialWorker.codeInputHash,
agentWorkerBootCommit: initialPlan.sourceCommitId
}), null, 2));
await git(repo, ["add", "deploy/artifact-catalog.v02.json"]);
await git(repo, ["commit", "-m", "seed v02 worker catalog"]);
await writeFile(path.join(repo, "package.json"), JSON.stringify({
type: "module",
dependencies: {
"@openai/codex": "^0.129.0"
}
}, null, 2));
await git(repo, ["add", "package.json"]);
await git(repo, ["commit", "-m", "change worker env dependency"]);
const plan = await createG14CiPlan({
repoRoot: repo,
lane: "v02",
baseRef: "HEAD~1",
targetRef: "HEAD",
artifactCatalogPath: "deploy/artifact-catalog.v02.json",
services: ["hwlab-agent-worker"]
});
const worker = plan.services.find((service) => service.serviceId === "hwlab-agent-worker");
assert.equal(worker.runtimeMode, "env-reuse-git-mirror-checkout");
assert.equal(worker.envChanged, true);
assert.equal(worker.buildRequired, true);
assert.deepEqual(plan.affectedServices, ["hwlab-agent-worker"]);
assert.deepEqual(plan.buildServices, ["hwlab-agent-worker"]);
assert.ok(worker.reason.includes("environment-input-changed"));
assert.ok(worker.reason.includes("runtime-deps-changed"));
});
test("v02 planner keeps hwlab-cli-only changes out of runtime service builds", async () => {
const repo = await createFixtureRepo({ includeDevicePod: true });
const initialSha = (await git(repo, ["rev-parse", "HEAD"])).stdout.trim();
@@ -458,9 +550,11 @@ async function createFixtureRepo(options = {}) {
const deployServices = options.deployServices !== false;
const k3sServiceMappings = options.k3sServiceMappings === true;
const includeDevicePod = options.includeDevicePod === true;
const includeAgentWorker = options.includeAgentWorker === true;
const repo = await mkdtemp(path.join(os.tmpdir(), "hwlab-g14-ci-plan-"));
await mkdir(path.join(repo, "cmd/hwlab-cloud-api"), { recursive: true });
await mkdir(path.join(repo, "cmd/hwlab-deepseek-responses-bridge"), { recursive: true });
await mkdir(path.join(repo, "cmd/hwlab-agent-worker"), { recursive: true });
await mkdir(path.join(repo, "web/hwlab-cloud-web"), { recursive: true });
await mkdir(path.join(repo, "internal/dev-entrypoint"), { recursive: true });
await mkdir(path.join(repo, "internal/device-pod"), { recursive: true });
@@ -479,6 +573,7 @@ async function createFixtureRepo(options = {}) {
await writeFile(path.join(repo, "cmd/hwlab-cloud-api/main.ts"), "console.log('api');\n");
await writeFile(path.join(repo, "cmd/hwlab-deepseek-responses-bridge/main.ts"), "console.log('bridge');\n");
await writeFile(path.join(repo, "cmd/hwlab-deepseek-responses-bridge/main.test.ts"), "console.log('test');\n");
await writeFile(path.join(repo, "cmd/hwlab-agent-worker/main.ts"), "console.log('worker');\n");
await writeFile(path.join(repo, "web/hwlab-cloud-web/index.html"), "<html></html>\n");
await writeFile(path.join(repo, "internal/dev-entrypoint/artifact-runtime.mjs"), "export const artifactRuntime = 1;\n");
await writeFile(path.join(repo, "internal/dev-entrypoint/cloud-web-runtime.mjs"), "export const runtime = 1;\n");
@@ -493,6 +588,7 @@ async function createFixtureRepo(options = {}) {
await writeFile(path.join(repo, "skills/device-pod-cli/scripts/device-pod-cli.mjs"), "console.log('skill wrapper');\n");
await writeFile(path.join(repo, "skills/device-pod-cli/assets/device-host-cli.mjs"), "console.log('host cli');\n");
await writeFile(path.join(repo, "deploy/runtime/boot/hwlab-cloud-web.sh"), "#!/bin/sh\nbun run --cwd web/hwlab-cloud-web build\nexec bun .hwlab-cloud-web-runtime.mjs\n");
await writeFile(path.join(repo, "deploy/runtime/boot/hwlab-agent-worker.sh"), "#!/bin/sh\nexec bun cmd/hwlab-agent-worker/main.ts \"$@\"\n");
await writeFile(path.join(repo, "deploy/runtime/boot/hwlab-device-pod.sh"), "#!/bin/sh\nexec bun cmd/hwlab-device-pod/main.ts\n");
await writeFile(path.join(repo, "deploy/runtime/launcher/hwlab-env-reuse-launcher.ts"), "console.log('launcher');\n");
await writeFile(path.join(repo, "skills/hwlab-agent-runtime/SKILL.md"), "agent runtime skill\n");
@@ -506,7 +602,7 @@ async function createFixtureRepo(options = {}) {
baseRef: "HEAD",
targetRef: "HEAD",
artifactCatalogPath: "deploy/nonexistent-artifact-catalog.json",
services: ["hwlab-cloud-api", "hwlab-cloud-web", ...(includeDevicePod ? ["hwlab-device-pod"] : [])]
services: ["hwlab-cloud-api", "hwlab-cloud-web", ...(includeAgentWorker ? ["hwlab-agent-worker"] : []), ...(includeDevicePod ? ["hwlab-device-pod"] : [])]
});
const componentInputHashes = Object.fromEntries(initialPlan.services.map((service) => [service.serviceId, service.componentInputHash]));
const catalog = createCatalogFixture(catalogMode, { sourceCommitId: initialSha, componentInputHashes });
@@ -541,9 +637,10 @@ function createDeployFixture({ deployServices, k3sServiceMappings, includeDevice
lanes: {
v02: {
sourceRepo: "git@github.com:pikasTech/HWLAB.git",
envReuseServices: ["hwlab-cloud-web", "hwlab-device-pod"],
envReuseServices: ["hwlab-cloud-web", "hwlab-agent-worker", "hwlab-device-pod"],
bootScripts: {
"hwlab-cloud-web": "deploy/runtime/boot/hwlab-cloud-web.sh",
"hwlab-agent-worker": "deploy/runtime/boot/hwlab-agent-worker.sh",
"hwlab-device-pod": "deploy/runtime/boot/hwlab-device-pod.sh"
}
}
@@ -571,7 +668,7 @@ function createDeployFixture({ deployServices, k3sServiceMappings, includeDevice
function createCatalogFixture(mode, options = {}) {
const digest = mode === "ready" ? `sha256:${"1".repeat(64)}` : "not_published";
return {
services: ["hwlab-cloud-api", "hwlab-cloud-web", "hwlab-device-pod"].map((serviceId) => ({
services: ["hwlab-cloud-api", "hwlab-cloud-web", "hwlab-agent-worker", "hwlab-device-pod"].map((serviceId) => ({
serviceId,
commitId: "abc1234",
sourceCommitId: options.sourceCommitId ?? "abc1234",
@@ -581,20 +678,26 @@ function createCatalogFixture(mode, options = {}) {
...((options.componentInputHashes?.[serviceId] || (serviceId === "hwlab-cloud-api" && options.cloudApiComponentInputHash)) ? {
componentInputHash: options.cloudApiComponentInputHash ?? options.componentInputHashes?.[serviceId]
} : {}),
...((serviceId === "hwlab-cloud-web" || serviceId === "hwlab-device-pod") ? {
...((serviceId === "hwlab-cloud-web" || serviceId === "hwlab-agent-worker" || serviceId === "hwlab-device-pod") ? {
runtimeMode: "env-reuse-git-mirror-checkout",
envReuse: true,
environmentImage: `127.0.0.1:5000/hwlab/${serviceId}-env:env-abc1234`,
environmentDigest: digest,
environmentInputHash: serviceId === "hwlab-cloud-web"
? options.cloudWebEnvironmentInputHash ?? "e".repeat(64)
: serviceId === "hwlab-agent-worker"
? options.agentWorkerEnvironmentInputHash ?? "e".repeat(64)
: options.devicePodEnvironmentInputHash ?? "e".repeat(64),
codeInputHash: serviceId === "hwlab-cloud-web"
? options.cloudWebCodeInputHash ?? "c".repeat(64)
: serviceId === "hwlab-agent-worker"
? options.agentWorkerCodeInputHash ?? "c".repeat(64)
: options.devicePodCodeInputHash ?? "c".repeat(64),
bootRepo: "git@github.com:pikasTech/HWLAB.git",
bootCommit: serviceId === "hwlab-cloud-web"
? options.cloudWebBootCommit ?? "abc1234"
: serviceId === "hwlab-agent-worker"
? options.agentWorkerBootCommit ?? "abc1234"
: options.devicePodBootCommit ?? "abc1234",
bootSh: `deploy/runtime/boot/${serviceId}.sh`
} : {})
+12 -10
View File
@@ -416,7 +416,8 @@ function catalogServiceById(catalog, serviceId) {
return (catalog?.services ?? []).find((service) => service?.serviceId === serviceId) ?? null;
}
function v02EnvReuseEnabled(catalog, serviceId) {
function v02EnvReuseEnabled(catalog, serviceId, envReuseServiceIds = null) {
if (envReuseServiceIds?.has(serviceId)) return true;
const service = catalogServiceById(catalog, serviceId);
return service?.runtimeMode === v02EnvReuseRuntimeMode || service?.envReuse === true;
}
@@ -458,17 +459,17 @@ function bootMetadataForService({ args, catalog, deployService, serviceId, sourc
};
}
function runtimeArtifactForService({ catalog, serviceId, source, registryPrefix, useDeployImages = false, digestPin = false }) {
function runtimeArtifactForService({ catalog, deploy, serviceId, source, registryPrefix, useDeployImages = false, digestPin = false, envReuseServiceIds = null }) {
const catalogService = catalogServiceById(catalog, serviceId);
if (catalogService?.runtimeMode === v02EnvReuseRuntimeMode || catalogService?.envReuse === true) {
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;
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: catalogService.bootCommit ?? source.full,
commit: catalogService?.bootCommit ?? source.full,
runtimeMode: v02EnvReuseRuntimeMode,
environmentDigest: catalogService.environmentDigest ?? catalogService.digest ?? null
environmentDigest: catalogService?.environmentDigest ?? catalogService?.digest ?? null
};
}
const fallbackImageTag = source.imageTag ?? source.short;
@@ -753,6 +754,7 @@ function transformWorkloads({ workloads, deploy, catalog, source, sourceBranch =
const profileLabel = runtimeLabelForProfile(profile);
const gitopsTarget = gitopsTargetForProfile(profile);
const digestPin = profile === "v02";
const envReuseServiceIds = envReuseServiceIdsForLane(deploy, profile);
const stableRuntimeLabels = {
"app.kubernetes.io/part-of": "hwlab",
"hwlab.pikastech.local/environment": profileLabel,
@@ -784,7 +786,7 @@ function transformWorkloads({ workloads, deploy, catalog, source, sourceBranch =
const podTemplate = item?.spec?.template;
if (!podTemplate?.spec?.containers) continue;
const templateServiceId = serviceIdForWorkload(item, podTemplate.spec.containers[0]);
const templateArtifact = runtimeArtifactForService({ catalog, serviceId: templateServiceId, source, registryPrefix, useDeployImages, digestPin });
const templateArtifact = runtimeArtifactForService({ catalog, deploy, serviceId: templateServiceId, source, registryPrefix, useDeployImages, digestPin, envReuseServiceIds });
const templateSourceCommit = profile === "v02" ? (templateArtifact.commit ?? source.full) : source.full;
const templateArtifactCommit = templateArtifact.commit;
label(podTemplate.metadata ??= {}, {
@@ -808,8 +810,8 @@ function transformWorkloads({ workloads, deploy, catalog, source, sourceBranch =
const serviceId = serviceIdForWorkload(item, container);
const deployService = deployServices.get(serviceId);
if (!deployService) continue;
const artifact = runtimeArtifactForService({ catalog, serviceId, source, registryPrefix, useDeployImages, digestPin });
const envReuse = profile === "v02" && v02EnvReuseEnabled(catalog, serviceId);
const artifact = runtimeArtifactForService({ catalog, deploy, serviceId, source, registryPrefix, useDeployImages, digestPin, envReuseServiceIds });
const envReuse = profile === "v02" && v02EnvReuseEnabled(catalog, serviceId, envReuseServiceIds);
const bootMetadata = envReuse ? bootMetadataForService({ args: { sourceRepo: deploy?.lanes?.v02?.sourceRepo || defaultSourceRepo, registryPrefix }, catalog, deployService, serviceId, source }) : null;
const image = artifact.image;
const runtimeCommit = artifact.commit;
+8 -2
View File
@@ -229,9 +229,15 @@ test("v02 render follows TypeScript runtime checks and does not self-patch boots
assert.ok(cloudApi, "expected v02 hwlab-cloud-api workload");
const cloudApiEnv = cloudApi.spec.template.spec.containers[0].env;
assert.ok(cloudApiEnv.some((entry) => entry.name === "HWLAB_CODE_AGENT_AGENTRUN_SOURCE_COMMIT" && entry.value === sourceRevision));
const agentWorker = workloadsJson.items.find((item) => item.metadata?.name === "hwlab-agent-worker");
const agentWorker = workloadsJson.items.find((item) => item.metadata?.labels?.["hwlab.pikastech.local/service-id"] === "hwlab-agent-worker");
assert.ok(agentWorker, "expected v02 hwlab-agent-worker suspended Job template");
const agentWorkerEnv = agentWorker?.spec?.template?.spec?.containers?.[0]?.env ?? [];
assert.equal(agentWorkerEnv.some((entry) => entry.name === "HWLAB_BOOT_COMMIT"), false, "agent-worker must not be switched to env reuse by device-pod work");
assert.ok(agentWorkerEnv.some((entry) => entry.name === "HWLAB_RUNTIME_MODE" && entry.value === "env-reuse-git-mirror-checkout"));
assert.ok(agentWorkerEnv.some((entry) => entry.name === "HWLAB_BOOT_REPO" && entry.value === "git@github.com:pikasTech/HWLAB.git"));
assert.ok(agentWorkerEnv.some((entry) => entry.name === "HWLAB_BOOT_COMMIT" && entry.value === sourceRevision));
assert.ok(agentWorkerEnv.some((entry) => entry.name === "HWLAB_BOOT_SH" && entry.value === "deploy/runtime/boot/hwlab-agent-worker.sh"));
assert.equal(agentWorker?.spec?.template?.metadata?.annotations?.["hwlab.pikastech.local/runtime-mode"], "env-reuse-git-mirror-checkout");
assert.equal(agentWorker?.spec?.template?.metadata?.annotations?.["hwlab.pikastech.local/boot-commit"], sourceRevision);
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.equal(devicePod.spec.template.metadata.labels["hwlab.pikastech.local/source-commit"], sourceRevision);
-2
View File
@@ -83,8 +83,6 @@ const serviceSpecificPaths = Object.freeze({
"hwlab-agent-worker": [
"cmd/hwlab-agent-worker/",
"internal/agent/",
"internal/db/",
"internal/audit/",
"skills/hwlab-agent-runtime/"
],
"hwlab-device-pod": ["cmd/hwlab-device-pod/", "internal/device-pod/"],