Uh oh!
There was an error while loading. Please reload this page.
feat(install): prepare-host admin step — re-land onto develop (#1178, client) - #381
Conversation
…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>
LukasWodka
commented
Jul 23, 2026
bugbot run |
Uh oh!
There was an error while loading. Please reload this page.
# Conflicts: # scripts/manifest.sha256
…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 24, 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.
…l 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>
LukasWodka
commented
Jul 24, 2026
e578a31 addresses both Bugbot Mediums:
Regression tests for both: the bootstrap suite stamps |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
…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>
Uh oh!
There was an error while loading. Please reload this page.
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>
Uh oh!
There was an error while loading. Please reload this page.
…(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>
LukasWodka
commented
Jul 24, 2026
@cursor review |
Uh oh!
There was an error while loading. Please reload this page.
…uidance (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>
LukasWodka
commented
Jul 24, 2026
@cursor review |
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 ad6ae2a. Configure here.
divyasinghds
left a comment
There was a problem hiding this comment.
Approve. A clean cherry-pick of the already-reviewed-and-approved #377 onto develop (only manifest.sha256 regenerated), re-landed because #377 merged into a dead-end branch.
- The
install.shrefactor decoupling_tb_forcefrom_tb_bail_okis correct: prepare-host skips the healthy bailout without exportingTB_FORCE_REINSTALL, while--force/--reinstall/REF/BRANCHstill set both — no regression (the new test assertsTB_FORCE_REINSTALL=unset). - Least-privilege holds: prepare-host mode never grants the socket to the invoking admin or
sg-re-execs (which would silently become a full provision), grants only an explicitTB_PREPARE_USER(never$SUDO_USER), trims the username before the grant, and stays terminal in prepare-host wording on every Docker failure path. The|| trueguards on the diagnostic pipelines correctly prevent aset -edeath before the guidance prints.
Reviewed with Claude Code.
LukasWodka
commented
Jul 27, 2026
bugbot run |
aptracebloc
left a comment
There was a problem hiding this comment.
Approving — re-land of the already-approved #377 prepare-host work, and I re-verified the security-critical part.
run_prepare_host grants docker-group access (root-equivalent) only to an explicitly-named TB_PREPARE_USER — it deliberately does NOT fall back to $SUDO_USER (the admin who ran prepare-host), whitespace-trims the value, refuses empty/root, sets granted=1 only on a successful usermod, and only makes the "no-admin install" promise when a grant actually happened. That's the right shape for a privileged grant — no auto-granting root-equivalent access to the wrong user. 8 Bugbot findings resolved, CI green.
One caveat that gates the merge (not the approval): the branch was CONFLICTING with develop — develop advanced and touched setup-linux.sh, setup-linux.bats, and manifest.sha256, which this branch also changes. The manifest conflict is mechanical, but setup-linux.sh is the security-critical file, so the conflict resolution there is worth a re-check before/at merge (I verified the pre-rebase state; a merge could shift run_prepare_host). If it's already been resolved and merged, all the better — just flagging in case the resolution touched that function.
— drafted with Claude (Opus 4.8), sent by @aptracebloc
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 ad6ae2a. Configure here.
LukasWodka
commented
Jul 27, 2026
bugbot run |
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 ff2a3d2. Configure here.
Uh oh!
There was an error while loading. Please reload this page.
…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>
Re-land: prepare-host client half onto
developtracebloc/backend#1178(client half). This re-targets the prepare-host work that was previously reviewed + approved in #377.Why this PR exists:#377 was merged, but into its stacked base
feat/lpi-tier0rather thandevelop. That branch had already reached develop via #375's squash-merge, so it's a dead end —run_prepare_hostnever actually landed ondevelop. This PR puts the exact same (approved) commit on top of currentdevelopso it ships.Contents (identical to the approved #377 change — a clean cherry-pick, only the generated
manifest.sha256regenerated for develop):scripts/lib/setup-linux.sh—run_prepare_host(installs runtime + prereqs; grants docker-group access only to an explicitTB_PREPARE_USER, never$SUDO_USER; message gated on an actual grant).scripts/install-k8s.sh—prepare-hostmode routing.scripts/tests/setup-linux.bats— the run_prepare_host tests.scripts/manifest.sha256— regenerated.Pairs with the already-merged CLI half
tracebloc/cli#394(tracebloc prepare-host <researcher-username>).Test plan
shellcheck --severity=errorclean on the touched scripts.gen-manifest.sh --checkclean.bats scripts/tests/*.bats— only the 3 pre-existing macOS baseline failures (validate_config valid / un-stamped DEFAULT_REF / _extract_yaml_value single-quoted).🤖 Generated with Claude Code
Note
Medium Risk
Changes privileged installer/bootstrap behavior (sudo, docker group, early exit paths) on shared hosts; scope is limited to the new prepare-host flow with extensive bats coverage and no cluster/credential provisioning in that mode.
Overview
Adds
prepare-hostas a one-time, admin-only installer path so a shared Linux host can get Docker and system deps without provisioning tracebloc as the admin. Researchers named viaTB_PREPARE_USER(never$SUDO_USER) receive docker-group access; messaging only promises a no-admin install when that grant succeeds.Routing:
install-k8s.shtreatsprepare-host/--prepare-hostas terminal (like--diagnose), including when mixed with flags such as--force, and runsrun_prepare_hostwith a lightweight EXIT trap so sudo keepalive is torn down.install.shstill bypasses the healthytracebloc doctorbailout for prepare-host, but no longer exportsTB_FORCE_REINSTALLfor that case (only true force/reinstall/pinned-ref paths do).Docker under prep:
install_docker_enginehonorsTB_PREPARE_HOST_MODE: verify/start the daemon withsudo, skip adding the admin to the docker group, blocksg dockerre-exec (which would drop args and run a full install), and use prepare-host-specific error text instead of “log out and back in” / “re-run this installer”. Diagnosticsystemctlpipelines gain|| truesoset -ecannot exit before guidance prints.Bats cover bootstrap bailout vs force propagation and prepare-host Docker/grant behavior;
manifest.sha256is updated for the touched scripts.Reviewed by Cursor Bugbot for commit ff2a3d2. Bugbot is set up for automated code reviews on this repo. Configure here.