import { spawnSync } from 'node:child_process' import { readFileSync } from 'node:fs' import { resolve } from 'node:path' import { runInNewContext } from 'node:vm' import * as yaml from 'js-yaml' import { describe, expect, it } from 'vitest' const root = resolve(import.meta.dirname, '..') const workflow = yaml.load(readFileSync(resolve(root, '.github/workflows/build-exe-for-python-sdk.yml'), 'utf8')) as { jobs: Record }> }> } const build = workflow.jobs.build! const selector = build['runs-on'].slice(3, -2).trim() const windows = ['self-hosted', 'dsh-win-ci', 'windows', 'x64'] function context() { return { inputs: { ci: true, release: false }, github: { repository: 'deepseek-harness/deepseek-harness', event_name: 'pull_request', ref: 'refs/pull/42/merge', event: { pull_request: { head: { repo: { full_name: 'deepseek-harness/deepseek-harness', fork: false } }, user: { login: 'contributor' }, } }, }, matrix: { target: 'node24-win-x64', runner: 'windows-2025' }, vars: { DSH_CI_FAILOVER_WINDOWS: 'selfhosted' }, fromJSON: JSON.parse, } } function route(value: ReturnType, expression = selector): unknown { // The workflow uses only comparisons, booleans and fromJSON; execute that exact expression. return runInNewContext(expression, value, { timeout: 1000 }) } describe('Python runtime self-hosted routing', () => { it('routes same-repository member PRs and master CI to native x64 Windows', () => { expect(route(context())).toEqual(windows) const master = context() master.github.event_name = 'push' master.github.ref = 'refs/heads/master' expect(route(master)).toEqual(windows) }) it.each([ ['release caller', (value: ReturnType) => { value.inputs.release = true }], ['non-CI caller', (value: ReturnType) => { value.inputs.ci = false }], ['manual dispatch', (value: ReturnType) => { value.github.event_name = 'workflow_dispatch' }], ['pull_request_target', (value: ReturnType) => { value.github.event_name = 'pull_request_target' }], ['unknown event', (value: ReturnType) => { value.github.event_name = '' }], ['fork', (value: ReturnType) => { value.github.event.pull_request.head.repo.fork = true }], ['different repository head', (value: ReturnType) => { value.github.event.pull_request.head.repo.full_name = 'someone/fork' }], ['different caller repository', (value: ReturnType) => { value.github.repository = 'someone/fork' }], ['Dependabot author', (value: ReturnType) => { value.github.event.pull_request.user.login = 'dependabot[bot]' }], ['disabled failover', (value: ReturnType) => { value.vars.DSH_CI_FAILOVER_WINDOWS = '' }], ['unknown failover value', (value: ReturnType) => { value.vars.DSH_CI_FAILOVER_WINDOWS = 'hosted' }], ['branch push', (value: ReturnType) => { value.github.event_name = 'push'; value.github.ref = 'refs/heads/topic' }], ['tag push', (value: ReturnType) => { value.github.event_name = 'push'; value.github.ref = 'refs/tags/python-v1' }], ] as const)('keeps %s on the hosted fallback', (_name, change) => { const value = context() change(value) expect(route(value)).toBe('windows-2025') }) it.each([ ['node24-linux-x64', 'ubuntu-latest'], ['node24-linux-arm64', 'ubuntu-24.04-arm'], ['node24-macos-arm64', 'macos-latest'], ['node24-macos-x64', 'macos-15-intel'], ])('keeps %s hosted even with failover enabled', (target, runner) => { const value = context() value.matrix = { target, runner } expect(route(value)).toBe(runner) }) it('keeps setup helper jobs on hosted images', () => { expect(workflow.jobs.plan!['runs-on']).toBe('ubuntu-latest') expect(workflow.jobs['sdk-wheel']!['runs-on']).toBe('ubuntu-latest') }) it('isolates setup before pnpm and excludes shared installers and cache archives', () => { const privateSetup = build.steps.findIndex(step => step.id === 'private-windows') expect(privateSetup).toBeGreaterThan(0) expect(privateSetup).toBeLessThan(build.steps.findIndex(step => step.uses?.startsWith('pnpm/action-setup@'))) for (const step of build.steps.filter(step => step.uses?.startsWith('actions/setup-python@') || step.uses?.startsWith('actions/cache@') || step.name === 'Install Python build tooling')) { expect(step.if).toBe("runner.environment != 'self-hosted'") } expect(build.steps.find(step => step.name?.startsWith('Enable Windows'))?.if).toBe("runner.os == 'Windows' && runner.environment != 'self-hosted'") expect(build.steps.find(step => step.uses?.startsWith('actions/setup-node@'))?.with?.cache).toContain("runner.environment != 'self-hosted'") expect(build.steps.at(-1)).toMatchObject({ if: "always() && steps.private-windows.outputs.root != ''", shell: 'pwsh' }) const cleanup = build.steps.at(-1)!.run! expect(cleanup).toContain('"NODE_COMPILE_CACHE=" >> $env:GITHUB_ENV') expect(cleanup).toContain('"TMP=$env:RUNNER_TEMP" >> $env:GITHUB_ENV') expect(cleanup).toContain('"TEMP=$env:RUNNER_TEMP" >> $env:GITHUB_ENV') expect(cleanup).toContain('maxRetries: 10, retryDelay: 100') }) it('reads UTF-8 Session JSONL independently of the host locale', () => { const setup = readFileSync(resolve(root, 'scripts/setup-python-runtime-windows.ps1'), 'utf8') const utf8 = /PYTHONUTF8 = '([^']+)'/.exec(setup)?.[1] expect(utf8).toBe('1') const result = spawnSync(process.platform === 'win32' ? 'python' : 'python3', ['-c', [ 'import pathlib, tempfile, sys', 'assert sys.flags.utf8_mode == 1', 'with tempfile.TemporaryDirectory(prefix="python-runtime-encoding-") as root:', ' log = pathlib.Path(root) / "session.jsonl"', ' text = chr(0x2014) + chr(0x4e2d)', ' log.write_bytes(text.encode("utf-8"))', ' assert log.read_text() == text', ].join('\n')], { env: { ...process.env, LC_ALL: 'C', LANG: 'C', PYTHONCOERCECLOCALE: '0', PYTHONUTF8: utf8 }, encoding: 'utf8', timeout: 10000, }) expect(result.error).toBeUndefined() expect(result.signal).toBeNull() expect(result.status, result.stderr).toBe(0) }) it('pins portable Python without registry or shared cache writes', () => { const setup = readFileSync(resolve(root, 'scripts/setup-python-runtime-windows.ps1'), 'utf8') expect(setup).toContain('--no-bin --no-registry 3.10') expect(setup).toContain('--managed-python --no-python-downloads --seed') expect(setup).toContain('UV_PYTHON_INSTALL_REGISTRY') expect(setup).toContain('PNPM_CONFIG_STORE_DIR') expect(setup).toContain('PKG_CACHE_PATH') expect(setup).not.toMatch(/reg add|Set-ItemProperty|InstallAllUsers/) }) })