verify-packed-package.mjs 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. #!/usr/bin/env node
  2. import assert from "node:assert/strict";
  3. import { execFile } from "node:child_process";
  4. import { constants } from "node:fs";
  5. import { access, mkdtemp, rm, stat } from "node:fs/promises";
  6. import { tmpdir } from "node:os";
  7. import { basename, join, resolve } from "node:path";
  8. import { promisify } from "node:util";
  9. const execFileAsync = promisify(execFile);
  10. const PACKAGE_NAME = "codex-app-server-bridge";
  11. const DEFAULT_CACHE = "/private/tmp/codex-app-server-bridge-npm-cache";
  12. async function selectedTarball(argv) {
  13. if (argv.length !== 1) {
  14. throw new Error("usage: npm run verify:package -- /absolute/path/to/codex-app-server-bridge-VERSION.tgz");
  15. }
  16. const tarball = resolve(argv[0]);
  17. if (!tarball.endsWith(".tgz")) throw new Error("package path must end in .tgz");
  18. const metadata = await stat(tarball);
  19. if (!metadata.isFile()) throw new Error("package path must identify a readable file");
  20. await access(tarball, constants.R_OK);
  21. return tarball;
  22. }
  23. async function verify() {
  24. const tarball = await selectedTarball(process.argv.slice(2));
  25. const prefix = await mkdtemp(join(tmpdir(), "codex-app-server-bridge-package-"));
  26. const cache = process.env.CODEX_APP_SERVER_BRIDGE_NPM_CACHE ?? DEFAULT_CACHE;
  27. try {
  28. await execFileAsync("npm", [
  29. "install",
  30. "--prefix",
  31. prefix,
  32. "--ignore-scripts",
  33. "--cache",
  34. cache,
  35. tarball,
  36. ], { maxBuffer: 10 * 1024 * 1024 });
  37. const executable = join(prefix, "node_modules", ".bin", PACKAGE_NAME);
  38. await access(executable, constants.X_OK);
  39. try {
  40. await execFileAsync(executable, ["--unsupported"], { maxBuffer: 1024 * 1024 });
  41. throw new Error("installed executable unexpectedly accepted an unsupported invocation");
  42. } catch (error) {
  43. if (typeof error !== "object" || error === null || !("code" in error) || error.code !== 1) {
  44. throw error;
  45. }
  46. const stdout = "stdout" in error ? String(error.stdout) : "";
  47. const stderr = "stderr" in error ? String(error.stderr) : "";
  48. assert.equal(stdout, "");
  49. assert.match(stderr, /Usage: codex-app-server-bridge app-server/);
  50. }
  51. process.stdout.write(`${JSON.stringify({
  52. ok: true,
  53. package: basename(tarball),
  54. executable: `node_modules/.bin/${PACKAGE_NAME}`,
  55. invocation: "verified",
  56. })}\n`);
  57. } finally {
  58. await rm(prefix, { recursive: true, force: true });
  59. }
  60. }
  61. verify().catch((error) => {
  62. const message = error instanceof Error ? error.message : String(error);
  63. process.stderr.write(`Packed-package verification failed: ${message}\n`);
  64. process.exitCode = 1;
  65. });