feat: derive approval reasons at read time and add opt-in auto-approve rules - #32
Merged
Conversation
…e rules Pending approvals created without a stored reason now render a human-readable sentence derived from the reviewed plan (agent upgrades, linemeta metadata syncs, nft/netpolicy/selfdns/proxycore/tunnel/wireguard applies). Stored rows are never migrated; derivation happens in the view mapping so every reader sees a consistent reason. Auto-approve is an operator opt-in via LATTICE_APPROVAL_AUTO_RULES (default off = fully manual). Fresh pending submissions flow through the new submitApproval chokepoint; the first matching rule approves (and optionally queues) through the exact same plan-hash-bound decision path as the manual endpoint, crediting policy:<rule> as the actor, with a per-rule daily cap and approval.auto_approve / approval.auto_skip audit events.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
From the 2026-08-10 review: 45 pending production approvals, every
reasonempty, and trusted system writers force a human click for additive fleet-wide plans.approvalDisplayReasonrenders a human sentence per plugin/action from the plan ("Node agent upgrade 0.3.0 -> 0.3.3 (edge-1)", "Line identity metadata sync (26 inbounds)", nft/dns/netpolicy/netguard/group-policy shapes covered, title-case fallback). Wired intoApprovalViewsonly — stored rows are never rewritten; existing approvals gain reasons with zero migration. A stored non-empty reason always wins.LATTICE_APPROVAL_AUTO_RULES/-approval-auto-rulesJSON rules ({name, writer, plugin, action_prefix, queue, daily_cap}). Empty/absent (the default) is a pure pass-through — zero behavior change. All nine creation sites now funnel throughsubmitApproval, which evaluates the first matching rule against fresh pending submissions only. The auto path calls the factoredapproveApprovalCorewith the sha256 of the just-persisted plan, so the TOCTOU hash binding is byte-identical to the manual endpoint; the policy actor (policy:<name>) is stamped only after a successful decision, so failures never poison the daily cap. Audits:approval.auto_approve/approval.auto_skip(daily_cap), both attributable. Malformed config warns and starts with zero rules — startup never fails on it.Verification
Notes