feat(hololake): add explicit JD release activation operator

This commit is contained in:
冰朔 2026-08-13 18:54:04 +08:00
commit 4357d25ea8
5 changed files with 608 additions and 0 deletions

View file

@ -23,6 +23,10 @@
"release_broadcast_candidate_service_implemented": true,
"release_broadcast_candidate_service_default_state": "EMPTY_FAIL_CLOSED_LOOPBACK_ONLY",
"release_broadcast_candidate_service_source": "server/release-broadcast/server.mjs",
"release_broadcast_explicit_operator_activation_implemented": true,
"release_broadcast_activation_requires_exact_human_approval": true,
"release_broadcast_activation_requires_repeated_expected_facts": true,
"release_broadcast_operator_automatic_restart_allowed": false,
"release_pipeline_automatic_upload_allowed": false,
"release_production_activation_state": "BLOCKED_PENDING_PUBLIC_HTTPS_TRUST_UPDATER_KEY_PIPELINE_EXECUTION_AND_APPLE_NOTARIZATION",
"tauri_update_artifacts_enabled": false,

View file

@ -47,6 +47,10 @@ test('release activation remains explicitly human controlled', () => {
assert.equal(foundation.release_signed_notarized_pipeline_implemented, true)
assert.equal(foundation.release_broadcast_candidate_service_implemented, true)
assert.equal(foundation.release_broadcast_candidate_service_default_state, 'EMPTY_FAIL_CLOSED_LOOPBACK_ONLY')
assert.equal(foundation.release_broadcast_explicit_operator_activation_implemented, true)
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_pipeline_automatic_upload_allowed, false)
assert.equal(
foundation.release_production_activation_state,

View file

@ -0,0 +1,167 @@
import assert from 'node:assert/strict'
import crypto from 'node:crypto'
import fs from 'node:fs'
import os from 'node:os'
import path from 'node:path'
import test from 'node:test'
import { activateRelease, verifyReleaseBundle } from '../server/release-broadcast/operator.mjs'
import { loadRuntimeState } from '../server/release-broadcast/server.mjs'
const sha256 = (bytes) => crypto.createHash('sha256').update(bytes).digest('hex')
const writeJson = (file, value) => fs.writeFileSync(file, `${JSON.stringify(value, null, 2)}\n`, { mode: 0o600 })
function buildOperatorFixture() {
const fixtureRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'hololake-release-operator-fixture-'))
const source = path.join(fixtureRoot, 'source')
const approvals = path.join(fixtureRoot, 'approvals')
const stateRoot = path.join(fixtureRoot, 'state')
for (const directory of [source, approvals, stateRoot]) fs.mkdirSync(directory, { mode: 0o700 })
const packageName = 'HoloLake.app.tar.gz'
const packageBytes = Buffer.from('signed-notarized-updater-package')
const sourceCommit = '2'.repeat(40)
fs.writeFileSync(path.join(source, packageName), packageBytes, { mode: 0o600 })
writeJson(path.join(source, 'HOLOLAKE-CODESIGN.json'), {
schema: 'hololake.platform-code-signature-receipt/v1',
state: 'DEVELOPER_ID_SIGNATURE_STRICT_AND_GATEKEEPER_ACCEPTED',
sourceCommit,
})
writeJson(path.join(source, 'HOLOLAKE-NOTARIZATION.json'), {
schema: 'hololake.apple-notarization-receipt/v1',
state: 'APPLE_NOTARIZATION_ACCEPTED_AND_STAPLED',
sourceCommit,
})
const broadcast = {
schema: 'hololake.release-broadcast/v1',
releaseId: 'GH-HOLOLAKE-RELEASE-0.2.0',
version: '0.2.0',
pub_date: '2026-08-13T10:00:00.000Z',
notes: 'Signed release',
platforms: {
'darwin-aarch64': {
url: `https://guanghulab.com/hololake/releases/0.2.0/${packageName}`,
signature: 'trusted-updater-signature',
size: packageBytes.length,
sha256: sha256(packageBytes),
platformCodeSignatureReceipt: 'HOLOLAKE-CODESIGN',
notarizationReceipt: 'HOLOLAKE-NOTARIZATION',
},
},
hololake: {
features: ['Stage one'],
fixes: [],
compatibility: { minimumVersion: '0.1.0', dataMigrationRequired: false },
restart: { required: true, automaticAllowed: false },
rollback: { supported: true, healthReceiptRequired: true, previousVersion: '0.1.0' },
},
}
const broadcastPath = path.join(source, 'latest.json')
writeJson(broadcastPath, broadcast)
const broadcastSha256 = sha256(fs.readFileSync(broadcastPath))
writeJson(path.join(source, 'pipeline-receipt.json'), {
schema: 'hololake.signed-release-pipeline-receipt/v1',
state: 'SIGNED_NOTARIZED_RELEASE_BROADCAST_READY_FOR_JD_CONTROLLER_UPLOAD',
sourceCommit,
broadcastSha256,
automaticUpload: false,
automaticActivation: false,
})
const approval = path.join(approvals, 'approval.json')
writeJson(approval, {
schema: 'hololake.release-broadcast-human-approval/v1',
state: 'HUMAN_APPROVED_EXACT_SIGNED_NOTARIZED_RELEASE',
approvalId: 'GH-HUMAN-RELEASE-APPROVAL-002',
releaseId: broadcast.releaseId,
version: broadcast.version,
broadcastSha256,
})
return {
fixtureRoot,
source,
approval,
stateRoot,
expected: { releaseId: broadcast.releaseId, version: broadcast.version, sourceCommit, broadcastSha256 },
}
}
test('verify reconstructs and validates an exact private candidate without mutating state', () => {
const fixture = buildOperatorFixture()
try {
const result = verifyReleaseBundle(fixture.source, fixture.approval)
assert.equal(result.state, 'EXACT_SIGNED_NOTARIZED_HUMAN_APPROVED_BUNDLE_VERIFIED')
assert.equal(result.broadcastSha256, fixture.expected.broadcastSha256)
assert.equal(result.artifacts.some((artifact) => artifact.name === 'HoloLake.app.tar.gz'), true)
assert.deepEqual(fs.readdirSync(fixture.stateRoot), [])
} finally {
fs.rmSync(fixture.fixtureRoot, { recursive: true, force: true })
}
})
test('activation repeats expected facts, commits atomically, and still requires explicit restart', () => {
const fixture = buildOperatorFixture()
try {
const receipt = activateRelease({
sourceDirectory: fixture.source,
humanApprovalPath: fixture.approval,
stateRoot: fixture.stateRoot,
expected: fixture.expected,
enforceRootOwner: false,
})
assert.equal(receipt.state, 'ACTIVATED_EXPLICIT_SERVICE_RESTART_REQUIRED')
assert.equal(receipt.automaticUpload, false)
assert.equal(receipt.automaticActivation, false)
assert.equal(receipt.automaticRestart, false)
assert.equal(loadRuntimeState(fixture.stateRoot).state, 'READY_SIGNED_NOTARIZED_BROADCAST')
assert.equal(fs.existsSync(path.join(fixture.stateRoot, '.operator-lock')), false)
} finally {
fs.rmSync(fixture.fixtureRoot, { recursive: true, force: true })
}
})
test('expected-fact mismatch performs no activation or release staging', () => {
const fixture = buildOperatorFixture()
try {
assert.throws(() => activateRelease({
sourceDirectory: fixture.source,
humanApprovalPath: fixture.approval,
stateRoot: fixture.stateRoot,
expected: { ...fixture.expected, broadcastSha256: '3'.repeat(64) },
enforceRootOwner: false,
}), /HOLOLAKE_RELEASE_OPERATOR_EXPECTED_BROADCAST_SHA256_MISMATCH/)
assert.deepEqual(fs.readdirSync(fixture.stateRoot), [])
} finally {
fs.rmSync(fixture.fixtureRoot, { recursive: true, force: true })
}
})
test('human approval cannot be reused after broadcast bytes change', () => {
const fixture = buildOperatorFixture()
try {
const latestPath = path.join(fixture.source, 'latest.json')
const latest = JSON.parse(fs.readFileSync(latestPath, 'utf8'))
latest.notes = 'Changed after approval'
writeJson(latestPath, latest)
assert.throws(
() => verifyReleaseBundle(fixture.source, fixture.approval),
/HOLOLAKE_RELEASE_OPERATOR_PIPELINE_RECEIPT_INVALID/,
)
} finally {
fs.rmSync(fixture.fixtureRoot, { recursive: true, force: true })
}
})
test('symlinked package inputs are rejected instead of followed', () => {
const fixture = buildOperatorFixture()
try {
const packagePath = path.join(fixture.source, 'HoloLake.app.tar.gz')
const moved = path.join(fixture.fixtureRoot, 'moved-package')
fs.renameSync(packagePath, moved)
fs.symlinkSync(moved, packagePath)
assert.throws(
() => verifyReleaseBundle(fixture.source, fixture.approval),
/HOLOLAKE_RELEASE_OPERATOR_FILE_INVALID/,
)
} finally {
fs.rmSync(fixture.fixtureRoot, { recursive: true, force: true })
}
})

