Skip to content

[Bug][macOS] v1.2.3 → v1.2.4 内置更新失败:codesign requirement 缺少 "=" 与 "field." #753

Closed

Description

@vliuyt

问题描述

macOS 桌面端从 v1.2.3 更新至 v1.2.4 时,更新包下载、DMG 校验和挂载均成功,但应用内更新反复失败,界面只显示:

安装更新失败,请稍后再试。

排查发现失败发生在生成的 macOS 更新辅助脚本的开发者身份校验阶段。签名本身有效,是 codesign -R 的 requirement 参数存在两处语法问题。

环境

  • macOS 27.2(26B123)
  • Apple Silicon / arm64
  • 原安装:Memmy v1.2.3 国内版,位于 /Applications/Memmy.app
  • 目标安装包:Memmy-1.2.4-darwin-arm64-cn-signed.dmg(官方 GitHub Release)
  • Bundle ID:cn.memtensor.memmy
  • 已安装版本和官方目标包的 TeamIdentifier 均为 S7NLXHGBJ2

复现步骤

  1. 使用官方签名的 v1.2.3 国内版。
  2. 在「设置 → 关于」检查并安装 v1.2.4 更新。
  3. 下载后进入 staging,签名身份校验失败。
  4. 再次重试仍然失败,版本保持 v1.2.3。

更新日志中的关键错误

~/Library/Application Support/Memmy/updates/mac-update-install.log:

anchor apple generic and identifier "cn.memtensor.memmy" and certificate leaf[1.2.840.113635.100.6.1.13] exists and certificate leaf[subject.OU] = "S7NLXHGBJ2": No such file or directory
invalid requirement specification
Memmy update does not have the installed Apple Developer ID identity

主进程日志同时记录:

download app update failed Error: Error invoking remote method 'memmy:download-update': Error: helper script exited with code 1

根因及独立验证

代码位置:

macBundleValidationScript() 生成的 requirement 包含:

certificate leaf[1.2.840.113635.100.6.1.13] exists

随后执行:

/usr/bin/codesign --verify --deep --strict -R "$signing_requirement" "$app_path"

两处问题已在本机独立验证:

  1. 缺少 literal requirement 前缀 =。 codesign 将没有此前缀的参数作为 requirement 文件路径,因此报 No such file or directory。
  2. 证书扩展 OID 缺少 field. 前缀。 仅补上 = 后仍报:
    error: invalid or corrupted code requirement(s)
    Requirement syntax error(s):
    line 1:80: unexpected char: '.'
    
    应使用 certificate leaf[field.1.2.840.113635.100.6.1.13] exists。

对官方 v1.2.4 应用执行以下修正后的命令,验证通过:

/usr/bin/codesign --verify --deep --strict \
  -R '=anchor apple generic and identifier "cn.memtensor.memmy" and certificate leaf[field.1.2.840.113635.100.6.1.13] exists and certificate leaf[subject.OU] = "S7NLXHGBJ2"' \
  /Applications/Memmy.app

另外,原始 codesign --verify --deep --strict 检查通过,spctl --assess --type execute --verbose=2 返回 accepted / source=Notarized Developer ID。官方国内版 DMG 的 SHA-256 也与 Release 元数据一致:

e607497b38d2cd04189e5abea7b291cf124a656b677dabb867178699c323dd71

因此,这次失败不应被归类为实际的开发者身份不匹配。

预期行为及修复建议

  • 合法、同开发者签名的官方更新包应能正常完成 staging 和安装。
  • requirement 同时修正 literal 前缀与 OID 字段语法,保留现有 Bundle ID、Apple Developer ID、TeamIdentifier 和完整签名检查。
  • 为共享的 staging / install 校验路径补充真实 macOS codesign 验证,覆盖合法同团队包通过、错误团队或 Bundle ID 的包仍被拒绝。
  • UI 在更新失败时提供具体错误或日志入口,避免只显示“请稍后再试”。

临时处理及验证范围

已在核验官方安装包签名、公证和哈希并备份用户数据后,手动完成同渠道 v1.2.4 更新;原账户和数据保留,应用「关于」显示当前已是最新版本,Memory service 2.1.7 健康检查通过。

v1.2.4 打包产物及提交反馈时的 main 中仍包含上述校验代码。尚未验证 v1.2.4 到后续版本的应用内升级;这里报告的是实际发生的 v1.2.3 → v1.2.4 失败,以及对校验命令的独立复现。

