release(main): 准备 v0.1.0 候选版本 (#5)
Client Quality Gates / Shared client and Web (push) Has been cancelled
Client Quality Gates / macOS Desktop (push) Has been cancelled
Storage Persistence Guard / storage-persistence-audit (push) Has been cancelled
Client Quality Gates / Shared client and Web (pull_request) Has been cancelled
Client Quality Gates / macOS Desktop (pull_request) Has been cancelled
Storage Persistence Guard / storage-persistence-audit (pull_request) Has been cancelled
Client Quality Gates / Shared client and Web (push) Has been cancelled
Client Quality Gates / macOS Desktop (push) Has been cancelled
Storage Persistence Guard / storage-persistence-audit (push) Has been cancelled
Client Quality Gates / Shared client and Web (pull_request) Has been cancelled
Client Quality Gates / macOS Desktop (pull_request) Has been cancelled
Storage Persistence Guard / storage-persistence-audit (pull_request) Has been cancelled
* docs: add desktop project plan * feat(desktop): implement phase 1 tauri client * refactor(client): unify web and desktop release workflow * feat(desktop): implement phase 2 native capabilities * 完善桌面端交互体验与发布检查 * 完善桌面端界面、发布检查与邮箱域名同步 * fix(deploy): 修复数据库初始化复用旧镜像 * fix(deploy): 增加部署更新实时进度 * fix(auth): 支持无邮箱后缀时手动输入 * feat(desktop): 稳定桌面端界面与文件操作反馈 - 重构 DesktopPreferences 为分栏式设置面板,整合连接、外观、通知、更新与诊断信息分区,并补充过渡动效与暗色主题样式 - DesktopLayout 侧边栏导航分组支持展开折叠,调整管理/项目区块顺序并统一图标与标题 - 新增 fileTaskFeedback 工具,统一 pickFiles/saveFile/openFile 的成功/取消提示,替换审计导出、权限日志、附件、文档、线程、项目配置等处的直接调用 - desktopUpdateManager 暴露更新状态快照与状态变更监听,区分检查中、安装中、已推迟、失败等状态 - DesktopServerSettings 增加连接诊断信息(检查时间、健康地址、耗时、HTTP 状态) - unified-page.css 与 ProjectMilestones 引入 CSS 变量以适配暗色主题 - WebLayout 将服务器设置入口改为打开系统偏好面板,管理菜单中邮件服务归入系统设置分组 - ProfileSettings 移除已迁入偏好面板的桌面端专属区块 - 补充 Layout.desktop 布局与偏好面板契约测试 * feat(desktop): 支持桌面端三十天免登录 * 完善桌面端发布稳定化门禁 * 完善桌面端端到端回归收口 * 补齐桌面端附件文件流回归 * 完善桌面端回归与安全边界复审 * 完善桌面体验与系统通知收口 * feat(desktop): 收口桌面工作台视觉与活动反馈 * 优化桌面端界面布局 * style: 优化个人中心和偏好设置弹窗样式,重构工作入口为精致分屏布局并移除首字徽标 * 功能(桌面端):增加在线辅助本地缓存 * 优化桌面端标签导航与后台交互 * ci: 新增 Windows 桌面端内测构建 * fix: 修复桌面检查脚本的 Windows 路径判断 * test: 兼容 Windows 换行的桌面布局断言 * test: 兼容 Windows 换行的路由断言 * ci: 修复 Windows 内测构建配置传参 * ci: 避免 Windows 安装器构建交互等待 * 修复桌面端界面显示与稳定性问题 * feat(网页端): 完善登录后工作台与项目管理体验 * docs(desktop): 精简桌面端约束入口 * feat(admin): 完善审计访问上下文与后台布局 * fix(git): 跟踪原生图标资源 * fix(web): 修正工作台端侧标识 * feat(监控): 完善系统监控、登录状态与访问审计能力 * 修复(权限管理):统一 PM 系统导航与权限校验 * feat(工作台): 优化入口布局与连接安全状态 * feat(桌面与监控): 完善工作台导航和登录活动定位 - 优化桌面标签、上下文标题、前进后退、导航栏隐藏和原生菜单体验 - 补充登录会话 IP 采集、地理位置回退、管理端展示及数据库迁移 - 更新桌面发布检查、运维文档和前后端测试覆盖 * 功能(文档与桌面):完善文件预览下载与客户端构建基线 - 保存文档版本原始文件名,规范下载响应并持久化上传目录\n- 增加 PDF.js 预览、桌面保存打开流程及统一错误反馈\n- 统一 Node.js 22.13 构建基线并收紧临时文件权限门禁\n- 补充迁移、单元测试、发布检查与运维文档 * 功能(文档预览):集成 ONLYOFFICE 安全只读预览与工作台体验 新增 ONLYOFFICE 配置签名、内部内容接口、容器编排与反向代理。 打通网页端和桌面端独立预览工作区,完善文档入口、布局及帮助体验。 补充桌面安全发布门禁、开发脚本、使用文档和前后端测试。 * feat(collaboration): 完善在线文档协作与通知闭环 - 新增协作文件夹、文件、不可变修订、成员、会话、回调回执、编辑申请与分享链接数据模型。 - 补齐新建、导入、复制、下载、回收站、恢复、成员授权、所有权转让及文件级权限接口。 - 接入 ONLYOFFICE 共同编辑、历史版本预览与恢复、修订另存副本、导出下载审计和幂等回调保存。 - 增加编辑权限申请、审批通知、项目提醒聚合、通知 Feed、已读处理及历史待办数据回填。 - 支持公开分享的查看或编辑模式、有效期、密码哈希、失败锁定、短时访问凭证与固定分享地址。 - 增加协作者导出、申请编辑、工作表结构保护和所有权管理策略,并纳入项目接口权限矩阵。 - 新增协作文件库、编辑工作区、公开分享页、下载与另存为对话框,以及导航、路由和权限入口。 - 统一网页端与桌面端通知布局,增加沉浸式工作区和浏览器、Tauri 双端全屏能力。 - 扩展运行时文件下载适配、Tauri 环境识别和原生全屏命令,继续保持业务代码运行时边界。 - 加固 ONLYOFFICE 消息桥的同源下载、签名地址隔离和保存为能力校验,并更新桌面发布检查。 - 增加连续数据库迁移、50MB 上传限制、OnlyOffice 中文文案与开发启动路由校验。 - 补充协作、通知、权限、路由、运行时、布局和 OnlyOffice 相关测试及模块说明文档。 * refactor(frontend): 按需加载页面并清理未使用代码 - 将业务页面路由统一改为动态导入,拆分首屏入口与各功能模块构建产物。 - 将网页端和桌面端布局改为异步组件,避免两套平台布局同时进入初始包。 - 新增 Element Plus 按需安装入口,并通过全局配置组件统一注入中文语言包。 - 提取 API 运行时钩子,在应用启动时注入项目清理、令牌续期和认证失效退出能力。 - 将权限监控面板及地图资源改为延迟加载,补充地图加载状态、失败提示和切换竞态保护。 - 删除已被现有工作流替代的项目成员、接口权限、中心绑定、培训表单及旧项目首页等页面。 - 清理废弃的快捷操作、项目选择、用户选择、FAQ 表单、风险占位组件和旧地图辅助模块。 - 移除未使用的 API 方法、类型、字典、状态机、展示工具、样式和项目详情编辑逻辑。 - 开启 TypeScript 未使用变量与参数检查,并同步收紧相关测试和组件暴露类型。 - 移除未使用的 updater、date-fns 和 Sass 前端依赖,更新锁文件并删除旧 CSS 清洗插件。 - 更新路由、Axios、ETMF、通知、权限监控和桌面布局测试以覆盖重构后的边界。 * fix(审计): 移除共享库审计与预览噪声 * 功能(提醒):统一项目提醒中心与桌面通知链路 增加通用提醒状态、数据库迁移和定时同步,覆盖风险时效、文件回执、项目里程碑、访视窗口与协作申请。 新增网页端和桌面端提醒中心、真实投递诊断与固定隐私通知正文,并补齐登录来源聚合、测试和说明文档。 * feat(deploy): 默认安装 ONLYOFFICE 标准组件 * build(release): 加固 v0.1.0 桌面发布链路 (#3)
This commit is contained in:
@@ -14,6 +14,10 @@ on:
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: desktop-release-candidate-${{ github.ref }}
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
macos-release-candidate:
|
||||
name: Signed macOS release candidate
|
||||
@@ -67,6 +71,9 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Audit dependencies
|
||||
run: npm audit
|
||||
|
||||
- name: Check release build metadata and signing environment
|
||||
run: npm run release:env:check
|
||||
|
||||
@@ -94,37 +101,255 @@ jobs:
|
||||
- name: Build Web artifact
|
||||
run: npm run build
|
||||
|
||||
- name: Build signed Universal macOS artifacts
|
||||
- name: Build signed and notarized Universal macOS artifacts
|
||||
run: npm run desktop:build:macos-release -- --ci
|
||||
|
||||
- name: Create desktop update feed
|
||||
- name: Verify and stage macOS artifacts
|
||||
shell: bash
|
||||
run: |
|
||||
if [[ -z "${DESKTOP_UPDATE_BASE_URL}" ]]; then
|
||||
echo "DESKTOP_UPDATE_BASE_URL or workflow input artifact_base_url is required."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
app="$(find src-tauri/target -path '*/release/bundle/macos/*.app' -print -quit)"
|
||||
artifact="$(find src-tauri/target -path '*/release/bundle/macos/*.app.tar.gz' -print -quit)"
|
||||
if [[ -z "${artifact}" ]]; then
|
||||
echo "No macOS updater artifact was produced."
|
||||
dmg="$(find src-tauri/target -path '*/release/bundle/dmg/*.dmg' -print -quit)"
|
||||
if [[ -z "${app}" || -z "${artifact}" || -z "${dmg}" || ! -s "${artifact}.sig" ]]; then
|
||||
echo "Signed macOS app, updater artifact/signature, and DMG are all required."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
include_args=()
|
||||
dmg="$(find src-tauri/target -path '*/release/bundle/dmg/*.dmg' -print -quit)"
|
||||
if [[ -n "${dmg}" ]]; then
|
||||
include_args+=(--include "${dmg}")
|
||||
codesign --verify --deep --strict --verbose=2 "${app}"
|
||||
spctl --assess --type execute --verbose=2 "${app}"
|
||||
xcrun stapler validate "${app}"
|
||||
xcrun stapler validate "${dmg}"
|
||||
|
||||
stage="src-tauri/target/desktop-release-macos"
|
||||
mkdir -p "${stage}"
|
||||
cp "${artifact}" "${artifact}.sig" "${dmg}" "${stage}/"
|
||||
|
||||
- name: Upload signed macOS candidate artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ctms-desktop-macos-${{ github.ref_name }}
|
||||
path: frontend/src-tauri/target/desktop-release-macos/*
|
||||
if-no-files-found: error
|
||||
|
||||
windows-release-candidate:
|
||||
name: Signed Windows release candidate
|
||||
runs-on: windows-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: frontend
|
||||
env:
|
||||
VITE_BUILD_CHANNEL: release
|
||||
VITE_BUILD_COMMIT: ${{ github.sha }}
|
||||
RELEASE_BUILD: "true"
|
||||
REQUIRE_WINDOWS_SIGNING: "true"
|
||||
DESKTOP_UPDATE_BASE_URL: ${{ github.event_name == 'workflow_dispatch' && inputs.artifact_base_url || vars.DESKTOP_UPDATE_BASE_URL }}
|
||||
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
|
||||
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
|
||||
WINDOWS_CERTIFICATE: ${{ secrets.WINDOWS_CERTIFICATE }}
|
||||
WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}
|
||||
WINDOWS_TIMESTAMP_URL: ${{ vars.WINDOWS_TIMESTAMP_URL }}
|
||||
steps:
|
||||
- name: Checkout release source
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "22.13"
|
||||
cache: npm
|
||||
cache-dependency-path: frontend/package-lock.json
|
||||
|
||||
- name: Enforce release tag context
|
||||
shell: pwsh
|
||||
run: |
|
||||
if ($env:GITHUB_REF_TYPE -ne "tag") {
|
||||
throw "Signed desktop release candidates must run from a vX.Y.Z tag."
|
||||
}
|
||||
$expectedTag = "v$(node -p "require('./package.json').version")"
|
||||
if ($env:GITHUB_REF_NAME -ne $expectedTag) {
|
||||
throw "Release tag $env:GITHUB_REF_NAME does not match package version $expectedTag."
|
||||
}
|
||||
|
||||
- name: Setup Rust
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Audit dependencies
|
||||
run: npm audit
|
||||
|
||||
- name: Check release build metadata and signing environment
|
||||
run: npm run release:env:check
|
||||
|
||||
- name: Check signed desktop release readiness
|
||||
run: npm run desktop:release-readiness:check
|
||||
|
||||
- name: Check synchronized client version
|
||||
run: npm run version:check
|
||||
|
||||
- name: Check runtime boundary
|
||||
run: npm run runtime:check
|
||||
|
||||
- name: Check desktop release and security gate
|
||||
run: npm run desktop:release:check
|
||||
|
||||
- name: Check UI contract
|
||||
run: npm run ui:contract
|
||||
|
||||
- name: Type check
|
||||
run: npm run type-check
|
||||
|
||||
- name: Unit tests
|
||||
run: npm run test:unit
|
||||
|
||||
- name: Build Web artifact
|
||||
run: npm run build
|
||||
|
||||
- name: Import Windows code-signing certificate
|
||||
shell: pwsh
|
||||
run: |
|
||||
$pfxPath = Join-Path $env:RUNNER_TEMP "ctms-windows-signing.pfx"
|
||||
$encodedCertificate = $env:WINDOWS_CERTIFICATE `
|
||||
-replace "-----BEGIN [^-]+-----", "" `
|
||||
-replace "-----END [^-]+-----", "" `
|
||||
-replace "\s", ""
|
||||
[IO.File]::WriteAllBytes($pfxPath, [Convert]::FromBase64String($encodedCertificate))
|
||||
$password = ConvertTo-SecureString $env:WINDOWS_CERTIFICATE_PASSWORD -AsPlainText -Force
|
||||
$importedCertificates = Import-PfxCertificate -FilePath $pfxPath -CertStoreLocation "Cert:\CurrentUser\My" -Password $password -Exportable:$false
|
||||
$certificate = $importedCertificates | Where-Object { $_.HasPrivateKey } | Select-Object -First 1
|
||||
if (-not $certificate -or -not $certificate.HasPrivateKey) {
|
||||
throw "The imported Windows code-signing certificate is missing its private key."
|
||||
}
|
||||
$now = Get-Date
|
||||
if ($certificate.NotBefore -gt $now -or $certificate.NotAfter -le $now) {
|
||||
throw "The Windows code-signing certificate is not currently valid."
|
||||
}
|
||||
$codeSigningEku = $certificate.EnhancedKeyUsageList | Where-Object { $_.ObjectId.Value -eq "1.3.6.1.5.5.7.3.3" }
|
||||
if (-not $codeSigningEku) {
|
||||
throw "The Windows certificate does not contain the Code Signing enhanced key usage."
|
||||
}
|
||||
"WINDOWS_CERTIFICATE_THUMBPRINT=$($certificate.Thumbprint)" | Out-File -FilePath $env:GITHUB_ENV -Append
|
||||
Remove-Item $pfxPath -Force
|
||||
|
||||
- name: Write signed Windows Tauri config
|
||||
shell: pwsh
|
||||
run: |
|
||||
$config = @{
|
||||
bundle = @{
|
||||
windows = @{
|
||||
certificateThumbprint = $env:WINDOWS_CERTIFICATE_THUMBPRINT
|
||||
digestAlgorithm = "sha256"
|
||||
timestampUrl = $env:WINDOWS_TIMESTAMP_URL
|
||||
tsp = $true
|
||||
}
|
||||
}
|
||||
} | ConvertTo-Json -Depth 8
|
||||
Set-Content -Path "tauri.windows.release.conf.json" -Value $config -Encoding utf8
|
||||
Get-Content "tauri.windows.release.conf.json"
|
||||
|
||||
- name: Build signed Windows NSIS artifacts
|
||||
timeout-minutes: 30
|
||||
run: npm run desktop:build:windows-release -- --config tauri.windows.release.conf.json --ci
|
||||
|
||||
- name: Verify Authenticode and stage Windows artifacts
|
||||
shell: pwsh
|
||||
run: |
|
||||
$bundleDir = "src-tauri/target/release/bundle/nsis"
|
||||
$installers = @(Get-ChildItem -Path $bundleDir -Filter "*.exe" -File)
|
||||
$updaters = @(Get-ChildItem -Path $bundleDir -Filter "*.nsis.zip" -File)
|
||||
$appExecutables = @(Get-ChildItem -Path "src-tauri/target/release" -Filter "*.exe" -File)
|
||||
if ($installers.Count -ne 1 -or $updaters.Count -ne 1 -or $appExecutables.Count -eq 0) {
|
||||
throw "Exactly one NSIS installer/updater and at least one application executable are required."
|
||||
}
|
||||
|
||||
$signaturePath = "$($updaters[0].FullName).sig"
|
||||
if (-not (Test-Path $signaturePath) -or (Get-Item $signaturePath).Length -eq 0) {
|
||||
throw "The Windows updater signature is missing or empty."
|
||||
}
|
||||
|
||||
foreach ($executable in @($appExecutables + $installers)) {
|
||||
$signature = Get-AuthenticodeSignature -FilePath $executable.FullName
|
||||
if ($signature.Status -ne "Valid" -or -not $signature.SignerCertificate -or -not $signature.TimeStamperCertificate) {
|
||||
throw "Authenticode signature or RFC 3161 timestamp is invalid for $($executable.FullName): $($signature.StatusMessage)"
|
||||
}
|
||||
}
|
||||
|
||||
$stage = "src-tauri/target/desktop-release-windows"
|
||||
New-Item -ItemType Directory -Path $stage -Force | Out-Null
|
||||
Copy-Item $installers[0].FullName, $updaters[0].FullName, $signaturePath -Destination $stage
|
||||
|
||||
- name: Remove Windows signing certificate
|
||||
if: always()
|
||||
shell: pwsh
|
||||
run: |
|
||||
if ($env:WINDOWS_CERTIFICATE_THUMBPRINT) {
|
||||
Remove-Item "Cert:\CurrentUser\My\$env:WINDOWS_CERTIFICATE_THUMBPRINT" -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
Remove-Item (Join-Path $env:RUNNER_TEMP "ctms-windows-signing.pfx") -Force -ErrorAction SilentlyContinue
|
||||
Remove-Item "tauri.windows.release.conf.json" -Force -ErrorAction SilentlyContinue
|
||||
|
||||
- name: Upload signed Windows candidate artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ctms-desktop-windows-${{ github.ref_name }}
|
||||
path: frontend/src-tauri/target/desktop-release-windows/*
|
||||
if-no-files-found: error
|
||||
|
||||
aggregate-release-candidate:
|
||||
name: Verify combined desktop release directory
|
||||
needs:
|
||||
- macos-release-candidate
|
||||
- windows-release-candidate
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: frontend
|
||||
env:
|
||||
DESKTOP_UPDATE_BASE_URL: ${{ github.event_name == 'workflow_dispatch' && inputs.artifact_base_url || vars.DESKTOP_UPDATE_BASE_URL }}
|
||||
steps:
|
||||
- name: Checkout release source
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "22.13"
|
||||
|
||||
- name: Download signed macOS candidate artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: ctms-desktop-macos-${{ github.ref_name }}
|
||||
path: frontend/src-tauri/target/desktop-release-input/macos
|
||||
|
||||
- name: Download signed Windows candidate artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: ctms-desktop-windows-${{ github.ref_name }}
|
||||
path: frontend/src-tauri/target/desktop-release-input/windows
|
||||
|
||||
- name: Create combined desktop update feed
|
||||
shell: bash
|
||||
run: |
|
||||
mapfile -t mac_artifacts < <(find src-tauri/target/desktop-release-input/macos -name '*.app.tar.gz' -type f)
|
||||
mapfile -t dmgs < <(find src-tauri/target/desktop-release-input/macos -name '*.dmg' -type f)
|
||||
mapfile -t windows_artifacts < <(find src-tauri/target/desktop-release-input/windows -name '*.nsis.zip' -type f)
|
||||
mapfile -t installers < <(find src-tauri/target/desktop-release-input/windows -name '*.exe' -type f)
|
||||
if [[ ${#mac_artifacts[@]} -ne 1 || ${#dmgs[@]} -ne 1 || ${#windows_artifacts[@]} -ne 1 || ${#installers[@]} -ne 1 ]]; then
|
||||
echo "Exactly one macOS updater/DMG and one Windows updater/installer are required."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
npm run desktop:update-feed:create -- \
|
||||
--artifact "${artifact}" \
|
||||
"${include_args[@]}" \
|
||||
--artifact "${mac_artifacts[0]}" \
|
||||
--platform-artifact "windows-x86_64=${windows_artifacts[0]}" \
|
||||
--include "${dmgs[0]}" \
|
||||
--include "${installers[0]}" \
|
||||
--output-dir src-tauri/target/desktop-release-feed \
|
||||
--base-url "${DESKTOP_UPDATE_BASE_URL}"
|
||||
|
||||
- name: Verify desktop update feed
|
||||
run: npm run desktop:update-feed:check -- --feed src-tauri/target/desktop-release-feed/latest.json --artifacts-dir src-tauri/target/desktop-release-feed --base-url "${DESKTOP_UPDATE_BASE_URL}"
|
||||
- name: Verify combined desktop update feed
|
||||
run: npm run desktop:update-feed:check -- --feed src-tauri/target/desktop-release-feed/latest.json --artifacts-dir src-tauri/target/desktop-release-feed --base-url "${DESKTOP_UPDATE_BASE_URL}" --require-platform windows-x86_64
|
||||
|
||||
- name: Upload verified desktop release directory
|
||||
uses: actions/upload-artifact@v4
|
||||
|
||||
Reference in New Issue
Block a user