Merge origin/main into mobile i18n audit

This commit is contained in:
Brennan Benson
2026-07-31 11:38:51 -07:00
270 changed files with 17050 additions and 1753 deletions
@@ -1,13 +1,72 @@
import { readFileSync } from 'node:fs'
import * as nodeFs from 'node:fs'
import { mkdtempSync, readFileSync, rmSync } from 'node:fs'
import * as nodePath from 'node:path'
import { join } from 'node:path'
import { tmpdir } from 'node:os'
import { EventEmitter } from 'node:events'
import { runInNewContext } from 'node:vm'
import { describe, expect, it } from 'vitest'
import { createBootstrapFatalExitBanner, electronViteConfig } from '../../electron.vite.config'
import {
BOOTSTRAP_FATAL_LOG_ENV_VAR,
BOOTSTRAP_FATAL_LOG_FILE_NAME,
createBootstrapFatalExitBanner
} from '../../build-plugins/bootstrap-fatal-exit-banner'
import { electronViteConfig } from '../../electron.vite.config'
import { BOOTSTRAP_FATAL_EXIT_GUARD_KEY } from '../../src/main/startup/bootstrap-fatal-exit-guard'
const targetConfig = readFileSync('config/electron-vite-target.config.ts', 'utf8')
const devRunner = readFileSync('config/scripts/run-electron-vite-dev.mjs', 'utf8')
type BootstrapProcessMock = EventEmitter & {
env: Record<string, string>
pid: number
exit: (code: number) => void
exitCode?: number
}
/** Runs the banner in a bare context and raises the bootstrap fault it guards against. */
function failBootstrapWithBanner(options: {
env: Record<string, string>
tmpdir?: string
stderrWrites?: string[]
}): BootstrapProcessMock {
const processMock = new EventEmitter() as BootstrapProcessMock
processMock.env = options.env
processMock.pid = 4242
processMock.exit = () => {}
const fsShim = {
...nodeFs,
writeSync: (descriptor: number, data: string) => {
if (descriptor === 2) {
options.stderrWrites?.push(data)
return data.length
}
return nodeFs.writeSync(descriptor, data)
}
}
const context = {
process: processMock,
setImmediate: () => {},
require: (specifier: string) => {
if (specifier === 'node:fs') {
return fsShim
}
if (specifier === 'node:path') {
return nodePath
}
if (specifier === 'node:os' && options.tmpdir !== undefined) {
return { tmpdir: () => options.tmpdir }
}
// Electron's own module is unreachable from a bootstrap fault this early.
throw new Error(`unexpected require: ${specifier}`)
}
}
runInNewContext(createBootstrapFatalExitBanner(), context)
processMock.emit('uncaughtException', new Error("Cannot find module 'ws'"))
return processMock
}
describe('Electron Vite output contract', () => {
it('keeps main-process and plain-Node entries at stable CommonJS paths', () => {
const output = electronViteConfig.main?.build?.rollupOptions?.output
@@ -40,12 +99,20 @@ describe('Electron Vite output contract', () => {
const processMock = new EventEmitter() as EventEmitter & {
exit: (code: number) => void
exitCode?: number
stderr: { write: (chunk: string) => boolean }
}
let scheduledExit: (() => void) | null = null
let exitedWith: number | null = null
const stderrWrites: string[] = []
processMock.exit = (code) => {
exitedWith = code
}
processMock.stderr = {
write: (chunk) => {
stderrWrites.push(chunk)
return true
}
}
const context = {
process: processMock,
setImmediate: (callback: () => void) => {
@@ -61,6 +128,63 @@ describe('Electron Vite output contract', () => {
scheduledExit?.()
expect(exitedWith).toBe(1)
expect(context).toHaveProperty(BOOTSTRAP_FATAL_EXIT_GUARD_KEY)
expect(stderrWrites.join('')).toContain("Cannot find module 'zod'")
})
it('records the bootstrap failure it exits on, since the guard hides Electron dialog', () => {
const logDirectory = mkdtempSync(join(tmpdir(), 'orca-bootstrap-fatal-'))
const logPath = join(logDirectory, 'fatal.log')
const stderrWrites: string[] = []
try {
const processMock = failBootstrapWithBanner({
env: { [BOOTSTRAP_FATAL_LOG_ENV_VAR]: logPath },
stderrWrites
})
expect(stderrWrites.join('')).toContain("Cannot find module 'ws'")
const recorded = readFileSync(logPath, 'utf8')
expect(recorded).toContain("Cannot find module 'ws'")
expect(recorded).toContain('pid=4242')
expect(processMock.exitCode).toBe(1)
} finally {
rmSync(logDirectory, { recursive: true, force: true })
}
})
it('creates the parent directory an overridden log path names but does not have', () => {
const logDirectory = mkdtempSync(join(tmpdir(), 'orca-bootstrap-fatal-'))
const logPath = join(logDirectory, 'nested', 'diagnostics', 'fatal.log')
try {
const processMock = failBootstrapWithBanner({
env: { [BOOTSTRAP_FATAL_LOG_ENV_VAR]: logPath }
})
expect(readFileSync(logPath, 'utf8')).toContain("Cannot find module 'ws'")
expect(processMock.exitCode).toBe(1)
} finally {
rmSync(logDirectory, { recursive: true, force: true })
}
})
it('falls back to the default location when the overridden log path is unwritable', () => {
const logDirectory = mkdtempSync(join(tmpdir(), 'orca-bootstrap-fatal-'))
const fallbackDirectory = join(logDirectory, 'fallback')
try {
const processMock = failBootstrapWithBanner({
// A directory can never be opened as the log file, so the override must yield.
env: { [BOOTSTRAP_FATAL_LOG_ENV_VAR]: logDirectory },
tmpdir: fallbackDirectory
})
const recorded = readFileSync(join(fallbackDirectory, BOOTSTRAP_FATAL_LOG_FILE_NAME), 'utf8')
expect(recorded).toContain("Cannot find module 'ws'")
expect(processMock.exitCode).toBe(1)
} finally {
rmSync(logDirectory, { recursive: true, force: true })
}
})
it('isolates renderer entry side effects behind strict facades', () => {
+28 -2
View File
@@ -35,6 +35,7 @@ const appDir = resolve(readAppDirArg(process.argv.slice(2)))
const tempRoot = await mkdtemp(join(tmpdir(), 'orca-packaged-cli-smoke-'))
const copiedAppDir = join(tempRoot, basename(appDir))
let smokeFailure = null
try {
await cp(appDir, copiedAppDir, { recursive: true, verbatimSymlinks: true })
const cliPath = getPackagedCliPath(copiedAppDir)
@@ -73,6 +74,31 @@ try {
assert.equal(install.executed, false)
assert.equal(update.executed, false)
console.log(`[packaged-cli-smoke] help and skills commands passed via ${cliPath}`)
} finally {
await rm(tempRoot, { recursive: true, force: true })
} catch (error) {
smokeFailure = error
}
// Why: on Windows the launcher above spawns the copied Orca.exe (and its crashpad/utility children)
// once per command; those handles can outlive execFile's exit by a few ms, so this cleanup hits
// EBUSY on our own just-exited process after every assertion already passed. Same retry treatment
// as removeHostTree(); a lock that never clears still throws — unless the smoke run itself failed,
// in which case surfacing EBUSY instead of the real assertion would hide the actual regression.
const cleanupFailure = await rm(tempRoot, {
recursive: true,
force: true,
maxRetries: 20,
retryDelay: 250
}).then(
() => null,
(error) => error
)
if (smokeFailure) {
if (cleanupFailure) {
console.warn(`[packaged-cli-smoke] temp cleanup failed: ${cleanupFailure.message}`)
}
throw smokeFailure
}
if (cleanupFailure) {
throw cleanupFailure
}
@@ -104,6 +104,41 @@ describe('Windows signing workflow contract', () => {
expect(installRun).toContain('throw "Unable to install the SignPath PowerShell module')
})
it('still installs SignPath when the cut ref predates the composite action', () => {
const parsedWorkflow = readWorkflow('.github/workflows/release-cut.yml')
const steps = parsedWorkflow.jobs.build.steps
const stepNames = steps.map((step) => step.name)
const checkoutIndex = stepNames.indexOf('Checkout')
const restoreIndex = stepNames.indexOf('Restore composite actions from the workflow ref')
const installIndex = stepNames.indexOf('Install SignPath PowerShell module')
// Why: the build job checks out the cut tag, which for a hotfix cut from an
// older ref can predate `.github/actions/install-signpath-module`; without
// this restore the `uses: ./…` step dies on a missing action.yml.
expect(restoreIndex).toBeGreaterThan(checkoutIndex)
expect(restoreIndex).toBeLessThan(installIndex)
const restoreStep = steps[restoreIndex]
const restoreRun = restoreStep.run
expect(restoreStep.env.WORKFLOW_SHA).toBe('${{ github.workflow_sha }}')
expect(restoreRun).toContain('.github/actions/install-signpath-module/action.yml')
expect(restoreRun).toContain('git fetch --no-tags --depth=1 origin "$WORKFLOW_SHA"')
expect(restoreRun).toContain('git checkout "$WORKFLOW_SHA" -- .github/actions')
// Why: restoring the action must not turn signing into a soft dependency —
// a missing module still has to fail the Windows job, and the CDN fallback
// still has to reject an unexpected payload.
expect(steps[installIndex]['continue-on-error']).toBeUndefined()
expect(restoreStep['continue-on-error']).toBeUndefined()
const installRun = readWorkflow('.github/actions/install-signpath-module/action.yml').runs
.steps[0].run
expect(installRun).toContain('$actualHash -ne $expectedHash.ToUpperInvariant()')
expect(installRun).toContain('throw "SHA-256 mismatch for $source')
})
it('shares one SignPath module install path between release and rehearsal', () => {
const rehearsalWorkflow = readWorkflow('.github/workflows/windows-signing-rehearsal.yml')
const stepNames = rehearsalWorkflow.jobs.rehearse.steps.map((step) => step.name)