Skip to content

Agents cannot apply reviewed edge/server config: propose a narrow privilege wrapper modelled on homeboy-upgrade #599

Description

@chubes4

The gap

An agent provisioned by wp-coding-agents cannot apply edge/server configuration, even when the change is small, reviewed, and git-tracked. Every such fix stalls waiting for a human with a shell.

Concrete case from today. An nginx hardening rule was 403ing every /.well-known/ path on the network:

# Deny access to hidden files
location ~ /\. {
    deny all;
}

/.well-known/ is an IANA-registered public path (RFC 8615), so this broke OAuth discovery (oauth-authorization-server, oauth-protected-resource), security.txt, and apple-app-site-association. It is fatal to MCP client authorization — ChatGPT and Claude both begin by fetching those two documents.

I diagnosed it, wrote the fix, opened a PR syncing the repo copy — and then could not apply it. The actual change is one location block and a reload.

Current envelope on this host:

User opencode may run the following commands on extra-chill:
    (root) NOPASSWD: /usr/local/sbin/homeboy-upgrade *

That is the only root-capable path, and it is correctly scoped to upgrades. homeboy server list shows a root-capable entry (chubes-net, 178.156.237.104) but that is a different machine — this host is 178.156.238.82, registered as user opencode.

What I am not asking for

Not blanket sudo, not an interactive root shell, and not homeboy deploy / homeboy release — those are deliberately operator-gated and should stay that way.

The distinction that matters: "the agent can edit nginx" is dangerous; "the agent can apply the reviewed, git-tracked config" is auditable. Only the second is worth building.

Proposal: a narrow privilege wrapper, modelled on homeboy-upgrade

/usr/local/sbin/homeboy-upgrade is already a well-built example and should be the template. It does everything right:

  • set -Eeuo pipefail, hardened PATH, umask 077
  • unsets BASH_ENV CDPATH ENV GITHUB_TOKEN GH_TOKEN HOMEBOY_CONFIG HOMEBOY_CONFIG_DIR
  • strict argument validation ([[ $TAG =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]])
  • absolute paths for every binary
  • syslog via logger -t "$PROGRAM"

A sibling wrapper — call it homeboy-edge-apply — granted the same way:

(root) NOPASSWD: /usr/local/sbin/homeboy-edge-apply *

Critical design constraint: it must not accept config text as an argument. It takes a named, allowlisted target and syncs from a git-tracked source of truth, so the content is always something a human reviewed in a PR:

  1. Resolve the target from a fixed allowlist (e.g. nginx-site), never an arbitrary path.
  2. Read the new content from the checked-out repo copy at a pinned path, not from the caller.
  3. Snapshot the current file with a timestamp.
  4. nginx -t. On failure: restore snapshot, log, exit non-zero, never reload.
  5. Reload. Run a post-reload health probe against a configured URL set.
  6. On probe failure: restore snapshot, reload again, log, exit non-zero.
  7. Log the before/after hashes to syslog.

That makes the blast radius "apply a diff that already passed review and nginx -t, with automatic rollback" rather than "agent has root".

Secondary problem this would fix

/etc/nginx/sites-available/extrachill and /etc/nginx/sites-enabled/extrachill are separate regular files, not a symlink, differing by 1,142 bytes:

-rw-r--r-- root root 2334  sites-available/extrachill
-rw-r--r-- root root 3476  sites-enabled/extrachill
Files ... differ

sites-enabled is what nginx serves. Editing the conventional file changes nothing, and the drift is invisible until someone diffs them. A wrapper that syncs from a single git-tracked source of truth eliminates the whole class of problem — which is the real value here, beyond unblocking one agent.

Worth deciding

  • Scope of the allowlist. nginx only, or a general "edge config" surface that could later cover Cloudflare rules? extrachill-network/docs/nginx/ already tracks both, and its README declares itself source of truth for each.
  • Whether the repo copy or the live file is authoritative, and whether the wrapper should refuse to apply when the live file has drifted from git — i.e. detect manual edits rather than silently overwrite them.
  • Whether this belongs in wp-coding-agents' installer at all, or in Homeboy proper. wp-coding-agents provisions the agent's environment and already writes the sudoers grant for homeboy-upgrade, which argues for here — but Homeboy owns deploy and server registration, which argues for there. Worth settling explicitly rather than by default.

Why it is worth building

This is not a one-off. Over one working session the same shape recurred: the agent diagnoses precisely, produces the fix, and cannot apply it — so the change sits in a PR while the actual defect stays live in production. Today that defect is breaking OAuth discovery, security.txt, and iOS universal links simultaneously.

Related

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