mirror of
https://github.com/stablyai/orca.git
synced 2026-10-04 16:02:08 +00:00
* feat(runtime): pin the Node 24.21.0 server runtime with an offline CI check Add src/shared/node-runtime-pin.ts (NODE_RUNTIME_PIN, SERVER_TARGETS, NODE_RUNTIME_ASSETS for all 8 server targets plus the headers tarball), generated by config/scripts/update-node-runtime-pin.mjs from the nodejs.org and unofficial-builds SHASUMS. check-node-runtime-pin.mjs verifies, with no network, that the pin tracks the locked Electron, matches engines.node's major, and covers exactly SERVER_TARGETS; it runs in the static analysis job. ORCAD_BUN_TARGETS consumers now read SERVER_TARGETS so there is one target list; orcad's Bun runtime and build output are unchanged. * fix(runtime): reject a pinned archive that belongs to another target --------- Co-authored-by: m4air <m4air@m4airs-Air.localdomain>
87 lines
3.1 KiB
JavaScript
87 lines
3.1 KiB
JavaScript
import { createHash } from 'node:crypto'
|
|
import { mkdir, readFile, writeFile } from 'node:fs/promises'
|
|
import { createRequire } from 'node:module'
|
|
import { join, resolve } from 'node:path'
|
|
import { x as extractTar } from 'tar'
|
|
import { parseAllDocuments } from 'yaml'
|
|
import { SERVER_TARGETS } from '../../src/shared/node-runtime-pin.ts'
|
|
|
|
const root = resolve(import.meta.dirname, '../..')
|
|
const require = createRequire(import.meta.url)
|
|
const archiveLimit = 16 * 1024 * 1024
|
|
|
|
export function parseWatcherLockfile(contents) {
|
|
const packages = {}
|
|
for (const document of parseAllDocuments(contents)) {
|
|
if (document.errors.length) {
|
|
throw document.errors[0]
|
|
}
|
|
Object.assign(packages, document.toJS()?.packages)
|
|
}
|
|
return { packages }
|
|
}
|
|
|
|
export function watcherPackageIdentity(target, version, lockfile) {
|
|
if (!SERVER_TARGETS.includes(target)) {
|
|
throw new Error(`Unsupported watcher target: ${target}`)
|
|
}
|
|
const name = `@parcel/watcher-${target}`
|
|
const integrity = lockfile.packages?.[`${name}@${version}`]?.resolution?.integrity
|
|
if (typeof integrity !== 'string' || !/^sha512-[A-Za-z0-9+/]+=*$/.test(integrity)) {
|
|
throw new Error(`The lockfile does not pin ${name}@${version}`)
|
|
}
|
|
return {
|
|
integrity,
|
|
url: `https://registry.npmjs.org/${name}/-/watcher-${target}-${version}.tgz`
|
|
}
|
|
}
|
|
|
|
export function verifyWatcherArchive(bytes, integrity) {
|
|
if (bytes.length > archiveLimit) {
|
|
throw new Error('Watcher archive exceeds the size limit')
|
|
}
|
|
if (`sha512-${createHash('sha512').update(bytes).digest('base64')}` !== integrity) {
|
|
throw new Error('Watcher archive does not match the lockfile integrity')
|
|
}
|
|
}
|
|
|
|
// Fetch only these small release assets; ordinary installs remain host-only.
|
|
export async function materializeWatcherPackage(target) {
|
|
const { version } = require('@parcel/watcher/package.json')
|
|
const lockfile = parseWatcherLockfile(await readFile(join(root, 'pnpm-lock.yaml'), 'utf8'))
|
|
const { integrity, url } = watcherPackageIdentity(target, version, lockfile)
|
|
const cache = join(root, 'out', '.orcad-watchers', version, target)
|
|
const archivePath = join(cache, 'package.tgz')
|
|
await mkdir(cache, { recursive: true })
|
|
let bytes
|
|
try {
|
|
bytes = await readFile(archivePath)
|
|
verifyWatcherArchive(bytes, integrity)
|
|
} catch {
|
|
const response = await fetch(url, { signal: AbortSignal.timeout(60_000) })
|
|
if (!response.ok || !response.body) {
|
|
await response.body?.cancel()
|
|
throw new Error(`Watcher download failed: ${response.status} ${response.statusText}`)
|
|
}
|
|
const chunks = []
|
|
let length = 0
|
|
for await (const chunk of response.body) {
|
|
length += chunk.length
|
|
if (length > archiveLimit) {
|
|
throw new Error('Watcher archive exceeds the size limit')
|
|
}
|
|
chunks.push(chunk)
|
|
}
|
|
bytes = Buffer.concat(chunks)
|
|
verifyWatcherArchive(bytes, integrity)
|
|
await writeFile(archivePath, bytes)
|
|
}
|
|
await extractTar({
|
|
file: archivePath,
|
|
cwd: cache,
|
|
strict: true,
|
|
filter: (path, entry) => path === 'package/watcher.node' && entry.type === 'File'
|
|
})
|
|
return join(cache, 'package', 'watcher.node')
|
|
}
|