加固部署配置与敏感路径拦截 #1
@@ -16,7 +16,7 @@
|
||||
- token、附件下载凭据和敏感业务信息不得写入 URL、日志、系统通知正文或明文浏览器存储。
|
||||
- 正式桌面客户端的默认 CTMS 服务端入口必须由构建环境变量 `VITE_DESKTOP_SERVER_URL` 注入,不得在运行时代码中写死生产域名;用户仍可在桌面服务器设置中手动覆盖,手动值优先并沿用既有的切换服务器登出与缓存失效边界。该变量只表示业务服务端 origin,不得与 updater 制品前缀 `DESKTOP_UPDATE_BASE_URL` 混用。
|
||||
- Windows x64 NSIS 已获准作为正式桌面发布目标;正式制品必须由 `.github/workflows/desktop-release-candidate.yml` 从与 macOS/Web 相同的 `vX.Y.Z` tag 和 SHA 构建。平台签名默认要求组织 Windows 代码签名证书、RFC 3161 时间戳和 Authenticode 校验;只有 `frontend/desktop-release-policy.json` 中按精确版本记录、经发布负责人批准的例外可跳过平台签名。无论是否采用平台签名例外,都必须使用 updater 私钥、校验 updater feed,并明确标记平台未签名风险。`.github/workflows/desktop-windows-internal.yml` 仍只用于分支上的无签名兼容性验证,不得生成生产 `latest.json`、updater feed 或正式发布制品。
|
||||
- v0.1.0 另获准在 GitHub Actions 额度不可用时,从最终 `release` 上不可移动的 `v0.1.0` tag/SHA 在受控 macOS 主机本地构建并先行上传 macOS ad-hoc 制品;Windows 只能在额度恢复后从同一 tag/SHA 后补。macOS 先行阶段必须发布 updater `.sig`、checksum、provenance、`UNSIGNED-PLATFORM` 与 Windows pending 说明,但不得发布或替换生产 `latest.json`;只有 Windows `NotSigned` 制品和联合 feed 均验证通过后才能激活自动更新源。该本地/分阶段例外不适用于后续版本。
|
||||
- v0.1.0 另获准在 GitHub Actions 额度不可用时,从最终 `release` 上不可移动的 `v0.1.0` tag/SHA 在受控 macOS 主机本地构建并先行上传 macOS ad-hoc 制品;Windows 只能在额度恢复后从同一 tag/SHA 后补。面向安装用户的 GitHub Release 只保留 DMG 与只校验该安装包的 `SHA256SUMS.txt`,平台未签名风险和 Windows pending 状态写入 Release Notes。macOS updater 包及 `.sig`、完整 checksum、provenance、`UNSIGNED-PLATFORM` 与 Windows pending 证据必须保存在被 Git 忽略的私有发布目录,待 Windows `NotSigned` 制品和联合 feed 均验证通过后再发布到可匿名读取的独立 HTTPS updater 源;此前不得发布或替换生产 `latest.json`。该本地/分阶段例外不适用于后续版本。
|
||||
|
||||
## 分支与发布治理
|
||||
|
||||
@@ -59,4 +59,4 @@ npm run desktop:build:app
|
||||
|
||||
本地缓存相关变更至少执行 `runtime:check`、`desktop:release:check`、`ui:contract`、`type-check`、`test:unit` 和 `build`;若新增 Tauri command、capability、CSP 或底层持久化存储,还需执行 `desktop:build:app` 并在真实桌面 App 中验证缓存清理和诊断入口。
|
||||
|
||||
正式桌面发布构建必须使用组织批准的 updater 签名私钥,updater 签名不可因平台签名例外而关闭。平台签名默认要求 macOS 完成 Apple 签名/公证、Windows 完成组织代码签名、RFC 3161 时间戳和 Authenticode 校验。当前仅批准 v0.1.0 采用受控分发例外:macOS 使用 ad-hoc 签名且不公证,Windows 应用和安装器保持 Authenticode 未签名;制品名、发布说明、校验清单和 provenance 必须清楚标注 `UNSIGNED-PLATFORM`,并提示 Gatekeeper/SmartScreen 警告。该例外不自动适用于后续版本。
|
||||
正式桌面发布构建必须使用组织批准的 updater 签名私钥,updater 签名不可因平台签名例外而关闭。平台签名默认要求 macOS 完成 Apple 签名/公证、Windows 完成组织代码签名、RFC 3161 时间戳和 Authenticode 校验。当前仅批准 v0.1.0 采用受控分发例外:macOS 使用 ad-hoc 签名且不公证,Windows 应用和安装器保持 Authenticode 未签名;制品名、Release Notes、私有发布证据、完整 updater 校验清单和 provenance 必须清楚标注 `UNSIGNED-PLATFORM`,并提示 Gatekeeper/SmartScreen 警告。面向安装用户的 GitHub Release 可按精确版本策略精简为安装包与对应 checksum,但不得因此删除私有 updater 签名制品或验证证据。该例外不自动适用于后续版本。
|
||||
|
||||
@@ -290,9 +290,9 @@ npm run desktop:build:app
|
||||
- Windows 应用和 NSIS 安装器不做 Authenticode 签名,必须通过 `Get-AuthenticodeSignature` 确认 `NotSigned`,不执行或声称 RFC 3161 时间戳。
|
||||
- 两端仍必须从同一 `v0.1.0` tag 和 SHA 构建,使用同一 updater 私钥生成 `.sig`,并通过联合 feed、checksum 和 provenance 校验。
|
||||
- GitHub Actions 额度不可用期间,发布负责人额外批准从最终 `v0.1.0` tag/SHA 在受控 macOS 主机本地构建并先行上传 macOS 制品;Windows 必须在恢复后从同一 tag/SHA 后补。
|
||||
- macOS 先行 Release 必须包含 DMG、updater 包及 `.sig`、checksum、provenance、`UNSIGNED-PLATFORM` 和 Windows pending 说明,且不得包含或替换生产 `latest.json`。
|
||||
- macOS 先行的用户可见 GitHub Release 只包含 DMG、仅覆盖该 DMG 的 checksum 和 GitHub 自动源码归档;Release Notes 必须明确 macOS ad-hoc/未公证风险和 Windows pending,且不得包含或替换生产 `latest.json`。updater 包及 `.sig`、完整 checksum、provenance、`UNSIGNED-PLATFORM` 和 Windows pending 证据必须先复制到权限受限且被 Git 忽略的私有发布目录。
|
||||
- Windows `NotSigned` 实物和联合 feed 全部验证通过后,才允许激活生产 updater feed;tag 不得为补充 Windows 制品而移动。
|
||||
- 制品与 Actions artifact 名称必须含 `_UNSIGNED` 或 `UNSIGNED-PLATFORM`,发布目录必须携带 `UNSIGNED-PLATFORM-RELEASE.txt` 和 `DESKTOP-RELEASE-PROVENANCE.json`。
|
||||
- 制品与 Actions artifact 名称必须含 `_UNSIGNED` 或 `UNSIGNED-PLATFORM`,私有证据/完整 updater 发布目录必须携带 `UNSIGNED-PLATFORM-RELEASE.txt` 和 `DESKTOP-RELEASE-PROVENANCE.json`;installer-only GitHub Release 通过 `_UNSIGNED` 安装包名和 Release Notes 呈现风险,不要求公开展示内部证据文件。
|
||||
- 受控分发说明必须明确提示 macOS Gatekeeper 与 Windows SmartScreen 警告;平台未签名制品不得描述为 Apple/Microsoft 信任或已公证/已 Authenticode 签名。
|
||||
|
||||
本地实物验证已完成:使用当前 updater 私钥成功构建 Universal `x86_64 arm64` macOS app、DMG、`.app.tar.gz` 和 `.sig`;`codesign --verify --deep --strict` 通过,签名详情为 `Signature=adhoc`、`TeamIdentifier=not set`,Gatekeeper 拒绝符合预期。Windows `NotSigned`、NSIS 和 updater `.sig` 仍须由 `windows-latest` 原生 job 在正式 tag 上验证。
|
||||
|
||||
@@ -321,10 +321,16 @@ For v0.1.0 only, the release owner also approved a staged contingency while
|
||||
hosted Actions capacity is unavailable: macOS may be built on a controlled
|
||||
local macOS host from the immutable final `v0.1.0` tag and published first.
|
||||
Windows remains pending and must later be built from that same tag and SHA.
|
||||
The macOS-only release must carry checksums, provenance, updater signature,
|
||||
platform-trust warnings, and an explicit Windows-pending notice. It must not
|
||||
publish or replace production `latest.json`; updater feed activation waits for
|
||||
combined macOS and Windows verification.
|
||||
The user-facing macOS-only GitHub Release may contain only the DMG and a
|
||||
checksum manifest that covers that installer; platform-trust and
|
||||
Windows-pending status must remain explicit in the Release Notes. The updater
|
||||
package and signature, full checksum manifest, provenance, warning, and
|
||||
Windows-pending evidence must be retained in a Git-ignored private release
|
||||
directory. After Windows is built from the same tag and SHA, those updater
|
||||
artifacts may be published only to a separately configured anonymous HTTPS
|
||||
update origin. The staged release must not publish or replace production
|
||||
`latest.json`; updater feed activation waits for combined macOS and Windows
|
||||
verification.
|
||||
|
||||
Reference:
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ npm run desktop:build:app
|
||||
|
||||
正式桌面发布构建必须从同一正式 tag 分别在 macOS 和 Windows 原生 CI job 执行。两端都必须设置 updater 签名私钥,updater 签名不可关闭。平台签名默认路径仍要求 macOS 设置 Apple 签名/公证变量并以 `REQUIRE_DESKTOP_SIGNING=true` 执行,Windows 设置 PFX、密码和 RFC 3161 时间戳变量并以 `REQUIRE_WINDOWS_SIGNING=true` 执行。只有 `frontend/desktop-release-policy.json` 对当前精确版本存在已批准例外时,workflow 才可改为 macOS ad-hoc、Windows Authenticode 未签名路径;例外制品必须标注 `UNSIGNED-PLATFORM`、生成 provenance 和风险说明。两个平台与联合 feed 校验通过后才能汇总正式 updater feed。
|
||||
|
||||
v0.1.0 额外批准 GitHub Actions 额度不可用时的分阶段应急路径:先在受控 macOS 主机从最终、不可移动的 `v0.1.0` tag/SHA 本地构建并上传 macOS ad-hoc 制品,随附 updater `.sig`、checksum、provenance、平台未签名警告和 Windows pending 说明;Windows 恢复后必须从同一 tag/SHA 后补。macOS 先行阶段不得发布或替换生产 `latest.json`,联合 feed 必须等待 Windows `NotSigned` 实物验证完成。
|
||||
v0.1.0 额外批准 GitHub Actions 额度不可用时的分阶段应急路径:先在受控 macOS 主机从最终、不可移动的 `v0.1.0` tag/SHA 本地构建 macOS ad-hoc 制品,面向安装用户的 GitHub Release 只保留 DMG 与仅覆盖该安装包的 checksum,平台未签名警告和 Windows pending 状态写入 Release Notes。macOS updater 包及 `.sig`、完整 checksum、provenance、风险说明和 Windows pending 证据必须保存在被 Git 忽略的私有发布目录;Windows 恢复后必须从同一 tag/SHA 后补,并在联合验证通过后把 updater 制品发布到可匿名读取的独立 HTTPS 更新源。macOS 先行阶段不得发布或替换生产 `latest.json`,联合 feed 必须等待 Windows `NotSigned` 实物验证完成。
|
||||
|
||||
后端改动应补充执行受影响模块的后端测试、迁移检查和接口回归。
|
||||
|
||||
@@ -297,9 +297,9 @@ git tag -a v1.2.0 -m "CTMS v1.2.0"
|
||||
git push origin v1.2.0
|
||||
```
|
||||
|
||||
网页端、macOS 和 Windows 桌面端必须从同一个 `v1.2.0` 标签构建。不得从不同分支、不同提交或本地未提交状态构建正式制品。两个平台的 updater 签名制品必须始终验证通过;macOS 签名/公证和 Windows 代码签名/RFC 3161 时间戳必须验证通过,除非 `frontend/desktop-release-policy.json` 对该精确版本记录了已批准例外。采用例外时必须验证 macOS 确为 ad-hoc、Windows 确为 `NotSigned`,并随安装包分发 `UNSIGNED-PLATFORM` 风险说明、provenance 和 checksum,之后才能最后原子替换生产 `latest.json`。
|
||||
网页端、macOS 和 Windows 桌面端必须从同一个 `v1.2.0` 标签构建。不得从不同分支、不同提交或本地未提交状态构建正式制品。两个平台的 updater 签名制品必须始终验证通过;macOS 签名/公证和 Windows 代码签名/RFC 3161 时间戳必须验证通过,除非 `frontend/desktop-release-policy.json` 对该精确版本记录了已批准例外。采用例外时必须验证 macOS 确为 ad-hoc、Windows 确为 `NotSigned`,并在 Release Notes、私有发布证据、完整 updater checksum 和 provenance 中记录 `UNSIGNED-PLATFORM` 风险;面向安装用户的 Release 可按精确版本策略只显示安装包与安装包 checksum,但 updater 制品及验证证据必须保留,之后才能最后原子替换生产 `latest.json`。
|
||||
|
||||
若执行 v0.1.0 的已批准分阶段应急路径,首次 macOS Release 可先于 Windows 发布,但 tag/SHA 不得移动;首次 Release 不包含 `latest.json`,并必须明确标记 Windows pending。Windows 后补且联合 feed 验证通过后,才允许按上述顺序激活生产 updater feed。
|
||||
若执行 v0.1.0 的已批准分阶段应急路径,首次 macOS Release 可先于 Windows 发布,但 tag/SHA 不得移动;GitHub Release 只保留 DMG、仅覆盖该 DMG 的 checksum 和 GitHub 自动提供的源码归档,并在 Release Notes 中明确标记未签名风险与 Windows pending。updater 包、`.sig`、完整 checksum、provenance 和说明文件必须在私有发布目录留存。Windows 后补且联合 feed 验证通过后,才允许把这些 updater 制品发布到独立匿名 HTTPS 更新源并按上述顺序激活生产 updater feed。
|
||||
|
||||
发布记录至少包含:
|
||||
|
||||
@@ -454,7 +454,7 @@ git log --oneline --decorate --graph --all -30
|
||||
- [ ] `npm run build` 通过
|
||||
- [ ] `npm run desktop:build:app` 通过
|
||||
- [ ] 正式桌面发布构建已使用 updater 签名私钥执行
|
||||
- [ ] 平台签名已验证,或当前精确版本已在 `frontend/desktop-release-policy.json` 获批例外且 `UNSIGNED-PLATFORM` 风险说明、provenance 和 checksum 齐备
|
||||
- [ ] 平台签名已验证,或当前精确版本已在 `frontend/desktop-release-policy.json` 获批例外且 Release Notes、私有 `UNSIGNED-PLATFORM` 证据、provenance 和完整 updater checksum 齐备;若 GitHub Release 采用 installer-only profile,公开 checksum 只覆盖公开安装包
|
||||
- [ ] 数据库迁移与回滚方案确认
|
||||
- [ ] 发布说明完成
|
||||
- [ ] `main -> release` 合并完成
|
||||
|
||||
@@ -163,26 +163,39 @@ Platform signing defaults to `signed`. An exception is allowed only when
|
||||
`frontend/desktop-release-policy.json` names the exact product version and
|
||||
records release-owner approval. The current v0.1.0 exception uses macOS ad-hoc
|
||||
signing and unsigned Windows application/installer binaries. Its artifact names
|
||||
and release directory contain `UNSIGNED-PLATFORM`; the directory must include
|
||||
`UNSIGNED-PLATFORM-RELEASE.txt`, `DESKTOP-RELEASE-PROVENANCE.json`, and
|
||||
`SHA256SUMS.txt`. This does not establish Apple or Microsoft publisher trust,
|
||||
and Gatekeeper or SmartScreen warnings are expected. Later versions return to
|
||||
the signed default unless separately approved.
|
||||
and verified updater release directory contain `UNSIGNED-PLATFORM`; the private
|
||||
evidence/update directory must include `UNSIGNED-PLATFORM-RELEASE.txt`,
|
||||
`DESKTOP-RELEASE-PROVENANCE.json`, and the full `SHA256SUMS.txt`. The
|
||||
user-facing GitHub Release may use the exact-version
|
||||
`installer-and-checksum-only` profile, with platform warnings in Release Notes
|
||||
and a separate checksum manifest covering only the displayed installer. This
|
||||
does not establish Apple or Microsoft publisher trust, and Gatekeeper or
|
||||
SmartScreen warnings are expected. Later versions return to the signed default
|
||||
unless separately approved.
|
||||
|
||||
### v0.1.0 staged macOS contingency
|
||||
|
||||
The release owner approved one additional v0.1.0 contingency for unavailable
|
||||
hosted Actions capacity. A controlled local macOS host may build the macOS
|
||||
ad-hoc artifacts from the immutable final `v0.1.0` tag and publish them first.
|
||||
That initial GitHub Release must include the DMG, updater package and `.sig`,
|
||||
`SHA256SUMS.txt`, provenance, the unsigned-platform warning, and an explicit
|
||||
Windows-pending notice. Windows must later be built from the same tag and SHA.
|
||||
That initial user-facing GitHub Release contains only the DMG and a
|
||||
`SHA256SUMS.txt` that covers the DMG, in addition to GitHub's automatic source
|
||||
archives. The Release Notes must state that macOS is ad-hoc/not notarized and
|
||||
that Windows remains pending. The macOS updater package and `.sig`, full
|
||||
checksum manifest, provenance, unsigned-platform warning, and Windows-pending
|
||||
notice must be copied to a permission-restricted, Git-ignored private release
|
||||
directory before any visible asset is removed. Windows must later be built from
|
||||
the same tag and SHA.
|
||||
|
||||
The staged macOS release is an installer distribution, not an activated
|
||||
cross-platform updater release. Do not upload or replace production
|
||||
`latest.json` until the Windows `NotSigned` installer/updater has been built and
|
||||
the combined macOS/Windows feed passes full verification. This fallback is
|
||||
limited to v0.1.0 and does not authorize local formal builds for later versions.
|
||||
the combined macOS/Windows feed passes full verification. The combined updater
|
||||
artifacts, signatures, provenance, full checksum manifest, and `latest.json`
|
||||
must use a separately configured HTTPS update origin that anonymous production
|
||||
clients can read; a private GitHub Release is not a valid production updater
|
||||
origin. This fallback is limited to v0.1.0 and does not authorize local formal
|
||||
builds for later versions.
|
||||
|
||||
## Windows Release and Internal Validation
|
||||
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
"macosLocalExactTagFallback": true,
|
||||
"windowsDelivery": "deferred-same-tag",
|
||||
"updaterFeedActivation": "after-combined-platform-verification",
|
||||
"githubReleaseAssetProfile": "installer-and-checksum-only",
|
||||
"stagedEvidenceRetention": "private-until-updater-publish",
|
||||
"updaterArtifactPublishTarget": "anonymous-https-origin",
|
||||
"approvedOn": "2026-07-17",
|
||||
"reason": "The v0.1.0 release owner cannot currently provide Apple Developer signing/notarization credentials or an organization Windows code-signing certificate, and hosted Windows build capacity is temporarily unavailable."
|
||||
}
|
||||
|
||||
@@ -41,6 +41,18 @@ const validatePolicy = (policy) => {
|
||||
exception?.updaterFeedActivation === "after-combined-platform-verification",
|
||||
`${prefix} must withhold the production updater feed until both platforms are verified.`,
|
||||
);
|
||||
assert(
|
||||
exception?.githubReleaseAssetProfile === "installer-and-checksum-only",
|
||||
`${prefix} must keep the user-facing GitHub Release limited to installers and their checksum manifest.`,
|
||||
);
|
||||
assert(
|
||||
exception?.stagedEvidenceRetention === "private-until-updater-publish",
|
||||
`${prefix} must retain updater artifacts and release evidence privately until updater publication.`,
|
||||
);
|
||||
assert(
|
||||
exception?.updaterArtifactPublishTarget === "anonymous-https-origin",
|
||||
`${prefix} must publish updater artifacts to an anonymous HTTPS origin.`,
|
||||
);
|
||||
}
|
||||
assert(/^\d{4}-\d{2}-\d{2}$/.test(exception?.approvedOn || ""), `${prefix} must record an approval date.`);
|
||||
assert(
|
||||
@@ -92,6 +104,9 @@ export const resolveDesktopReleasePolicy = (version, policy) => {
|
||||
macosLocalExactTagFallback: exception.macosLocalExactTagFallback === true,
|
||||
windowsDelivery: exception.windowsDelivery,
|
||||
updaterFeedActivation: exception.updaterFeedActivation,
|
||||
githubReleaseAssetProfile: exception.githubReleaseAssetProfile,
|
||||
stagedEvidenceRetention: exception.stagedEvidenceRetention,
|
||||
updaterArtifactPublishTarget: exception.updaterArtifactPublishTarget,
|
||||
exception,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -428,7 +428,7 @@ const verifyWorkflowGates = async () => {
|
||||
const windowsPendingNotice = await readFile(resolve(frontendDir, "desktop-release-windows-pending.txt"), "utf8");
|
||||
assert(
|
||||
windowsPendingNotice.includes("same immutable v0.1.0 tag") && windowsPendingNotice.includes("latest.json is intentionally withheld"),
|
||||
"The staged v0.1.0 release must include an explicit Windows-pending and updater-feed notice.",
|
||||
"The staged v0.1.0 private release evidence must include an explicit Windows-pending and updater-feed notice.",
|
||||
);
|
||||
|
||||
const releasePolicy = await readJson(resolve(frontendDir, "desktop-release-policy.json"));
|
||||
@@ -446,8 +446,11 @@ const verifyWorkflowGates = async () => {
|
||||
assert(
|
||||
currentUnsignedException?.macosLocalExactTagFallback === true &&
|
||||
currentUnsignedException?.windowsDelivery === "deferred-same-tag" &&
|
||||
currentUnsignedException?.updaterFeedActivation === "after-combined-platform-verification",
|
||||
"The v0.1.0 exception must constrain local macOS staging, deferred Windows delivery, and updater feed activation.",
|
||||
currentUnsignedException?.updaterFeedActivation === "after-combined-platform-verification" &&
|
||||
currentUnsignedException?.githubReleaseAssetProfile === "installer-and-checksum-only" &&
|
||||
currentUnsignedException?.stagedEvidenceRetention === "private-until-updater-publish" &&
|
||||
currentUnsignedException?.updaterArtifactPublishTarget === "anonymous-https-origin",
|
||||
"The v0.1.0 exception must constrain local macOS staging, deferred Windows delivery, visible GitHub assets, private evidence retention, and updater publication.",
|
||||
);
|
||||
}
|
||||
if (currentUnsignedException) {
|
||||
|
||||
Reference in New Issue
Block a user