Give the privileged tier a working v1 to v2 path, and link the upgrade docs #22

Merged
branderson merged 2 commits from upgrade-path-privileged into main 2026-08-27 21:00:17 -07:00
Collaborator

Summary generated by LLM agent

Two findings, both from reading the upgrade path as an operator on a specific box rather than from testing.

The privileged tier had no working v1 → v2 path

upgrades/0002's "record it properly" block was confined-shaped:

sudo ./install.sh                        # does not run on a privileged host
sudo dejima-ci-upgrade set-tier confined # only works because install.sh just ran

install.sh does not run on a privileged host — that is the grant the tier exists for — so the tool is never installed and the two bare invocations fail with exactly the error that started this thread: the tool reporting it cannot find itself.

#21 added a section telling privileged operators to run from ./bin/, but that is the ephemeral path. The persist path — the one that survives a rollback — had no privileged form at all.

There is now a block per tier. Confined keeps install.sh. Privileged gets the three install commands dejima-ci-bootstrap uses, because bootstrap is the only thing that installs the tool on that tier and re-running it on a built machine also redoes runner setup — a real cost on a machine that is already serving.

Those three lines duplicate bootstrap's and can drift from it, so a test pins both ends to the same destinations. A tool installed to the wrong path is a tool that is not there, reported three sections later as "not installed here", which is how this whole thread started.

The upgrade docs were not linked from the README at all

Only docs/README.md mentioned them. An operator with a running box had no path from the front page to the flow.

There is now an Updating an existing runner section carrying what is actually needed:

  • the command to check what version the box is at;
  • the instruction to walk the notes in order, because each assumes the one before;
  • run it from a checkout, not the installed copy — which knows only the versions that existed when it was installed, and on a privileged host may not exist at all;
  • recording a version is itself a guest-side change, thrown away at the next rollback unless baked into the snapshot. The console work is not: hypervisor rules are in force either way.

The intro points at it where someone skimming will be, and so do the runbook and the docs index. Both runbooks now say at the top that they build a runner rather than update one — that is the page you land on when you come back to change a rule.

Tested

bats test/ — 136 passing, 1 new: that the hand-install recipe in v2 and the privileged branch of bootstrap name the same destinations.

Method note

This is the fourth bug in the same seam, and every one was found by reading the path as an operator on a specific box rather than by a test. My audit of the sister project's stack last round reported "tooling availability is fine" — and it was, because that project's v2 runs bootstrap. I did not re-run the same audit against this project's privileged tier, where the equivalent step does not exist.

The general shape: the upgrade tooling keeps assuming it is already installed, and the tests cannot catch it because they run in a checkout where everything is present.

**Summary generated by LLM agent** Two findings, both from reading the upgrade path as an operator on a specific box rather than from testing. ## The privileged tier had no working v1 → v2 path `upgrades/0002`'s "record it properly" block was confined-shaped: ```sh sudo ./install.sh # does not run on a privileged host sudo dejima-ci-upgrade set-tier confined # only works because install.sh just ran ``` `install.sh` does not run on a privileged host — that is the grant the tier exists for — so the tool is never installed and the two bare invocations fail with **exactly the error that started this thread**: the tool reporting it cannot find itself. [#21](https://gitbox.branderson.io/dejima/dejima-ci-hardener/pulls/21) added a section telling privileged operators to run from `./bin/`, but that is the *ephemeral* path. The **persist** path — the one that survives a rollback — had no privileged form at all. There is now a block per tier. Confined keeps `install.sh`. Privileged gets the three install commands `dejima-ci-bootstrap` uses, because bootstrap is the only thing that installs the tool on that tier and **re-running it on a built machine also redoes runner setup** — a real cost on a machine that is already serving. Those three lines duplicate bootstrap's and can drift from it, so a test pins both ends to the same destinations. A tool installed to the wrong path is a tool that is not there, reported three sections later as "not installed here", which is how this whole thread started. ## The upgrade docs were not linked from the README at all Only `docs/README.md` mentioned them. An operator with a running box had no path from the front page to the flow. There is now an **Updating an existing runner** section carrying what is actually needed: - the command to check what version the box is at; - the instruction to **walk the notes in order**, because each assumes the one before; - run it from a checkout, not the installed copy — which knows only the versions that existed when it was installed, and on a privileged host may not exist at all; - recording a version is **itself a guest-side change**, thrown away at the next rollback unless baked into the snapshot. The console work is not: hypervisor rules are in force either way. The intro points at it where someone skimming will be, and so do the runbook and the docs index. Both runbooks now say at the top that they *build* a runner rather than update one — that is the page you land on when you come back to change a rule. ## Tested `bats test/` — 136 passing, 1 new: that the hand-install recipe in v2 and the privileged branch of bootstrap name the same destinations. ## Method note This is the fourth bug in the same seam, and every one was found by reading the path as an operator on a specific box rather than by a test. My audit of the sister project's stack last round reported "tooling availability is fine" — and it was, because that project's v2 runs bootstrap. I did not re-run the same audit against this project's privileged tier, where the equivalent step does not exist. The general shape: **the upgrade tooling keeps assuming it is already installed**, and the tests cannot catch it because they run in a checkout where everything is present.
dejima-agent added 1 commit 2026-08-27 20:29:07 -07:00
Give the privileged tier a working v1 -> v2 path, and link the upgrade docs
tests / runner-env (confined) (pull_request_target) Successful in 43s
tests / runner-env (privileged) (pull_request_target) Successful in 41s
tests / tests (pull_request_target) Successful in 1m28s
tests / compose-schema (pull_request_target) Successful in 50s
f6316e6c0e
Two findings, both from reading the path rather than the code.

