Skip to content

ci(release): 显式 strip macOS bundle xattr (defense-in-depth)#83

Merged
appergb merged 1 commit into
mainfrom
ci/strip-xattr-defense
Apr 30, 2026
Merged

ci(release): 显式 strip macOS bundle xattr (defense-in-depth)#83
appergb merged 1 commit into
mainfrom
ci/strip-xattr-defense

Conversation

@appergb
Copy link
Copy Markdown
Collaborator

@appergb appergb commented Apr 30, 2026

防御性步骤:在 macOS 产物 upload 之前 xattr -cr 一次。GitHub Actions 输出本来就不带 quarantine,但显式声明让 "云端 artifact 一定干净" 变成可验证承诺。

Summary by Sourcery

CI:

  • Add a macOS-only step in the Tauri release workflow to strip extended attributes and quarantine flags from .app and .dmg artifacts before upload.

GitHub Actions 输出本来就不带 com.apple.quarantine (actions/upload-artifact
不跨机器持久化 xattr, softprops/action-gh-release 上传 binary stream 也不带),
但加这一步让 "云端 artifact 一定干净" 变成可验证的承诺, 未来 release 不会因
runner 环境变化退化.

用户下载到本地后浏览器/LaunchServices 仍会加 quarantine, 依赖 release notes
里的 xattr -cr 指引或一行安装命令处理.
@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented Apr 30, 2026

Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

Adds a defensive CI step in the Tauri release workflow to strip extended attributes (including com.apple.quarantine) from macOS bundles before uploading them as artifacts, ensuring uploaded artifacts are verifiably clean.

Sequence diagram for macOS bundle xattr stripping before artifact upload

sequenceDiagram
  participant WF as Workflow
  participant R as Actions_runner_macos
  participant X as xattr_tool
  participant FS as macOS_filesystem
  participant A as GitHub_Artifacts

  WF->>R: Execute job for matrix.platform == macos-latest
  R->>R: Build macOS bundles
  R->>FS: List bundle directories (ls macos/ dmg/ ...)

  WF->>R: Run Strip xattr / quarantine step
  loop For each path in macos/*.app and dmg/*.dmg
    R->>FS: Check if path exists
    alt Path exists
      R->>X: xattr -cr path
      X->>FS: Clear extended attributes
      R->>X: xattr -lr path
      X->>R: List remaining attributes (for logging)
    else Path does not exist
      R-->>R: Skip path
    end
  end

  WF->>R: Run Upload macOS artifacts step
  R->>A: Upload sanitized .app and .dmg bundles
Loading

Flow diagram for new macOS xattr stripping step in release workflow

flowchart TD
  A["Build macOS bundles"] --> B["List bundle directories (ls macos/ dmg/ ...)"]
  B --> C["Strip xattr / quarantine on macOS bundles (macos-latest only)"]
  C --> D["Upload macOS artifacts via actions/upload-artifact"]

  subgraph Strip_xattr_step
    C1["Loop over macos/*.app"]
    C2["Loop over dmg/*.dmg"]
    C3["For each existing path: xattr -cr path"]
    C4["Then: xattr -lr path (log remaining attributes)"]

    C --> C1
    C1 --> C3
    C --> C2
    C2 --> C3
    C3 --> C4
  end
Loading

File-Level Changes

Change Details Files
Add a macOS-only CI step to recursively clear and then list extended attributes on .app and .dmg bundles before artifact upload.
  • Introduce a bash step conditioned on matrix.platform == 'macos-latest' in the release workflow.
  • Run a loop over macOS bundle output directories (macos/.app and dmg/.dmg), skipping non-existent paths gracefully.
  • For each existing bundle, invoke xattr -cr to strip all extended attributes, ignoring failures, and then xattr -lr to log remaining attributes for auditability.
  • Place the stripping step immediately before the macOS artifact upload step so that uploaded artifacts are guaranteed to be post-processed.
.github/workflows/release-tauri.yml

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@appergb appergb merged commit e3f91e8 into main Apr 30, 2026
2 checks passed
@appergb appergb deleted the ci/strip-xattr-defense branch April 30, 2026 06:56
Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've left some high level feedback:

  • Consider using xattr -d com.apple.quarantine (or a targeted attribute list) instead of xattr -cr, so you only remove the quarantine flag and avoid unintentionally stripping other extended attributes that might be meaningful (e.g., for signing or metadata).
  • Right now both xattr invocations are suffixed with || true, which will hide any unexpected failures; if the intent is defense-in-depth, you might want to at least log non-zero exit codes or only ignore specific, benign failures (like "No such xattr").
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Consider using `xattr -d com.apple.quarantine` (or a targeted attribute list) instead of `xattr -cr`, so you only remove the quarantine flag and avoid unintentionally stripping other extended attributes that might be meaningful (e.g., for signing or metadata).
- Right now both `xattr` invocations are suffixed with `|| true`, which will hide any unexpected failures; if the intent is defense-in-depth, you might want to at least log non-zero exit codes or only ignore specific, benign failures (like "No such xattr").

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

appergb pushed a commit that referenced this pull request Apr 30, 2026
…attr

修复 Codex audit 对 main HEAD a9c81e6 的 2 条 HIGH + 把 macOS auto-update 的
"重启后 Gatekeeper 拦截"问题封死。

## HIGH #2: 版本号不一致
PR #84 没顺手 bump 版本,main 仍自报 1.2.2,下次直接打 v1.2.3-tauri 会让 updater
manifest 自报 1.2.2,已安装的 1.2.2 客户端永远拿不到 "有新版本"。

修:package.json + tauri.conf.json + Cargo.toml 全部改 1.2.3。

## HIGH #1: updater pubkey 所有权
PR #84 使用的 pubkey 是外部贡献者本地生成的,appergb 不掌握对应 private key。
任何持有那把私钥的人都能签发更新 -> 客户端 OTA 装上恶意版本。

修:
- 用 npx @tauri-apps/cli signer generate --ci 生成 appergb 自己的 keypair
- 新 pubkey: F0FCDE68E08E6D4E (写入 tauri.conf.json plugins.updater.pubkey)
- 私钥已通过 gh secret set TAURI_SIGNING_PRIVATE_KEY 配到 GitHub repo secret
- 私钥本地副本只在 /tmp,不进 git,commit 后会清除

## macOS auto-update 后 strip xattr
restart_app 在 app.restart() 前对 .app bundle 跑 /usr/bin/xattr -cr。这是
Tauri auto-updater + 未公证应用的组合下唯一让"自动更新对用户零摩擦"的解法 —
否则 Gatekeeper 在重启时会拦说"OpenLess 已损坏",用户必须开终端 xattr 才能
继续用,违反 auto-update 的本意。

未来发版逻辑必须保留这一步。release-tauri.yml 上一次 PR (#83) 已经在 CI 侧
strip 过一次,本次在 client 侧重启时再 strip 一次,双保险覆盖
"下载 -> 解压 -> 安装 -> 重启"全链路。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant