Uh oh!
There was an error while loading. Please reload this page.
feat(install): prepare-host admin step (#1178, client) - #377
Conversation
LukasWodka
commented
Jul 22, 2026
bugbot run |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
LukasWodka
commented
Jul 23, 2026
bugbot run |
prepare-host cleared the EXIT trap (install_cleanup does not apply to a host-prep run), but run_prepare_host still calls preflight_sudo, which backgrounds a sudo credential keepalive — left orphaned, polling sudo every 50s. Replace the blanket `trap - EXIT` with a lightweight EXIT trap that kills SUDO_KEEPALIVE_PID (whether run_prepare_host returns or error()s), without install_cleanup's credential-shred + messaging that do not apply here. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2643238 to
72780ccCompareLukasWodka
commented
Jul 23, 2026
bugbot run |
Uh oh!
There was an error while loading. Please reload this page.
72780cc to
2a66916Compareprepare-host cleared the EXIT trap (install_cleanup does not apply to a host-prep run), but run_prepare_host still calls preflight_sudo, which backgrounds a sudo credential keepalive — left orphaned, polling sudo every 50s. Replace the blanket `trap - EXIT` with a lightweight EXIT trap that kills SUDO_KEEPALIVE_PID (whether run_prepare_host returns or error()s), without install_cleanup's credential-shred + messaging that do not apply here. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
LukasWodka
commented
Jul 23, 2026
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
1 issue from previous review remains unresolved.
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 2a66916. Configure here.
Uh oh!
There was an error while loading. Please reload this page.
prepare-host cleared the EXIT trap (install_cleanup does not apply to a host-prep run), but run_prepare_host still calls preflight_sudo, which backgrounds a sudo credential keepalive — left orphaned, polling sudo every 50s. Replace the blanket `trap - EXIT` with a lightweight EXIT trap that kills SUDO_KEEPALIVE_PID (whether run_prepare_host returns or error()s), without install_cleanup's credential-shred + messaging that do not apply here. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
e694781 to
e522814CompareUh oh!
There was an error while loading. Please reload this page.
…EPARE_USER, never SUDO_USER (Bugbot #377) SUDO_USER is the ADMIN who ran prepare-host, not the researcher — the fallback added the wrong user to the docker group and reported success while the researcher still could not install at Tier 0. Require TB_PREPARE_USER explicitly; otherwise skip the grant and tell the admin exactly how to grant it. New bats asserts SUDO_USER is not used. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
LukasWodka
commented
Jul 23, 2026
bugbot run |
Uh oh!
There was an error while loading. Please reload this page.
prepare-host cleared the EXIT trap (install_cleanup does not apply to a host-prep run), but run_prepare_host still calls preflight_sudo, which backgrounds a sudo credential keepalive — left orphaned, polling sudo every 50s. Replace the blanket `trap - EXIT` with a lightweight EXIT trap that kills SUDO_KEEPALIVE_PID (whether run_prepare_host returns or error()s), without install_cleanup's credential-shred + messaging that do not apply here. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2a66916 to
e694781CompareUh oh!
There was an error while loading. Please reload this page.
LukasWodka
commented
Jul 23, 2026
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
1 issue from previous review remains unresolved.
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit c9e11e9. Configure here.
78d2285 to
c9e11e9Compareprepare-host cleared the EXIT trap (install_cleanup does not apply to a host-prep run), but run_prepare_host still calls preflight_sudo, which backgrounds a sudo credential keepalive — left orphaned, polling sudo every 50s. Replace the blanket `trap - EXIT` with a lightweight EXIT trap that kills SUDO_KEEPALIVE_PID (whether run_prepare_host returns or error()s), without install_cleanup's credential-shred + messaging that do not apply here. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…EPARE_USER, never SUDO_USER (Bugbot #377) SUDO_USER is the ADMIN who ran prepare-host, not the researcher — the fallback added the wrong user to the docker group and reported success while the researcher still could not install at Tier 0. Require TB_PREPARE_USER explicitly; otherwise skip the grant and tell the admin exactly how to grant it. New bats asserts SUDO_USER is not used. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…appened The closing "The researcher can now install with no administrator rights" message printed unconditionally — even when no TB_PREPARE_USER was given (we only hinted how to grant access) or the usermod grant failed. In those cases the researcher still can't reach the docker socket, so the promise was a lie that sends them into an install which then demands sudo (Bugbot #377). Track whether a grant succeeded and branch the closing message: the no-admin promise only when granted, otherwise an honest "once they have docker-group access, they can install" note. Add tests for the granted / no-target / usermod-failed paths. Also resolve stray git conflict markers left in setup-linux.bats by the earlier rebase cascade (the _tier0_gpu_flags #375 tests and the run_prepare_host #377 tests both belong here; the non-nvidia test's closing brace had been swallowed by the ======= marker). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
LukasWodka
commented
Jul 23, 2026
bugbot run |
…all unprivileged (#1178) Adds the admin-only prepare-host path: installs the container runtime + prerequisites and grants a named non-admin user docker-group access, so they later install tracebloc at Tier 0 with no root. Rebased onto the current feat/lpi-tier0 (which now targets develop after routing #374 merged); collapsed from the prior 4-commit history to avoid replaying an intermediate that carried resolved conflict markers. Incorporates the three Bugbot fixes from that history: - reap the sudo keepalive on EXIT (no lingering background sudo -v loop); - grant docker-group ONLY to the explicit TB_PREPARE_USER, never $SUDO_USER (the admin who ran prepare-host); - only print the "researcher can now install with no admin" message when a docker-group grant actually succeeded. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
✅ 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 aedbc73. Configure here.
aedbc73 to
7a625b0Compare
divyasinghds
left a comment
There was a problem hiding this comment.
Approve. My earlier finding on the docker-group targeting is fully resolved:
local target="${TB_PREPARE_USER:-}"— the$SUDO_USERfallback is gone, with a comment explaining SUDO_USER is the admin, not the researcher.- New
grantedflag gates the closing message, so it no longer falsely promises "no administrator rights" when no grant happened (no TB_PREPARE_USER, or usermod failed) — that was a secondary half of the same problem, and it's handled. - Four new tests cover it, including one explicitly asserting SUDO_USER (the admin) is NOT added, and the usermod-fails path.
The rest still checks out: reuses the exact privileged install functions (no drift), terminal mode with the keepalive-reaping EXIT trap, non-Linux pointer. $OS is set at source time in common.sh so the guard is safe despite skipping run_preflight. CI green. LGTM.
* feat(cli): tracebloc prepare-host — one-time admin step wrapper (RFC 0001 #1178) Adds `tracebloc prepare-host`: a thin, discoverable wrapper that re-runs the official installer's verified prepare-host step (curl … | bash -s -- prepare-host), exactly like `tracebloc upgrade` delegates to the installer rather than re-implementing privileged host prep in the CLI. Registered in root; copy catalog gains 11-prepare-host.golden + the strings flow into zz-all-strings. build/vet/ staticcheck/deadcode clean; catalog no-drift; gofmt clean. Pairs with the client installer prepare-host step (tracebloc/client#377). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(cli): set -o pipefail in prepare-host so a curl failure is not swallowed (Bugbot #394) Without pipefail, `curl … | bash -s -- prepare-host` under `bash -c` exits 0 when curl fails (bash reads empty stdin), so the command reported success while prepare-host never ran. Prepend `set -o pipefail;` so curl's non-zero propagates and c.Run() surfaces the failure. Regression guard added. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * prepare-host: run installer pipeline in its own process group Cancelling the context (Ctrl-C / parent shutdown) previously killed only the top-level `bash -c`, leaving the `curl` and the `bash -s` prepare-host child -- which performs privileged host prep -- running detached after the CLI had already reported failure and exited (Bugbot #394). Extract prepareHostCmd(ctx): set SysProcAttr.Setpgid so the pipeline gets its own process group, and a Cancel that group-signals (kill -PGID SIGINT) so the whole pipeline stops when the user aborts. Add a test asserting Setpgid + Cancel are wired. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * prepare-host: run installer from a temp file, not a pipe (keep stdin on TTY) `curl | bash -s -- prepare-host` makes the inner bash read its *program* from the pipe, so the installer's stdin is no longer the terminal — any interactive prompt in prepare-host (e.g. which non-admin user gets runtime access) gets EOF (Bugbot #394, second finding). Switching to `bash <(curl …)` would fix stdin but reopen the FIRST #394 finding: process-substitution exit codes bypass pipefail, so a failed curl would silently run nothing. Instead download to a temp file under `set -e` (so a failed `curl -o` aborts) and run the file (stdin stays on the TTY). Best of both: fail-closed on download error AND interactive-capable. The manual-run hint shown on failure uses `bash <(curl …)` — the repo's recommended idiom — since a human re-running it keeps their own TTY. Add tests: fail-closed on download error (set -e + curl -o), and never pipe the script into bash. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * prepare-host: fix Windows build — move POSIX process-group logic behind build tags The process-group cancel added for Bugbot #394 used syscall.SysProcAttr.Setpgid and syscall.Kill(-pid, …), which are POSIX-only — the Windows build failed to compile (unknown field Setpgid; undefined syscall.Kill). Extract configureProcessGroup into build-tagged files: - prepare_host_unix.go (//go:build !windows): sets Setpgid + the group-killing Cancel (unchanged behavior on linux/darwin). - prepare_host_windows.go (//go:build windows): no-op — POSIX process groups don't exist there, and exec.CommandContext still kills the top-level process; prepare-host is a Linux host op regardless. Move the Setpgid assertion test into prepare_host_unix_test.go (also !windows-tagged) so `go test`/`go vet` compile on Windows too. Verified: `GOOS=windows go build/vet ./...` now pass for amd64 + arm64, and the native build/test/staticcheck stay green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * prepare-host: run in the foreground group, quiet interrupt on cancel (Bugbot #394) The process-group approach was wrong for an interactive command and Bugbot flagged five follow-ups: - Setpgid put the installer in its own (background) process group while stdin was the TTY, so any prepare-host prompt got SIGTTIN and hung (High). - the SIGINT-only Cancel with no WaitDelay could hang Wait forever if a privileged child ignored the signal, re-opening the orphaned-work risk. - a user Ctrl-C was wrapped as "prepare-host didn't complete — retry" instead of a quiet interrupt. Drop Setpgid and the custom Cancel entirely: keep the installer in the CLI's foreground process group so prompts work and a terminal Ctrl-C signals the whole pipeline (bash + curl + child) at once. Add WaitDelay=5s so a programmatic cancel can't hang Wait. Treat ctx cancel as exitInterrupted (130), matching the other cancellable paths. This also removes all syscall usage, so the Windows build no longer needs the build-tagged split (files deleted). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * prepare-host: reuse installCmd for the hint + robust interrupt detection (Bugbot #394) - prepareHostManualHint duplicated the bootstrap idiom owned by installCmd (doctor.go), so a URL/idiom change could leave the prepare-host fallback stale. Build it from installCmd + " prepare-host" (same value, one source). - Interrupt detection only checked ctx.Err() after c.Run(); on a terminal Ctrl-C the child dies (bash exits 130) and Run can return before NotifyContext flips ctx.Err(), so an abort was mis-reported as a failed install. Add prepareHostInterrupted(ctx, err): interrupt if ctx cancelled OR the run exited 130 (128+SIGINT). Unit-tested (cancelled ctx, exit 130, exit 1). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * prepare-host: accept a researcher username to grant docker-group access (Divya #377) prepare-host was cobra.NoArgs with no flag and no mention of TB_PREPARE_USER, so an admin had no discoverable way to name the researcher — the installer's docker-group grant (which reads TB_PREPARE_USER) was always skipped and the feature couldn't deliver Tier-0 access end-to-end. Add an optional positional arg: `tracebloc prepare-host <researcher-username>` (MaximumNArgs(1)). The username is validated (Linux-username shape) and passed to the installer via the TB_PREPARE_USER environment variable (not the command string, so it can't be shell-interpreted; the installer quotes it for usermod). Help text explains the arg and stresses it's the researcher, not the admin. Without it, prepare-host installs prereqs only and prints how to grant access. The client installer already grants ONLY TB_PREPARE_USER (never $SUDO_USER), so this closes the loop. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(cli): guard prepare-host on Windows (Bugbot #394) prepare-host shells out to bash/curl/mktemp and readies a Linux server / HPC login node (container runtime, docker group) — a Unix-only concept. On Windows it appeared in --help then failed with a cryptic missing-bash error and a Unix-only retry hint. It now stops early with a clear explanation (a no-op-with-message), mirroring upgrade's Windows handling. Adds a regression test for the OS guard. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: shujaat hasan <shujaathasan@shujaats-MacBook-Pro.local>
Uh oh!
There was an error while loading. Please reload this page.
…e admin (Bugbot) install_docker_engine's tail assumed the invoking user is the end-user: on the documented non-root prepare-host path it added the ADMIN to the docker group and the sg re-exec re-ran the script WITHOUT the prepare-host argument -- a silent FULL provision as the admin -- and a socket-less admin aborted before the TB_PREPARE_USER grant. In TB_PREPARE_HOST_MODE the daemon check runs via sudo, the group-add and re-exec are skipped, and only the researcher named by TB_PREPARE_USER is ever granted the socket (same least-privilege rule as #377). Two bats regressions pin both escapes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
LukasWodka
commented
Jul 25, 2026
Functional review — NOT passed, held deliberatelyI advanced 25 of the 29 items in Only 4 checks ran on this PR and none of them is behavioural — unlike its sibling installer PRs, which each ran the multi-distro |
… client) (#381) * feat(install): prepare-host — one-time admin step so researchers install unprivileged (#1178) Adds the admin-only prepare-host path: installs the container runtime + prerequisites and grants a named non-admin user docker-group access, so they later install tracebloc at Tier 0 with no root. Rebased onto the current feat/lpi-tier0 (which now targets develop after routing #374 merged); collapsed from the prior 4-commit history to avoid replaying an intermediate that carried resolved conflict markers. Incorporates the three Bugbot fixes from that history: - reap the sudo keepalive on EXIT (no lingering background sudo -v loop); - grant docker-group ONLY to the explicit TB_PREPARE_USER, never $SUDO_USER (the admin who ran prepare-host); - only print the "researcher can now install with no admin" message when a docker-group grant actually succeeded. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * prepare-host: sudo-verified engine gate; never sg-re-exec or grant the admin (Bugbot) install_docker_engine's tail assumed the invoking user is the end-user: on the documented non-root prepare-host path it added the ADMIN to the docker group and the sg re-exec re-ran the script WITHOUT the prepare-host argument -- a silent FULL provision as the admin -- and a socket-less admin aborted before the TB_PREPARE_USER grant. In TB_PREPARE_HOST_MODE the daemon check runs via sudo, the group-add and re-exec are skipped, and only the researcher named by TB_PREPARE_USER is ever granted the socket (same least-privilege rule as #377). Two bats regressions pin both escapes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(prepare-host): reach the sub-script on healthy machines + terminal active-daemon corner (Bugbot r2) Two follow-ups on the prepare-host re-land: - install.sh: prepare-host/--prepare-host now skip the healthy-install bailout — the argument is useful precisely on a machine that is already set up (grant ANOTHER researcher docker-group access), and the bailout would open the home screen and silently skip the TB_PREPARE_USER grant. It skips ONLY the bailout: the force flag is split out (_tb_force), so host-prep is never mislabeled as a forced reinstall — a stale sub-script without the prepare-host dispatch would otherwise treat the run as a full forced provision. - setup-linux.sh: in prepare-host mode, a daemon that systemd reports ACTIVE but that doesn't answer 'sudo docker info' is now terminal with prepare-host-appropriate guidance, instead of falling through to the docker-group 'log out and back in' abort meant for regular users. Regression tests: bootstrap bats stamps DEFAULT_REF like the release pipeline (assignment line only) to prove prepare-host passes the bailout with TB_FORCE_REINSTALL unset; setup-linux bats covers the active-but- unresponsive daemon corner. 16/16 + 58/58. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(prepare-host): terminal daemon-down path + trim TB_PREPARE_USER (Bugbot r3) - Daemon DOWN in prepare-host mode: start it via sudo (starting Docker IS host preparation), re-verify, and stay terminal in prepare-host wording on every failure — the shared diagnostics end with 're-run this installer', which for the admin means a full provision as themselves, the exact outcome prepare-host exists to prevent. Reboot-required case gets prepare-host wording too. - TB_PREPARE_USER is trimmed before the non-empty gate and the grant, so a pasted value with stray spaces doesn't fail usermod while skipping the honest no-grant messaging. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(prepare-host): dispatch at any argument position (Bugbot r4) install.sh's bailout exemption scans all of "$@" for prepare-host, but the sub-script only dispatched on $1 — so '--force prepare-host' skipped the bailout, exported the force flag, and then fell through into a FULL FORCED provision as the admin. The dispatch now scans every argument, matching the bootstrap's contract. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(prepare-host): enable docker on boot in the already-running path (Bugbot r5) Running NOW isn't host-prep: after a reboot the Tier-0 researcher can't start the daemon themselves. The success path now ensures docker.service is enabled on boot (best-effort), matching the fresh-install and daemon-down recovery paths. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(prepare-host): don't let diagnostics pipelines abort before the guidance (Bugbot r6) systemctl status exits 3 for an inactive unit (and the shared block's grep exits 1 on no match) — under set -e -o pipefail the failing diagnostics pipeline aborted BEFORE the terminal error message, a silent death with no re-run guidance. Both the prepare-host block and the shared daemon-down block now guard the pipeline with || true; the bats stub returns the real rc 3 to exercise the path. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…(Bugbot r2)
The sudo-refuse prepare-host remedy filled TB_PREPARE_USER=${SUDO_USER}, but SUDO_USER
is the ADMIN who ran sudo — the "setting up for someone else" case targets a DIFFERENT
researcher. Following it would grant the admin docker-group access and leave the
intended user locked out (the #377 least-privilege footgun). Use a
<researcher-username> placeholder and say "not yourself". Test updated to require the
placeholder and reject $SUDO_USER.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>…installs (#511) * fix(#427): grant docker group on any daemon run; refuse sudo-wrapped installs Two compounding identity bugs on Linux: 1. The docker-group grant ran ONLY inside the fresh-Docker-install branch. On a box where Docker was already present and the user wasn't in the group, the else-branch printed "Docker" without granting, and the recovery path dead-ended at "Could not connect to Docker. Try logging out and back in…" — which couldn't help, because membership was never granted. Re-runs looped on the same message. Fix: after the install/else, ensure the invoking user is in the docker group whenever the daemon path is chosen, regardless of a fresh install. Skip if already a member (no redundant usermod); prepare-host stays exempt (only TB_PREPARE_USER is granted, later — least-privilege, #381). The existing sg-docker re-exec then activates the new membership in-session, so no dead-end loop. 2. Nothing was SUDO_USER-aware: `sudo bash install.sh` ran the WHOLE provision as root — usermod granted root (not the user), and ~/.tracebloc, ~/.kube/config, and the chmod-600 credential landed root-owned under /root, with no chown anywhere to undo it. The installer's model is to run as the daily user and elevate per-step (RFC-0002), so rather than a fragile ownership remap, refuse the sudo-wrapped full run early (before any file is created): refuse_sudo_wrapped_install errors when EUID 0 AND $SUDO_USER is a real (non-root) user. Exemptions: a genuine root login (no SUDO_USER); prepare-host (the admin path, already dispatched+exited in main()). Because we never run as root-with-SUDO_USER, every $HOME/$USER path in the tree stays correct with no remap. Also: honor TB_PREPARE_USER as the grant target in the main install (new _real_install_user helper; the #418 Windows peer). Tests: install_docker_engine grants on the pre-installed path + when only TB_PREPARE_USER differs, skips when already a member, never grants the admin in prepare-host, still grants on a fresh install; refuse_sudo_wrapped_install refuses sudo+SUDO_USER but allows root-login / sudo -i / non-root; _real_install_user. Closes#427 * fix(#427): grant the invoking user (not TB_PREPARE_USER); name TB_PREPARE_USER in the refuse hint Bugbot: - The main-install docker-group grant targeted _real_install_user (TB_PREPARE_USER when set), but socket access and the sg-docker re-exec key off $USER. When they differ (e.g. a leftover `export TB_PREPARE_USER=` from prepare-host), the invoking user never got membership and hit the same dead-end this PR fixes. Grant $USER directly — the sudo-wrapped run is already refused, so $USER is the real daily user — and keep TB_PREPARE_USER on the prepare-host path only (where it's granted). Removed the now-unused _real_install_user helper + its tests. - The sudo-refuse hint pointed admins at a BARE `prepare-host`, but run_prepare_host only grants when TB_PREPARE_USER is set — so that remedy prepares the daemon and grants nobody. Name it: `export TB_PREPARE_USER=<user> && … prepare-host`. Tests: the grant targets $USER even with a leftover TB_PREPARE_USER; the refuse hint includes TB_PREPARE_USER=<user>. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(#427): refuse hint names a RESEARCHER placeholder, not the admin (Bugbot r2) The sudo-refuse prepare-host remedy filled TB_PREPARE_USER=${SUDO_USER}, but SUDO_USER is the ADMIN who ran sudo — the "setting up for someone else" case targets a DIFFERENT researcher. Following it would grant the admin docker-group access and leave the intended user locked out (the #377 least-privilege footgun). Use a <researcher-username> placeholder and say "not yourself". Test updated to require the placeholder and reject $SUDO_USER. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(#427): key the sg-docker re-exec off _grant_user, consistent with the grant (reviewer) The grant resolved its target with a `${USER:-$(id -un)}` fallback, but the in-session sg-docker re-exec guard still keyed off bare `$USER`. In the exact USER-unset case the fallback exists for, the grant landed on `$(id -un)` while that guard saw an empty `$USER`, skipped the re-exec, and re-introduced the "log out and back in" dead-end. Hoist _grant_user to the top of install_docker_engine and use it in both places so they can't disagree. Guard test added. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

What (#1178 — prepare-host, client side)
The standalone, admin-run Tier-2 step. An administrator runs it once on a host a researcher can't install on unprivileged; afterwards the researcher installs at Tier 0 with no admin.
curl -fsSL https://tracebloc.io/i.sh | bash -s -- prepare-host(the bootstrap already forwards"$@"toinstall-k8s.sh, so no bootstrap change was needed) or, later,tracebloc prepare-host.run_prepare_hostdoes only the privileged prerequisites, reusing the exact functions the full install uses:preflight_sudo+install_docker_engine+install_system_deps. It then grants the researcher (SUDO_USER, orTB_PREPARE_USER) docker-group access — so their later install is Tier 0.main()(mirrors--diagnose). Non-Linux gets a Docker-Desktop / WSL2 pointer.Tests
setup-linux.bats: installs the runtime prereqs + adds the researcher to the docker group (and does not create a cluster / install the CLI); best-effort when there's no target user; non-Linux errors with the right pointer.Scope
Client half of #1178. The
clitracebloc prepare-hostsubcommand (a thin wrapper that runs… | bash -s -- prepare-host, liketracebloc upgrade) is a separate cli PR. The rootless/userns-enable nuance for hosts that need Tier 1 lives with #1177.Stack
Stacked on #1175 → #1172 → #1171. Base is
feat/lpi-tier0; merge in order.Part of the least-privilege install epic (#1168), Wave 2.
Part of tracebloc/backend#1178 (client half; cli half to follow).
🤖 Generated with Claude Code
Note
Medium Risk
Runs privileged package/Docker setup and
usermodon shared hosts; behavior is narrowed to an explicit admin step with guarded messaging and tests, but mis-setTB_PREPARE_USERcould still leave researchers without socket access until fixed manually.Overview
Adds a one-time administrator path so shared Linux hosts can be prepped without running the full tracebloc install as the admin.
prepare-host/--prepare-hostis a terminal mode ininstall-k8s.sh(like--diagnose): it skips provisioning, cluster creation, and CLI install, uses a lightweight EXIT trap to stop the sudo keepalive from orphaning (#377), and callsrun_prepare_hostinsetup-linux.sh.run_prepare_hostruns the same privileged pieces as a full install (preflight_sudo, Docker engine, system deps) and optionally adds a named researcher to thedockergroup viaTB_PREPARE_USERonly—no fallback toSUDO_USER(#377). Success text promises a no-admin install only whenusermodactually succeeded.Five new
setup-linux.batscases cover happy path, missing user, failed grant, admin-not-granted, and non-Linux.manifest.sha256is updated for the touched scripts.Reviewed by Cursor Bugbot for commit 7a625b0. Bugbot is set up for automated code reviews on this repo. Configure here.