Skip to content

release-train: develop -> staging - #687

Merged
tracebloc-release-train[bot] merged 2 commits into
stagingfrom
release-train/to-staging
Aug 12, 2026
Merged

release-train: develop -> staging#687
tracebloc-release-train[bot] merged 2 commits into
stagingfrom
release-train/to-staging

Conversation

@LukasWodka

@LukasWodkaLukasWodka commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Automated promotion by the release train (RFC-0008 D14). Head is the train-managed release-train/to-staging branch (a mirror of develop), so it never collides with a human PR. Merged only when the fr-gate is green.


Note

Medium Risk
Touches the installer's stop-and-check classification and failure/exit paths that decide whether machines reinstall or reconcile. Changes are defensive and covered by new bats tests, but misclassification here directly affects real installs.

Overview
Hardens the bash installer so re-runs and failures report the real machine state instead of a generic first-time or empty-log outcome.

Stop-and-check (client#682):_assess_classify now probes Docker reachability first. An installed-but-unreachable daemon is degraded/runtime-down (with an honest “Docker isn’t running” line) instead of fresh, so the normal flow starts Docker and reconciles rather than offering a first-time install. Permission-denied cases stay on the normal path.

Failure diagnostics (client#681): Arms an ERR trap with set -E so _record_err captures the first failing site inside install_macos/install_linux. install_cleanup logs the command, names the site on screen, treats Ctrl-C/SIGTERM as interrupted (not broken), and adds step-b breadcrumbs.

Pipefail / SIGPIPE (#680): Switches early-exit cmd | grep/awk probes to capture-then-match (and similar) in _cluster_exists, macOS admin/arch detection, and related paths so a live cluster, Apple Silicon Mac, or admin user is no longer misread as absent.

Also bumps actions/add-to-project to v2.0.0 and extends bats coverage for the new probes and traps.

Reviewed by Cursor Bugbot for commit ef5c159. Bugbot is set up for automated code reviews on this repo. Configure here.

LukasWodkaand others added 2 commits August 12, 2026 14:25
v1.0.2 declares `using: node20`. Node 20 is deprecated on GitHub-hosted
runners, so GitHub force-runs this action on Node 24 today and prints the
deprecation notice on every run -- including the 542 that succeeded. That
fallback is temporary; when it is withdrawn every repo still on v1.0.2 breaks
at once. v2.0.0 declares node24 and needs no fallback.
Not an outage fix: re-running the reported failed job unchanged on the v1.0.2
pin succeeded, so that failure was a transient TLS condition, not a runtime
incompatibility. cli and release-train have run this exact v2.0.0 pin
successfully (12/12 recent runs).
v2.0.0 is input-compatible: it declares project-url, github-token, labeled and
label-operator; this caller passes the first two.
Refs: tracebloc/backend#1816
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…time a fresh machine (client#681, client#682) (#683)
* fix(installer): say where a step died, and stop calling a stopped runtime a fresh machine
Two failures that were reported together, both bash-only gaps the PowerShell
installer had already closed.
1. A step could fail with zero diagnostics (client#681). Under `set -euo
pipefail` a command failing outside an if/&&/|| context killed the run with
no output at all — and the install log, which is the whole session tee'd,
recorded nothing either, so "check the install log" led to a log that said
nothing. There was no ERR trap anywhere in scripts/.
Adds an ERR trap (armed with `set -E`, without which it would only fire at
top level and miss every failure inside install_macos/install_linux) that
records file:line, the unexpanded command, and the exit status. The closer
names the site on screen and logs the command; step b logs a breadcrumb per
stage so the log narrows the failure even if the trap is bypassed. Ctrl-C and
SIGTERM now read as "interrupted", not as an installer failure — they were
indistinguishable from a real one, on screen and in the log.
Counterparts: Show-FatalError / Show-Interrupted (#577), Err's detail lines
(#423).
2. A stopped container runtime was classified as a fresh machine (client#682).
`_cluster_exists` is a boolean whose three probes all swallow stderr and
return 1, so a down daemon looked exactly like an empty machine: a laptop
that only needed Docker started was told "setting up for the first time".
Classifies an installed-but-unreachable runtime as degraded/runtime-down
before the cluster probe, and says so. Deliberately narrow: no docker binary
is still fresh, and "permission denied" is a different remedy that keeps its
own path. The run CONTINUES — install_docker_desktop already starts Docker
Desktop and create_cluster reconciles the existing cluster, and taking that
away would trade one bad outcome for another. The bug was the claim, not the
flow.
Counterpart: the tri-state Get-ClusterRunStateFromList (#557).
Covered by 15 new bats tests (940 total, green), including the pipefail/SIGPIPE
death class that previously produced no output whatsoever.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(macos): close the early-exit pipe hazard in the admin check step b runs first
#680 swept this hazard across the fleet but did not reach setup-macos.sh, whose
_macos_user_is_admin is the FIRST command step b executes.
printf '%s\n' $groups | grep -qx admin
`grep -q` stops at its first match and `admin` sits near the FRONT of a macOS
group list, so printf is often still writing when the pipe closes: SIGPIPE,
pipefail, 141. The caller reads that as "not an administrator" and hard-fails a
perfectly fine machine with the managed-Mac remedy. Reproducible, not
theoretical — with a long group list the old form returns 141 on every run and
the new one returns 0:
old=141 new=0 (x5)
Match POSITION is the trigger, not producer size, so a directory-bound or
MDM-managed Mac with a long group list hits it and a short one does not.
Same transform as #680 (capture, then match with a here-string), plus two more
sites in the same file and one in common.sh where a SIGPIPE'd producer inside an
`if` would MISBRANCH rather than abort:
- setup-macos.sh: hw.optional.arm64 -> would call an Apple Silicon Mac amd64 and
fetch the Intel Docker Desktop DMG
- setup-macos.sh: the Docker.app arch probes -> `case`, which also drops the
`A && B` set -e subtlety
- common.sh: the load-time ARCH override -> would pick the wrong download for
every pinned tool on Apple Silicon
Mutation-real regression test in setup-macos-lifecycle.bats, driven through a
real script so pipefail is genuinely in force (943 bats, green).
Refs tracebloc/backend#1778
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(assess): permission-denied must beat the connection match, not lose to it
Bugbot, correctly. The real Linux docker-group error contains BOTH the
permission wording and a `dial unix …` clause:
permission denied while trying to connect to the Docker daemon socket at
unix:///var/run/docker.sock: Get "http://…/info": dial unix
/var/run/docker.sock: connect: permission denied
so matching the connection phrases first classified a docker-group problem as a
down daemon and answered it with "start Docker" — the exact confusion
_assess_runtime_down exists to prevent.
Checks permission-denied FIRST and returns not-down. A negative match before the
positive one is the only ordering that survives an error string containing both.
The test was vacuous for the same reason: its fixture was a shortened message
with no `dial unix`, so it passed against the broken code. Both fixtures are now
the real full messages (the `permission denied` and `Got permission denied`
variants), and are mutation-real — dropping the guard fails them.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(cluster): close the second route to the client#682 misclassification
_cluster_exists is the function client#682 names, and guarding the daemon-down
case did not finish the job: all three of its probes piped k3d into a consumer
that stops at the FIRST matching line — and our own cluster is usually that
line. k3d takes SIGPIPE, pipefail makes the pipeline 141, and inside these `if`s
that reads as "no such cluster". The gate then calls a machine with a live,
running cluster FRESH and offers a first-time install: the same user-visible bug
as a down daemon, reached a completely different way.
Capture-then-match (#680's transform) on all three probes, which also spares two
extra k3d invocations. Same fix in two more spots in this file:
- _handle_existing_cluster's non-jq server count — awk `exit` closes the pipe on
our row, so this could abort the installer mid-reconcile with no message
- the proxy-env check — grep -Eq stops at the first match, so a present variable
could be reported MISSING and produce a spurious warning
Two tests in cluster.bats. Note the "found" one is mutation-real only against the
WHOLE pre-fix function: reverting probe 2 alone still passes, because probe 3's
grep fallback finds the cluster anyway — the vacuity trap #680 called out. The
test comment says so.
946 bats, green.
Refs tracebloc/backend#1778
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* refactor(cluster): capture each k3d listing lazily, inside the probe that reads it
Asad on #683: `_list` was captured at the top of _cluster_exists but is only read
by probe 2. On the common re-run — jq present, our cluster found by the JSON
probe — that shell-out ran and was thrown away, so the comment claiming the
capture "spares two extra k3d calls" was backwards for exactly the path that
matters: it ADDED one.
Each capture now sits inside the probe that reads it, so a probe that never runs
never shells out. The k3d call count is identical to the pre-fix code, and the
common path is back to one call. Comment corrected to say that rather than the
opposite.
No behaviour change; 946 bats green.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
@LukasWodka

Copy link
Copy Markdown
ContributorAuthor

bugbot run

@cursorcursorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit ef5c159. Configure here.

@tracebloc-release-traintracebloc-release-trainBot added gate-nudge Toggled by the release train to (re-)fire the fr-gate and removed gate-nudge Toggled by the release train to (re-)fire the fr-gate labels Aug 12, 2026
@tracebloc-release-train
tracebloc-release-trainBot merged commit ce24641 into stagingAug 12, 2026
56 checks passed
Sign up for freeto 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

@LukasWodka