From ea708c35f8092d9d4af0f7385e5ec7f55d77580d Mon Sep 17 00:00:00 2001 From: Sarthak Agrawal Date: Wed, 2 Sep 2026 22:09:37 +0530 Subject: [PATCH 1/5] chore: complete verification tooling modules 1/1 --- scripts/run-cross-review-benchmark.mjs | 455 +++++++++++++ scripts/run-cross-review-benchmark.test.mjs | 101 +++ scripts/run-native-bridge-benchmark.sh | 43 ++ scripts/run-native-checks.test.mjs | 156 +++++ scripts/run-osv-offline.mjs | 191 ++++++ scripts/run-osv-offline.test.mjs | 70 ++ scripts/stryker-accounting.config.mjs | 33 + scripts/sync-capability-registry.mjs | 55 ++ scripts/verification-receipts/dogfood-cli.mjs | 102 +++ .../producer-adapters.mjs | 641 ++++++++++++++++++ 10 files changed, 1847 insertions(+) create mode 100644 scripts/run-cross-review-benchmark.mjs create mode 100644 scripts/run-cross-review-benchmark.test.mjs create mode 100755 scripts/run-native-bridge-benchmark.sh create mode 100644 scripts/run-native-checks.test.mjs create mode 100644 scripts/run-osv-offline.mjs create mode 100644 scripts/run-osv-offline.test.mjs create mode 100644 scripts/stryker-accounting.config.mjs create mode 100644 scripts/sync-capability-registry.mjs create mode 100644 scripts/verification-receipts/dogfood-cli.mjs create mode 100644 scripts/verification-receipts/producer-adapters.mjs diff --git a/scripts/run-cross-review-benchmark.mjs b/scripts/run-cross-review-benchmark.mjs new file mode 100644 index 00000000..98a02525 --- /dev/null +++ b/scripts/run-cross-review-benchmark.mjs @@ -0,0 +1,455 @@ +#!/usr/bin/env node + +import { spawn } from 'node:child_process'; +import { createHash, randomUUID } from 'node:crypto'; +import { + cpSync, + existsSync, + mkdirSync, + mkdtempSync, + readFileSync, + readdirSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import { dirname, join, resolve } from 'node:path'; +import { fileURLToPath, pathToFileURL } from 'node:url'; + +const repositoryRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..'); +const defaultCasesRoot = join(repositoryRoot, 'benchmarks/public-catch-rate/cases'); +const defaultBinary = join(repositoryRoot, 'apps/desktop/src-tauri/target/debug/codevetter'); +const genericTask = + 'Review this exact change for correctness, security, reliability, and maintainability defects.'; + +const typeKeywords = { + sql_injection: ['sql injection', 'parameteriz', 'interpolat'], + xss: ['xss', 'cross-site scripting', 'innerhtml', 'unescaped', 'sanitiz'], + hardcoded_credentials: ['hardcoded', 'hard-coded', 'credential', 'secret', 'password'], + hardcoded_secret: ['hardcoded', 'hard-coded', 'credential', 'secret', 'api key'], + command_injection: ['command injection', 'shell', 'exec', 'subprocess', 'os.system'], + path_traversal: ['path traversal', 'directory traversal', '../', 'normaliz'], + ssrf: ['ssrf', 'server-side request forgery', 'internal network', 'metadata'], + insecure_deserialization: ['deserializ', 'pickle', 'unpickl', 'yaml.load'], + weak_crypto: ['md5', 'sha1', 'sha-1', 'weak hash'], + insecure_random: ['random', 'prng', 'securerandom', 'predictable'], + race_condition: ['race', 'concurrent', 'mutex', 'atomic', 'lock'], + nil_dereference: ['nil pointer', 'nil deref', 'null pointer', 'nil check'], + unchecked_error: ['unchecked error', 'ignored error', 'error return', 'err !='], + code_injection: ['eval', 'code injection', 'function constructor'], + open_redirect: ['open redirect', 'redirect', 'unvalidated url'], + swallowed_error: ['bare except', 'broad exception', 'swallow'], + resource_exhaustion: ['zip bomb', 'decompression', 'uncompressed size', 'resource'], + integer_overflow: ['overflow', 'wrapping', 'checked_', 'saturating'], + dead_code: ['dead code', 'unused', 'unreachable'], + missing_await: ['await', 'unawaited', 'floating promise'], + prototype_pollution: ['prototype pollution', '__proto__', 'constructor.prototype'], + regex_dos: ['redos', 'regex dos', 'catastrophic backtracking', 'exponential'], + insecure_cookie: ['cookie', 'httponly', 'secure flag', 'samesite'], + type_confusion: ['type confusion', 'unsafe cast', 'as unknown', 'any'], +}; + +export function parseArguments(argv) { + const options = { + binary: defaultBinary, + casesRoot: defaultCasesRoot, + caseIDs: [], + limit: undefined, + outRoot: join(repositoryRoot, 'artifacts/cross-review-benchmark'), + rescore: false, + resumeDirectory: undefined, + timeoutMS: 300_000, + }; + const readers = { + '--binary': (value) => { + options.binary = resolve(value); + }, + '--cases-root': (value) => { + options.casesRoot = resolve(value); + }, + '--case': (value) => { + options.caseIDs.push(value); + }, + '--limit': (value) => { + options.limit = Number(value); + }, + '--out-root': (value) => { + options.outRoot = resolve(value); + }, + '--resume': (value) => { + options.resumeDirectory = resolve(value); + }, + '--timeout-ms': (value) => { + options.timeoutMS = Number(value); + }, + }; + for (let index = 0; index < argv.length; index += 1) { + const argument = argv[index]; + if (argument === '--') continue; + if (argument === '--rescore') { + options.rescore = true; + continue; + } + const reader = readers[argument]; + const next = argv[index + 1]; + if (!reader || next === undefined) + throw new Error(`Unknown or incomplete argument: ${argument}`); + reader(next); + index += 1; + } + if (options.limit !== undefined && (!Number.isInteger(options.limit) || options.limit < 1)) { + throw new Error('--limit must be a positive integer'); + } + if (!Number.isInteger(options.timeoutMS) || options.timeoutMS < 1_000) { + throw new Error('--timeout-ms must be an integer of at least 1000'); + } + return options; +} + +function keywordsFor(type) { + return typeKeywords[type] ?? [String(type).replaceAll('_', ' ')]; +} + +function findingText(finding) { + return `${finding.title ?? ''} ${finding.summary ?? ''} ${finding.suggestion ?? ''}`.toLowerCase(); +} + +export function matchFinding(finding, label) { + const findingPath = finding.filePath ?? finding.file_path; + const findingLine = Number(finding.line); + if (findingPath !== label.source_file || !Number.isInteger(findingLine) || findingLine < 1) { + return []; + } + const text = findingText(finding); + return label.ground_truth + .filter((groundTruth) => { + const [first, last] = groundTruth.location?.lines ?? []; + const lineMatches = + Number.isInteger(first) && Number.isInteger(last) + ? findingLine >= first - 5 && findingLine <= last + 5 + : false; + return lineMatches && keywordsFor(groundTruth.type).some((keyword) => text.includes(keyword)); + }) + .map((groundTruth) => groundTruth.id); +} + +export function scoreFindings(findings, label) { + const caught = new Set(); + let falsePositives = 0; + let redundant = 0; + for (const finding of findings) { + const matches = matchFinding(finding, label); + if (matches.length === 0) { + falsePositives += 1; + continue; + } + let added = false; + for (const match of matches) { + if (!caught.has(match)) { + caught.add(match); + added = true; + } + } + if (!added) redundant += 1; + } + const expected = label.ground_truth.length; + return { + expected, + caught: caught.size, + missed: label.ground_truth.map((groundTruth) => groundTruth.id).filter((id) => !caught.has(id)), + findings: findings.length, + false_positives: falsePositives, + redundant, + }; +} + +export function aggregateScores(cases, reviewer) { + const totals = cases.reduce( + (sum, entry) => { + const score = entry.reviewers[reviewer]; + for (const key of ['expected', 'caught', 'findings', 'false_positives', 'redundant']) { + sum[key] += score[key]; + } + sum.duration_ms += entry.duration_ms[reviewer] ?? 0; + return sum; + }, + { expected: 0, caught: 0, findings: 0, false_positives: 0, redundant: 0, duration_ms: 0 } + ); + const denominator = totals.caught + totals.false_positives + totals.redundant; + const recall = totals.expected === 0 ? 0 : totals.caught / totals.expected; + const precision = denominator === 0 ? 0 : totals.caught / denominator; + return { + ...totals, + recall, + precision, + f1: recall + precision === 0 ? 0 : (2 * recall * precision) / (recall + precision), + mean_duration_ms: cases.length === 0 ? 0 : Math.round(totals.duration_ms / cases.length), + }; +} + +export function scoreReceipt(receipt, label) { + const crossReview = receipt.stages?.review?.evidence?.cross_review; + if (crossReview?.status !== 'completed') { + throw new Error(`case ${label.id} did not complete both passes`); + } + const passes = Object.fromEntries(crossReview.passes.map((pass) => [pass.reviewer, pass])); + return { + claude: scoreFindings(passes.claude?.qualified_findings ?? [], label), + codex: scoreFindings(passes.codex?.qualified_findings ?? [], label), + cross: scoreFindings(crossReview.findings ?? [], label), + }; +} + +function sha256File(path) { + return createHash('sha256').update(readFileSync(path)).digest('hex'); +} + +function run(command, arguments_, options = {}) { + return new Promise((resolvePromise, reject) => { + const child = spawn(command, arguments_, { + cwd: options.cwd, + env: options.env, + stdio: ['ignore', 'pipe', 'pipe'], + }); + const stdout = []; + const stderr = []; + child.stdout.on('data', (chunk) => stdout.push(chunk)); + child.stderr.on('data', (chunk) => stderr.push(chunk)); + const timeout = setTimeout(() => { + child.kill('SIGTERM'); + setTimeout(() => child.kill('SIGKILL'), 2_000).unref(); + }, options.timeoutMS ?? 30_000); + child.on('error', reject); + child.on('close', (code, signal) => { + clearTimeout(timeout); + resolvePromise({ + code, + signal, + stdout: Buffer.concat(stdout).toString('utf8'), + stderr: Buffer.concat(stderr).toString('utf8'), + }); + }); + }); +} + +async function git(repo, ...arguments_) { + const result = await run('git', arguments_, { cwd: repo, timeoutMS: 30_000 }); + if (result.code !== 0) throw new Error(`git ${arguments_.join(' ')} failed`); +} + +async function prepareCase(caseDirectory, label, workRoot) { + const repo = join(workRoot, 'repo'); + mkdirSync(repo, { recursive: true }); + await git(repo, 'init', '--quiet'); + await git(repo, 'config', 'user.name', 'CodeVetter Benchmark'); + await git(repo, 'config', 'user.email', 'benchmark@codevetter.local'); + writeFileSync(join(repo, 'README.md'), '# Synthetic review case\n'); + await git(repo, 'add', 'README.md'); + await git(repo, 'commit', '--quiet', '-m', 'baseline'); + cpSync(join(caseDirectory, label.source_file), join(repo, label.source_file)); + await git(repo, 'add', label.source_file); + await git(repo, 'commit', '--quiet', '-m', 'candidate'); + return repo; +} + +function boundedFailure(result) { + const summary = result.stderr.trim().split('\n').slice(-8).join('\n'); + return summary.slice(0, 2_000); +} + +async function runCase({ binary, caseDirectory, label, outputDirectory, timeoutMS }) { + const workRoot = mkdtempSync(join(tmpdir(), `codevetter-cross-${label.id}-`)); + try { + const repo = await prepareCase(caseDirectory, label, workRoot); + const appData = join(workRoot, 'app-data'); + mkdirSync(appData, { recursive: true }); + const started = Date.now(); + const result = await run( + binary, + [ + 'check', + '--range', + 'HEAD^..HEAD', + '--task', + genericTask, + '--agent', + 'cross', + '--repo', + repo, + '--request-id', + `cross-benchmark-${label.id}-${randomUUID()}`, + '--json', + ], + { + cwd: repo, + env: { ...process.env, CODEVETTER_APP_DATA_DIR: appData }, + timeoutMS, + } + ); + const wallTimeMS = Date.now() - started; + let receipt; + try { + receipt = JSON.parse(result.stdout); + } catch { + throw new Error( + `case ${label.id} emitted no valid receipt (exit ${result.code}, signal ${result.signal ?? 'none'}): ${boundedFailure(result)}` + ); + } + const crossReview = receipt.stages?.review?.evidence?.cross_review; + const receiptName = + crossReview?.status === 'completed' + ? `${label.id}.json` + : `${label.id}.incomplete-${randomUUID()}.json`; + writeFileSync( + join(outputDirectory, 'receipts', receiptName), + `${JSON.stringify(receipt, null, 2)}\n` + ); + if (crossReview?.status !== 'completed') { + throw new Error(`case ${label.id} did not complete both passes`); + } + const passes = Object.fromEntries(crossReview.passes.map((pass) => [pass.reviewer, pass])); + const reviewers = scoreReceipt(receipt, label); + const entry = { + case_id: label.id, + exit_code: result.code, + verdict: receipt.verdict, + wall_time_ms: wallTimeMS, + policy_binding: crossReview.policy_binding, + unit_plan_identity: crossReview.unit_plan_identity, + classes: crossReview.counts, + duration_ms: { + claude: passes.claude?.duration_ms ?? null, + codex: passes.codex?.duration_ms ?? null, + cross: receipt.stages?.review?.duration_ms ?? wallTimeMS, + }, + usage: { + claude: passes.claude?.usage ?? null, + codex: passes.codex?.usage ?? null, + }, + reviewers, + }; + return entry; + } finally { + rmSync(workRoot, { recursive: true, force: true }); + } +} + +function loadCases({ partialPath, rescore, casesRoot, outputDirectory }) { + let cases = existsSync(partialPath) ? JSON.parse(readFileSync(partialPath, 'utf8')) : []; + if (!rescore) return cases; + cases = cases.map((entry) => { + const label = JSON.parse(readFileSync(join(casesRoot, entry.case_id, 'label.json'), 'utf8')); + const receipt = JSON.parse( + readFileSync(join(outputDirectory, 'receipts', `${entry.case_id}.json`), 'utf8') + ); + return { ...entry, reviewers: scoreReceipt(receipt, label) }; + }); + writeFileSync(partialPath, `${JSON.stringify(cases, null, 2)}\n`); + return cases; +} + +export async function main(argv = process.argv.slice(2)) { + const options = parseArguments(argv); + if (!existsSync(options.binary)) + throw new Error(`CodeVetter binary not found: ${options.binary}`); + if (!existsSync(options.casesRoot)) + throw new Error(`Benchmark cases not found: ${options.casesRoot}`); + + const allIDs = readdirSync(options.casesRoot, { withFileTypes: true }) + .filter((entry) => entry.isDirectory()) + .map((entry) => entry.name) + .sort(); + let caseIDs = options.caseIDs.length > 0 ? options.caseIDs : allIDs; + if (options.limit !== undefined) caseIDs = caseIDs.slice(0, options.limit); + for (const caseID of caseIDs) { + if (!allIDs.includes(caseID)) throw new Error(`Unknown benchmark case: ${caseID}`); + } + + const runID = new Date() + .toISOString() + .replaceAll(':', '-') + .replace(/\.\d{3}Z$/, 'Z'); + const outputDirectory = options.resumeDirectory ?? join(options.outRoot, runID); + mkdirSync(join(outputDirectory, 'receipts'), { recursive: true }); + const partialPath = join(outputDirectory, 'partial.json'); + const cases = loadCases({ + partialPath, + rescore: options.rescore, + casesRoot: options.casesRoot, + outputDirectory, + }); + const completedCaseIDs = new Set(cases.map((entry) => entry.case_id)); + const sourceRevision = ( + await run('git', ['rev-parse', 'HEAD'], { cwd: repositoryRoot, timeoutMS: 30_000 }) + ).stdout.trim(); + for (const [index, caseID] of caseIDs.entries()) { + if (completedCaseIDs.has(caseID)) { + console.log(`[cross-benchmark] ${index + 1}/${caseIDs.length} ${caseID} (preserved)`); + continue; + } + console.log(`[cross-benchmark] ${index + 1}/${caseIDs.length} ${caseID}`); + const caseDirectory = join(options.casesRoot, caseID); + const label = JSON.parse(readFileSync(join(caseDirectory, 'label.json'), 'utf8')); + let entry; + let lastError; + for (let attempt = 1; attempt <= 2 && !entry; attempt += 1) { + try { + entry = await runCase({ + binary: options.binary, + caseDirectory, + label, + outputDirectory, + timeoutMS: options.timeoutMS, + }); + } catch (error) { + lastError = error; + console.warn(`[cross-benchmark] ${caseID} attempt ${attempt}/2: ${error.message}`); + } + } + if (!entry) throw lastError; + cases.push(entry); + writeFileSync(partialPath, `${JSON.stringify(cases, null, 2)}\n`); + console.log( + `[cross-benchmark] ${caseID}: claude ${entry.reviewers.claude.caught}/${entry.reviewers.claude.expected}, codex ${entry.reviewers.codex.caught}/${entry.reviewers.codex.expected}, cross ${entry.reviewers.cross.caught}/${entry.reviewers.cross.expected}` + ); + } + + const report = { + schema_version: 'codevetter.cross-review-benchmark/v1', + recorded_at: new Date().toISOString(), + source: { + repository_revision: sourceRevision, + binary_path: options.binary, + binary_sha256: sha256File(options.binary), + benchmark: 'benchmarks/public-catch-rate', + task: genericTask, + }, + policy: { + execution: 'Claude then Codex, independent original context', + mapping: 'same source path, label line within five lines, and narrow defect-type keywords', + limitations: [ + 'Synthetic single-file cases do not represent full repository review.', + 'Ground-truth mapping is deterministic but remains a proposal until human-reviewed.', + 'Provider usage is unavailable when the local executor omits it.', + 'Reviewer agreement is review coverage and never executable proof.', + ], + }, + cases, + reviewers: { + claude: aggregateScores(cases, 'claude'), + codex: aggregateScores(cases, 'codex'), + cross: aggregateScores(cases, 'cross'), + }, + }; + const reportPath = join(outputDirectory, 'report.json'); + writeFileSync(reportPath, `${JSON.stringify(report, null, 2)}\n`); + console.log(`[cross-benchmark] report ${reportPath}`); + return report; +} + +if (import.meta.url === pathToFileURL(process.argv[1]).href) { + main().catch((error) => { + console.error(`[cross-benchmark] ${error.message}`); + process.exitCode = 1; + }); +} diff --git a/scripts/run-cross-review-benchmark.test.mjs b/scripts/run-cross-review-benchmark.test.mjs new file mode 100644 index 00000000..079c1215 --- /dev/null +++ b/scripts/run-cross-review-benchmark.test.mjs @@ -0,0 +1,101 @@ +import assert from 'node:assert/strict'; +import test from 'node:test'; + +import { + aggregateScores, + matchFinding, + parseArguments, + scoreFindings, +} from './run-cross-review-benchmark.mjs'; + +const label = { + source_file: 'source.ts', + ground_truth: [ + { + id: 'sql-at-sink', + type: 'sql_injection', + location: { lines: [14, 14] }, + }, + ], +}; + +test('cross-review benchmark arguments reject ambiguous bounds', () => { + assert.equal(parseArguments(['--', '--limit', '2']).limit, 2); + assert.equal(parseArguments(['--rescore']).rescore, true); + assert.equal( + parseArguments(['--resume', 'artifacts/run']).resumeDirectory.endsWith('/artifacts/run'), + true + ); + assert.throws(() => parseArguments(['--limit', '0']), /positive integer/); + assert.throws(() => parseArguments(['--case']), /Unknown or incomplete/); +}); + +test('finding mapping requires path, nearby line, and defect semantics', () => { + assert.deepEqual( + matchFinding( + { + filePath: 'source.ts', + line: 13, + title: 'SQL injection through string interpolation', + }, + label + ), + ['sql-at-sink'] + ); + assert.deepEqual( + matchFinding({ filePath: 'source.ts', line: 13, title: 'Add a test' }, label), + [] + ); + assert.deepEqual( + matchFinding({ filePath: '../source.ts', line: 14, title: 'SQL injection' }, label), + [] + ); + assert.deepEqual( + matchFinding( + { filePath: 'source.py', line: 8, title: 'Passwords are stored with unsalted MD5' }, + { + source_file: 'source.py', + ground_truth: [ + { id: 'weak-password-hash', type: 'weak_crypto', location: { lines: [7, 7] } }, + ], + } + ), + ['weak-password-hash'] + ); +}); + +test('scoring separates missed, false-positive, and redundant findings', () => { + const score = scoreFindings( + [ + { filePath: 'source.ts', line: 14, title: 'SQL injection' }, + { filePath: 'source.ts', line: 14, title: 'Parameterize SQL injection' }, + { filePath: 'source.ts', line: 40, title: 'Unrelated concern' }, + ], + label + ); + assert.deepEqual(score, { + expected: 1, + caught: 1, + missed: [], + findings: 3, + false_positives: 1, + redundant: 1, + }); +}); + +test('aggregate report compares all reviewers under one scoring policy', () => { + const cases = [ + { + duration_ms: { claude: 100, codex: 80, cross: 180 }, + reviewers: { + claude: { expected: 2, caught: 1, findings: 2, false_positives: 1, redundant: 0 }, + codex: { expected: 2, caught: 2, findings: 2, false_positives: 0, redundant: 0 }, + cross: { expected: 2, caught: 2, findings: 3, false_positives: 1, redundant: 0 }, + }, + }, + ]; + const aggregate = aggregateScores(cases, 'cross'); + assert.equal(aggregate.recall, 1); + assert.equal(aggregate.precision, 2 / 3); + assert.equal(aggregate.mean_duration_ms, 180); +}); diff --git a/scripts/run-native-bridge-benchmark.sh b/scripts/run-native-bridge-benchmark.sh new file mode 100755 index 00000000..c07b0e4d --- /dev/null +++ b/scripts/run-native-bridge-benchmark.sh @@ -0,0 +1,43 @@ +#!/bin/sh +set -eu + +SCRIPT_DIR=$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd) +REPOSITORY_ROOT=$(CDPATH='' cd -- "$SCRIPT_DIR/.." && pwd) +ARTIFACT_DIR="$REPOSITORY_ROOT/artifacts/native-bridge" +RUST_MANIFEST="$REPOSITORY_ROOT/apps/desktop/src-tauri/Cargo.toml" +SWIFT_PACKAGE="$REPOSITORY_ROOT/apps/macos/CodeVetterPackage" +BRIDGE_LIBRARY="$ARTIFACT_DIR/libcodevetter_bridge_probe.dylib" +CODEVETTER_CLI="$REPOSITORY_ROOT/apps/desktop/src-tauri/target/release/codevetter" +BENCHMARK_BIN="$SWIFT_PACKAGE/.build/out/Products/Release/NativeBridgeBenchmark" +XCODEBUILDMCP_NPM_CACHE="$ARTIFACT_DIR/xcodebuildmcp-npm-cache" + +mkdir -p "$ARTIFACT_DIR" "$XCODEBUILDMCP_NPM_CACHE" +cd "$REPOSITORY_ROOT" + +# pnpm projects child npm settings into scripts. Keep the pinned npx invocation +# isolated from package-manager-only keys that npm otherwise warns about. +unset npm_config_user_agent npm_config_verify_deps_before_run \ + npm_config_npm_globalconfig npm_config__jsr_registry npm_config_store_dir 2>/dev/null || true + +rustc --crate-type cdylib -O \ + benchmarks/native-bridge/capability_bridge.rs \ + -o "$BRIDGE_LIBRARY" + +TAURI_CONFIG='{"bundle":{"externalBin":[]}}' \ + cargo build --release --manifest-path "$RUST_MANIFEST" \ + --features browser-agent --bin codevetter + +npm_config_cache="$XCODEBUILDMCP_NPM_CACHE" \ + npm_config_userconfig=/dev/null \ + npm_config_globalconfig="$ARTIFACT_DIR/empty-npmrc" \ + npm_config_update_notifier=false \ + npx -y xcodebuildmcp@2.7.0 swift-package build \ + --package-path "$SWIFT_PACKAGE" \ + --configuration release + +if [ ! -x "$BENCHMARK_BIN" ]; then + echo "XcodeBuildMCP did not produce $BENCHMARK_BIN" >&2 + exit 2 +fi + +"$BENCHMARK_BIN" "$BRIDGE_LIBRARY" "$CODEVETTER_CLI" diff --git a/scripts/run-native-checks.test.mjs b/scripts/run-native-checks.test.mjs new file mode 100644 index 00000000..20adce10 --- /dev/null +++ b/scripts/run-native-checks.test.mjs @@ -0,0 +1,156 @@ +import assert from 'node:assert/strict'; +import test from 'node:test'; + +import { + nativeCheckCommands, + nativeCheckCachePath, + nativeCheckEnvironment, + nativeCheckInvocation, + nativeReleaseBuildSettings, + parseNativeCheckArguments, +} from './run-native-checks.mjs'; + +test('native automation defaults to the non-activating background lane', () => { + const parsed = parseNativeCheckArguments([]); + assert.deepEqual(parsed, { + mode: 'background', + foregroundApproved: false, + desktopIdleApproved: false, + }); + const commands = nativeCheckCommands(parsed); + assert.equal(commands.length, 2); + assert.ok(commands.every((command) => command.backgroundSafe)); + assert.ok( + commands.every( + (command) => !command.arguments.includes('test') || command.arguments[0] === 'swift-package' + ) + ); + assert.deepEqual(commands[0].arguments.slice(-2), ['--parallel', 'false']); +}); + +test('UI automation fails closed without explicit foreground approval', () => { + assert.throws(() => parseNativeCheckArguments(['--ui']), /requires the just-in-time flags/); + assert.throws(() => parseNativeCheckArguments(['--full']), /requires the just-in-time flags/); + assert.throws(() => parseNativeCheckArguments(['--ui', '--foreground']), /--desktop-idle/); + assert.throws(() => parseNativeCheckArguments(['--ui', '--desktop-idle']), /--foreground/); +}); + +test('release automation disables coverage at the workspace command boundary', () => { + const parsed = parseNativeCheckArguments(['--release']); + assert.deepEqual(parsed, { + mode: 'release', + foregroundApproved: false, + desktopIdleApproved: false, + }); + const [command] = nativeCheckCommands(parsed); + assert.equal(command.backgroundSafe, true); + assert.deepEqual(command.arguments.slice(0, 3), ['macos', 'build', '--json']); + const settings = JSON.parse(command.arguments[3]); + assert.equal(settings.configuration, 'Release'); + assert.equal(settings.arch, 'arm64'); + assert.equal(settings.derivedDataPath, 'artifacts/native-build/DerivedData'); + assert.deepEqual(settings.extraArgs, [ + 'ENABLE_CODE_COVERAGE=NO', + 'CLANG_ENABLE_CODE_COVERAGE=NO', + 'CLANG_COVERAGE_MAPPING=NO', + ]); +}); + +test('production release builds require exact updater and identity inputs', () => { + const publicKey = Buffer.alloc(32, 7).toString('base64'); + assert.deepEqual( + nativeReleaseBuildSettings({ + CODEVETTER_NATIVE_CHANNEL: 'production', + CODEVETTER_NATIVE_BUNDLE_IDENTIFIER: 'com.codevetter.desktop', + CODEVETTER_NATIVE_SPARKLE_FEED_URL: + 'https://github.com/Codevetter/codevetter/releases/latest/download/appcast.xml', + CODEVETTER_NATIVE_SPARKLE_PUBLIC_KEY: publicKey, + }).slice(-3), + [ + 'PRODUCT_BUNDLE_IDENTIFIER=com.codevetter.desktop', + 'INFOPLIST_KEY_SUFeedURL=https://github.com/Codevetter/codevetter/releases/latest/download/appcast.xml', + `INFOPLIST_KEY_SUPublicEDKey=${publicKey}`, + ] + ); + assert.throws( + () => nativeReleaseBuildSettings({ CODEVETTER_NATIVE_CHANNEL: 'production' }), + /com\.codevetter\.desktop/ + ); + assert.throws( + () => + nativeReleaseBuildSettings({ + CODEVETTER_NATIVE_CHANNEL: 'production', + CODEVETTER_NATIVE_BUNDLE_IDENTIFIER: 'com.codevetter.desktop', + CODEVETTER_NATIVE_SPARKLE_FEED_URL: 'http://updates.example.test/appcast.xml', + CODEVETTER_NATIVE_SPARKLE_PUBLIC_KEY: publicKey, + }), + /HTTPS Sparkle feed/ + ); +}); + +test('the foreground lane runs only XCUITest interaction targets', () => { + const parsed = parseNativeCheckArguments(['--ui', '--', '--foreground', '--desktop-idle']); + const [command] = nativeCheckCommands(parsed); + assert.equal(command.backgroundSafe, false); + assert.equal(command.arguments[0], 'macos'); + assert.match(command.arguments.at(-1), /only-testing:CodeVetterUITests/); +}); + +test('the pnpm argument delimiter does not weaken unknown-argument rejection', () => { + assert.deepEqual(parseNativeCheckArguments(['--ui', '--', '--foreground', '--desktop-idle']), { + mode: 'ui', + foregroundApproved: true, + desktopIdleApproved: true, + }); + assert.throws( + () => + parseNativeCheckArguments(['--ui', '--', '--foreground', '--desktop-idle', '--unexpected']), + /Unknown native-check argument/ + ); +}); + +test('full qualification keeps background checks before the foreground lane', () => { + const commands = nativeCheckCommands( + parseNativeCheckArguments(['--full', '--foreground', '--desktop-idle']) + ); + assert.deepEqual( + commands.map((command) => command.backgroundSafe), + [true, true, false] + ); +}); + +test('the runner removes package-manager-only config noise from child npx processes', () => { + const environment = nativeCheckEnvironment( + { + PATH: '/usr/bin', + npm_config_store_dir: '/tmp/pnpm-store', + NPM_CONFIG_VERIFY_DEPS_BEFORE_RUN: 'true', + HTTPS_PROXY: 'https://proxy.example.test', + }, + '/tmp/native-cache' + ); + assert.deepEqual(environment, { + PATH: '/usr/bin', + HTTPS_PROXY: 'https://proxy.example.test', + npm_config_cache: '/tmp/native-cache', + npm_config_update_notifier: 'false', + }); +}); + +test('the reusable cache remains repository-local and outside committed evidence', () => { + assert.equal( + nativeCheckCachePath('/fixture/repo'), + '/fixture/repo/artifacts/native-checks/xcodebuildmcp-npm-cache' + ); +}); + +test('local checks stay polite while isolated hosted gates retain normal priority', () => { + const [background] = nativeCheckCommands(parseNativeCheckArguments([])); + const local = nativeCheckInvocation(background, {}); + assert.equal(local.executable, '/usr/bin/nice'); + assert.deepEqual(local.arguments.slice(0, 5), ['-n', '10', 'npx', '-y', 'xcodebuildmcp@2.7.0']); + + const hosted = nativeCheckInvocation(background, { GITHUB_ACTIONS: 'true' }); + assert.equal(hosted.executable, 'npx'); + assert.deepEqual(hosted.arguments.slice(0, 2), ['-y', 'xcodebuildmcp@2.7.0']); +}); diff --git a/scripts/run-osv-offline.mjs b/scripts/run-osv-offline.mjs new file mode 100644 index 00000000..01cbf728 --- /dev/null +++ b/scripts/run-osv-offline.mjs @@ -0,0 +1,191 @@ +#!/usr/bin/env node + +import { spawnSync } from 'node:child_process'; +import { createHash } from 'node:crypto'; +import { + closeSync, + existsSync, + mkdirSync, + openSync, + readSync, + readFileSync, + readdirSync, + renameSync, + statSync, + writeFileSync, +} from 'node:fs'; +import { homedir } from 'node:os'; +import { dirname, relative, resolve } from 'node:path'; +import { fileURLToPath, pathToFileURL } from 'node:url'; + +export const RECEIPT_SCHEMA = 'codevetter.osv-offline-scan/v1'; + +const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url)); +const REPOSITORY_ROOT = resolve(SCRIPT_DIR, '..'); +const DEFAULT_OUTPUT_DIR = resolve(REPOSITORY_ROOT, 'artifacts/tooling/osv'); + +function sha256File(path) { + const hash = createHash('sha256'); + const buffer = Buffer.alloc(1024 * 1024); + const descriptor = openSync(path, 'r'); + try { + let bytesRead = readSync(descriptor, buffer, 0, buffer.length, null); + while (bytesRead > 0) { + hash.update(buffer.subarray(0, bytesRead)); + bytesRead = readSync(descriptor, buffer, 0, buffer.length, null); + } + } finally { + closeSync(descriptor); + } + return hash.digest('hex'); +} + +export function defaultDatabaseRoot({ + platform = process.platform, + home = homedir(), + xdgCacheHome = process.env.XDG_CACHE_HOME, + localAppData = process.env.LOCALAPPDATA, +} = {}) { + if (platform === 'darwin') return resolve(home, 'Library/Caches/osv-scalibr'); + if (platform === 'win32' && localAppData) return resolve(localAppData, 'osv-scalibr'); + return resolve(xdgCacheHome ?? resolve(home, '.cache'), 'osv-scalibr'); +} + +export function parseScannerVersion(stdout) { + const match = stdout.match(/^osv-scanner version:\s*(\S+)/m); + if (!match) throw new Error('Unable to parse osv-scanner version output'); + return match[1]; +} + +export function classifyScannerExit(status) { + if (status === 0) return 'clean'; + if (status === 1) return 'findings'; + return 'operational_failure'; +} + +export function collectDatabaseIdentities(databaseRoot) { + if (!existsSync(databaseRoot)) return []; + return readdirSync(databaseRoot, { withFileTypes: true }) + .filter((entry) => entry.isDirectory()) + .map((entry) => ({ ecosystem: entry.name, path: resolve(databaseRoot, entry.name, 'all.zip') })) + .filter((entry) => existsSync(entry.path)) + .map(({ ecosystem, path }) => { + const stat = statSync(path); + return { + ecosystem, + sha256: sha256File(path), + bytes: stat.size, + modified_at: stat.mtime.toISOString(), + }; + }) + .sort((left, right) => left.ecosystem.localeCompare(right.ecosystem)); +} + +function gitRevision(repositoryRoot) { + const result = spawnSync('git', ['rev-parse', 'HEAD'], { + cwd: repositoryRoot, + encoding: 'utf8', + }); + if (result.status !== 0) throw new Error('Unable to resolve repository revision'); + return result.stdout.trim(); +} + +function sarifResultCount(path) { + const sarif = JSON.parse(readFileSync(path, 'utf8')); + return (sarif.runs ?? []).reduce((count, run) => count + (run.results?.length ?? 0), 0); +} + +function writeJsonAtomic(path, value) { + mkdirSync(dirname(path), { recursive: true }); + const temporary = `${path}.tmp-${process.pid}`; + writeFileSync(temporary, `${JSON.stringify(value, null, 2)}\n`); + renameSync(temporary, path); +} + +export function runOfflineScan({ + repositoryRoot = REPOSITORY_ROOT, + outputDir = DEFAULT_OUTPUT_DIR, + databaseRoot = defaultDatabaseRoot(), + scanner = 'osv-scanner', +} = {}) { + const versionResult = spawnSync(scanner, ['--version'], { encoding: 'utf8' }); + if (versionResult.status !== 0) { + throw new Error('osv-scanner is unavailable; install the pinned qualified version first'); + } + + const databases = collectDatabaseIdentities(databaseRoot); + if (databases.length === 0) { + throw new Error('No offline OSV databases found; refresh them in an explicit network step'); + } + + mkdirSync(outputDir, { recursive: true }); + const sarifPath = resolve(outputDir, 'results.sarif'); + const receiptPath = resolve(outputDir, 'receipt.json'); + const startedAt = new Date(); + const scan = spawnSync( + scanner, + [ + 'scan', + 'source', + '--offline', + '--offline-vulnerabilities', + '--recursive', + '--format=sarif', + `--output-file=${sarifPath}`, + '--verbosity=warn', + '.', + ], + { cwd: repositoryRoot, encoding: 'utf8' } + ); + const finishedAt = new Date(); + const outcome = classifyScannerExit(scan.status); + + const receipt = { + schema: RECEIPT_SCHEMA, + tool: { + name: 'osv-scanner', + version: parseScannerVersion(versionResult.stdout), + }, + source: { + revision: gitRevision(repositoryRoot), + scan_root: '.', + recursive: true, + }, + execution: { + network: 'disabled', + vulnerability_source: 'preseeded-local-databases', + started_at: startedAt.toISOString(), + finished_at: finishedAt.toISOString(), + duration_ms: finishedAt.getTime() - startedAt.getTime(), + scanner_exit_code: scan.status, + outcome, + }, + databases, + artifact: existsSync(sarifPath) + ? { + path: relative(repositoryRoot, sarifPath), + sha256: sha256File(sarifPath), + result_count: sarifResultCount(sarifPath), + } + : null, + limitations: [ + 'Database refresh is intentionally outside this offline command.', + 'A lockfile advisory does not by itself establish runtime reachability.', + 'OSV result count may include aliases for the same underlying vulnerability.', + ], + }; + writeJsonAtomic(receiptPath, receipt); + + if (scan.stderr) process.stderr.write(scan.stderr); + process.stdout.write(`${JSON.stringify(receipt, null, 2)}\n`); + return scan.status ?? 2; +} + +if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) { + try { + process.exitCode = runOfflineScan(); + } catch (error) { + process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`); + process.exitCode = 2; + } +} diff --git a/scripts/run-osv-offline.test.mjs b/scripts/run-osv-offline.test.mjs new file mode 100644 index 00000000..1393a799 --- /dev/null +++ b/scripts/run-osv-offline.test.mjs @@ -0,0 +1,70 @@ +import assert from 'node:assert/strict'; +import { mkdirSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import test from 'node:test'; + +import { + classifyScannerExit, + collectDatabaseIdentities, + defaultDatabaseRoot, + parseScannerVersion, + RECEIPT_SCHEMA, +} from './run-osv-offline.mjs'; + +test('defines a versioned receipt contract', () => { + assert.equal(RECEIPT_SCHEMA, 'codevetter.osv-offline-scan/v1'); +}); + +test('resolves platform cache roots without exposing them in evidence', () => { + assert.equal( + defaultDatabaseRoot({ platform: 'darwin', home: '/Users/example' }), + '/Users/example/Library/Caches/osv-scalibr' + ); + assert.equal( + defaultDatabaseRoot({ platform: 'linux', home: '/home/example' }), + '/home/example/.cache/osv-scalibr' + ); + assert.equal( + defaultDatabaseRoot({ + platform: 'linux', + home: '/home/example', + xdgCacheHome: '/cache', + }), + '/cache/osv-scalibr' + ); +}); + +test('parses scanner identity and keeps findings distinct from operational failure', () => { + assert.equal( + parseScannerVersion('osv-scanner version: 2.5.1\nosv-scalibr version: 0.5.2'), + '2.5.1' + ); + assert.equal(classifyScannerExit(0), 'clean'); + assert.equal(classifyScannerExit(1), 'findings'); + assert.equal(classifyScannerExit(2), 'operational_failure'); + assert.equal(classifyScannerExit(null), 'operational_failure'); +}); + +test('hashes databases by ecosystem without retaining absolute cache paths', (context) => { + const root = join(tmpdir(), `codevetter-osv-db-${process.pid}-${Date.now()}`); + context.after(() => { + // The test runner owns this unique temporary directory; removal is bounded. + rmSync(root, { recursive: true, force: true }); + }); + mkdirSync(join(root, 'npm'), { recursive: true }); + mkdirSync(join(root, 'crates.io'), { recursive: true }); + writeFileSync(join(root, 'npm', 'all.zip'), 'npm-db'); + writeFileSync(join(root, 'crates.io', 'all.zip'), 'rust-db'); + + const identities = collectDatabaseIdentities(root); + assert.deepEqual( + identities.map(({ ecosystem, bytes }) => ({ ecosystem, bytes })), + [ + { ecosystem: 'crates.io', bytes: 7 }, + { ecosystem: 'npm', bytes: 6 }, + ] + ); + assert.ok(identities.every((entry) => !('path' in entry))); + assert.ok(identities.every((entry) => /^[a-f0-9]{64}$/.test(entry.sha256))); +}); diff --git a/scripts/stryker-accounting.config.mjs b/scripts/stryker-accounting.config.mjs new file mode 100644 index 00000000..9d7af3f7 --- /dev/null +++ b/scripts/stryker-accounting.config.mjs @@ -0,0 +1,33 @@ +export default { + mutate: ['scripts/qualify-codex-accounting-oracle.mjs'], + ignorePatterns: [ + '.agents/**', + '.claude/**', + '.clawpatch/**', + '.codevetter/**', + '.codex/**', + '.impeccable/**', + '.symphony/**', + '**/.build/**', + '**/dist/**', + '**/node_modules/**', + '**/target/**', + 'artifacts/**', + ], + testRunner: 'command', + commandRunner: { + command: 'node --test scripts/qualify-codex-accounting-oracle.test.mjs', + }, + coverageAnalysis: 'off', + concurrency: 1, + timeoutMS: 30_000, + reporters: ['clear-text', 'json'], + jsonReporter: { + fileName: 'artifacts/tooling/stryker/accounting-mutation-report.json', + }, + thresholds: { + high: 80, + low: 60, + break: 80, + }, +}; diff --git a/scripts/sync-capability-registry.mjs b/scripts/sync-capability-registry.mjs new file mode 100644 index 00000000..3010754e --- /dev/null +++ b/scripts/sync-capability-registry.mjs @@ -0,0 +1,55 @@ +import { spawnSync } from 'node:child_process'; +import { mkdirSync, readFileSync, writeFileSync } from 'node:fs'; +import { dirname, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const root = resolve(dirname(fileURLToPath(import.meta.url)), '..'); +const manifest = resolve(root, 'apps/desktop/src-tauri/Cargo.toml'); +const output = resolve( + root, + 'apps/macos/CodeVetterPackage/Sources/CodeVetterFeature/Resources/capabilities.v1.json' +); +const check = process.argv.includes('--check'); + +const result = spawnSync( + 'cargo', + [ + 'run', + '--quiet', + '--manifest-path', + manifest, + '--features', + 'browser-agent', + '--bin', + 'codevetter', + '--', + 'capabilities', + '--json', + ], + { + cwd: root, + encoding: 'utf8', + env: { + ...process.env, + TAURI_CONFIG: JSON.stringify({ bundle: { externalBin: [] } }), + }, + } +); + +if (result.status !== 0) { + process.stderr.write(result.stderr); + process.exit(result.status ?? 1); +} + +const canonical = `${JSON.stringify(JSON.parse(result.stdout), null, 2)}\n`; +if (check) { + const current = readFileSync(output, 'utf8'); + if (current !== canonical) { + throw new Error('Native capability fixture is stale; run pnpm capabilities:sync'); + } + process.stdout.write('Native capability fixture matches the Rust registry.\n'); +} else { + mkdirSync(dirname(output), { recursive: true }); + writeFileSync(output, canonical); + process.stdout.write(`Updated ${output}\n`); +} diff --git a/scripts/verification-receipts/dogfood-cli.mjs b/scripts/verification-receipts/dogfood-cli.mjs new file mode 100644 index 00000000..67ed7a82 --- /dev/null +++ b/scripts/verification-receipts/dogfood-cli.mjs @@ -0,0 +1,102 @@ +#!/usr/bin/env node +import { spawn } from 'node:child_process'; +import { mkdir } from 'node:fs/promises'; +import { dirname, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +import { ingestReceiptDocument } from './analyze.mjs'; +import { loadReceipt, stableStringify, writeJsonWithinRepository } from './contracts.mjs'; + +const REPOSITORY_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '../..'); +const OUTPUT_DIRECTORY = 'artifacts/verification-dogfood'; +const OUTPUT_PATH = `${OUTPUT_DIRECTORY}/summary.json`; +const PRODUCERS = [ + { + id: 'playwright', + command: 'pnpm', + args: ['--dir', 'apps/desktop', 'test'], + receipts: ['apps/desktop/test-results/playwright.json', 'apps/desktop/test-results/junit.xml'], + }, + { + id: 'c8', + command: 'pnpm', + args: ['--dir', 'apps/desktop', 'test:coverage'], + receipts: ['apps/desktop/coverage/lcov.info', 'apps/desktop/coverage/cobertura-coverage.xml'], + }, +]; + +export async function runDogfood({ + repositoryRoot = REPOSITORY_ROOT, + stdout = process.stdout, +} = {}) { + await mkdir(resolve(repositoryRoot, OUTPUT_DIRECTORY), { recursive: true }); + const producers = []; + const artifacts = []; + + for (const producer of PRODUCERS) { + const exitCode = await runProducer(producer, repositoryRoot); + producers.push({ id: producer.id, exit_code: exitCode, receipts: producer.receipts }); + for (const receiptPath of producer.receipts) { + try { + const loaded = await loadReceipt(repositoryRoot, receiptPath); + const bundle = ingestReceiptDocument(loaded.receipt, { + sourcePath: loaded.relativePath, + sourceSha256: loaded.sha256, + }); + artifacts.push({ + path: loaded.relativePath, + format: loaded.sourceFormat, + sha256: loaded.sha256, + bundle_id: bundle.bundle_id, + verdict: bundle.verdict, + limitations: bundle.limitations, + }); + } catch (error) { + artifacts.push({ + path: receiptPath, + error: boundedError(error, repositoryRoot), + }); + } + } + } + + const summary = { + schema_version: 'codevetter.external-tool-dogfood/v1', + authority: 'integration-check-only', + producers, + artifacts, + }; + await writeJsonWithinRepository(repositoryRoot, OUTPUT_PATH, summary); + stdout.write(`${stableStringify(summary)}\n`); + return producers.some((entry) => entry.exit_code !== 0) || artifacts.some((entry) => entry.error) + ? 1 + : 0; +} + +function runProducer(producer, repositoryRoot) { + return new Promise((resolveExit) => { + const child = spawn(producer.command, producer.args, { + cwd: repositoryRoot, + env: process.env, + stdio: 'inherit', + shell: false, + }); + child.once('error', () => resolveExit(127)); + child.once('exit', (code, signal) => resolveExit(signal ? 128 : (code ?? 1))); + }); +} + +function boundedError(error, repositoryRoot) { + return String(error?.message ?? error) + .replaceAll(repositoryRoot, '') + .slice(0, 500); +} + +if (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]) { + if (process.argv.length !== 2) { + process.stderr.write('usage: dogfood-cli.mjs\n'); + process.exitCode = 2; + } else { + process.exitCode = await runDogfood(); + } +} diff --git a/scripts/verification-receipts/producer-adapters.mjs b/scripts/verification-receipts/producer-adapters.mjs new file mode 100644 index 00000000..57609fd6 --- /dev/null +++ b/scripts/verification-receipts/producer-adapters.mjs @@ -0,0 +1,641 @@ +import { createHash } from 'node:crypto'; +import { isAbsolute, relative, sep } from 'node:path'; + +import { lcovParser } from '@friedemannsommer/lcov-parser/sync'; +import { XMLParser, XMLValidator } from 'fast-xml-parser'; + +import { adaptVerificationReceipt } from './adapters.mjs'; + +const CANONICAL_VERSION = 'codevetter.project-verification-receipt/v1'; +const XML_OPTIONS = { + ignoreAttributes: false, + attributeNamePrefix: '@_', + parseAttributeValue: true, + parseTagValue: true, + processEntities: false, + trimValues: true, +}; + +export function adaptVerificationArtifact({ + bytes, + relativePath, + sourceSha256, + repository, + repositoryRoot, +}) { + const text = bytes.toString('utf8'); + const trimmed = text.trimStart(); + + if (looksLikeLcov(trimmed)) { + return { + receipt: adaptLcov(text, metadata()), + sourceFormat: 'lcov', + }; + } + + if (trimmed.startsWith('<')) { + return adaptXml(text, metadata()); + } + + let value; + try { + value = JSON.parse(text); + } catch { + throw new Error('verification artifact is neither supported JSON, XML, nor LCOV'); + } + + try { + return adaptVerificationReceipt(value, { repositoryId: repository.id }); + } catch (error) { + if (isPlaywrightJson(value)) { + return { + receipt: adaptPlaywrightJson(value, metadata()), + sourceFormat: 'playwright-json', + }; + } + if (isLighthouseJson(value)) { + return { + receipt: adaptLighthouseJson(value, metadata()), + sourceFormat: 'lighthouse-json', + }; + } + if (isChromeTraceJson(value)) { + return { + receipt: adaptChromeTraceJson(value, metadata()), + sourceFormat: 'chrome-trace-json', + }; + } + throw error; + } + + function metadata() { + return { relativePath, sourceSha256, repository, repositoryRoot }; + } +} + +export function adaptPlaywrightJson(value, metadata) { + if (!isPlaywrightJson(value)) throw new Error('artifact is not a Playwright JSON report'); + const entries = []; + walkPlaywrightSuites(value.suites, [], entries); + if (entries.length === 0) throw new Error('Playwright JSON report contains no tests'); + + const tests = []; + const attempts = []; + let retries = 0; + for (const [testIndex, entry] of entries.entries()) { + const testId = `playwright:${digest({ + file: entry.file, + title: entry.title, + project: entry.projectName, + index: testIndex, + }).slice(0, 24)}`; + tests.push({ + id: testId, + file: containedProducerPath(entry.file, metadata, metadata.relativePath), + selected_by: [], + reason: 'selected by the Playwright producer report', + }); + const results = entry.results.length > 0 ? entry.results : [{ status: 'interrupted' }]; + retries += Math.max(0, results.length - 1); + results.forEach((result, resultIndex) => { + const status = playwrightStatus(result.status); + attempts.push({ + id: `${testId}:attempt:${resultIndex + 1}`, + test_id: testId, + phase: resultIndex === 0 ? 'primary' : 'recheck', + status, + duration_ms: nonNegative(result.duration, 0), + failure_signature: failureSignature('playwright', result.error ?? result.errors, status), + }); + }); + } + + return testReceipt({ + metadata, + runner: { + id: 'playwright-json', + version: text(value.config?.version, 'unknown'), + profile: 'json-reporter', + command: 'playwright test --reporter=json', + }, + capturedAt: timestamp(value.stats?.startTime), + tests, + attempts, + wallMs: nonNegative(value.stats?.duration, sum(attempts, 'duration_ms')), + retries, + limitations: [ + 'Adapted from the maintained Playwright JSON reporter; the raw report remains authoritative.', + 'The report does not prove repository revision, process-tree resources, network isolation, or complete test discovery.', + ], + }); +} + +export function adaptJunitXml(document, metadata) { + const roots = asArray(document.testsuites?.testsuite ?? document.testsuite); + const cases = []; + for (const suite of roots) walkJunitSuites(suite, [], cases); + if (cases.length === 0) throw new Error('JUnit XML report contains no test cases'); + + const tests = []; + const attempts = []; + for (const [index, entry] of cases.entries()) { + const file = containedProducerPath(entry['@_file'], metadata, metadata.relativePath); + const title = [entry['@_classname'], entry['@_name']].filter(Boolean).join(' › '); + const testId = `junit:${digest({ file, title, index }).slice(0, 24)}`; + const status = entry.failure + ? 'failed' + : entry.error + ? 'failed' + : entry.skipped + ? 'skipped' + : 'passed'; + tests.push({ + id: testId, + file, + selected_by: [], + reason: 'declared by the JUnit producer report', + }); + attempts.push({ + id: `${testId}:attempt:1`, + test_id: testId, + phase: 'primary', + status, + duration_ms: secondsToMs(entry['@_time']), + failure_signature: failureSignature('junit', entry.failure ?? entry.error, status), + }); + } + + const firstSuite = roots[0] ?? {}; + return testReceipt({ + metadata, + runner: { + id: 'junit-xml', + version: 'unknown', + profile: text(firstSuite['@_name'], 'junit'), + command: 'external producer with JUnit XML reporter', + }, + capturedAt: timestamp(firstSuite['@_timestamp']), + tests, + attempts, + wallMs: secondsToMs(firstSuite['@_time']) || sum(attempts, 'duration_ms'), + retries: 0, + limitations: [ + 'Adapted from JUnit XML through fast-xml-parser; the raw report remains authoritative.', + 'JUnit XML does not standardize runner version, retry history, repository revision, or process-tree resources.', + ], + }); +} + +export function adaptLcov(textValue, metadata) { + let sections; + try { + sections = lcovParser({ from: textValue }); + } catch (error) { + throw new Error(`invalid LCOV report: ${error.message}`); + } + if (sections.length === 0) throw new Error('LCOV report contains no source records'); + const totals = sections.reduce( + (result, section) => { + result.linesFound += section.lines.instrumented; + result.linesHit += section.lines.hit; + result.functionsFound += section.functions.instrumented; + result.functionsHit += section.functions.hit; + result.branchesFound += section.branches.instrumented; + result.branchesHit += section.branches.hit; + return result; + }, + { + linesFound: 0, + linesHit: 0, + functionsFound: 0, + functionsHit: 0, + branchesFound: 0, + branchesHit: 0, + } + ); + return observationReceipt({ + metadata, + runner: { id: 'lcov', version: '1', profile: 'coverage', command: 'external LCOV producer' }, + observations: coverageObservations(totals, 'lcov'), + limitations: [ + 'Parsed with @friedemannsommer/lcov-parser; the raw LCOV report remains authoritative.', + 'Coverage is aggregate producer evidence and is not changed-line coverage unless the producer scope proves that separately.', + ], + }); +} + +export function adaptCoberturaXml(coverage, metadata) { + const totals = { + linesFound: integerAttribute(coverage, 'lines-valid'), + linesHit: integerAttribute(coverage, 'lines-covered'), + functionsFound: 0, + functionsHit: 0, + branchesFound: integerAttribute(coverage, 'branches-valid'), + branchesHit: integerAttribute(coverage, 'branches-covered'), + }; + if (totals.linesFound === 0 && totals.branchesFound === 0) { + throw new Error('Cobertura XML report contains no coverage totals'); + } + return observationReceipt({ + metadata, + runner: { + id: 'cobertura-xml', + version: text(coverage['@_version'], 'unknown'), + profile: 'coverage', + command: 'external Cobertura XML producer', + }, + capturedAt: unixTimestamp(coverage['@_timestamp']), + observations: coverageObservations(totals, 'cobertura'), + limitations: [ + 'Parsed from Cobertura XML through fast-xml-parser; the raw report remains authoritative.', + 'Coverage is aggregate producer evidence and is not changed-line coverage unless the producer scope proves that separately.', + ], + }); +} + +export function adaptLighthouseJson(value, metadata) { + if (!isLighthouseJson(value)) throw new Error('artifact is not a Lighthouse JSON report'); + const observations = []; + addObservation( + observations, + 'lighthouse.performance.score', + value.categories?.performance?.score, + 'ratio', + 'navigation' + ); + for (const [audit, metric] of [ + ['first-contentful-paint', 'lighthouse.fcp'], + ['largest-contentful-paint', 'lighthouse.lcp'], + ['interaction-to-next-paint', 'lighthouse.inp'], + ['total-blocking-time', 'lighthouse.tbt'], + ['speed-index', 'lighthouse.speed_index'], + ['cumulative-layout-shift', 'lighthouse.cls'], + ]) { + const entry = value.audits?.[audit]; + addObservation( + observations, + metric, + entry?.numericValue, + text(entry?.numericUnit, audit === 'cumulative-layout-shift' ? 'unitless' : 'millisecond'), + 'navigation' + ); + } + if (observations.length === 0) + throw new Error('Lighthouse JSON report contains no supported metrics'); + return observationReceipt({ + metadata, + runner: { + id: 'lighthouse', + version: text(value.lighthouseVersion, 'unknown'), + profile: text(value.configSettings?.formFactor, 'unknown-form-factor'), + command: 'external Lighthouse JSON producer', + }, + capturedAt: timestamp(value.fetchTime), + observations, + limitations: [ + 'Lighthouse metrics are observational until repeated, revision-bound, same-scope comparison evidence is supplied.', + 'A Lighthouse category score is not a CodeVetter correctness or shipping verdict.', + ], + }); +} + +export function adaptChromeTraceJson(value, metadata) { + if (!isChromeTraceJson(value)) throw new Error('artifact is not a Chrome trace JSON report'); + let minimum = Number.POSITIVE_INFINITY; + let maximum = Number.NEGATIVE_INFINITY; + for (const event of value.traceEvents) { + if (!Number.isFinite(event?.ts)) continue; + minimum = Math.min(minimum, event.ts); + maximum = Math.max(maximum, event.ts + nonNegative(event.dur, 0)); + } + const observations = []; + addObservation(observations, 'chrome_trace.events', value.traceEvents.length, 'count', 'trace'); + if (Number.isFinite(minimum) && Number.isFinite(maximum)) { + addObservation( + observations, + 'chrome_trace.duration', + (maximum - minimum) / 1_000, + 'millisecond', + 'trace' + ); + } + return observationReceipt({ + metadata, + runner: { + id: 'chrome-trace', + version: 'trace-event-format', + profile: 'metadata-only', + command: 'external Chrome DevTools trace producer', + }, + observations, + limitations: [ + 'Only bounded Chrome trace metadata is normalized; the raw trace remains the source for flame-chart and network analysis.', + 'Trace duration and event count are observational and do not establish Core Web Vitals or an optimization claim.', + ], + }); +} + +function adaptXml(textValue, metadata) { + const parseableXml = textValue.replace( + //i, + '' + ); + if (/ [entry.id, entry.file]))}`, + inventory_total: tests.length, + selector_change_allowed: false, + changed_files: [], + tests, + }, + outcome: { + total: statuses.filter((status) => status !== 'operational_failure').length, + passed: statuses.filter((status) => status === 'passed').length, + failed: statuses.filter((status) => status === 'failed' || status === 'timed_out').length, + skipped: statuses.filter((status) => status === 'skipped').length, + operational_failures: statuses.filter((status) => status === 'operational_failure').length, + }, + attempts, + wallMs, + retries, + inventoryCoverage: 'aggregate', + selectionCoverage: 'aggregate', + observations: [], + limitations, + }); +} + +function observationReceipt({ metadata, runner, capturedAt, observations, limitations }) { + return baseReceipt({ + metadata, + runner, + capturedAt, + selection: { + mode: 'none', + inventory_id: `${runner.id}-${metadata.sourceSha256}`, + inventory_total: 0, + selector_change_allowed: false, + changed_files: [], + tests: [], + }, + outcome: { total: 0, passed: 0, failed: 0, skipped: 0, operational_failures: 0 }, + attempts: [], + wallMs: 0, + retries: 0, + inventoryCoverage: 'missing', + selectionCoverage: 'missing', + observations, + limitations, + }); +} + +function baseReceipt({ + metadata, + runner, + capturedAt, + selection, + outcome, + attempts, + wallMs, + retries, + inventoryCoverage, + selectionCoverage, + observations, + limitations, +}) { + return { + schema_version: CANONICAL_VERSION, + captured_at: capturedAt ?? '1970-01-01T00:00:00.000Z', + subject: { + repository: metadata.repository, + runner, + environment: { + id: `artifact-ingestion-${process.platform}-${process.arch}-node${process.versions.node}`, + platform: process.platform, + arch: process.arch, + runtime: `Node ${process.versions.node}`, + }, + }, + selection, + outcome, + attempts, + metrics: { + wall_ms: wallMs, + cpu_ms: null, + peak_rss_bytes: null, + peak_processes: null, + samples: { wall_ms: wallMs > 0 ? [wallMs] : [], cpu_ms: [], peak_rss_bytes: [] }, + coverage: { + inventory: inventoryCoverage, + cpu: 'missing', + rss: 'missing', + process_tree: 'missing', + network: 'missing', + fixed_waits: 'missing', + selection: selectionCoverage, + }, + }, + safety: { fixed_wait_ms: null, live_network_requests: null, mock_cost_usd: 0, retries }, + budgets: { + policy_id: `${runner.id}-observational-v1`, + maxima: { + wall_ms: null, + cpu_ms: null, + peak_rss_bytes: null, + peak_processes: null, + fixed_wait_ms: null, + live_network_requests: null, + retries: null, + }, + required_metrics: [], + regression: { + relative_percent: 0, + wall_absolute_ms: 0, + cpu_absolute_ms: 0, + peak_rss_absolute_bytes: 0, + peak_processes_absolute: 0, + }, + }, + evidence: [{ kind: runner.id, path: metadata.relativePath, sha256: metadata.sourceSha256 }], + limitations: [...new Set(limitations)].sort(), + producer_observations: observations, + }; +} + +function coverageObservations(totals, scope) { + const observations = []; + for (const [metric, value] of [ + ['coverage.lines.found', totals.linesFound], + ['coverage.lines.hit', totals.linesHit], + ['coverage.functions.found', totals.functionsFound], + ['coverage.functions.hit', totals.functionsHit], + ['coverage.branches.found', totals.branchesFound], + ['coverage.branches.hit', totals.branchesHit], + ]) + addObservation(observations, metric, value, 'count', scope); + return observations; +} + +function addObservation(target, metric, value, unit, scope) { + if (!Number.isFinite(value) || value < 0) return; + target.push({ metric, value, unit, scope, evidence: 'producer_artifact' }); +} + +function walkPlaywrightSuites(suites, parents, target) { + for (const suite of asArray(suites)) { + const lineage = suite.title ? [...parents, suite.title] : parents; + for (const spec of asArray(suite.specs)) { + for (const test of asArray(spec.tests)) { + target.push({ + file: spec.file ?? suite.file, + title: [...lineage, spec.title ?? test.title].filter(Boolean).join(' › '), + projectName: test.projectName ?? 'default', + results: asArray(test.results), + }); + } + } + walkPlaywrightSuites(suite.suites, lineage, target); + } +} + +function walkJunitSuites(suite, parents, target) { + if (!suite || typeof suite !== 'object') return; + const lineage = suite['@_name'] ? [...parents, String(suite['@_name'])] : parents; + for (const testcase of asArray(suite.testcase)) target.push({ ...testcase, __lineage: lineage }); + for (const child of asArray(suite.testsuite)) walkJunitSuites(child, lineage, target); +} + +function containedProducerPath(value, metadata, fallback) { + if (typeof value !== 'string' || value.trim() === '') return fallback; + let candidate = value.replaceAll('\\', '/'); + if (isAbsolute(candidate)) { + candidate = relative(metadata.repositoryRoot, candidate).replaceAll(sep, '/'); + } + if ( + candidate === '' || + candidate.startsWith('../') || + candidate.startsWith('/') || + candidate.split('/').some((part) => part === '' || part === '.' || part === '..') + ) + return fallback; + return candidate; +} + +function playwrightStatus(value) { + if (value === 'passed') return 'passed'; + if (value === 'failed') return 'failed'; + if (value === 'timedOut') return 'timed_out'; + if (value === 'skipped') return 'skipped'; + return 'operational_failure'; +} + +function failureSignature(prefix, failure, status) { + if (status === 'passed' || status === 'skipped') return null; + return `${prefix}-${status}-${digest(failure ?? status).slice(0, 16)}`; +} + +function isPlaywrightJson(value) { + return ( + Boolean(value) && + typeof value === 'object' && + Array.isArray(value.suites) && + value.config && + value.stats + ); +} + +function isLighthouseJson(value) { + return ( + Boolean(value) && + typeof value === 'object' && + typeof value.lighthouseVersion === 'string' && + value.audits + ); +} + +function isChromeTraceJson(value) { + return Boolean(value) && typeof value === 'object' && Array.isArray(value.traceEvents); +} + +function looksLikeLcov(value) { + return /^(?:TN:|SF:)/m.test(value.slice(0, 4_096)); +} + +function asArray(value) { + if (value === undefined || value === null) return []; + return Array.isArray(value) ? value : [value]; +} + +function text(value, fallback) { + return typeof value === 'string' && value.trim() !== '' ? value.slice(0, 1_024) : fallback; +} + +function timestamp(value) { + return typeof value === 'string' && Number.isFinite(Date.parse(value)) + ? new Date(value).toISOString() + : undefined; +} + +function unixTimestamp(value) { + if (!Number.isFinite(value) || value < 0) return undefined; + const milliseconds = value >= 1_000_000_000_000 ? value : value * 1_000; + const date = new Date(milliseconds); + return Number.isNaN(date.getTime()) ? undefined : date.toISOString(); +} + +function secondsToMs(value) { + const parsed = Number(value); + return Number.isFinite(parsed) && parsed >= 0 ? parsed * 1_000 : 0; +} + +function integerAttribute(value, name) { + const parsed = Number(value?.[`@_${name}`]); + return Number.isInteger(parsed) && parsed >= 0 ? parsed : 0; +} + +function nonNegative(value, fallback) { + return Number.isFinite(value) && value >= 0 ? value : fallback; +} + +function sum(values, key) { + return values.reduce((total, value) => total + nonNegative(value[key], 0), 0); +} + +function digest(value) { + return createHash('sha256').update(JSON.stringify(value)).digest('hex'); +} From 438b31cd940592cda382f301d9ac038ed70224ae Mon Sep 17 00:00:00 2001 From: Sarthak Agrawal Date: Wed, 2 Sep 2026 22:09:50 +0530 Subject: [PATCH 2/5] chore: declare verification producer dependencies --- package.json | 45 +++++++++++++ pnpm-lock.yaml | 170 +++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 188 insertions(+), 27 deletions(-) diff --git a/package.json b/package.json index 2af9fe24..fb549bfa 100644 --- a/package.json +++ b/package.json @@ -7,11 +7,22 @@ ], "scripts": { "bench:public": "node scripts/run-public-benchmark.mjs", + "bench:cross-review": "node scripts/run-cross-review-benchmark.mjs", "bench:catch-rate": "node scripts/run-catch-rate-benchmark.mjs", "bench:graph-context": "node scripts/run-structural-context-evaluation.mjs", "bench:curation": "node scripts/report-benchmark-curation.mjs", "bench:1brc": "node --test benchmarks/runtime-challenges/temperature-aggregation/temperature-aggregation.test.mjs", "bench:1brc:campaign": "node benchmarks/runtime-challenges/temperature-aggregation/campaign.mjs", + "bench:native-bridge": "sh scripts/run-native-bridge-benchmark.sh", + "native:data-continuity": "node scripts/qualify-native-data-continuity.mjs", + "native:installed-upgrade:qualify": "node scripts/qualify-native-installed-upgrade.mjs", + "native:package:qualify": "node scripts/qualify-native-package.mjs", + "native:release:inspect": "node scripts/inspect-native-release-readiness.mjs", + "native:appcast:inspect": "node scripts/inspect-native-appcast.mjs", + "native:notarization:prove": "node scripts/create-native-notarization-proof.mjs", + "native:package:finalize": "node scripts/finalize-native-package-archives.mjs", + "native:review:render": "node scripts/render-native-owner-review.mjs render", + "native:runtime:compare": "node scripts/compare-desktop-runtime.mjs", "bench:readiness": "node scripts/report-benchmark-curation.mjs benchmarks/agent-prs/public-copilot-corpus.json --require-publishable", "bench:new-case": "node scripts/create-benchmark-case.mjs", "bench:curate-public": "node scripts/curate-public-agent-prs.mjs", @@ -47,7 +58,11 @@ "verification:ingest": "node scripts/verification-receipts/cli.mjs ingest", "verification:compare": "node scripts/verification-receipts/cli.mjs compare", "verification:mcp": "node scripts/verification-receipts/mcp.mjs", + "verification:dogfood": "node scripts/verification-receipts/dogfood-cli.mjs", + "capabilities:sync": "node scripts/sync-capability-registry.mjs", + "capabilities:check": "node scripts/sync-capability-registry.mjs --check", "test:benchmark": "node --test scripts/run-catch-rate-benchmark.test.mjs scripts/run-structural-context-evaluation.test.mjs", + "test:cross-review-benchmark": "node --test scripts/run-cross-review-benchmark.test.mjs", "test:graph-context": "node --test scripts/run-structural-context-evaluation.test.mjs", "test:corpus-contracts": "node --test scripts/agent-task-corpus/*.test.mjs", "test:context-provider-plan": "node --test scripts/agent-task-corpus/context-provider-plan.test.mjs", @@ -55,6 +70,22 @@ "test:runtime-failure-capsule": "node --test scripts/runtime-failure-capsule/*.test.mjs", "test:verification-receipts": "node --test scripts/verification-receipts/*.test.mjs", "test:automation": "node --test scripts/emit-foundry-receipt.test.mjs", + "test:native-data-continuity": "node --test scripts/qualify-native-data-continuity.test.mjs", + "test:native-installed-upgrade": "node --test scripts/qualify-native-installed-upgrade.test.mjs", + "test:native-package": "node --test scripts/qualify-native-package.test.mjs", + "test:native-review-gallery": "node --test scripts/owner-review-gallery.test.mjs", + "test:native-review-render": "node --test scripts/render-native-owner-review.test.mjs", + "test:native-release": "node --test scripts/inspect-native-release-readiness.test.mjs", + "test:native-appcast": "node --test scripts/inspect-native-appcast.test.mjs", + "test:native-notarization": "node --test scripts/create-native-notarization-proof.test.mjs", + "test:native-package-finalize": "node --test scripts/finalize-native-package-archives.test.mjs", + "test:native-runtime-compare": "node --test scripts/compare-desktop-runtime.test.mjs", + "native:build:release": "node scripts/run-native-checks.mjs --release", + "test:native": "node scripts/run-native-checks.mjs", + "test:native:background": "node scripts/run-native-checks.mjs --background", + "test:native:ui": "node scripts/run-native-checks.mjs --ui", + "test:native:full": "node scripts/run-native-checks.mjs --full", + "test:native-runner": "node --test scripts/run-native-checks.test.mjs", "test:coverage": "pnpm --filter @code-reviewer/desktop test:coverage", "verify": "pnpm --filter @code-reviewer/desktop verify", "prepare": "husky || true", @@ -68,6 +99,13 @@ "quality:complexity": "node scripts/check-changed-complexity.mjs", "quality:cycles": "biome lint --only=suspicious/noImportCycles .", "quality:dependencies": "pnpm audit --audit-level high", + "quality:sarif": "node scripts/run-biome-sarif.mjs", + "quality:secrets": "gitleaks git --no-banner --redact=100 .", + "quality:secrets:staged": "gitleaks git --pre-commit --staged --no-banner --redact=100 .", + "quality:mutation:accounting": "pnpm --package @stryker-mutator/core@10.0.0 --package typescript@5.9.3 dlx stryker run scripts/stryker-accounting.config.mjs", + "quality:rust-policy": "cargo-deny --manifest-path apps/desktop/src-tauri/Cargo.toml --config apps/desktop/src-tauri/deny.toml --frozen check --hide-inclusion-graph licenses sources bans", + "quality:vulnerabilities": "node scripts/run-osv-offline.mjs", + "quality:workflows": "actionlint", "quality:duplication": "jscpd apps/desktop/src apps/landing-page-astro/src scripts --min-lines 8 --min-tokens 60 --mode strict --format typescript,tsx,javascript --cross-formats js-ts --ignore '**/fixtures/**,**/generated/**,**/gen/**,**/node_modules/**,**/dist/**,**/out/**,**/coverage/**' --threshold 0.81 --reporters console,threshold --no-colors --no-tips", "retrieval:discover": "node scripts/context-retrieval/discover-candidates.mjs --registry benchmarks/context-retrieval/candidates.json --fresh-since 2026-02-22" }, @@ -79,10 +117,14 @@ }, "devDependencies": { "@biomejs/biome": "^2.5.1", + "@friedemannsommer/lcov-parser": "8.0.0", + "@size-limit/file": "13.0.3", + "fast-xml-parser": "5.11.1", "husky": "^9.1.7", "jscpd": "5.0.14", "knip": "^6.6.3", "lint-staged": "^16.4.0", + "size-limit": "13.0.3", "ultracite": "7.10.2" }, "optionalDependencies": { @@ -95,12 +137,15 @@ "@tailwindcss/vite>vite": "7.3.6", "astro>esbuild": "0.28.1", "brace-expansion": "5.0.9", + "browserslist": "4.28.7", "js-yaml": "4.3.1", "nanoid": "3.3.18", "postcss": "8.5.26", + "postcss-nested>postcss-selector-parser": "6.1.3", "sharp": "0.35.3", "svgo": "4.0.2", "tsx>esbuild": "0.28.1", + "tailwindcss>postcss-selector-parser": "6.1.3", "undici": "7.29.0", "wrangler>esbuild": "0.28.1", "ws": "8.21.3" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ec4de4e6..37696bb9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,12 +9,15 @@ overrides: '@tailwindcss/vite>vite': 7.3.6 astro>esbuild: 0.28.1 brace-expansion: 5.0.9 + browserslist: 4.28.7 js-yaml: 4.3.1 nanoid: 3.3.18 postcss: 8.5.26 + postcss-nested>postcss-selector-parser: 6.1.3 sharp: 0.35.3 svgo: 4.0.2 tsx>esbuild: 0.28.1 + tailwindcss>postcss-selector-parser: 6.1.3 undici: 7.29.0 wrangler>esbuild: 0.28.1 ws: 8.21.3 @@ -26,6 +29,15 @@ importers: '@biomejs/biome': specifier: ^2.5.1 version: 2.5.1 + '@friedemannsommer/lcov-parser': + specifier: 8.0.0 + version: 8.0.0 + '@size-limit/file': + specifier: 13.0.3 + version: 13.0.3(size-limit@13.0.3) + fast-xml-parser: + specifier: 5.11.1 + version: 5.11.1 husky: specifier: ^9.1.7 version: 9.1.7 @@ -38,6 +50,9 @@ importers: lint-staged: specifier: ^16.4.0 version: 16.4.0 + size-limit: + specifier: 13.0.3 + version: 13.0.3 ultracite: specifier: 7.10.2 version: 7.10.2 @@ -924,6 +939,10 @@ packages: '@floating-ui/utils@0.2.11': resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==} + '@friedemannsommer/lcov-parser@8.0.0': + resolution: {integrity: sha512-7NAl5m3cnPTqY6wj3wkGZxLqu9S3Q2gd/RBRqDivsaFeLvrif3ube0nPfOcL57Zx/ERiP2j70nGzNTurNMe9DQ==} + engines: {node: '>=22'} + '@img/colour@1.1.0': resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} engines: {node: '>=18'} @@ -1161,6 +1180,9 @@ packages: '@emnapi/core': ^1.7.1 || ^2.0.0-alpha.4 '@emnapi/runtime': ^1.7.1 || ^2.0.0-alpha.4 + '@nodable/entities@3.0.0': + resolution: {integrity: sha512-8L9xFeTYKhm49xfIypoe2W5wV1m/3Z58kT+7kR9A8OyFxcPduI4VmxaUMQyKYrRjUoLLSXv6EKKID5Tvj9cUVw==} + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -2004,6 +2026,12 @@ packages: resolution: {integrity: sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw==} engines: {node: '>=18'} + '@size-limit/file@13.0.3': + resolution: {integrity: sha512-PWTITIXH5p9aGIf6qq2Fruihn/b9nBQyfkyoAyb6DzFJgS1Ek9MSPJYKxKFLO8jdo0aqSgBPd3sevbS6PyBiJw==} + engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} + peerDependencies: + size-limit: 13.0.3 + '@speed-highlight/core@1.2.24': resolution: {integrity: sha512-qeW2e1l78afw8VhRPfPQ1Gjj+KU5XFQ/OFV5ti6eTa9bruO7mJyZtA4vw0ofqmA3tKCkROE9xLk3VZoeRc98nw==} @@ -2320,6 +2348,9 @@ packages: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} + anynum@1.0.1: + resolution: {integrity: sha512-N6//FLET/tXYNM/F6ABca1oH6fWB+KlTt909Le28WMDBk8oaT4vY17DCrwg2MvmuqUKt3Ni4N5dGJ/EoBgcO6A==} + arg@5.0.2: resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} @@ -2366,8 +2397,8 @@ packages: resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} engines: {node: 18 || 20 || >=22} - baseline-browser-mapping@2.10.21: - resolution: {integrity: sha512-Q+rUQ7Uz8AHM7DEaNdwvfFCTq7a43lNTzuS94eiWqwyxfV/wJv+oUivef51T91mmRY4d4A1u9rcSvkeufCVXlA==} + baseline-browser-mapping@2.11.20: + resolution: {integrity: sha512-H0ulySigv6icDJ1F7SjtdCD6PrhTpdYCmP0CactWy1+ekh0AFd0o1Wn5T8b+hnTmdBx19u9yhL6wvCylXMY7zw==} engines: {node: '>=6.0.0'} hasBin: true @@ -2389,11 +2420,15 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} - browserslist@4.28.2: - resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} + browserslist@4.28.7: + resolution: {integrity: sha512-JxV13hNrFxqjOc8alRbq9dK1MM79NEXYpma2B2J4wAtpWS5zIEIKqWPGCl7N4o7Uc7B7itylh7SuDujATRyyTw==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + bytes-iec@3.1.1: + resolution: {integrity: sha512-fey6+4jDK7TFtFg/klGSvNKJctyU7n2aQdnM+CO0ruLPbqqMOM8Tio0Pc+deqUeVKX1tL5DQep1zQ7+37aTAsA==} + engines: {node: '>= 0.8'} + c8@11.0.0: resolution: {integrity: sha512-e/uRViGHSVIJv7zsaDKM7VRn2390TgHXqUSvYwPHBQaU6L7E9L0n9JbdkwdYPvshDT0KymBmmlwSpms3yBaMNg==} engines: {node: 20 || >=22} @@ -2411,6 +2446,9 @@ packages: caniuse-lite@1.0.30001790: resolution: {integrity: sha512-bOoxfJPyYo+ds6W0YfptaCWbFnJYjh2Y1Eow5lRv+vI2u8ganPZqNm1JwNh0t2ELQCqIWg4B3dWEusgAmsoyOw==} + caniuse-lite@1.0.30001810: + resolution: {integrity: sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==} + ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -2610,8 +2648,8 @@ packages: resolution: {integrity: sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==} engines: {node: '>=4'} - electron-to-chromium@1.5.344: - resolution: {integrity: sha512-4MxfbmNDm+KPh066EZy+eUnkcDPcZ35wNmOWzFuh/ijvHsve6kbLTLURy88uCNK5FbpN+yk2nQY6BYh1GEt+wg==} + electron-to-chromium@1.5.418: + resolution: {integrity: sha512-UzS26r3AEbG5wSoGVpJKqwHIU9zwQN7LHdVIThDrJpS0I5KdlXFMEb8543fhc9dVnIIAST6ar8rhwa00AL5MlA==} emoji-regex@10.6.0: resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} @@ -2682,6 +2720,13 @@ packages: fast-wrap-ansi@0.2.2: resolution: {integrity: sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==} + fast-xml-builder@1.3.1: + resolution: {integrity: sha512-pIM/1n3ntFXKYrUZwW7QCK0gAW7XY+wzj1YMIV3tLDvPj/V+zTGJK5e3/4WJfwj0qWw2ElNXiTixda/R+3YSug==} + + fast-xml-parser@5.11.1: + resolution: {integrity: sha512-TBw6K/fxoQGGjCmZDw9w/ZwP3uDcnTM4YH/g+PFRWr8sbe5idXtxNN6vITh4+1ruCZaho6uBFurElsA7F0zzgw==} + hasBin: true + fastq@1.20.1: resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} @@ -2894,6 +2939,9 @@ packages: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} + is-unsafe@2.0.2: + resolution: {integrity: sha512-HgbIHPBH0KHHCcjLfGsCvhtPTVxjaAZlXjwdz7/GQC40SjSe4sfQsar8J5VFo8JOSbarkpV0OLG95bbaNd9aAQ==} + isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} @@ -3276,6 +3324,9 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + nanospinner@1.2.2: + resolution: {integrity: sha512-Zt/AmG6qRU3e+WnzGGLuMCEAO/dAu45stNbHY223tUxldaDAeE+FxSPsd9Q+j+paejmm0ZbrNVs5Sraqy3dRxA==} + neotraverse@1.0.1: resolution: {integrity: sha512-WmmLty1YWwJl9yZi77v2dVIV6X2kuYV8YYBI/G3LWGKdGHmHUvL1z7FW0iDvEvGAwNEoc5x1tOOOyDnf5jJw/w==} engines: {node: '>= 10'} @@ -3289,8 +3340,9 @@ packages: node-mock-http@1.0.4: resolution: {integrity: sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ==} - node-releases@2.0.38: - resolution: {integrity: sha512-3qT/88Y3FbH/Kx4szpQQ4HzUbVrHPKTLVpVocKiLfoYvw9XSGOX2FmD2d6DrXbVYyAQTF2HeF6My8jmzx7/CRw==} + node-releases@2.0.54: + resolution: {integrity: sha512-YHs7BmmcsdAI5Ozuf8JZo6PT0mv2GIWC9vMfvUC3dp65M8hn7Ux8CPL+2oBI7juNuj9d0ndhTcznq2ODBps9cQ==} + engines: {node: '>=18'} normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} @@ -3384,6 +3436,10 @@ packages: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} + path-expression-matcher@1.6.2: + resolution: {integrity: sha512-enSlaiat05iasnzmgNxRj8reFdj3puY2QpNgP1aPIaVfT6nn9ICuPoFlKHk8EN22HcwewshO+mN2DGbkCEOtqQ==} + engines: {node: '>=14.0.0'} + path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -3477,8 +3533,8 @@ packages: resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==} engines: {node: '>=4'} - postcss-selector-parser@6.1.2: - resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} + postcss-selector-parser@6.1.3: + resolution: {integrity: sha512-cDoO18VWCIWRsSaws3C23b0HXRxlUknttfdNcbXnf3IGHAPRNLlXPHc6dYiatOkxW0W4uZh524Plaaw5a7WEtQ==} engines: {node: '>=4'} postcss-value-parser@4.2.0: @@ -3693,6 +3749,11 @@ packages: engines: {node: '>=20.19.5', npm: '>=10.8.2'} hasBin: true + size-limit@13.0.3: + resolution: {integrity: sha512-KVb2aNEU49BwTR21SVjD+2QHP9gBV/nWsTHzNB/heRwXtHyA7lLQiDZDQ1TiNh/B/TZXKAZrHYyTt+cvBUrzYw==} + engines: {node: ^22.18.0 || ^24.0.0 || >=26.0.0} + hasBin: true + slice-ansi@7.1.2: resolution: {integrity: sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==} engines: {node: '>=18'} @@ -3757,6 +3818,9 @@ packages: resolution: {integrity: sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==} engines: {node: '>=14.16'} + strnum@2.4.2: + resolution: {integrity: sha512-rDG3Ah4TV0k1hWvLSzkZtMmLN9+eS+h3knq4MP6A42Y3Yh5qGNnOUs1jJkoSr8FG5dsL28c7KgkIBzSEykqtuw==} + sucrase@3.35.1: resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==} engines: {node: '>=16 || 14 >=14.17'} @@ -4006,7 +4070,7 @@ packages: resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} hasBin: true peerDependencies: - browserslist: '>= 4.21.0' + browserslist: 4.28.7 use-callback-ref@1.3.3: resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} @@ -4230,6 +4294,10 @@ packages: resolution: {integrity: sha512-sqMMuL1rc0FmMBOzCpd0yuy9trqF2yTTVe+E9ogwCSWQCdDEtQUwrZPT6AxqtsFGRNxycgncbP/xmOOSPw5ZUw==} engines: {node: '>= 6.0'} + xml-naming@0.3.0: + resolution: {integrity: sha512-ghig2TBE/H11aOVgmahA3MhimvkBr6JIYknH/Dhdk10nXwdbIqBJsbfMxpvFPG8bAw77gN29aQWvKpmVoPlvPQ==} + engines: {node: '>=16.0.0'} + xxhash-wasm@1.1.0: resolution: {integrity: sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA==} @@ -4422,7 +4490,7 @@ snapshots: dependencies: '@babel/compat-data': 7.29.0 '@babel/helper-validator-option': 7.27.1 - browserslist: 4.28.2 + browserslist: 4.28.7 lru-cache: 5.1.1 semver: 6.3.1 @@ -4836,6 +4904,8 @@ snapshots: '@floating-ui/utils@0.2.11': {} + '@friedemannsommer/lcov-parser@8.0.0': {} + '@img/colour@1.1.0': {} '@img/sharp-darwin-arm64@0.35.3': @@ -5025,6 +5095,8 @@ snapshots: '@tybys/wasm-util': 0.10.3 optional: true + '@nodable/entities@3.0.0': {} + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -5611,6 +5683,10 @@ snapshots: '@sindresorhus/is@7.2.0': {} + '@size-limit/file@13.0.3(size-limit@13.0.3)': + dependencies: + size-limit: 13.0.3 + '@speed-highlight/core@1.2.24': {} '@tailwindcss/node@4.2.4': @@ -5889,6 +5965,8 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.2 + anynum@1.0.1: {} + arg@5.0.2: {} argparse@2.0.1: {} @@ -5992,7 +6070,7 @@ snapshots: autoprefixer@10.5.0(postcss@8.5.26): dependencies: - browserslist: 4.28.2 + browserslist: 4.28.7 caniuse-lite: 1.0.30001790 fraction.js: 5.3.4 picocolors: 1.1.1 @@ -6007,7 +6085,7 @@ snapshots: balanced-match@4.0.4: {} - baseline-browser-mapping@2.10.21: {} + baseline-browser-mapping@2.11.20: {} binary-extensions@2.3.0: {} @@ -6023,13 +6101,15 @@ snapshots: dependencies: fill-range: 7.1.1 - browserslist@4.28.2: + browserslist@4.28.7: dependencies: - baseline-browser-mapping: 2.10.21 - caniuse-lite: 1.0.30001790 - electron-to-chromium: 1.5.344 - node-releases: 2.0.38 - update-browserslist-db: 1.2.3(browserslist@4.28.2) + baseline-browser-mapping: 2.11.20 + caniuse-lite: 1.0.30001810 + electron-to-chromium: 1.5.418 + node-releases: 2.0.54 + update-browserslist-db: 1.2.3(browserslist@4.28.7) + + bytes-iec@3.1.1: {} c8@11.0.0: dependencies: @@ -6049,6 +6129,8 @@ snapshots: caniuse-lite@1.0.30001790: {} + caniuse-lite@1.0.30001810: {} + ccount@2.0.1: {} ccusage@20.0.20: @@ -6226,7 +6308,7 @@ snapshots: dset@3.1.4: {} - electron-to-chromium@1.5.344: {} + electron-to-chromium@1.5.418: {} emoji-regex@10.6.0: {} @@ -6344,6 +6426,20 @@ snapshots: dependencies: fast-string-width: 3.0.2 + fast-xml-builder@1.3.1: + dependencies: + path-expression-matcher: 1.6.2 + xml-naming: 0.3.0 + + fast-xml-parser@5.11.1: + dependencies: + '@nodable/entities': 3.0.0 + fast-xml-builder: 1.3.1 + is-unsafe: 2.0.2 + path-expression-matcher: 1.6.2 + strnum: 2.4.2 + xml-naming: 0.3.0 + fastq@1.20.1: dependencies: reusify: 1.1.0 @@ -6562,6 +6658,8 @@ snapshots: is-stream@2.0.1: optional: true + is-unsafe@2.0.2: {} + isexe@2.0.0: {} istanbul-lib-coverage@3.2.2: {} @@ -6911,6 +7009,10 @@ snapshots: nanoid@3.3.18: {} + nanospinner@1.2.2: + dependencies: + picocolors: 1.1.1 + neotraverse@1.0.1: {} nlcst-to-string@4.0.0: @@ -6921,7 +7023,7 @@ snapshots: node-mock-http@1.0.4: {} - node-releases@2.0.38: {} + node-releases@2.0.54: {} normalize-path@3.0.0: {} @@ -7050,6 +7152,8 @@ snapshots: path-exists@4.0.0: {} + path-expression-matcher@1.6.2: {} + path-key@3.1.1: {} path-parse@1.0.7: {} @@ -7109,14 +7213,14 @@ snapshots: postcss-nested@6.2.0(postcss@8.5.26): dependencies: postcss: 8.5.26 - postcss-selector-parser: 6.1.2 + postcss-selector-parser: 6.1.3 postcss-selector-parser@6.0.10: dependencies: cssesc: 3.0.0 util-deprecate: 1.0.2 - postcss-selector-parser@6.1.2: + postcss-selector-parser@6.1.3: dependencies: cssesc: 3.0.0 util-deprecate: 1.0.2 @@ -7387,6 +7491,12 @@ snapshots: arg: 5.0.2 sax: 1.6.0 + size-limit@13.0.3: + dependencies: + bytes-iec: 3.1.1 + lilconfig: 3.1.3 + nanospinner: 1.2.2 + slice-ansi@7.1.2: dependencies: ansi-styles: 6.2.3 @@ -7446,6 +7556,10 @@ snapshots: strip-json-comments@5.0.3: {} + strnum@2.4.2: + dependencies: + anynum: 1.0.1 + sucrase@3.35.1: dependencies: '@jridgewell/gen-mapping': 0.3.13 @@ -7503,7 +7617,7 @@ snapshots: postcss-js: 4.1.0(postcss@8.5.26) postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.26)(tsx@4.21.0)(yaml@2.9.0) postcss-nested: 6.2.0(postcss@8.5.26) - postcss-selector-parser: 6.1.2 + postcss-selector-parser: 6.1.3 resolve: 1.22.12 sucrase: 3.35.1 transitivePeerDependencies: @@ -7665,9 +7779,9 @@ snapshots: until-async@3.0.2: {} - update-browserslist-db@1.2.3(browserslist@4.28.2): + update-browserslist-db@1.2.3(browserslist@4.28.7): dependencies: - browserslist: 4.28.2 + browserslist: 4.28.7 escalade: 3.2.0 picocolors: 1.1.1 @@ -7818,6 +7932,8 @@ snapshots: os-paths: 4.4.0 optional: true + xml-naming@0.3.0: {} + xxhash-wasm@1.1.0: {} y18n@5.0.8: {} From 7246411f4a24dd8f39ee64c971a6f296f0edb75b Mon Sep 17 00:00:00 2001 From: Sarthak Agrawal Date: Wed, 2 Sep 2026 22:10:01 +0530 Subject: [PATCH 3/5] chore: declare repository quality binaries --- knip.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/knip.json b/knip.json index 0b9a9a28..42bb86ce 100644 --- a/knip.json +++ b/knip.json @@ -34,9 +34,12 @@ "ccusage" ], "ignoreBinaries": [ + "actionlint", + "cargo-deny", "ditto", "du", "go", + "gitleaks", "lipo", "lsof", "netstat", From afccdef0e3905bd8d1a5ae90695fd35dd6e8e1a7 Mon Sep 17 00:00:00 2001 From: Sarthak Agrawal Date: Thu, 3 Sep 2026 13:27:32 +0530 Subject: [PATCH 4/5] test(integration): stage shared parity fixture --- .../tests/fixtures/surface-parity/evidence-scope-v1.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 apps/desktop/src-tauri/tests/fixtures/surface-parity/evidence-scope-v1.json diff --git a/apps/desktop/src-tauri/tests/fixtures/surface-parity/evidence-scope-v1.json b/apps/desktop/src-tauri/tests/fixtures/surface-parity/evidence-scope-v1.json new file mode 100644 index 00000000..fda89e48 --- /dev/null +++ b/apps/desktop/src-tauri/tests/fixtures/surface-parity/evidence-scope-v1.json @@ -0,0 +1 @@ +{"schema_version":"codevetter.surface-parity-fixture/v1","authority":{"rust":"authoritative_resolver","cli":"supervised_projection","native":"supervised_projection","mcp":"read_only_projection","mcp_may_execute":false},"request":{"consumer":"performance","kind":"flow","value":"coupon total"},"repository":{"files":{"vitest.config.ts":"export default {};\n","src/cart/coupon.ts":"export const couponTotal = (value: number) => value;\n","src/cart/coupon.test.ts":"import { couponTotal } from './coupon';\ntest('coupon total', () => couponTotal(2));\n"}},"expected":{"schema_version":1,"status":"ready","candidate_count":1,"first_candidate":{"id":"scope-336fa25dbb5e59fc","adapter":"vitest","target":"src/cart/coupon.test.ts","confidence_milli":950,"testing_supported":true,"performance_supported":true},"limitation_contains":"Human-language scope is a deterministic local search"},"canonical_receipt":{"schema_version":1,"plan_id":"scope:surface-parity-v1","repository_revision":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","dirty":false,"kind":"flow","original_input":"coupon total","consumer":"performance","status":"ready","candidates":[{"id":"scope-336fa25dbb5e59fc","adapter":"vitest","target":"src/cart/coupon.test.ts","name":null,"reason":"Matched the described flow through local path/content evidence (score 35)","source_paths":["src/cart/coupon.test.ts","src/cart/coupon.ts"],"confidence_milli":950,"testing_supported":true,"performance_supported":true}],"uncovered_paths":[],"limitations":["Human-language scope is a deterministic local search, not model interpretation."]}} From edf29eb842e004f2462ea24810d1e6fce0860cd2 Mon Sep 17 00:00:00 2001 From: Sarthak Agrawal Date: Thu, 3 Sep 2026 13:51:03 +0530 Subject: [PATCH 5/5] test(native): prove isolated gate orchestration --- scripts/run-native-checks.test.mjs | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/scripts/run-native-checks.test.mjs b/scripts/run-native-checks.test.mjs index 20adce10..b930840c 100644 --- a/scripts/run-native-checks.test.mjs +++ b/scripts/run-native-checks.test.mjs @@ -18,14 +18,33 @@ test('native automation defaults to the non-activating background lane', () => { desktopIdleApproved: false, }); const commands = nativeCheckCommands(parsed); - assert.equal(commands.length, 2); + assert.equal(commands.length, 7); assert.ok(commands.every((command) => command.backgroundSafe)); assert.ok( commands.every( (command) => !command.arguments.includes('test') || command.arguments[0] === 'swift-package' ) ); - assert.deepEqual(commands[0].arguments.slice(-2), ['--parallel', 'false']); + assert.deepEqual(JSON.parse(commands[0].arguments[3]), { + packagePath: 'apps/macos/CodeVetterPackage', + parallel: false, + }); + const performanceCommands = commands.slice(1, 6); + assert.deepEqual( + performanceCommands.map((command) => JSON.parse(command.arguments[3]).filter), + [ + 'hundredRunLedgerDecodesAndRendersWithinTheNativeGate', + 'largeUnpackProjectionDecodesAndRendersWithinTheNativeGate', + 'largeUsageReportDecodesAndRendersWithinTheNativeGate', + 'hundredRowPerformanceReceiptDecodesAndRendersWithinTheNativeGate', + 'hundredJourneyTestingReceiptDecodesAndRendersWithinTheNativeGate', + ] + ); + assert.ok( + performanceCommands.every( + (command) => command.environment.CODEVETTER_NATIVE_PERFORMANCE_GATE === '1' + ) + ); }); test('UI automation fails closed without explicit foreground approval', () => { @@ -115,7 +134,7 @@ test('full qualification keeps background checks before the foreground lane', () ); assert.deepEqual( commands.map((command) => command.backgroundSafe), - [true, true, false] + [true, true, true, true, true, true, true, false] ); });