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

@ -14,6 +14,7 @@ const tauriConfig = readJson('src-tauri/tauri.conf.json')
const capability = readJson('src-tauri/capabilities/default.json')
const broadcast = readJson('contracts/release-broadcast.schema.json')
const stageOne = readJson('contracts/stage-one-platform.json')
const publicRoute = readJson('server/release-broadcast/public-route.json')
test('clean Tauri foundation contains no inherited product updater endpoint', () => {
assert.deepEqual(foundation.upstream_product_update_endpoints, [])
@ -30,6 +31,11 @@ test('clean Tauri foundation contains no inherited product updater endpoint', ()
const source = readText(relative)
assert.doesNotMatch(source, /refactoringhq|tolaria|outline/i)
}
assert.equal(publicRoute.releaseEndpoint, 'https://guanghulab.com/hololake/releases/latest.json')
assert.equal(publicRoute.allowedMethods.join(','), 'GET,HEAD')
assert.equal(publicRoute.requestBodyAllowed, false)
assert.equal(publicRoute.automaticUpload, false)
assert.equal(publicRoute.automaticActivation, false)
})
test('release activation remains explicitly human controlled', () => {
@ -51,6 +57,12 @@ test('release activation remains explicitly human controlled', () => {
assert.equal(foundation.release_broadcast_activation_requires_exact_human_approval, true)
assert.equal(foundation.release_broadcast_activation_requires_repeated_expected_facts, true)
assert.equal(foundation.release_broadcast_operator_automatic_restart_allowed, false)
assert.equal(foundation.release_public_path_prefix, '/hololake/releases')
assert.equal(foundation.release_public_route_deployed, false)
assert.equal(publicRoute.publicPathPrefix, foundation.release_public_path_prefix)
assert.equal(publicRoute.proxyRequestUriPolicy, 'PRESERVE_FULL_PUBLIC_PATH')
assert.equal(publicRoute.frontDoorLoopbackPort, null)
assert.equal(publicRoute.deployed, false)
assert.equal(foundation.release_pipeline_automatic_upload_allowed, false)
assert.equal(
foundation.release_production_activation_state,

View file

@ -165,3 +165,27 @@ test('symlinked package inputs are rejected instead of followed', () => {
fs.rmSync(fixture.fixtureRoot, { recursive: true, force: true })
}
})
test('operator refuses a bundle whose packages escape the registered public path', () => {
const fixture = buildOperatorFixture()
try {
const latestPath = path.join(fixture.source, 'latest.json')
const latest = JSON.parse(fs.readFileSync(latestPath, 'utf8'))
latest.platforms['darwin-aarch64'].url = 'https://guanghulab.com/updates/0.2.0/HoloLake.app.tar.gz'
writeJson(latestPath, latest)
const broadcastSha256 = sha256(fs.readFileSync(latestPath))
const pipelinePath = path.join(fixture.source, 'pipeline-receipt.json')
const pipeline = JSON.parse(fs.readFileSync(pipelinePath, 'utf8'))
pipeline.broadcastSha256 = broadcastSha256
writeJson(pipelinePath, pipeline)
const approval = JSON.parse(fs.readFileSync(fixture.approval, 'utf8'))
approval.broadcastSha256 = broadcastSha256
writeJson(fixture.approval, approval)
assert.throws(
() => verifyReleaseBundle(fixture.source, fixture.approval),
/HOLOLAKE_RELEASE_OPERATOR_PACKAGE_PUBLIC_PREFIX_MISMATCH/,
)
} finally {
fs.rmSync(fixture.fixtureRoot, { recursive: true, force: true })
}
})

View file

@ -47,7 +47,7 @@ function buildReleaseRoot() {
notes: 'Signed release',
platforms: {
'darwin-aarch64': {
url: `https://release.guanghu.test/releases/0.2.0/${packageName}`,
url: `https://release.guanghu.test/hololake/releases/0.2.0/${packageName}`,
signature: 'trusted-updater-signature',
size: packageBytes.length,
sha256: sha256(packageBytes),
@ -105,6 +105,10 @@ test('empty release root stays healthy but returns Tauri-compatible 204 no updat
assert.equal(health.status, 200)
assert.deepEqual((await health.json()).upstreamUpdateSources, [])
assert.equal((await fetch(`${base}/latest.json`)).status, 204)
assert.equal((await fetch(`${base}/hololake/releases/latest.json`)).status, 204)
const publicHealth = await fetch(`${base}/hololake/releases/health`)
assert.equal(publicHealth.status, 200)
assert.equal((await publicHealth.json()).releaseEndpointPath, '/hololake/releases/latest.json')
})
})
@ -127,7 +131,10 @@ test('only an exact human-approved signed notarized evidence chain becomes reada
const latest = await fetch(`${base}/latest.json`)
assert.equal(latest.status, 200)
assert.equal((await latest.json()).releaseId, 'GH-HOLOLAKE-RELEASE-0.2.0')
const updater = await fetch(`${base}/releases/0.2.0/HoloLake.app.tar.gz`)
const publicLatest = await fetch(`${base}/hololake/releases/latest.json`)
assert.equal(publicLatest.status, 200)
assert.equal((await publicLatest.json()).releaseId, 'GH-HOLOLAKE-RELEASE-0.2.0')
const updater = await fetch(`${base}/hololake/releases/0.2.0/HoloLake.app.tar.gz`)
assert.equal(updater.status, 200)
assert.deepEqual(Buffer.from(await updater.arrayBuffer()), fixture.packageBytes)
assert.equal((await fetch(`${base}/unknown`)).status, 404)
@ -151,3 +158,27 @@ test('a symlinked immutable current directory is recognized as the intended exec
fs.symlinkSync(versionDirectory, current)
assert.equal(isMainModule(path.join(current, 'server.mjs'), new URL(`file://${copy}`)), true)
})
test('a package outside the registered public prefix locks the release', () => {
const fixture = buildReleaseRoot()
const latestPath = path.join(fixture.root, 'releases', '0.2.0', 'latest.json')
const latest = JSON.parse(fs.readFileSync(latestPath, 'utf8'))
latest.platforms['darwin-aarch64'].url = 'https://release.guanghu.test/releases/0.2.0/HoloLake.app.tar.gz'
writeJson(latestPath, latest)
const broadcastSha256 = sha256(fs.readFileSync(latestPath))
const pipelinePath = path.join(fixture.root, 'releases', '0.2.0', 'pipeline-receipt.json')
const pipeline = JSON.parse(fs.readFileSync(pipelinePath, 'utf8'))
pipeline.broadcastSha256 = broadcastSha256
writeJson(pipelinePath, pipeline)
const approvalPath = path.join(fixture.root, 'releases', '0.2.0', 'human-approval.json')
const approval = JSON.parse(fs.readFileSync(approvalPath, 'utf8'))
approval.broadcastSha256 = broadcastSha256
writeJson(approvalPath, approval)
const activationPath = path.join(fixture.root, 'ACTIVE.json')
const activation = JSON.parse(fs.readFileSync(activationPath, 'utf8'))
activation.broadcastSha256 = broadcastSha256
writeJson(activationPath, activation)
const state = loadRuntimeState(fixture.root)
assert.equal(state.state, 'LOCKED_INVALID_RELEASE_EVIDENCE')
assert.equal(state.reasonCode, 'HOLOLAKE_RELEASE_PACKAGE_PUBLIC_PREFIX_MISMATCH')
})

View file

@ -8,6 +8,8 @@ import path from 'node:path'
import { fileURLToPath } from 'node:url'
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..')
const PUBLIC_RELEASE_ENDPOINT_PATH = '/hololake/releases/latest.json'
const PUBLIC_RELEASE_PREFIX = '/hololake/releases'
const fail = (code) => {
throw new Error(code)
@ -28,7 +30,15 @@ export function validateReleaseTrust(trust) {
if (!Array.isArray(trust.allowedReleaseHosts) || trust.allowedReleaseHosts.length !== 1) fail('HOLOLAKE_RELEASE_PIPELINE_EXACT_HOST_REQUIRED')
const endpoint = new URL(trust.endpoints[0])
const host = requireText(trust.allowedReleaseHosts[0], 'HOLOLAKE_RELEASE_PIPELINE_HOST_REQUIRED')
if (endpoint.protocol !== 'https:' || endpoint.hostname !== host || endpoint.username || endpoint.password) {
if (
endpoint.protocol !== 'https:' ||
endpoint.hostname !== host ||
endpoint.username ||
endpoint.password ||
endpoint.search ||
endpoint.hash ||
endpoint.pathname !== PUBLIC_RELEASE_ENDPOINT_PATH
) {
fail('HOLOLAKE_RELEASE_PIPELINE_ENDPOINT_NOT_HOLOLAKE_HTTPS')
}
if (requireText(trust.publicKey, 'HOLOLAKE_RELEASE_PIPELINE_UPDATER_PUBLIC_KEY_REQUIRED').length < 32) {
@ -50,7 +60,15 @@ export function validateReleaseInput(input, trustFacts) {
if (!/^[a-f0-9]{40}$/.test(input.sourceCommit || '')) fail('HOLOLAKE_RELEASE_PIPELINE_SOURCE_COMMIT_INVALID')
if (input.releaseTag !== `v${version}`) fail('HOLOLAKE_RELEASE_PIPELINE_IMMUTABLE_TAG_INVALID')
const packageUrl = new URL(requireText(input.packageUrl, 'HOLOLAKE_RELEASE_PIPELINE_PACKAGE_URL_REQUIRED'))
if (packageUrl.protocol !== 'https:' || packageUrl.hostname !== trustFacts.host || packageUrl.username || packageUrl.password) {
if (
packageUrl.protocol !== 'https:' ||
packageUrl.hostname !== trustFacts.host ||
packageUrl.username ||
packageUrl.password ||
packageUrl.search ||
packageUrl.hash ||
!packageUrl.pathname.startsWith(`${PUBLIC_RELEASE_PREFIX}/`)
) {
fail('HOLOLAKE_RELEASE_PIPELINE_PACKAGE_HOST_NOT_TRUSTED')
}
if (!Array.isArray(input.features) || input.features.length === 0 || input.features.some((item) => typeof item !== 'string' || !item.trim())) {

View file

@ -10,7 +10,7 @@ import {
const readyTrust = () => ({
schema: 'hololake.release-trust/v1',
state: 'PROVISIONED',
endpoints: ['https://release.guanghu.test/latest.json'],
endpoints: ['https://release.guanghu.test/hololake/releases/latest.json'],
publicKey: 'A'.repeat(64),
allowedReleaseHosts: ['release.guanghu.test'],
automaticCheckOnStartup: false,
@ -28,7 +28,7 @@ const readyInput = () => ({
releaseTag: 'v0.2.0',
sourceCommit: 'a'.repeat(40),
platformCode: 'darwin-aarch64',
packageUrl: 'https://release.guanghu.test/releases/0.2.0/HoloLake.app.tar.gz',
packageUrl: 'https://release.guanghu.test/hololake/releases/0.2.0/HoloLake.app.tar.gz',
appleTeamIdentifier: '825A9L3G7Q',
notes: 'Signed release',
features: ['Persistent direct connection'],
@ -53,6 +53,10 @@ test('release package must use the exact registered HoloLake HTTPS host and immu
wrongHost.packageUrl = 'https://github.com/example/HoloLake.app.tar.gz'
assert.throws(() => validateReleaseInput(wrongHost, trust), /PACKAGE_HOST_NOT_TRUSTED/)
const wrongPath = readyInput()
wrongPath.packageUrl = 'https://release.guanghu.test/updates/HoloLake.app.tar.gz'
assert.throws(() => validateReleaseInput(wrongPath, trust), /PACKAGE_HOST_NOT_TRUSTED/)
const wrongTag = readyInput()
wrongTag.releaseTag = 'latest'
assert.throws(() => validateReleaseInput(wrongTag, trust), /IMMUTABLE_TAG_INVALID/)