Skip to content

fix(desktop): unlink destination before copying binaries - #10705

Merged
alexhancock merged 1 commit into
aaif-goose:mainfrom
vincenzopalazzo:fix/atomic-binary-copy
Jul 31, 2026
Merged

fix(desktop): unlink destination before copying binaries#10705
alexhancock merged 1 commit into
aaif-goose:mainfrom
vincenzopalazzo:fix/atomic-binary-copy

Conversation

@vincenzopalazzo

Copy link
Copy Markdown
Contributor

Summary

  • prepare-platform-binaries.js used fs.copyFileSync/fs.cpSync directly onto existing destinations, truncating and rewriting executables in place. On macOS arm64 this invalidates the code signature of any running process mapped from that file, and the kernel SIGKILLs it (EXC_CRASH — Code Signature Invalid).
  • Now unlinks the destination first (fresh inode), matching the Justfile copy-binary recipe. Running goose serve/goose acp processes survive a re-run of packaging.
  • Documents the rule in AGENTS.md (## Never section).

Review Notes

  • Production-safety review passed (2 rounds).
  • Script is not covered by eslint (only src/**/*.ts); verified with node --check.
  • Windows-only code paths changed (win32 branch + pinned uv binaries); macOS/Linux flows untouched.

Decision Log

Hardest decision: Whether to use copy-to-temp + atomic rename instead of unlink-then-copy. Chose unlink-then-copy to match the existing Justfile convention (rm -f + cp -p) — consistent, simpler, and the non-atomic window doesn't matter for a build script that owns its output directory.

Alternatives rejected:

  • Atomic rename via temp file: marginally safer but introduces a second convention and more code for no practical gain here.
  • Keep force: true on cpSync: redundant once the destination is removed first.

Least confident about: The file branch uses plain rmSync (not recursive), so it would throw if a directory ever existed at a file's destination path. That can't happen with the current fixed file set (goose-npm, *.cmd), and the old code failed identically in that scenario — so no regression, just not newly hardened.

Test plan

  • CI passes
  • Re-running desktop packaging while a packaged Goose.app is running no longer kills its goose serve process

Overwriting an executable in place (fs.copyFileSync onto an existing
file) truncates and rewrites it, which invalidates the code signature
of any running process mapped from it - macOS then SIGKILLs those
processes with "Code Signature Invalid". This bites developers who
re-run packaging while the Goose desktop app or another ACP host
(e.g. buzz) still has goose serve/acp processes alive.

Unlink the destination first (matching the Justfile copy-binary
recipe) so the new copy gets a fresh inode and running processes keep
their valid old mapping. Also documents the rule in AGENTS.md.
@alexhancock alexhancock self-assigned this Jul 30, 2026
@alexhancock
alexhancock self-requested a review July 31, 2026 15:18
@alexhancock
alexhancock merged commit b6db6a1 into aaif-goose:main Jul 31, 2026
23 checks passed
lifeizhou-ap added a commit that referenced this pull request Aug 3, 2026
* main: (103 commits)
  fix: parse PyPI requirements for OSV checks (#10510)
  fix(telegram): contain voice file extensions (#10456)
  Revert "feat(security): chunk command-classifier input with overlapping windows" (#10416) (#10870)
  docs: update Discord invite (#10863)
  fix(security): preserve denied tool request precedence (#10612)
  fix(hints): contain subdirectory hint discovery (#10545)
  chore(deps): bump pem from 3.0.6 to 4.0.0 (#10853)
  chore(deps): bump base64 from 0.22.1 to 0.23.0 (#10851)
  chore(deps): bump jsonwebtoken from 10.4.0 to 11.0.0 (#10850)
  chore(deps): bump astral-sh/setup-uv from 8.3.2 to 9.0.0 (#10847)
  chore(deps): bump docker/login-action from 4.5.1 to 4.5.2 (#10846)
  chore(deps): bump github/codeql-action from 4 to 4.37.3 (#10845)
  chore(deps): bump actions/stale from 10.4.0 to 11.0.0 (#10844)
  feat(dictation): add LOCAL_WHISPER_LANGUAGE for multilingual local transcription (#10634)
  fix(desktop): clear stale validation error when reopening the schedule modal (#10627)
  fix(docs): resolve CVE-2026-13149 in both brace-expansion copies (#10842)
  feat(provider): add Friendli as declarative provider (#10762)
  fix: sanitize shell/subprocess call in linux.rs (#10748)
  fix(desktop): unlink destination before copying binaries (#10705)
  feat(otel): enrich root span with gen_ai attributes and improve output format (#10816)
  ...
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.

2 participants