From b7fe7ba45f36770701e019811c94efbac04c85f7 Mon Sep 17 00:00:00 2001 From: OrcaWin Date: Thu, 5 Nov 2026 08:08:26 -0800 Subject: [PATCH] test: remove low-value workflow and compiler test inventories (#38587) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> --- .../ci-unit-input-ownership.test.mjs | 183 ------------ .../node-server-concurrency.test.mjs | 98 ------ .../node-server-fast-runners.test.mjs | 94 ------ .../win32-test-lane-registration.test.mjs | 276 ----------------- .../ci-draft-pr-admission.test.mjs | 94 ------ .../ci-managed-ssh-execution.test.mjs | 102 +------ .../ci-native-toolchain.test.mjs | 59 ---- .../cloud-security-history-workflow.test.mjs | 13 - .../hourly-preflight-workflow.test.mjs | 17 -- .../pr-auxiliary-preflight-admission.test.mjs | 281 ------------------ .../pr-test-loc-summary.test.mjs | 206 ------------- .../pr-workflow-parallelism.test.mjs | 100 ------- .../required-pr-check-name.test.mjs | 32 -- .../workflow-ref-mirror-case-safety.test.mjs | 102 ------- .../zcode-credential-workflow.test.mjs | 244 --------------- config/scripts/cli-build/build-cli.test.mjs | 217 -------------- .../check-daemon-protocol-crossing.test.mjs | 19 -- ...runtime-launcher-protocol-ratchet.test.mjs | 80 +---- .../daemon-protocol-facts.test.mjs | 46 +-- ...tched-dependencies-frozen-install.test.mjs | 136 --------- 20 files changed, 5 insertions(+), 2394 deletions(-) delete mode 100644 config/scripts/ci/unit-selection/dependency-graph/ci-unit-input-ownership.test.mjs delete mode 100644 config/scripts/ci/unit-selection/node-server-concurrency.test.mjs delete mode 100644 config/scripts/ci/unit-selection/node-server-fast-runners.test.mjs delete mode 100644 config/scripts/ci/unit-selection/win32-test-lane-registration.test.mjs delete mode 100644 config/scripts/ci/workflow-contracts/ci-draft-pr-admission.test.mjs delete mode 100644 config/scripts/ci/workflow-contracts/ci-native-toolchain.test.mjs delete mode 100644 config/scripts/ci/workflow-contracts/pr-test-loc-summary.test.mjs delete mode 100644 config/scripts/ci/workflow-contracts/pr-workflow-parallelism.test.mjs delete mode 100644 config/scripts/ci/workflow-contracts/workflow-ref-mirror-case-safety.test.mjs delete mode 100644 config/scripts/ci/workflow-contracts/zcode-credential-workflow.test.mjs delete mode 100644 config/scripts/cli-build/build-cli.test.mjs delete mode 100644 config/scripts/dependency-security/audit-tools/patched-dependencies-frozen-install.test.mjs diff --git a/config/scripts/ci/unit-selection/dependency-graph/ci-unit-input-ownership.test.mjs b/config/scripts/ci/unit-selection/dependency-graph/ci-unit-input-ownership.test.mjs deleted file mode 100644 index bff87593dec..00000000000 --- a/config/scripts/ci/unit-selection/dependency-graph/ci-unit-input-ownership.test.mjs +++ /dev/null @@ -1,183 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { buildUnitDependencyGraph } from './ci-unit-dependency-graph.mjs' -import { selectUnitFiles } from '../ci-unit-selection.mjs' -import { checkUnitInputOwnership, unitInputSourceDigest } from './ci-unit-input-ownership.mjs' - -const owner = 'src/census.test.ts' -const helper = 'src/census-reader.ts' -const options = 'src/census-options.ts' -const original = new Map([ - [owner, "import { census } from './census-reader'; census()"], - [ - helper, - "import { options } from './census-options'; export const census = () => ts.createProgram(options)" - ], - [options, 'export const options = {}'], - ['src/domain/value.ts', 'export const value = 1'], - ['src/domain/value.test.ts', "import './value'"], - ['src/other.ts', 'export const other = 1'], - ['src/other.test.ts', "import './other'"] -]) -const record = { - file: helper, - inputs: ['src/domain/'], - emptyEnv: [], - contextSha256: buildUnitDependencyGraph(original).ownershipContextSha256, - sourceClosureSha256: unitInputSourceDigest( - new Map([ - [helper, original.get(helper)], - [options, original.get(options)] - ]) - ), - reason: 'This fixture compiler reads only the domain source directory.' -} - -function graph(sources = original, records = [record]) { - return { - ...buildUnitDependencyGraph(sources, undefined, records), - files: new Set(sources.keys()) - } -} - -function selection(changed, input = graph()) { - const tests = [...input.files].filter((file) => file.endsWith('.test.ts')) - return selectUnitFiles(tests, changed, input) -} - -describe('checked indirect unit inputs', () => { - it('retains a declared consumer while excluding it for unrelated source changes', () => { - expect(selection(['src/domain/value.ts']).files).toEqual([owner, 'src/domain/value.test.ts']) - expect(selection(['src/other.ts']).files).toEqual(['src/other.test.ts']) - expect(graph().opaque.has(helper)).toBe(false) - }) - - it('owns new files under a directory even with a direct consumer hiding full fallback', () => { - const sources = new Map(original) - sources.set('src/domain/added.ts', 'export const added = 1') - sources.set('src/domain/added.test.ts', "import './added'") - expect(selection(['src/domain/added.ts'], graph(sources))).toMatchObject({ - full: false, - files: [owner, 'src/domain/added.test.ts'] - }) - }) - - it('bounds an entry point without suppressing other callers of its indirect reader', () => { - const sources = new Map(original) - const otherCaller = 'src/other-census.test.ts' - sources.set(otherCaller, "import { census } from './census-reader'; census()") - const entry = { - ...record, - file: owner, - sourceClosureSha256: unitInputSourceDigest( - new Map([owner, helper, options].map((file) => [file, sources.get(file)])) - ) - } - const input = graph(sources, [entry]) - expect(selection(['src/other.ts'], input).files).toEqual(['src/other.test.ts', otherCaller]) - expect(selection(['src/domain/value.ts'], input).files).toContain(owner) - expect(selection([helper], input).files).toContain(owner) - expect(selection([owner], input).files).toContain(owner) - expect(input.opaque.has(helper)).toBe(true) - }) - - it('invalidates declarations after dependency or shared-runtime changes', () => { - const dependencyInputs = new Map([['pnpm-lock.yaml', 'reviewed dependencies']]) - const contextSha256 = buildUnitDependencyGraph( - original, - undefined, - [], - dependencyInputs - ).ownershipContextSha256 - const records = [{ ...record, contextSha256 }] - expect( - buildUnitDependencyGraph(original, undefined, records, dependencyInputs).opaque.has(helper) - ).toBe(false) - dependencyInputs.set('pnpm-lock.yaml', 'updated dependencies') - expect( - buildUnitDependencyGraph(original, undefined, records, dependencyInputs).opaque.has(helper) - ).toBe(true) - const sources = new Map(original) - sources.set( - 'config/scripts/test-runtime/dom/vitest-dom-setup.ts', - 'configureDifferentRuntime()' - ) - expect(graph(sources).opaque.has(helper)).toBe(true) - }) - - it('keeps deleted and renamed inputs on the full fallback', () => { - const sources = new Map(original) - sources.delete('src/domain/value.ts') - sources.set('src/domain/renamed.ts', 'export const value = 1') - expect(selection(['src/domain/value.ts'], graph(sources)).full).toBe(true) - expect(selection(['src/domain/value.ts', 'src/domain/renamed.ts'], graph(sources)).full).toBe( - true - ) - }) - - it.each( - [ - [], - [{ ...record, sourceClosureSha256: '0'.repeat(64) }], - [record, { ...record, reason: '' }], - [{ ...record, inputs: ['src/domain/../other.ts'] }], - [{ ...record, inputs: ['src/domain\\value.ts'] }], - [{ ...record, inputs: ['src/domain/**'] }] - ].map((records) => ({ records })) - )('retains unowned or invalidly owned consumers: %j', ({ records }) => { - expect(selection(['src/other.ts'], graph(original, records)).files).toContain(owner) - expect(graph(original, records).opaque.has(helper)).toBe(true) - }) - - it('invalidates ownership when a statically imported helper changes', () => { - const sources = new Map(original) - sources.set(options, 'export const options = { rootDir: "src/other" }') - const result = graph(sources) - expect(result.opaque.has(helper)).toBe(true) - expect(selection(['src/other.ts'], result).files).toContain(owner) - }) - - it('rejects a closure changed by a newly resolved JavaScript sibling', () => { - const sources = new Map(original) - sources.set('src/census-options.js', 'export const options = { rootDir: "src/other" }') - expect(graph(sources).opaque.has(helper)).toBe(true) - expect(selection(['src/other.ts'], graph(sources)).files).toContain(owner) - }) - - it('does not clear unresolved local-import fallback with a matching known-source digest', () => { - const sources = new Map(original) - sources.set( - helper, - "import { options } from './census-options'; import './missing'; export const census = () => ts.createProgram(options)" - ) - const matching = { - ...record, - sourceClosureSha256: unitInputSourceDigest( - new Map([ - [helper, sources.get(helper)], - [options, sources.get(options)] - ]) - ) - } - expect(graph(sources, [matching]).opaque.has(helper)).toBe(true) - }) - - it('rejects environment-dependent declarations when the required variable is set', () => { - const conditional = { ...record, emptyEnv: ['ORCA_CENSUS_EXTRA_ROOT'] } - const closure = () => - new Map([ - [helper, original.get(helper)], - [options, original.get(options)] - ]) - expect( - checkUnitInputOwnership([conditional], closure, {}, record.contextSha256).has(helper) - ).toBe(true) - expect( - checkUnitInputOwnership( - [conditional], - closure, - { ORCA_CENSUS_EXTRA_ROOT: 'src/other/' }, - record.contextSha256 - ).size - ).toBe(0) - }) -}) diff --git a/config/scripts/ci/unit-selection/node-server-concurrency.test.mjs b/config/scripts/ci/unit-selection/node-server-concurrency.test.mjs deleted file mode 100644 index 4a9ef914d09..00000000000 --- a/config/scripts/ci/unit-selection/node-server-concurrency.test.mjs +++ /dev/null @@ -1,98 +0,0 @@ -import { readFileSync } from 'node:fs' -import { runInNewContext } from 'node:vm' -import { expect, it } from 'vitest' -import { parse } from 'yaml' -import { compileAggregateExpression } from '../../workflow/pr-admission/pr-aggregate-gate-context.mjs' - -const workflow = parse(readFileSync('.github/workflows/node-server-tests.yml', 'utf8')) - -function context(event, runId, inputs = {}) { - return { - github: { - event_name: event, - run_id: runId, - ref: 'refs/heads/main', - event: { pull_request: { number: 123 } } - }, - inputs: { build_template: false, ref: '', ...inputs }, - matrix: { os: 'windows-2022' }, - format: (template, value) => template.replace('{0}', value) - } -} - -function expression(source, ctx) { - return runInNewContext(source.slice(3, -2).trim(), ctx) -} - -function group(policy, ctx) { - return policy.group.replace(/\$\{\{([\s\S]*?)\}\}/g, (_match, source) => - String(runInNewContext(source, ctx)) - ) -} - -it('skips draft detection and rechecks the same draft once it is ready', () => { - const draft = context('pull_request', 1) - draft.github.event.pull_request.draft = true - expect(runInNewContext(workflow.jobs.changes.if, draft)).toBe(false) - draft.github.event.pull_request.draft = false - expect(runInNewContext(workflow.jobs.changes.if, draft)).toBe(true) - expect(workflow.on.pull_request.types).toContain('ready_for_review') - expect(runInNewContext(workflow.jobs.changes.if, context('push', 2))).toBe(true) - for (const event of ['schedule', 'workflow_dispatch', 'workflow_call']) { - expect(runInNewContext(workflow.jobs.changes.if, context(event, 2))).toBe(false) - } -}) - -it('lets main pushes finish detection without cancelling another push', () => { - const first = context('push', 1) - const second = context('push', 2) - expect(group(workflow.concurrency, first)).not.toBe(group(workflow.concurrency, second)) - expect(expression(workflow.concurrency['cancel-in-progress'], first)).toBe(false) -}) - -it('still replaces superseded pull requests at workflow level', () => { - const first = context('pull_request', 1) - const second = context('pull_request', 2) - expect(group(workflow.concurrency, first)).toBe(group(workflow.concurrency, second)) - expect(expression(workflow.concurrency['cancel-in-progress'], first)).toBe(true) -}) - -it.each(['persistence', 'linux_glibc_floor', 'linux_glibc217_compat', 'linux_musl'])( - '%s only supersedes eligible main qualification, isolating releases and nightly runs', - (name) => { - const job = workflow.jobs[name] - const eligible = compileAggregateExpression(job.if, ['needs', 'github', 'inputs']) - for (const shouldRun of ['true', 'false']) { - const ctx = { - ...context('push', 1), - needs: { - changes: { - outputs: { should_run: shouldRun, qualification: 'true', native_compatibility: 'true' } - }, - mobile_web_bundle: { result: 'success' } - } - } - expect(eligible(ctx).coerceString()).toBe(shouldRun) - } - const policy = job.concurrency - const first = context('push', 1) - const second = context('push', 2) - expect(group(policy, first)).toBe(group(policy, second)) - expect(expression(policy['cancel-in-progress'], first)).toBe(true) - for (const [event, inputs] of [ - ['schedule', {}], - ['workflow_dispatch', {}], - ['push', { build_template: true }], - ['push', { ref: 'refs/tags/v1' }] - ]) { - const isolated = context(event, 2, inputs) - expect(group(policy, isolated)).not.toBe(group(policy, first)) - expect(expression(policy['cancel-in-progress'], isolated)).toBe(false) - expect(group(policy, isolated)).not.toBe(group(policy, context(event, 3, inputs))) - } - if (job.strategy?.matrix) { - second.matrix.os = 'windows-11-arm' - expect(group(policy, second)).not.toBe(group(policy, first)) - } - } -) diff --git a/config/scripts/ci/unit-selection/node-server-fast-runners.test.mjs b/config/scripts/ci/unit-selection/node-server-fast-runners.test.mjs deleted file mode 100644 index 8ff9fe1ecf7..00000000000 --- a/config/scripts/ci/unit-selection/node-server-fast-runners.test.mjs +++ /dev/null @@ -1,94 +0,0 @@ -import { readFileSync } from 'node:fs' -import { runInNewContext } from 'node:vm' -import { expect, it } from 'vitest' -import { parse } from 'yaml' -import { compileAggregateExpression } from '../../workflow/pr-admission/pr-aggregate-gate-context.mjs' - -const workflow = parse(readFileSync('.github/workflows/node-server-tests.yml', 'utf8')) - -function runnerFor(job, os, fast, event = 'workflow_dispatch') { - return compileAggregateExpression(job['runs-on'], ['inputs', 'matrix', 'github'])({ - inputs: { fast_runners: fast }, - matrix: { os }, - github: { event_name: event } - }).coerceString() -} - -it.each([ - ['ubuntu-22.04', 'blacksmith-8vcpu-ubuntu-2204'], - ['ubuntu-24.04-arm', 'blacksmith-8vcpu-ubuntu-2404-arm'], - ['macos-15', 'blacksmith-6vcpu-macos-15'], - ['macos-15-intel', 'macos-15-intel'], - ['windows-2022', 'windows-2022'], - ['windows-11-arm', 'windows-11-arm'] -])('preserves the qualification architecture for %s', (os, fastRunner) => { - expect(runnerFor(workflow.jobs.persistence, os, false)).toBe(os) - expect(runnerFor(workflow.jobs.persistence, os, true)).toBe(fastRunner) - expect(runnerFor(workflow.jobs.persistence, os, undefined)).toBe(os) - for (const event of ['pull_request', 'schedule']) { - expect(runnerFor(workflow.jobs.persistence, os, undefined, event)).toBe(os) - } -}) - -it('retains both Linux architectures and the pinned libc qualification containers', () => { - for (const name of ['linux_glibc_floor', 'linux_musl']) { - const job = workflow.jobs[name] - expect(job.strategy.matrix.os).toEqual(['ubuntu-22.04', 'ubuntu-24.04-arm']) - for (const os of job.strategy.matrix.os) { - expect(runnerFor(job, os, false)).toBe(os) - expect(runnerFor(job, os, true)).toBe( - `blacksmith-8vcpu-ubuntu-${os === 'ubuntu-22.04' ? '2204' : '2404-arm'}` - ) - for (const event of ['pull_request', 'schedule']) { - expect(runnerFor(job, os, undefined, event)).toBe(os) - } - } - } - const floor = workflow.jobs.linux_glibc_floor - expect(floor.container).toBe('${{ matrix.image }}') - for (const { image } of floor.strategy.matrix.include) { - expect(image).toMatch(/^quay\.io\/pypa\/manylinux_2_28_.*@sha256:/) - } - expect(workflow.jobs.linux_glibc217_compat.steps.map((step) => step.run).join('\n')).toContain( - 'quay.io/pypa/manylinux2014_x86_64@sha256:' - ) -}) - -it.each([ - ['changes', 'ubuntu-latest', 'blacksmith-2vcpu-ubuntu-2404'], - ['mobile_web_bundle', 'ubuntu-latest', 'blacksmith-8vcpu-ubuntu-2404'], - ['desktop_template', 'ubuntu-latest', 'blacksmith-4vcpu-ubuntu-2404'], - ['linux_glibc217_compat', 'ubuntu-22.04', 'blacksmith-8vcpu-ubuntu-2204'] -])('sizes %s while preserving the signing workflow override', (name, hostedRunner, fastRunner) => { - expect(runnerFor(workflow.jobs[name], undefined, false)).toBe(hostedRunner) - expect(runnerFor(workflow.jobs[name], undefined, true)).toBe(fastRunner) - expect(runnerFor(workflow.jobs[name], undefined, undefined, 'pull_request')).toBe(hostedRunner) - expect(runnerFor(workflow.jobs[name], undefined, undefined, 'schedule')).toBe(hostedRunner) -}) - -it('still builds and uploads cross-compiled Windows template addons on the x64 lane', () => { - const steps = workflow.jobs.persistence.steps - const launcher = steps.find((step) => step.uses?.includes('prepare-windows-cli-launcher')) - for (const [os, arch, buildTemplate, expectedArches, expectedUpload] of [ - ['windows-2022', 'X64', true, 'x64 arm64', true], - ['windows-2022', 'X64', false, 'x64', false], - ['windows-11-arm', 'ARM64', true, 'arm64', false], - ['windows-11-arm', 'ARM64', false, 'arm64', false] - ]) { - for (const hasSecurityBuilder of [true, false]) { - const ctx = { - inputs: { build_template: buildTemplate }, - matrix: { os }, - runner: { arch }, - hashFiles: () => (hasSecurityBuilder ? 'fixture-builder-hash' : '') - } - for (const fragment of ['process-table addons', 'CLI launchers', 'security addons']) { - const upload = steps.find((step) => step.name?.includes(`Keep the Windows ${fragment}`)) - expect(runInNewContext(upload.if, ctx), `${os} ${fragment}`).toBe( - expectedUpload && (fragment !== 'security addons' || hasSecurityBuilder) - ) - } - expect(runInNewContext(launcher.with.arches.slice(3, -2), ctx)).toBe(expectedArches) - } - } -}) diff --git a/config/scripts/ci/unit-selection/win32-test-lane-registration.test.mjs b/config/scripts/ci/unit-selection/win32-test-lane-registration.test.mjs deleted file mode 100644 index 70c7c1fb87c..00000000000 --- a/config/scripts/ci/unit-selection/win32-test-lane-registration.test.mjs +++ /dev/null @@ -1,276 +0,0 @@ -import { readFileSync, statSync } from 'node:fs' -import { join, resolve } from 'node:path' -import { describe, expect, it } from 'vitest' -import { parse } from 'yaml' -import { scanSourceTree, stripComments } from '../../../../src/shared/source-scan/source-tree-scan' -import { classifyPrJobs } from '../../workflow/source-routing/pr-code-change-scope.mjs' -import { WINDOWS_BOUNDARY_TESTS } from '../../workflow/source-routing/pr-package-test-paths.mjs' - -// Register every Windows-named or suite-gated file in sole Windows lane’s curated list; otherwise Ubuntu self-skips can pass without execution. -// Follow suite/describe gates, nested aliases, local boolean polarity and narrowing &&; do not follow case-level gates, imported/function flags, broad OR/skipIf conjunctions. -// Proves registration/routing list membership, not actual suite execution (manual env gates can skip), diff-trigger coverage or assertion quality. - -const projectDir = resolve(import.meta.dirname, '../../../..') -const WINDOWS_LANE_JOB = 'package_windows' -const WINDOWS_LANE_STEPS = [ - 'Test Windows-specific boundaries', - 'Test Windows installer process probe' -] - -// Shrink-only pre-existing Windows files missing lane registration; remove entry when registered, never add. -const UNREGISTERED_ON_MAIN = [ - // Suite gated with `describe.skipIf(platform !== 'win32')`; the cross-platform - // half of the file still runs on ubuntu, the Windows half runs nowhere. - 'src/main/antigravity/windows-hook-payload-delivery.test.ts', - // `.win32.test.ts` by name yet not registered -- the plainest instance of the class. - 'src/main/daemon/pty-subprocess/testing/node-pty-windows-input-error.win32.test.ts', - // Same shape as the antigravity file: a win32-only sibling suite that never runs. - 'src/main/grok/windows-grok-hook-script.test.ts', - // Whole file is `describe.runIf(platform === 'win32')`; runs on no machine. - 'src/main/ipc/preflight-windows-path-refresh.repro.test.ts', - // `describeWindows` ternary over the whole file; runs on no machine. - 'src/main/providers/windows-shell-preflight-runtime.windows.test.ts', - // Whole file is `describe.runIf(platform === 'win32')`; runs on no machine. - 'src/main/startup/windows-shell-path-restoration.windows.test.ts', - // Whole file is `describe.skipIf(platform !== 'win32')`; runs on no machine. - 'src/shared/setup-agent-sequencing.windows.test.ts' -] - -// Manual suites need real-distro/filesystem opt-in as well as win32; assert env actually reaches gate so this cannot hide registrable debt. -const MANUAL_OPT_IN = [ - // `runIf(platform === 'win32' && Boolean(distro))`, distro from ORCA_TEST_WSL_DISTRO. - 'src/main/git/runner-wsl-linked-gitdir-windows.test.ts', - // `runRealWsl = … && ORCA_REAL_WSL_BANNER_TEST === '1'`; needs a real distro. - 'src/main/workspaces/removal/local-worktree-filesystem-wsl-banner.wsl.test.ts', - // `ORCA_REAL_WINDOWS_SKILL_TEST === '1'`; installs into a real Windows workspace. - 'src/main/skills/skill-windows-workspace.integration.test.ts', - // `RUN_REAL_WSL = … && ORCA_REAL_WSL_SKILL_TEST === '1'`; real distro filesystem. - 'src/main/skills/skill-wsl-delete.integration.test.ts', - // Same flag; real WSL install transactions. - 'src/main/skills/skill-wsl-install-transaction.integration.test.ts', - // Same flag; real WSL POSIX semantics. - 'src/main/skills/skill-wsl-posix-semantics.integration.test.ts', - // `runRealWsl = … && ORCA_REAL_WSL_DELETE_TEST === '1'`; real distro traversal race. - 'src/main/persistence/moving-wsl-projects/wsl-approved-root-race.wsl.test.ts', - // Same flag; real UNC delete against a distro. - 'src/main/wsl/filesystem/wsl-unc-delete.wsl.test.ts', - // `enabled = platform === 'win32' && ORCA_REAL_WSL_RUNNER_TEST === '1'`; mutates a real distro's ~/.profile. - 'src/main/wsl/execution/wsl-runner.wsl.test.ts' -] - -const TEST_FILE_PATTERN = /\.(?:test|spec)\.(?:ts|tsx|mjs|cjs|js)$/ - -// Exclude mobile: separate Vitest job never triggers desktop package_windows lane. -const UNREACHABLE_BY_THE_WINDOWS_LANE = 'mobile/' - -const SCANNER_SELF_PATH = 'config/scripts/ci/unit-selection/win32-test-lane-registration.test.mjs' - -export function isScannerSelfPath(path) { - return path === SCANNER_SELF_PATH -} - -const WIN32_TRUE_EXPRESSION = String.raw`process\.platform\s*===\s*['"]win32['"]` -const WIN32_FALSE_EXPRESSION = String.raw`process\.platform\s*!==\s*['"]win32['"]` -const SUITE = String.raw`(?:describe|suite)` - -// Resolve named flag polarity from assignment, excluding ternary suite aliases. Truthy win32 && narrows; falsy non-win32 && widens skipIf to run on POSIX too. Reject || for both. -const FLAG_TRUE_ASSIGNMENT = new RegExp( - String.raw`(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*${WIN32_TRUE_EXPRESSION}(?=\s*(?:&&|;|\r?\n|$))`, - 'g' -) -const FLAG_FALSE_ASSIGNMENT = new RegExp( - String.raw`(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*${WIN32_FALSE_EXPRESSION}(?=\s*(?:;|\r?\n|$))`, - 'g' -) - -function escapeForAlternation(name) { - return name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') -} - -/** Never-matching branch, so an empty flag set cannot widen a pattern. */ -const MATCHES_NOTHING = String.raw`(?!)` - -function alternation(names) { - return names.length === 0 ? MATCHES_NOTHING : names.map(escapeForAlternation).join('|') -} - -function buildGates(source) { - const trueOnWindows = [...source.matchAll(FLAG_TRUE_ASSIGNMENT)].map(([, name]) => name) - const falseOnWindows = [...source.matchAll(FLAG_FALSE_ASSIGNMENT)].map(([, name]) => name) - const isTrue = `(?:${WIN32_TRUE_EXPRESSION}|\\b(?:${alternation(trueOnWindows)})\\b)` - const isFalse = `(?:${WIN32_FALSE_EXPRESSION}|!\\s*(?:${alternation(trueOnWindows)})\\b|\\b(?:${alternation(falseOnWindows)})\\b)` - return [ - // Accept bare gate or narrowing &&; requiring only closing parenthesis misses runIf(win32 && hasAddon). - new RegExp(String.raw`\b${SUITE}\s*\.\s*runIf\s*\(\s*${isTrue}\s*(?:\)|&&)`), - new RegExp(String.raw`\b${SUITE}\s*\.\s*skipIf\s*\(\s*${isFalse}\s*(?:\)|\|\|)`), - // Reject inverted describe.skip branch, which gates POSIX rather than Windows. - new RegExp(String.raw`=\s*${isTrue}\s*\?\s*${SUITE}\s*(?!\s*\.\s*skip)`), - new RegExp(String.raw`=\s*${isFalse}\s*\?\s*${SUITE}\s*\.\s*skip`) - ] -} - -export function isWindows32GatedTestFile(path, source) { - if (/\.win32\.(?:test|spec)\./.test(path)) { - return true - } - // Strip actual comments with quote tracking; slash-star in string must not erase live gate. - const code = stripComments(source) - return buildGates(code).some((gate) => gate.test(code)) -} - -// Manual exemption requires env read in same win32 conjunct or one referenced const; unrelated env elsewhere cannot park registrable suite. Deeper chains fail closed as registrable. -const WIN32_CONJUNCT = new RegExp(String.raw`${WIN32_TRUE_EXPRESSION}\s*&&([^\n]*)`, 'g') -const ENV_READ = /process\.env\.[A-Za-z0-9_]+/ -const IDENTIFIER = /[A-Za-z_$][\w$]*/g - -function isAssignedFromEnv(name, code) { - return new RegExp( - String.raw`(?:const|let|var)\s+${escapeForAlternation(name)}\s*=[^\n]*process\.env\.` - ).test(code) -} - -export function requiresEnvOptIn(source) { - const code = stripComments(source) - return [...code.matchAll(WIN32_CONJUNCT)].some(([, conjunct]) => { - if (ENV_READ.test(conjunct)) { - return true - } - return [...conjunct.matchAll(IDENTIFIER)].some(([name]) => isAssignedFromEnv(name, code)) - }) -} - -/** The Windows job's curated files: the boundary list plus any argv the lane steps spell out. */ -function readWindowsWorkflow() { - const workflow = parse(readFileSync(join(projectDir, '.github/workflows/pr.yml'), 'utf8')) - const steps = workflow.jobs?.[WINDOWS_LANE_JOB]?.steps ?? [] - const runs = WINDOWS_LANE_STEPS.map((name) => { - const step = steps.find((candidate) => candidate?.name === name) - if (!step) { - throw new Error( - `No "${name}" step in ${WINDOWS_LANE_JOB}; update WINDOWS_LANE_STEPS if renamed.` - ) - } - const run = String(step.run ?? '') - if (!/(?:vitest|vitest\.mjs) run/.test(run)) { - throw new Error(`The "${name}" step no longer invokes vitest; this guard is stale.`) - } - return run - }) - if (!runs[0].includes('config/scripts/workflow/source-routing/pr-package-test-paths.mjs')) { - throw new Error(`The "${WINDOWS_LANE_STEPS[0]}" step no longer reads WINDOWS_BOUNDARY_TESTS.`) - } - const run = runs.join(' ') - return { - laneFiles: [ - ...WINDOWS_BOUNDARY_TESTS, - ...run.split(/\s+/).filter((token) => TEST_FILE_PATTERN.test(token)) - ] - } -} - -const { laneFiles } = readWindowsWorkflow() -const scannedTestFiles = scanSourceTree(projectDir, { - includeTests: true, - extensions: TEST_FILE_PATTERN -}).filter(({ relativePath }) => !relativePath.startsWith(UNREACHABLE_BY_THE_WINDOWS_LANE)) -const gatedFiles = scannedTestFiles - .filter(({ relativePath }) => !isScannerSelfPath(relativePath)) - .filter(({ relativePath, source }) => isWindows32GatedTestFile(relativePath, source)) - .map(({ relativePath }) => relativePath) - -// Ask actual CI classifier, not private WINDOWS_PACKAGE_TESTS; force-all paths could look registered without listing, though none are test paths today. -function isInClassifier(path) { - return classifyPrJobs([path])[WINDOWS_LANE_JOB] === true -} - -function registrationFailure(path) { - const missing = [] - if (!laneFiles.includes(path)) { - missing.push( - `add '${path}' to WINDOWS_BOUNDARY_TESTS in config/scripts/workflow/source-routing/pr-package-test-paths.mjs` - ) - } - if (!isInClassifier(path)) { - missing.push( - `add '${path}' to WINDOWS_PACKAGE_TESTS in config/scripts/workflow/source-routing/pr-package-test-paths.mjs` - ) - } - return missing.length === 0 ? null : `${path}: ${missing.join('; and ')}` -} - -function sourceOf(path) { - return readFileSync(join(projectDir, path), 'utf8') -} - -describe('Windows-gated test files are registered in the Windows CI lane', () => { - it('enables real Windows rename contention tests in the registered step', () => { - const workflow = parse(readFileSync(join(projectDir, '.github/workflows/pr.yml'), 'utf8')) - const step = workflow.jobs.package_windows.steps.find( - (candidate) => candidate.name === 'Test Windows-specific boundaries' - ) - expect(step.env.ORCA_REAL_WINDOWS_SKILL_TEST).toBe('1') - expect(step.env.ORCA_BACKGROUND_LAUNCH).toBe('1') - expect(WINDOWS_BOUNDARY_TESTS).toContain( - 'src/main/skills/skill-windows-rename-contention.integration.test.ts' - ) - }) - - it('parses a plausible Windows lane invocation', () => { - expect(laneFiles.length).toBeGreaterThan(15) - const missingFromDisk = laneFiles.filter((path) => { - try { - return !statSync(join(projectDir, path)).isFile() - } catch { - return true - } - }) - expect( - missingFromDisk, - 'The Windows lane invokes vitest on paths that do not exist -- vitest will run nothing for them.' - ).toEqual([]) - }) - - it('has every Windows-gated test file registered in the Windows lane', () => { - const grandfathered = new Set([...UNREGISTERED_ON_MAIN, ...MANUAL_OPT_IN]) - const failures = gatedFiles - .filter((path) => !grandfathered.has(path)) - .map(registrationFailure) - .filter((failure) => failure !== null) - expect( - failures, - 'A Windows-gated test file is not registered in the Windows CI lane. It self-skips on ' + - 'ubuntu and reports success, so it runs on no machine. Fix each line below.' - ).toEqual([]) - }) - - it('has no stale entry in either grandfathered list', () => { - const stale = [...UNREGISTERED_ON_MAIN, ...MANUAL_OPT_IN].filter( - (path) => !gatedFiles.includes(path) || registrationFailure(path) === null - ) - expect( - stale, - 'These files are no longer unregistered Windows-gated debt -- they were registered, ' + - 'renamed, un-gated, or deleted. Delete each line from UNREGISTERED_ON_MAIN or ' + - 'MANUAL_OPT_IN; the lists only ever shrink.' - ).toEqual([]) - }) - - it('keeps MANUAL_OPT_IN to suites CI genuinely cannot run', () => { - // Otherwise this list is just a quieter way to skip registration. - const notActuallyOptIn = MANUAL_OPT_IN.filter((path) => !requiresEnvOptIn(sourceOf(path))) - expect( - notActuallyOptIn, - 'A MANUAL_OPT_IN entry has no env-var opt-in, so registering it WOULD make it run. ' + - 'Register it in WINDOWS_BOUNDARY_TESTS and delete the line.' - ).toEqual([]) - }) - - it('keeps every UNREGISTERED_ON_MAIN file ineligible for MANUAL_OPT_IN', () => { - // Registrable debt cannot move to manual list just to lower cap. - const movable = UNREGISTERED_ON_MAIN.filter((path) => requiresEnvOptIn(sourceOf(path))) - expect( - movable, - 'This file is registrable; it cannot be reclassified as MANUAL_OPT_IN.' - ).toEqual([]) - }) -}) diff --git a/config/scripts/ci/workflow-contracts/ci-draft-pr-admission.test.mjs b/config/scripts/ci/workflow-contracts/ci-draft-pr-admission.test.mjs deleted file mode 100644 index 03b5b25fa8c..00000000000 --- a/config/scripts/ci/workflow-contracts/ci-draft-pr-admission.test.mjs +++ /dev/null @@ -1,94 +0,0 @@ -import { readFileSync, readdirSync } from 'node:fs' -import { expect, it } from 'vitest' -import { parse } from 'yaml' -import { compileAggregateExpression } from '../../workflow/pr-admission/pr-aggregate-gate-context.mjs' - -const workflows = readdirSync('.github/workflows').flatMap((file) => { - const workflow = parse(readFileSync(`.github/workflows/${file}`, 'utf8')) - // The LoC reporter updates PR metadata rather than running CI. - return Object.hasOwn(workflow.on ?? {}, 'pull_request') && file !== 'pr-test-loc.yml' - ? [{ file, workflow }] - : [] -}) - -function admitted(condition, draft, needs = {}, eventName = 'pull_request') { - return ( - compileAggregateExpression(condition ?? 'true', ['github', 'needs', 'inputs'])({ - github: { - event_name: eventName, - repository: 'stablyai/orca', - event: { pull_request: { draft } } - }, - needs, - inputs: {} - }).coerceString() === 'true' - ) -} - -it.each(workflows)('$file starts no CI jobs for a draft PR', ({ workflow }) => { - const needs = Object.fromEntries( - Object.keys(workflow.jobs).map((id) => [id, { result: 'skipped', outputs: {} }]) - ) - for (const [id, job] of Object.entries(workflow.jobs)) { - // Jobs without a status function inherit success(), so skipped parents block them. - if (job.needs && !/\b(?:cancelled|always|success|failure)\(/.test(job.if ?? '')) { - continue - } - expect(admitted(job.if, true, needs), id).toBe(false) - } -}) - -it.each(workflows)('$file starts CI when ready and cancels it when drafted', ({ workflow }) => { - const types = workflow.on.pull_request.types - expect(types).toEqual( - expect.arrayContaining([ - 'opened', - 'synchronize', - 'reopened', - 'ready_for_review', - 'converted_to_draft' - ]) - ) - expect(Object.values(workflow.jobs).some((job) => !job.needs && admitted(job.if, false))).toBe( - true - ) - const concurrency = workflow.concurrency['cancel-in-progress'] - expect(typeof concurrency === 'boolean' ? concurrency : admitted(concurrency, true)).toBe(true) -}) - -it.each(workflows)('$file keeps its non-PR entry points eligible', ({ workflow }) => { - const needs = Object.fromEntries( - Object.keys(workflow.jobs).map((id) => [id, { result: 'success', outputs: {} }]) - ) - for (const event of Object.keys(workflow.on).filter((name) => name !== 'pull_request')) { - for (const [id, job] of Object.entries(workflow.jobs)) { - expect(admitted(job.if, true, needs, event), `${event}/${id}`).toBe( - admitted(job.if, false, needs, event) - ) - } - } -}) - -it('keeps the root and README guards on ready docs-only PRs without another runner', () => { - const { workflow: prWorkflow } = workflows.find(({ file }) => file === 'pr.yml') - const detector = prWorkflow.jobs.code_paths - const eligible = compileAggregateExpression(detector.if ?? 'true', ['github', 'steps', 'needs']) - expect(admitted(detector.if, true)).toBe(false) - expect(admitted(prWorkflow.jobs.verify.if, true)).toBe(false) - for (const shouldRun of ['false', 'true']) { - expect( - eligible({ - github: { event_name: 'pull_request', event: { pull_request: { draft: false } } }, - steps: { filter: { outputs: { should_run: shouldRun } } }, - needs: {} - }).coerceString() - ).toBe('true') - } - expect(detector.needs).toBeUndefined() - for (const name of ['Reject new root-level files and folders', 'Check README local links']) { - const step = detector.steps.find((candidate) => candidate.name === name) - expect(step).toBeDefined() - expect(step.if).toBeUndefined() - } - expect(prWorkflow.jobs.root_directory_guard).toBeUndefined() -}) diff --git a/config/scripts/ci/workflow-contracts/ci-managed-ssh-execution.test.mjs b/config/scripts/ci/workflow-contracts/ci-managed-ssh-execution.test.mjs index 90bfa8715bb..7e4a7f332cb 100644 --- a/config/scripts/ci/workflow-contracts/ci-managed-ssh-execution.test.mjs +++ b/config/scripts/ci/workflow-contracts/ci-managed-ssh-execution.test.mjs @@ -4,21 +4,14 @@ import { tmpdir } from 'node:os' import { delimiter, join } from 'node:path' import { parse } from 'yaml' import { runProcess } from '@orca/process-host' -import { - managedSshShards, - MANAGED_SSH_E2E_SPEC_PREFIX -} from '../e2e-selection/ci-e2e-job-selection.mjs' -import { compileAggregateExpression } from '../../workflow/pr-admission/pr-aggregate-gate-context.mjs' -import { selectPrE2eSpecs } from '../../workflow/source-routing/pr-e2e-source-routing.mjs' +import { managedSshShards } from '../e2e-selection/ci-e2e-job-selection.mjs' const workflow = parse(readFileSync('.github/workflows/e2e.yml', 'utf8')) -const prWorkflow = parse(readFileSync('.github/workflows/pr.yml', 'utf8')) const lane = workflow.jobs['orcad-ssh-docker'] const command = lane.steps.find( (step) => step.name === 'Run managed SSH specs on a Docker host' ).run const selector = readFileSync('config/scripts/ci/e2e-selection/ci-e2e-job-selection.mjs', 'utf8') -const small = ['tests/e2e/ssh-orcad-open-in-owner.spec.ts', 'tests/e2e/ssh-orcad-idle-exit.spec.ts'] const directories = [] afterEach(() => { for (const directory of directories.splice(0)) { @@ -26,61 +19,6 @@ afterEach(() => { } }) -it('uses one PR shard for at most two selected files and preserves the full default', () => { - const caller = compileAggregateExpression(prWorkflow.jobs.e2e.with.managed_ssh_shards) - const matrix = compileAggregateExpression(lane.strategy.matrix.shard, ['inputs']) - for (const [specs, expected] of [ - [[small[0]], ['1/1']], - [small, ['1/1']], - [ - [...small, 'tests/e2e/ssh-orcad-workspace-tools.spec.ts'], - ['1/2', '2/2'] - ], - [[MANAGED_SSH_E2E_SPEC_PREFIX], ['1/2', '2/2']] - ]) { - const shards = caller({ - needs: { - code_paths: { - outputs: { - e2e_ssh_shards: JSON.stringify(managedSshShards(JSON.stringify(specs))) - } - } - } - }).coerceString() - expect( - matrix({ inputs: { managed_ssh_shards: shards } }) - .values() - .map((item) => item.value) - ).toEqual(expected) - } - expect( - matrix({ inputs: {} }) - .values() - .map((item) => item.value) - ).toEqual(['1/2', '2/2']) -}) - -it('keeps shared SSH fixtures on the full suite but excludes the experimental sidebar spec', () => { - for (const file of [ - 'tests/e2e/helpers/orcad-managed-workspace.ts', - 'tests/e2e/helpers/paired-host-terminal.ts', - '.github/workflows/e2e.yml' - ]) { - expect(selectPrE2eSpecs([file])).toContain(MANAGED_SSH_E2E_SPEC_PREFIX) - } - for (const file of [ - 'tests/e2e/ssh-orcad-phone-feed-list.spec.ts', - 'tests/e2e/helpers/phone-feed-list.ts', - 'tests/e2e/helpers/sidebar-inputs-build.ts', - 'src/shared/sidebar-list/sidebar-feed-list.ts' - ]) { - expect( - selectPrE2eSpecs([file]).some((spec) => spec.startsWith(MANAGED_SSH_E2E_SPEC_PREFIX)), - file - ).toBe(false) - } -}) - async function execute(input, version = 'current') { const directory = mkdtempSync(join(tmpdir(), 'orca-ssh-selection-')) directories.push(directory) @@ -134,44 +72,6 @@ require('node:fs').writeFileSync(process.env.ARGV_CAPTURE, JSON.stringify(proces // The production lane runs Bash on Linux; the stubs never start Docker, Electron, or Xvfb. describe.skipIf(process.platform === 'win32')('managed SSH workflow command', () => { - it('passes only the selected SSH files to Playwright, with literal file matching', async () => { - const { result, args } = await execute( - JSON.stringify([...small, 'tests/e2e/other.spec.ts', small[0]]) - ) - expect(result.code, result.stderr).toBe(0) - const filters = args.slice( - args.indexOf('tests/playwright.config.ts') + 1, - args.indexOf('--project=electron-headless') - ) - expect(filters).toHaveLength(2) - expect(small.map((file) => filters.some((filter) => new RegExp(filter).test(file)))).toEqual([ - true, - true - ]) - expect( - filters.some((filter) => new RegExp(filter).test('tests/e2e/ssh-orcad-open-in-ownerXspecYts')) - ).toBe(false) - expect( - filters.some((filter) => new RegExp(filter).test('tests/e2e/ssh-orcad-unselected.spec.ts')) - ).toBe(false) - expect(args).toContain('--shard=1/1') - }) - - it.each(['', JSON.stringify([MANAGED_SSH_E2E_SPEC_PREFIX, small[0]])])( - 'keeps full daily and explicit suite execution for %s', - async (input) => { - const { result, args } = await execute(input) - expect(result.code, result.stderr).toBe(0) - expect(args).toContain(MANAGED_SSH_E2E_SPEC_PREFIX) - } - ) - - it.each(['legacy', 'missing'])('keeps compatibility with %s checkout refs', async (version) => { - const { result, args } = await execute(JSON.stringify(small), version) - expect(result.code, result.stderr).toBe(0) - expect(args).toContain(MANAGED_SSH_E2E_SPEC_PREFIX) - }) - it.each([ 'malformed', '[]', diff --git a/config/scripts/ci/workflow-contracts/ci-native-toolchain.test.mjs b/config/scripts/ci/workflow-contracts/ci-native-toolchain.test.mjs deleted file mode 100644 index 6075965cc6b..00000000000 --- a/config/scripts/ci/workflow-contracts/ci-native-toolchain.test.mjs +++ /dev/null @@ -1,59 +0,0 @@ -import { execFileSync } from 'node:child_process' -import { chmodSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs' -import { tmpdir } from 'node:os' -import { join } from 'node:path' -import { parse } from 'yaml' -import { describe, expect, it } from 'vitest' - -const steps = parse(readFileSync('.github/actions/prepare-native-runtime/action.yml', 'utf8')).runs - .steps -const toolchain = steps.find((step) => step.name === 'Use external node-gyp') - -describe('CI native toolchain preparation', () => { - // The action's toolchain workaround only runs in Linux Bash. - it.skipIf(process.platform === 'win32').each([ - ['node', 'true', '0', false], - ['node', 'true', '1', true], - ['node', 'false', '0', true], - ['node', '', '0', true] - ])('runtime=%s cache=%s probe=%s installs=%s', (runtime, hit, probeStatus, installs) => { - const directory = mkdtempSync(join(tmpdir(), 'orca-ci-native-toolchain-')) - const log = join(directory, 'commands') - const environment = join(directory, 'github-env') - try { - writeFileSync(log, '') - writeFileSync(environment, '') - for (const [name, source] of [ - ['node', 'echo "node $*" >> "$COMMAND_LOG"\nexit "$PROBE_STATUS"'], - ['npm', 'echo "npm $*" >> "$COMMAND_LOG"\nif [ "$1" = root ]; then echo /global; fi'] - ]) { - const path = join(directory, name) - writeFileSync(path, `#!/bin/sh\n${source}\n`) - chmodSync(path, 0o755) - } - execFileSync('bash', ['-e', '-o', 'pipefail', '-c', toolchain.run], { - env: { - ...process.env, - PATH: `${directory}:${process.env.PATH}`, - NATIVE_RUNTIME: runtime, - NATIVE_CACHE_HIT: hit, - PROBE_STATUS: probeStatus, - COMMAND_LOG: log, - GITHUB_ENV: environment - } - }) - const commands = readFileSync(log, 'utf8') - expect(commands.includes('npm install -g node-gyp@11.5.0')).toBe(installs) - expect( - commands.includes( - 'node config/scripts/native-build/node-addons/ensure-native-runtime.mjs --check-only' - ) - ).toBe(runtime === 'node' && hit === 'true') - expect(readFileSync(environment, 'utf8')).toBe( - installs ? 'npm_config_node_gyp=/global/node-gyp/bin/node-gyp.js\n' : '' - ) - } finally { - rmSync(directory, { recursive: true, force: true }) - } - }) -}) diff --git a/config/scripts/ci/workflow-contracts/cloud-security-history-workflow.test.mjs b/config/scripts/ci/workflow-contracts/cloud-security-history-workflow.test.mjs index f8d05dde19e..afc5ac30383 100644 --- a/config/scripts/ci/workflow-contracts/cloud-security-history-workflow.test.mjs +++ b/config/scripts/ci/workflow-contracts/cloud-security-history-workflow.test.mjs @@ -77,16 +77,3 @@ it('fetches both merge parents and deleted content without unrelated branches or rmSync(directory, { recursive: true, force: true }) } }) - -it('completes history before scanning the same HEAD and Cloud paths', () => { - expect(steps[0].with['fetch-depth']).toBe(1) - expect(history['working-directory']).toBe('.') - const scanIndex = steps.findIndex( - (step) => step.run?.includes('docker run') && step.run.includes('gitleaks@') - ) - expect(steps.indexOf(history)).toBeLessThan(scanIndex) - expect(steps[scanIndex].run).toContain( - '--log-opts="HEAD -- cloud :(glob).github/workflows/cloud-*.yml .github/actions/cloud-sql-rollout-lease"' - ) - expect(steps.some((step) => step.run?.includes('trufflehog@'))).toBe(true) -}) diff --git a/config/scripts/ci/workflow-contracts/hourly-preflight-workflow.test.mjs b/config/scripts/ci/workflow-contracts/hourly-preflight-workflow.test.mjs index cc488365a73..c59a910ec6a 100644 --- a/config/scripts/ci/workflow-contracts/hourly-preflight-workflow.test.mjs +++ b/config/scripts/ci/workflow-contracts/hourly-preflight-workflow.test.mjs @@ -58,23 +58,6 @@ async function checkFreshness(overrides = {}) { } describe('hourly build preflight', () => { - it('gates Mac allocation and pins the checkout and downstream identity', () => { - const build = workflow.jobs['build-hourly-mac'] - expect(preflight['runs-on']).toBe('ubuntu-latest') - expect(preflight.steps.some((step) => step.uses?.startsWith('actions/checkout'))).toBe(false) - expect( - preflight.steps.find((step) => step.id === 'app_token').with['permission-contents'] - ).toBe('read') - expect(build.needs).toEqual(['preflight', 'orcad-template']) - expect(build.if).toBe("needs.preflight.outputs.should_build == 'true'") - expect(build.steps.find((step) => step.name === 'Checkout').with.ref).toBe( - build.outputs.head_sha - ) - expect(build.outputs.head_sha).toBe('${{ needs.preflight.outputs.head_sha }}') - expect(build.steps.find((step) => step.id === 'release').env.SHA).toBe(build.outputs.head_sha) - expect(workflow.concurrency).toEqual({ group: 'hourly-mac-build', 'cancel-in-progress': false }) - }) - it.each([ ['unchanged', {}, false], ['changed', { LAST_SHA: '123456789012' }, true], diff --git a/config/scripts/ci/workflow-contracts/pr-auxiliary-preflight-admission.test.mjs b/config/scripts/ci/workflow-contracts/pr-auxiliary-preflight-admission.test.mjs index 7874f2bddc1..83a3cee313e 100644 --- a/config/scripts/ci/workflow-contracts/pr-auxiliary-preflight-admission.test.mjs +++ b/config/scripts/ci/workflow-contracts/pr-auxiliary-preflight-admission.test.mjs @@ -9,226 +9,11 @@ import { } from 'node:fs' import { tmpdir } from 'node:os' import { dirname, join, resolve } from 'node:path' -import { runInNewContext } from 'node:vm' import { afterEach, describe, expect, it } from 'vitest' import { runProcessSync } from '@orca/process-host' import { parse } from 'yaml' -import { classifyPrJobs } from '../../workflow/source-routing/pr-code-change-scope.mjs' -import { collectNodeServerInputs } from '../../node-server/qualification/node-server-change-scope.mjs' const workflow = parse(readFileSync('.github/workflows/pr.yml', 'utf8')) -const unit = parse(readFileSync('.github/workflows/unit-tests.yml', 'utf8')) -const relaySteps = unit.jobs.relay_integration.steps -const chrome = relaySteps.find((step) => step.name === 'Resolve Chrome for the browser provider') -const browser = relaySteps.find((step) => step.name === 'Test external Chromium browser provider') -const routes = [ - ['git_compatibility', 'src/shared/git/commands/git-capability-cache.ts'], - ['codex_index_heal_contract', 'src/main/codex/history/index/codex-session-index-heal.ts'], - ['xterm_patch_sync', 'config/patches/xterm-upstream.json'], - ['shell_contracts', 'src/main/pty/pty-manager.ts'], - ['orcad_browser', 'src/main/orcad/orcad-browser-provider.ts'], - ['cross-version-wire', 'src/shared/orchestration-rpc-contract.ts'], - ['managed_hook_node18', 'src/shared/agent-hook-status.ts'] -] - -function evaluate(expression, context) { - return runInNewContext( - expression - .replace(/^\$\{\{\s*|\s*\}\}$/g, '') - .replaceAll('.cross-version-wire', '["cross-version-wire"]'), - context - ) -} - -function routedOutputs(files, reused, options) { - const scope = classifyPrJobs(files, options) - const context = { - steps: { - readiness: { outputs: { reused } }, - filter: { - outputs: Object.fromEntries( - Object.entries(scope).map(([key, value]) => [key, String(value)]) - ) - } - } - } - return Object.fromEntries( - [ - 'test', - 'static_analysis', - 'typecheck', - 'mobile_ci_tools', - 'relay_integration', - ...routes.map(([job]) => job) - ].map((name) => [name, String(evaluate(workflow.jobs.code_paths.outputs[name], context))]) - ) -} - -it('preserves relay continuation, setup guards and cancellation', () => { - const steps = relaySteps - const install = steps.find((step) => step.id === 'relay_dependencies') - const test = steps.find((step) => step.name === 'Test relay integration contracts') - const context = { - cancelled: () => false, - success: () => false, - steps: { - root_dependencies: { outcome: 'success' }, - relay_dependencies: { outcome: 'success' } - } - } - expect(evaluate(install.if, context)).toBe(true) - expect(evaluate(test.if, context)).toBe(true) - context.steps.root_dependencies.outcome = 'failure' - expect(evaluate(install.if, context)).toBe(false) - context.steps.relay_dependencies.outcome = 'failure' - expect(evaluate(test.if, context)).toBe(false) - context.steps.root_dependencies.outcome = 'success' - context.steps.relay_dependencies.outcome = 'success' - context.cancelled = () => true - expect(evaluate(install.if, context)).toBe(false) - expect(evaluate(test.if, context)).toBe(false) - expect( - steps.findIndex((step) => step.name === 'Test external Chromium browser provider') - ).toBeLessThan(steps.indexOf(install)) - expect(test['continue-on-error']).toBeUndefined() - expect(unit.jobs.relay_integration['continue-on-error']).toBeUndefined() - expect(chrome['continue-on-error']).toBeUndefined() - expect(browser['continue-on-error']).toBeUndefined() - expect(workflow.jobs.verify.needs).toContain('test') -}) - -it('guards both browser steps after setup or discovery failure and for default callers', () => { - const context = { - inputs: { browser_contract: true }, - success: () => true - } - expect(evaluate(chrome.if, context)).toBe(true) - expect(evaluate(browser.if, context)).toBe(true) - context.success = () => false - expect(evaluate(chrome.if, context)).toBe(false) - expect(evaluate(browser.if, context)).toBe(false) - context.success = () => true - context.inputs.browser_contract = unit.on.workflow_call.inputs.browser_contract.default - expect(evaluate(chrome.if, context)).toBe(false) - expect(evaluate(browser.if, context)).toBe(false) -}) - -describe('Mobile CI tool preflight routing', () => { - const verified = { allowMobileCiTools: true } - - it.each([ - { - files: [ - 'config/scripts/mobile-web/check-entry/run-mobile-ci-tests.mjs', - 'config/mobile-ci.vitest.config.mjs' - ] - }, - { files: ['config/scripts/mobile-web/check-entry/mobile-release-check-scope.test.mjs'] }, - { files: ['config/scripts/mobile-web/check-entry/mobile-test-change-scope.test.mjs'] } - ])('keeps affected controls required without starting root shards for $files', ({ files }) => { - const outputs = routedOutputs(files, 'false', verified) - expect(outputs.mobile_ci_tools).toBe('true') - expect(outputs.test).toBe('true') - const context = { needs: { code_paths: { outputs } } } - expect(evaluate(workflow.jobs.preflight.if, context)).toBe(true) - expect(evaluate(workflow.jobs.test.with.run_shards, context)).toBe(false) - expect(evaluate(unit.jobs.test.if, { inputs: { run_shards: false } })).toBe(false) - const required = workflow.jobs.verify.steps.find( - (step) => step.name === 'Require successful checks' - ) - expect(evaluate(required.env.PREFLIGHT_SHOULD_RUN, context)).toBe(true) - }) - - it('requires complete modification evidence and an exact path scope', () => { - const tool = 'config/scripts/mobile-web/check-entry/run-mobile-ci-tests.mjs' - expect(classifyPrJobs([tool]).test).toBe(true) - expect(classifyPrJobs([tool]).mobile_ci_tools).toBe(false) - for (const files of [ - [], - [tool, 'src/main/runtime/orca-runtime.ts'], - [tool, 'pnpm-lock.yaml'], - [tool, 'package.json'], - [tool, 'config/vitest.config.ts'], - [tool, 'config/scripts/workflow/source-routing/pr-code-change-scope.mjs'], - [tool, 'config/scripts/workflow/source-routing/pr-package-test-paths.mjs'], - [tool, 'config/scripts/new-mobile-tool.mjs'], - [tool, 'README.md'], - [tool, 'mobile/vitest.config.ts'] - ]) { - const selected = classifyPrJobs(files, verified) - expect(selected.mobile_ci_tools).toBe(false) - expect(selected.test).toBe(true) - } - }) -}) - -describe('Renderer-only relay admission', () => { - const renderer = 'src/renderer/src/components/right-sidebar/file-explorer/panel/FileExplorer.tsx' - const admitted = (files) => { - const outputs = routedOutputs(files, 'false') - const runRelay = evaluate(workflow.jobs.test.with.run_relay_integration, { - needs: { code_paths: { outputs } } - }) - return evaluate(unit.jobs.relay_integration.if, { - inputs: { run_relay_integration: runRelay } - }) - } - - it('skips relay setup for renderer-only changes while retaining unit and package checks', () => { - const files = [renderer, 'src/renderer/src/i18n/locales/en.json', 'README.md'] - expect(admitted(files)).toBe(false) - expect(classifyPrJobs(files)).toMatchObject({ - test: true, - static_analysis: true, - typecheck: true, - package: true, - package_windows: true - }) - }) - - it.each([ - [], - ['src/main/runtime/mobile-cloud-relay/relay-http-client.ts'], - ['src/shared/relay-region-preference.ts'], - ['tests/e2e/relay-region-compatibility.unit.test.ts'], - ['src/main/orcad/orcad-browser-provider.ts'], - ['package.json'], - ['pnpm-lock.yaml'], - ['config/vitest.config.ts'], - ['.github/workflows/unit-tests.yml'], - ['.github/workflows/pr.yml'], - ['unknown-input'], - [renderer, 'cloud/packages/relay-contract/src/director-messages.ts'], - [renderer, 'src/main/runtime/mobile-cloud-relay/relay-http-client.ts'], - [renderer, 'src/shared/relay-region-preference.ts'] - ])('retains relay coverage for non-renderer or incomplete evidence: %j', (...files) => { - expect(admitted(files)).toBe(true) - }) - - it.each([ - {}, - { relay_integration: '' }, - { relay_integration: 'unknown' }, - { relay_integration: 'false', orcad_browser: 'true' } - ])( - 'retains relay/browser execution for missing routes or a selected browser contract: %j', - (outputs) => { - expect( - evaluate(workflow.jobs.test.with.run_relay_integration, { - needs: { code_paths: { outputs } } - }) - ).toBe(true) - } - ) - - it('keeps the shipped relay contracts independent of renderer inputs', async () => { - const testStep = relaySteps.find((step) => step.name === 'Test relay integration contracts') - const entryPoints = testStep.run.split(/\s+/).filter((arg) => arg.endsWith('.test.ts')) - expect(entryPoints.length).toBeGreaterThan(0) - const inputs = await collectNodeServerInputs({ entryPoints }) - expect([...inputs].filter((file) => file.startsWith('src/renderer/'))).toEqual([]) - }) -}) const mobileCiScopeDirectories = [] afterEach(() => { @@ -371,69 +156,3 @@ describe.skipIf(process.platform === 'win32')('Mobile CI complete Git change evi expect(result.stderr).toContain('not a git repository') }) }) - -describe.skipIf(process.platform === 'win32')('Daemon mock complete Git change evidence', () => { - const helper = 'src/main/daemon/providers/lifecycle/testing/daemon-init-dependency-mocks.ts' - it('keeps real unit and type contracts while omitting unrelated packages for a modification', () => { - const repo = createMobileCiScopeRepository(true, helper) - writeFileSync(repo.tool, 'export const revision = 2\n') - repo.commit() - const { result, output } = repo.detect() - expect(result.code, result.stderr).toBe(0) - const flags = readFileSync(output, 'utf8') - expect(flags).toContain('package=false\n') - expect(flags).toContain('package_windows=false\n') - expect(flags).toContain('test=true\n') - expect(flags).toContain('typecheck=true\n') - }) - it('routes the complete three-file modification through the real detector', () => { - const companions = [ - 'src/main/native-chat/agent-session-wire/structured-agent-session-claude-queued-stop.test.ts', - 'config/scripts/desktop-distribution/runtime-verification/process-host-build-dist.test.mjs' - ] - const repo = createMobileCiScopeRepository(true, helper, companions) - for (const file of [helper, ...companions]) { - writeFileSync(join(repo.directory, file), 'export const revision = 2\n') - } - repo.commit() - const { result, output } = repo.detect() - expect(result.code, result.stderr).toBe(0) - const flags = readFileSync(output, 'utf8') - for (const name of ['package', 'package_windows']) { - expect(classifyPrJobs([helper, ...companions])[name]).toBe(true) - expect(flags).toContain(`${name}=false\n`) - } - for (const name of ['test', 'static_analysis', 'typecheck', 'cross-version-wire']) { - expect(flags).toContain(`${name}=true\n`) - } - const e2e = repo.detect('e2e_filter') - expect(e2e.result.code, e2e.result.stderr).toBe(0) - const routes = readFileSync(e2e.output, 'utf8') - expect(routes).toContain('test_files=[]\n') - expect(routes).toContain('should_run=false\n') - }) - it.each(['addition', 'deletion', 'rename', 'type change'])( - 'keeps platform packages for an actual %s', - (change) => { - const repo = createMobileCiScopeRepository(change !== 'addition', helper) - if (change === 'addition') { - writeFileSync(repo.tool, 'export const revision = 1\n') - } else if (change === 'deletion') { - rmSync(repo.tool) - } else if (change === 'rename') { - repo.git('mv', helper, helper.replace('.ts', '-renamed.ts')) - } else { - rmSync(repo.tool) - symlinkSync( - '../../../config/scripts/workflow/source-routing/pr-code-change-scope.mjs', - repo.tool - ) - } - repo.commit() - const { result, output } = repo.detect() - expect(result.code, result.stderr).toBe(0) - expect(readFileSync(output, 'utf8')).toContain('package=true\n') - expect(readFileSync(output, 'utf8')).toContain('package_windows=true\n') - } - ) -}) diff --git a/config/scripts/ci/workflow-contracts/pr-test-loc-summary.test.mjs b/config/scripts/ci/workflow-contracts/pr-test-loc-summary.test.mjs deleted file mode 100644 index 8ad46954743..00000000000 --- a/config/scripts/ci/workflow-contracts/pr-test-loc-summary.test.mjs +++ /dev/null @@ -1,206 +0,0 @@ -import { spawnSync } from 'node:child_process' -import { mkdtempSync, rmSync, writeFileSync } from 'node:fs' -import { tmpdir } from 'node:os' -import { join, resolve } from 'node:path' -import { afterEach, describe, expect, it } from 'vitest' -import { - listPullFiles, - updatePullRequest -} from '../../../../.github/scripts/pr-test-loc-summary.mjs' -import { - LOC_HANDS_OFF_COMMENT, - mergeLocBlock, - renderLocBlock, - sumChangedFiles -} from '../../../../.github/scripts/pr-test-loc-table.mjs' - -const projectDir = resolve(import.meta.dirname, '../../../..') -const locScript = join(projectDir, '.github/scripts/pr-test-loc-summary.mjs') -const tempDirs = [] - -function runLoc(args, { env } = {}) { - return spawnSync(process.execPath, [locScript, ...args], { - cwd: projectDir, - encoding: 'utf8', - env: { ...process.env, ...env } - }) -} - -afterEach(() => { - while (tempDirs.length > 0) { - rmSync(tempDirs.pop(), { force: true, recursive: true }) - } -}) - -describe('PR test LoC summary', () => { - it('paginates pull files until Link rel=next is gone', async () => { - const pages = { - 'https://api.github.com/repos/stablyai/orca/pulls/9/files?per_page=100': { - body: [{ filename: 'src/app.ts', additions: 2, deletions: 0 }], - link: '; rel="next"' - }, - 'https://api.github.com/repos/stablyai/orca/pulls/9/files?page=2': { - body: [{ filename: 'src/app.test.ts', additions: 5, deletions: 1 }], - link: null - } - } - - const files = await listPullFiles({ - owner: 'stablyai', - repo: 'orca', - pullNumber: 9, - token: 'test-token', - fetchImpl: async (url) => { - const page = pages[url] - if (page == null) { - throw new Error(`unexpected url ${String(url)}`) - } - return { - ok: true, - json: async () => page.body, - headers: { get: (name) => (name === 'link' ? page.link : null) } - } - } - }) - - expect(sumChangedFiles(files)).toEqual({ - test: { files: 1, added: 5, deleted: 1 }, - nonTest: { files: 1, added: 2, deleted: 0 } - }) - }) - - it('retries transient GitHub errors when updating the PR body', async () => { - const body = '## Description\n' - const totals = { - test: { files: 1, added: 2, deleted: 0 }, - nonTest: { files: 0, added: 0, deleted: 0 } - } - const delays = [] - const responses = [ - { ok: false, status: 503, statusText: 'Service Unavailable' }, - { ok: true, status: 200, statusText: 'OK' } - ] - const requests = [] - const result = await updatePullRequest({ - owner: 'stablyai', - repo: 'orca', - pullNumber: 14656, - token: 'test-token', - totals, - fetchImpl: async (url, options) => { - requests.push({ url, options }) - if (requests.length === 1) { - return { - ok: true, - status: 200, - json: async () => ({ body }) - } - } - return responses.shift() - }, - sleepImpl: async (milliseconds) => { - delays.push(milliseconds) - } - }) - - expect(result).toBe(0) - expect(requests).toHaveLength(3) - expect(requests.map(({ url }) => url)).toEqual( - Array(3).fill('https://api.github.com/repos/stablyai/orca/pulls/14656') - ) - for (const { options } of requests.slice(1)) { - expect(options.method).toBe('PATCH') - expect(JSON.parse(options.body)).toEqual({ - body: `${body}\n${renderLocBlock(totals)}\n` - }) - } - expect(delays).toEqual([1000]) - }) - - it('renders the table with a hands-off marker', () => { - const block = renderLocBlock({ - test: { files: 1, added: 2, deleted: 1 }, - nonTest: { files: 1, added: 4, deleted: 0 } - }) - - expect(block).toContain(LOC_HANDS_OFF_COMMENT) - expect(block).toContain( - '| Test | 1 | $\\color{#1a7f37}{\\Huge{\\mathbf{+}}}$​2 | $\\color{#cf222e}{\\Huge{\\mathbf{−}}}$​1 | $\\color{#1a7f37}{\\Huge{\\mathbf{+}}}$​1 |' - ) - expect(block).toContain( - '| Prod | 1 | $\\color{#1a7f37}{\\Huge{\\mathbf{+}}}$​4 | 0 | $\\color{#1a7f37}{\\Huge{\\mathbf{+}}}$​4 |' - ) - expect(block).not.toContain('| Total |') - }) - - it('places the table after the ELI5 section so link unfurls stay readable', () => { - const totals = { - test: { files: 1, added: 2, deleted: 1 }, - nonTest: { files: 1, added: 4, deleted: 0 } - } - const block = renderLocBlock(totals) - const expected = `## ELI5\n\nHello\n\n${block}\n\n## Why\n\nBecause\n` - - expect(mergeLocBlock('## ELI5\n\nHello\n\n## Why\n\nBecause\n', totals)).toBe(expected) - // Idempotent once placed. - expect(mergeLocBlock(expected, totals)).toBe(expected) - // Migrates a block previously prepended at the top, including legacy formats. - expect(mergeLocBlock(`${block}\n\n## ELI5\n\nHello\n\n## Why\n\nBecause\n`, totals)).toBe( - expected - ) - expect( - mergeLocBlock( - '\n**LoC** · test **+1 / −0**\n\n\n## ELI5\n\nHello\n\n## Why\n\nBecause\n', - totals - ) - ).toBe(expected) - // ELI5 subsections stay inside the section. - expect(mergeLocBlock('## ELI5\n\nHi\n\n### Detail\n\nMore\n\n## Why\n', totals)).toBe( - `## ELI5\n\nHi\n\n### Detail\n\nMore\n\n${block}\n\n## Why\n` - ) - }) - - it('appends the table when there is no ELI5 section to follow', () => { - const totals = { - test: { files: 0, added: 0, deleted: 0 }, - nonTest: { files: 1, added: 4, deleted: 0 } - } - const block = renderLocBlock(totals) - - expect(mergeLocBlock('## ELI5\n\nHello\n', totals)).toBe(`## ELI5\n\nHello\n\n${block}\n`) - expect(mergeLocBlock('Bump deps\n', totals)).toBe(`Bump deps\n\n${block}\n`) - expect(mergeLocBlock(`${block}\n\nBump deps\n`, totals)).toBe(`Bump deps\n\n${block}\n`) - expect(mergeLocBlock('', totals)).toBe(`${block}\n`) - expect(mergeLocBlock(null, totals)).toBe(`${block}\n`) - }) - - it('counts and merges from a files JSON fixture', () => { - const root = mkdtempSync(join(tmpdir(), 'orca-pr-test-loc-')) - tempDirs.push(root) - const filesPath = join(root, 'files.json') - const bodyPath = join(root, 'body.md') - writeFileSync( - filesPath, - JSON.stringify([ - { filename: 'src/app.ts', additions: 2, deletions: 0 }, - { filename: 'src/app.test.ts', additions: 6, deletions: 1 } - ]) - ) - writeFileSync(bodyPath, '## ELI5\n\nHello\n') - - const result = runLoc(['--files-json', filesPath, '--merge-body', bodyPath]) - - expect(result.status).toBe(0) - expect(result.stdout.startsWith('## ELI5\n\nHello\n\n')).toBe(true) - expect(result.stdout).toContain(LOC_HANDS_OFF_COMMENT) - expect(result.stdout).toContain( - '| Test | 1 | $\\color{#1a7f37}{\\Huge{\\mathbf{+}}}$\u200b6 | $\\color{#cf222e}{\\Huge{\\mathbf{−}}}$\u200b1 | $\\color{#1a7f37}{\\Huge{\\mathbf{+}}}$\u200b5 |' - ) - expect(result.stdout).toContain( - '| Prod | 1 | $\\color{#1a7f37}{\\Huge{\\mathbf{+}}}$\u200b2 | 0 | $\\color{#1a7f37}{\\Huge{\\mathbf{+}}}$\u200b2 |' - ) - expect(result.stdout).not.toContain('| Total |') - expect(result.stdout).toContain('## ELI5\n\nHello\n') - expect(result.stdout.match(//g)).toHaveLength(1) - }) -}) diff --git a/config/scripts/ci/workflow-contracts/pr-workflow-parallelism.test.mjs b/config/scripts/ci/workflow-contracts/pr-workflow-parallelism.test.mjs deleted file mode 100644 index 455c7eb120f..00000000000 --- a/config/scripts/ci/workflow-contracts/pr-workflow-parallelism.test.mjs +++ /dev/null @@ -1,100 +0,0 @@ -import { readFileSync } from 'node:fs' -import { runInNewContext } from 'node:vm' -import { parse } from 'yaml' -import { describe, expect, it } from 'vitest' - -const workflow = parse(readFileSync('.github/workflows/pr.yml', 'utf8')) -const unitTestWorkflow = parse(readFileSync('.github/workflows/unit-tests.yml', 'utf8')) -const planWorkflow = parse(readFileSync('.github/workflows/unit-plan.yml', 'utf8')) -const evidenceWorkflow = parse( - readFileSync('.github/workflows/unit-selection-evidence.yml', 'utf8') -) - -describe('PR workflow parallelism', () => { - it.each([ - ['shadow', false, true], - ['shadow', true, true], - ['selected', false, true], - ['selected', true, false], - ['', true, true] - ])('plans only once for mode %s, draft %s', (mode, draft, deferred) => { - const evaluate = (expression, context) => runInNewContext(expression.slice(3, -2), context) - const context = { - vars: { ORCA_UNIT_SELECTION_MODE: mode }, - github: { event: { pull_request: { draft } } } - } - const inputs = { - defer_shadow: evaluate(workflow.jobs.unit_plan.with.defer_shadow, context), - selection_mode: evaluate(workflow.jobs.unit_plan.with.selection_mode, context) - } - const planContext = { ...context, inputs } - expect(evaluate(planWorkflow.jobs.plan.env.DEFER_SHADOW, planContext)).toBe(deferred) - // Downstream jobs read the plan's output rather than re-deriving the draft condition. - const planned = String(evaluate(planWorkflow.jobs.plan.outputs.selection_planned, planContext)) - const needs = { unit_plan: { outputs: { selection_planned: planned } } } - expect(evaluate(workflow.jobs.test.with.download_selection_plan, { needs })).toBe(!deferred) - expect(evaluate(workflow.jobs.unit_selection_evidence.with.rebuild_plan, { needs })).toBe( - deferred - ) - }) - - it('keeps advisory unit-selection evidence off the gate', () => { - // Keep advisory continue-on-error work off unit-tests.yml’s critical path: caller needs:test otherwise waits ~36s beyond last shard. - const evidence = workflow.jobs.unit_selection_evidence - expect(evidence.uses).toBe('./.github/workflows/unit-selection-evidence.yml') - expect(evidence.needs).toEqual(['unit_plan', 'test']) - for (const [result, cancelled, expected] of [ - ['success', false, true], - ['failure', false, true], - ['skipped', false, false], - ['cancelled', false, false], - ['success', true, false], - ['failure', true, false] - ]) { - expect( - runInNewContext(evidence.if.slice(3, -2), { - cancelled: () => cancelled, - needs: { test: { result } } - }) - ).toBe(expected) - } - expect(workflow.jobs.verify.needs).not.toContain('unit_selection_evidence') - expect(unitTestWorkflow.jobs.selection_evidence).toBeUndefined() - const job = evidenceWorkflow.jobs.selection_evidence - expect(job['continue-on-error']).toBe(true) - }) - - it.each([undefined, 'false', 'true'])( - 'runs the advisory CLI without an action credential and preserves failures (deferred %s)', - async (rebuild) => { - const steps = evidenceWorkflow.jobs.selection_evidence.steps - expect(steps.some((step) => step.uses?.startsWith('actions/setup-node@'))).toBe(false) - const comparison = steps.find((step) => step.name === 'Compare selection with full results') - expect(comparison.uses).toBe('actions/github-script@v8') - expect(comparison.with['github-token']).toBe('unused') - const publicEnv = { - GITHUB_STEP_SUMMARY: '/tmp/summary', - ...(rebuild === undefined ? {} : { REBUILD_SELECTION_PLAN: rebuild }) - } - const env = { ...publicEnv, 'INPUT_GITHUB-TOKEN': 'test-token' } - const failure = new Error('comparison failed') - const result = runInNewContext(`(async () => { ${comparison.with.script} })()`, { - process: { env, execPath: '/bundled/node24' }, - exec: { - exec: async (command, args, options) => { - expect(command).toBe('/bundled/node24') - expect(args).toEqual([ - 'config/scripts/ci/unit-selection/ci-unit-selection-review.mjs', - 'unit-evidence', - ...(rebuild === 'true' ? ['ci-shards/unit-selection.json'] : []) - ]) - expect(options.env).toEqual(publicEnv) - throw failure - } - } - }) - await expect(result).rejects.toBe(failure) - expect(env['INPUT_GITHUB-TOKEN']).toBe('test-token') - } - ) -}) diff --git a/config/scripts/ci/workflow-contracts/required-pr-check-name.test.mjs b/config/scripts/ci/workflow-contracts/required-pr-check-name.test.mjs index e79f26fc66b..c10552e8275 100644 --- a/config/scripts/ci/workflow-contracts/required-pr-check-name.test.mjs +++ b/config/scripts/ci/workflow-contracts/required-pr-check-name.test.mjs @@ -1,39 +1,7 @@ -import { readFileSync } from 'node:fs' import { expect, it } from 'vitest' import { parse } from 'yaml' -import { runProcessSync } from '@orca/process-host' import { verifyRequiredPrContext } from '../../../../.github/scripts/check-required-pr-context.mjs' -it('reserves the required PR context for the full aggregate with both YAML parsers', () => { - expect(() => verifyRequiredPrContext(parse)).not.toThrow() - const result = runProcessSync({ - program: 'bun', - args: ['.github/scripts/check-required-pr-context.mjs'], - env: { ...process.env, ORCA_BACKGROUND_LAUNCH: '1' }, - timeoutMs: 10_000 - }) - expect(result.code, result.stderr).toBe(0) -}) - -it('checks context names even when workflow-only changes skip root tests', () => { - const workflow = parse(readFileSync('.github/workflows/pr.yml', 'utf8')) - const job = workflow.jobs.code_paths - const step = job.steps.find( - (candidate) => candidate.run === 'bun .github/scripts/check-required-pr-context.mjs' - ) - expect(step).toBeDefined() - expect(step.if).toBeUndefined() - expect(step['continue-on-error']).toBeUndefined() - const checkout = job.steps.find((candidate) => candidate.uses?.startsWith('actions/checkout@')) - for (const path of [ - '/.github/workflows/', - '/.github/scripts/check-required-pr-context.mjs', - '/config/.bun-version' - ]) { - expect(checkout.with['sparse-checkout'].split('\n')).toContain(path) - } -}) - it('rejects aggregate conditions that hide a successful result', () => { for (const condition of [undefined, 'success()', 'always()', '!cancelled() && !(true)']) { const parseChanged = (source) => { diff --git a/config/scripts/ci/workflow-contracts/workflow-ref-mirror-case-safety.test.mjs b/config/scripts/ci/workflow-contracts/workflow-ref-mirror-case-safety.test.mjs deleted file mode 100644 index 0f1cbad0a55..00000000000 --- a/config/scripts/ci/workflow-contracts/workflow-ref-mirror-case-safety.test.mjs +++ /dev/null @@ -1,102 +0,0 @@ -import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs' -import { tmpdir } from 'node:os' -import { join, resolve } from 'node:path' -import { pathToFileURL } from 'node:url' -import { describe, expect, it } from 'vitest' -import { parse } from 'yaml' -import { runProcessSync } from '@orca/process-host' - -const projectDir = resolve(import.meta.dirname, '../../../..') - -const readWorkflow = (relativePath) => parse(readFileSync(join(projectDir, relativePath), 'utf8')) - -describe('ref-mirroring vet steps', () => { - it.each(['daily', 'hourly', 'adhoc'])('%s builds only need the current commit', (channel) => { - const { jobs } = readWorkflow(`.github/workflows/${channel}-mac-build.yml`) - const job = jobs[channel === 'adhoc' ? 'build-adhoc-mac-arch' : `build-${channel}-mac`] - const identity = channel === 'adhoc' ? jobs['orcad-template-support'] : job - const checkout = job.steps.find((step) => step.uses === 'actions/checkout@v6') - expect(checkout.with['fetch-depth']).toBe(1) - expect( - (channel === 'adhoc' ? jobs['build-adhoc-mac'] : job).steps.some((step) => - step.run?.includes('gh release list') - ) - ).toBe(true) - expect( - identity.steps.some((step) => step.run?.includes('ORCA_PUBLISHED_VERSIONS="$published"')) - ).toBe(true) - }) - - // Use matching refs, not releases: unpublished stable release still owns tag number and must not roll channel backward. - it.each(['daily', 'hourly', 'adhoc'])( - '%s versions from git tags, not main GitHub releases', - (channel) => { - const { jobs } = readWorkflow(`.github/workflows/${channel}-mac-build.yml`) - const identity = - channel === 'adhoc' - ? jobs['orcad-template-support'] - : jobs[channel === 'adhoc' ? 'build-adhoc-mac-arch' : `build-${channel}-mac`] - const step = identity.steps.find( - (candidate) => candidate.name === `Compute ${channel} version` - ) - expect(step.run).toContain('git/matching-refs/tags/v') - expect(step.run).not.toMatch( - /gh release list[\s\S]*--repo "\$GITHUB_REPOSITORY"[\s\S]*--json tagName/ - ) - if (channel !== 'adhoc') { - expect(step.run).toContain('channel_tags=') - } - } - ) - - it('retains release-cut history for version reservation and retry ancestry', () => { - const checkout = readWorkflow('.github/workflows/release-cut.yml').jobs.cut.steps.find( - (step) => step.uses === 'actions/checkout@v6' - ) - expect(checkout.with['fetch-depth']).toBe(0) - }) - - it('resolves identical dev identities in full and depth-one checkouts without local tags', () => { - const directory = mkdtempSync(join(tmpdir(), 'orca-checkout-identity-')) - const source = join(directory, 'source') - const shallow = join(directory, 'shallow') - const run = (program, args, cwd) => { - const result = runProcessSync({ program, args, cwd }) - expect(result.code, result.stderr).toBe(0) - return result.stdout.trim() - } - const git = (args, cwd = directory) => run('git', args, cwd) - try { - git(['init', source]) - git(['config', 'user.name', 'CI test'], source) - git(['config', 'user.email', 'ci@example.invalid'], source) - writeFileSync(join(source, 'package.json'), JSON.stringify({ version: '1.4.165-rc.0' })) - git(['add', 'package.json'], source) - git(['-c', 'commit.gpgsign=false', 'commit', '-m', 'initial'], source) - git(['tag', 'v1.4.167'], source) - git(['-c', 'commit.gpgsign=false', 'commit', '--allow-empty', '-m', 'head'], source) - git(['clone', '--depth=1', '--no-tags', pathToFileURL(source).href, shallow]) - expect(git(['rev-list', '--count', 'HEAD'], shallow)).toBe('1') - expect(git(['tag', '--list'], shallow)).toBe('') - const script = ` - const result = []; - for (const [channel, exported] of [['daily', 'Daily'], ['hourly', 'Hourly'], ['adhoc', 'Adhoc']]) { - const module = await import(${JSON.stringify(pathToFileURL(join(projectDir, 'config/scripts/release/versioning/')).href)} + channel + '-build-version.mjs'); - const date = new Date('2026-09-12T00:00:00Z'); - result.push(channel === 'adhoc' - ? module.getAdhocBuildIdentity(date, 'branch', ['v1.4.167']) - : module['get' + exported + 'BuildIdentity'](date, { publishedVersions: ['v1.4.167'], releaseNames: [] })); - } - process.stdout.write(JSON.stringify(result)); - ` - const identities = (cwd) => run(process.execPath, ['--input-type=module', '-e', script], cwd) - const shallowIdentities = identities(shallow) - expect(shallowIdentities).toBe(identities(source)) - expect( - JSON.parse(shallowIdentities).every((identity) => identity.version.startsWith('1.4.168-')) - ).toBe(true) - } finally { - rmSync(directory, { recursive: true, force: true }) - } - }) -}) diff --git a/config/scripts/ci/workflow-contracts/zcode-credential-workflow.test.mjs b/config/scripts/ci/workflow-contracts/zcode-credential-workflow.test.mjs deleted file mode 100644 index c0716a22d2b..00000000000 --- a/config/scripts/ci/workflow-contracts/zcode-credential-workflow.test.mjs +++ /dev/null @@ -1,244 +0,0 @@ -import { execFileSync } from 'node:child_process' -import { - chmodSync, - mkdirSync, - mkdtempSync, - readFileSync, - renameSync, - rmSync, - writeFileSync -} from 'node:fs' -import { tmpdir } from 'node:os' -import { delimiter, dirname, join } from 'node:path' -import { runInNewContext } from 'node:vm' -import { expect, it } from 'vitest' -import { parse } from 'yaml' - -const workflow = parse(readFileSync('.github/workflows/zcode-credential-contract.yml', 'utf8')) -const accountWorkflow = parse(readFileSync('.github/workflows/zcode-account-contract.yml', 'utf8')) -const job = workflow.jobs['credential-files'] -const scope = job.steps.find((step) => step.id === 'scope') -const account = job.steps.find( - (step) => step.name === 'Verify read-only credentials and account changes' -) -const credentials = job.steps.find( - (step) => step.name === 'Verify rollback and native Windows permissions' -) -const accountFiles = [ - 'src/main/zcode/zcode-v2-plan-credentials.test.ts', - 'src/main/zcode/zcode-v2-personal-overlay-raw-json.test.ts', - 'src/main/rate-limits/service-zcode-usage.test.ts', - 'src/shared/node-bounded-file-reader-sync.test.ts' -] -const credentialFiles = [ - 'src/main/zcode/zcode-plan-api-key-store.test.ts', - 'src/main/zcode/zcode-plan-api-key-store-plaintext-rollback.test.ts', - 'src/main/zcode/zcode-plan-api-key-store-publication-race.test.ts', - 'src/main/zcode/zcode-plan-api-key-store-native-windows.test.ts', - 'src/shared/secure-file.test.ts' -] - -it('shares one bootstrap across the original modules and operating systems', () => { - expect(job.strategy).toEqual({ - 'fail-fast': false, - matrix: { os: ['ubuntu-22.04', 'macos-15', 'windows-2022'] } - }) - expect(job.name).toBe('ZCode credentials (${{ matrix.os }})') - expect(account.run.split(/\s+/).slice(2)).toEqual(accountFiles) - expect(credentials.run.split(/\s+/).slice(2)).toEqual(credentialFiles) - expect( - job.steps.filter((step) => step.uses === './.github/actions/install-node-dependencies') - ).toHaveLength(1) - expect(job.steps.find((step) => step.id === 'dependencies').with['native-runtime']).toBe('node') - expect(job.env.ORCA_BACKGROUND_LAUNCH).toBe('1') - expect(job['timeout-minutes']).toBe(20) - expect(job.steps[0].with['fetch-depth']).toBe(2) - expect(workflow.on.pull_request.paths).toEqual([ - 'src/main/zcode/**', - 'src/shared/node-bounded-file-reader*', - 'src/main/rate-limits/**', - 'src/shared/secure-file*', - 'src/shared/secure-path-windows-acl*', - 'src/shared/windows-security-descriptor*', - '.github/workflows/zcode-account-contract.yml', - '.github/workflows/zcode-credential-contract.yml', - 'config/scripts/ci/workflow-contracts/zcode-credential-workflow.test.mjs' - ]) - expect(accountWorkflow.on).toEqual({ workflow_dispatch: null }) - expect(accountWorkflow.jobs['account-contract']).toEqual({ - uses: './.github/workflows/zcode-credential-contract.yml', - with: { contract: 'account' } - }) - expect(workflow.on.workflow_dispatch).toBeNull() - expect(workflow.on.workflow_call.inputs.contract.default).toBe('credentials') -}) - -it('runs the other selected contract after a sibling fails and retains prerequisite failures', () => { - for (const step of [account, credentials]) { - expect(step['continue-on-error']).toBeUndefined() - for (const [cancelled, installed, bun, selected, expected] of [ - [false, 'success', 'success', 'true', true], - [false, 'failure', 'success', 'true', false], - [false, 'success', 'failure', 'true', false], - [false, 'success', 'success', 'false', false], - [true, 'success', 'success', 'true', false] - ]) { - expect( - runInNewContext(step.if.slice(3, -2), { - cancelled: () => cancelled, - steps: { - scope: { outputs: { account: selected, credentials: selected } }, - dependencies: { outcome: installed }, - bun: { outcome: bun } - } - }) - ).toBe(expected) - } - } -}) - -function executeScope(directory, overrides = {}) { - const output = join(directory, 'github-output') - writeFileSync(output, '') - execFileSync('bash', ['-e', '-o', 'pipefail', '-c', scope.run], { - cwd: directory, - env: { - ...process.env, - ORCA_BACKGROUND_LAUNCH: '1', - EVENT_NAME: 'pull_request', - MANUAL_ACCOUNT: 'false', - MANUAL_CREDENTIALS: 'true', - GITHUB_OUTPUT: output, - ...overrides - } - }) - return Object.fromEntries( - readFileSync(output, 'utf8') - .trim() - .split('\n') - .map((line) => line.split('=')) - ) -} - -// The workflow owns Bash execution on Windows; this contract executes the same source on Unix. -it.skipIf(process.platform === 'win32')( - 'selects the original path groups, including deletions and renames', - () => { - const directory = mkdtempSync(join(tmpdir(), 'orca-zcode-workflow-')) - const git = (args) => execFileSync('git', args, { cwd: directory, stdio: 'pipe' }) - const write = (file, value) => { - mkdirSync(dirname(join(directory, file)), { recursive: true }) - writeFileSync(join(directory, file), value) - } - const commit = () => { - git(['add', '-A']) - git([ - '-c', - 'user.name=Fixture', - '-c', - 'user.email=fixture@example.test', - 'commit', - '--allow-empty', - '-qm', - 'fixture' - ]) - } - const cases = [ - ['src/main/zcode/credentials.ts', true, true], - ['src/main/zcode/nested/credentials.ts', true, true], - ['src/shared/node-bounded-file-reader-sync.test.ts', true, false], - ['src/main/rate-limits/service-zcode-usage.ts', true, false], - ['src/shared/secure-file.ts', false, true], - ['src/shared/secure-path-windows-acl.ts', false, true], - ['src/shared/windows-security-descriptor.ts', false, true], - ['.github/workflows/zcode-account-contract.yml', true, false], - ['.github/workflows/zcode-credential-contract.yml', true, true], - ['config/scripts/ci/workflow-contracts/zcode-credential-workflow.test.mjs', true, true], - ['docs/unrelated.md', false, false] - ] - try { - git(['init', '-q']) - write('README.md', 'fixture') - commit() - expect(executeScope(directory)).toEqual({ account: 'true', credentials: 'true' }) - for (const [file, runsAccount, runsCredentials] of cases) { - write(file, 'first') - commit() - expect(executeScope(directory), file).toEqual({ - account: String(runsAccount), - credentials: String(runsCredentials) - }) - rmSync(join(directory, file)) - commit() - expect(executeScope(directory), `deleted ${file}`).toEqual({ - account: String(runsAccount), - credentials: String(runsCredentials) - }) - } - write('src/main/zcode/credentials.ts', 'renamed') - commit() - renameSync(join(directory, 'src/main/zcode/credentials.ts'), join(directory, 'README.md')) - commit() - expect(executeScope(directory)).toEqual({ account: 'true', credentials: 'true' }) - write('src/main/rate-limits/service.ts', 'mixed') - write('src/shared/secure-file.ts', 'mixed') - commit() - expect(executeScope(directory)).toEqual({ account: 'true', credentials: 'true' }) - commit() - expect(executeScope(directory)).toEqual({ account: 'true', credentials: 'true' }) - } finally { - rmSync(directory, { recursive: true, force: true }) - } - } -) - -it.skipIf(process.platform === 'win32')( - 'keeps both manual entry points and missing diff evidence', - () => { - const directory = mkdtempSync(join(tmpdir(), 'orca-zcode-manual-')) - try { - expect(executeScope(directory)).toEqual({ account: 'true', credentials: 'true' }) - expect(executeScope(directory, { EVENT_NAME: 'workflow_dispatch' })).toEqual({ - account: 'false', - credentials: 'true' - }) - expect( - executeScope(directory, { - EVENT_NAME: 'workflow_dispatch', - MANUAL_ACCOUNT: 'true', - MANUAL_CREDENTIALS: 'false' - }) - ).toEqual({ account: 'true', credentials: 'false' }) - } finally { - rmSync(directory, { recursive: true, force: true }) - } - } -) - -it.skipIf(process.platform === 'win32')( - 'runs both groups when the full diff fails even if scoped diffs would report no changes', - () => { - const directory = mkdtempSync(join(tmpdir(), 'orca-zcode-diff-failure-')) - try { - const gitShim = join(directory, 'git') - writeFileSync( - gitShim, - '#!/bin/sh\nif [ "$1" = rev-parse ]; then exit 0; fi\nif [ "$#" = 5 ]; then exit "$FULL_DIFF_STATUS"; fi\nexit 0\n' - ) - chmodSync(gitShim, 0o755) - const env = { PATH: `${directory}${delimiter}${process.env.PATH}` } - expect(executeScope(directory, { ...env, FULL_DIFF_STATUS: '1' })).toEqual({ - account: 'false', - credentials: 'false' - }) - for (const status of ['2', '128']) { - expect(executeScope(directory, { ...env, FULL_DIFF_STATUS: status })).toEqual({ - account: 'true', - credentials: 'true' - }) - } - } finally { - rmSync(directory, { recursive: true, force: true }) - } - } -) diff --git a/config/scripts/cli-build/build-cli.test.mjs b/config/scripts/cli-build/build-cli.test.mjs deleted file mode 100644 index ad1bf894419..00000000000 --- a/config/scripts/cli-build/build-cli.test.mjs +++ /dev/null @@ -1,217 +0,0 @@ -import { - mkdirSync, - existsSync, - mkdtempSync, - readFileSync, - readdirSync, - rmSync, - symlinkSync, - writeFileSync -} from 'node:fs' -import { availableParallelism, tmpdir } from 'node:os' -import { join, resolve } from 'node:path' -import { runProcess, runProcessSync } from '@orca/process-host' -import { afterEach, expect, it, vi } from 'vitest' -import { buildCli } from './build-cli.mjs' -import { resolvePinnedBunExecutable } from '../tool-invocation/pinned-bun-executable.mjs' -import { resolveProjectCompiler } from '../typecheck/project-execution/run-typecheck-projects-in-parallel.mjs' -import { supportsTsrs } from '../typecheck/project-execution/tsrs-typecheck-compiler.mjs' - -const ROOT = process.cwd() -const resolveBunExecutable = () => resolvePinnedBunExecutable(ROOT, runProcessSync) -const directories = [] -afterEach(() => { - for (const directory of directories.splice(0)) { - rmSync(directory, { recursive: true, force: true }) - } -}) - -function fixture() { - const root = mkdtempSync(join(tmpdir(), 'orca-cli-build-')) - directories.push(root) - mkdirSync(join(root, 'config')) - mkdirSync(join(root, 'src')) - symlinkSync(resolve('node_modules'), join(root, 'node_modules'), 'junction') - writeFileSync(join(root, 'package.json'), '{"type":"commonjs"}') - writeFileSync(join(root, 'config', '.bun-version'), readFileSync('config/.bun-version')) - writeFileSync( - join(root, 'config', 'tsconfig.build.cli.json'), - JSON.stringify({ - compilerOptions: { - module: 'Node20', - moduleResolution: 'Node16', - target: 'ES2022', - strict: true, - types: [], - rootDir: '../src', - declaration: true, - declarationMap: true, - sourceMap: true - }, - include: ['../src/**/*.ts'] - }) - ) - writeFileSync(join(root, 'src', 'constants.ts'), 'export const enum Mode { Ready = 7 }\n') - writeFileSync( - join(root, 'src', 'entry.ts'), - `import { Mode } from './constants' -export interface Item { value: number } -export const item: Item = { value: Mode.Ready } -` - ) - return root -} - -it('checks the emit project first, retains all CPU cores and preserves the TypeScript emitter', async () => { - const order = [] - const check = vi.fn(async () => { - order.push('check') - return [] - }) - const execute = vi.fn(async () => { - order.push('emit') - return { code: 0 } - }) - await buildCli({ check, execute, resolveBunExecutable: () => 'pinned-bun' }) - expect(order).toEqual(['check', 'emit']) - expect(check).toHaveBeenCalledWith( - expect.objectContaining({ - compiler: 'bun', - bunExecutable: 'pinned-bun', - projects: [{ config: 'config/tsconfig.build.cli.json', heapGib: 2 }], - bunThreads: availableParallelism() - }) - ) - expect(execute).toHaveBeenCalledWith( - expect.objectContaining({ - program: process.execPath, - args: [ - resolveProjectCompiler('config/tsconfig.build.cli.json'), - '-p', - 'config/tsconfig.build.cli.json', - '--outDir', - 'out', - '--composite', - 'false', - '--incremental', - 'false', - '--noCheck' - ] - }) - ) -}) - -it('does not emit when checking fails or the pinned Bun is missing', async () => { - const execute = vi.fn() - await expect( - buildCli({ - check: async () => [new Error('type error')], - execute, - resolveBunExecutable: () => 'pinned-bun' - }) - ).rejects.toThrow('type error') - await expect(buildCli({ execute, resolveBunExecutable: () => null })).rejects.toThrow( - 'run pnpm install' - ) - expect(execute).not.toHaveBeenCalled() -}) - -it('propagates emitter failures', async () => { - await expect( - buildCli({ - check: async () => [], - resolveBunExecutable: () => 'pinned-bun', - execute: async () => ({ code: null, signal: 'SIGKILL' }) - }) - ).rejects.toThrow('signal=SIGKILL') -}) - -it('rejects unknown compiler selections before emission', async () => { - const execute = vi.fn() - await expect(buildCli({ compiler: 'unknown', execute })).rejects.toThrow( - 'Invalid ORCA_CLI_BUILD_COMPILER' - ) - expect(execute).not.toHaveBeenCalled() -}) - -it('produces byte-identical JavaScript, declarations and maps with the real compilers', async () => { - const root = fixture() - const baseline = await runProcess({ - program: process.execPath, - args: [ - resolveProjectCompiler('config/tsconfig.build.cli.json', root), - '-p', - 'config/tsconfig.build.cli.json', - '--outDir', - 'baseline', - '--composite', - 'false', - '--incremental', - 'false' - ], - cwd: root - }) - expect(baseline.code, baseline.stdout + baseline.stderr).toBe(0) - await buildCli({ root, outDir: 'optimized', resolveBunExecutable }) - const files = readdirSync(join(root, 'baseline')).sort() - expect(readdirSync(join(root, 'optimized')).sort()).toEqual(files) - expect(files).toHaveLength(8) - for (const file of files) { - expect( - readFileSync(join(root, 'optimized', file)).equals( - readFileSync(join(root, 'baseline', file)) - ), - file - ).toBe(true) - } -}) - -it('blocks output for real type errors and rejects compiler version drift', async () => { - const root = fixture() - writeFileSync(join(root, 'src', 'entry.ts'), 'export const value: number = "wrong"\n') - const execute = vi.fn() - await expect(buildCli({ root, execute, resolveBunExecutable })).rejects.toThrow( - 'exited with code 1' - ) - expect(execute).not.toHaveBeenCalled() - - const drift = fixture() - rmSync(join(drift, 'node_modules')) - mkdirSync(join(drift, 'node_modules', 'typescript'), { recursive: true }) - writeFileSync( - join(drift, 'node_modules', 'typescript', 'package.json'), - JSON.stringify({ - name: 'typescript', - version: '99.0.0', - bin: { tsc: 'compiler.cjs' } - }) - ) - await expect(buildCli({ root: drift, execute, resolveBunExecutable })).rejects.toThrow( - 'resolves 99.0.0' - ) - expect(execute).not.toHaveBeenCalled() -}) - -it.skipIf(!supportsTsrs())( - 'the optional compiler preserves emitted bytes and blocks output on type errors', - async () => { - const root = fixture() - await buildCli({ root, outDir: 'baseline', compiler: 'bun', resolveBunExecutable }) - await buildCli({ root, outDir: 'optimized', compiler: 'tsrs' }) - const files = readdirSync(join(root, 'baseline')).sort() - expect(readdirSync(join(root, 'optimized')).sort()).toEqual(files) - for (const file of files) { - expect( - readFileSync(join(root, 'optimized', file)).equals( - readFileSync(join(root, 'baseline', file)) - ), - file - ).toBe(true) - } - writeFileSync(join(root, 'src', 'entry.ts'), 'export const value: number = "wrong"\n') - await expect(buildCli({ root, outDir: 'failed', compiler: 'tsrs' })).rejects.toThrow( - 'CLI compilation failed' - ) - expect(existsSync(join(root, 'failed'))).toBe(false) - } -) diff --git a/config/scripts/daemon-protocol/admission/check-daemon-protocol-crossing.test.mjs b/config/scripts/daemon-protocol/admission/check-daemon-protocol-crossing.test.mjs index 2a22ab3630e..138158702d7 100644 --- a/config/scripts/daemon-protocol/admission/check-daemon-protocol-crossing.test.mjs +++ b/config/scripts/daemon-protocol/admission/check-daemon-protocol-crossing.test.mjs @@ -77,14 +77,6 @@ describe('selectLatestStableReleaseTag', () => { expect(selectLatestStableReleaseTag(['v0.0.0'])).toBe('v0.0.0') } ) - - it('skips unfilled entries in a sparse tag list', () => { - const sparse = [] - sparse.length = 12 - sparse[3] = 'v1.2.3' - sparse[8] = 'v2.0.0' - expect(selectLatestStableReleaseTag(Object.freeze(sparse))).toBe('v2.0.0') - }) }) describe('checkDaemonProtocolCrossing', () => { @@ -103,17 +95,6 @@ describe('checkDaemonProtocolCrossing', () => { const env = {} - it('passes a bump that lists the newest release version, reporting rollback as info', () => { - const repo = repoWithTags([ - ['v1.0.9', 5], - ['v1.0.10', 6] - ]) - writeProtocol(repo, 7) - const result = checkDaemonProtocolCrossing({ repoRoot: repo, env }) - expect(result).toMatchObject({ upgrade: true, rollback: false }) - expect(result.lines[0]).toBe('release v1.0.10: daemon protocol 6') - }) - it('fails when the working tree drops the newest release version', () => { const repo = repoWithTags([['v1.0.0', 6]]) writeFileSync( diff --git a/config/scripts/daemon-protocol/admission/check-runtime-launcher-protocol-ratchet.test.mjs b/config/scripts/daemon-protocol/admission/check-runtime-launcher-protocol-ratchet.test.mjs index aab46843b42..04f4ab63b67 100644 --- a/config/scripts/daemon-protocol/admission/check-runtime-launcher-protocol-ratchet.test.mjs +++ b/config/scripts/daemon-protocol/admission/check-runtime-launcher-protocol-ratchet.test.mjs @@ -1,19 +1,13 @@ import { execFileSync } from 'node:child_process' -import { existsSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs' +import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs' import { tmpdir } from 'node:os' -import { dirname, join, resolve } from 'node:path' +import { dirname, join } from 'node:path' import { afterEach, describe, expect, it } from 'vitest' import { - RUNTIME_LAUNCHER_PATHS, RUNTIME_PROTOCOL_OVERRIDE_ENV, - assessRuntimeLauncherProtocolRatchet, - checkRuntimeLauncherProtocolRatchet, - isOverrideEnabled + checkRuntimeLauncherProtocolRatchet } from './check-runtime-launcher-protocol-ratchet.mjs' import { DAEMON_PROTOCOL_SOURCE_PATH } from '../schema-facts/daemon-protocol-facts.mjs' -import { classifyPrJobs } from '../../workflow/source-routing/pr-code-change-scope.mjs' - -const repoRoot = resolve(import.meta.dirname, '../../..', '..') const repos = [] const LAUNCHER = 'src/main/managed-server/install/orcad-remote-runtime.ts' @@ -76,74 +70,6 @@ afterEach(() => { } }) -describe('RUNTIME_LAUNCHER_PATHS', () => { - it('names only files that exist, so a rename cannot silently drop one from the gate', () => { - expect(RUNTIME_LAUNCHER_PATHS).toContain(LAUNCHER) - expect(RUNTIME_LAUNCHER_PATHS.filter((path) => !existsSync(join(repoRoot, path)))).toEqual([]) - }) -}) - -describe('PR routing', () => { - it('runs the ratchet job when its checker or the protocol changes', () => { - for (const file of [ - 'config/scripts/daemon-protocol/admission/check-runtime-launcher-protocol-ratchet.mjs', - DAEMON_PROTOCOL_SOURCE_PATH - ]) { - expect(classifyPrJobs([file])['cross-version-wire']).toBe(true) - } - }) -}) - -describe('assessRuntimeLauncherProtocolRatchet', () => { - const launcherAndBump = { - changedFiles: [LAUNCHER, DAEMON_PROTOCOL_SOURCE_PATH], - baseProtocolVersion: 3, - candidateProtocolVersion: 4 - } - - it('fails a launcher change that also bumps the protocol', () => { - expect( - assessRuntimeLauncherProtocolRatchet({ ...launcherAndBump, overridden: false }) - ).toMatchObject({ - ok: false, - violated: true - }) - }) - - it('lets an explicit override through while still reporting the violation', () => { - const result = assessRuntimeLauncherProtocolRatchet({ ...launcherAndBump, overridden: true }) - expect(result).toMatchObject({ ok: true, violated: true }) - expect(result.lines.at(-1)).toContain('OVERRIDDEN') - }) - - it('passes a protocol bump without a launcher change, and a launcher change without a bump', () => { - expect( - assessRuntimeLauncherProtocolRatchet({ - ...launcherAndBump, - changedFiles: [DAEMON_PROTOCOL_SOURCE_PATH], - overridden: false - }).ok - ).toBe(true) - expect( - assessRuntimeLauncherProtocolRatchet({ - ...launcherAndBump, - candidateProtocolVersion: 3, - overridden: false - }).ok - ).toBe(true) - }) -}) - -describe('isOverrideEnabled', () => { - it('accepts only an explicit true', () => { - expect(isOverrideEnabled({ [RUNTIME_PROTOCOL_OVERRIDE_ENV]: 'true' })).toBe(true) - expect(isOverrideEnabled({ [RUNTIME_PROTOCOL_OVERRIDE_ENV]: '1' })).toBe(true) - expect(isOverrideEnabled({ [RUNTIME_PROTOCOL_OVERRIDE_ENV]: 'false' })).toBe(false) - expect(isOverrideEnabled({ [RUNTIME_PROTOCOL_OVERRIDE_ENV]: '' })).toBe(false) - expect(isOverrideEnabled({})).toBe(false) - }) -}) - describe('checkRuntimeLauncherProtocolRatchet against git history', () => { it('enforces the restriction when the base predates the protocol source move', () => { const { repo, base } = repoWithCandidate((candidate) => { diff --git a/config/scripts/daemon-protocol/schema-facts/daemon-protocol-facts.test.mjs b/config/scripts/daemon-protocol/schema-facts/daemon-protocol-facts.test.mjs index a3ed6f33cfa..0b70f1091f8 100644 --- a/config/scripts/daemon-protocol/schema-facts/daemon-protocol-facts.test.mjs +++ b/config/scripts/daemon-protocol/schema-facts/daemon-protocol-facts.test.mjs @@ -1,14 +1,5 @@ -import { readFileSync } from 'node:fs' -import { join, resolve } from 'node:path' import { describe, expect, it } from 'vitest' -import { - DAEMON_PROTOCOL_SOURCE_PATH, - canAttach, - crossingRequirements, - parseDaemonProtocolFacts -} from './daemon-protocol-facts.mjs' - -const projectDir = resolve(import.meta.dirname, '../../../..') +import { parseDaemonProtocolFacts } from './daemon-protocol-facts.mjs' function source(current, previous) { return [ @@ -24,16 +15,6 @@ const facts = (protocolVersion, previousProtocolVersions) => ({ }) describe('parseDaemonProtocolFacts', () => { - it('reads the working tree declarations and keeps the append-only range', () => { - const parsed = parseDaemonProtocolFacts( - readFileSync(join(projectDir, DAEMON_PROTOCOL_SOURCE_PATH), 'utf8') - ) - expect(parsed.protocolVersion).toBeGreaterThan(1) - expect(parsed.previousProtocolVersions).toEqual( - Array.from({ length: parsed.protocolVersion - 1 }, (_, index) => index + 1) - ) - }) - it('parses multi-line lists and type annotations', () => { const text = [ '// PROTOCOL_VERSION = 99 in a comment is ignored', @@ -63,28 +44,3 @@ describe('parseDaemonProtocolFacts', () => { expect(() => parseDaemonProtocolFacts(text, 'fixture.ts')).toThrow(/fixture\.ts/) }) }) - -describe('protocol crossing', () => { - const release = facts(37, [36, 35]) - - it('lets a same-version or listing candidate adopt the release daemon', () => { - expect(canAttach(facts(37, [36, 35]), release)).toBe(true) - expect(canAttach(facts(38, [37, 36, 35]), release)).toBe(true) - }) - - it('rejects a candidate that dropped the release version', () => { - expect(canAttach(facts(38, [36, 35]), release)).toBe(false) - }) - - it('cannot roll back past a protocol bump', () => { - expect(canAttach(release, facts(38, [37, 36, 35]))).toBe(false) - expect(canAttach(release, facts(36, [35]))).toBe(true) - }) - - it('describes the requirements in both directions', () => { - expect(crossingRequirements(release)).toMatchObject({ - upgrade: 'candidate speaks 37 or lists 37 as previous', - rollback: expect.stringContaining('35..37') - }) - }) -}) diff --git a/config/scripts/dependency-security/audit-tools/patched-dependencies-frozen-install.test.mjs b/config/scripts/dependency-security/audit-tools/patched-dependencies-frozen-install.test.mjs deleted file mode 100644 index 89b75cdb0b2..00000000000 --- a/config/scripts/dependency-security/audit-tools/patched-dependencies-frozen-install.test.mjs +++ /dev/null @@ -1,136 +0,0 @@ -import { - cpSync, - copyFileSync, - existsSync, - mkdirSync, - mkdtempSync, - readFileSync, - writeFileSync -} from 'node:fs' -import { tmpdir } from 'node:os' -import { isAbsolute, join, parse, resolve } from 'node:path' -import { describe, expect, it } from 'vitest' -import { runProcessSync } from '@orca/process-host' -import { resolveCliCommand } from '../../../../src/shared/node-cli-command-resolution.ts' -import { removeTreeSync } from '../../../../src/shared/windows-transient-lock-removal.ts' -import { resolvePnpmCliInvocation } from '../../tool-invocation/pnpm-cli-invocation.mjs' -import { workspacePackageManifests } from '../../workspace/source-exports/workspace-source-exports.mjs' - -// Run actual pnpm: it hashes LF-normalized patch content; repeated raw SHA checks agreed with a bad CRLF lockfile and missed frozen-install failures. -// lockfile-only/ignore-scripts checks resolution without node_modules or native builds; patch application is tested separately below. -const PROJECT_DIR = resolve(import.meta.dirname, '../../../..') -const WINDOWS_PROCESS_TREE_PATCH = '@vscode__windows-process-tree@0.8.0.patch' - -// Use pnpm-cli-invocation’s Windows shim resolver; omit shell because runProcessSync rejects it and handles interpreter routing itself. -function resolvePnpmInvocation() { - const { command, prefixArgs } = resolvePnpmCliInvocation() - if (isAbsolute(command)) { - return existsSync(command) ? { program: command, prefixArgs } : null - } - // Without npm_execpath, use bare extensionless name so shared resolver can try every executable form. - const resolved = resolveCliCommand(parse(command).name) - return isAbsolute(resolved) ? { program: resolved, prefixArgs } : null -} - -describe('patched dependencies', () => { - it('installs with --frozen-lockfile, which is what validates every patch hash', () => { - const pnpm = resolvePnpmInvocation() - expect(pnpm, 'pnpm must be installed; it is the only thing that can check this').not.toBeNull() - - // Use a copy: even frozen-lockfile rewrites untracked lockfile sections; preserve repository bytes. - const scratch = mkdtempSync(join(tmpdir(), 'orca-frozen-install-')) - try { - for (const file of [ - 'package.json', - 'pnpm-lock.yaml', - 'pnpm-workspace.yaml', - // The lockfile pins its checksum, so a frozen install fails without it. - 'config/pnpmfile.cjs', - ...workspacePackageManifests(PROJECT_DIR) - ]) { - mkdirSync(resolve(scratch, file, '..'), { recursive: true }) - copyFileSync(join(PROJECT_DIR, file), join(scratch, file)) - } - mkdirSync(join(scratch, 'config'), { recursive: true }) - cpSync(join(PROJECT_DIR, 'config', 'patches'), join(scratch, 'config', 'patches'), { - recursive: true - }) - - const result = runProcessSync({ - program: pnpm.program, - args: [ - ...pnpm.prefixArgs, - 'install', - '--frozen-lockfile', - '--lockfile-only', - '--ignore-scripts' - ], - cwd: scratch, - timeoutMs: 300_000 - }) - - expect(result.code, `${result.stdout}\n${result.stderr}`).toBe(0) - } finally { - removeTreeSync(scratch) - } - // Allow the full 300s spawn budget beyond Vitest’s 30s case default. - }, 300_000) - - // lockfile-only never applies patches; install one real dependency and check its marker to cover application without a full install. - it('materializes the patched command-line reader on a real install', () => { - const pnpm = resolvePnpmInvocation() - expect(pnpm, 'pnpm must be installed; it is the only thing that can check this').not.toBeNull() - - const scratch = mkdtempSync(join(tmpdir(), 'orca-patch-apply-')) - try { - mkdirSync(join(scratch, 'config', 'patches'), { recursive: true }) - copyFileSync( - join(PROJECT_DIR, 'config', 'patches', WINDOWS_PROCESS_TREE_PATCH), - join(scratch, 'config', 'patches', WINDOWS_PROCESS_TREE_PATCH) - ) - writeFileSync( - join(scratch, 'package.json'), - `${JSON.stringify( - { - name: 'orca-patch-apply-probe', - version: '1.0.0', - dependencies: { '@vscode/windows-process-tree': '0.8.0' } - }, - null, - 2 - )}\n` - ) - writeFileSync( - join(scratch, 'pnpm-workspace.yaml'), - 'packages: []\n' + - 'patchedDependencies:\n' + - ` '@vscode/windows-process-tree@0.8.0': config/patches/${WINDOWS_PROCESS_TREE_PATCH}\n` - ) - - const result = runProcessSync({ - program: pnpm.program, - args: [...pnpm.prefixArgs, 'install', '--no-frozen-lockfile', '--ignore-scripts'], - cwd: scratch, - timeoutMs: 300_000 - }) - expect(result.code, `${result.stdout}\n${result.stderr}`).toBe(0) - - const materialized = readFileSync( - join( - scratch, - 'node_modules', - '@vscode', - 'windows-process-tree', - 'src', - 'process_commandline.cc' - ), - 'utf8' - ) - expect(materialized).toContain('kProcessCommandLineInformation') - // Require upstream reader removal, not merely a supplementary patched reader. - expect(materialized).not.toContain('ReadProcessMemory') - } finally { - removeTreeSync(scratch) - } - }, 300_000) -})