Skip to content

fix(install): stop the installer hanging on the macOS signature check - #234

Open
plombeer31 wants to merge 1 commit into
mainfrom
fix/install-signature-check-hang
Open

fix(install): stop the installer hanging on the macOS signature check#234
plombeer31 wants to merge 1 commit into
mainfrom
fix/install-signature-check-hang

Conversation

@plombeer31

Copy link
Copy Markdown
Collaborator

The report

curl -fsSL https://atomicagent.io/install | sh prints the checksum line and then sits there with a bare cursor. It looks dead.

What is actually happening

Nothing is wrong with v0.4.1 — the tarball is intact and the binary runs (atomic-agent 0.4.1). The install is blocked inside the signature gate, which ran inline and silently:

codesign --verify --strict "$_tmp_bin"

macOS scans a newly written executable the first time anything asks about its signature, and codesign blocks — at ~0% CPU, so it does not even look busy — until that scan lands. On a 140 MB SEA binary that is minutes. Measured on an idle M-series laptop:

what wall clock
codesign --verify --strict on the freshly extracted binary 4m59s (0.16s user, 0% CPU)
the same bytes cp'd to a path the scanner has already seen 0.19s

The wait alone is bad. The install-breaking part is what people do about it: they read the frozen cursor as a hang and press Ctrl-C. By then the binary has been copied to $INSTALL_DIR/.atomic-agent.tmp.$$ but not yet renamed into place, and the EXIT trap only cleaned the work dir — so they are left with no atomic-agent at all plus a 140 MB orphan beside it:

-rwxr-xr-x  141145856  .atomic-agent.tmp.2116
-rwxr-xr-x  141145856  .atomic-agent.tmp.272
(no atomic-agent, no atag)

That is the exact state this was reported from — two abandoned attempts, no CLI.

The fix

  • Bound the check. It runs in the background behind a one-line progress readout in the same style as the download bar, capped at 20s (ATOMIC_AGENT_VERIFY_TIMEOUT, 0 skips it). A timeout warns and proceeds — the sha256 compared immediately above already proves the bytes are the ones the release published — while a codesign that actually returns non-zero still aborts, because a binary whose pages do not match its signature gets SIGKILLed on launch.
  • Verify the archive copy, before touching the install dir. A check that fails or is interrupted now leaves the existing installation exactly as it was.
  • Clean up on INT/TERM as well as EXIT, and sweep .atomic-agent.tmp.* orphans left behind by installs interrupted before this existed.

One subtlety worth flagging for review: the status-capturing subshell uses || _rc=$? rather than a bare command. It inherits set -e, so a bare failing codesign would kill the subshell before it could write its status — which reads to the parent exactly like a pass. Caught that in testing; the failure path is covered below.

Verification

macOS 15 (arm64); sh -n / bash -n / dash -n all clean.

case result
slow codesign (stub sleeps 300s), budget 5s times out at 5s, continues, installs working atomic-agent 0.4.1, no orphans
failing codesign (stub exits 1) aborts with the original error, exit 1, previous binary preserved, install dir otherwise untouched
ATOMIC_AGENT_VERIFY_TIMEOUT=0 check skipped entirely, install completes
real codesign, real download capped at 20s, installs working atomic-agent 0.4.1, no orphans
SIGTERM during the check exit 143, no orphaned tmp binary, no leftover work dir
TTY rendering checking signature ███░░░░░ 3s, redrawn in place, one trailing newline; degrades to a plain line without a TTY and to ASCII glyphs in a non-UTF-8 locale

No release is needed: atomicagent.io/install 302s straight to raw.githubusercontent.com/AtomicBot-ai/atomic-agent/main/scripts/install.sh, so merging this to main fixes the published one-liner.

🤖 Generated with Claude Code

`curl -fsSL https://atomicagent.io/install | sh` printed the checksum line
and then sat there with a bare cursor for minutes. Nothing was wrong with
the release — the install was blocked inside

    codesign --verify --strict "$_tmp_bin"

which ran inline and silently. macOS scans a newly written executable the
first time anything asks about its signature, and codesign blocks — at ~0%
CPU, so it does not even look busy — until that scan lands. On our 140 MB
SEA binary that is minutes: measured 4m59s on an idle M-series laptop,
against 0.2s for a codesign of the very same bytes at a path the scanner
had already seen.

People read the frozen cursor as a hang and pressed Ctrl-C, which is the
part that actually broke installs: the binary had already been copied to
`$INSTALL_DIR/.atomic-agent.tmp.$$` but not yet renamed, so they were left
with no `atomic-agent` at all and a 140 MB orphan next to it. Two of those
orphans, and no CLI, is exactly the state this was reported from.

- Bound the check. It runs in the background against a one-line progress
  readout in the same style as the download bar, capped at 20s
  (ATOMIC_AGENT_VERIFY_TIMEOUT; 0 skips it). A timeout warns and proceeds —
  the sha256 compared just above already proves the bytes are the released
  ones — while a codesign that actually returns non-zero still aborts.
- Verify the archive copy, before anything is written to the install dir,
  so a failed or interrupted check leaves the existing install untouched.
- Clean up on INT/TERM as well as EXIT, and sweep `.atomic-agent.tmp.*`
  orphans left by installs interrupted before this existed.

Verified on macOS 15 (arm64), sh/bash/dash: slow codesign times out at the
budget and still installs a working `atomic-agent 0.4.1`; a failing
codesign aborts with the old error and preserves the previous binary;
SIGTERM mid-check exits 143 leaving neither an orphan nor a work dir.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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