feat(hololake): bind release chain to public path namespace

This commit is contained in:
冰朔 2026-08-13 19:11:26 +08:00
commit 9006075310
13 changed files with 223 additions and 29 deletions

View file

@ -7,6 +7,7 @@ import path from 'node:path'
import { fileURLToPath } from 'node:url'
const MAX_CONTROL_BYTES = 1024 * 1024
export const DEFAULT_PUBLIC_PREFIX = '/hololake/releases'
const VERSION_PATTERN = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/
const SHA256_PATTERN = /^[a-f0-9]{64}$/
@ -21,6 +22,18 @@ const requireText = (value, code) => {
return value.trim()
}
export function normalizePublicPrefix(value) {
const prefix = requireText(value, 'HOLOLAKE_RELEASE_PUBLIC_PREFIX_REQUIRED')
if (!prefix.startsWith('/') || prefix.endsWith('/') || prefix.includes('//') || prefix.includes('?') || prefix.includes('#')) {
fail('HOLOLAKE_RELEASE_PUBLIC_PREFIX_INVALID')
}
const normalized = path.posix.normalize(prefix)
if (normalized !== prefix || normalized === '/' || normalized.split('/').some((segment) => segment === '..')) {
fail('HOLOLAKE_RELEASE_PUBLIC_PREFIX_INVALID')
}
return prefix
}
function trustedRegularFile(file, { enforceRootOwner, maxBytes = null }) {
const info = fs.lstatSync(file)
if (!info.isFile() || info.isSymbolicLink()) fail('HOLOLAKE_RELEASE_FILE_NOT_REGULAR')
@ -43,13 +56,16 @@ function readTrustedJson(file, options) {
return { bytes: fs.readFileSync(file), value: JSON.parse(fs.readFileSync(file, 'utf8')) }
}
function validatePlatform(platform, releaseDirectory, enforceRootOwner, sourceCommit) {
function validatePlatform(platform, releaseDirectory, enforceRootOwner, sourceCommit, publicPrefix) {
const url = new URL(requireText(platform?.url, 'HOLOLAKE_RELEASE_PACKAGE_URL_REQUIRED'))
if (url.protocol !== 'https:' || url.username || url.password || url.search || url.hash) {
fail('HOLOLAKE_RELEASE_PACKAGE_URL_INVALID')
}
const packageName = decodeURIComponent(path.posix.basename(url.pathname))
if (!packageName || packageName === '.' || packageName === '..') fail('HOLOLAKE_RELEASE_PACKAGE_NAME_INVALID')
if (!url.pathname.startsWith(`${publicPrefix}/`) || url.pathname === `${publicPrefix}/latest.json` || url.pathname === `${publicPrefix}/health`) {
fail('HOLOLAKE_RELEASE_PACKAGE_PUBLIC_PREFIX_MISMATCH')
}
const packagePath = safeRelative(releaseDirectory, packageName, 'HOLOLAKE_RELEASE_PACKAGE_PATH_INVALID')
const packageInfo = trustedRegularFile(packagePath, { enforceRootOwner })
if (!Number.isSafeInteger(platform.size) || platform.size <= 0 || platform.size !== packageInfo.size) {
@ -82,10 +98,10 @@ function validatePlatform(platform, releaseDirectory, enforceRootOwner, sourceCo
return { pathname: url.pathname, file: packagePath, size: packageInfo.size }
}
function loadActiveRelease(stateRoot, enforceRootOwner) {
function loadActiveRelease(stateRoot, enforceRootOwner, publicPrefix) {
const activationPath = path.join(stateRoot, 'ACTIVE.json')
if (!fs.existsSync(activationPath)) {
return { state: 'EMPTY_FAIL_CLOSED', release: null, reasonCode: null }
return { state: 'EMPTY_FAIL_CLOSED', release: null, reasonCode: null, publicPrefix }
}
const activation = readTrustedJson(activationPath, { enforceRootOwner }).value
if (
@ -135,7 +151,7 @@ function loadActiveRelease(stateRoot, enforceRootOwner) {
const releaseDirectory = path.dirname(broadcastPath)
const packages = new Map()
for (const platform of Object.values(broadcast.platforms)) {
const accepted = validatePlatform(platform, releaseDirectory, enforceRootOwner, pipelineReceipt.sourceCommit)
const accepted = validatePlatform(platform, releaseDirectory, enforceRootOwner, pipelineReceipt.sourceCommit, publicPrefix)
if (packages.has(accepted.pathname)) fail('HOLOLAKE_RELEASE_PACKAGE_ROUTE_COLLISION')
packages.set(accepted.pathname, accepted)
}
@ -143,18 +159,21 @@ function loadActiveRelease(stateRoot, enforceRootOwner) {
state: 'READY_SIGNED_NOTARIZED_BROADCAST',
release: { releaseId, version, broadcastBytes: broadcastDocument.bytes, packages },
reasonCode: null,
publicPrefix,
}
}
export function loadRuntimeState(stateRoot, { enforceRootOwner = false } = {}) {
export function loadRuntimeState(stateRoot, { enforceRootOwner = false, publicPrefix = DEFAULT_PUBLIC_PREFIX } = {}) {
const resolvedRoot = path.resolve(stateRoot)
try {
return loadActiveRelease(resolvedRoot, enforceRootOwner)
const normalizedPrefix = normalizePublicPrefix(publicPrefix)
return loadActiveRelease(resolvedRoot, enforceRootOwner, normalizedPrefix)
} catch (error) {
return {
state: 'LOCKED_INVALID_RELEASE_EVIDENCE',
release: null,
reasonCode: error instanceof Error ? error.message : 'HOLOLAKE_RELEASE_UNKNOWN_FAILURE',
publicPrefix: null,
}
}
}
@ -178,7 +197,9 @@ export function createReleaseServer(runtimeState) {
return response.end()
}
const pathname = new URL(request.url || '/', 'http://127.0.0.1').pathname
if (pathname === '/health') {
const publicHealthPath = runtimeState.publicPrefix ? `${runtimeState.publicPrefix}/health` : null
const publicLatestPath = runtimeState.publicPrefix ? `${runtimeState.publicPrefix}/latest.json` : null
if (pathname === '/health' || pathname === publicHealthPath) {
const status = runtimeState.state === 'LOCKED_INVALID_RELEASE_EVIDENCE' ? 503 : 200
return jsonResponse(response, status, {
schema: 'hololake.release-broadcast-health/v1',
@ -187,11 +208,15 @@ export function createReleaseServer(runtimeState) {
automaticUpload: false,
automaticActivation: false,
upstreamUpdateSources: [],
...(runtimeState.publicPrefix ? {
publicPathPrefix: runtimeState.publicPrefix,
releaseEndpointPath: `${runtimeState.publicPrefix}/latest.json`,
} : {}),
...(runtimeState.release ? { releaseId: runtimeState.release.releaseId, version: runtimeState.release.version } : {}),
...(runtimeState.reasonCode ? { reasonCode: runtimeState.reasonCode } : {}),
})
}
if (pathname === '/latest.json') {
if (pathname === '/latest.json' || pathname === publicLatestPath) {
if (runtimeState.state === 'EMPTY_FAIL_CLOSED') {
response.writeHead(204, { 'Cache-Control': 'no-store' })
return response.end()
@ -230,7 +255,11 @@ export function main(env = process.env) {
const port = Number(env.HOLOLAKE_RELEASE_PORT || 3940)
if (!Number.isInteger(port) || port < 1024 || port > 65535) fail('HOLOLAKE_RELEASE_PORT_INVALID')
const stateRoot = path.resolve(env.HOLOLAKE_RELEASE_STATE_ROOT || '/var/lib/guanghu/hololake-release-broadcast')
const runtimeState = loadRuntimeState(stateRoot, { enforceRootOwner: env.HOLOLAKE_RELEASE_ENFORCE_ROOT_OWNER === '1' })
const publicPrefix = env.HOLOLAKE_RELEASE_PUBLIC_PREFIX || DEFAULT_PUBLIC_PREFIX
const runtimeState = loadRuntimeState(stateRoot, {
enforceRootOwner: env.HOLOLAKE_RELEASE_ENFORCE_ROOT_OWNER === '1',
publicPrefix,
})
const server = createReleaseServer(runtimeState)
server.on('clientError', (_error, socket) => socket.end('HTTP/1.1 400 Bad Request\r\nConnection: close\r\n\r\n'))
server.listen(port, host, () => {