fix(desktop): clarify source rejection and isolate Git fixtures

This commit is contained in:
winewill committed 2026-10-15 14:03:50 +08:00
1 parent 61059baf61
commit 29221675a2
6 files changed
+30 -22

No files matched your search

+2 -2
View File
@@ -85,8 +85,8 @@ jobs:
const head=cp.execFileSync('git',['rev-parse','HEAD'],{encoding:'utf8'}).trim();
if(tagged!==head) throw Error('Checkout does not match source tag');
} else {
const branch=cp.execFileSync('git',['symbolic-ref','--short','HEAD'],{encoding:'utf8'}).trim();
if(branch!==ref || ref.startsWith('refs/')) throw Error('Select a branch in this repository, not a SHA or PR ref');
const branch=cp.execFileSync('git',['rev-parse','--abbrev-ref','HEAD'],{encoding:'utf8'}).trim();
if(branch==='HEAD' || branch!==ref || ref.startsWith('refs/')) throw Error('Select a branch in this repository, not a SHA or PR ref');
}
if(!fs.readFileSync('apps/desktop/scripts/desktop-ci-version.mjs','utf8').includes('PACKAGE_VERSION_MODE')) throw Error('Source lacks Desktop channel/version CI support; select a newer release');"
- uses: pnpm/action-setup@v5.0.0
+2 -2
View File
@@ -97,8 +97,8 @@ jobs:
const head=cp.execFileSync('git',['rev-parse','HEAD'],{encoding:'utf8'}).trim();
if(tagged!==head) throw Error('Checkout does not match source tag');
} else {
const branch=cp.execFileSync('git',['symbolic-ref','--short','HEAD'],{encoding:'utf8'}).trim();
if(branch!==ref || ref.startsWith('refs/')) throw Error('Select a branch in this repository, not a SHA or PR ref');
const branch=cp.execFileSync('git',['rev-parse','--abbrev-ref','HEAD'],{encoding:'utf8'}).trim();
if(branch==='HEAD' || branch!==ref || ref.startsWith('refs/')) throw Error('Select a branch in this repository, not a SHA or PR ref');
}
if(!fs.readFileSync('apps/desktop/scripts/desktop-ci-version.mjs','utf8').includes('PACKAGE_VERSION_MODE')) throw Error('Source lacks Desktop channel/version CI support; select a newer release');"
- uses: pnpm/action-setup@v5.0.0
+2 -2
View File
@@ -18,8 +18,8 @@
en: 990ff7e56dd6005a
zh: 18f9dc23c520dc8c
/desktop-ci-publication/package-and-publish:
en: 46aaf2a0e7a818cc
zh: aa2de110b2ee084d
en: 2143e73bc7c65385
zh: cd968050774f4bb3
/desktop-ci-publication/recovery-and-records:
en: e92bfad06162443e
zh: 6c3e3d8ece673217
+1 -1
View File
@@ -35,7 +35,7 @@ Environment approval gates this workflow, not arbitrary code running under the s
## Package and publish
Select the platform's `Package Desktop` workflow, preset, source, channel and version mode. `source_ref` accepts repository branch names (for example `feature/desktop-update`) or `dsh-v*` tags for test; production accepts only `master` or `dsh-v*` tags. Tags must match the selected product version. Dispatch the packaging workflow from `master` and enter the source separately; raw commit SHAs, PR refs and fork repositories are not supported. The selected source must contain the CI adapters, so older sources fail before dependency installation. Only select trusted branches: their build code runs on the signing machine. Publication uses the recorded commit and requires it to remain in the selected branch history; normal branch advances are allowed, deletion or a diverging force-push rejects. Tag publication requires the tag to still resolve to the recorded commit. Dispatch the publisher from `master`; its hosted routing job rejects other refs before scheduling the original machine. The packaged source commit is recorded separately. `version_mode=default` selects product for production and auto for test; product preserves the selected checkout version, auto appends date/run/attempt, and manual requires `build_version`. A latest package requires a stable version, so test/latest needs product or a stable manual version. The optional `test_release_id` is the test URL prefix: blank retains the machine default, successive upgrade tests on that platform need the same value, and defaults should be rotated periodically. It is not a GitHub run ID. See [packaging configuration](../../packaging/README.md#configuration-and-local-builds) for its validation and rotation limits.
Select the platform's `Package Desktop` workflow, preset, source, channel and version mode. `source_ref` accepts repository branch names (for example `feature/desktop-update`) or `dsh-v*` tags for test; production accepts only `master` or `dsh-v*` tags. Names matching `dsh-v` followed by a digit and letters, digits, dots or hyphens are treated as tags, even if a branch has that name. Tags must match the selected product version. We recommend dispatching the packaging workflow from `master` and enter the source separately; raw commit SHAs, PR refs and fork repositories are not supported. The selected source must contain the CI adapters, so older sources fail before dependency installation. Only select trusted branches: their build code runs on the signing machine. This is an operating convention, not enforced workflow-origin or credential isolation. Publication uses the recorded commit and requires it to remain in the selected branch history; normal branch advances are allowed, deletion or a diverging force-push rejects. Tag publication requires the tag to still resolve to the recorded commit. Dispatch the publisher from `master`; its hosted routing job rejects other refs before scheduling the original machine. The packaged source commit is recorded separately. `version_mode=default` selects product for production and auto for test; product preserves the selected checkout version, auto appends date/run/attempt, and manual requires `build_version`. A latest package requires a stable version, so test/latest needs product or a stable manual version. The optional `test_release_id` is the test URL prefix: blank retains the machine default, successive upgrade tests on that platform need the same value, and defaults should be rotated periodically. It is not a GitHub run ID. See [packaging configuration](../../packaging/README.md#configuration-and-local-builds) for its validation and rotation limits.
Packaging only retains files. After success, open **Publish Desktop · COS → Run workflow** on `master`, enter `package_run_id` from the packaging run URL, and optionally enter `package_run_attempt`. Blank selects the latest attempt, which must have succeeded; it never falls back to an older success. An explicit attempt selects that exact successful build. Windows must be signed; macOS must finish notarization and stapling. GitHub job evidence selects the original runner; its local manifest supplies the preset, version, source and channel before approval. No installer or request artifact is downloaded. Retained packages with the old `publishRequested=false` flag remain eligible; missing or changed local files stop publication.
+1 -1
View File
@@ -35,7 +35,7 @@ Environment 审批限制此工作流,不限制同一机器账户运行的任
## 打包与发布
选择对应平台的 `Package Desktop` 工作流、preset、源码、通道和版本模式。test 的 `source_ref` 接受仓库内分支名(如 `feature/desktop-update`)或 `dsh-v*` tag;production 仅接受 `master` 或 `dsh-v*` tag。tag 必须与所选产品版本一致。从 `master` 启动打包工作流,再单独填写打包源码;不支持直接填写 commit SHA、PR ref 或 fork 仓库。源码必须包含 CI 适配脚本,旧源码会在安装依赖前失败。仅选择可信分支:其构建代码将在签名机器上执行。发布使用记录的 commit,并要求该提交仍在所选分支历史中;正常追加提交不影响发布,删除分支或导致历史分叉的强推会拒绝。tag 发布要求 tag 仍指向记录的提交。从 `master` 发起发布;托管路由 job 会在派发到原机器前拒绝其他 ref。实际打包源码提交单独记录。`version_mode=default` 对 production 选择 product,对 test 选择 auto;product 保留所选源码版本,auto 追加日期/run/attempt,manual 要求填写 `build_version`。latest 包要求稳定版本,因此 test/latest 需选择 product 或稳定的手填版本。可选 `test_release_id` 是测试 URL 前缀:留空沿用机器默认值,同一平台连续升级测试需保持相同值,并应定期轮换默认值。它不是 GitHub run ID。格式校验和轮换限制见[打包配置](../../packaging/README.zh.md#configuration-and-local-builds)。
选择对应平台的 `Package Desktop` 工作流、preset、源码、通道和版本模式。test 的 `source_ref` 接受仓库内分支名(如 `feature/desktop-update`)或 `dsh-v*` tag;production 仅接受 `master` 或 `dsh-v*` tag。符合 `dsh-v` 后接数字、其余为字母、数字、点或连字符的名称按 tag 处理,即使存在同名分支。tag 必须与所选产品版本一致。建议从 `master` 启动打包工作流,再单独填写打包源码;不支持直接填写 commit SHA、PR ref 或 fork 仓库。源码必须包含 CI 适配脚本,旧源码会在安装依赖前失败。仅选择可信分支:其构建代码将在签名机器上执行。这是操作约定,不提供工作流来源强制限制或凭据隔离。发布使用记录的 commit,并要求该提交仍在所选分支历史中;正常追加提交不影响发布,删除分支或导致历史分叉的强推会拒绝。tag 发布要求 tag 仍指向记录的提交。从 `master` 发起发布;托管路由 job 会在派发到原机器前拒绝其他 ref。实际打包源码提交单独记录。`version_mode=default` 对 production 选择 product,对 test 选择 auto;product 保留所选源码版本,auto 追加日期/run/attempt,manual 要求填写 `build_version`。latest 包要求稳定版本,因此 test/latest 需选择 product 或稳定的手填版本。可选 `test_release_id` 是测试 URL 前缀:留空沿用机器默认值,同一平台连续升级测试需保持相同值,并应定期轮换默认值。它不是 GitHub run ID。格式校验和轮换限制见[打包配置](../../packaging/README.zh.md#configuration-and-local-builds)。
打包只保留文件。成功后,在 `master` 上打开 **Publish Desktop · COS → Run workflow**,填写打包运行 URL 中的 `package_run_id`,并可填写 `package_run_attempt`。留空选择最新尝试,且该尝试必须成功,不会回退到较早的成功尝试;显式填写则选择对应的成功构建。Windows 必须完成签名,macOS 必须完成公证和 stapling。GitHub job 证据确定原 runner,本机清单在审批前提供 preset、版本、源码和通道。不会下载安装包或请求 artifact。旧清单的 `publishRequested=false` 不影响发布资格;本机文件缺失或变化会停止发布。
+22 -14
View File
@@ -10,10 +10,15 @@ it.each(['macos', 'windows'])('%s packaging accepts test branches but preserves
jobs: { package: { steps: Array<{ name?: string; run?: string }> } }
}
const command = workflow.jobs.package.steps.find(step => step.name === 'Validate selected source and adapter support')!.run!
expect(command.startsWith('node -e "')).toBe(true)
expect(command.endsWith('"')).toBe(true)
const script = command.slice('node -e "'.length, -1)
const root = mkdtempSync(join(tmpdir(), 'desktop-source-'))
try {
const git = (...args: string[]) => execFileSync('git', args, { cwd: root, encoding: 'utf8', stdio: 'pipe' }).trim()
const env = { ...process.env, GIT_CONFIG_NOSYSTEM: '1', GIT_CONFIG_GLOBAL: '', GIT_CONFIG_PARAMETERS: '',
GIT_CONFIG_COUNT: '0', GIT_DIR: undefined, GIT_WORK_TREE: undefined, GIT_INDEX_FILE: undefined }
const git = (...args: string[]) => execFileSync('git', ['-c', 'core.hooksPath=/dev/null', '-c', 'tag.gpgSign=false', ...args],
{ cwd: root, env, encoding: 'utf8', stdio: 'pipe' }).trim()
git('init', '--initial-branch=master')
mkdirSync(join(root, 'apps/desktop/scripts'), { recursive: true })
writeFileSync(join(root, 'package.json'), '{"version":"1.0.0"}')
@@ -25,25 +30,28 @@ it.each(['macos', 'windows'])('%s packaging accepts test branches but preserves
git('tag', 'dsh-v2.0.0')
const run = (preset: string, ref: string) => {
const result = spawnSync(process.execPath, ['-e', script], {
cwd: root, encoding: 'utf8', env: { ...process.env, DSH_PACKAGING_PRESET: preset, PACKAGE_SOURCE_REF: ref },
cwd: root, encoding: 'utf8', env: { ...env, DSH_PACKAGING_PRESET: preset, PACKAGE_SOURCE_REF: ref },
})
expect(result.error).toBeUndefined()
expect(result.signal).toBeNull()
return result.status
return result
}
for (const preset of ['test', 'production']) expect(run(preset, 'master')).toBe(0)
for (const preset of ['test', 'production']) expect(run(preset, 'master').status).toBe(0)
git('checkout', '-b', 'feature/desktop-update')
expect(run('test', 'feature/desktop-update')).toBe(0)
expect(run('production', 'feature/desktop-update')).not.toBe(0)
expect(run('test', 'refs/pull/42/head')).not.toBe(0)
expect(run('test', 'refs/heads/feature/desktop-update')).not.toBe(0)
expect(run('unknown', 'feature/desktop-update')).not.toBe(0)
expect(run('test', 'feature/desktop-update').status).toBe(0)
expect(run('production', 'feature/desktop-update').status).not.toBe(0)
expect(run('test', 'refs/pull/42/head').status).not.toBe(0)
expect(run('test', 'refs/heads/feature/desktop-update').status).not.toBe(0)
expect(run('unknown', 'feature/desktop-update').status).not.toBe(0)
git('checkout', '--detach', sha)
expect(run('test', sha)).not.toBe(0)
expect(run('test', 'master')).not.toBe(0)
for (const preset of ['test', 'production']) expect(run(preset, 'dsh-v1.0.0')).toBe(0)
expect(run('test', 'dsh-v2.0.0')).not.toBe(0)
for (const ref of [sha, 'master', 'HEAD', 'refs/pull/42/head']) {
const result = run('test', ref)
expect(result.status).not.toBe(0)
expect(result.stderr).toContain('Select a branch in this repository, not a SHA or PR ref')
}
for (const preset of ['test', 'production']) expect(run(preset, 'dsh-v1.0.0').status).toBe(0)
expect(run('test', 'dsh-v2.0.0').status).not.toBe(0)
writeFileSync(join(root, 'apps/desktop/scripts/desktop-ci-version.mjs'), 'old adapter')
expect(run('test', 'dsh-v1.0.0')).not.toBe(0)
expect(run('test', 'dsh-v1.0.0').status).not.toBe(0)
} finally { rmSync(root, { recursive: true, force: true, maxRetries: 3 }) }
})