From c00d11dea17b126c7a3de3bcac9a1fcecde4bdb9 Mon Sep 17 00:00:00 2001 From: Sebastian Mendel Date: Thu, 30 Jul 2026 14:52:22 +0200 Subject: [PATCH 1/3] fix(installers): stop silent death in GitHub release resolution and authenticate in CI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The GitHub-releases fallback assigned LATEST from an unguarded curl|awk pipeline. Under `set -eo pipefail` a failing curl (anonymous requests from shared CI runner IPs are frequently rate-limited) killed the script with zero output — the smoke test then reported "github_release_binary.sh fd install failed:" with an empty log. Guard the pipeline with `|| true` so resolution failure reaches the proper diagnostic (now naming rate limiting as a likely cause), prefer the authenticated API when GITHUB_TOKEN is set, and pass GITHUB_TOKEN to the smoke-test workflow step so CI resolution is deterministic. Fixes #43 Signed-off-by: Sebastian Mendel --- .github/workflows/smoke-test.yml | 4 ++++ .../installers/github_release_binary.sh | 18 +++++++++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/.github/workflows/smoke-test.yml b/.github/workflows/smoke-test.yml index eaf0948..15ea995 100644 --- a/.github/workflows/smoke-test.yml +++ b/.github/workflows/smoke-test.yml @@ -16,4 +16,8 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Run smoke test + env: + # Installer release resolution: anonymous GitHub requests from + # shared runner IPs are rate-limited and made the round-trip flaky. + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: bash scripts/smoke-test.sh diff --git a/skills/cli-tools/scripts/installers/github_release_binary.sh b/skills/cli-tools/scripts/installers/github_release_binary.sh index 26902f4..49828bb 100755 --- a/skills/cli-tools/scripts/installers/github_release_binary.sh +++ b/skills/cli-tools/scripts/installers/github_release_binary.sh @@ -67,12 +67,24 @@ fi # Fallback to GitHub releases if no version URL if [ -z "$LATEST" ] && [ -n "$GITHUB_REPO" ]; then - LATEST="$(curl -fsSIL -H "User-Agent: cli-audit" -o /dev/null -w '%{url_effective}' \ - "https://github.com/$GITHUB_REPO/releases/latest" 2>/dev/null | awk -F'/' '{print $NF}')" + # Authenticated API first when a token is available: anonymous requests + # from shared CI runner IPs are frequently rate-limited. + if [ -n "${GITHUB_TOKEN:-}" ]; then + LATEST="$(curl -fsSL -H "Authorization: Bearer $GITHUB_TOKEN" -H "User-Agent: cli-audit" \ + "https://api.github.com/repos/$GITHUB_REPO/releases/latest" 2>/dev/null | \ + jq -r '.tag_name // empty' 2>/dev/null || true)" + fi + # The `|| true` is load-bearing: under `set -eo pipefail` an unguarded + # failing curl inside this assignment kills the whole script with zero + # output (stderr is /dev/null'd) instead of reaching the error below. + if [ -z "$LATEST" ]; then + LATEST="$(curl -fsSIL -H "User-Agent: cli-audit" -o /dev/null -w '%{url_effective}' \ + "https://github.com/$GITHUB_REPO/releases/latest" 2>/dev/null | awk -F'/' '{print $NF}' || true)" + fi fi if [ -z "$LATEST" ]; then - echo "[$TOOL] Error: Unable to resolve latest version" >&2 + echo "[$TOOL] Error: Unable to resolve latest version (network failure or GitHub rate limit)" >&2 echo "[$TOOL] before: ${before:-}" >&2 exit 1 fi From 8329076228e48ad53d934511693f16c04b9cd3a8 Mon Sep 17 00:00:00 2001 From: Sebastian Mendel Date: Thu, 30 Jul 2026 14:56:41 +0200 Subject: [PATCH 2/3] fix(installers): satisfy Sonar on new code and trace installer in smoke test - [[ ]] instead of [ ] and curl --proto '=https' on the new release resolution lines (shelldre:S7688, shell:S6506). - Run the smoke-test installer under bash -x: the failure mode being chased produces zero output, and the xtrace lands in the install log that is only printed on failure. Signed-off-by: Sebastian Mendel --- scripts/smoke-test.sh | 5 ++++- .../cli-tools/scripts/installers/github_release_binary.sh | 8 ++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/scripts/smoke-test.sh b/scripts/smoke-test.sh index b104cdb..da28060 100755 --- a/scripts/smoke-test.sh +++ b/scripts/smoke-test.sh @@ -66,8 +66,11 @@ echo "=== smoke-test: full installer round-trip ===" # download -> binary in place) works, not just the catalog lookup in isolation. # PREFIX (read by lib/install_strategy.sh's get_install_dir) isolates the # install to a scratch dir instead of touching the real ~/.local/bin. +# bash -x: the installer once died under `set -e` with ZERO output, making +# the failure undiagnosable from CI logs. The xtrace lands in the install +# log, which is only ever printed on failure — successes stay quiet. TMP_PREFIX="$(mktemp -d)" -if PREFIX="$TMP_PREFIX" bash "$SCRIPTS/installers/github_release_binary.sh" fd >"$TMP_PREFIX/smoke-fd-install.log" 2>&1; then +if PREFIX="$TMP_PREFIX" bash -x "$SCRIPTS/installers/github_release_binary.sh" fd >"$TMP_PREFIX/smoke-fd-install.log" 2>&1; then if [ -x "$TMP_PREFIX/bin/fd" ] && "$TMP_PREFIX/bin/fd" --version >/dev/null 2>&1; then pass "github_release_binary.sh installed a working fd: $("$TMP_PREFIX/bin/fd" --version)" else diff --git a/skills/cli-tools/scripts/installers/github_release_binary.sh b/skills/cli-tools/scripts/installers/github_release_binary.sh index 49828bb..99f50fe 100755 --- a/skills/cli-tools/scripts/installers/github_release_binary.sh +++ b/skills/cli-tools/scripts/installers/github_release_binary.sh @@ -69,16 +69,16 @@ fi if [ -z "$LATEST" ] && [ -n "$GITHUB_REPO" ]; then # Authenticated API first when a token is available: anonymous requests # from shared CI runner IPs are frequently rate-limited. - if [ -n "${GITHUB_TOKEN:-}" ]; then - LATEST="$(curl -fsSL -H "Authorization: Bearer $GITHUB_TOKEN" -H "User-Agent: cli-audit" \ + if [[ -n "${GITHUB_TOKEN:-}" ]]; then + LATEST="$(curl --proto '=https' -fsSL -H "Authorization: Bearer $GITHUB_TOKEN" -H "User-Agent: cli-audit" \ "https://api.github.com/repos/$GITHUB_REPO/releases/latest" 2>/dev/null | \ jq -r '.tag_name // empty' 2>/dev/null || true)" fi # The `|| true` is load-bearing: under `set -eo pipefail` an unguarded # failing curl inside this assignment kills the whole script with zero # output (stderr is /dev/null'd) instead of reaching the error below. - if [ -z "$LATEST" ]; then - LATEST="$(curl -fsSIL -H "User-Agent: cli-audit" -o /dev/null -w '%{url_effective}' \ + if [[ -z "$LATEST" ]]; then + LATEST="$(curl --proto '=https' -fsSIL -H "User-Agent: cli-audit" -o /dev/null -w '%{url_effective}' \ "https://github.com/$GITHUB_REPO/releases/latest" 2>/dev/null | awk -F'/' '{print $NF}' || true)" fi fi From 38ce657ba29f14d5490c33a0a78daa1007ad578f Mon Sep 17 00:00:00 2001 From: Sebastian Mendel Date: Thu, 30 Jul 2026 15:00:01 +0200 Subject: [PATCH 3/3] fix(installers): verify the installed binary, not a PATH lookup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The post-install report ran `command -v "$BINARY_NAME" && (...)` — when BIN_DIR is not on PATH (isolated PREFIX in the CI smoke test) the substitution exits non-zero and set -e kills the script silently after a fully successful install. This, not release resolution, was the actual cause of the empty-log smoke failures (#43); the bash -x trace pinpointed the dying assignment. A PATH lookup is also wrong with multiple installs: it can resolve a different copy than the one just written. Probe "$BIN_DIR/$BINARY_NAME" directly and print it as the path. Reproduced red/green locally with fd off PATH: silent exit 1 with a zero-byte log before, clean success report after. Fixes #43 Signed-off-by: Sebastian Mendel --- .../installers/github_release_binary.sh | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/skills/cli-tools/scripts/installers/github_release_binary.sh b/skills/cli-tools/scripts/installers/github_release_binary.sh index 99f50fe..42a1188 100755 --- a/skills/cli-tools/scripts/installers/github_release_binary.sh +++ b/skills/cli-tools/scripts/installers/github_release_binary.sh @@ -253,15 +253,21 @@ if [ -n "$EXTRACT_DIR" ] && [ -d "$EXTRACT_DIR" ]; then rm -rf "$EXTRACT_DIR" fi -# Report -after="$(command -v "$BINARY_NAME" >/dev/null 2>&1 && \ - (timeout 2 "$BINARY_NAME" --version /dev/null || \ - timeout 2 "$BINARY_NAME" version --client /dev/null | head -1 || \ - timeout 2 "$BINARY_NAME" version /dev/null | head -1 || true))" -path="$(command -v "$BINARY_NAME" 2>/dev/null || true)" +# Report — probe the binary we actually installed, never a PATH lookup: +# $BIN_DIR may not be on PATH (isolated PREFIX in CI), where the old +# `command -v && (...)` substitution exited non-zero and set -e killed the +# script silently right here; with multiple installs a PATH lookup can also +# resolve a different copy than the one just written. +installed_bin="$BIN_DIR/$BINARY_NAME" +after="" +if [[ -x "$installed_bin" ]]; then + after="$(timeout 2 "$installed_bin" --version /dev/null || \ + timeout 2 "$installed_bin" version --client /dev/null | head -1 || \ + timeout 2 "$installed_bin" version /dev/null | head -1 || true)" +fi printf "[%s] before: %s\n" "$TOOL" "${before:-}" printf "[%s] after: %s\n" "$TOOL" "${after:-}" -if [ -n "$path" ]; then printf "[%s] path: %s\n" "$TOOL" "$path"; fi +printf "[%s] path: %s\n" "$TOOL" "$installed_bin" # Refresh snapshot after successful installation refresh_snapshot "$TOOL" || true