mirror of
https://github.com/stablyai/orca.git
synced 2026-10-18 00:03:20 +00:00
402 lines
14 KiB
JavaScript
402 lines
14 KiB
JavaScript
import { createHash } from 'node:crypto'
|
|
import { lstat, mkdir, readFile, realpath, rm, writeFile } from 'node:fs/promises'
|
|
import { basename, dirname, join, resolve } from 'node:path'
|
|
import { pathToFileURL } from 'node:url'
|
|
|
|
import { collectSshRelayRuntimeManifestArtifacts } from './ssh-relay-runtime-manifest-artifact-collection.mjs'
|
|
import {
|
|
finalizeSshRelayRuntimeManifestAggregate,
|
|
prepareSshRelayRuntimeManifestAggregate
|
|
} from './ssh-relay-runtime-manifest-aggregate.mjs'
|
|
import {
|
|
decodeSshRelayRuntimeManifestSigningRequestArtifact,
|
|
encodeSshRelayRuntimeManifestSigningRequestArtifact
|
|
} from './ssh-relay-runtime-manifest-seed-signing.mjs'
|
|
import { sshRelayRuntimeManifestKeyId } from './ssh-relay-runtime-manifest-signing-handoff.mjs'
|
|
|
|
const MAX_JSON_BYTES = 48 * 1024 * 1024
|
|
const SOURCE_SHA = /^[0-9a-f]{40}$/u
|
|
const TIMESTAMP = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/u
|
|
const BASE64 = /^[A-Za-z0-9+/]+={0,2}$/u
|
|
const DIGEST = /^sha256:[0-9a-f]{64}$/u
|
|
const PREPARED_FIELDS = [
|
|
'acceptedKeysSha256',
|
|
'createdAt',
|
|
'inputTuples',
|
|
'inputTuplesSha256',
|
|
'relayProtocolVersion',
|
|
'releaseTag',
|
|
'schemaVersion',
|
|
'signingRequest',
|
|
'sourceSha',
|
|
'unsignedManifest'
|
|
]
|
|
|
|
function assertObject(value, label) {
|
|
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
|
|
throw new Error(`SSH relay runtime manifest aggregate command ${label} must be an object`)
|
|
}
|
|
}
|
|
|
|
function assertExactFields(value, fields, label) {
|
|
assertObject(value, label)
|
|
const actual = Object.keys(value).sort()
|
|
const expected = [...fields].sort()
|
|
if (JSON.stringify(actual) !== JSON.stringify(expected)) {
|
|
throw new Error(`SSH relay runtime manifest aggregate command ${label} has invalid fields`)
|
|
}
|
|
}
|
|
|
|
function sha256(bytes) {
|
|
return `sha256:${createHash('sha256').update(bytes).digest('hex')}`
|
|
}
|
|
|
|
function canonicalJson(value) {
|
|
return Buffer.from(`${JSON.stringify(value)}\n`, 'utf8')
|
|
}
|
|
|
|
function parseReleaseTag(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, version: match[1], channel }
|
|
}
|
|
}
|
|
throw new Error('SSH relay runtime manifest aggregate command release tag is invalid')
|
|
}
|
|
|
|
function commandIdentity(input) {
|
|
if (!SOURCE_SHA.test(input.sourceSha ?? '')) {
|
|
throw new Error('SSH relay runtime manifest aggregate command source SHA is invalid')
|
|
}
|
|
const release = parseReleaseTag(input.releaseTag)
|
|
if (
|
|
typeof input.createdAt !== 'string' ||
|
|
!TIMESTAMP.test(input.createdAt) ||
|
|
new Date(input.createdAt).toISOString() !== input.createdAt
|
|
) {
|
|
throw new Error('SSH relay runtime manifest aggregate command timestamp is invalid')
|
|
}
|
|
if (!Number.isSafeInteger(input.relayProtocolVersion) || input.relayProtocolVersion <= 0) {
|
|
throw new Error('SSH relay runtime manifest aggregate command protocol version is invalid')
|
|
}
|
|
return {
|
|
sourceSha: input.sourceSha,
|
|
releaseTag: input.releaseTag,
|
|
createdAt: input.createdAt,
|
|
relayProtocolVersion: input.relayProtocolVersion,
|
|
build: { ...release, relayProtocolVersion: input.relayProtocolVersion }
|
|
}
|
|
}
|
|
|
|
async function readBoundedJson(path, label) {
|
|
const before = await lstat(path, { bigint: true })
|
|
if (
|
|
!before.isFile() ||
|
|
before.isSymbolicLink() ||
|
|
before.size <= 0n ||
|
|
before.size > BigInt(MAX_JSON_BYTES)
|
|
) {
|
|
throw new Error(
|
|
`SSH relay runtime manifest aggregate command ${label} must be bounded regular JSON`
|
|
)
|
|
}
|
|
try {
|
|
const bytes = await readFile(path)
|
|
const after = await lstat(path, { bigint: true })
|
|
if (
|
|
before.dev !== after.dev ||
|
|
before.ino !== after.ino ||
|
|
before.size !== after.size ||
|
|
before.mtimeNs !== after.mtimeNs ||
|
|
before.ctimeNs !== after.ctimeNs
|
|
) {
|
|
throw new Error('file changed while reading')
|
|
}
|
|
return JSON.parse(bytes.toString('utf8'))
|
|
} catch (error) {
|
|
throw new Error(
|
|
`SSH relay runtime manifest aggregate command ${label} is invalid JSON: ${error.message}`
|
|
)
|
|
}
|
|
}
|
|
|
|
function decodeCanonicalBase64(value, label, expectedSize) {
|
|
if (typeof value !== 'string' || !BASE64.test(value)) {
|
|
throw new Error(`SSH relay runtime manifest aggregate command ${label} is not canonical base64`)
|
|
}
|
|
const bytes = Buffer.from(value, 'base64')
|
|
if (bytes.length !== expectedSize || bytes.toString('base64') !== value) {
|
|
throw new Error(
|
|
`SSH relay runtime manifest aggregate command ${label} must contain ${expectedSize} bytes`
|
|
)
|
|
}
|
|
return bytes
|
|
}
|
|
|
|
async function readAcceptedKeys(path) {
|
|
const document = await readBoundedJson(resolve(path), 'accepted keys')
|
|
assertExactFields(document, ['keys', 'schemaVersion'], 'accepted keys')
|
|
if (
|
|
document.schemaVersion !== 1 ||
|
|
!Array.isArray(document.keys) ||
|
|
document.keys.length === 0 ||
|
|
document.keys.length > 4
|
|
) {
|
|
throw new Error('SSH relay runtime manifest aggregate command accepted keys are invalid')
|
|
}
|
|
const seen = new Set()
|
|
const artifactKeys = document.keys
|
|
.map((key, index) => {
|
|
assertExactFields(key, ['keyId', 'publicKeyBase64'], `accepted key ${index}`)
|
|
const publicKey = decodeCanonicalBase64(key.publicKeyBase64, 'accepted public key', 32)
|
|
const keyId = sshRelayRuntimeManifestKeyId(publicKey)
|
|
if (!DIGEST.test(key.keyId ?? '') || key.keyId !== keyId || seen.has(keyId)) {
|
|
throw new Error(
|
|
'SSH relay runtime manifest aggregate command accepted key identity is invalid'
|
|
)
|
|
}
|
|
seen.add(keyId)
|
|
return { keyId, publicKeyBase64: key.publicKeyBase64, publicKey }
|
|
})
|
|
.sort((left, right) => (left.keyId < right.keyId ? -1 : left.keyId > right.keyId ? 1 : 0))
|
|
const serialized = artifactKeys.map(({ keyId, publicKeyBase64 }) => ({ keyId, publicKeyBase64 }))
|
|
return {
|
|
acceptedKeys: artifactKeys.map(({ keyId, publicKey }) => ({ keyId, publicKey })),
|
|
sha256: sha256(canonicalJson({ schemaVersion: 1, keys: serialized }))
|
|
}
|
|
}
|
|
|
|
async function exclusiveOutputDirectory(outputDirectory) {
|
|
const absolute = resolve(outputDirectory)
|
|
const parent = resolve(await realpath(dirname(absolute)))
|
|
const parentMetadata = await lstat(parent)
|
|
if (!parentMetadata.isDirectory() || parentMetadata.isSymbolicLink()) {
|
|
throw new Error('SSH relay runtime manifest aggregate command output parent must be real')
|
|
}
|
|
const output = resolve(parent, basename(absolute))
|
|
try {
|
|
await lstat(output)
|
|
} catch (error) {
|
|
if (error.code === 'ENOENT') {
|
|
return output
|
|
}
|
|
throw error
|
|
}
|
|
throw new Error(
|
|
'SSH relay runtime manifest aggregate command requires an exclusive output directory'
|
|
)
|
|
}
|
|
|
|
function assertReceiptBindings(bindings, prepared) {
|
|
const tuples = new Map(prepared.unsignedManifest.tuples.map((tuple) => [tuple.tupleId, tuple]))
|
|
for (const binding of bindings) {
|
|
if (tuples.get(binding.tupleId)?.contentId !== binding.contentId) {
|
|
throw new Error(
|
|
`SSH relay runtime manifest aggregate command receipt content drifted: ${binding.tupleId}`
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
function preparedArtifact(identity, acceptedKeysSha256, prepared) {
|
|
return {
|
|
schemaVersion: 1,
|
|
sourceSha: identity.sourceSha,
|
|
releaseTag: identity.releaseTag,
|
|
createdAt: identity.createdAt,
|
|
relayProtocolVersion: identity.relayProtocolVersion,
|
|
acceptedKeysSha256,
|
|
inputTuples: prepared.inputTuples,
|
|
inputTuplesSha256: prepared.inputTuplesSha256,
|
|
unsignedManifest: prepared.unsignedManifest,
|
|
signingRequest: encodeSshRelayRuntimeManifestSigningRequestArtifact(prepared.signingRequest)
|
|
}
|
|
}
|
|
|
|
async function collectAndPrepare(input, output, identity, signal) {
|
|
const stagingDirectory = join(output, 'aggregate-input')
|
|
await mkdir(stagingDirectory)
|
|
const bindings = await collectSshRelayRuntimeManifestArtifacts({
|
|
artifactsDirectory: input.artifactsDirectory,
|
|
stagingDirectory,
|
|
signal
|
|
})
|
|
const prepared = await prepareSshRelayRuntimeManifestAggregate({
|
|
inputDirectory: stagingDirectory,
|
|
build: identity.build,
|
|
createdAt: identity.createdAt,
|
|
tupleInputs: bindings.map(({ aggregateInput }) => aggregateInput),
|
|
signal
|
|
})
|
|
assertReceiptBindings(bindings, prepared)
|
|
return prepared
|
|
}
|
|
|
|
export async function prepareSshRelayRuntimeManifestAggregateCommand(input) {
|
|
const identity = commandIdentity(input)
|
|
// Why: public-key policy must be valid before canonical bytes can leave this boundary.
|
|
const keys = await readAcceptedKeys(input.acceptedKeysPath)
|
|
const output = await exclusiveOutputDirectory(input.outputDirectory)
|
|
let created = false
|
|
try {
|
|
await mkdir(output, { mode: 0o700 })
|
|
created = true
|
|
const prepared = await collectAndPrepare(input, output, identity, input.signal)
|
|
const artifact = preparedArtifact(identity, keys.sha256, prepared)
|
|
await writeFile(join(output, 'prepared-aggregate.json'), canonicalJson(artifact), {
|
|
flag: 'wx',
|
|
mode: 0o600
|
|
})
|
|
await writeFile(join(output, 'signing-request.json'), canonicalJson(artifact.signingRequest), {
|
|
flag: 'wx',
|
|
mode: 0o600
|
|
})
|
|
await rm(join(output, 'aggregate-input'), { recursive: true, force: true })
|
|
return prepared
|
|
} catch (error) {
|
|
if (created) {
|
|
await rm(output, { recursive: true, force: true })
|
|
}
|
|
throw error
|
|
}
|
|
}
|
|
|
|
function normalizePreparedArtifact(value) {
|
|
assertExactFields(value, PREPARED_FIELDS, 'prepared aggregate')
|
|
if (value.schemaVersion !== 1 || !DIGEST.test(value.acceptedKeysSha256 ?? '')) {
|
|
throw new Error('SSH relay runtime manifest aggregate command prepared aggregate is invalid')
|
|
}
|
|
decodeSshRelayRuntimeManifestSigningRequestArtifact(value.signingRequest)
|
|
return value
|
|
}
|
|
|
|
function sameJson(left, right) {
|
|
return JSON.stringify(left) === JSON.stringify(right)
|
|
}
|
|
|
|
export async function finalizeSshRelayRuntimeManifestAggregateCommand(input) {
|
|
const identity = commandIdentity(input)
|
|
const keys = await readAcceptedKeys(input.acceptedKeysPath)
|
|
const prior = normalizePreparedArtifact(
|
|
await readBoundedJson(
|
|
join(resolve(input.preparedDirectory), 'prepared-aggregate.json'),
|
|
'prepared aggregate'
|
|
)
|
|
)
|
|
const signingResult = await readBoundedJson(resolve(input.signingResultPath), 'signing result')
|
|
assertExactFields(signingResult, ['keyId', 'signature'], 'signing result')
|
|
const output = await exclusiveOutputDirectory(input.outputDirectory)
|
|
let created = false
|
|
try {
|
|
await mkdir(output, { mode: 0o700 })
|
|
created = true
|
|
const prepared = await collectAndPrepare(input, output, identity, input.signal)
|
|
const current = preparedArtifact(identity, keys.sha256, prepared)
|
|
if (!sameJson(prior, current)) {
|
|
throw new Error('SSH relay runtime manifest aggregate command prepared receipt drifted')
|
|
}
|
|
const finalized = finalizeSshRelayRuntimeManifestAggregate({
|
|
prepared,
|
|
signingResults: [signingResult],
|
|
acceptedKeys: keys.acceptedKeys
|
|
})
|
|
const assets = join(output, 'assets')
|
|
const evidence = join(output, 'evidence')
|
|
await Promise.all([mkdir(assets), mkdir(evidence)])
|
|
await writeFile(join(assets, finalized.manifestAsset.name), finalized.bytes, {
|
|
flag: 'wx',
|
|
mode: 0o600
|
|
})
|
|
await writeFile(
|
|
join(evidence, 'manifest-aggregate.json'),
|
|
canonicalJson({
|
|
schemaVersion: 1,
|
|
sourceSha: identity.sourceSha,
|
|
releaseTag: identity.releaseTag,
|
|
acceptedKeysSha256: keys.sha256,
|
|
inputTuplesSha256: finalized.inputTuplesSha256,
|
|
manifestAsset: finalized.manifestAsset
|
|
}),
|
|
{ flag: 'wx', mode: 0o600 }
|
|
)
|
|
await rm(join(output, 'aggregate-input'), { recursive: true, force: true })
|
|
return finalized
|
|
} catch (error) {
|
|
if (created) {
|
|
await rm(output, { recursive: true, force: true })
|
|
}
|
|
throw error
|
|
}
|
|
}
|
|
|
|
export function parseSshRelayRuntimeManifestAggregateCommandArguments(argv) {
|
|
const command = argv[0]
|
|
if (command !== 'prepare' && command !== 'finalize') {
|
|
throw new Error('SSH relay runtime manifest aggregate command requires prepare or finalize')
|
|
}
|
|
const fields = new Map([
|
|
['--artifacts-directory', 'artifactsDirectory'],
|
|
['--accepted-keys', 'acceptedKeysPath'],
|
|
['--output-directory', 'outputDirectory'],
|
|
['--source-sha', 'sourceSha'],
|
|
['--release-tag', 'releaseTag'],
|
|
['--created-at', 'createdAt'],
|
|
['--relay-protocol-version', 'relayProtocolVersion'],
|
|
['--prepared-directory', 'preparedDirectory'],
|
|
['--signing-result', 'signingResultPath']
|
|
])
|
|
const result = { command }
|
|
for (let index = 1; index < argv.length; index += 2) {
|
|
const field = fields.get(argv[index])
|
|
const value = argv[index + 1]
|
|
if (!field || !value || value.startsWith('--') || result[field]) {
|
|
throw new Error(
|
|
`Invalid SSH relay runtime manifest aggregate command argument: ${argv[index]}`
|
|
)
|
|
}
|
|
result[field] = field === 'relayProtocolVersion' ? Number(value) : value
|
|
}
|
|
const required = [
|
|
'artifactsDirectory',
|
|
'acceptedKeysPath',
|
|
'outputDirectory',
|
|
'sourceSha',
|
|
'releaseTag',
|
|
'createdAt',
|
|
'relayProtocolVersion'
|
|
]
|
|
if (command === 'finalize') {
|
|
required.push('preparedDirectory', 'signingResultPath')
|
|
}
|
|
for (const field of required) {
|
|
if (!result[field]) {
|
|
throw new Error(`Missing SSH relay runtime manifest aggregate command argument: ${field}`)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
async function main() {
|
|
const options = parseSshRelayRuntimeManifestAggregateCommandArguments(process.argv.slice(2))
|
|
const operation =
|
|
options.command === 'prepare'
|
|
? prepareSshRelayRuntimeManifestAggregateCommand
|
|
: finalizeSshRelayRuntimeManifestAggregateCommand
|
|
const result = await operation(options)
|
|
process.stdout.write(`${JSON.stringify({ inputTuplesSha256: result.inputTuplesSha256 })}\n`)
|
|
}
|
|
|
|
if (process.argv[1] && pathToFileURL(resolve(process.argv[1])).href === import.meta.url) {
|
|
main().catch((error) => {
|
|
process.stderr.write(
|
|
`SSH relay runtime manifest aggregate command failed: ${error.stack ?? error}\n`
|
|
)
|
|
process.exitCode = 1
|
|
})
|
|
}
|