Activity

  1. self-assigned this
    on Oct 26, 2026
  2. Memtensor-AI commented on Oct 26, 2026

    @Memtensor-AI
    Collaborator

    🤖 AutoDev has picked up this issue and started working on it.

    Task ID: d93c34215c89cf05
    Working branch: bugfix/autodev-753-20261026235019878
    Target branch: main
    Workflow: AutoDev (coding → PR)

    I will post the PR link here once done. If I need more information, I will ask in the comments.

  3. Memtensor-AI commented on Oct 27, 2026

    @Memtensor-AI
    Collaborator

    ✅ AutoDev task d93c34215c89cf05 completed.

    Summary: Fixes issue #753: macOS in-app updates from v1.2.3 to v1.2.4 failed because the generated update helper passed a malformed codesign requirement.

    Root cause and fix (App/shell/desktop/src/main/mac-update-scripts.ts): the requirement string handed to codesign --verify -R had two syntax errors — it lacked the literal "=" prefix (so codesign interpreted it as a requirement file path and reported "No such file or directory") and the Developer ID certificate extension OID lacked the field. prefix (parser error "unexpected char: '.'"). A new exported buildMacSigningRequirement() builds the literal requirement as =anchor apple generic and identifier "cn.memtensor.memmy" and certificate leaf[field.1.2.840.113635.100.6.1.13] exists and certificate leaf[subject.OU] = "<team>", and is now the single source for both the stage and install helper scripts. The existing bundle-ID, Developer ID extension, TeamIdentifier and full codesign --verify --deep --strict checks are all retained; the unsigned-build path is unchanged. Values containing quotes or backslashes are rejected instead of being spliced into the generated shell script.

    Tests (App/shell/desktop/tests/mac-update-scripts.test.ts, gated to macOS, plus cross-platform assertions): (1) the generated requirement starts with "=", uses field.<oid>, and contains the bundle ID / subject.OU clauses; (2) both helper scripts embed the corrected literal and no longer contain the legacy forms; (3) unsigned builds omit the team requirement; (4) real codesign verification of ad-hoc-signed .app fixtures proves the corrected value is treated as an inline requirement (no ENOENT / "unexpected char"), reproduces both legacy failures exactly as reported, matches the bundle ID and rejects a different one; (5) a throwaway self-signed identity (TeamIdentifier in subject.OU + Developer ID extension OID, in a temporary keychain) confirms a same-team package passes the team/extension clauses while a foreign team, foreign bundle ID, or missing extension is rejected, and that the full shipped requirement parses (only the Apple anchor excludes the synthetic fixture). A mock-codesign test also asserts the helper forwards the literal requirement string to -R. App/shell/desktop/tests/packaged-runtime-boundary.test.ts was extended to lock in the new IPC channel.

    UI (App/frontend/desktop): update failures now carry a showLogs flag, and the About tab renders a "查看更新日志 / View update logs" action beside the error instead of only "安装更新失败,请稍后再试。". New memmy:open-update-logs IPC + openUpdateLogs() preload bridge opens the updates directory containing mac-update-install.log, where the concrete reason is recorded. New zh/en message key settings.about.openUpdateLogs; settings-page test covers error, prepared-with-failure, success (no link), and English rendering.

    Verification: tsc --noEmit clean for App/shell/desktop and App/frontend/desktop; eslint reports 0 errors (only pre-existing warnings); targeted suites pass — shell mac-update-scripts + packaged-runtime-boundary + windows-update-validation (115 passed, 28 macOS-skipped on this Linux runner), frontend settings-page + i18n + model-config parity (103 passed). Known unrelated pre-existing failures on this Linux runner: React act is not a function in several App/frontend/desktop/src/app interaction tests and a computer-use-agent-restart test (both reproduce on a clean tree); Electron-dependent shell suites cannot load electron on Linux. The new macOS-only codesign tests were not executed here and will run on macOS CI.

    Base branch: main
    Branch: bugfix/autodev-753-20261026235019878
    Commit: ac8d05f
    PR: #754
    Assigned to: @XiaohuiSu

  4. syzsunshine219 commented on Oct 28, 2026

    @syzsunshine219
    Collaborator

    This issue has been fixed in v1.2.401. You can download the latest installation package. If you are unable to update, you can download the installation package from the official website and overwrite the existing installation with the latest package

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions