UNPKG

@capgo/capgo-skills

Version:

55 agent skills for Capacitor mobile development

110 lines (103 loc) • 4.34 kB
#!/usr/bin/env node // Filter `xcodebuild -showBuildSettings -json` output to security-relevant settings. // Usage: // node audit-build-settings.mjs <settings.json> [--pbxproj path/to/project.pbxproj] [--target App] [--unhardened] // Read-only: never writes files. import { readFileSync } from 'node:fs'; // key -> expected hardened value(s). `null` means informational only. const TRACKED = { // Stage A: compiler warnings GCC_WARN_ABOUT_RETURN_TYPE: ['YES_ERROR'], GCC_WARN_UNINITIALIZED_AUTOS: ['YES_AGGRESSIVE'], CLANG_WARN_IMPLICIT_FALLTHROUGH: ['YES'], GCC_WARN_64_TO_32_BIT_CONVERSION: ['YES'], GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS: ['YES'], // Stage B: static analyzer CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER: ['YES'], CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND: ['YES'], CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY: ['YES'], CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION: ['YES'], // Default-on checkers (flag only if disabled) CLANG_ANALYZER_SECURITY_KEYCHAIN_API: ['YES'], CLANG_ANALYZER_SECURITY_INSECUREAPI_UNCHECKEDRETURN: ['YES'], CLANG_ANALYZER_SECURITY_INSECUREAPI_GETPW_GETS: ['YES'], CLANG_ANALYZER_SECURITY_INSECUREAPI_MKSTEMP: ['YES'], CLANG_ANALYZER_SECURITY_INSECUREAPI_VFORK: ['YES'], GCC_WARN_TYPECHECK_CALLS_TO_PRINTF: ['YES'], // Stage C: Enhanced Security ENABLE_ENHANCED_SECURITY: ['YES'], ENABLE_POINTER_AUTHENTICATION: ['YES'], ENABLE_HARDWARE_CHECKED_POINTER_ARITHMETIC_SLICE: ['YES'], GCC_WARN_SHADOW: ['YES'], CLANG_WARN_EMPTY_BODY: ['YES'], ENABLE_SECURITY_COMPILER_WARNINGS: ['YES'], CLANG_CXX_STANDARD_LIBRARY_HARDENING: ['fast', 'debug', 'extensive'], CLANG_ENABLE_C_TYPED_ALLOCATOR_SUPPORT: ['YES'], CLANG_ENABLE_CPLUSPLUS_TYPED_ALLOCATOR_SUPPORT: ['YES'], // Stage E: extra diagnostics CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION: ['YES'], CLANG_ANALYZER_SECURITY_BUFFER_OVERFLOW_EXPERIMENTAL: ['YES'], CLANG_WARN_ASSIGN_ENUM: ['YES'], GCC_WARN_SIGN_COMPARE: ['YES'], CLANG_WARN_COMPLETION_HANDLER_MISUSE: ['YES'], CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF: ['YES'], CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK: ['YES'], ENABLE_USER_SCRIPT_SANDBOXING: ['YES'], // Context CODE_SIGN_ENTITLEMENTS: null, IPHONEOS_DEPLOYMENT_TARGET: null, SDKROOT: null, SUPPORTED_PLATFORMS: null, SWIFT_VERSION: null, ONLY_ACTIVE_ARCH: null, ARCHS: null, CONFIGURATION: null, }; const args = process.argv.slice(2); const file = args.find((a) => !a.startsWith('--') && args[args.indexOf(a) - 1] !== '--pbxproj' && args[args.indexOf(a) - 1] !== '--target'); const opt = (name) => { const i = args.indexOf(name); return i >= 0 ? args[i + 1] : undefined; }; const pbxPath = opt('--pbxproj'); const targetFilter = opt('--target'); const unhardenedOnly = args.includes('--unhardened'); if (!file) { console.error('usage: audit-build-settings.mjs <settings.json> [--pbxproj file] [--target App] [--unhardened]'); process.exit(2); } let entries; try { entries = JSON.parse(readFileSync(file, 'utf8')); } catch (e) { console.error(`Cannot parse ${file} as JSON. Did you pass -json to xcodebuild -showBuildSettings? (${e.message})`); process.exit(1); } if (!Array.isArray(entries)) entries = [entries]; const pbxLines = pbxPath ? readFileSync(pbxPath, 'utf8').split('\n') : []; const explicitLines = (key) => { const rx = new RegExp(`\\b${key}\\s*=`); const hits = []; pbxLines.forEach((line, i) => { if (rx.test(line)) hits.push(i + 1); }); return hits; }; for (const entry of entries) { const target = entry.target ?? '(unknown target)'; if (targetFilter && target !== targetFilter) continue; const bs = entry.buildSettings ?? {}; console.log(`\n# target: ${target} configuration: ${bs.CONFIGURATION ?? '?'}`); for (const [key, expected] of Object.entries(TRACKED)) { const value = bs[key] ?? ''; const lines = pbxPath ? explicitLines(key) : []; let status; if (expected === null) status = 'info'; else if (expected.includes(value)) status = 'hardened'; else if (lines.length > 0) status = 'DISABLED'; else status = 'default-off'; if (unhardenedOnly && (status === 'hardened' || status === 'info')) continue; const where = lines.length ? ` [explicit: pbxproj ${lines.join(',')}]` : ''; console.log(`${status.padEnd(12)} ${key}=${value}${where}`); } }