Files
deepseek-harness/apps/desktop/scripts/verify-harness.mjs
T
Pine 8e79ec4942 feat: enhance desktop packaging process with self-contained harness verification
- Updated README and README.zh to clarify packaging commands and added verification step.
- Improved packaging scripts to automatically build the self-contained runtime and verify its integrity.
- Introduced new scripts for verifying harness self-containment and booting the web profile.
- Added comprehensive tests for relinking harness symlinks and ensuring self-containment.
- Updated package.json scripts to reflect new build and verification processes.
2026-08-16 00:31:19 +08:00

190 lines
6.2 KiB
JavaScript

#!/usr/bin/env node
/**
* Verify a harness tree is self-contained and actually boots from the bundle.
*
* Default: check the assembled `build/harness`. With `--app <dir>`, locate the
* `resources/harness` inside a packed/unpacked app instead — this additionally
* proves electron-builder's `extraResources` copy preserved the relative
* in-tree links. `--boot` also spawns the web profile straight from the bundle
* (temp DSH_HOME, telemetry off) and waits for its readiness line, proving the
* relinked node_modules resolves without the repository present.
*
* Usage:
* node scripts/verify-harness.mjs # build/harness
* node scripts/verify-harness.mjs --boot # + web boot smoke
* node scripts/verify-harness.mjs --app dist # a packed app's harness
* node scripts/verify-harness.mjs --app dist --boot
*/
import { spawn, spawnSync } from 'node:child_process'
import { existsSync, mkdtempSync, readdirSync, rmSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { basename, dirname, isAbsolute, join, resolve } from 'node:path'
import { fileURLToPath } from 'node:url'
import { assertSelfContained } from './harness-relink.mjs'
const root = resolve(dirname(fileURLToPath(import.meta.url)), '../../..')
const desktopDir = join(root, 'apps/desktop')
const defaultHarness = join(desktopDir, 'build/harness')
const args = process.argv.slice(2)
const boot = args.includes('--boot')
const appIndex = args.indexOf('--app')
const appValue = args.find((a) => a.startsWith('--app='))?.slice('--app='.length) ?? (appIndex !== -1 ? args[appIndex + 1] : undefined)
const appRoot = appValue === undefined
? undefined
: isAbsolute(appValue)
? resolve(appValue)
: resolve(desktopDir, appValue)
const timeoutMs = 60_000
const READY_RE = /http:\/\/127\.0\.0\.1:(\d+)/
function fail(message) {
console.error(`verify-harness: ${message}`)
process.exit(1)
}
/** Find every `resources/harness` under an unpacked electron-builder app. */
function findHarnessUnder(appDir) {
const found = []
// electron-builder unpacked layout:
// win: <root>/win-unpacked/resources/harness
// mac: <root>/mac(-arch)/<Name>.app/Contents/Resources/harness
const visit = (dir, depth) => {
if (depth > 5) return
let entries
try {
entries = readdirSync(dir, { withFileTypes: true })
} catch {
return
}
for (const entry of entries) {
const p = join(dir, entry.name)
if (basename(p) === 'harness' && basename(dirname(p)) === 'resources') found.push(p)
if (entry.isDirectory()) visit(p, depth + 1)
}
}
visit(appDir, 0)
return found
}
function nodeBinary(harness) {
return join(harness, 'bin', process.platform === 'win32' ? 'node.exe' : 'node')
}
function cliEntry(harness) {
return join(harness, 'apps/cli/lib/bin.js')
}
/** Run the bundled CLI's `--version` straight from the bundle. */
function checkVersion(harness) {
const result = spawnSync(nodeBinary(harness), [cliEntry(harness), '--version'], {
cwd: harness,
encoding: 'utf8',
timeout: timeoutMs,
})
if (result.error !== undefined || result.status !== 0) {
fail(`the bundled CLI failed to run: ${result.error?.message ?? result.stderr?.trim() ?? `exit ${String(result.status)}`}`)
}
console.log(` dsh --version: ${result.stdout?.trim()}`)
}
/**
* Spawn the web profile from the bundle and resolve once it prints its
* readiness URL. Hermetic: a temp DSH_HOME and telemetry off, so the check
* neither touches the real profile nor the repository.
*/
function bootWeb(harness) {
const home = mkdtempSync(join(tmpdir(), 'dsh-verify-home-'))
const child = spawn(
nodeBinary(harness),
[cliEntry(harness), '--profile', 'web', '--host', '127.0.0.1', '--port', '0'],
{
cwd: harness,
stdio: ['ignore', 'pipe', 'inherit'],
env: { ...process.env, DSH_HOME: home, DSH_TELEMETRY_DISABLED: '1', DSH_ALLOW_PLUGIN_INSTALL: '1' },
},
)
return new Promise((resolvePromise, reject) => {
let settled = false
let buffered = ''
const cleanup = () => {
try {
rmSync(home, { recursive: true, force: true })
} catch {
// Best effort; a locked file on Windows is not fatal for a verify tool.
}
}
const timer = setTimeout(() => {
if (settled) return
settled = true
child.kill()
cleanup()
reject(new Error(`web boot timed out after ${timeoutMs}ms`))
}, timeoutMs)
child.stdout?.setEncoding('utf8')
child.stdout?.on('data', (chunk) => {
if (settled) return
buffered += chunk
if (READY_RE.test(buffered)) {
settled = true
clearTimeout(timer)
child.kill()
cleanup()
resolvePromise()
}
})
child.on('error', (error) => {
if (settled) return
settled = true
clearTimeout(timer)
cleanup()
reject(error)
})
child.on('exit', (code) => {
if (settled) return
settled = true
clearTimeout(timer)
cleanup()
reject(new Error(`harness exited before serving (code ${String(code)})`))
})
})
}
async function main() {
const harness = (() => {
if (appRoot !== undefined) {
const found = findHarnessUnder(appRoot)
if (found.length === 0) fail(`no resources/harness found under ${appRoot}`)
if (found.length > 1) {
console.warn(`verify-harness: ${found.length} harness dirs found; checking the first:\n ${found.join('\n ')}`)
}
return found[0]
}
if (!existsSync(defaultHarness)) fail(`build/harness not found at ${defaultHarness} — run build:harness first`)
return defaultHarness
})()
console.log(`verify-harness: ${harness}`)
if (!existsSync(nodeBinary(harness))) fail(`bundled node not found at ${nodeBinary(harness)}`)
try {
assertSelfContained(harness)
} catch (error) {
fail(error instanceof Error ? error.message : String(error))
}
console.log(' links: self-contained (no link escapes the bundle)')
checkVersion(harness)
if (boot) {
try {
await bootWeb(harness)
} catch (error) {
fail(error instanceof Error ? error.message : String(error))
}
console.log(' web boot: ok')
}
console.log('verify-harness: ok')
}
main().catch((error) => fail(error instanceof Error ? error.message : String(error)))