mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-08-17 18:25:42 +02:00
85 lines
4.1 KiB
JavaScript
85 lines
4.1 KiB
JavaScript
#!/usr/bin/env node
|
|
// Reports code-signing state; --require-signed fails unless signed (release CI gate, post-sign). Local builds are unsigned by design. Win: Authenticode Valid; mac: codesign + spctl + staple.
|
|
|
|
'use strict';
|
|
const { execSync } = require('child_process');
|
|
const h = require('./lib/app-harness');
|
|
|
|
function parseArgs(argv) {
|
|
const out = { target: null, requireSigned: false };
|
|
for (let i = 0; i < argv.length; i++) {
|
|
if (argv[i] === '--target') out.target = argv[++i];
|
|
else if (argv[i] === '--require-signed') out.requireSigned = true;
|
|
}
|
|
return out;
|
|
}
|
|
|
|
function sh(cmd) {
|
|
try { return { ok: true, out: execSync(cmd, { encoding: 'utf8' }).trim() }; }
|
|
catch (e) { return { ok: false, out: ((e.stdout || '') + (e.stderr || '')).toString().trim(), code: e.status }; }
|
|
}
|
|
|
|
// Windows: Authenticode status + signer subject via Get-AuthenticodeSignature.
|
|
// Azure Trusted Signing uses fresh short-lived certs, so Get-AuthenticodeSignature
|
|
// reports "Unknown" on a CI runner (chain/revocation can't validate in-context)
|
|
// even when the file IS properly signed. So when a signer cert is present but the
|
|
// quick status isn't "Valid", we defer to `signtool verify /pa`, the canonical
|
|
// Authenticode verifier. A genuinely unsigned file (no signer) still fails the gate.
|
|
function inspectWindows(target) {
|
|
const ps = `$ErrorActionPreference='SilentlyContinue'; $s = Get-AuthenticodeSignature -LiteralPath '${target}'; '{0}|{1}' -f $s.Status, ($s.SignerCertificate.Subject)`;
|
|
const r = sh(`powershell -NoProfile -Command "${ps.replace(/"/g, '\\"')}"`);
|
|
const [statusRaw, subject] = (r.out || '').split('|');
|
|
const status = (statusRaw || 'Unknown').trim();
|
|
const signer = (subject || '').trim();
|
|
|
|
if (status === 'Valid') return { signed: true, status, signer };
|
|
// Azure Trusted Signing's fresh short-lived certs make Get-AuthenticodeSignature
|
|
// report "Unknown" (often with a null SignerCertificate) on CI runners even when the
|
|
// file IS signed, so its quick status can't be trusted here. Defer to signtool
|
|
// verify /pa, the canonical Authenticode verifier, as the authoritative check: it
|
|
// passes a genuinely-signed file and fails a genuinely-unsigned one.
|
|
const signtool = process.env.SIGNTOOL_PATH || 'signtool';
|
|
const v = sh(`"${signtool}" verify /pa "${target}"`);
|
|
return {
|
|
signed: v.ok,
|
|
status: `${status} | signtool verify /pa: ${v.ok ? 'pass' : 'FAIL'}`,
|
|
signer,
|
|
detail: v.ok ? '' : v.out,
|
|
};
|
|
}
|
|
|
|
// macOS: codesign validity + Gatekeeper assessment + notarization staple.
|
|
function inspectMac(target) {
|
|
const cs = sh(`codesign --verify --deep --strict --verbose=2 "${target}"`);
|
|
const assess = sh(`spctl --assess --type execute --verbose=4 "${target}"`);
|
|
const staple = sh(`xcrun stapler validate "${target}"`);
|
|
const signed = cs.ok && assess.ok;
|
|
const status = `codesign=${cs.ok ? 'valid' : 'invalid'} gatekeeper=${assess.ok ? 'accepted' : 'rejected'} staple=${staple.ok ? 'present' : 'absent'}`;
|
|
return { signed, status, signer: (cs.out.match(/Authority=(.+)/) || [])[1] || '' };
|
|
}
|
|
|
|
function main() {
|
|
const args = parseArgs(process.argv.slice(2));
|
|
const target = h.signableTarget(args.target || h.packagedAppPath());
|
|
process.stdout.write(`Inspecting signature: ${target}\n`);
|
|
|
|
let info;
|
|
if (process.platform === 'win32') info = inspectWindows(target);
|
|
else if (process.platform === 'darwin') info = inspectMac(target);
|
|
else { process.stdout.write(' (linux: no code-signing model checked)\n'); process.exit(0); }
|
|
|
|
process.stdout.write(` signed = ${info.signed}\n status = ${info.status}\n`);
|
|
if (info.signer) process.stdout.write(` signer = ${info.signer}\n`);
|
|
if (info.detail) process.stdout.write(` signtool: ${info.detail}\n`);
|
|
|
|
if (args.requireSigned && !info.signed) {
|
|
process.stderr.write(`\nSIGNATURE FAIL: --require-signed but artifact is not validly signed (${info.status}).\n`);
|
|
process.exit(1);
|
|
}
|
|
if (!info.signed) process.stdout.write('\nNOTE: artifact is UNSIGNED (expected for a local dev build; CI signs on v* tags).\n');
|
|
else process.stdout.write('\nSIGNATURE OK: artifact is validly signed.\n');
|
|
process.exit(0);
|
|
}
|
|
|
|
main();
|