Files
orca/config/scripts/ssh-relay-runtime-release-assets.test.mjs
T
2026-07-15 12:46:20 -04:00

194 lines
6.8 KiB
JavaScript

import { describe, expect, it, vi } from 'vitest'
import { createSshRelayArtifactTestManifest } from '../../src/main/ssh/ssh-relay-artifact-test-manifest'
import { verifySshRelayRuntimeReleaseAssets } from './ssh-relay-runtime-release-assets.mjs'
const MANIFEST_NAME = 'orca-ssh-relay-runtime-manifest.json'
const SIGNATURE_NAME = 'orca-ssh-relay-runtime-manifest.sig'
const digest = (character) => `sha256:${character.repeat(64)}`
function buildIdentity(tag) {
for (const [pattern, channel] of [
[/^v(\d+\.\d+\.\d+)$/u, 'stable'],
[/^v(\d+\.\d+\.\d+-rc\.\d+)$/u, 'rc'],
[/^v(\d+\.\d+\.\d+-rc\.\d+\.perf)$/u, 'perf']
]) {
const match = pattern.exec(tag)
if (match) {
return { tag, channel, version: match[1] }
}
}
throw new Error(`Unsupported test tag: ${tag}`)
}
function fixture(tag = 'v1.4.140-rc.1') {
const manifest = createSshRelayArtifactTestManifest()
manifest.build = { ...manifest.build, ...buildIdentity(tag) }
const manifestAsset = { name: MANIFEST_NAME, size: 2_048, sha256: digest('e') }
const signatureAsset = {
name: SIGNATURE_NAME,
size: 256,
sha256: digest('f'),
manifestSha256: manifestAsset.sha256,
keyIds: manifest.signatures.map((signature) => signature.keyId)
}
const expectedAssets = [
manifest.tuples[0].archive,
manifest.tuples[0].metadataAssets.sbom,
manifest.tuples[0].metadataAssets.provenance,
manifestAsset,
signatureAsset
]
const release = {
id: 42,
tag_name: tag,
draft: true,
prerelease: manifest.build.channel !== 'stable',
assets: [
...expectedAssets.map((asset, index) => ({
id: index + 1,
name: asset.name,
state: 'uploaded',
size: asset.size
})),
{ id: 99, name: 'orca-windows-setup.exe', state: 'uploaded', size: 3_000 }
]
}
return {
releaseId: release.id,
tag,
release,
verifiedManifest: { manifest, manifestAsset, signatureAsset }
}
}
function managedAsset(input, name) {
return input.release.assets.find((asset) => asset.name === name)
}
describe('SSH relay runtime release required assets', () => {
it.each([
['v1.4.140', 'stable', false],
['v1.4.140-rc.2', 'rc', true],
['v1.4.140-rc.2.perf', 'perf', true]
])(
'accepts exact %s manifest coverage and authenticated draft metadata',
(tag, channel, prerelease) => {
const input = fixture(tag)
expect(verifySshRelayRuntimeReleaseAssets(input)).toEqual({
releaseId: 42,
tag,
channel,
draft: true,
prerelease,
checked: expect.arrayContaining([
input.verifiedManifest.manifest.tuples[0].archive.name,
input.verifiedManifest.manifest.tuples[0].metadataAssets.sbom.name,
input.verifiedManifest.manifest.tuples[0].metadataAssets.provenance.name,
MANIFEST_NAME,
SIGNATURE_NAME
])
})
}
)
it.each([
['missing', (input) => input.release.assets.splice(0, 1), /missing managed asset/i],
[
'extra managed',
(input) =>
input.release.assets.push({
id: 100,
name: 'orca-ssh-relay-runtime-uncovered.zip',
state: 'uploaded',
size: 1
}),
/unexpected managed asset/i
],
[
'duplicate',
(input) => input.release.assets.push(structuredClone(input.release.assets[0])),
/duplicate release asset/i
]
])('rejects a %s managed asset set', (_label, mutate, message) => {
const input = fixture()
mutate(input)
expect(() => verifySshRelayRuntimeReleaseAssets(input)).toThrow(message)
})
it.each([
['non-uploaded', (asset) => (asset.state = 'new'), /not uploaded/i],
['empty', (asset) => (asset.size = 0), /empty/i],
['wrong-size', (asset) => (asset.size += 1), /size disagrees/i]
])('rejects a %s covered asset', (_label, mutate, message) => {
const input = fixture()
mutate(managedAsset(input, MANIFEST_NAME))
expect(() => verifySshRelayRuntimeReleaseAssets(input)).toThrow(message)
})
it('rejects release, manifest, or prerelease identity crossing tags and channels', () => {
const crossRelease = fixture()
crossRelease.release.tag_name = 'v1.4.140-rc.2'
expect(() => verifySshRelayRuntimeReleaseAssets(crossRelease)).toThrow(/release tag/i)
const crossDraft = fixture()
crossDraft.release.id += 1
expect(() => verifySshRelayRuntimeReleaseAssets(crossDraft)).toThrow(/release ID/i)
const crossManifest = fixture()
Object.assign(crossManifest.verifiedManifest.manifest.build, buildIdentity('v1.4.140-rc.2'))
expect(() => verifySshRelayRuntimeReleaseAssets(crossManifest)).toThrow(/manifest tag/i)
const crossChannel = fixture()
crossChannel.verifiedManifest.manifest.build.channel = 'stable'
expect(() => verifySshRelayRuntimeReleaseAssets(crossChannel)).toThrow(/manifest.*identity/i)
const wrongPrerelease = fixture()
wrongPrerelease.release.prerelease = false
expect(() => verifySshRelayRuntimeReleaseAssets(wrongPrerelease)).toThrow(/prerelease/i)
})
it('rejects a detached signature asset that disagrees with verified manifest signatures', () => {
const input = fixture()
input.verifiedManifest.signatureAsset.keyIds = [digest('0')]
expect(() => verifySshRelayRuntimeReleaseAssets(input)).toThrow(/signature keys disagree/i)
const crossManifest = fixture()
crossManifest.verifiedManifest.signatureAsset.manifestSha256 = digest('0')
expect(() => verifySshRelayRuntimeReleaseAssets(crossManifest)).toThrow(
/signature manifest identity disagrees/i
)
})
it('rejects malformed or incomplete verified-manifest asset bindings', () => {
const malformedDigest = fixture()
malformedDigest.verifiedManifest.manifestAsset.sha256 = digest('A')
expect(() => verifySshRelayRuntimeReleaseAssets(malformedDigest)).toThrow(/sha-256/i)
const missingSignature = fixture()
missingSignature.verifiedManifest.manifest.signatures = []
expect(() => verifySshRelayRuntimeReleaseAssets(missingSignature)).toThrow(/signature/i)
const malformedSignature = fixture()
malformedSignature.verifiedManifest.manifest.signatures[0].signature = 42
expect(() => verifySshRelayRuntimeReleaseAssets(malformedSignature)).toThrow(/signature/i)
const unexpectedField = fixture()
unexpectedField.verifiedManifest.manifestAsset.path = '/tmp/manifest'
expect(() => verifySshRelayRuntimeReleaseAssets(unexpectedField)).toThrow(/fields/i)
})
it('is a disconnected metadata gate with no network request', () => {
const fetchMock = vi.fn(() => {
throw new Error('network must remain disconnected')
})
vi.stubGlobal('fetch', fetchMock)
expect(() => verifySshRelayRuntimeReleaseAssets(fixture())).not.toThrow()
expect(fetchMock).not.toHaveBeenCalled()
vi.unstubAllGlobals()
})
})