refactor: make v0.3 runtime node-scoped

This commit is contained in:
Codex Agent
2026-06-08 22:19:30 +08:00
parent e8ab452b10
commit 187fb80a5d
38 changed files with 549 additions and 450 deletions
+29 -29
View File
@@ -14,7 +14,7 @@ import { fileURLToPath } from "node:url";
import { activeReportLifecycle } from "../internal/dev-report-lifecycle.mjs";
import { ENVIRONMENT_DEV, SERVICE_IDS } from "../internal/protocol/index.mjs";
import { createG14CiPlan } from "./src/g14-ci-plan-lib.mjs";
import { createCiPlan } from "./src/ci-plan-lib.mjs";
import {
BUILDABLE_IMPLEMENTATION_STATES,
resolveDevArtifactServices,
@@ -26,7 +26,7 @@ import { readStructuredFile } from "./src/structured-config.mjs";
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
const cliEntrypoint = process.env.HWLAB_ARTIFACT_PUBLISH_ENTRYPOINT || "scripts/artifact-publish.mjs";
const defaultLane = process.env.HWLAB_ARTIFACT_LANE || process.env.HWLAB_GITOPS_LANE || "g14";
const defaultLane = process.env.HWLAB_ARTIFACT_LANE || process.env.HWLAB_GITOPS_LANE || "node";
const defaultRegistryPrefix =
process.env.HWLAB_DEV_REGISTRY_PREFIX || process.env.HWLAB_DEV_REGISTRY || "127.0.0.1:5000/hwlab";
const defaultBaseImage = process.env.HWLAB_DEV_BASE_IMAGE || null;
@@ -121,7 +121,7 @@ function parseArgs(argv) {
else throw new Error(`unknown argument ${arg}`);
}
assert.ok(args.lane === "g14" || isRuntimeArtifactLane(args.lane), `unknown artifact lane ${args.lane}`);
assert.ok(args.lane === "node" || isRuntimeArtifactLane(args.lane), `unknown artifact lane ${args.lane}`);
assert.ok(["short", "full"].includes(args.imageTagMode), `unknown image tag mode ${args.imageTagMode}`);
return args;
@@ -146,12 +146,12 @@ function artifactIdentityValue(env, name) {
return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
}
function g14ArtifactIdentityName(env = process.env) {
function artifactIdentityName(env = process.env) {
return ciArtifactIdentityEnvNames.find((name) => artifactIdentityValue(env, name));
}
function g14ArtifactProducer(env = process.env) {
const idName = g14ArtifactIdentityName(env);
function artifactProducer(env = process.env) {
const idName = artifactIdentityName(env);
if (!idName) {
return {
kind: "missing",
@@ -160,24 +160,24 @@ function g14ArtifactProducer(env = process.env) {
};
}
return {
kind: "g14-ci-artifact",
kind: "node-ci-artifact",
runId: artifactIdentityValue(env, idName),
owner: artifactIdentityValue(env, "HWLAB_CI_ARTIFACT_RUN_OWNER") ?? idName
};
}
function g14ArtifactPublishIdentityGuardFailure({ script, mode }) {
function artifactPublishIdentityGuardFailure({ script, mode }) {
return {
ok: false,
status: "blocked",
error: "g14-artifact-publish-identity-required",
code: "g14-artifact-publish-identity-required",
error: "artifact-publish-identity-required",
code: "artifact-publish-identity-required",
script,
mode,
requiredEnv: "HWLAB_CI_ARTIFACT_RUN_ID or standard CI run identity",
acceptedEnv: ciArtifactIdentityEnvNames,
entrypoint: `HWLAB_CI_ARTIFACT_RUN_ID=<run-id> HWLAB_CI_ARTIFACT_RUN_OWNER=<owner> node scripts/g14-artifact-publish.mjs --publish --report ${tempReportPath("dev-artifacts.json")}`,
summary: `${script} ${mode} is a G14 artifact publish side-effect step and must run under CI artifact identity. Legacy D601 CD transaction identity is not accepted.`,
entrypoint: `HWLAB_CI_ARTIFACT_RUN_ID=<run-id> HWLAB_CI_ARTIFACT_RUN_OWNER=<owner> node scripts/artifact-publish.mjs --publish --report ${tempReportPath("dev-artifacts.json")}`,
summary: `${script} ${mode} is a node artifact publish side-effect step and must run under CI artifact identity. Legacy D601 CD transaction identity is not accepted.`,
devOnly: true,
prodTouched: false,
cdLockRequired: false,
@@ -186,8 +186,8 @@ function g14ArtifactPublishIdentityGuardFailure({ script, mode }) {
};
}
function requireG14ArtifactPublishIdentity({ env = process.env, script, mode }) {
return g14ArtifactIdentityName(env) ? null : g14ArtifactPublishIdentityGuardFailure({ script, mode });
function requireArtifactPublishIdentity({ env = process.env, script, mode }) {
return artifactIdentityName(env) ? null : artifactPublishIdentityGuardFailure({ script, mode });
}
function printHelp() {
@@ -197,7 +197,7 @@ function printHelp() {
"Commit-pinned artifact build/publish helper for controlled CI execution.",
"",
"options:",
" --lane LANE g14 or runtime lane vNN; default: g14",
" --lane LANE node or runtime lane vNN; default: node",
` --catalog-path PATH default: ${defaultCatalogPath}`,
` --deploy-config PATH default: ${defaultDeployPath}`,
" --image-tag-mode MODE short or full; v02 uses full source commit IDs",
@@ -235,11 +235,11 @@ function emit(event, payload = {}) {
}
function ciTimingEnabled(env = process.env) {
return env.HWLAB_G14_CICD_TIMING === "1" || env.HWLAB_CI_TIMING === "1";
return env.HWLAB_NODE_CICD_TIMING === "1" || env.HWLAB_CI_TIMING === "1";
}
function emitCiTiming(payload) {
emit("g14-cicd-timing", {
emit("node-cicd-timing", {
schemaVersion: "v1",
source: "scripts/artifact-publish.mjs",
pipelineRun: process.env.HWLAB_TEKTON_PIPELINERUN ?? null,
@@ -305,7 +305,7 @@ function parseDockerfileStepTimings(text) {
} catch {
continue;
}
if (parsed?.event !== "g14-cicd-build-step-timing") continue;
if (parsed?.event !== "node-cicd-build-step-timing") continue;
timings.push({
stage: parsed.stage,
status: parsed.status ?? "unknown",
@@ -369,7 +369,7 @@ function buildkitBaseImagePreflight(baseImage) {
blockers: [],
nextSteps: [],
recommendation: {
source: "G14 k8s registry image used by rootless BuildKit.",
source: "node k8s registry image used by rootless BuildKit.",
envVar: "HWLAB_DEV_BASE_IMAGE",
recommendedEnvValue: requestedImage
},
@@ -638,7 +638,7 @@ function artifactCatalogSkeleton({ args, deployManifest, commitId }) {
ciPublished: false,
registryVerified: false,
provenance: "not_available_until_publish",
note: `${artifactEnvironment(args)} artifact catalog skeleton initialized without DEV/G14 fallback.`
note: `${artifactEnvironment(args)} artifact catalog skeleton initialized without DEV/node fallback.`
},
allowedProfiles: [artifactEnvironment(args)],
forbiddenProfiles: isRuntimeArtifactLane(args.lane) ? ["dev", "prod"] : ["prod"],
@@ -808,7 +808,7 @@ async function resolveServices(serviceIds, catalog) {
}
function dockerfile(baseImage, port, labels = []) {
const dependencyTimingScript = `started_at=$(node -e "console.log(Date.now())"); status=succeeded; if [ -d /opt/hwlab-node-runtime-base/node_modules ]; then cp -a /opt/hwlab-node-runtime-base/node_modules ./node_modules; fi && if [ -f package-lock.json ]; then npm install --omit=dev --include=optional --ignore-scripts; else npm install --omit=dev --include=optional --ignore-scripts; fi && if [ "\${HWLAB_ARTIFACT_KIND:-}" = "bun-command" ]; then bun_pkg=""; case "$(uname -m)" in x86_64|amd64) bun_pkg="@oven/bun-linux-x64@1.3.13" ;; aarch64|arm64) bun_pkg="@oven/bun-linux-aarch64@1.3.13" ;; *) echo "unsupported bun-command architecture: $(uname -m)" >&2; false ;; esac && npm install --no-save --omit=dev --include=optional --ignore-scripts "$bun_pkg" && test -x "node_modules/\${bun_pkg%@*}/bin/bun" && ln -sf "/app/node_modules/\${bun_pkg%@*}/bin/bun" /usr/local/bin/bun; fi && codex_version="$(node -p "require('./node_modules/@openai/codex/package.json').version")" && case "$(uname -m)" in x86_64|amd64) test -e node_modules/@openai/codex-linux-x64 || npm install --omit=dev --include=optional --ignore-scripts "@openai/codex-linux-x64@npm:@openai/codex@\${codex_version}-linux-x64" ;; aarch64|arm64) test -e node_modules/@openai/codex-linux-arm64 || npm install --omit=dev --include=optional --ignore-scripts "@openai/codex-linux-arm64@npm:@openai/codex@\${codex_version}-linux-arm64" ;; esac || status=failed; finished_at=$(node -e "console.log(Date.now())"); node -e "console.log(JSON.stringify({event:'g14-cicd-build-step-timing',stage:'dependency-install',status:process.argv[1],durationMs:Number(process.argv[3])-Number(process.argv[2]),source:'dockerfile-run'}))" "$status" "$started_at" "$finished_at"; test "$status" = succeeded`;
const dependencyTimingScript = `started_at=$(node -e "console.log(Date.now())"); status=succeeded; if [ -d /opt/hwlab-node-runtime-base/node_modules ]; then cp -a /opt/hwlab-node-runtime-base/node_modules ./node_modules; fi && if [ -f package-lock.json ]; then npm install --omit=dev --include=optional --ignore-scripts; else npm install --omit=dev --include=optional --ignore-scripts; fi && if [ "\${HWLAB_ARTIFACT_KIND:-}" = "bun-command" ]; then bun_pkg=""; case "$(uname -m)" in x86_64|amd64) bun_pkg="@oven/bun-linux-x64@1.3.13" ;; aarch64|arm64) bun_pkg="@oven/bun-linux-aarch64@1.3.13" ;; *) echo "unsupported bun-command architecture: $(uname -m)" >&2; false ;; esac && npm install --no-save --omit=dev --include=optional --ignore-scripts "$bun_pkg" && test -x "node_modules/\${bun_pkg%@*}/bin/bun" && ln -sf "/app/node_modules/\${bun_pkg%@*}/bin/bun" /usr/local/bin/bun; fi && codex_version="$(node -p "require('./node_modules/@openai/codex/package.json').version")" && case "$(uname -m)" in x86_64|amd64) test -e node_modules/@openai/codex-linux-x64 || npm install --omit=dev --include=optional --ignore-scripts "@openai/codex-linux-x64@npm:@openai/codex@\${codex_version}-linux-x64" ;; aarch64|arm64) test -e node_modules/@openai/codex-linux-arm64 || npm install --omit=dev --include=optional --ignore-scripts "@openai/codex-linux-arm64@npm:@openai/codex@\${codex_version}-linux-arm64" ;; esac || status=failed; finished_at=$(node -e "console.log(Date.now())"); node -e "console.log(JSON.stringify({event:'node-cicd-build-step-timing',stage:'dependency-install',status:process.argv[1],durationMs:Number(process.argv[3])-Number(process.argv[2]),source:'dockerfile-run'}))" "$status" "$started_at" "$finished_at"; test "$status" = succeeded`;
const runtimeReadinessScript = `set -eu; fail() { echo "hwlab-artifact-runtime-check-failed:$1" >&2; exit 1; }; mkdir -p /workspace /codex-home; rm -rf /workspace/hwlab; ln -s /app /workspace/hwlab; if [ "\${HWLAB_ARTIFACT_KIND:-}" = "bun-command" ]; then test -x /usr/local/bin/bun || fail bun-missing; /usr/local/bin/bun --version >/tmp/hwlab-bun-version.txt || fail bun-version; fi; chmod -R a+rwX /app /workspace /codex-home || fail chmod; test -x /app/node_modules/.bin/codex || fail codex-bin-missing; /app/node_modules/.bin/codex --version >/tmp/hwlab-codex-version.txt || fail codex-version; test -x /app/node_modules/@openai/codex-linux-x64/vendor/x86_64-unknown-linux-musl/codex/codex || test -x /app/node_modules/@openai/codex-linux-arm64/vendor/aarch64-unknown-linux-musl/codex/codex || fail codex-native-missing`;
return [
`FROM ${baseImage}`,
@@ -1032,7 +1032,7 @@ async function preflight({ args, services, catalog, deployManifest, baseImagePre
type: "safety_blocker",
scope: "registry",
summary: error.message,
next: "Use the G14 local/internal registry prefix, for example 127.0.0.1:5000/hwlab."
next: "Use the node local/internal registry prefix, for example 127.0.0.1:5000/hwlab."
})
);
}
@@ -1072,7 +1072,7 @@ async function preflight({ args, services, catalog, deployManifest, baseImagePre
type: "environment_blocker",
scope: "buildkit-command",
summary: `BuildKit command ${args.buildkitCommand} is not available in the publish task image.`,
next: "Use the G14 Tekton BuildKit path that prepares buildctl/buildkitd before running --publish."
next: "Use the node Tekton BuildKit path that prepares buildctl/buildkitd before running --publish."
})
);
}
@@ -2038,14 +2038,14 @@ function createReport({ args, repo, commitId, shortCommit, mode, services, artif
documents: [
"docs/reference/MVP-e2e-acceptance.md",
"docs/reference/spec-v02-documentation-governance.md",
"docs/reference/g14-gitops-cicd.md",
"docs/reference/node-gitops-cicd.md",
"docs/reference/spec-v02-cicd.md"
],
summary: `${environment} artifact publish evidence; runtime acceptance stays separate from artifact publication.`
},
validationCommands: [
"node --check scripts/artifact-publish.mjs",
"node --check scripts/g14-artifact-publish.mjs",
"node --check scripts/artifact-publish.mjs",
"node --check scripts/src/dev-artifact-services.mjs",
"node --check scripts/src/registry-capabilities.mjs",
"node --check scripts/preflight-dev-base-image.mjs",
@@ -2053,7 +2053,7 @@ function createReport({ args, repo, commitId, shortCommit, mode, services, artif
"node --check scripts/dev-runtime-base-image.mjs",
"node --test scripts/refresh-artifact-catalog.test.mjs",
"node scripts/preflight-dev-base-image.mjs",
"node scripts/g14-artifact-publish.mjs --preflight --no-report",
"node scripts/artifact-publish.mjs --preflight --no-report",
"node --check scripts/validate-dev-gate-report.mjs",
"node scripts/validate-dev-gate-report.mjs"
],
@@ -2197,7 +2197,7 @@ async function main() {
return;
}
if (args.mode === "publish") {
const identityGuard = requireG14ArtifactPublishIdentity({
const identityGuard = requireArtifactPublishIdentity({
script: cliEntrypoint,
mode: "--publish"
});
@@ -2237,8 +2237,8 @@ async function main() {
}
const buildCreatedAt = new Date().toISOString();
const repo = repoLabelFromRemote(remoteUrl);
const producer = g14ArtifactProducer(process.env);
const ciPlan = await createG14CiPlan({
const producer = artifactProducer(process.env);
const ciPlan = await createCiPlan({
repoRoot,
lane: args.lane,
targetRef: "HEAD",