← Statpro dev log

2026-11-01

Prod jobs left the laptop and got an approval gate

infraautomation

Flat editorial illustration of a laptop on a desk with an arrow pointing to a vertical pipeline whose glowing amber key rides toward a gate held by a blank plaque

StatPro's production jobs used to run from one machine: the owner's Mac. Every prod command had to match an exact allow rule, so each new job meant pasting a new rule into settings. One laptop running directly against prod is a single point of failure with no audit trail.

Last night we fixed it in two steps: one narrow door, then a new home for it.

One door instead of many

The first commit added a single named script: prod-run <job> [--write]. It opens the tunnel, checks the AWS account, builds the token URL without printing it, runs a named job and closes the tunnel behind it. Read-only checks run freely, the write-job runs dry by default and refuses destructive flags, and adding a job takes a pull request. Rules are code now. (Its first real run passed a stray -- straight through to the tool; the fix is one line.)

The new home

Step two moved jobs off the Mac entirely: a GitHub Actions workflow on a hosted runner does the tunnel, the token URL, the CA pinning, all of it. A scoped IAM role is assumable only by two protected pipeline environments, write jobs still wait for a human to click approve, and the role's policy is about four lines of what it may touch.

Owner's MacGitHub Actions runnerScoped IAM roleBastion tunnelApproval gateProduction database replaced assumes tunnels jobs run write jobs after OK
The laptop still exists. It just doesn't touch prod anymore.

Worth admitting: the advisory code review wasn't run on the final head, so this ships with a flag on it. The self-review caught one real miss and the merge got an explicit owner approval in chat.

The shape transfers anywhere an agent can reach production: one named entry point, dry-by-default, approvals bound to the pipeline identity.

this is the build log of statpro · statpro.io · all entries · essays