Let an AI Agent Author Policy-as-Code, Never Override Its Verdict
An AI assistant writing Terraform is now unremarkable. It reads the module, proposes the change, opens the pull request, and does it faster than the engineer who asked. The interesting question moved a layer up: what checks that output, and who controls the check. Terraform is the declarative provisioning tool that turns a written description of infrastructure into API calls, which is exactly why a pull request against it is the last place a human reliably sees the change. Fourteen new tools address that gate.
ZopNight added fourteen MCP tools for infrastructure-as-code governance, taking the catalogue from 275 tools to 289, of which 43% are writes. Eleven of them let an agent create, edit, list and dry-run the Terraform and Terraform and OpenTofu pull-request gates, switch per-repository scanning on, manage scan tokens, and read validation runs with their audit trail. Two obvious companions were deliberately left out, and those two are where the design lives.
The Question Is Not Whether an Agent Writes Terraform, It Is Who Owns the Gate
A policy gate is worth something only if the thing it gates cannot lift it. That is the entire property, and it is easy to lose by accident when the same agent holds both the authoring tools and the override.
The bypass boundary is the line between authoring a control and lifting its result: an agent may propose, write, dry-run and read a governance policy, and may never be the actor that waives an outcome that policy produced. Everything on the authoring side is reviewable after the fact, because the policy is an artefact somebody can read. An override is a single act that leaves the artefact intact and the outcome reversed.
Two tools sit on the wrong side of that line, and both were withheld. start_iac_validation needs a full Terraform plan and state blob supplied by the caller, which means the agent would be handing in the evidence its own change is judged on. override_iac_validation is a governance bypass outright, and the release notes say what it needs before it ships: actor-attributed, audited elevation. Not a scope. An elevation with a name attached.
Fourteen Tools, and the Two Left Out Define the Boundary
| Group | Tools | Why it is safe to hand an agent |
|---|---|---|
| Policy authoring | Create, update, list IaC policies | Produces a reviewable artefact; nothing is enforced until enabled |
| Policy dry run | Validate an IaC policy | Persists nothing, returns a verdict and errors |
| Repository wiring | Enable scanning, check status | Turns the gate on, which fails toward more checking rather than less |
| Token management | List and revoke scan tokens | Revocation is the safe direction; minting is where care is needed |
| Evidence | Read validation runs and their audit trail | Read-only, and the audit trail is the record the agent cannot alter |
| Catalogues and lookup | IaC policy catalogue, tag policy catalogue, Jira assignable users | Reference data an agent needs to write a valid policy or ticket |
Read the middle column as a risk ordering and one entry stands out. Enabling scanning on a repository fails toward more governance, not less. An agent that wires up a gate nobody asked for creates a review conversation. An agent that removes one creates an incident a month later.
That asymmetry is the practical rule for deciding which governance tools an agent may hold. Ask what the worst plausible mistake produces. If it produces a stricter estate and an annoyed team, the tool is a reasonable thing to hand over. If it produces a quieter estate and no visible change, it is not.
A Dry Run Is What Makes Agent-Authored Policy Safe
validate_iac_policy takes a policy, checks it, persists nothing, and returns whether it is valid along with any errors. It is the direct analogue of the already-shipped watch-policy validator.
Without a dry run, an agent authoring policy has exactly one feedback channel: enable it and watch whose pull request fails. That is a bad loop for a human and a worse one for an agent, which will iterate faster and therefore break more pull requests per hour of good intentions.
There is a schema wrinkle worth knowing if you build MCP surfaces. The validator is declared mutating, even though it changes nothing, because the read guard forbids binding a GET to a POST route and a policy body has to be posted. The declaration is a protocol artefact, not a claim about effect. It is worth flagging in your own tool descriptions when it happens, because an agent reasoning about which tools are safe to call speculatively will read that declaration literally and avoid a tool that was safe all along.
Not Idempotent, and Labelled That Way
ensure_iac_ci reads like the safest possible verb. Ensure. Call it twice, get the same state.
It is not idempotent, and it is now marked that way. In some non-wired states a retry mints a new scan token and revokes the previous one. A caller that retries on a timeout can therefore invalidate a token that was working, and the failure surfaces later as a CI job that cannot authenticate.
| Assumption about retries | What a retry actually does | Where it surfaces |
|---|---|---|
| Idempotent, safe to retry on timeout | New token minted, prior token revoked | CI authentication failure on the next pull request |
| Not idempotent, declared | Caller surfaces the timeout instead of retrying | Immediately, to whoever is watching |
The fix was not to make retries safe. It was to declare the truth and move the tool onto the not-idempotent list, so the retry logic above it stops retrying. That is the right call when making an operation genuinely idempotent would require holding a token in a half-created state, which is its own security problem.
For agent-facing APIs this labelling matters more than for human ones. A human who calls something twice usually remembers doing it. An agent’s retry is a policy in a client library it never reasoned about, applied to a tool whose name promised it was fine.
A Filter That Can Never Match Teaches the Agent a Wrong Model
list_iac_policies was first built by reusing the schema from the alerting and watch policy lists. That inherited a target_type filter offering values of organisation and cloud account.
Every IaC policy is repository-scoped. Neither value can ever match anything.
The repair replaced it with a repo_ref filter mapped to the underlying target parameter. But the bug is worth sitting with, because it is not a filter bug. It is a documentation bug that an agent reads as domain knowledge.
An agent given a schema advertising organisation-scoped IaC policies will believe IaC policies can be organisation-scoped. It will offer that as an option when a human asks how to apply a rule estate-wide. It will call the tool, receive an empty list, and reason about why this organisation has no organisation-scoped policies rather than concluding the category does not exist. Every one of those steps is competent reasoning over a false premise handed to it in the schema.
Schema fields are not hints for an agent. They are the domain model, and an inherited field nobody removed is a claim the system is making about itself.
Redaction Anchored to Arguments Drops the Whole Response Body
One last footgun, and it only ever shows up in the audit log. The gateway’s redaction list is anchored to a tool’s arguments, not to fields in its response. A non-empty redaction list therefore causes the entire response body to be dropped from the audit record.
That is defensible as a default: if something in this call is sensitive enough to redact, do not store the response. It is also surprising enough that comments across the tool definitions were corrected, and an integration test now pins that the audit response body for ensure_iac_ci is empty rather than leaving it to a future reader to rediscover.
The general shape is familiar to anyone who has built an audit trail. Redaction rules are written once, by someone thinking about arguments, and applied forever, by a pipeline handling responses. The only reliable defence is a test that asserts what the audit record actually contains, for the specific tools where it matters, rather than a comment describing what somebody intended.
This works when the policy an agent authors is reviewed before it is enabled. It fails if enabling is automated too, because the dry run then checks only that the policy parses, not that anyone agreed with it. Fourteen tools is a small number against a 289-tool catalogue. The reason this particular fourteen is worth writing about is that they are the first set where the agent is being handed the controls rather than the estate, and the discipline that shows up is the one you would want: author freely, dry-run often, read the audit trail, and never hold the override.
