import { spawnSync } from "node:child_process"; import { mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync } from "node:fs"; import { tmpdir } from "node:os"; import path from "node:path"; import { afterEach, describe, expect, it } from "vitest"; const tempDirs: string[] = []; const scriptPath = "scripts/codesign-mac-app.sh"; function makeTempDir(prefix: string): string { const dir = mkdtempSync(path.join(tmpdir(), prefix)); tempDirs.push(dir); return dir; } function entitlementTemps(dir: string): string[] { return readdirSync(dir).filter((name) => name.startsWith("openclaw-entitlements")); } function runCodesign(args: string[], tempRoot: string) { return spawnSync("bash", [scriptPath, ...args], { cwd: process.cwd(), encoding: "utf8", env: { ...process.env, TMPDIR: tempRoot, }, }); } afterEach(() => { for (const dir of tempDirs.splice(0)) { rmSync(dir, { recursive: true, force: true }); } }); describe("codesign-mac-app temp file hygiene", () => { it("does not generate unused entitlement plist files", () => { const script = readFileSync(scriptPath, "utf8"); expect(script).toContain('ENT_TMP_APP="$ENT_TMP_DIR/app.plist"'); expect(script).not.toContain("ENT_TMP_BASE"); expect(script).not.toContain("ENT_TMP_RUNTIME"); expect(script).not.toContain("base.plist"); expect(script).not.toContain("runtime.plist"); }); it("does not allocate entitlement temp files for help output", () => { const tempRoot = makeTempDir("openclaw-codesign-help-"); const result = runCodesign(["--help"], tempRoot); expect(result.status).toBe(0); expect(result.stdout).toContain("Usage: scripts/codesign-mac-app.sh"); expect(entitlementTemps(tempRoot)).toEqual([]); }); it("does not allocate entitlement temp files before app validation", () => { const tempRoot = makeTempDir("openclaw-codesign-missing-"); const missingApp = path.join(tempRoot, "Missing.app"); const result = runCodesign([missingApp], tempRoot); expect(result.status).toBe(1); expect(result.stderr).toContain("App bundle not found"); expect(entitlementTemps(tempRoot)).toEqual([]); }); it("cleans entitlement temp files when signing fails", () => { const tempRoot = makeTempDir("openclaw-codesign-fail-"); const app = path.join(tempRoot, "Fake.app"); mkdirSync(path.join(app, "Contents", "MacOS"), { recursive: true }); const result = spawnSync("bash", [scriptPath, app], { cwd: process.cwd(), encoding: "utf8", env: { ...process.env, ALLOW_ADHOC_SIGNING: "1", TMPDIR: tempRoot, }, }); expect(result.status).not.toBe(0); expect(entitlementTemps(tempRoot)).toEqual([]); }); });