Skip to content

fix(installer): abort on signal instead of resuming and exiting 0 - #64

Merged
WomB0ComB0 merged 2 commits into
mainfrom
fix/abort-on-signal
Aug 16, 2026
Merged

fix(installer): abort on signal instead of resuming and exiting 0#64
WomB0ComB0 merged 2 commits into
mainfrom
fix/abort-on-signal

Conversation

@WomB0ComB0

Copy link
Copy Markdown
Member

Highest-severity finding from the reference-corpus audit (nvm defensive-shell lens), verified before and after in two shells.

The bug

trap cleanup EXIT HUP INT QUIT TERM

One handler for six events. A trap on a non-EXIT signal runs its handler and then resumes — it does not terminate. So Ctrl-C during a long step ran cleanup, fell through to the next step, printed Ready! and exited 0.

set -e doesn't rescue it either: every long step sits in a condition — if ! sh "$_nix_installer" install, if nix develop … --command true, if ! gh release download — and a command in a condition context is exempt from set -e by definition. The interrupted step was simply logged as a soft failure and the installer carried on.

Verified, both directions

old  under bash -> exit=0    reached "Ready!"
old  under sh   -> exit=0    reached "Ready!"
new  under bash -> exit=130  did not
new  under sh   -> exit=130  did not

(sh here is busybox ash — a genuine POSIX shell, not bash wearing a different name.)

Why it matters more than Ctrl-C

The worst case is SIGTERM in the documented unattended mode (REPO=<name> YES=1). CI kills the run on timeout, the installer continues through its remaining steps, exits 0, and the wrapper records a successful provision of a machine that was never provisioned.

Second-order: cleanup also clears _TMP_PATHS, so a signal arriving just after make_tmpdir removed the temp directory and forgot it while the script continued. That one degrades safely — the next write into the deleted path fails and the step is skipped with a warning — but it's another way the run looked fine and wasn't.

The fix

Two lines. cleanup is idempotent (it clears _TMP_PATHS in the current shell — only the read loop is a subshell), so the EXIT trap firing afterwards is a no-op.

POSIX only, no bashisms, so the curl-pipe path is unaffected. Verified: sh -n passes, shellcheck -S warning -s sh -x is clean, stamp --check still in sync.

Scope

scripts/install-hooks.sh:131 has the identical pattern and is deliberately not touched here — it's a separate pinned artifact with a generated digest, so it belongs in its own change.

Note this reaches users only after a release; main and the served v0.4.3 will differ until then.

Related

The audit produced 20 confirmed findings against 10 refuted. This is the one worth landing on its own. #63 carries the CI-gate half — including that -S error provably passes a file containing a bash array and [[ ]], so a bashism could have entered this very script with a green board.

install.sh registered one handler for six events:

    trap cleanup EXIT HUP INT QUIT TERM

A trap on a non-EXIT signal runs its handler and then RESUMES the
script. It does not terminate. So Ctrl-C during a long step ran cleanup,
fell through to the next step, printed "Ready!" and exited 0.

set -e does not rescue it. Every long step here sits in a condition, and
a command in a condition context is exempt from set -e by definition, so
the interrupted step was merely observed and logged as a soft failure.

Verified in bash and in busybox ash, before and after:

    old  under bash -> exit=0    reached "Ready!"
    old  under sh   -> exit=0    reached "Ready!"
    new  under bash -> exit=130  did not
    new  under sh   -> exit=130  did not

The worst case is not Ctrl-C. It is SIGTERM in the documented unattended
mode: CI kills the run on timeout, the installer continues through the
remaining steps and exits 0, and the wrapper records a successful
provision of a machine that was never provisioned.

Second-order: cleanup also clears the temp-path list, so a signal
arriving just after make_tmpdir removed the temp directory and forgot it
while the script carried on. That degrades safely — the next write into
the deleted path fails and the step is skipped with a warning — but it
is another way the run looked fine and was not.

Fix is two lines. cleanup is idempotent, so the EXIT trap firing after
the signal handler is a no-op.

POSIX only, no bashisms, so the curl-pipe path is unaffected. Verified:
sh -n passes, shellcheck at warning severity in sh dialect is clean, and
stamp --check is still in sync.

scripts/install-hooks.sh has the same pattern and is deliberately left
alone here — it is a separate pinned artifact whose digest is generated,
so it belongs in its own change.

Found by the reference-corpus audit, nvm defensive-shell lens.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@WomB0ComB0
WomB0ComB0 requested a review from a team as a code owner August 16, 2026 08:58
@coderabbitai

coderabbitai Bot commented Aug 16, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@WomB0ComB0, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 3 minutes

Limit details: You’ve used all 1 included review currently available under your plan.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 46c1d00f-900e-4617-8652-dbfe02c6a6ae

📥 Commits

Reviewing files that changed from the base of the PR and between 84656b5 and 4c730d1.

📒 Files selected for processing (1)
  • install.sh

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 16, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
get-resq-software 4c730d1 Aug 16 2026, 09:49 AM

@github-actions

Copy link
Copy Markdown
Contributor

In install.sh, the script may fail with "Unknown option: --" if -- is passed as an argument.

The for loop in the main function that parses arguments does not handle --, which is conventionally used to signify the end of options.

To reproduce, run:

sh install.sh --

This will output:

fail  Unknown option: -- (try --help)

I suggest adding a case for -- in the argument parsing loop to break and stop processing further arguments as options.

--- a/install.sh
+++ b/install.sh
@@ -936,6 +936,7 @@
   for _arg in "$@"; do
     case "$_arg" in
       -h|--help)    usage; exit 0 ;;
+      --)           break ;;
       -V|--version) printf 
 "$SCRIPT_VERSION"; exit 0 ;;
       *)            fail "Unknown option: $_arg (try --help)" ;;
     esac

Generated by ai-auditor for #64 · gem25pro · 50.6 AIC · ⌖ 3.89 AIC · ⊞ 12.6K ·

@WomB0ComB0
WomB0ComB0 merged commit 3967d08 into main Aug 16, 2026
23 checks passed
@WomB0ComB0
WomB0ComB0 deleted the fix/abort-on-signal branch August 16, 2026 09:51
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