Files
edgeever/scripts/verify-acp-npm-upgrade.mjs
T
tianma-if 59d6548abd fix: harden remaining dependency paths and desktop npm
Remove the unused React Native Markdown renderer. Pin safe YAML, shell quoting, tar, and cache dependencies; upgrade npm within the 11 series and apply upstream fixes to its hidden bundled Undici and cache copies.

Add actual-consumer security regressions and an opt-in real npm/ACP upgrade verifier. Typechecks, Web build, Android APK/signature checks, and 2,997 tests passed (23 skipped). Real old-to-new npm installs, ACP initialize, rollback, restart, and fallback retention passed under the desktop Electron runtime.

Android USB-device validation and full desktop automatic-update release gates remain pending. Dependency audit is reduced from 85 to 74 unique advisories; this is not a complete security clearance.
2026-10-12 12:48:47 +08:00

71 lines
3.6 KiB
JavaScript

import assert from "node:assert/strict";
import { existsSync } from "node:fs";
import { mkdtemp, readdir, rm } from "node:fs/promises";
import { createRequire } from "node:module";
import { tmpdir } from "node:os";
import path from "node:path";
import { createAcpAdapterManager } from "../apps/desktop/src/main/acp-adapter-manager.mjs";
import { executeRealAcpHandshake } from "./verify-acp-adapter-real-e2e.mjs";
// Opt-in network verification: real published packages, real npm extraction,
// and ACP initialize only. Never authenticate or send a model prompt.
export const verifyAcpNpmUpgrade = async ({ oldNpmPath, executablePath = process.execPath }) => {
assert.ok(oldNpmPath && existsSync(oldNpmPath), "Provide the previous npm CLI path");
const root = await mkdtemp(path.join(tmpdir(), "edgeever-acp-npm-upgrade-"));
let version = "2.2.1";
const fetchImpl = async () => new Response(JSON.stringify({ agents: [{
id: "codex-acp",
version,
distribution: { npx: { package: `@agentclientprotocol/codex-acp@${version}` } },
}] }));
const common = { root, fetchImpl, executablePath };
const validate = async (command) => {
const result = await executeRealAcpHandshake(command);
assert.equal(result.state, "available");
assert.equal(result.protocolVersion, 1);
return result;
};
try {
const previous = createAcpAdapterManager({ ...common, npmPath: oldNpmPath });
assert.equal((await previous.install("codex", validate)).version, version);
console.log("Previous npm installed official codex-acp 2.2.1; ACP initialize passed");
const current = createAcpAdapterManager(common);
assert.equal(current.get("codex")?.version, version);
version = "2.2.2";
await assert.rejects(current.install("codex", async (command) => {
await validate(command);
throw new Error("intentional_validation_failure");
}, { updateOnly: true }), /intentional_validation_failure/);
assert.equal(current.get("codex")?.version, "2.2.1");
await validate(current.get("codex").command);
console.log("Failed upgrade preserved the working previous adapter");
assert.equal((await current.install("codex", validate, { updateOnly: true })).version, version);
const restarted = createAcpAdapterManager(common);
assert.equal(restarted.get("codex")?.version, version);
await validate(restarted.get("codex").command);
await restarted.prune();
const names = await readdir(path.join(root, "codex"));
assert.ok(names.includes("2.2.1") && names.includes("2.2.2"));
assert.ok(!names.some((name) => name.startsWith(".stage-")));
console.log("Current npm upgraded to official codex-acp 2.2.2; restart, ACP initialize, and fallback retention passed");
return { ok: true, oldAdapter: "2.2.1", newAdapter: "2.2.2" };
} finally {
await rm(root, { recursive: true, force: true });
}
};
if (import.meta.main) {
const desktopRequire = createRequire(new URL("../apps/desktop/package.json", import.meta.url));
const electronRoot = path.dirname(desktopRequire.resolve("electron/package.json"));
const defaultExecutablePath = process.platform === "darwin"
? path.join(electronRoot, "dist/Electron.app/Contents/MacOS/Electron")
: path.join(electronRoot, "dist", process.platform === "win32" ? "electron.exe" : "electron");
const executablePath = process.argv[3] ? path.resolve(process.argv[3]) : defaultExecutablePath;
assert.ok(process.argv[2], "Provide the previous npm CLI path");
const oldNpmPath = path.resolve(process.argv[2]);
assert.ok(existsSync(executablePath), "Provide an installed Electron or Node runtime path");
console.log(JSON.stringify(await verifyAcpNpmUpgrade({ oldNpmPath, executablePath })));
}