Files
orca/config/scripts/ssh-relay-runtime-zip.test.mjs
T
2026-07-14 09:58:21 -04:00

135 lines
4.3 KiB
JavaScript

import { createHash } from 'node:crypto'
import { createWriteStream } from 'node:fs'
import { chmod, mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { pipeline } from 'node:stream/promises'
import { afterEach, describe, expect, it } from 'vitest'
import yazl from 'yazl'
import { computeSshRelayRuntimeContentId } from './ssh-relay-runtime-identity.mjs'
import { createSshRelayRuntimeZip, inspectSshRelayRuntimeZip } from './ssh-relay-runtime-zip.mjs'
const temporaryDirectories = []
afterEach(async () => {
await Promise.all(temporaryDirectories.splice(0).map((path) => rm(path, { recursive: true })))
})
const digest = (value) => `sha256:${createHash('sha256').update(value).digest('hex')}`
async function fixture() {
const directory = await mkdtemp(join(tmpdir(), 'orca-runtime-zip-test-'))
temporaryDirectories.push(directory)
const runtimeRoot = join(directory, 'runtime')
await mkdir(join(runtimeRoot, 'bin'), { recursive: true })
await Promise.all([
writeFile(join(runtimeRoot, 'bin', 'node.exe'), 'node executable'),
writeFile(join(runtimeRoot, 'relay.js'), 'relay')
])
await chmod(join(runtimeRoot, 'bin', 'node.exe'), 0o755)
const base = {
tupleId: 'win32-x64',
os: 'win32',
architecture: 'x64',
compatibility: {
kind: 'win32',
minimumBuild: 20348,
minimumOpenSshVersion: '8.1p1',
minimumPowerShellVersion: '5.1',
minimumDotNetFrameworkRelease: 528040
},
nodeVersion: '24.18.0',
dependencies: { nodePtyVersion: '1.1.0', parcelWatcherVersion: '2.5.6' },
entries: [
{ path: 'bin', type: 'directory', mode: 0o755 },
{
path: 'bin/node.exe',
type: 'file',
role: 'node',
size: 15,
mode: 0o755,
sha256: digest('node executable')
},
{
path: 'relay.js',
type: 'file',
role: 'relay',
size: 5,
mode: 0o644,
sha256: digest('relay')
}
],
fileCount: 2,
expandedSize: 20
}
return {
directory,
runtimeRoot,
identity: { ...base, contentId: computeSshRelayRuntimeContentId(base) }
}
}
async function writeZip(path, entries) {
const zip = new yazl.ZipFile()
for (const entry of entries) {
zip.addBuffer(Buffer.from(entry.bytes ?? ''), entry.path, {
mtime: new Date('2025-07-17T00:00:00.000Z'),
mode: entry.mode ?? 0o644
})
}
zip.end()
await pipeline(zip.outputStream, createWriteStream(path))
}
describe('SSH relay runtime Windows ZIP', () => {
it('creates deterministic ZIP bytes and rehashes the complete declared tree', async () => {
const value = await fixture()
const firstDirectory = join(value.directory, 'first')
const secondDirectory = join(value.directory, 'second')
await Promise.all([mkdir(firstDirectory), mkdir(secondDirectory)])
const first = await createSshRelayRuntimeZip({
runtimeRoot: value.runtimeRoot,
outputDirectory: firstDirectory,
identity: value.identity,
sourceDateEpoch: 1_752_710_400
})
const second = await createSshRelayRuntimeZip({
runtimeRoot: value.runtimeRoot,
outputDirectory: secondDirectory,
identity: value.identity,
sourceDateEpoch: 1_752_710_400
})
expect(first.name).toMatch(/\.zip$/)
expect(await readFile(first.path)).toEqual(await readFile(second.path))
await expect(inspectSshRelayRuntimeZip(first.path, value.identity)).resolves.toEqual({
entries: 3,
files: 2,
expandedBytes: 20
})
})
it('rejects undeclared entries and declared-file integrity mismatches', async () => {
const value = await fixture()
const extra = join(value.directory, 'extra.zip')
const tampered = join(value.directory, 'tampered.zip')
await writeZip(extra, [
{ path: 'bin/node.exe', bytes: 'node executable', mode: 0o755 },
{ path: 'relay.js', bytes: 'relay' },
{ path: 'extra.js', bytes: 'extra' }
])
await writeZip(tampered, [
{ path: 'bin/node.exe', bytes: 'node executable', mode: 0o755 },
{ path: 'relay.js', bytes: 'wrong' }
])
await expect(inspectSshRelayRuntimeZip(extra, value.identity)).rejects.toThrow(
/extra or duplicate/i
)
await expect(inspectSshRelayRuntimeZip(tampered, value.identity)).rejects.toThrow(
/integrity mismatch/i
)
})
})