diff --git a/apps/desktop/tests/README.i18n.yaml b/apps/desktop/tests/README.i18n.yaml index f043547c8b..762d6177f1 100644 --- a/apps/desktop/tests/README.i18n.yaml +++ b/apps/desktop/tests/README.i18n.yaml @@ -18,8 +18,8 @@ en: c4b4ee8763d8464a zh: ee2159bc08966592 /desktop-local-update-verification/evidence: - en: bc4634c9a9ceddca - zh: 21370a4c088b50df + en: 331a6709d0f7d03f + zh: 98499192ef9d3a81 /desktop-local-update-verification/open-verification: en: 20e9ea47acb1ff50 zh: acce24b56d57e12c diff --git a/apps/desktop/tests/README.md b/apps/desktop/tests/README.md index 6064f4d3b9..b2b04d590a 100644 --- a/apps/desktop/tests/README.md +++ b/apps/desktop/tests/README.md @@ -42,6 +42,8 @@ With Host, client, and Desktop artifacts built, run `node --import tsx apps/desk The local command builds Desktop and executes Electron 44 with the actual HTTP updater, policy client, sandboxed preload, and mandatory renderer. It records each scenario and preserves its report under `.desktop-build/qualification/local-updater-*`. The installer call, external browser, and clipboard are observation substitutes; downloaded bytes are not an executable installer. +Packaging supervision fixtures control their Git metadata and use real file hashes with inert child processes. Git-head and worktree changes still refuse packaging; concurrent tests cannot change the fixture’s recorded Git inputs. + | Layer | Observed result | |---|---| | Ordinary updater | Same/older-version rejection, user-authorized full download, SHA-512 rejection, interrupted transfer, stalled-feed/download deadlines, explicit retry, coalesced requests, same-address feed replacement, readiness, and separate install handoff pass | diff --git a/apps/desktop/tests/README.zh.md b/apps/desktop/tests/README.zh.md index d72883d0fa..9356c9592a 100644 --- a/apps/desktop/tests/README.zh.md +++ b/apps/desktop/tests/README.zh.md @@ -42,6 +42,8 @@ Host、客户端与 Desktop 产物构建完成后,在 Windows 仓库根目录 本地命令构建 Desktop,并在 Electron 44 中运行真实 HTTP updater、策略客户端、沙箱预加载和强更页面。它记录每个场景,并把报告保存在 `.desktop-build/qualification/local-updater-*`。安装器调用、外部浏览器和剪贴板均替换为观测记录;下载字节不是可执行安装器。 +打包监督 fixture 控制自己的 Git 元数据,并使用真实文件哈希和无签名行为的子进程。Git 提交或工作区变化仍会拒绝打包;并发测试不会改变该 fixture 记录的 Git 输入。 + | 层次 | 观测结果 | |---|---| | 常规 updater | 同版本/旧版本拒绝、用户授权完整下载、SHA-512 拒绝、传输中断、清单/下载停滞截止时间、显式重试、请求合并、同地址清单替换、就绪状态和独立安装交接通过 | diff --git a/apps/desktop/tests/installed-update-packaging.spec.ts b/apps/desktop/tests/installed-update-packaging.spec.ts index 4abb1dfb03..d3169acc6a 100644 --- a/apps/desktop/tests/installed-update-packaging.spec.ts +++ b/apps/desktop/tests/installed-update-packaging.spec.ts @@ -5,7 +5,19 @@ import { describe, expect, it, vi } from 'vitest' import { createInstalledUpdateRun } from '../scripts/installed-update-qualification.ts' import { assertInstalledUpdateSigningClear, installedUpdatePackagingEnvironment, packageInstalledUpdate } from '../scripts/installed-update-packaging.ts' -const state = vi.hoisted(() => ({ home: '', settings: {} as NodeJS.ProcessEnv, loads: 0 })) +const state = vi.hoisted(() => ({ home: '', settings: {} as NodeJS.ProcessEnv, loads: 0, + sourceCommit: 'a'.repeat(40), dirtyFiles: '' })) +// Other test processes create workspace probes; only this fixture controls its recorded Git inputs. +vi.mock('node:child_process', async (original) => { + const actual = await original() + return { ...actual, execFileSync: (...args: Parameters) => { + if (args[0] !== 'git') return actual.execFileSync(...args) + const command = args[1]?.join(' ') + if (command === 'rev-parse HEAD') return state.sourceCommit + if (command === 'status --porcelain=v1 --untracked-files=normal') return state.dirtyFiles + throw new Error(`unexpected fixture Git command: ${String(command)}`) + } } +}) vi.mock('node:os', async original => ({ ...await original(), homedir: () => state.home })) vi.mock('../scripts/desktop-package-environment.mjs', () => ({ loadDesktopPackageEnvironment: () => { state.loads++; return state.settings }, @@ -118,17 +130,19 @@ describe('operator-driven packaging entry', () => { }) }) - it.runIf(process.platform === 'win32' && process.arch === 'x64').each(['output', 'source'] as const)( + it.runIf(process.platform === 'win32' && process.arch === 'x64').each(['output', 'source', 'git-head', 'git-status'] as const)( 'refuses an intervening %s change before launching the builder', async (change) => { await fixture(async (manifest, root) => { await expect(packageInstalledUpdate(manifest, versions[0], { execute: true, confirm: async () => { if (change === 'source') await writeFile(join(root, 'certificate.cer'), 'changed certificate bytes') + else if (change === 'git-head') state.sourceCommit = 'b'.repeat(40) + else if (change === 'git-status') state.dirtyFiles = ' M apps/desktop/package.json' else { await mkdir(join(manifest, '..', versions[0], 'installer')) await writeFile(join(manifest, '..', versions[0], 'installer/owner.txt'), 'preserve') } return true - } })).rejects.toThrow() + } })).rejects.toThrow(change === 'output' ? 'EEXIST' : 'recorded source or tool inputs changed before packaging') const parent = join(manifest, '..', versions[0], 'packaging') const record = join(parent, (await readdir(parent))[0]!) expect(await readFile(join(record, 'events.jsonl'), 'utf8')).not.toContain('stage-spawn') diff --git a/apps/web/tests/expected/settings-appearance/account.expected.md b/apps/web/tests/expected/settings-appearance/account.expected.md index e4ef360c8f..55dee3a0a0 100644 --- a/apps/web/tests/expected/settings-appearance/account.expected.md +++ b/apps/web/tests/expected/settings-appearance/account.expected.md @@ -2,7 +2,7 @@ - text: Radius example - status: r***@example.com - link "更多账号信息": - - /url: https://platform.deepseek.com + - /url: https://platform.deepseek.com/ - text: 充值余额 ¥128.50 赠金余额 ¥12.00 更多 - link "查询用量": - /url: https://platform.deepseek.com/usage