allod: read the repository registry through INVENTORY, falling back to the public path #218

Merged
vnprc merged 2 commits from agent/registry-honors-inventory into master 2026-09-19 14:45:49 +01:00
Member

Nothing changes on any machine until the deployment moves its allod-tools pin. After that, on a host where INVENTORY is set (nexus renders it from nexus.provisioning.inventoryCheckout), allod secret and allod patch read the repository registry from that inventory's scripts/repositories.json, so a private deployment's secrets and deploy checkouts resolve to where its own registry says they are instead of to the public template paths. With INVENTORY unset, nothing changes: the registry is still ~/work/allod/inventory/scripts/repositories.json. No new variable is introduced; the one pointer the host already declares now reaches every consumer. Proof is five new tests over fixture registries plus the full test suites under every tag set, and one cold review by a model that did not write it. If it is wrong, revert and move the pin back; the symptom would be a checkout resolving somewhere unexpected, and every command names the path it resolved before acting.

What changes

  • cmd/allod/registry.go: registryCheckout reads registryPath(), which is $INVENTORY/scripts/repositories.json when INVENTORY is set and the old literal path otherwise. It deliberately does not call inventoryCheckout, which falls back to the registry for the inventory alias and would recurse. The trailing-slash and root handling both readers need lives in one helper, trimmedInventory.
  • cmd/allod/secret_common.go: inventoryCheckout uses that helper instead of its own copy. secretsCheckoutRelative and deployCheckoutRelative are untouched and inherit the fix through registryCheckout, as does allod patch's registry-id resolution.
  • cmd/allod/registry_test.go (new, untagged): INVENTORY wins over a differing registry under WORK_DIR; the WORK_DIR registry is read when INVENTORY is unset; an INVENTORY with no registry behind it yields not-found and the allod/secrets and allod/deploy fallbacks rather than a silent read of the public registry; a trailing slash resolves the same; inventoryCheckout returns through the registry fallback without recursing; and the trailing-slash test asserts on inventoryCheckout's bare return, which fails if trimming is removed (checked by the worker with the trim disabled).
  • docs/allod-secret.md and docs/allod-patch.md state where the registry is found.

Risk

R2: one file-location decision changed, with the old behaviour preserved when the variable is unset; every consumer goes through the one reader; rollback is a revert. The residual case is an INVENTORY that points somewhere without a registry, which now resolves to the conventional fallback names rather than the public registry; the resolved path appears in the command's own refusal.

Validation

Run by the overseer in the worktree on the committed tree (bad432c, two commits):

command last line exit
nix develop -c gofmt -l . no output 0
nix develop -c go vet ./... no output 0
nix develop -c go test ./... ok forge.anarch.diy/allod/tools/internal/gitremote 0.125s 0
nix develop -c go test -tags site ./... ok forge.anarch.diy/allod/tools/internal/gitremote 0.130s 0
nix develop -c go test -tags secret ./... ok forge.anarch.diy/allod/tools/internal/gitremote 0.148s 0
nix develop -c go test -tags site,secret ./... ok forge.anarch.diy/allod/tools/internal/gitremote 0.119s 0
git diff --check no output 0

One cold review, per the R2 budget, by gpt-5.5 at effort high through codex reading a .git-free snapshot of the first commit: no blocker, high, or medium; two lows, both verified and fixed in the second commit: the trailing-slash test could not fail because filepath.Join absorbed the slash, and the docs named ~/work where the code honors WORK_DIR. The second commit is a test and two doc sentences, verified by reading and by the suite.

Not run: a live allod secret rotate on the host with INVENTORY set; that is the first thing to run after the pin moves, as --dry-run, and it should name the private checkout in its output.

Closes allod/tools#217
Refs allod/nexus#52

