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("