Skip to content

Portal v0.39.0 — One runbook, one unpublished change, and a diff before you publish

Choose a tag to compare

@AndrewDryga AndrewDryga released this 10 Aug 06:45
· 671 commits to main since this release
Immutable release. Only release title and notes can be modified.
v0.39.0
5e7184a

Runbook versioning stopped counting saves and started counting decisions.

Runbooks

Every save used to mint a version. Fifteen authoring passes were fifteen versions, and v7 could be the second thing that ever ran — the number told you how often someone had pressed save, not what had ever been approved.

Worse, the three facts an operator needed were smeared across those rows. Which version is live, which is a draft sitting on top of it, and which has been superseded were all derived by comparing rows, and the editor opened whichever row you clicked. An old version was one click from what looked like a working editor, and publishing from there made old content the newest published version — silently changing what a plain Run dispatches, with no step that announced it.

A runbook is now one thing that carries one unpublished change:

  • Publishing shows the change. The confirm step renders the lines that differ from what runs today, against the exact canonical text whose hash is the definition's identity — so what you approve is what moved the hash. A first release says so rather than showing an empty diff.
  • Only the live release runs. Naming an older one answers not_live instead of quietly running current content, and running an unpublished change takes explicit consent plus the hash of exactly what you read.
  • History is inspectable, never editable. The list names the live release on the Run button itself (Run v3) and marks a waiting change with a quiet dot.
  • Executions keep what they started with. Each one snapshots the definition it dispatched, so a later edit, publish, or delete cannot rewrite what an audit says ran.

The MCP surface follows the same model: get_runbook and update_runbook_draft are keyed by slug, an agent replaces the single unpublished change under the hash it read, and publication stays human-only.

Security

The runner redacts more of what a configuration actually calls a secret: connection strings and database URLs, key-derivation inputs like salt and pepper, cookie and session signing keys, and the passphrase spellings. This is the safety net beneath actions that forget to declare their own redactions — it is never a reason to lower an action's risk tier, because a key name nobody thought of still leaks.

Reading a pfSense certificate no longer emits its private key, and the fleet installer keeps a reusable enrollment key off the process command line.

Packs

The behavior harness now proves the shapes it used to declare out of reach: a real service manager booted as PID 1, a Docker daemon each case owns, iptables inside the namespace it writes, and a real dpkg database for install, remove, and autoremove. What remains uncovered is recorded with the reason it is uncovered, so the exception list is an inventory rather than a shrug.

pfSense gains resolver, NTP, and WireGuard peer reads that never return their secrets, plus a DHCP reservation staged for the operator to apply.

Billing

A new subscription adopts the Paddle customer an owner's email already has instead of failing, and a repeating conflict now says which one it is.


Upgrade. The portal migration collapses each runbook's version rows into one runbook, renumbers its published versions into releases, and repoints execution history before removing anything — executions keep the definition and release number they ran. It runs before the instance serves, as usual.

Runner v0.19.0 ships alongside this release and carries the redaction change above; the MCP bridge is unchanged at mcp-v0.7.0.