Nothing changes on any machine until the deployment moves its `allod-tools` pin. After that, on a host where `INVENTORY` is set (nexus renders it from `nexus.provisioning.inventoryCheckout`), `allod secret` and `allod patch` read the repository registry from that inventory's `scripts/repositories.json`, so a private deployment's `secrets` and `deploy` checkouts resolve to where its own registry says they are instead of to the public template paths. With `INVENTORY` unset, nothing changes: the registry is still `~/work/allod/inventory/scripts/repositories.json`. No new variable is introduced; the one pointer the host already declares now reaches every consumer. Proof is five new tests over fixture registries plus the full test suites under every tag set, and one cold review by a model that did not write it. If it is wrong, revert and move the pin back; the symptom would be a checkout resolving somewhere unexpected, and every command names the path it resolved before acting. ## What changes - `cmd/allod/registry.go`: `registryCheckout` reads `registryPath()`, which is `$INVENTORY/scripts/repositories.json` when `INVENTORY` is set and the old literal path otherwise. It deliberately does not call `inventoryCheckout`, which falls back to the registry for the inventory alias and would recurse. The trailing-slash and root handling both readers need lives in one helper, `trimmedInventory`. - `cmd/allod/secret_common.go`: `inventoryCheckout` uses that helper instead of its own copy. `secretsCheckoutRelative` and `deployCheckoutRelative` are untouched and inherit the fix through `registryCheckout`, as does `allod patch`'s registry-id resolution. - `cmd/allod/registry_test.go` (new, untagged): `INVENTORY` wins over a differing registry under `WORK_DIR`; the `WORK_DIR` registry is read when `INVENTORY` is unset; an `INVENTORY` with no registry behind it yields not-found and the `allod/secrets` and `allod/deploy` fallbacks rather than a silent read of the public registry; a trailing slash resolves the same; `inventoryCheckout` returns through the registry fallback without recursing; and the trailing-slash test asserts on `inventoryCheckout`'s bare return, which fails if trimming is removed (checked by the worker with the trim disabled). - `docs/allod-secret.md` and `docs/allod-patch.md` state where the registry is found. ## Risk R2: one file-location decision changed, with the old behaviour preserved when the variable is unset; every consumer goes through the one reader; rollback is a revert. The residual case is an `INVENTORY` that points somewhere without a registry, which now resolves to the conventional fallback names rather than the public registry; the resolved path appears in the command's own refusal. ## Validation Run by the overseer in the worktree on the committed tree (`bad432c`, two commits): | command | last line | exit | |---|---|---| | `nix develop -c gofmt -l .` | no output | 0 | | `nix develop -c go vet ./...` | no output | 0 | | `nix develop -c go test ./...` | `ok forge.anarch.diy/allod/tools/internal/gitremote 0.125s` | 0 | | `nix develop -c go test -tags site ./...` | `ok forge.anarch.diy/allod/tools/internal/gitremote 0.130s` | 0 | | `nix develop -c go test -tags secret ./...` | `ok forge.anarch.diy/allod/tools/internal/gitremote 0.148s` | 0 | | `nix develop -c go test -tags site,secret ./...` | `ok forge.anarch.diy/allod/tools/internal/gitremote 0.119s` | 0 | | `git diff --check` | no output | 0 | One cold review, per the R2 budget, by `gpt-5.5` at effort high through codex reading a `.git`-free snapshot of the first commit: no blocker, high, or medium; two lows, both verified and fixed in the second commit: the trailing-slash test could not fail because `filepath.Join` absorbed the slash, and the docs named `~/work` where the code honors `WORK_DIR`. The second commit is a test and two doc sentences, verified by reading and by the suite. Not run: a live `allod secret rotate` on the host with `INVENTORY` set; that is the first thing to run after the pin moves, as `--dry-run`, and it should name the private checkout in its output. Closes allod/tools#217 Refs allod/nexus#52
allod secret rotate and the other secret/patch commands read the
repository registry from a literal ~/work/allod/inventory checkout, so
on a private deployment the reader found the public template's
registry instead of the operator's own, pointing secret rotate at the
wrong secrets checkout and printing deploy steps against the wrong
composition root.

registryCheckout now reads $INVENTORY/scripts/repositories.json when
INVENTORY is set (the same variable nexus.provisioning.inventoryCheckout
renders into the session, and every other nexus script already
resolves the registry through), falling back to the conventional
~/work/allod/inventory/scripts/repositories.json otherwise. Every
consumer of registryCheckout inherits this: secret's secrets, deploy,
and inventory resolution, and patch's registry-id resolution. The
INVENTORY trimming (trailing slash, root special-case) is shared
between the new registryPath and the existing inventoryCheckout
through one helper instead of duplicated, and the reader does not call
inventoryCheckout, which would recurse back into it.

Refs allod/tools#217
The trailing-slash test asserted through registryPath's filepath.Join,
which absorbs an untrimmed slash on its own, so the test could not
have caught trimmedInventory failing to trim; it now asserts on
inventoryCheckout's bare return, which is exactly trimmedInventory's
output, for a single slash and for a root form of "///".

The two docs described the untagged fallback path as literally
~/work/allod/inventory/scripts/repositories.json, but the code joins
onto the work directory, which WORK_DIR can override; both now say the
fallback is allod/inventory/scripts/repositories.json under the work
directory (~/work, or WORK_DIR when set).

Refs allod/tools#217
vnprc approved these changes 2026-09-19 14:45:43 +01:00
vnprc merged commit bad432c642 into master 2026-09-19 14:45:49 +01:00
vnprc deleted branch agent/registry-honors-inventory 2026-09-19 14:45:49 +01:00
Sign in to join this conversation.
No description provided.