mirror of
https://github.com/stablyai/orca.git
synced 2026-10-04 08:02:09 +00:00
* fix(ssh): launch the Windows relay outside sshd's job without WMI Win32-OpenSSH kills a session's job on close but allows breakaway. relay.js gains a one-shot launcher mode that starts the detached relay with CREATE_BREAKAWAY_FROM_JOB through the staged process-tree addon, so a standard user no longer needs a WMI Remote Enable grant. WMI stays as the fallback for a relay without the addon, and a refusal there is named. The Windows SSH-host lanes drop their WMI grant and assert the breakaway route and adoption. * fix(ssh): find runtime holds without WMI on a standard-user Windows host The store GC read held runtimes through Get-CimInstance Win32_Process, which WMI refuses to a standard user's SSH logon, so the pass kept every runtime. On a refusal it now reads this account's own process image paths through Get-Process. * build(relay): ship the Windows relay launcher addon in every desktop package macOS and Linux packages carried Windows relays without windows-process-tree.node, so a legacy-runtime relay they uploaded to a Windows SSH host could not launch outside sshd's job and fell back to WMI, which a standard user is refused. A reusable Windows job now compiles the x64 and arm64 addons once and uploads them; release-cut, release-mac-build, and the hourly/daily/adhoc mac builds download them before build:release and require both arches. Staging now rejects a binary with the wrong PE machine, the ReadProcessMemory import, or no spawnOutsideJob export, so a stale pre-launcher build cannot ship. * ci(ssh): run the Windows SSH-host lanes when the relay process-tree build scripts change The staging and gyp-rebuild scripts decide which windows-process-tree addon the relay ships, so a change to either must re-prove the Windows host cells. * test(ci): find the mac orcad-template download by artifact name The release mac job now also downloads the relay Windows process-tree addons, so the first download-artifact step is no longer the template's. --------- Co-authored-by: m4air <m4air@m4airs-Air.localdomain>
92 lines
3.4 KiB
JavaScript
92 lines
3.4 KiB
JavaScript
import { mkdtempSync, readFileSync, rmSync } from 'node:fs'
|
|
import { tmpdir } from 'node:os'
|
|
import { join } from 'node:path'
|
|
import { describe, expect, it } from 'vitest'
|
|
import { parse } from 'yaml'
|
|
import { runProcess } from '../../src/shared/child-process/run-process'
|
|
|
|
const workflow = parse(
|
|
readFileSync(new URL('../../.github/workflows/hourly-mac-build.yml', import.meta.url), 'utf8')
|
|
)
|
|
const preflight = workflow.jobs.preflight
|
|
const freshness = preflight.steps.find((step) => step.id === 'freshness')
|
|
const head = 'abcdef0123'.repeat(4)
|
|
|
|
async function checkFreshness(overrides = {}) {
|
|
const directory = mkdtempSync(join(tmpdir(), 'hourly-preflight-'))
|
|
const output = join(directory, 'output')
|
|
try {
|
|
const result = await runProcess({
|
|
program: 'bash',
|
|
args: [
|
|
'-c',
|
|
`gh() {
|
|
case "$1 $2" in
|
|
"api "*) printf '%s\\n' "$HEAD_SHA" ;;
|
|
"release list") printf '%s\\n' "$LAST_TAG" ;;
|
|
"release view") printf '%s\\n' "$LAST_SHA" ;;
|
|
*) return 1 ;;
|
|
esac
|
|
}
|
|
${freshness.run}`
|
|
],
|
|
env: {
|
|
...process.env,
|
|
GITHUB_OUTPUT: output,
|
|
GITHUB_REPOSITORY: 'stablyai/orca',
|
|
MAIN_REPO_TOKEN: 'main-token',
|
|
HOURLY_REPO: 'stablyai/orca-hourly',
|
|
HEAD_SHA: head,
|
|
LAST_TAG: 'previous-hourly',
|
|
LAST_SHA: head.slice(0, 12),
|
|
FORCED: 'false',
|
|
...overrides
|
|
}
|
|
})
|
|
return {
|
|
exitCode: result.code,
|
|
stderr: result.stderr,
|
|
stdout: result.stdout,
|
|
output: result.code === 0 ? readFileSync(output, 'utf8') : ''
|
|
}
|
|
} finally {
|
|
rmSync(directory, { recursive: true, force: true })
|
|
}
|
|
}
|
|
|
|
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', 'relay-windows-process-tree'])
|
|
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],
|
|
['forced', { FORCED: 'true' }, true],
|
|
['first build', { LAST_TAG: '' }, true],
|
|
['missing prior identity', { LAST_SHA: '' }, true]
|
|
])('%s main selects the expected build decision', async (_name, env, shouldBuild) => {
|
|
const result = await checkFreshness(env)
|
|
expect(result.exitCode, `${result.stdout} ${result.stderr}`).toBe(0)
|
|
expect(result.output).toBe(`head_sha=${head}\nshould_build=${shouldBuild}\n`)
|
|
})
|
|
|
|
it('fails closed when main cannot be resolved, even when forced', async () => {
|
|
const result = await checkFreshness({ HEAD_SHA: '', FORCED: 'true' })
|
|
expect(result.exitCode).not.toBe(0)
|
|
})
|
|
})
|