mirror of
https://github.com/stablyai/orca.git
synced 2026-10-18 08:03:22 +00:00
252 lines
9.2 KiB
JavaScript
252 lines
9.2 KiB
JavaScript
import { mkdtemp, mkdir, readFile, realpath, rm, writeFile } from 'node:fs/promises'
|
|
import { tmpdir } from 'node:os'
|
|
import { join } from 'node:path'
|
|
|
|
import { parse } from 'yaml'
|
|
import { afterEach, describe, expect, it, vi } from 'vitest'
|
|
|
|
import { createSshRelayArtifactTestManifest } from '../../src/main/ssh/ssh-relay-artifact-test-manifest.ts'
|
|
import {
|
|
finalizeSshRelayRuntimeLinuxArtifact,
|
|
parseSshRelayRuntimeLinuxFinalizationArguments
|
|
} from './ssh-relay-runtime-linux-finalization.mjs'
|
|
|
|
const temporaryDirectories = []
|
|
const VERIFIED_AT = '2026-07-15T13:30:00.000Z'
|
|
const artifactWorkflowUrl = new URL(
|
|
'../../.github/workflows/ssh-relay-runtime-artifacts.yml',
|
|
import.meta.url
|
|
)
|
|
|
|
function linuxIdentity() {
|
|
const tuple = createSshRelayArtifactTestManifest().tuples[0]
|
|
const {
|
|
archive,
|
|
metadataAssets: _metadataAssets,
|
|
nativeVerification: _native,
|
|
...identity
|
|
} = tuple
|
|
return { identity: { ...identity, archive }, finalIdentity: identity }
|
|
}
|
|
|
|
function linuxPlan(identity) {
|
|
return {
|
|
platform: 'linux',
|
|
verificationFiles: identity.entries
|
|
.filter(
|
|
(entry) =>
|
|
entry.type === 'file' &&
|
|
['node', 'node-pty-native', 'parcel-watcher-native', 'native-runtime'].includes(
|
|
entry.role
|
|
)
|
|
)
|
|
.map((entry) => ({ path: entry.path, role: entry.role, sourceSha256: entry.sha256 }))
|
|
}
|
|
}
|
|
|
|
async function fixture() {
|
|
const root = await mkdtemp(join(tmpdir(), 'orca-runtime-linux-finalization-'))
|
|
temporaryDirectories.push(root)
|
|
const source = join(root, 'source')
|
|
const runtime = join(source, 'runtime')
|
|
const output = join(root, 'final')
|
|
await mkdir(runtime, { recursive: true })
|
|
const { identity, finalIdentity } = linuxIdentity()
|
|
const identityPath = join(source, `orca-ssh-relay-runtime-${identity.tupleId}.identity.json`)
|
|
const archivePath = join(source, identity.archive.name)
|
|
const sbomPath = join(source, `orca-ssh-relay-runtime-${identity.tupleId}.spdx.json`)
|
|
const provenancePath = join(source, `orca-ssh-relay-runtime-${identity.tupleId}.provenance.json`)
|
|
await Promise.all([
|
|
writeFile(identityPath, `${JSON.stringify(identity)}\n`),
|
|
writeFile(archivePath, 'archive'),
|
|
writeFile(sbomPath, 'sbom'),
|
|
writeFile(provenancePath, 'provenance')
|
|
])
|
|
return { source, runtime, output, identity, finalIdentity, identityPath }
|
|
}
|
|
|
|
afterEach(async () => {
|
|
await Promise.all(
|
|
temporaryDirectories
|
|
.splice(0)
|
|
.map((directory) => rm(directory, { recursive: true, force: true }))
|
|
)
|
|
})
|
|
|
|
describe('SSH relay runtime Linux hash-only finalization', () => {
|
|
it('verifies before emitting an exact aggregate-ready descriptor and receipt', async () => {
|
|
const input = await fixture()
|
|
const order = []
|
|
const plan = linuxPlan(input.finalIdentity)
|
|
const physicalIdentityPath = await realpath(input.identityPath)
|
|
const physicalRuntime = await realpath(input.runtime)
|
|
const physicalSource = await realpath(input.source)
|
|
const verifyRuntimeImpl = vi.fn(async ({ runtimeDirectory, identityPath, archivePath }) => {
|
|
order.push('verify')
|
|
expect(runtimeDirectory).toBe(physicalRuntime)
|
|
expect(identityPath).toBe(physicalIdentityPath)
|
|
expect(archivePath).toBe(join(physicalSource, input.identity.archive.name))
|
|
return { smoke: { nodeVersion: 'v24.18.0' } }
|
|
})
|
|
const writeDescriptorImpl = vi.fn(async (options) => {
|
|
order.push('descriptor')
|
|
expect(options.finalIdentity).toEqual(input.finalIdentity)
|
|
expect(options.verificationReport).toEqual({
|
|
tupleId: input.identity.tupleId,
|
|
sourceContentId: input.identity.contentId,
|
|
finalContentId: input.identity.contentId,
|
|
verifiedFiles: plan.verificationFiles.map((file) => ({
|
|
path: file.path,
|
|
role: file.role,
|
|
sha256: file.sourceSha256
|
|
}))
|
|
})
|
|
expect(options.nativeVerificationTool).toEqual({ name: 'node', version: '24.18.0' })
|
|
expect(options.verifiedAt).toBe(VERIFIED_AT)
|
|
return {
|
|
tupleId: input.identity.tupleId,
|
|
input: {
|
|
tupleId: input.identity.tupleId,
|
|
descriptor: { name: 'descriptor.json', size: 1, sha256: `sha256:${'a'.repeat(64)}` },
|
|
archive: {
|
|
name: input.identity.archive.name,
|
|
size: 7,
|
|
sha256: `sha256:${'b'.repeat(64)}`
|
|
},
|
|
sbom: { name: 'sbom.json', size: 4, sha256: `sha256:${'c'.repeat(64)}` },
|
|
provenance: { name: 'provenance.json', size: 10, sha256: `sha256:${'d'.repeat(64)}` }
|
|
}
|
|
}
|
|
})
|
|
|
|
const result = await finalizeSshRelayRuntimeLinuxArtifact({
|
|
sourceOutputDirectory: input.source,
|
|
identityPath: input.identityPath,
|
|
outputDirectory: input.output,
|
|
verifiedAt: VERIFIED_AT,
|
|
nativeVerificationTool: { name: 'node', version: '24.18.0' },
|
|
readIdentityImpl: async () => input.identity,
|
|
buildPlanImpl: () => plan,
|
|
verifyRuntimeImpl,
|
|
writeDescriptorImpl
|
|
})
|
|
|
|
expect(order).toEqual(['verify', 'descriptor'])
|
|
expect(result).toMatchObject({
|
|
tupleId: input.identity.tupleId,
|
|
contentId: input.identity.contentId,
|
|
aggregateInput: { tupleId: input.identity.tupleId }
|
|
})
|
|
expect(JSON.parse(await readFile(result.receiptPath, 'utf8'))).toEqual({
|
|
tupleId: input.identity.tupleId,
|
|
contentId: input.identity.contentId,
|
|
verification: { smoke: { nodeVersion: 'v24.18.0' } },
|
|
aggregateInput: result.aggregateInput
|
|
})
|
|
await expect(
|
|
readFile(join(result.assetsRoot, input.identity.archive.name), 'utf8')
|
|
).resolves.toBe('archive')
|
|
})
|
|
|
|
it('rejects non-Linux input and removes partial output on failure', async () => {
|
|
const input = await fixture()
|
|
const nonLinux = { ...input.identity, os: 'darwin', tupleId: 'darwin-x64' }
|
|
await expect(
|
|
finalizeSshRelayRuntimeLinuxArtifact({
|
|
sourceOutputDirectory: input.source,
|
|
identityPath: input.identityPath,
|
|
outputDirectory: input.output,
|
|
verifiedAt: VERIFIED_AT,
|
|
nativeVerificationTool: { name: 'node', version: '24.18.0' },
|
|
readIdentityImpl: async () => nonLinux,
|
|
verifyRuntimeImpl: vi.fn(),
|
|
writeDescriptorImpl: vi.fn()
|
|
})
|
|
).rejects.toThrow(/linux/i)
|
|
|
|
await expect(
|
|
finalizeSshRelayRuntimeLinuxArtifact({
|
|
sourceOutputDirectory: input.source,
|
|
identityPath: input.identityPath,
|
|
outputDirectory: input.output,
|
|
verifiedAt: VERIFIED_AT,
|
|
nativeVerificationTool: { name: 'node', version: '24.18.0' },
|
|
readIdentityImpl: async () => input.identity,
|
|
buildPlanImpl: () => linuxPlan(input.finalIdentity),
|
|
verifyRuntimeImpl: async () => ({ smoke: true }),
|
|
writeDescriptorImpl: async () => {
|
|
throw new Error('descriptor failed')
|
|
}
|
|
})
|
|
).rejects.toThrow(/descriptor failed/i)
|
|
await expect(
|
|
readFile(join(input.output, 'assets', input.identity.archive.name))
|
|
).rejects.toMatchObject({ code: 'ENOENT' })
|
|
})
|
|
|
|
it('parses only the exact bounded CLI arguments', () => {
|
|
expect(
|
|
parseSshRelayRuntimeLinuxFinalizationArguments([
|
|
'--source-output-directory',
|
|
'source',
|
|
'--identity',
|
|
'identity.json',
|
|
'--output-directory',
|
|
'output',
|
|
'--verified-at',
|
|
VERIFIED_AT,
|
|
'--native-verification-tool-version',
|
|
'24.18.0'
|
|
])
|
|
).toMatchObject({
|
|
verifiedAt: VERIFIED_AT,
|
|
nativeVerificationToolVersion: '24.18.0'
|
|
})
|
|
expect(() =>
|
|
parseSshRelayRuntimeLinuxFinalizationArguments(['--output-directory', 'output'])
|
|
).toThrow(/missing/i)
|
|
expect(() =>
|
|
parseSshRelayRuntimeLinuxFinalizationArguments([
|
|
'--source-output-directory',
|
|
'source',
|
|
'--identity',
|
|
'identity.json',
|
|
'--output-directory',
|
|
'output',
|
|
'--verified-at',
|
|
VERIFIED_AT,
|
|
'--native-verification-tool-version',
|
|
'24.18.0',
|
|
'--extra',
|
|
'value'
|
|
])
|
|
).toThrow(/invalid/i)
|
|
})
|
|
|
|
it('emits Linux descriptors before upload and runs the contract on both native families', async () => {
|
|
const source = await readFile(artifactWorkflowUrl, 'utf8')
|
|
const workflow = parse(source)
|
|
const posix = workflow.jobs['build-posix-runtime']
|
|
const windows = workflow.jobs['build-windows-runtime']
|
|
const build = posix.steps.find(
|
|
(step) => step.name === 'Build twice, inspect, smoke, and compare exact runtime'
|
|
).run
|
|
const finalization = build.indexOf('ssh-relay-runtime-linux-finalization.mjs')
|
|
const descriptorCopy = build.indexOf('.manifest-tuple.json', finalization)
|
|
const linuxExit = build.indexOf('exit 0', descriptorCopy)
|
|
expect(finalization).toBeGreaterThan(-1)
|
|
expect(descriptorCopy).toBeGreaterThan(finalization)
|
|
expect(linuxExit).toBeGreaterThan(descriptorCopy)
|
|
for (const job of [posix, windows]) {
|
|
const contract = job.steps.find(
|
|
(step) => step.name === 'Run runtime artifact contract tests'
|
|
).run
|
|
expect(contract).toContain(
|
|
'node --check config/scripts/ssh-relay-runtime-linux-finalization.mjs'
|
|
)
|
|
expect(contract).toContain('config/scripts/ssh-relay-runtime-linux-finalization.test.mjs')
|
|
}
|
|
expect(posix.steps.at(-1).with.path).toBe('runtime-evidence/${{ matrix.tuple }}/')
|
|
})
|
|
})
|