Files
orca/config/scripts/qualified-orcad-template.test.mjs
T
OrcaWinandOrcaWin 61ad1ba166 ci: move routine checks and unsigned builds to Blacksmith (#32913)
* ci: move routine checks and unsigned builds to Blacksmith

* ci: retain GitHub Mac images for isolated SSH fixtures

* ci: keep shared terminal perf preparation on Blacksmith

* test: allow encrypted slow-link fixture to finish on ARM CI

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-23 13:29:01 -07:00

157 lines
5.9 KiB
JavaScript

import {
existsSync,
mkdtempSync,
mkdirSync,
readFileSync,
rmSync,
symlinkSync,
writeFileSync
} from 'node:fs'
import { tmpdir } from 'node:os'
import { join, resolve } from 'node:path'
import { expect, it } from 'vitest'
import { parse } from 'yaml'
import { runProcessSync } from '@orca/process-host'
import { writeOrcadTemplateTestFixture } from './orcad-template-test-fixture.mjs'
const workflow = parse(readFileSync('.github/workflows/qualified-orcad-template.yml', 'utf8'))
const identity = workflow.jobs.cache.steps.find((step) => step.id === 'identity')
it('separates runner provenance, embedded CLI commits, workflow policy and daily requalification', () => {
const root = mkdtempSync(join(tmpdir(), 'qualified-template-key-'))
const policy = join(root, '.build', 'workflow-policy')
const output = join(root, 'output')
function run(program, args, cwd = root, env = {}) {
const result = runProcessSync({ program, args, cwd, env: { ...process.env, ...env } })
expect(result.code, result.stderr).toBe(0)
return result.stdout.trim()
}
function commit(cwd, message) {
run(
'git',
[
'-c',
'user.name=Template test',
'-c',
'user.email=template@example.invalid',
'commit',
'--allow-empty',
'-m',
message
],
cwd
)
}
function key(day = '20261021', profile = 'github-hosted') {
run('bash', ['-c', `date() { printf '%s' "$TEST_DATE"; }; ${identity.run}`], root, {
GITHUB_OUTPUT: output,
TEST_DATE: day,
RUNNER_PROFILE: profile
})
return readFileSync(output, 'utf8').trim().split('\n').at(-1)
}
try {
run('git', ['init', '-q'])
commit(root, 'first source commit')
mkdirSync(join(policy, '.github'), { recursive: true })
run('git', ['init', '-q'], policy)
writeFileSync(join(policy, '.github', 'policy'), 'first')
run('git', ['add', '.github'], policy)
commit(policy, 'first workflow policy')
const originalTree = run('git', ['rev-parse', 'HEAD^{tree}'])
const initial = key()
expect(key()).toBe(initial)
expect(initial).toContain('-github-hosted-')
expect(key('20261021', 'fast')).not.toBe(initial)
commit(root, 'same tree with a different embedded CLI commit')
expect(run('git', ['rev-parse', 'HEAD^{tree}'])).toBe(originalTree)
const nextCommit = key()
expect(nextCommit).not.toBe(initial)
writeFileSync(join(policy, '.github', 'policy'), 'changed')
run('git', ['add', '.github'], policy)
commit(policy, 'changed workflow policy')
const nextPolicy = key()
expect(nextPolicy).not.toBe(nextCommit)
expect(key('20261022')).not.toBe(nextPolicy)
} finally {
rmSync(root, { recursive: true, force: true })
}
})
it('qualifies cache misses and permits cache publication only after the full matrix succeeds', () => {
expect(workflow.jobs.qualify.if).toBe("needs.cache.outputs.hit != 'true'")
expect(workflow.jobs.qualify.uses).toBe('./.github/workflows/node-server-tests.yml')
expect(workflow.jobs.qualify.with).toMatchObject({
build_template: true,
fast_runners: '${{ inputs.fast_runners }}'
})
expect(workflow.jobs.save.needs).toContain('qualify')
expect(workflow.jobs.save.if).toBe("needs.qualify.result == 'success'")
const restore = workflow.jobs.cache.steps.find((step) => step.id === 'restore')
expect(restore.with['restore-keys']).toBeUndefined()
const validate = workflow.jobs.cache.steps.find((step) => step.id === 'validate')
expect(validate.run).toContain('verifyPackagedOrcadTemplate')
expect(validate.run).toContain('assertNotDarkBuild')
})
it('keeps SignPath on GitHub runners and isolates Blacksmith qualification caches', () => {
const release = parse(readFileSync('.github/workflows/release-cut.yml', 'utf8'))
const adhoc = parse(readFileSync('.github/workflows/adhoc-mac-build.yml', 'utf8'))
expect(workflow.on.workflow_call.inputs.fast_runners.default).toBe(true)
expect(release.jobs['orcad-template'].uses).toBe(
'./.github/workflows/qualified-orcad-template.yml'
)
expect(release.jobs['orcad-template'].with).toEqual({
ref: 'refs/tags/${{ needs.cut.outputs.tag }}',
fast_runners: false
})
expect(adhoc.jobs['orcad-template'].with.fast_runners).toBe(true)
expect(identity.env.RUNNER_PROFILE).toBe(
"${{ inputs.fast_runners && 'fast' || 'github-hosted' }}"
)
for (const name of ['cache', 'save']) {
expect(workflow.jobs[name]['runs-on']).toBe(
"${{ inputs.fast_runners && 'blacksmith-2vcpu-ubuntu-2404' || 'ubuntu-latest' }}"
)
}
})
it.each(['valid', 'corrupt', 'dark'])(
'validates restored bytes and requalifies an unsafe template: %s',
async (kind) => {
const root = mkdtempSync(join(tmpdir(), 'qualified-template-restore-'))
const output = join(root, 'output')
try {
symlinkSync(
resolve('config'),
join(root, 'config'),
process.platform === 'win32' ? 'junction' : 'dir'
)
const template = await writeOrcadTemplateTestFixture(join(root, 'out'))
if (kind === 'corrupt') {
writeFileSync(join(template, 'out/mobile-web/index.html'), 'mutated')
} else if (kind === 'dark') {
writeFileSync(join(template, 'ORCA_LAYOUT_OWNER_MAIN'), 'dark build')
}
const validate = workflow.jobs.cache.steps.find((step) => step.id === 'validate')
const result = runProcessSync({
program: 'bash',
args: ['-e', '-c', validate.run],
cwd: root,
env: { ...process.env, GITHUB_OUTPUT: output }
})
expect(result.code, result.stderr).toBe(0)
if (kind === 'valid') {
expect(readFileSync(output, 'utf8').trim()).toBe('valid=true')
expect(existsSync(template)).toBe(true)
} else {
expect(existsSync(output)).toBe(false)
expect(existsSync(template)).toBe(false)
expect(result.stdout).toContain('qualifying a fresh build')
}
} finally {
rmSync(root, { recursive: true, force: true })
}
}
)