mirror of
https://github.com/stablyai/orca.git
synced 2026-10-17 16:02:55 +00:00
213 lines
6.4 KiB
JavaScript
213 lines
6.4 KiB
JavaScript
import { afterEach, describe, expect, it, vi } from 'vitest'
|
|
|
|
import { verifySshRelayRuntimeDraftReadback } from './ssh-relay-runtime-draft-readback.mjs'
|
|
|
|
const TAG = 'v1.4.140-rc.1'
|
|
const REPO = 'stablyai/orca'
|
|
const TOKEN = 'secret-token'
|
|
const bytes = Buffer.from('immutable release bytes')
|
|
const expected = {
|
|
name: 'orca-ssh-relay-runtime-v1-linux-x64-glibc-a.tar.xz',
|
|
sha256: 'sha256:5396515749878bd28c5dae110040b4fbae1c33f59318b9c23f446319d68e236a',
|
|
size: bytes.length
|
|
}
|
|
|
|
function release(overrides = {}) {
|
|
return {
|
|
id: 42,
|
|
tag_name: TAG,
|
|
draft: true,
|
|
assets: [{ id: 101, name: expected.name, state: 'uploaded', size: expected.size }],
|
|
...overrides
|
|
}
|
|
}
|
|
|
|
function fetchFixture(assetResponse = new Response(bytes)) {
|
|
return vi
|
|
.fn()
|
|
.mockResolvedValueOnce(Response.json(release()))
|
|
.mockResolvedValueOnce(assetResponse)
|
|
}
|
|
|
|
afterEach(() => vi.restoreAllMocks())
|
|
|
|
describe('SSH relay runtime draft read-back', () => {
|
|
it('downloads and hashes every exact managed asset from the same draft', async () => {
|
|
const fetchImpl = fetchFixture()
|
|
|
|
await expect(
|
|
verifySshRelayRuntimeDraftReadback({
|
|
repo: REPO,
|
|
releaseId: 42,
|
|
tag: TAG,
|
|
token: TOKEN,
|
|
expectedAssets: [expected],
|
|
fetchImpl
|
|
})
|
|
).resolves.toEqual({ releaseId: 42, tag: TAG, downloadedAssets: [expected] })
|
|
})
|
|
|
|
it('follows only the approved asset redirect without forwarding authorization', async () => {
|
|
const location = 'https://release-assets.githubusercontent.com/example/runtime?sig=signed'
|
|
const fetchImpl = vi
|
|
.fn()
|
|
.mockResolvedValueOnce(Response.json(release()))
|
|
.mockResolvedValueOnce(new Response(null, { status: 302, headers: { location } }))
|
|
.mockResolvedValueOnce(new Response(bytes))
|
|
|
|
await verifySshRelayRuntimeDraftReadback({
|
|
repo: REPO,
|
|
releaseId: 42,
|
|
tag: TAG,
|
|
token: TOKEN,
|
|
expectedAssets: [expected],
|
|
fetchImpl
|
|
})
|
|
|
|
expect(fetchImpl.mock.calls[1][1].headers.Authorization).toBe(`Bearer ${TOKEN}`)
|
|
expect(fetchImpl.mock.calls[2][0]).toBe(location)
|
|
expect(fetchImpl.mock.calls[2][1].headers).not.toHaveProperty('Authorization')
|
|
})
|
|
|
|
it.each([
|
|
['http://release-assets.githubusercontent.com/runtime', 'HTTPS'],
|
|
['https://example.com/runtime', 'origin']
|
|
])('rejects an unsafe asset redirect %s', async (location, message) => {
|
|
const fetchImpl = vi
|
|
.fn()
|
|
.mockResolvedValueOnce(Response.json(release()))
|
|
.mockResolvedValueOnce(new Response(null, { status: 302, headers: { location } }))
|
|
|
|
await expect(
|
|
verifySshRelayRuntimeDraftReadback({
|
|
repo: REPO,
|
|
releaseId: 42,
|
|
tag: TAG,
|
|
token: TOKEN,
|
|
expectedAssets: [expected],
|
|
fetchImpl
|
|
})
|
|
).rejects.toThrow(new RegExp(message, 'i'))
|
|
})
|
|
|
|
it.each(['direct API response', 'redirected CDN response'])(
|
|
'rejects an unexpected successful status from the %s',
|
|
async (responseKind) => {
|
|
const partialResponse = new Response(bytes, {
|
|
status: 206,
|
|
headers: { 'content-range': `bytes 0-${bytes.length - 1}/${bytes.length}` }
|
|
})
|
|
const fetchImpl =
|
|
responseKind === 'direct API response'
|
|
? fetchFixture(partialResponse)
|
|
: vi
|
|
.fn()
|
|
.mockResolvedValueOnce(Response.json(release()))
|
|
.mockResolvedValueOnce(
|
|
new Response(null, {
|
|
status: 302,
|
|
headers: {
|
|
location: 'https://release-assets.githubusercontent.com/example/runtime'
|
|
}
|
|
})
|
|
)
|
|
.mockResolvedValueOnce(partialResponse)
|
|
|
|
await expect(
|
|
verifySshRelayRuntimeDraftReadback({
|
|
repo: REPO,
|
|
releaseId: 42,
|
|
tag: TAG,
|
|
token: TOKEN,
|
|
expectedAssets: [expected],
|
|
fetchImpl
|
|
})
|
|
).rejects.toThrow(/failed 206/i)
|
|
}
|
|
)
|
|
|
|
it('rejects changed, truncated, or oversized returned bytes', async () => {
|
|
for (const body of [
|
|
Buffer.from('changed release bytes'),
|
|
bytes.subarray(1),
|
|
Buffer.concat([bytes, bytes])
|
|
]) {
|
|
await expect(
|
|
verifySshRelayRuntimeDraftReadback({
|
|
repo: REPO,
|
|
releaseId: 42,
|
|
tag: TAG,
|
|
token: TOKEN,
|
|
expectedAssets: [expected],
|
|
fetchImpl: fetchFixture(new Response(body))
|
|
})
|
|
).rejects.toThrow(/size|sha-?256/i)
|
|
}
|
|
})
|
|
|
|
it('rejects a published, cross-tag, incomplete, or unexpected managed draft', async () => {
|
|
for (const changedRelease of [
|
|
release({ draft: false }),
|
|
release({ tag_name: 'v1.4.140-rc.2' }),
|
|
release({ assets: [] }),
|
|
release({
|
|
assets: [
|
|
...release().assets,
|
|
{ id: 102, name: 'orca-ssh-relay-runtime-extra.zip', state: 'uploaded', size: 1 }
|
|
]
|
|
})
|
|
]) {
|
|
const fetchImpl = vi.fn().mockResolvedValueOnce(Response.json(changedRelease))
|
|
await expect(
|
|
verifySshRelayRuntimeDraftReadback({
|
|
repo: REPO,
|
|
releaseId: 42,
|
|
tag: TAG,
|
|
token: TOKEN,
|
|
expectedAssets: [expected],
|
|
fetchImpl
|
|
})
|
|
).rejects.toThrow(/draft|tag|missing|unexpected/i)
|
|
}
|
|
})
|
|
|
|
it('rejects non-uploaded metadata or a mismatched declared size before download', async () => {
|
|
for (const asset of [
|
|
{ ...release().assets[0], state: 'new' },
|
|
{ ...release().assets[0], size: expected.size + 1 }
|
|
]) {
|
|
const fetchImpl = vi.fn().mockResolvedValueOnce(Response.json(release({ assets: [asset] })))
|
|
await expect(
|
|
verifySshRelayRuntimeDraftReadback({
|
|
repo: REPO,
|
|
releaseId: 42,
|
|
tag: TAG,
|
|
token: TOKEN,
|
|
expectedAssets: [expected],
|
|
fetchImpl
|
|
})
|
|
).rejects.toThrow(/uploaded|size/i)
|
|
expect(fetchImpl).toHaveBeenCalledTimes(1)
|
|
}
|
|
})
|
|
|
|
it('honors cancellation before any GitHub request', async () => {
|
|
const controller = new AbortController()
|
|
controller.abort(new Error('cancel read-back'))
|
|
const fetchImpl = vi.fn()
|
|
|
|
await expect(
|
|
verifySshRelayRuntimeDraftReadback({
|
|
repo: REPO,
|
|
releaseId: 42,
|
|
tag: TAG,
|
|
token: TOKEN,
|
|
expectedAssets: [expected],
|
|
fetchImpl,
|
|
signal: controller.signal
|
|
})
|
|
).rejects.toThrow(/cancel read-back/i)
|
|
expect(fetchImpl).not.toHaveBeenCalled()
|
|
})
|
|
})
|