| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134 |
- #!/usr/bin/env node
- import assert from "node:assert/strict";
- import { execFile } from "node:child_process";
- import { constants } from "node:fs";
- import { access, lstat, mkdtemp, readFile, realpath, rm } from "node:fs/promises";
- import { tmpdir } from "node:os";
- import { isAbsolute, join, relative } from "node:path";
- import { promisify } from "node:util";
- import { Client } from "@modelcontextprotocol/sdk/client/index.js";
- import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
- const execFileAsync = promisify(execFile);
- const EXPECTED_TOOLS = ["overview", "list_threads", "inspect_thread", "wait_for_change"];
- const PACKAGE_NAME = "@bodicsek/codex-chief-of-staff";
- const BIN_NAME = "codex-chief-of-staff";
- const DEFAULT_CACHE = "/private/tmp/codex-chief-of-staff-npm-cache";
- const USAGE = "usage: npm run verify:git-package -- <git+https|git+ssh|git+file URL>#<vX.Y.Z|40-character-commit>";
- function selectedGitPackage(argv) {
- if (argv.length !== 1) throw new Error(USAGE);
- const packageSpec = argv[0];
- const fragmentAt = packageSpec.lastIndexOf("#");
- const repository = packageSpec.slice(0, fragmentAt);
- const revision = packageSpec.slice(fragmentAt + 1);
- const supportedRepository = /^(?:git\+https|git\+ssh|git\+file):\/\/.+\.git$/.test(repository);
- const immutableRevision = /^(?:[0-9a-fA-F]{40}|v\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?)$/.test(revision);
- if (fragmentAt <= 0 || !supportedRepository || !immutableRevision) {
- throw new Error("Git package must use a supported URL pinned to a full commit or release tag");
- }
- return { packageSpec, revision };
- }
- function isWithin(parent, child) {
- const pathFromParent = relative(parent, child);
- return pathFromParent === "" || (!pathFromParent.startsWith("..") && !isAbsolute(pathFromParent));
- }
- function commandExit(error) {
- return typeof error === "object" && error !== null && "code" in error
- ? String(error.code)
- : "unknown";
- }
- async function installPackage(prefix, cache, packageSpec) {
- try {
- await execFileAsync("npm", [
- "install",
- "--global",
- "--prefix",
- prefix,
- "--ignore-scripts",
- "--cache",
- cache,
- packageSpec,
- ], { maxBuffer: 10 * 1024 * 1024 });
- } catch (error) {
- throw new Error(`isolated npm installation failed with exit code ${commandExit(error)}`);
- }
- }
- async function installedPackage(prefix, cache) {
- const packageRoot = join(prefix, "lib", "node_modules", PACKAGE_NAME);
- const executable = join(prefix, "bin", BIN_NAME);
- await access(executable, constants.X_OK);
- const packageMetadata = await lstat(packageRoot);
- if (packageMetadata.isSymbolicLink()) {
- throw new Error("installed package must not be a temporary link");
- }
- const [realPrefix, realCache, realPackage, realExecutable] = await Promise.all([
- realpath(prefix),
- realpath(cache),
- realpath(packageRoot),
- realpath(executable),
- ]);
- if (!isWithin(realPrefix, realPackage) || isWithin(realCache, realPackage)) {
- throw new Error("installed package resolved outside the isolated prefix");
- }
- if (!isWithin(realPackage, realExecutable) || isWithin(realCache, realExecutable)) {
- throw new Error("installed executable resolved outside the installed package");
- }
- const manifest = JSON.parse(await readFile(join(realPackage, "package.json"), "utf8"));
- assert.equal(manifest.name, PACKAGE_NAME);
- assert.deepEqual(manifest.bin, { [BIN_NAME]: "dist/src/index.js" });
- return { executable, version: String(manifest.version) };
- }
- async function verify() {
- const { packageSpec, revision } = selectedGitPackage(process.argv.slice(2));
- const prefix = await mkdtemp(join(tmpdir(), "codex-chief-of-staff-git-package-"));
- const cache = process.env.CODEX_CHIEF_OF_STAFF_NPM_CACHE ?? DEFAULT_CACHE;
- let client;
- try {
- await installPackage(prefix, cache, packageSpec);
- const installed = await installedPackage(prefix, cache);
- client = new Client({ name: "git-package-verifier", version: "1.0.0" });
- const transport = new StdioClientTransport({
- command: installed.executable,
- env: {
- ...process.env,
- CODEX_APP_SERVER_URL: process.env.CODEX_APP_SERVER_URL ?? "ws://127.0.0.1:4500",
- },
- });
- await client.connect(transport);
- assert.match(client.getInstructions() ?? "", /call overview first/i);
- const listed = await client.listTools();
- assert.deepEqual(listed.tools.map(({ name }) => name), EXPECTED_TOOLS);
- process.stdout.write(`${JSON.stringify({
- ok: true,
- package: `${PACKAGE_NAME}@${installed.version}`,
- revision,
- executable: `bin/${BIN_NAME}`,
- storage: "isolated-prefix",
- instructions: "verified",
- tools: EXPECTED_TOOLS,
- })}\n`);
- } finally {
- if (client !== undefined) await client.close().catch(() => undefined);
- await rm(prefix, { recursive: true, force: true });
- }
- }
- verify().catch((error) => {
- const message = error instanceof Error ? error.message : String(error);
- process.stderr.write(`Git-package verification failed: ${message}\n`);
- process.exitCode = 1;
- });
|