diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 12bdc387..a3e6e064 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,10 +37,10 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: fetch-depth: 0 - - name: Set up current Go 1.25 patch + - name: Set up repository-pinned Go uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: - go-version: '1.25.x' + go-version-file: go.mod check-latest: true cache: true - name: Test CI helpers @@ -70,10 +70,10 @@ jobs: # Protocol and Surface history are compared with the exact PR/push # baseline. The first Surface registry PR is its explicit bootstrap. fetch-depth: 0 - - name: Set up current Go 1.25 patch + - name: Set up repository-pinned Go uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: - go-version: '1.25.x' + go-version-file: go.mod check-latest: true cache: true - name: Report Go toolchain @@ -135,10 +135,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - - name: Set up current Go 1.25 patch + - name: Set up repository-pinned Go uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: - go-version: '1.25.x' + go-version-file: go.mod check-latest: true cache: true - name: Race-check Workspace Access permission and authority fencing @@ -155,10 +155,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - - name: Set up current Go 1.25 patch + - name: Set up repository-pinned Go uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: - go-version: '1.25.x' + go-version-file: go.mod check-latest: true cache: true - name: Install pinned govulncheck @@ -183,10 +183,10 @@ jobs: shard: [0, 1, 2, 3, 4, 5, 6, 7] steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - - name: Set up current Go 1.25 patch + - name: Set up repository-pinned Go uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: - go-version: '1.25.x' + go-version-file: go.mod check-latest: true cache: true - name: Run exact Store shard @@ -241,10 +241,10 @@ jobs: os: [ubuntu-latest, macos-latest, windows-latest] steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - - name: Set up current Go 1.25 patch + - name: Set up repository-pinned Go uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: - go-version: '1.25.x' + go-version-file: go.mod check-latest: true cache: true - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 @@ -305,10 +305,10 @@ jobs: - run: npm run check:api - run: npm test - run: npm run build - - name: Set up current Go 1.25 patch + - name: Set up repository-pinned Go uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: - go-version: '1.25.x' + go-version-file: go.mod check-latest: true cache: true - name: Verify Go bundle loader and embedded production UI bundle @@ -338,10 +338,10 @@ jobs: working-directory: analyzers steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - - name: Set up current Go 1.25 patch + - name: Set up repository-pinned Go uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: - go-version: '1.25.x' + go-version-file: go.mod check-latest: true cache: true - name: Report Go toolchain @@ -414,10 +414,10 @@ jobs: runs-on: macos-latest steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - - name: Set up current Go 1.25 patch + - name: Set up repository-pinned Go uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: - go-version: '1.25.x' + go-version-file: go.mod check-latest: true cache: true - name: Report Go toolchain @@ -465,11 +465,11 @@ jobs: TRAVERSE_BOARD_LOCAL_SANDBOX_TEST_HOST_PREP: '1' steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - - name: Set up current Go 1.25 patch + - name: Set up repository-pinned Go id: windows-go uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: - go-version: '1.25.x' + go-version-file: go.mod check-latest: true cache: true - name: Report Go toolchain @@ -480,6 +480,7 @@ jobs: TRAVERSE_CI_GO_VERSION: ${{ steps.windows-go.outputs.go-version }} run: | ./scripts/tests/prepare-windows-fixed-go.tests.ps1 + ./scripts/tests/desktop-toolchain.tests.ps1 ./scripts/prepare-windows-fixed-go.ps1 -ExpectedGoVersion $env:TRAVERSE_CI_GO_VERSION - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: @@ -561,10 +562,10 @@ jobs: timeout-minutes: 10 steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - - name: Set up current Go 1.25 patch + - name: Set up repository-pinned Go uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: - go-version: '1.25.x' + go-version-file: go.mod check-latest: true cache: true - name: Verify Local Sandbox on the Windows 2022 compatibility host diff --git a/.github/workflows/release-desktop.yml b/.github/workflows/release-desktop.yml index 87a45617..7bb839d9 100644 --- a/.github/workflows/release-desktop.yml +++ b/.github/workflows/release-desktop.yml @@ -191,10 +191,10 @@ jobs: throw "The exact release revision has no successful full central CI; run CI manually for this revision before releasing" } - - name: Set up pinned Go 1.25.12 + - name: Set up repository-pinned Go uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: - go-version: '1.25.12' + go-version-file: go.mod cache: true - name: Set up pinned Node 24.16.0 @@ -251,10 +251,10 @@ jobs: run: | echo 'Stable macOS publication requires Developer ID signing, notarization and final-package manual acceptance; this pipeline currently produces previews only.' >&2 exit 1 - - name: Set up pinned Go 1.25.12 + - name: Set up repository-pinned Go uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: - go-version: '1.25.12' + go-version-file: go.mod cache: true - name: Set up pinned Node 24.16.0 uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 @@ -316,10 +316,10 @@ jobs: throw "Windows source differs from shared release revision" } - - name: Set up pinned Go 1.25.12 + - name: Set up repository-pinned Go uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: - go-version: '1.25.12' + go-version-file: go.mod cache: true - name: Set up pinned Node 24.16.0 @@ -738,10 +738,10 @@ jobs: --dir build/desktop if ($LASTEXITCODE -ne 0) { throw "Exact Windows candidate download failed" } - - name: Set up pinned Go 1.25.12 + - name: Set up repository-pinned Go uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: - go-version: '1.25.12' + go-version-file: go.mod cache: true - name: Reverify downloaded Windows candidate @@ -1065,10 +1065,10 @@ jobs: --dir build/store if ($LASTEXITCODE -ne 0) { throw "Exact Partner Center artifact download failed" } - - name: Set up pinned Go 1.25.12 + - name: Set up repository-pinned Go uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: - go-version: '1.25.12' + go-version-file: go.mod cache: true - name: Reverify downloaded candidate diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ab301636..ee915c34 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,12 +16,15 @@ Thank you for contributing to Universal Code. Resumability, auditability, and fa | 工具 | 版本 | 来源与用途 | |---|---:|---| -| Go | 1.25 | [`go.mod`](go.mod);唯一控制平面、CLI、TUI、HTTP API 与持久化 | +| Go | 1.26.9 | [`go.mod`](go.mod);唯一控制平面、CLI、TUI、HTTP API 与持久化 | | Node.js | 24 | [CI](.github/workflows/ci.yml);`web/` 下的 React/Vite 控制台 | | Rust | 1.97.1 | [`analyzers/rust-toolchain.toml`](analyzers/rust-toolchain.toml);确定性 Analyzer 夹具 | Git 需要 2.41+;修改 Analyzer 时另需 rustup。普通 Go/Web 开发不要求 Docker、真实 Provider 或 API key;未配置外部模型时使用 Mock Provider。`configs/models.yaml` 是无秘密的示例,不是运行时配置源。 +Go 构建使用 `go.mod` 中的精确补丁版本;本机安装其他版本时,设置 +`GOTOOLCHAIN=go1.26.9`。较新的 Go 发布分支也可能尚未修复同一漏洞,不能只按版本大小判断安全性。 + 首次检出后,按你要修改的表面准备依赖: ```bash @@ -40,7 +43,7 @@ rustup target add wasm32-wasip1 --toolchain 1.97.1 ### Windows Desktop -桌面开发和便携构建必须在 Windows 10/11 上进行,并安装 Microsoft Edge WebView2 Evergreen Runtime `94.0.992.31` 或更新版本。还需要上表中的 Go 1.25、Node.js 24 和 PowerShell;Rust 只在修改或完整验证 Analyzer 路径时需要。应用会在打开 SQLite 前检查 WebView2,缺失或过旧时失败关闭,不会自行下载或安装。 +桌面开发和便携构建必须在 Windows 10/11 上进行,并安装 Microsoft Edge WebView2 Evergreen Runtime `94.0.992.31` 或更新版本。还需要上表中的 Go 1.26.9、Node.js 24 和 PowerShell;Rust 只在修改或完整验证 Analyzer 路径时需要。应用会在打开 SQLite 前检查 WebView2,缺失或过旧时失败关闭,不会自行下载或安装。 ```powershell # 在仓库根目录构建未签名的本地测试包 @@ -54,7 +57,7 @@ rustup target add wasm32-wasip1 --toolchain 1.97.1 ### macOS Desktop -macOS 便携构建需要 macOS 11+(Big Sur)与 Xcode 命令行工具(codesign),以及上表中的 Go 1.25、Node.js 24;WKWebView 随系统提供,不需要 WebView2 式预检。前端测试环境固定在 Node.js 24 基线:本地 Node 版本不符时脚本会在前端检查前明确报错(可用 `nvm use 24` 切换,或 `-SkipFrontend` 跳过已构建好的 web/dist)。 +macOS 便携构建需要 macOS 12+(Monterey)与 Xcode 命令行工具(codesign),以及上表中的 Go 1.26.9、Node.js 24;WKWebView 随系统提供,不需要 WebView2 式预检。前端测试环境固定在 Node.js 24 基线:本地 Node 版本不符时脚本会在前端检查前明确报错(可用 `nvm use 24` 切换,或 `-SkipFrontend` 跳过已构建好的 web/dist)。 ```bash # 在仓库根目录构建未签名、ad-hoc 签名的本地测试包 diff --git a/cmd/cyberagent-desktop/main_darwin.go b/cmd/cyberagent-desktop/main_darwin.go index 7cd7a3ee..417b2c68 100644 --- a/cmd/cyberagent-desktop/main_darwin.go +++ b/cmd/cyberagent-desktop/main_darwin.go @@ -24,7 +24,7 @@ func trustedDesktopRendererHost() string { } // checkDesktopPrerequisites returns nil on macOS: WKWebView ships with every -// supported macOS release (the Go 1.25 toolchain requires macOS 11 Big Sur or +// supported macOS release (the Go 1.26 toolchain requires macOS 12 Monterey or // newer), so the Desktop never probes, downloads, or installs a web runtime. func checkDesktopPrerequisites() error { return nil diff --git a/docs/DESKTOP_PLAN.md b/docs/DESKTOP_PLAN.md index d311c322..fc82dc77 100644 --- a/docs/DESKTOP_PLAN.md +++ b/docs/DESKTOP_PLAN.md @@ -83,7 +83,7 @@ macOS 本地构建(D0-Mac): open build/desktop/Prayu.app ``` -输出为 `build/desktop/Prayu.app` 与同目录启动器/指南,默认不开放 control token;需要 Xcode 命令行工具(codesign)与 `CGO_ENABLED=1`。产物只有 ad-hoc 签名、未公证,是开发/便携测试包,不是正式发行包。macOS 11+(Big Sur)自带 WKWebView,构建不做 WebView2 式运行时预检;启动失败只写入 stderr 并显示有界 osascript 对话框。工作区启动器只通过固定 `/usr/bin/open` 打开已验证的 .app(Finder、Terminal、Antigravity、PyCharm、WebStorm、Visual Studio Code)。系统凭证库仍未接入;用户终端默认关闭,显式启用后使用 Bash PTY,受限浏览器与完整 CDP 继续失败关闭,凭证请使用环境变量。自动检查通过后 `release_ready` 仍为 false,直到签名、公证、PTY 实机行为与人工 macOS 矩阵完成。 +输出为 `build/desktop/Prayu.app` 与同目录启动器/指南,默认不开放 control token;需要 Xcode 命令行工具(codesign)与 `CGO_ENABLED=1`。产物只有 ad-hoc 签名、未公证,是开发/便携测试包,不是正式发行包。macOS 12+(Monterey)自带 WKWebView,构建不做 WebView2 式运行时预检;启动失败只写入 stderr 并显示有界 osascript 对话框。工作区启动器只通过固定 `/usr/bin/open` 打开已验证的 .app(Finder、Terminal、Antigravity、PyCharm、WebStorm、Visual Studio Code)。系统凭证库仍未接入;用户终端默认关闭,显式启用后使用 Bash PTY,受限浏览器与完整 CDP 继续失败关闭,凭证请使用环境变量。自动检查通过后 `release_ready` 仍为 false,直到签名、公证、PTY 实机行为与人工 macOS 矩阵完成。 显式启用受控 Run 创建: @@ -364,7 +364,7 @@ capability grant 为 false。开关只作用于 Traverse 管理的隔离内置 ## 发布门禁 - Windows 自动化覆盖启动前置条件、关闭/恢复、同库续传和 renderer 边界;Windows 11 x64 已实机验证,Windows 10 x64 仍是正式发行前必过矩阵。 -- macOS 自动化覆盖 desktop-tag 测试、Mach-O/codesign 兼容检查和双构建可复现性;签名、公证与 macOS 11+/Retina 实机矩阵是正式发行前必过项,`release_ready` 保持 false。 +- macOS 自动化覆盖 desktop-tag 测试、Mach-O/codesign 兼容检查和双构建可复现性;签名、公证与 macOS 12+/Retina 实机矩阵是正式发行前必过项,`release_ready` 保持 false。 - 渲染进程无法绕过 Go API 访问 Shell、Docker、密钥或工作区外文件。 - CLI 与 Desktop 同时运行时,SQLite 不损坏、operation 重放不分叉、Run lease 不被窗口生命周期或 Run 创建偷取。 - 安装、升级和卸载不会静默删除 Workspace、数据库、凭证或用户创建文件。 diff --git a/docs/PROJECT_MEMORY.md b/docs/PROJECT_MEMORY.md index 4808f506..5187d4ba 100644 --- a/docs/PROJECT_MEMORY.md +++ b/docs/PROJECT_MEMORY.md @@ -1,5 +1,13 @@ # Prayu Project Memory +> 2026-10-09 Go security baseline (#289): Go 1.26.9 is the minimum compiler; +> CI and release builders read the exact version from go.mod. Local desktop +> builders require that same patched compiler. The x/net +> dependency includes the October HTTP/2 fixes. Native macOS packaging now +> declares and verifies macOS 12, matching the compiler's actual support floor. +> The nightly full matrix and blocking vulnerability audit remain enabled; +> see [CI security baseline](ci.md#go-security-baseline) for scan evidence limits. + > 2026-10-07 extension onboarding checkpoint (#276): shared Web/Desktop settings > stage manual MCP descriptors, import pinned Plugin ZIPs and stage/review LSP > configuration through Go-owned services. Backend capability flags, source/scope, diff --git a/docs/ci.md b/docs/ci.md index 91ff236f..8e531dd4 100644 --- a/docs/ci.md +++ b/docs/ci.md @@ -28,6 +28,34 @@ An unreadable or empty change set fails selection. Failed selection, a failed required job, cancellation, or an unexpected required-job skip cannot become a successful aggregate result. Unclassified build inputs select full checks. +## Go security baseline + +The supported build toolchain is Go **1.26.9**, pinned by `go.mod`. Both central +CI and release builders read that exact version with `go-version-file`. +This avoids selecting an older patch while the setup-go version catalog lags +behind a new Go security release. Local desktop builders require the same +version; set `GOTOOLCHAIN=go1.26.9` when another Go toolchain is installed. +The module's minimum version alone cannot exclude vulnerable newer release +branches, such as Go 1.27.0 and 1.27.1; a larger version is not security evidence. +The Windows fixed-toolchain fixture must match the exact version selected by +`setup-go` and retains its official archive and executable hash checks. +Update the module pin and fixture guard together when moving to another +supported Go release, then rerun the full matrix and current vulnerability audit. + +`govulncheck` uses the current Go vulnerability database. A successful scan is +evidence for its recorded toolchain, source revision and database timestamp; +newly published advisories can make a later scan of the same commit fail. +Affected-check PR runs may skip the Go audit, while nightly and manual full +runs always select it. Check the job selection and scan log before treating a +green PR as current full security evidence. + +The 2026-10-08 database update exposed the retired Go 1.25 baseline in the +2026-10-09 nightly run ([#289](https://github.com/CWNU-Open-Source-Community/Universal-Code/issues/289)). +The repair upgrades Go and `golang.org/x/net` without suppressing advisories or +changing the schedule. Go 1.26 requires macOS 12+, so native build flags, bundle +metadata and package verification use that same minimum; the earlier macOS 11 +declaration was already inconsistent with Go 1.25's supported platforms. + ## Go impact selection `scripts/ci/run_go_checks.py` uses `go list -json ./...` to identify package diff --git a/docs/mac-keychain.md b/docs/mac-keychain.md index ff67a448..65e42be7 100644 --- a/docs/mac-keychain.md +++ b/docs/mac-keychain.md @@ -22,4 +22,4 @@ TRAVERSE_TEST_KEYCHAIN=1 CGO_ENABLED=1 go test -tags=keychainintegration -count= ## 仍需实际应用验收 -隔离 CRUD 不能证明实际 `.app` 的登录会话、ACL 和授权提示体验。使用独立 Mac 测试用户/可销毁环境,验证首次配置、替换、删除、退出重开、锁定后恢复、手动取消、同版本重启和不同 ad-hoc 构建升级。锁定/取消的真实系统对话框不在上述无人值守测试中伪造通过。记录准确的应用提交、OS、架构和二进制身份;Mac 15 runner 通过不能证明 macOS 11 或正式发行已就绪。 +隔离 CRUD 不能证明实际 `.app` 的登录会话、ACL 和授权提示体验。使用独立 Mac 测试用户/可销毁环境,验证首次配置、替换、删除、退出重开、锁定后恢复、手动取消、同版本重启和不同 ad-hoc 构建升级。锁定/取消的真实系统对话框不在上述无人值守测试中伪造通过。记录准确的应用提交、OS、架构和二进制身份;Mac 15 runner 通过不能证明 macOS 12 或正式发行已就绪。 diff --git a/docs/macos-release.md b/docs/macos-release.md index c97b6f8d..14266570 100644 --- a/docs/macos-release.md +++ b/docs/macos-release.md @@ -35,7 +35,7 @@ bash scripts/release-desktop-darwin.sh v1.0.0-rc.1 "$(git rev-parse HEAD)" "$(go 流水线固定 `macos-15` ARM64 与 `macos-15-intel` Intel runner;检查原生 CPU、Go target、 Mach-O CPU 三者一致。构建两次比较二进制,再 ad-hoc 签名。`CFBundleVersion` 和 `CFBundleShortVersionString` 使用数字版本,完整预发布名称保留在 build metadata。 -最低构建目标为 macOS 11;不代表已在所有 macOS 11+ 真机上通过验收。 +最低构建目标为 macOS 12;不代表已在所有 macOS 12+ 真机上通过验收。 产物位于 `build/macos-public`。ZIP 包含完整应用、指南、兼容入口、元数据、兼容报告、 SBOM、NOTICE 与 LICENSE。`ditto` 保留 POSIX 权限;新目录解压后再次核对全部文件、 diff --git a/go.mod b/go.mod index 91e1ee20..d3fc3cd2 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module cyberagent-workbench -go 1.25.0 +go 1.26.9 require ( github.com/Microsoft/go-winio v0.6.2 @@ -18,9 +18,9 @@ require ( github.com/wailsapp/go-webview2 v1.0.23 github.com/wailsapp/wails/v2 v2.14.0 golang.org/x/image v0.45.0 - golang.org/x/net v0.58.0 - golang.org/x/sys v0.47.0 - golang.org/x/text v0.41.0 + golang.org/x/net v0.60.0 + golang.org/x/sys v0.48.0 + golang.org/x/text v0.42.0 gopkg.in/yaml.v3 v3.0.1 ) @@ -81,9 +81,9 @@ require ( github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect github.com/yosida95/uritemplate/v3 v3.0.2 // indirect - golang.org/x/crypto v0.55.0 // indirect + golang.org/x/crypto v0.57.0 // indirect golang.org/x/oauth2 v0.35.0 // indirect - golang.org/x/sync v0.22.0 // indirect + golang.org/x/sync v0.23.0 // indirect golang.org/x/time v0.15.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect ) diff --git a/go.sum b/go.sum index b17b9922..79a4154f 100644 --- a/go.sum +++ b/go.sum @@ -183,20 +183,20 @@ github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJu github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4= github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.55.0 h1:+KWHjbgOaAQ66dh/YlkZKHlz9ZUlq61AFirAR9ntP8M= -golang.org/x/crypto v0.55.0/go.mod h1:uq0V9dE/fzQuJtbnL+2EhWOE63vo164FY8xqEnV9xis= +golang.org/x/crypto v0.57.0 h1:3ZVCjf8Ggz7zneR/EHRVx68Ctf+2pmIMP2UFhh9cC6M= +golang.org/x/crypto v0.57.0/go.mod h1:Fdz0i5U6CoizGwLda9DttjSk6qlZo25zYNtR+ycvuZA= golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f h1:W3F4c+6OLc6H2lb//N1q4WpJkhzJCK5J6kUi1NTVXfM= golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f/go.mod h1:J1xhfL/vlindoeF/aINzNzt2Bket5bjo9sdOYzOsU80= golang.org/x/image v0.45.0 h1:FMb1nTbH5H9vF55SriQHgFw5GnNL9Jg6L25BwXKzhB0= golang.org/x/image v0.45.0/go.mod h1:n62x/7RqlwXDvGsSU4u6IUTUf6KghUZ9Bt7cG/T9Fx4= golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.58.0 h1:ynWG7rqYi4ccpTEuPZ2QGWHktVEM9DMCj9yzDE0Q7To= -golang.org/x/net v0.58.0/go.mod h1:YwCddHnFlT7eLQqVprV19OnhLGtc5xOKgE0RyqgfWAU= +golang.org/x/net v0.60.0 h1:79p50tfZlm0J9YfoDsSi639qSXNGVwEzOPLCxM2FsYU= +golang.org/x/net v0.60.0/go.mod h1:2DA/G1UfVbCpQPeWTmMPGY7Cs2PkBkwu743bVX5PIVg= golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ= golang.org/x/oauth2 v0.35.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= -golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek= -golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sync v0.23.0 h1:KameEIfc1IkluZyXWLn39Wd4tURc6GbCiISGiZm2bQk= +golang.org/x/sync v0.23.0/go.mod h1:sUUOizhqBxiL6pEWpqNLUiaJn1ShEbZ6BBqskPbjZm0= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -208,19 +208,19 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs= -golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/sys v0.48.0 h1:bbX/i/6MgT9BVLM9RT1thmxL04yeTAhbEz4SyadbXoo= +golang.org/x/sys v0.48.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.45.0 h1:NwWyBmoJCbfTHpxrWoZ9C6/VxOf7ic219I8xZZFdrf0= -golang.org/x/term v0.45.0/go.mod h1:9aqxs0blBcrm/n0L9QW0aRVD+ktan8ssZromtqJC43w= +golang.org/x/term v0.46.0 h1:3+OXuTbaKDgwk8jTi3aSLHRlmWqHEUDUtxnbFigO4YE= +golang.org/x/term v0.46.0/go.mod h1:+K02xbkittuwc0Am4abfA3Fc+XRGXkvBXNO88NCXPoc= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8= -golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M= +golang.org/x/text v0.42.0 h1:JbOZXgfeCPU9gacVtYliJqOhD+zhrEqK4LfdpmlUZqI= +golang.org/x/text v0.42.0/go.mod h1:ojzP1Z+2QtioaF8DTtO8K5q7JWVVYwZKenzujK0Zd0E= golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.48.0 h1:3+hClM1aLL5mjMKm5ovokw9epgRXPuu2tILgismM6RE= -golang.org/x/tools v0.48.0/go.mod h1:08xX0orndb/F7jJxGDicx061tyd5pcMto75YMAXr6lk= +golang.org/x/tools v0.49.0 h1:3NI7VXzL9+1WZD52Dx2ttoPwD5DWrFGpl9mFZDlmisI= +golang.org/x/tools v0.49.0/go.mod h1:SJNXV9DBKT0UbdttsQjbfJlAE/q+y36++zo3uL3N0Oo= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= diff --git a/packaging/macos/Info.plist b/packaging/macos/Info.plist index fdcc85f9..6b214834 100644 --- a/packaging/macos/Info.plist +++ b/packaging/macos/Info.plist @@ -23,7 +23,7 @@ CFBundleVersion @VERSION@ LSMinimumSystemVersion - 11.0.0 + 12.0.0 LSApplicationCategoryType public.app-category.developer-tools NSHighResolutionCapable diff --git a/packaging/macos/LOCAL-TEST-GUIDE.txt b/packaging/macos/LOCAL-TEST-GUIDE.txt index 1fad449f..618b28f4 100644 --- a/packaging/macos/LOCAL-TEST-GUIDE.txt +++ b/packaging/macos/LOCAL-TEST-GUIDE.txt @@ -2,6 +2,7 @@ Traverse Board · 针路簿 macOS 本地试用说明 ========================== 从下载的产品 ZIP 解压后,直接双击同目录 TraverseBoard.app;无需安装 Go、Node 或 Xcode。 +需要 macOS 12(Monterey)或更新版本。 以下命令在解压后的产品目录执行;源码构建后先进入 build/desktop/。 推荐入口 @@ -26,7 +27,7 @@ Start-Prayu-Operator-Preview.command 只是同一默认入口的兼容快捷方 Node 版本不符时脚本会在前端检查前明确报错;如果 web/dist 已经构建好, 也可以用 -SkipFrontend 跳过前端步骤。构建还需要 Xcode 命令行工具 -(codesign)和 Go 1.25。 +(codesign)和 Go 1.26.9。 首次接入真实模型 ---------------- @@ -81,6 +82,7 @@ Traverse Board macOS Local Test Guide ============================ After extracting the product ZIP, double-click TraverseBoard.app in that directory. +Requires macOS 12 Monterey or later. Go, Node and Xcode are only build dependencies. Run the commands below from the extracted product directory; after building from source, first enter build/desktop/. @@ -110,7 +112,7 @@ then run: A mismatched Node version fails fast before the frontend checks; use -SkipFrontend when web/dist is already built. Building also requires the -Xcode command line tools (codesign) and Go 1.25. +Xcode command line tools (codesign) and Go 1.26.9. Connect a real model -------------------- diff --git a/scripts/build-desktop-darwin.sh b/scripts/build-desktop-darwin.sh index 304f71cf..d796b8cd 100755 --- a/scripts/build-desktop-darwin.sh +++ b/scripts/build-desktop-darwin.sh @@ -41,6 +41,16 @@ repositoryRoot="$(cd "$(dirname "$0")/.." && pwd -P)" cd "$repositoryRoot" repositoryFull="$(pwd -P)" +# Match the exact compiler used by CI, including its security patch level. +expectedGoVersion="$(tr -d '\r' < go.mod | sed -nE 's/^go ([0-9]+\.[0-9]+\.[0-9]+)$/go\1/p')" +if [ -z "$expectedGoVersion" ]; then + die "Pinned Go toolchain is unavailable in go.mod" +fi +goVersion="$(go env GOVERSION)" +if [ "$goVersion" != "$expectedGoVersion" ]; then + die "Desktop build requires $expectedGoVersion from go.mod. Set GOTOOLCHAIN=$expectedGoVersion." +fi + mkdir -p "$OutputDirectory" outputRoot="$(cd "$OutputDirectory" && pwd -P)" case "$outputRoot" in @@ -117,10 +127,6 @@ cgoEnabled="$(go env CGO_ENABLED)" if [ "$cgoEnabled" != "1" ]; then die "Desktop macOS build requires CGO_ENABLED=1 (go-sqlite3 and Wails need cgo)" fi -goVersion="$(go env GOVERSION)" -if ! printf '%s' "$goVersion" | grep -Eq '^go[0-9]+.[0-9]+'; then - die "Go version build metadata is invalid" -fi targetOS="$(go env GOOS)" if [ "$targetOS" != "darwin" ]; then die "Desktop portable build requires GOOS=darwin" @@ -145,13 +151,13 @@ previousSourceDateEpoch="${SOURCE_DATE_EPOCH:-}" previousCgoLdflags="${CGO_LDFLAGS:-}" previousCgoCflags="${CGO_CFLAGS:-}" # Mirror the wails build command's darwin link flags: WailsContext.m uses -# UTType (macOS 11+). The deployment target matches the Go 1.25 darwin +# UTType (macOS 11+). The deployment target matches the Go 1.26 darwin # minimum and the bundle's LSMinimumSystemVersion. Plain go build does not -# add these itself. CGO_CFLAGS keeps the clang objects on the same 11.0 +# add these itself. CGO_CFLAGS keeps the clang objects on the same 12.0 # target; without it the macOS 26 SDK compiles them at 26.0 and the external # linker floods the build with "built for newer macOS version" warnings. -export CGO_CFLAGS="-g -O2 -mmacosx-version-min=11.0${previousCgoCflags:+ $previousCgoCflags}" -export CGO_LDFLAGS="-framework UniformTypeIdentifiers -mmacosx-version-min=11.0${previousCgoLdflags:+ $previousCgoLdflags}" +export CGO_CFLAGS="-g -O2 -mmacosx-version-min=12.0${previousCgoCflags:+ $previousCgoCflags}" +export CGO_LDFLAGS="-framework UniformTypeIdentifiers -mmacosx-version-min=12.0${previousCgoLdflags:+ $previousCgoLdflags}" export SOURCE_DATE_EPOCH="$sourceDateEpoch" trap 'export SOURCE_DATE_EPOCH="$previousSourceDateEpoch"; export CGO_LDFLAGS="$previousCgoLdflags"; export CGO_CFLAGS="$previousCgoCflags"' EXIT # The previous run codesigned the final binary in place. go build over an diff --git a/scripts/build-desktop.ps1 b/scripts/build-desktop.ps1 index 0271004b..97e5e395 100644 --- a/scripts/build-desktop.ps1 +++ b/scripts/build-desktop.ps1 @@ -72,6 +72,18 @@ function Assert-NoOutputReparsePoint { Assert-NoOutputReparsePoint -Root $repositoryFull -Candidate $outputRoot +# A newer Go release can still be affected by an advisory fixed in our pinned +# branch. Use the same exact compiler as CI and release packaging. +$goDirective = [regex]::Match( + [IO.File]::ReadAllText((Join-Path $repositoryRoot 'go.mod')), + '(?m)^go (?[0-9]+\.[0-9]+\.[0-9]+)\r?$') +if (-not $goDirective.Success) { throw 'Pinned Go toolchain is unavailable in go.mod.' } +$expectedGoVersion = 'go' + $goDirective.Groups['version'].Value +$goVersion = ([string](& go -C $repositoryRoot env GOVERSION)).Trim() +if ($LASTEXITCODE -ne 0 -or $goVersion -cne $expectedGoVersion) { + throw "Desktop build requires $expectedGoVersion from go.mod. Set GOTOOLCHAIN=$expectedGoVersion." +} + if (-not $SkipFrontend) { Push-Location (Join-Path $repositoryRoot "web") try { @@ -118,10 +130,6 @@ try { if ($LASTEXITCODE -ne 0 -or $cgoEnabled -notmatch '^[01]$') { throw "Go CGO build metadata is invalid" } - $goVersion = (& go env GOVERSION).Trim() - if ($LASTEXITCODE -ne 0 -or $goVersion -notmatch '^go[0-9]+\.[0-9]+') { - throw "Go version build metadata is invalid" - } $nodeVersion = (& node --version).Trim() if ($LASTEXITCODE -ne 0 -or $nodeVersion -notmatch '^v[0-9]+\.[0-9]+\.[0-9]+') { throw "Node version build metadata is invalid" diff --git a/scripts/check-macos-compat.sh b/scripts/check-macos-compat.sh index 5a511349..a86e3dd4 100755 --- a/scripts/check-macos-compat.sh +++ b/scripts/check-macos-compat.sh @@ -75,8 +75,8 @@ if go version -m "$binary" 2>/dev/null | grep -q "cyberagent-workbench" && GO_BUILD_METADATA_OK="true" fi -# The deployment target must match the Go 1.25 darwin minimum (macOS 11). The -# build script aligns both the cgo compile flags and the bundle plist to 11.0. +# The deployment target must match the Go 1.26 darwin minimum (macOS 12). The +# build script aligns both the cgo compile flags and the bundle plist to 12.0. DEPLOYMENT_TARGET="unknown" minimumOS="$(otool -l "$binary" | awk '/LC_BUILD_VERSION/{seen=1; next} seen && /minos/{print $2; exit}')" if [ -n "$minimumOS" ]; then @@ -136,8 +136,8 @@ add_check( ) add_check( "macho_deployment_target", - "pass" if os.environ["MACOS_COMPAT_DEPLOYMENT_TARGET"] == "11.0" else "fail", - "Mach-O deployment target matches the Go 1.25 macOS 11 minimum", + "pass" if os.environ["MACOS_COMPAT_DEPLOYMENT_TARGET"] == "12.0" else "fail", + "Mach-O deployment target matches the Go 1.26 macOS 12 minimum", ) add_check( "sha256_binding", @@ -255,7 +255,7 @@ else: add_check( "macos_matrix", "manual", - "verify macOS 11+, Retina scaling, notarized distribution, launch, and recovery on a clean machine", + "verify macOS 12+, Retina scaling, notarized distribution, launch, and recovery on a clean machine", ) failed = [check for check in checks if check["status"] == "fail"] diff --git a/scripts/ci/test_classify_changes.py b/scripts/ci/test_classify_changes.py index d8c821a7..a199ab79 100644 --- a/scripts/ci/test_classify_changes.py +++ b/scripts/ci/test_classify_changes.py @@ -217,6 +217,16 @@ def setUpClass(cls): cls.ci = (cls.root / ".github/workflows/ci.yml").read_text(encoding="utf-8") cls.release = (cls.root / ".github/workflows/release-desktop.yml").read_text(encoding="utf-8") + def test_all_builders_use_the_exact_module_toolchain(self): + module = (self.root / "go.mod").read_text(encoding="utf-8") + self.assertRegex(module, r"(?m)^go [0-9]+\.[0-9]+\.[0-9]+$") + for workflow in (self.ci, self.release): + builders = re.findall(r"uses: actions/setup-go@", workflow) + self.assertTrue(builders) + self.assertNotRegex(workflow, r"(?m)^\s*go-version:") + self.assertEqual(len(builders), len(re.findall( + r"(?m)^\s*go-version-file: go\.mod$", workflow))) + def run_gate(self, job, needs): start = self.ci.index(f" {job}:\n") block = self.ci[start:] diff --git a/scripts/macos-release.py b/scripts/macos-release.py index f319394a..91d4689e 100644 --- a/scripts/macos-release.py +++ b/scripts/macos-release.py @@ -120,7 +120,7 @@ def inspect_zip(path, version, revision, arch): numeric = re.match(r"v([0-9]+\.[0-9]+\.[0-9]+)", version).group(1) for key, value in {"CFBundleShortVersionString": numeric, "CFBundleVersion": numeric, "CFBundleIdentifier": "workbench.prayu.desktop", - "CFBundleExecutable": "cyberagent-desktop", "LSMinimumSystemVersion": "11.0.0"}.items(): + "CFBundleExecutable": "cyberagent-desktop", "LSMinimumSystemVersion": "12.0.0"}.items(): require(plist.get(key) == value, "bundle identity differs: " + key) compat = read_json(contents["macos-compatibility.json"]) for key, value in {"protocol_version": "macos_portable_compatibility.v1", diff --git a/scripts/prepare-windows-fixed-go.ps1 b/scripts/prepare-windows-fixed-go.ps1 index 3c042e7d..88ff0c9a 100644 --- a/scripts/prepare-windows-fixed-go.ps1 +++ b/scripts/prepare-windows-fixed-go.ps1 @@ -3,7 +3,7 @@ [CmdletBinding()] param( [Parameter(Mandatory = $true)] - [ValidatePattern('^1\.25\.[0-9]+$')] + [ValidatePattern('^1\.26\.[0-9]+$')] [string]$ExpectedGoVersion ) @@ -16,9 +16,9 @@ if ($env:GITHUB_ACTIONS -ne 'true' -or $env:RUNNER_ENVIRONMENT -ne 'github-hoste $setupGo = (Get-Command go -CommandType Application -All | Select-Object -First 1).Source $goVersion = (& $setupGo env GOVERSION).Trim() -if ($LASTEXITCODE -ne 0 -or $goVersion -notmatch '^go1\.25\.[0-9]+$' -or +if ($LASTEXITCODE -ne 0 -or $goVersion -notmatch '^go1\.26\.[0-9]+$' -or $goVersion -cne "go$ExpectedGoVersion") { - throw 'Expected the Go 1.25 patch selected by this workflow.' + throw 'Expected the Go 1.26 patch selected by this workflow.' } $programFilesRoot = [Environment]::GetFolderPath([Environment+SpecialFolder]::ProgramFiles) if (-not [IO.Path]::IsPathFullyQualified($programFilesRoot)) { diff --git a/scripts/test_macos_release.py b/scripts/test_macos_release.py index f2db8642..2d962ea5 100644 --- a/scripts/test_macos_release.py +++ b/scripts/test_macos_release.py @@ -1,10 +1,14 @@ """Archive corruption/identity tests. Fixtures are synthetic, not Mac GUI evidence.""" import importlib.util import json +import os from pathlib import Path import plistlib +import re +import shutil import stat import struct +import subprocess import tempfile import unittest import zipfile @@ -17,6 +21,36 @@ REVISION = "1234567890abcdef" * 2 + "12345678" +class MacToolchainTest(unittest.TestCase): + def test_build_requires_the_exact_patched_toolchain(self): + root = Path(__file__).resolve().parents[1] + if os.name == "nt": + git = shutil.which("git") + bash = Path(git).parents[1] / "bin/bash.exe" if git else None + else: + bash = shutil.which("bash") + if not bash or not Path(bash).is_file(): + self.skipTest("Bash is required for the macOS builder preflight") + source = (root / "scripts/build-desktop-darwin.sh").read_text(encoding="utf-8") + preflight = source[source.index('expectedGoVersion='):source.index('mkdir -p "$OutputDirectory"')] + module = (root / "go.mod").read_text(encoding="utf-8") + pinned = "go" + re.search(r"(?m)^go ([0-9]+\.[0-9]+\.[0-9]+)$", module).group(1) + shell = 'set -eu\ndie() { echo "$1" >&2; exit 1; }\ngo() { printf "%s\\n" "$TEST_GO_VERSION"; }\n' + with tempfile.TemporaryDirectory() as temporary: + # CRLF is a valid Go module file too; do not reject it as unpinned. + Path(temporary, "go.mod").write_bytes(module.replace("\n", "\r\n").encode()) + for version in (pinned, "go1.26.8", "go1.27.0", "go1.27.1", "go1.27.2"): + with self.subTest(version=version): + result = subprocess.run([str(bash), "-c", shell + preflight], cwd=temporary, + env=dict(os.environ, TEST_GO_VERSION=version), + capture_output=True, text=True) + if version == pinned: + self.assertEqual(result.returncode, 0, result.stderr) + else: + self.assertNotEqual(result.returncode, 0) + self.assertIn("Desktop build requires " + pinned, result.stderr) + + class MacArchiveTest(unittest.TestCase): def setUp(self): self.temp = tempfile.TemporaryDirectory() @@ -52,7 +86,7 @@ def setUp(self): self.contents[release.APP + "/Contents/Info.plist"] = plistlib.dumps({ "CFBundleShortVersionString": "1.0.0", "CFBundleVersion": "1.0.0", "CFBundleIdentifier": "workbench.prayu.desktop", "CFBundleExecutable": "cyberagent-desktop", - "LSMinimumSystemVersion": "11.0.0", + "LSMinimumSystemVersion": "12.0.0", }) def write(self, modes=None, extra=None): @@ -96,6 +130,16 @@ def test_old_revision_inside_rehashed_archive(self): with self.assertRaisesRegex(ValueError, "metadata differs: revision"): self.verify() + def test_incorrect_minimum_os_inside_rehashed_archive(self): + name = release.APP + "/Contents/Info.plist" + plist = plistlib.loads(self.contents[name]) + for minimum in ("11.0.0", "13.0.0"): + with self.subTest(minimum=minimum): + self.contents[name] = plistlib.dumps({**plist, "LSMinimumSystemVersion": minimum}) + self.write() + with self.assertRaisesRegex(ValueError, "bundle identity differs: LSMinimumSystemVersion"): + self.verify() + def test_wrong_cpu_even_when_metadata_claims_arm64(self): self.contents[release.BINARY] = bytes.fromhex("cffaedfe") + struct.pack("