View file

@ -14,3 +14,30 @@ service.
The service listens only on `127.0.0.1`. Public HTTPS routing, updater trust-key
provisioning, artifact upload, activation, and desktop rollout are independent
deployment gates.
`operator.mjs` supplies the separate, root-operated verification and activation
boundary. `verify` reconstructs a private candidate tree and accepts it only when
the broadcast, pipeline receipt, package bytes, Developer ID receipt, Apple
notarization receipt, and exact human approval all agree. `activate` additionally
requires the operator to repeat the expected release id, version, source commit,
and broadcast SHA-256. It copies only referenced immutable artifacts, commits
`ACTIVE.json` atomically, and reports that an explicit service restart is still
required. It never uploads, activates, or restarts on its own.
```text
node operator.mjs verify \
--source /secure/release/out/0.2.0 \
--human-approval /secure/approvals/0.2.0.json
sudo node operator.mjs activate \
--source /secure/release/out/0.2.0 \
--human-approval /secure/approvals/0.2.0.json \
--state-root /var/lib/guanghu/hololake-release-broadcast \
--expect-release-id GH-HOLOLAKE-RELEASE-0.2.0 \
--expect-version 0.2.0 \
--expect-source-commit 0000000000000000000000000000000000000000 \
--expect-broadcast-sha256 0000000000000000000000000000000000000000000000000000000000000000
```
The zeros above are placeholders, not deployable values. A real activation must
use the exact facts printed by `verify` and a separately issued human approval.

