Files
hermes-agent/apps/desktop/scripts/prepared-windows-tools.test.mjs
ethernet 2efa4ff94f refactor(desktop): prepare dependencies before saving build caches
Dependency acquisition during packaging left native wheels and packager
inputs outside the pre-build cache save. Compose PM and existing providers
into a preparation phase, then require builds to consume admitted inputs.

Share native preparation with PM Bundle. Keep path-bound environments and
signing outputs separate from reusable caches. Use read-only cache tokens
for commit builds and preserve the one-command local build path.

Verify pinned tools through PM, probe PTYs under the prepared Electron,
and supply dmgbuild through a build-only PM package. Resolve bundled tool
stores from their payload manifest so relocation preserves discovery.

Validation: focused Python and JS tests, checkJs, Ruff, Windows checks,
anti-slop, cache relocation, and network-denied Linux AppImage builds.
Relocated runtime smoke passed with NixOS host libraries supplied.
Native Windows/macOS signing and live GitHub cache behavior remain untested.
2026-09-13 14:28:31 -04:00

60 lines
2.6 KiB
JavaScript

import assert from 'node:assert/strict'
import fs from 'node:fs'
import os from 'node:os'
import path from 'node:path'
import { test } from 'vitest'
import { ensureWindowsBundleTools } from './windows-bundle-tools.mjs'
import { azureSignFile } from './sign-msix.mjs'
test('signing validates once per packager, including concurrent file hooks, never process-wide', async () => {
const previous = process.env.HERMES_PREPARED_PACKAGING
const previousDotnet = process.env.DOTNET_ROOT
process.env.HERMES_PREPARED_PACKAGING = 'operation-selection.json'
let admissions = 0
const signed = []
const dependencies = {
ensureTools: async () => { admissions++; return { dotnetRoot: 'prepared-dotnet' } },
loadManager: async () => class {
async initialize() {}
async signFile({ path: file }) { signed.push(file) }
},
}
const resources = os.tmpdir()
const packager = { config: { toolsets: { winCodeSign: { url: `file://${path.join(resources, 'prepared-packaging-tools/winCodeSign')}` } } }, buildResourcesDir: resources, platformOptions: {} }
try {
await Promise.all(['first.exe', 'second.msix'].map(file => azureSignFile(file, packager, dependencies)))
assert.equal(admissions, 1)
await azureSignFile('third.msix', { ...packager }, dependencies)
assert.equal(admissions, 2)
assert.deepEqual(signed, ['first.exe', 'second.msix', 'third.msix'])
} finally {
if (previous === undefined) delete process.env.HERMES_PREPARED_PACKAGING
else process.env.HERMES_PREPARED_PACKAGING = previous
if (previousDotnet === undefined) delete process.env.DOTNET_ROOT
else process.env.DOTNET_ROOT = previousDotnet
}
})
test('the per-file Azure signer admits the same prepared selection before constructing its manager', async () => {
const previous = process.env.HERMES_PREPARED_PACKAGING
process.env.HERMES_PREPARED_PACKAGING = path.join(os.tmpdir(), 'absent-signing-selection.json')
try {
await assert.rejects(azureSignFile('output.msix', { config: {}, buildResourcesDir: os.tmpdir() }), /run preparation again/)
} finally {
if (previous === undefined) delete process.env.HERMES_PREPARED_PACKAGING
else process.env.HERMES_PREPARED_PACKAGING = previous
}
})
test('a prepared signing selection cannot fall through to a supplier', async () => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'prepared-windows-'))
try {
await assert.rejects(ensureWindowsBundleTools({
prepared: path.join(root, 'missing.json'), signing: true, config: {},
load: async () => { throw new Error('supplier must not run') },
}), /run preparation again/i)
} finally {
fs.rmSync(root, { recursive: true, force: true })
}
})