Skip to content

Grant lifecycle: revive the dead sudoers API, delete the parallel one, and track the grants nobody owns #601

Description

@chubes4

Follow-up to #599, which asked whether a privilege wrapper belongs here or in Homeboy. Building one (Extra-Chill/homeboy#14726) surfaced the real answer: the wrapper was never the hard part. The grant is, and nothing owns it.

1. Most grants on a provisioned host are untracked

Census of /etc/sudoers.d/ on the extra-chill agent host:

File Written By what Tracked
opencode-kimaki Mar 9 by hand nowhere
homeboy-upgrade Aug 13 by hand nowhere
wp-coding-agents-kimaki-dispatch Sep 6 bridges/kimaki.sh here
homeboy-edge-apply Sep 16 by hand nowhere

One of four is machine-managed. Three disappear on a host rebuild, including the one that makes homeboy-upgrade — the agent's upgrade path — work at all.

verify.sh contains zero references to sudo. Nothing detects a missing, drifted, or unexpectedly-widened grant.

2. The API for this already exists here, and is dead

lib/systems-capabilities.sh:116 defines systems_capabilities_install_sudoers(). It is well built: atomic write to a temp file, visudo -cf validation before installation, root:root 0440, with systems_capabilities_drift() and a root-repair reporting path alongside it.

$ grep -rn systems_capabilities_install_sudoers .
lib/systems-capabilities.sh:116:systems_capabilities_install_sudoers() {

Zero call sites. Its only consumer was the dmc-process-inspect probe, removed in "refactor: retire DMC integration contracts." The consumer was retired; the mechanism was left behind.

3. So the next feature wrote its own — and the copy is the unsafe one

bridges/kimaki.sh grew a second, independent sudoers writer. It installs then validates (bridges/kimaki.sh:537-542):

printf '%s\n' "$sudoers_content" > "$sudoers_file"   # live path, /etc/sudoers.d/
chown root:root "$sudoers_file"
chmod 0440 "$sudoers_file"
if command -v visudo >/dev/null 2>&1; then
  visudo -cf "$sudoers_file" >/dev/null
fi

setup.sh and upgrade.sh both run under set -e, so a failed visudo aborts the run and leaves the invalid file at its live path. A malformed file in /etc/sudoers.d/ makes sudo refuse to run for every user on the host — including the recovery path someone would need to fix it.

The dead function does this correctly: validate the temp file, mv only on success, never expose a bad file. We have two implementations of one thing, and the one in service is the one that can lock the operator out of the box.

4. Proposal: one grant path, declared not imperative

Nothing new to invent. Revive systems_capabilities_install_sudoers() as the only way a grant reaches a host, and let components declare grants rather than write files:

  • A component (kimaki bridge, homeboy wrapper, future privileged helper) declares caller, runas, command, args-pattern.
  • One reconciler installs, validates before install, and records the grant in the capability profile — the desired-state pattern this repo already uses for installation profiles.
  • systems_capabilities_status includes grants, so verify.sh reports drift instead of nobody noticing for six months.
  • bridges/kimaki.sh's private writer is deleted.

Net effect: two implementations become one, the unsafe ordering disappears, the three hand-placed grants become declared and survive a rebuild, and grants become verifiable.

This is net deletion of code. It is not a new subsystem.

5. Where the boundary sits with Homeboy

  • Homeboy owns what a privileged action does — the wrapper, its validation, rollback, probes. Product-agnostic, no WordPress.
  • wp-coding-agents owns who may invoke it on a provisioned host. It provisions the host, creates the agent account, and already has the profile and drift machinery.

#599 argued for this repo on the grounds that it "already writes the sudoers grant for homeboy-upgrade." That is not true — it writes only the kimaki dispatch grant, and ALL=(opencode), never a root grant. But #599 picked the right repo for the wrong reason: the grant lifecycle does belong to the provisioner.

homeboy-edge-apply is a ready first consumer. Its grant is hand-placed today, which is the same defect as homeboy-upgrade — declaring it here would fix both and give the revived API a live consumer.

6. The general rule worth adopting

The specific bug is two sudoers writers. The pattern that produced it is a mechanism outliving its consumer, so the next feature quietly reimplements it. Worth enforcing directly: every mechanism has a live consumer or gets deleted, checked in CI rather than left to judgment. That catches the next systems_capabilities_install_sudoers before it becomes the next duplicate.


AI assistance: investigated and written by Claude Opus 4.5 via Claude Code, driven by Chris. The model audited the live host's grant files, traced the dead call site and its retired consumer through git history, and found the install-before-validate ordering in the kimaki bridge. Findings are from reading this repo and the host directly; the proposal is a recommendation, not implemented work.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions