fix(cicd): vendor Ajv bundle for warning stage
This commit is contained in:
@@ -52,7 +52,7 @@ const runtimeGitopsScriptsConfigMapNativeScript = readFileSync(rootPath("scripts
|
||||
const runtimeGitopsPostprocessNativeScript = readFileSync(rootPath("scripts/native/hwlab/runtime-gitops-postprocess.mjs"), "utf8").trimEnd();
|
||||
const runtimeGitopsVerifyNativeScript = readFileSync(rootPath("scripts/native/hwlab/runtime-gitops-verify.mjs"), "utf8").trimEnd();
|
||||
const featureConfigSchemaWarningNativeScript = readFileSync(rootPath("scripts/native/cicd/feature-config-schema-warning.mjs"), "utf8").trimEnd();
|
||||
const ajv2020BundleScript = readFileSync(rootPath("node_modules/ajv-dist/dist/ajv2020.min.js"), "utf8").trimEnd();
|
||||
const ajv2020BundleScript = readFileSync(rootPath("scripts/vendor/ajv-dist/8.17.1/ajv2020.min.js"), "utf8").trimEnd();
|
||||
const runtimePipelineProvenanceNativeScript = readFileSync(rootPath("scripts/native/hwlab/runtime-pipeline-provenance.mjs"), "utf8").trimEnd();
|
||||
|
||||
export function nodeRuntimeGitMirrorJobName(mirror: NodeRuntimeGitMirrorTargetSpec, action: "sync" | "flush"): string {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { expect, test } from "bun:test";
|
||||
import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { join, resolve } from "node:path";
|
||||
import { spawnSync } from "node:child_process";
|
||||
|
||||
import { resolveAgentRunLaneTarget } from "./agentrun-lanes";
|
||||
@@ -25,10 +25,50 @@ test("shared stage injects owning YAML OTel values for all three PaC repositorie
|
||||
expect(stage).toContain("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT='http://otel-collector.platform-infra.svc.cluster.local:4318/v1/traces'");
|
||||
expect(stage).toContain("OTEL_TRACES_SAMPLER_ARG='1'");
|
||||
expect(stage).toContain("OTEL_EXPORTER_TIMEOUT_MS='300'");
|
||||
expect(stage).toContain("NODE_UNIDESK_AJV2020_BUNDLE");
|
||||
expect(stage).not.toContain("process.env.webProbeSentinel");
|
||||
}
|
||||
});
|
||||
|
||||
test("HWLAB, AgentRun, and Sentinel normal stages validate without source workspace node_modules", () => {
|
||||
const root = mkdtempSync(join(tmpdir(), "feature-config-consumers-"));
|
||||
try {
|
||||
const source = join(root, "source");
|
||||
const rendered = join(root, "rendered");
|
||||
mkdirSync(join(source, "config"), { recursive: true });
|
||||
mkdirSync(rendered, { recursive: true });
|
||||
writeFileSync(join(source, "config", "feature-config.schema.json"), JSON.stringify({
|
||||
$schema: "https://json-schema.org/draft/2020-12/schema",
|
||||
type: "object",
|
||||
properties: { webProbeSentinel: { type: "boolean", "x-unidesk-feature": "web-probe-sentinel" } },
|
||||
additionalProperties: false,
|
||||
}));
|
||||
writeFileSync(join(rendered, "deployment.json"), JSON.stringify({
|
||||
apiVersion: "apps/v1",
|
||||
kind: "Deployment",
|
||||
spec: { template: { spec: { containers: [{ name: "fixture", env: [{ name: "webProbeSentinel", value: "true" }] }] } } },
|
||||
}));
|
||||
const vendorBundle = resolve(import.meta.dir, "../vendor/ajv-dist/8.17.1/ajv2020.min.js");
|
||||
for (const consumer of [
|
||||
{ repositoryId: "hwlab-nc01-v03", consumer: "hwlab-nc01-v03", ajvBundleExpression: JSON.stringify(vendorBundle) },
|
||||
{ repositoryId: "agentrun-nc01-v02", consumer: "agentrun-nc01-v02" },
|
||||
{ repositoryId: "sentinel-nc01-v03", consumer: "sentinel-nc01-v03" },
|
||||
]) {
|
||||
const stage = renderPacFeatureConfigSchemaStage({
|
||||
...consumer,
|
||||
repoDirExpression: JSON.stringify(source),
|
||||
renderedRootExpression: JSON.stringify(rendered),
|
||||
});
|
||||
const result = spawnSync("sh", [], { input: `set -eu\n${stage}\n`, encoding: "utf8" });
|
||||
expect(result.status, consumer.consumer).toBe(0);
|
||||
expect(result.stderr, consumer.consumer).toContain('"code":"feature-config-schema-valid"');
|
||||
expect(result.stderr, consumer.consumer).not.toContain("feature-config-validator-unavailable");
|
||||
}
|
||||
} finally {
|
||||
rmSync(root, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test("embedded node process failure remains a typed warning with zero shell exit", () => {
|
||||
const root = mkdtempSync(join(tmpdir(), "feature-config-stage-"));
|
||||
try {
|
||||
@@ -61,6 +101,7 @@ test("AgentRun normal GitOps publish task contains the shared warning-only stage
|
||||
expect(scripts).toContain("feature-config-schema-validation");
|
||||
expect(scripts).toContain("feature-config-validator-process-failure");
|
||||
expect(scripts).toContain("OTEL_EXPORTER_TIMEOUT_MS='300'");
|
||||
expect(scripts).toContain("NODE_UNIDESK_AJV2020_BUNDLE");
|
||||
});
|
||||
|
||||
test("repo-owned schema is Draft 2020-12 with one canonical feature property", () => {
|
||||
|
||||
@@ -4,6 +4,7 @@ import { rootPath } from "./config";
|
||||
import { loadCicdOtelRuntimeConfig } from "../native/cicd/otel-runtime-config";
|
||||
|
||||
const validatorSource = readFileSync(rootPath("scripts/native/cicd/feature-config-schema-warning.mjs"), "utf8").trimEnd();
|
||||
const ajv2020BundleSource = readFileSync(rootPath("scripts/vendor/ajv-dist/8.17.1/ajv2020.min.js"), "utf8").trimEnd();
|
||||
|
||||
export interface PacFeatureConfigSchemaStageOptions {
|
||||
readonly repositoryId: string;
|
||||
@@ -15,6 +16,7 @@ export interface PacFeatureConfigSchemaStageOptions {
|
||||
|
||||
export function renderPacFeatureConfigSchemaStage(options: PacFeatureConfigSchemaStageOptions): string {
|
||||
const otel = loadCicdOtelRuntimeConfig(options.repositoryId);
|
||||
const materializeBundle = options.ajvBundleExpression === undefined || options.ajvBundleExpression === null;
|
||||
return [
|
||||
"feature_config_schema_started_ms=\"$(date +%s%3N 2>/dev/null || date +%s000)\"",
|
||||
`export UNIDESK_FEATURE_CONFIG_REPO_DIR=${options.repoDirExpression}`,
|
||||
@@ -24,8 +26,20 @@ export function renderPacFeatureConfigSchemaStage(options: PacFeatureConfigSchem
|
||||
`export OTEL_SERVICE_NAME=${shellSingle(otel.serviceName)}`,
|
||||
`export OTEL_TRACES_SAMPLER_ARG=${shellSingle(String(otel.samplingRatio))}`,
|
||||
`export OTEL_EXPORTER_TIMEOUT_MS=${shellSingle(String(otel.timeoutMs))}`,
|
||||
...(options.ajvBundleExpression === undefined || options.ajvBundleExpression === null
|
||||
? []
|
||||
...(materializeBundle
|
||||
? [
|
||||
"feature_config_ajv_bundle=''",
|
||||
"if feature_config_ajv_bundle=\"$(mktemp \"${TMPDIR:-/tmp}/unidesk-ajv2020.XXXXXX\" 2>/dev/null)\"; then",
|
||||
" if ! cat >\"$feature_config_ajv_bundle\" <<'NODE_UNIDESK_AJV2020_BUNDLE'",
|
||||
ajv2020BundleSource,
|
||||
"NODE_UNIDESK_AJV2020_BUNDLE",
|
||||
" then",
|
||||
" rm -f \"$feature_config_ajv_bundle\" || true",
|
||||
" feature_config_ajv_bundle=''",
|
||||
" fi",
|
||||
"fi",
|
||||
"export UNIDESK_AJV2020_BUNDLE=\"${feature_config_ajv_bundle:-${TMPDIR:-/tmp}/unidesk-ajv2020-unavailable}\"",
|
||||
]
|
||||
: [`export UNIDESK_AJV2020_BUNDLE=${options.ajvBundleExpression}`]),
|
||||
"if ! node --input-type=module <<'NODE_UNIDESK_FEATURE_CONFIG_SCHEMA'",
|
||||
validatorSource,
|
||||
@@ -35,6 +49,7 @@ export function renderPacFeatureConfigSchemaStage(options: PacFeatureConfigSchem
|
||||
" consumer: process.env.UNIDESK_PAC_CONSUMER,",
|
||||
"});",
|
||||
"NODE_UNIDESK_FEATURE_CONFIG_SCHEMA",
|
||||
...(materializeBundle ? ["if [ -n \"$feature_config_ajv_bundle\" ]; then rm -f \"$feature_config_ajv_bundle\" || true; fi"] : []),
|
||||
"then",
|
||||
" printf '{\"event\":\"feature-config-schema-validation\",\"warning\":true,\"blocking\":false,\"code\":\"feature-config-validator-process-failure\",\"mutation\":false,\"valuesPrinted\":false}\\n' >&2",
|
||||
"fi",
|
||||
|
||||
@@ -372,6 +372,8 @@ describe("HWLAB YAML-owned Pipeline provenance", () => {
|
||||
"scripts/native/hwlab/runtime-gitops-postprocess.mjs",
|
||||
"scripts/native/hwlab/runtime-gitops-scripts-configmap.mjs",
|
||||
"scripts/native/hwlab/runtime-gitops-verify.mjs",
|
||||
"scripts/vendor/ajv-dist/8.17.1/ajv2020.min.js",
|
||||
"scripts/vendor/ajv-dist/8.17.1/manifest.json",
|
||||
"scripts/src/config.ts",
|
||||
"scripts/src/hwlab-node/render.ts",
|
||||
"scripts/src/hwlab-node-lanes.ts",
|
||||
|
||||
Reference in New Issue
Block a user