ci(macos): harden candidate verification diagnostics

This commit is contained in:
wiiiii123
2026-08-09 02:33:58 +07:00
parent b9683c8fbe
commit 1819ca55ff
3 changed files with 51 additions and 8 deletions
+17 -2
View File
@@ -158,12 +158,27 @@ jobs:
cert_path="$RUNNER_TEMP/recordly-developer-id.p12"
cert_pem_path="$RUNNER_TEMP/recordly-developer-id.pem"
printf '%s' "$APPLE_SIGNING_CERTIFICATE_P12_BASE64" | base64 --decode > "$cert_path"
openssl pkcs12 \
if ! openssl pkcs12 \
-in "$cert_path" \
-clcerts \
-nokeys \
-passin env:APPLE_SIGNING_CERTIFICATE_PASSWORD \
-out "$cert_pem_path"
-out "$cert_pem_path"; then
rm -f "$cert_pem_path"
pkcs12_help="$(openssl pkcs12 -help 2>&1 || true)"
if [[ "$pkcs12_help" != *"-legacy"* ]]; then
echo "PKCS#12 extraction failed and this OpenSSL has no legacy-provider fallback."
exit 1
fi
echo "Standard PKCS#12 extraction failed; retrying legacy Keychain compatibility."
openssl pkcs12 \
-legacy \
-in "$cert_path" \
-clcerts \
-nokeys \
-passin env:APPLE_SIGNING_CERTIFICATE_PASSWORD \
-out "$cert_pem_path"
fi
openssl x509 -in "$cert_pem_path" -noout -checkend 86400
cert_subject="$(openssl x509 -in "$cert_pem_path" -noout -subject -nameopt RFC2253 | sed 's/^subject=//')"
@@ -83,6 +83,15 @@ describe("macOS distribution entitlement policy", () => {
"unexpected root application entitlement: com.apple.security.cs.allow-dyld-environment-variables",
]);
});
it("rejects disabled but unreviewed entitlement keys", () => {
expect(
collectEntitlementErrors({
...validEntitlements,
"com.apple.security.get-task-allow": false,
}),
).toEqual(["unexpected root application entitlement: com.apple.security.get-task-allow"]);
});
});
describe("macOS distribution architecture policy", () => {
+25 -6
View File
@@ -26,6 +26,7 @@ const packageJson = JSON.parse(readFileSync(path.join(projectRoot, "package.json
const productName = packageJson.productName ?? packageJson.name ?? "Recordly";
const expectedBundleId = "dev.recordly.app";
const commandTimeoutMs = 5 * 60 * 1000;
const fileClassificationBatchSize = 100;
const maxReportDetailLength = 4_000;
function parseArguments(argv) {
@@ -281,10 +282,20 @@ function verifyEntitlements(appPath, label, tempRoot, check) {
function verifyMachOBinaries(appPath, arch, check) {
check("packaged app: nested Mach-O signatures and architectures", () => {
const machOBinaries = [];
for (const filePath of walkRegularFiles(appPath)) {
const fileType = runProcess("file", ["-b", filePath]).stdout;
if (fileType.includes("Mach-O")) {
machOBinaries.push(filePath);
const regularFiles = walkRegularFiles(appPath);
for (let index = 0; index < regularFiles.length; index += fileClassificationBatchSize) {
const batch = regularFiles.slice(index, index + fileClassificationBatchSize);
const fileTypes = runProcess("file", ["-b", ...batch]).stdout.split(/\r?\n/);
if (fileTypes.length !== batch.length) {
throw new Error(
`file classification returned ${fileTypes.length} rows for ${batch.length} paths`,
);
}
for (let batchIndex = 0; batchIndex < batch.length; batchIndex += 1) {
if (fileTypes[batchIndex].includes("Mach-O")) {
machOBinaries.push(batch[batchIndex]);
}
}
}
@@ -408,7 +419,7 @@ export function verifyMacOSDistribution(argv = process.argv.slice(2)) {
check("DMG filesystem integrity", () => runProcess("hdiutil", ["verify", dmgPath]).output);
const dmgMountPath = path.join(tempRoot, "dmg");
check("DMG mounts read-only", () => {
check("DMG attaches read-only for inspection", () => {
runProcess("mkdir", ["-p", dmgMountPath]);
runProcess("hdiutil", [
"attach",
@@ -453,7 +464,15 @@ export function verifyMacOSDistribution(argv = process.argv.slice(2)) {
console.log(`[macos-distribution] verification report: ${options.reportPath}`);
return report;
} catch (error) {
writeReport(report, options.reportPath, options.summaryPath);
try {
writeReport(report, options.reportPath, options.summaryPath);
} catch (reportError) {
console.error(
`[macos-distribution] failed to write report: ${
reportError instanceof Error ? reportError.message : String(reportError)
}`,
);
}
throw error;
} finally {
if (mountedDmgPath) {