mirror of
https://github.com/stablyai/orca.git
synced 2026-10-18 00:03:20 +00:00
194 lines
6.8 KiB
JavaScript
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()
|
|
})
|
|
})
|