| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849 |
- /** Persist a per-user hardware-signing interlock; failures and interrupted attempts never unlock automatically. */
- import { closeSync, existsSync, mkdirSync, openSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs'
- import { homedir } from 'node:os'
- import { join, isAbsolute } from 'node:path'
- import { randomUUID } from 'node:crypto'
- import { failPackagingRun, recordPackagingEvent } from './packaging-run.mjs'
- /**
- * Acquire the one hardware-signing attempt slot before launching SignTool.
- * @param {{runDirectory?: string, stateDirectory?: string, target: string}} options Run evidence and test-only isolated state directory.
- * @returns {{started: (pid: number|null) => void, success: () => void, failure: (code: number|string|null, diagnostic: string) => void}} Process evidence and completion callbacks; failure retains the interlock.
- */
- export function beginWindowsSigningAttempt(options) {
- const runDirectory = options.runDirectory ?? process.env.DSH_DESKTOP_PACKAGING_RUN_DIR
- if (!runDirectory || !isAbsolute(runDirectory) || !existsSync(join(runDirectory, 'run.json'))) {
- throw new Error('Windows hardware signing requires a supervised packaging run with retained records')
- }
- if (existsSync(join(runDirectory, 'fatal.json'))) throw new Error('Windows signing refused: packaging run already failed')
- const root = options.stateDirectory ?? join(homedir(), '.dsh-desktop-signing')
- const lock = join(root, 'attempt.json')
- const attemptId = randomUUID()
- mkdirSync(root, { recursive: true })
- let descriptor
- try { descriptor = openSync(lock, 'wx', 0o600) }
- catch (error) {
- failPackagingRun(runDirectory, 'hardware-signing-interlock-unavailable')
- throw new Error(`Windows signing refused: interlock unavailable at ${lock}; inspect the previous attempt before administrator-approved recovery (${error.code})`)
- }
- try {
- writeFileSync(descriptor, `${JSON.stringify({ attemptId, runDirectory, pid: process.pid, startedAt: new Date().toISOString(), target: options.target })}\n`, { flush: true })
- } finally { closeSync(descriptor) }
- try { recordPackagingEvent(runDirectory, { type: 'sign-start', attemptId, target: options.target }) }
- catch (error) { failPackagingRun(runDirectory, 'signing-audit-write-failed'); throw error }
- return {
- started(pid) {
- recordPackagingEvent(runDirectory, { type: 'sign-command-start', attemptId, commandPid: pid })
- },
- success() {
- recordPackagingEvent(runDirectory, { type: 'sign-success', attemptId, target: options.target })
- if (JSON.parse(readFileSync(lock, 'utf8')).attemptId !== attemptId) throw new Error('Windows signing interlock ownership changed')
- unlinkSync(lock)
- },
- failure(code, diagnostic) {
- // The attempt file stays in place even if recording the failure or notifying the parent fails.
- try { recordPackagingEvent(runDirectory, { type: 'sign-failure', attemptId, target: options.target, code, diagnostic }) }
- finally { failPackagingRun(runDirectory, 'hardware-signing-failed') }
- },
- }
- }
|