mirror of
https://github.com/deepseek-ai/deepseek-harness.git
synced 2026-10-26 16:55:08 +00:00
fix(desktop): preserve copyright and verify installer metadata
This commit is contained in:
1 parent
f351c96d71
commit
0d9a7f9abf
6 files changed
+23
-9
No files matched your search
@@ -3,6 +3,7 @@ import type { AfterPackContext, BeforePackContext } from 'app-builder-lib'
|
||||
/** Electron-builder fields asserted by the Desktop release tests. */
|
||||
export interface DesktopElectronBuilderConfig {
|
||||
readonly appId: string
|
||||
readonly copyright: string
|
||||
readonly artifactName: string
|
||||
readonly protocols: readonly [{ readonly name: 'DeepSeek Harness'; readonly schemes: readonly ['dsh'] }]
|
||||
readonly directories: {
|
||||
|
||||
@@ -45,14 +45,14 @@
|
||||
en: b42f103358d0dfd7
|
||||
zh: a534164ad9eb00da
|
||||
/desktop-packaging/runtime-file-selection-and-installation-checks:
|
||||
en: 080d251258b2358f
|
||||
zh: e3d968a0384971db
|
||||
en: bfd89e1d139c5729
|
||||
zh: 5d6cced5462ba13e
|
||||
/desktop-packaging/desktop-runtime-preparation:
|
||||
en: a7aa3066e649ffe8
|
||||
zh: 4334637910058c09
|
||||
/desktop-packaging/installation-and-release-verification:
|
||||
en: 0006b6b1ae4998f4
|
||||
zh: 2bab6918b0c37b25
|
||||
en: eb35eb973b796643
|
||||
zh: c1c52311632b7296
|
||||
/desktop-packaging/dev-note:
|
||||
en: b75c8458928b72b9
|
||||
zh: 003ba4e17b4b5269
|
||||
@@ -230,8 +230,6 @@ The served `time` is the real packing time, so pnpm 11's default 24-hour `minimu
|
||||
|
||||
## Runtime file selection and installation checks
|
||||
|
||||
Windows lists the installed application by product name without a version suffix; the version remains in the separate version field. The publisher comes from Desktop's `package.json` author name, independently of the signing certificate. These fields take effect when the rebuilt installer installs or updates the application.
|
||||
|
||||
Desktop packs workspace packages locally and installs external dependencies through the target's bundled Node and pnpm. [Desktop's file policy](../scripts/runtime-file-policy.ts) then filters the immutable `resources/app.asar/dsh/node_modules` copy before signing and integrity sealing. It omits TypeScript declarations, recognized JavaScript/CSS/TypeScript source maps, TypeScript build caches, Domino's test directory and Yarn development metadata, selected native compiler outputs, and node-pty prebuilds for other platforms. Non-Windows targets also omit `node-pty/third_party/conpty`; Windows targets retain that directory. It preserves runtime JavaScript, target native modules and their DLL/EXE helpers, WASM, unknown assets, licenses, and notices. Dependency manifests pass through electron-builder's metadata cleanup before integrity sealing, so archiving preserves their recorded bytes. The policy does not alter npm tarballs, the bundled package manager, or user-installed plugin files.
|
||||
|
||||
The [Electron shell file list](../scripts/electron-builder-config.mjs) excludes recognized JavaScript/CSS/TypeScript source maps and TypeScript build caches from the separate `resources/app.asar/node_modules` dependency collection. These exclusions preserve runtime code, native modules, WASM, data files (including ordinary `.map` assets), licenses, and notices; [shell archive tests](../tests/shell-file-selection.spec.ts) check retained bytes and exclusions.
|
||||
@@ -274,6 +272,8 @@ An unpacked artifact contains Electron, the materialized dsh production tree, pn
|
||||
|
||||
## Installation and release verification
|
||||
|
||||
Windows lists the installed application by product name without a version suffix; the version remains in the separate version field. Desktop's `package.json` `author.name` supplies the installer publisher and executable company name, independently of the signing certificate. Windows and macOS retain product-name copyright text. Installation or upgrade with a rebuilt installer applies the new metadata; existing installations retain their previous values until then.
|
||||
|
||||
Keep the generated installer, its version and packaging records together. Review signatures and runtime checks before installation, then follow the [installed-update qualification procedure](../tests/installed-update/README.md) for installed launch and upgrade evidence. The [Desktop test record](../tests/README.md) owns verification limits; a successful workflow alone does not establish production preset, new-workstation or installed-upgrade acceptance.
|
||||
|
||||
## Dev Note
|
||||
|
||||
@@ -230,8 +230,6 @@ pnpm run dev:bundle-registry
|
||||
|
||||
## 运行时文件筛选与安装检查
|
||||
|
||||
Windows 以不带版本后缀的产品名称显示已安装应用,版本保留在单独的版本字段中。发布者取自 Desktop 的 `package.json` 作者名称,与签名证书相互独立。这些字段在重新构建的安装包安装或更新应用时生效。
|
||||
|
||||
Desktop 在本地打包工作区包,并通过目标捆绑的 Node 和 pnpm 安装外部依赖。[Desktop 文件策略](../scripts/runtime-file-policy.ts)随后在签名和完整性封装前过滤不可变的 `resources/app.asar/dsh/node_modules` 副本。它排除 TypeScript 声明、已识别的 JavaScript/CSS/TypeScript source map、TypeScript 构建缓存、Domino 测试目录及 Yarn 开发元数据、选定的原生编译器输出和其他平台的 node-pty 预构建文件。非 Windows 目标还会排除 `node-pty/third_party/conpty`;Windows 目标保留该目录。它保留运行时 JavaScript、目标平台的原生模块及其 DLL/EXE 辅助文件、WASM、未知资源、许可证和 notices。依赖清单在完整性封装前经过 electron-builder 的元数据清理,确保归档保持已记录的字节。该策略不修改 npm tarball、捆绑的包管理器或用户安装的插件文件。
|
||||
|
||||
[Electron 外壳文件清单](../scripts/electron-builder-config.mjs)从单独收集的 `resources/app.asar/node_modules` 依赖中排除已识别的 JavaScript/CSS/TypeScript source map 和 TypeScript 构建缓存。这些排除规则保留运行时代码、原生模块、WASM、数据文件(包括普通 `.map` 资源)、许可证和 notices;[外壳归档测试](../tests/shell-file-selection.spec.ts)检查保留文件的字节和排除项。
|
||||
@@ -274,6 +272,8 @@ macOS 签名打包在组装 App 时、代码签名前写入 `Contents/Resources/
|
||||
|
||||
## 安装与发布验收
|
||||
|
||||
Windows 以不带版本后缀的产品名称显示已安装应用,版本保留在单独的版本字段中。Desktop 的 `package.json` 中的 `author.name` 提供安装包发布者和可执行文件公司名称,与签名证书相互独立。Windows 和 macOS 的版权文本仍使用产品名称。重新构建的安装包在安装或升级时写入新元数据;既有安装在此之前保留原值。
|
||||
|
||||
一起保留生成的安装包、版本和打包记录。安装前检查签名与运行时验证结果,再按[已安装更新验收流程](../tests/installed-update/README.zh.md)记录安装后启动及升级证据。[Desktop 测试记录](../tests/README.zh.md)维护验证限制;工作流成功本身不代表 production preset、新工作站或已安装升级验收通过。
|
||||
|
||||
## 开发备注
|
||||
|
||||
@@ -114,6 +114,7 @@ export function createElectronBuilderConfig(
|
||||
...packaged === undefined ? {} : { dshBuildCommit: packaged.commit, dshBuildDirty: packaged.dirty },
|
||||
},
|
||||
productName: 'DeepSeek Harness',
|
||||
copyright: `Copyright © ${new Date().getFullYear()} \${productName}`,
|
||||
// Unsigned builds carry their own suffix so a shared file can never pass for a release artifact.
|
||||
artifactName: `deepseek-harness-\${version}-\${os}-\${arch}${output.suffix}.\${ext}`,
|
||||
directories: { output: output.directory },
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { tmpdir } from 'node:os'
|
||||
import { readFileSync } from 'node:fs'
|
||||
import { Arch, Platform } from 'electron-builder'
|
||||
import { Packager } from 'app-builder-lib'
|
||||
import { AppInfo, Packager } from 'app-builder-lib'
|
||||
import { expandMacro } from 'app-builder-lib/out/util/macroExpander.js'
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
|
||||
const { execute } = vi.hoisted(() => ({ execute: vi.fn(async () => undefined) }))
|
||||
@@ -37,6 +38,17 @@ describe('installer preparation preserves application dependencies', () => {
|
||||
try {
|
||||
const { createElectronBuilderConfig } = await import('../electron-builder.config.mjs')
|
||||
const config = createElectronBuilderConfig(env, platform, 'x64')
|
||||
const metadataPackager = new Packager({ projectDir: tmpdir() })
|
||||
Object.defineProperties(metadataPackager, {
|
||||
config: { value: config },
|
||||
metadata: { value: JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')) },
|
||||
})
|
||||
const appInfo = new AppInfo(metadataPackager, undefined)
|
||||
expect(appInfo.companyName).toBe('Hangzhou DeepSeek Artificial Intelligence Co., Ltd.')
|
||||
expect(appInfo.copyright).toBe(`Copyright © ${new Date().getFullYear()} DeepSeek Harness`)
|
||||
if (platform === 'win32') {
|
||||
expect(expandMacro(config.nsis.uninstallDisplayName, null, appInfo, {}, false)).toBe('DeepSeek Harness')
|
||||
}
|
||||
const aboutIcon = config.extraResources.find(resource => resource.to === 'icon.png')
|
||||
expect(aboutIcon).toBeDefined()
|
||||
expect(readFileSync(aboutIcon!.from)).toEqual(readFileSync(new URL('../resources/icon-windows.png', import.meta.url)))
|
||||
|
||||
Reference in new issue
Block a user