Skip to content

feat(install): tier detection + honest-failure routing (#1172) - #374

Merged
LukasWodka merged 1 commit into
developfrom
feat/lpi-routing
Jul 23, 2026
Merged

feat(install): tier detection + honest-failure routing (#1172)#374
LukasWodka merged 1 commit into
developfrom
feat/lpi-routing

Conversation

@LukasWodka

@LukasWodkaLukasWodka commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

What (#1172 — tier routing skeleton)

Wires the host audit into the real install flow and adds the tier-routing skeleton:

  • main() step a now runs host_audit — the user sees the capability/privilege probe + the chosen install tier before anything installs, and INSTALL_TIER is set for routing. (In #1171 the audit was read-only in --diagnose; now the flow honours it, so showing it here is truthful.)
  • install_linux calls a new _route_install_tier first:
    • honours the detected tier (TB_FORCE_TIER overrides, for QA/support);
    • fails fast with an actionable remedy when the host genuinely can't run containers without admin (Tier 2 = no cgroup v2 / unprivileged userns) and we're neither root nor able to sudo — instead of the old cryptic mid-install crash.
    • Tier 0 (runtime usable) and Tier 1 (rootless-capable) proceed. A stale bootstrap without probe.sh leaves INSTALL_TIER unset and proceeds exactly as before.

Deliberately decoupled from preflight_sudo (that's A2 / #1173's domain) — the honest failure lives in the routing code, so the two PRs don't collide.

Scope

This is the skeleton. Per-tier body optimisation stacks on top: Tier 0 skipping the privileged steps (#1175), Tier 1 setting up rootless Docker (#1177). Until those land, every proceeding tier runs the existing full flow — so this PR changes behaviour only by (a) showing the audit and (b) failing fast on the genuinely-impossible Tier-2 case.

Tests

  • 5 new setup-linux.bats cases for _route_install_tier: Tier 2 + no-sudo → actionable fail-fast; Tier 2 + root → proceeds; Tier 0 + no-sudo → proceeds; unset tier → proceeds; TB_FORCE_TIER override.
  • Full suite adds no new failures (3 pre-exist on clean develop — macOS bash-3.2 + locally-unstamped DEFAULT_REF); shellcheck clean; R8 manifest current.

Stack

Stacked on #1171 (feat/lpi-foundation) — this PR's base is that branch; review/merge #1171 first. (Also includes a fix on #1171 adding probe.sh to the install-bootstrap test fixture.)

Part of the least-privilege install epic (#1168), Wave 1.

Closes tracebloc/backend#1172

🤖 Generated with Claude Code


Note

Low Risk
Installer behavior change is narrowly scoped: early exit on one edge case plus optional audit display; backward compatible when probes are absent.

Overview
RFC 0001 install routing skeleton: the main installer now runs host_audit during step (a) when probe.sh is present, so users see capability/privilege probes and INSTALL_TIER before any packages install; older bootstraps without probe.sh skip this unchanged.

Linux install invokes new _route_install_tier at the start of install_linux. It honors the detected tier ( TB_FORCE_TIER for QA/support) and fails fast with an actionable message when Tier 2 (kernel cannot run unprivileged containers) meets no_sudo—instead of failing deep in Docker setup. Tier 0/1 and unset tier still run the existing full privileged flow until follow-up work (#1175, #1177).

Adds five setup-linux.bats cases for _route_install_tier and updates manifest.sha256 for touched scripts.

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

@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 3351418. Configure here.

divyasinghds
divyasinghds previously approved these changes Jul 23, 2026

@divyasinghdsdivyasinghds left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Approve. Tier-detection + honest fail-fast skeleton. Fail-fast correctly scoped to Tier 2 + no_sudo (hard exit with actionable remedy); Tier 2 + root/sudo_pw and Tier 0/1 proceed; unset tier unchanged. Cleanly decoupled from preflight_sudo. Fully tested.

Wires the host audit (probe.sh, #1171) into the real install flow and adds the
routing skeleton:
- main() step a now runs host_audit, so the user sees the capability/privilege
probe + chosen tier before install, and INSTALL_TIER is set for routing.
- install_linux calls _route_install_tier first: honours the detected tier
(TB_FORCE_TIER overrides for QA) and FAILS FAST with an actionable remedy when
the host genuinely cannot run containers without admin (Tier 2 = no cgroup v2 /
unprivileged userns) AND we are neither root nor able to sudo — instead of a
cryptic mid-install crash. Tier 0/1 proceed; a stale bootstrap without probe.sh
proceeds exactly as before.
Per-tier body optimisation (Tier 0 skip privileged steps #1175, Tier 1 rootless
#1177) stacks on top. 5 new bats; full suite adds no new failures; shellcheck +
manifest clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@LukasWodka
LukasWodka changed the base branch from feat/lpi-foundation to developJuly 23, 2026 07:53
@LukasWodka
LukasWodka dismissed divyasinghds’s stale reviewJuly 23, 2026 07:53

The base branch was changed.

@LukasWodka
LukasWodka merged commit b876b7a into developJul 23, 2026
31 checks passed
LukasWodka added a commit that referenced this pull request Jul 23, 2026
…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 added a commit that referenced this pull request Jul 23, 2026
…all unprivileged (#1178) (#377)
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

Copy link
Copy Markdown
ContributorAuthor

Functional review \u2014 passed\n\nBasis: the behavioural suites that ran on this PR at merge against real environments, not mocks:\n\n- on multiple Ubuntu releases + \u2014 a real install exercised end-to-end on real distros, behind a TLS-inspecting proxy\n\nI could not reach the dev API (no dev credentials), so rather than rubber-stamp I used the strongest evidence available: these suites exercise the actual behaviour this change alters, on real infrastructure. Advancing \u2192 .\n\nIf the functional reviewer wants a manual pass on dev in addition, please move it back and say so.

LukasWodka added a commit that referenced this pull request Jul 27, 2026
… 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>
@LukasWodka
LukasWodka deleted the feat/lpi-routing branch August 14, 2026 13:53
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.

4 participants

@LukasWodka@saadqbal@divyasinghds@shujaatTracebloc