Files
adolf/test/scripts/generate-dependency-release-evidence.test.ts
alvis bedb527145
Some checks failed
ClawSweeper Dispatch / dispatch (push) Has been cancelled
CodeQL / Security High (actions) (push) Has been cancelled
CodeQL / Security High (channel-runtime-boundary) (push) Has been cancelled
CodeQL / Security High (core-auth-secrets) (push) Has been cancelled
CodeQL / Security High (mcp-process-tool-boundary) (push) Has been cancelled
CodeQL / Security High (network-ssrf-boundary) (push) Has been cancelled
CodeQL / Security High (plugin-trust-boundary) (push) Has been cancelled
CodeQL / Security High (process-exec-boundary) (push) Has been cancelled
Docs Sync Publish Repo / sync-publish-repo (push) Has been cancelled
Docs / docs (push) Has been cancelled
OpenClaw Stable Main Closeout / Resolve stable release closeout inputs (push) Has been cancelled
OpenClaw Stable Main Closeout / Verify stable main closeout (push) Has been cancelled
Workflow Sanity / no-tabs (push) Has been cancelled
Workflow Sanity / actionlint (push) Has been cancelled
Workflow Sanity / generated-doc-baselines (push) Has been cancelled
CI / runner-admission (push) Has been cancelled
CI / preflight (push) Has been cancelled
CI / security-fast (push) Has been cancelled
CI / pnpm-store-warmup (push) Has been cancelled
CI / build-artifacts (push) Has been cancelled
CI / native-i18n (push) Has been cancelled
CI / ${{ matrix.check_name }} (push) Has been cancelled
CI / ${{ matrix.checkName }} (push) Has been cancelled
CI / checks-node-compat-node22 (push) Has been cancelled
CI / check-bundled-channel-config-metadata (push) Has been cancelled
CI / check-dependencies (push) Has been cancelled
CI / check-guards (push) Has been cancelled
CI / check-lint (push) Has been cancelled
CI / check-prod-types (push) Has been cancelled
CI / check-shrinkwrap (push) Has been cancelled
CI / check-test-types (push) Has been cancelled
CI / check-additional-boundaries-a (push) Has been cancelled
CI / check-additional-boundaries-bcd (push) Has been cancelled
CI / check-additional-extension-bundled (push) Has been cancelled
CI / check-additional-extension-channels (push) Has been cancelled
CI / check-additional-extension-package-boundary (push) Has been cancelled
CI / check-additional-runtime-topology-architecture (push) Has been cancelled
CI / check-session-accessor-boundary (push) Has been cancelled
CI / check-session-transcript-reader-boundary (push) Has been cancelled
CI / check-docs (push) Has been cancelled
CI / skills-python (push) Has been cancelled
CI / macos-swift (push) Has been cancelled
CI / ios-build (push) Has been cancelled
CI / ci-timings-summary (push) Has been cancelled
Native App Locale Refresh / Refresh native fa (push) Has been cancelled
Native App Locale Refresh / Refresh native fr (push) Has been cancelled
Native App Locale Refresh / Refresh native hi (push) Has been cancelled
Native App Locale Refresh / Refresh native id (push) Has been cancelled
Native App Locale Refresh / Refresh native it (push) Has been cancelled
Native App Locale Refresh / Refresh native ja-JP (push) Has been cancelled
Control UI Locale Refresh / plan (push) Has been cancelled
Control UI Locale Refresh / Refresh ${{ matrix.locale }} (push) Has been cancelled
Control UI Locale Refresh / Commit control UI locale refresh (push) Has been cancelled
Live Media Runner Image / Build live media runner image (push) Has been cancelled
Native App Locale Refresh / Refresh native ar (push) Has been cancelled
Native App Locale Refresh / Refresh native de (push) Has been cancelled
Native App Locale Refresh / Refresh native es (push) Has been cancelled
Native App Locale Refresh / Refresh native ko (push) Has been cancelled
Native App Locale Refresh / Refresh native nl (push) Has been cancelled
Native App Locale Refresh / Refresh native pl (push) Has been cancelled
Native App Locale Refresh / Refresh native pt-BR (push) Has been cancelled
Native App Locale Refresh / Refresh native ru (push) Has been cancelled
Native App Locale Refresh / Refresh native sv (push) Has been cancelled
Native App Locale Refresh / Refresh native th (push) Has been cancelled
Native App Locale Refresh / Refresh native tr (push) Has been cancelled
Native App Locale Refresh / Refresh native uk (push) Has been cancelled
Native App Locale Refresh / Refresh native vi (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-CN (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-TW (push) Has been cancelled
Native App Locale Refresh / Commit native locale refresh (push) Has been cancelled
Plugin Init Scaffold Validation / Validate provider scaffold (push) Has been cancelled
Plugin NPM Release / preview_plugins_npm (push) Has been cancelled
Plugin NPM Release / Validate release publish approval (push) Has been cancelled
Plugin NPM Release / preview_plugin_pack (push) Has been cancelled
Plugin NPM Release / publish_plugins_npm (push) Has been cancelled
Sandbox Common Smoke / sandbox-common-smoke (push) Has been cancelled
Website Installer Sync / static (push) Has been cancelled
Website Installer Sync / linux-docker (push) Has been cancelled
Website Installer Sync / macos-installer (push) Has been cancelled
Website Installer Sync / windows-installer (push) Has been cancelled
Website Installer Sync / sync-website (push) Has been cancelled
Vendor OpenClaw source as Adolf fork baseline
Adolf is a fork/vendored clone of github.com/openclaw/openclaw (v2026.6.11),
free to diverge. Tree copied sans upstream .git; upstream remote added for
future syncs. Node pinned to 24 (.nvmrc); engines already require >=22.19.
Preserves docs/ARCHITECTURE.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LeqyaxJF2nbRXJtae2kNB2
2026-07-05 09:36:54 +00:00

288 lines
10 KiB
TypeScript

// Generate Dependency Release Evidence tests cover generate dependency release evidence script behavior.
import { spawnSync } from "node:child_process";
import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import path from "node:path";
import { describe, expect, it } from "vitest";
import {
DEPENDENCY_EVIDENCE_REPORTS,
collectDependencyEvidenceSummaryCounts,
createDependencyEvidenceManifest,
parseArgs,
renderDependencyEvidenceStepSummary,
renderDependencyEvidenceSummary,
resolvePreviousReleaseTag,
resolveReleaseTag,
} from "../../scripts/generate-dependency-release-evidence.mjs";
async function writeJson(dir: string, fileName: string, value: unknown) {
await writeFile(path.join(dir, fileName), `${JSON.stringify(value, null, 2)}\n`, "utf8");
}
function runCli(...args: string[]) {
return spawnSync(
process.execPath,
["scripts/generate-dependency-release-evidence.mjs", ...args],
{
cwd: path.resolve("."),
encoding: "utf8",
},
);
}
function expectNoNodeStack(stderr: string) {
expect(stderr).not.toContain("Node.js");
expect(stderr).not.toContain("\n at ");
}
describe("generate-dependency-release-evidence", () => {
it("defines the release evidence command list and policy classifications", () => {
expect(DEPENDENCY_EVIDENCE_REPORTS.map(({ command, policy }) => ({ command, policy }))).toEqual(
[
{ command: "pnpm deps:vuln:gate", policy: "hard-blocking" },
{ command: "pnpm deps:transitive-risk:report", policy: "report-only" },
{ command: "pnpm deps:ownership-surface:report", policy: "report-only" },
{ command: "pnpm deps:changes:report", policy: "report-only" },
],
);
});
it("creates the dependency evidence manifest shape", () => {
const manifest = createDependencyEvidenceManifest({
generatedAt: "2026-05-13T00:00:00.000Z",
releaseTag: "v2026.5.13-beta.1",
releaseRef: "v2026.5.13-beta.1",
releaseSha: "abc123",
npmDistTag: "beta",
packageVersion: "2026.5.13-beta.1",
workflowRunId: "123",
workflowRunAttempt: "2",
dependencyChangeBaseRef: "v2026.5.1",
});
expect(manifest).toEqual({
schemaVersion: 1,
generatedAt: "2026-05-13T00:00:00.000Z",
releaseTag: "v2026.5.13-beta.1",
releaseRef: "v2026.5.13-beta.1",
releaseSha: "abc123",
npmDistTag: "beta",
packageName: "openclaw",
packageVersion: "2026.5.13-beta.1",
workflowRunId: "123",
workflowRunAttempt: "2",
dependencyChangeBaseRef: "v2026.5.1",
reports: DEPENDENCY_EVIDENCE_REPORTS,
});
});
it("uses a synthetic release tag for validation-only SHA preflight input", () => {
expect(
resolveReleaseTag({
releaseRef: "0123456789abcdef0123456789abcdef01234567",
packageVersion: "2026.5.13",
}),
).toBe("v2026.5.13");
expect(
resolveReleaseTag({
releaseRef: "v2026.5.13-beta.1",
packageVersion: "2026.5.13-beta.1",
}),
).toBe("v2026.5.13-beta.1");
});
it("rejects missing dependency evidence CLI option values", () => {
const requiredArgs = ["--release-ref", "v2026.5.13", "--npm-dist-tag", "latest"];
expect(() =>
parseArgs(["--output-dir", "--release-ref", "v2026.5.13", "--npm-dist-tag", "latest"]),
).toThrow("Expected --output-dir <value>.");
expect(() => parseArgs(["--output-dir", "-h", ...requiredArgs])).toThrow(
"Expected --output-dir <value>.",
);
expect(() =>
parseArgs(["--output-dir", "evidence", "--release-ref", "--npm-dist-tag", "latest"]),
).toThrow("Expected --release-ref <value>.");
expect(() =>
parseArgs(["--output-dir", "evidence", "--release-ref", "-h", "--npm-dist-tag", "latest"]),
).toThrow("Expected --release-ref <value>.");
expect(() =>
parseArgs([
"--output-dir",
"evidence",
"--release-ref",
"v2026.5.13",
"--npm-dist-tag",
"-h",
]),
).toThrow("Expected --npm-dist-tag <value>.");
expect(() =>
parseArgs(["--output-dir", "evidence", "--release-ref", "v2026.5.13", "--base-ref"]),
).toThrow("Expected --base-ref <value>.");
expect(() =>
parseArgs(["--output-dir", "evidence", ...requiredArgs, "--base-ref", "-h"]),
).toThrow("Expected --base-ref <value>.");
expect(() =>
parseArgs([
"--output-dir",
"evidence",
"--release-ref",
"v2026.5.13",
"--npm-dist-tag",
"latest",
"--github-output",
"--github-step-summary",
"summary.md",
]),
).toThrow("Expected --github-output <value>.");
expect(() =>
parseArgs(["--output-dir", "evidence", ...requiredArgs, "--github-output", "-h"]),
).toThrow("Expected --github-output <value>.");
});
it("rejects duplicate dependency evidence CLI options", () => {
const requiredArgs = ["--release-ref", "v2026.5.13", "--npm-dist-tag", "latest"];
const artifactArgs = ["--output-dir", "evidence", ...requiredArgs];
const duplicateCases = [
["--root", ["--root", "repo-a", "--root", "repo-b", ...artifactArgs]],
["--output-dir", ["--output-dir", "evidence-a", "--output-dir", "evidence-b", ...requiredArgs]],
[
"--release-ref",
["--output-dir", "evidence", "--release-ref", "v2026.5.13", "--release-ref", "v2026.5.14", "--npm-dist-tag", "latest"],
],
[
"--npm-dist-tag",
["--output-dir", "evidence", "--release-ref", "v2026.5.13", "--npm-dist-tag", "latest", "--npm-dist-tag", "beta"],
],
["--base-ref", [...artifactArgs, "--base-ref", "origin/main", "--base-ref", "HEAD~1"]],
["--github-output", [...artifactArgs, "--github-output", "first.out", "--github-output", "second.out"]],
[
"--github-step-summary",
[...artifactArgs, "--github-step-summary", "first.md", "--github-step-summary", "second.md"],
],
] satisfies Array<[string, string[]]>;
for (const [flag, args] of duplicateCases) {
expect(() => parseArgs(args)).toThrow(`${flag} was provided more than once.`);
}
});
it("prints CLI help without generating evidence", () => {
const result = runCli("--help");
expect(result.status).toBe(0);
expect(result.stdout).toContain("Usage: node scripts/generate-dependency-release-evidence.mjs");
expect(result.stderr).toBe("");
});
it("reports CLI argument errors without a Node stack trace", () => {
const result = runCli("--wat");
expect(result.status).toBe(1);
expect(result.stdout).toBe("");
expect(result.stderr.trim()).toBe("Unsupported argument: --wat");
expectNoNodeStack(result.stderr);
});
it("falls back to fetching tags when local previous-release resolution misses", () => {
const calls: Array<{ command: string; args: string[] }> = [];
let describeCalls = 0;
const execFileSyncImpl = (command: string, args: string[] = []) => {
calls.push({ command, args });
if (command !== "git") {
throw new Error(`unexpected command: ${command}`);
}
if (args[0] === "describe") {
describeCalls += 1;
if (describeCalls === 1) {
throw new Error("tag not found");
}
return "v2026.5.1\n";
}
if (args[0] === "fetch") {
return "";
}
throw new Error(`unexpected git args: ${args.join(" ")}`);
};
expect(
resolvePreviousReleaseTag({
rootDir: "/repo",
execFileSyncImpl,
}),
).toBe("v2026.5.1");
expect(calls.map(({ args }) => args[0])).toEqual(["describe", "fetch", "describe"]);
expect(calls[1].args).toEqual(["fetch", "--tags", "--force", "origin"]);
});
it("collects report counts and renders human summaries", async () => {
const dir = await mkdtemp(path.join(tmpdir(), "openclaw-release-dependency-evidence-test-"));
try {
await writeJson(dir, "dependency-vulnerability-gate.json", {
blockers: [{ id: "GHSA-blocker" }],
findings: [{ id: "GHSA-blocker" }, { id: "GHSA-report" }],
});
await writeJson(dir, "transitive-manifest-risk-report.json", {
findingCount: 17,
workspaceExcludedFindingCount: 3,
metadataFailures: [{ packageName: "missing" }],
});
await writeJson(dir, "dependency-ownership-surface-report.json", {
summary: {
lockfilePackageCount: 101,
buildRiskPackageCount: 8,
},
});
await writeJson(dir, "dependency-changes-report.json", {
summary: {
dependencyFileChanges: 4,
addedPackages: 5,
removedPackages: 6,
changedPackages: 7,
},
});
const counts = await collectDependencyEvidenceSummaryCounts(dir);
expect(counts).toEqual({
vulnerabilityBlockers: 1,
vulnerabilityFindings: 2,
transitiveRiskSignals: 17,
workspaceExcludedTransitiveSignals: 3,
transitiveMetadataFailures: 1,
ownershipLockfilePackages: 101,
ownershipBuildRiskPackages: 8,
dependencyFileChanges: 4,
dependencyAddedPackages: 5,
dependencyRemovedPackages: 6,
dependencyChangedPackages: 7,
});
const summary = renderDependencyEvidenceSummary({
releaseTag: "v2026.5.13",
releaseSha: "abc123",
baseRef: "v2026.5.1",
counts,
});
expect(summary).toContain("- npm advisory vulnerability hard blockers: 1");
expect(summary).toContain("- Transitive manifest reported risk signals: 17");
expect(summary).toContain("- Dependency change baseline: `v2026.5.1`");
expect(summary).toContain("- Resolved package changes: +5 -6 changed 7");
const stepSummary = renderDependencyEvidenceStepSummary({
evidenceArtifactName: "openclaw-release-dependency-evidence-v2026.5.13",
baseRef: "v2026.5.1",
counts,
});
expect(stepSummary).toContain(
"- Evidence artifact: `openclaw-release-dependency-evidence-v2026.5.13`",
);
expect(stepSummary).toContain("- npm advisory vulnerability hard blockers: `1`");
await expect(
readFile(path.join(dir, "dependency-vulnerability-gate.json"), "utf8"),
).resolves.toContain("GHSA-blocker");
} finally {
await rm(dir, { force: true, recursive: true });
}
});
});