THE "RECORD IT PROPERLY" BLOCK WAS CONFINED-SHAPED. It ran install.sh - which
does not run on a privileged host, deliberately - and then invoked
dejima-ci-upgrade bare, which only works because install.sh had just put it
there. A privileged operator following it got exactly the error that started
this: the tool reporting it could not find itself.

There is now a block per tier. Confined keeps install.sh. Privileged gets the
three install commands bootstrap uses, because bootstrap is the only thing
that installs the tool on that tier and re-running it on a built machine also
redoes runner setup - a real cost for a machine that is already serving.

Those three duplicate bootstrap's lines and can drift from them, so a test
pins both ends to the same destinations. A tool installed to the wrong path
is a tool that is not there, reported three sections later as "not installed
here", which is how this whole thread started.

THE UPGRADE DOCS WERE NOT LINKED FROM THE README AT ALL. Only docs/README.md
mentioned them, so an operator with an existing runner had no path from the
front page to the flow. There is now an "Updating an existing runner" section
with the command to check a version, the instruction to walk the notes in
order, and the two things a runner operator needs before starting: run from a
checkout, and recording is itself a guest-side change. The runbook and the
docs index point at it, and so does the intro, where someone skimming will be.

`bats test/` 136 passing, 1 new.
dejima-agent added 1 commit 2026-08-27 20:47:48 -07:00
Do not assume /usr/local/sbin is on the PATH sudo hands you
tests / runner-env (confined) (pull_request_target) Successful in 45s
tests / tests (pull_request_target) Successful in 1m29s
tests / compose-schema (pull_request_target) Successful in 51s
tests / runner-env (privileged) (pull_request_target) Successful in 41s
5d61050f87
Reported from a real box: after the install commands in v2's privileged
block, `sudo dejima-ci-upgrade set-tier privileged` was not found.

Everything installs to /usr/local/sbin and every instruction in this
repository reads `sudo dejima-ci-...`. That works only where sudoers sets a
secure_path including sbin. Without one, sudo inherits the caller's PATH -
and Debian leaves every sbin directory off a non-root PATH, which is exactly
what the reporting operator's PATH showed. The result is a correct install
whose documented commands all report "command not found", read as a broken
install rather than as a PATH.

Nothing checked it, in either project. install.sh reported what it wrote;
whether anything could find it afterwards was never asked.

install.sh and the privileged branch of bootstrap now check and say so. The
check is honest rather than a proxy: both run under sudo, so their own PATH
is the one the operator's later sudo commands will get, which makes
`command -v` there the real question.

v2's install blocks use the full path for the commands immediately after an
install, on both tiers, because that is where the problem bites and where
naming the path costs nothing. The note also says how to tell which case you
are in, since `sudo printenv PATH` answers it and `sudo echo $PATH` does not -
the shell expands that one before sudo runs, so it prints the caller's PATH
and looks like an answer.

`bats test/` 136 passing.
branderson approved these changes 2026-08-27 21:00:12 -07:00
branderson merged commit 665113be51 into main 2026-08-27 21:00:17 -07:00
Sign in to join this conversation.