View file

@ -0,0 +1,406 @@
#!/usr/bin/env node
import crypto from 'node:crypto'
import fs from 'node:fs'
import os from 'node:os'
import path from 'node:path'
import { isMainModule, loadRuntimeState } from './server.mjs'
const MAX_CONTROL_BYTES = 1024 * 1024
const SHA256_PATTERN = /^[a-f0-9]{64}$/
const SOURCE_COMMIT_PATTERN = /^[a-f0-9]{40}$/
const VERSION_PATTERN = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/
const fail = (code) => {
throw new Error(code)
}
const sha256 = (bytes) => crypto.createHash('sha256').update(bytes).digest('hex')
const requireText = (value, code) => {
if (typeof value !== 'string' || value.trim() === '') fail(code)
return value.trim()
}
function requireTrustedDirectory(directory, { enforceRootOwner = false } = {}) {
const info = fs.lstatSync(directory)
if (!info.isDirectory() || info.isSymbolicLink()) fail('HOLOLAKE_RELEASE_OPERATOR_DIRECTORY_INVALID')
if ((info.mode & 0o022) !== 0) fail('HOLOLAKE_RELEASE_OPERATOR_DIRECTORY_WRITABLE_BY_NON_OWNER')
if (enforceRootOwner && info.uid !== 0) fail('HOLOLAKE_RELEASE_OPERATOR_DIRECTORY_NOT_ROOT_OWNED')
return info
}
function requireTrustedFile(file, { enforceRootOwner = false, maxBytes = null } = {}) {
const info = fs.lstatSync(file)
if (!info.isFile() || info.isSymbolicLink()) fail('HOLOLAKE_RELEASE_OPERATOR_FILE_INVALID')
if ((info.mode & 0o022) !== 0) fail('HOLOLAKE_RELEASE_OPERATOR_FILE_WRITABLE_BY_NON_OWNER')
if (enforceRootOwner && info.uid !== 0) fail('HOLOLAKE_RELEASE_OPERATOR_FILE_NOT_ROOT_OWNED')
if (maxBytes !== null && info.size > maxBytes) fail('HOLOLAKE_RELEASE_OPERATOR_CONTROL_FILE_TOO_LARGE')
return info
}
function readJson(file, { enforceRootOwner = false } = {}) {
requireTrustedFile(file, { enforceRootOwner, maxBytes: MAX_CONTROL_BYTES })
const bytes = fs.readFileSync(file)
return { bytes, value: JSON.parse(bytes.toString('utf8')) }
}
function directFile(directory, name, code) {
const value = requireText(name, code)
if (value !== path.basename(value) || value === '.' || value === '..' || value.includes('\0')) fail(code)
const resolved = path.resolve(directory, value)
if (path.dirname(resolved) !== directory) fail(code)
return resolved
}
function packageNameFromUrl(value) {
const url = new URL(requireText(value, 'HOLOLAKE_RELEASE_OPERATOR_PACKAGE_URL_REQUIRED'))
if (url.protocol !== 'https:' || url.username || url.password || url.search || url.hash) {
fail('HOLOLAKE_RELEASE_OPERATOR_PACKAGE_URL_INVALID')
}
let packageName
try {
packageName = decodeURIComponent(path.posix.basename(url.pathname))
} catch {
fail('HOLOLAKE_RELEASE_OPERATOR_PACKAGE_URL_INVALID')
}
if (!packageName || packageName === '.' || packageName === '..') fail('HOLOLAKE_RELEASE_OPERATOR_PACKAGE_NAME_INVALID')
return packageName
}
function addArtifact(artifacts, source, name, type) {
const previous = artifacts.get(name)
if (previous && previous.source !== source) fail('HOLOLAKE_RELEASE_OPERATOR_ARTIFACT_NAME_COLLISION')
artifacts.set(name, { source, name, type })
}
export function inspectReleaseBundle(sourceDirectory, humanApprovalPath, { enforceRootOwner = false } = {}) {
const source = path.resolve(sourceDirectory)
requireTrustedDirectory(source, { enforceRootOwner })
const latestPath = directFile(source, 'latest.json', 'HOLOLAKE_RELEASE_OPERATOR_BROADCAST_PATH_INVALID')
const pipelinePath = directFile(source, 'pipeline-receipt.json', 'HOLOLAKE_RELEASE_OPERATOR_PIPELINE_PATH_INVALID')
const approvalPath = path.resolve(humanApprovalPath)
const latestDocument = readJson(latestPath, { enforceRootOwner })
const pipelineReceipt = readJson(pipelinePath, { enforceRootOwner }).value
const approvalReceipt = readJson(approvalPath, { enforceRootOwner }).value
const broadcast = latestDocument.value
const broadcastSha256 = sha256(latestDocument.bytes)
if (broadcast?.schema !== 'hololake.release-broadcast/v1') fail('HOLOLAKE_RELEASE_OPERATOR_BROADCAST_INVALID')
const releaseId = requireText(broadcast.releaseId, 'HOLOLAKE_RELEASE_OPERATOR_RELEASE_ID_REQUIRED')
const version = requireText(broadcast.version, 'HOLOLAKE_RELEASE_OPERATOR_VERSION_REQUIRED')
if (!VERSION_PATTERN.test(version)) fail('HOLOLAKE_RELEASE_OPERATOR_VERSION_INVALID')
if (
broadcast?.hololake?.restart?.required !== true ||
broadcast?.hololake?.restart?.automaticAllowed !== false ||
broadcast?.hololake?.rollback?.supported !== true ||
broadcast?.hololake?.rollback?.healthReceiptRequired !== true ||
!broadcast.platforms ||
typeof broadcast.platforms !== 'object' ||
Array.isArray(broadcast.platforms) ||
Object.keys(broadcast.platforms).length === 0
) fail('HOLOLAKE_RELEASE_OPERATOR_BROADCAST_POLICY_INVALID')
if (
pipelineReceipt?.schema !== 'hololake.signed-release-pipeline-receipt/v1' ||
pipelineReceipt?.state !== 'SIGNED_NOTARIZED_RELEASE_BROADCAST_READY_FOR_JD_CONTROLLER_UPLOAD' ||
pipelineReceipt?.broadcastSha256 !== broadcastSha256 ||
!SOURCE_COMMIT_PATTERN.test(pipelineReceipt?.sourceCommit || '') ||
pipelineReceipt?.automaticUpload !== false ||
pipelineReceipt?.automaticActivation !== false
) fail('HOLOLAKE_RELEASE_OPERATOR_PIPELINE_RECEIPT_INVALID')
const approvalId = requireText(approvalReceipt?.approvalId, 'HOLOLAKE_RELEASE_OPERATOR_APPROVAL_ID_REQUIRED')
if (
approvalReceipt?.schema !== 'hololake.release-broadcast-human-approval/v1' ||
approvalReceipt?.state !== 'HUMAN_APPROVED_EXACT_SIGNED_NOTARIZED_RELEASE' ||
approvalReceipt?.releaseId !== releaseId ||
approvalReceipt?.version !== version ||
approvalReceipt?.broadcastSha256 !== broadcastSha256
) fail('HOLOLAKE_RELEASE_OPERATOR_HUMAN_APPROVAL_INVALID')
const artifacts = new Map()
addArtifact(artifacts, latestPath, 'latest.json', 'control')
addArtifact(artifacts, pipelinePath, 'pipeline-receipt.json', 'control')
addArtifact(artifacts, approvalPath, 'human-approval.json', 'control')
for (const platform of Object.values(broadcast.platforms)) {
const packageName = packageNameFromUrl(platform?.url)
const packagePath = directFile(source, packageName, 'HOLOLAKE_RELEASE_OPERATOR_PACKAGE_PATH_INVALID')
const packageInfo = requireTrustedFile(packagePath, { enforceRootOwner })
if (!Number.isSafeInteger(platform.size) || platform.size <= 0 || platform.size !== packageInfo.size) {
fail('HOLOLAKE_RELEASE_OPERATOR_PACKAGE_SIZE_MISMATCH')
}
if (!SHA256_PATTERN.test(platform.sha256 || '') || sha256(fs.readFileSync(packagePath)) !== platform.sha256) {
fail('HOLOLAKE_RELEASE_OPERATOR_PACKAGE_SHA256_MISMATCH')
}
requireText(platform.signature, 'HOLOLAKE_RELEASE_OPERATOR_PACKAGE_SIGNATURE_REQUIRED')
const codeReceiptId = requireText(platform.platformCodeSignatureReceipt, 'HOLOLAKE_RELEASE_OPERATOR_CODESIGN_RECEIPT_REQUIRED')
const notarizationReceiptId = requireText(platform.notarizationReceipt, 'HOLOLAKE_RELEASE_OPERATOR_NOTARIZATION_RECEIPT_REQUIRED')
const codeReceiptName = `${codeReceiptId}.json`
const notarizationReceiptName = `${notarizationReceiptId}.json`
const codeReceiptPath = directFile(source, codeReceiptName, 'HOLOLAKE_RELEASE_OPERATOR_CODESIGN_RECEIPT_PATH_INVALID')
const notarizationReceiptPath = directFile(source, notarizationReceiptName, 'HOLOLAKE_RELEASE_OPERATOR_NOTARIZATION_RECEIPT_PATH_INVALID')
const codeReceipt = readJson(codeReceiptPath, { enforceRootOwner }).value
const notarizationReceipt = readJson(notarizationReceiptPath, { enforceRootOwner }).value
if (
codeReceipt?.schema !== 'hololake.platform-code-signature-receipt/v1' ||
codeReceipt?.state !== 'DEVELOPER_ID_SIGNATURE_STRICT_AND_GATEKEEPER_ACCEPTED' ||
codeReceipt?.sourceCommit !== pipelineReceipt.sourceCommit
) fail('HOLOLAKE_RELEASE_OPERATOR_CODESIGN_RECEIPT_INVALID')
if (
notarizationReceipt?.schema !== 'hololake.apple-notarization-receipt/v1' ||
notarizationReceipt?.state !== 'APPLE_NOTARIZATION_ACCEPTED_AND_STAPLED' ||
notarizationReceipt?.sourceCommit !== pipelineReceipt.sourceCommit
) fail('HOLOLAKE_RELEASE_OPERATOR_NOTARIZATION_RECEIPT_INVALID')
addArtifact(artifacts, packagePath, packageName, 'package')
addArtifact(artifacts, codeReceiptPath, codeReceiptName, 'control')
addArtifact(artifacts, notarizationReceiptPath, notarizationReceiptName, 'control')
}
return {
schema: 'hololake.release-broadcast-operator-plan/v1',
state: 'EXACT_SIGNED_NOTARIZED_HUMAN_APPROVED_BUNDLE_VERIFIED',
releaseId,
version,
sourceCommit: pipelineReceipt.sourceCommit,
broadcastSha256,
approvalId,
artifacts: [...artifacts.values()],
}
}
function copyFileNoFollow(source, destination, mode) {
const sourceDescriptor = fs.openSync(source, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW)
let destinationDescriptor = null
try {
const sourceInfo = fs.fstatSync(sourceDescriptor)
if (!sourceInfo.isFile() || (sourceInfo.mode & 0o022) !== 0) fail('HOLOLAKE_RELEASE_OPERATOR_SOURCE_CHANGED')
destinationDescriptor = fs.openSync(destination, fs.constants.O_CREAT | fs.constants.O_EXCL | fs.constants.O_WRONLY, mode)
const buffer = Buffer.allocUnsafe(1024 * 1024)
let position = 0
while (position < sourceInfo.size) {
const read = fs.readSync(sourceDescriptor, buffer, 0, Math.min(buffer.length, sourceInfo.size - position), position)
if (read <= 0) fail('HOLOLAKE_RELEASE_OPERATOR_SOURCE_TRUNCATED')
let written = 0
while (written < read) written += fs.writeSync(destinationDescriptor, buffer, written, read - written)
position += read
}
fs.fsyncSync(destinationDescriptor)
} finally {
if (destinationDescriptor !== null) fs.closeSync(destinationDescriptor)
fs.closeSync(sourceDescriptor)
}
}
function writeJsonExclusive(file, value, mode) {
const descriptor = fs.openSync(file, fs.constants.O_CREAT | fs.constants.O_EXCL | fs.constants.O_WRONLY, mode)
try {
fs.writeFileSync(descriptor, `${JSON.stringify(value, null, 2)}\n`)
fs.fsyncSync(descriptor)
} finally {
fs.closeSync(descriptor)
}
}
function activationFor(plan) {
return {
schema: 'hololake.release-broadcast-activation/v1',
state: 'HUMAN_APPROVED_SIGNED_NOTARIZED_RELEASE_ACTIVE',
releaseId: plan.releaseId,
version: plan.version,
broadcastRelativePath: `releases/${plan.version}/latest.json`,
broadcastSha256: plan.broadcastSha256,
pipelineReceiptRelativePath: `releases/${plan.version}/pipeline-receipt.json`,
humanApprovalReceipt: plan.approvalId,
humanApprovalReceiptRelativePath: `releases/${plan.version}/human-approval.json`,
}
}
function prepareCandidate(candidateRoot, plan, { enforceRootOwner, trustedGroupId }) {
const releases = path.join(candidateRoot, 'releases')
const releaseDirectory = path.join(releases, plan.version)
fs.mkdirSync(releaseDirectory, { recursive: true, mode: enforceRootOwner ? 0o750 : 0o700 })
for (const artifact of plan.artifacts) {
const destination = path.join(releaseDirectory, artifact.name)
copyFileNoFollow(artifact.source, destination, enforceRootOwner ? 0o640 : 0o600)
if (enforceRootOwner) fs.chownSync(destination, 0, trustedGroupId)
}
const activationPath = path.join(candidateRoot, 'ACTIVE.json')
writeJsonExclusive(activationPath, activationFor(plan), enforceRootOwner ? 0o640 : 0o600)
if (enforceRootOwner) {
for (const directory of [candidateRoot, releases, releaseDirectory]) {
fs.chownSync(directory, 0, trustedGroupId)
fs.chmodSync(directory, 0o750)
}
fs.chownSync(activationPath, 0, trustedGroupId)
}
const state = loadRuntimeState(candidateRoot, { enforceRootOwner })
if (state.state !== 'READY_SIGNED_NOTARIZED_BROADCAST') {
fail(`HOLOLAKE_RELEASE_OPERATOR_CANDIDATE_INVALID:${state.reasonCode || state.state}`)
}
return { releaseDirectory, activationPath }
}
function requireExpected(plan, expected) {
for (const [field, code] of [
['releaseId', 'HOLOLAKE_RELEASE_OPERATOR_EXPECTED_RELEASE_ID_MISMATCH'],
['version', 'HOLOLAKE_RELEASE_OPERATOR_EXPECTED_VERSION_MISMATCH'],
['sourceCommit', 'HOLOLAKE_RELEASE_OPERATOR_EXPECTED_SOURCE_COMMIT_MISMATCH'],
['broadcastSha256', 'HOLOLAKE_RELEASE_OPERATOR_EXPECTED_BROADCAST_SHA256_MISMATCH'],
]) {
if (requireText(expected?.[field], `${code}_REQUIRED`) !== plan[field]) fail(code)
}
}
function replaceActivation(stateRoot, candidateActivation, previousBytes, enforceRootOwner, trustedGroupId) {
const tempActivation = path.join(stateRoot, `.ACTIVE.${crypto.randomUUID()}.tmp`)
copyFileNoFollow(candidateActivation, tempActivation, enforceRootOwner ? 0o640 : 0o600)
if (enforceRootOwner) fs.chownSync(tempActivation, 0, trustedGroupId)
fs.renameSync(tempActivation, path.join(stateRoot, 'ACTIVE.json'))
const committed = loadRuntimeState(stateRoot, { enforceRootOwner })
if (committed.state === 'READY_SIGNED_NOTARIZED_BROADCAST') return committed
const failedActive = path.join(stateRoot, 'ACTIVE.json')
if (previousBytes === null) {
fs.unlinkSync(failedActive)
} else {
const rollback = path.join(stateRoot, `.ACTIVE.rollback.${crypto.randomUUID()}.tmp`)
const descriptor = fs.openSync(rollback, fs.constants.O_CREAT | fs.constants.O_EXCL | fs.constants.O_WRONLY, enforceRootOwner ? 0o640 : 0o600)
try {
fs.writeFileSync(descriptor, previousBytes)
fs.fsyncSync(descriptor)
} finally {
fs.closeSync(descriptor)
}
if (enforceRootOwner) fs.chownSync(rollback, 0, trustedGroupId)
fs.renameSync(rollback, failedActive)
}
fail(`HOLOLAKE_RELEASE_OPERATOR_POST_COMMIT_INVALID:${committed.reasonCode || committed.state}`)
}
function acquireOperatorLock(stateRoot, enforceRootOwner, trustedGroupId) {
const lockDirectory = path.join(stateRoot, '.operator-lock')
try {
fs.mkdirSync(lockDirectory, { mode: enforceRootOwner ? 0o750 : 0o700 })
} catch (error) {
if (error?.code === 'EEXIST') fail('HOLOLAKE_RELEASE_OPERATOR_LOCKED')
throw error
}
try {
if (enforceRootOwner) fs.chownSync(lockDirectory, 0, trustedGroupId)
writeJsonExclusive(path.join(lockDirectory, 'owner.json'), {
schema: 'hololake.release-broadcast-operator-lock/v1',
pid: process.pid,
acquiredAt: new Date().toISOString(),
}, enforceRootOwner ? 0o640 : 0o600)
if (enforceRootOwner) fs.chownSync(path.join(lockDirectory, 'owner.json'), 0, trustedGroupId)
return lockDirectory
} catch (error) {
fs.rmSync(lockDirectory, { recursive: true, force: true })
throw error
}
}
export function verifyReleaseBundle(sourceDirectory, humanApprovalPath) {
const plan = inspectReleaseBundle(sourceDirectory, humanApprovalPath)
const candidateRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'hololake-release-operator-verify-'))
try {
prepareCandidate(candidateRoot, plan, { enforceRootOwner: false, trustedGroupId: process.getgid?.() ?? 0 })
return { ...plan, artifacts: plan.artifacts.map(({ name, type }) => ({ name, type })) }
} finally {
fs.rmSync(candidateRoot, { recursive: true, force: true })
}
}
export function activateRelease({ sourceDirectory, humanApprovalPath, stateRoot, expected, enforceRootOwner = true }) {
if (enforceRootOwner && process.getuid?.() !== 0) fail('HOLOLAKE_RELEASE_OPERATOR_ROOT_REQUIRED')
const root = path.resolve(stateRoot)
const rootInfo = requireTrustedDirectory(root, { enforceRootOwner })
const trustedGroupId = rootInfo.gid
const lockDirectory = acquireOperatorLock(root, enforceRootOwner, trustedGroupId)
let candidateRoot = null
try {
const plan = inspectReleaseBundle(sourceDirectory, humanApprovalPath, { enforceRootOwner })
requireExpected(plan, expected)
candidateRoot = fs.mkdtempSync(path.join(root, '.candidate-'))
const candidate = prepareCandidate(candidateRoot, plan, { enforceRootOwner, trustedGroupId })
const releasesRoot = path.join(root, 'releases')
if (!fs.existsSync(releasesRoot)) fs.mkdirSync(releasesRoot, { mode: enforceRootOwner ? 0o750 : 0o700 })
requireTrustedDirectory(releasesRoot, { enforceRootOwner })
if (enforceRootOwner) {
fs.chownSync(releasesRoot, 0, trustedGroupId)
fs.chmodSync(releasesRoot, 0o750)
}
const finalRelease = path.join(releasesRoot, plan.version)
if (fs.existsSync(finalRelease)) fail('HOLOLAKE_RELEASE_OPERATOR_VERSION_ALREADY_STAGED')
const activePath = path.join(root, 'ACTIVE.json')
const previousBytes = fs.existsSync(activePath) ? readJson(activePath, { enforceRootOwner }).bytes : null
fs.renameSync(candidate.releaseDirectory, finalRelease)
let committed
try {
committed = replaceActivation(root, candidate.activationPath, previousBytes, enforceRootOwner, trustedGroupId)
} catch (error) {
fs.rmSync(finalRelease, { recursive: true, force: true })
throw error
}
return {
schema: 'hololake.release-broadcast-operator-receipt/v1',
state: 'ACTIVATED_EXPLICIT_SERVICE_RESTART_REQUIRED',
releaseId: plan.releaseId,
version: plan.version,
sourceCommit: plan.sourceCommit,
broadcastSha256: plan.broadcastSha256,
approvalId: plan.approvalId,
automaticUpload: false,
automaticActivation: false,
automaticRestart: false,
runtimeStateAfterDiskCommit: committed.state,
}
} finally {
if (candidateRoot) fs.rmSync(candidateRoot, { recursive: true, force: true })
fs.rmSync(lockDirectory, { recursive: true, force: true })
}
}
function parseArguments(argv) {
const command = argv[0]
const values = {}
for (let index = 1; index < argv.length; index += 1) {
const key = argv[index]
if (!key.startsWith('--') || index + 1 >= argv.length) fail('HOLOLAKE_RELEASE_OPERATOR_ARGUMENT_INVALID')
values[key.slice(2)] = argv[++index]
}
return { command, values }
}
export function main(argv = process.argv.slice(2)) {
const { command, values } = parseArguments(argv)
const sourceDirectory = requireText(values.source, 'HOLOLAKE_RELEASE_OPERATOR_SOURCE_REQUIRED')
const humanApprovalPath = requireText(values['human-approval'], 'HOLOLAKE_RELEASE_OPERATOR_HUMAN_APPROVAL_PATH_REQUIRED')
if (command === 'verify') {
process.stdout.write(`${JSON.stringify(verifyReleaseBundle(sourceDirectory, humanApprovalPath), null, 2)}\n`)
return
}
if (command !== 'activate') fail('HOLOLAKE_RELEASE_OPERATOR_COMMAND_INVALID:verify|activate')
const receipt = activateRelease({
sourceDirectory,
humanApprovalPath,
stateRoot: requireText(values['state-root'], 'HOLOLAKE_RELEASE_OPERATOR_STATE_ROOT_REQUIRED'),
expected: {
releaseId: values['expect-release-id'],
version: values['expect-version'],
sourceCommit: values['expect-source-commit'],
broadcastSha256: values['expect-broadcast-sha256'],
},
})
process.stdout.write(`${JSON.stringify(receipt, null, 2)}\n`)
}
if (isMainModule(process.argv[1], import.meta.url)) {
try {
main()
} catch (error) {
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`)
process.exitCode = 1
}
}