---
title: "Dock + Terraform Cloud: infrastructure changes with dual-keyed approval"
excerpt: "Dock turns Terraform Cloud plans into structured change briefs and gates apply behind a dual-keyed handshake. Terraform stays the system of record for state; Dock holds the agent's reasoning, the reviewer, and the timestamp."
author: mei
category: Use Cases
date: "2026-05-30"
---

Terraform Cloud pauses every run between plan and apply. Dock fills the gap. When a planning agent proposes a change, Dock writes a change brief and refuses to dispatch apply until a named human signs alongside the agent. Plan output stays in Terraform. Reasoning, reviewer, and signed dispatch live in Dock. Part of the [Dock for DevOps](/blog/dock-for-devops) pattern.

Terraform Cloud and GitHub stay the system of record for the raw data. Dock is the system of record for what the AGENT INTERPRETS. Each Dock row carries a pointer back to the platform record, agent identity, decision, reviewer, and timestamp. The agent re-fetches platform data via fresh API reads when it needs current state.

## The change-brief table

One Dock table, `infra_changes`, holds the agent's interpretation of every Terraform run.

| run_id | workspace | tf_run_url | github_pr | resources_changed | blast_radius | agent | agent_summary | reviewer | applied_at |
|---|---|---|---|---|---|---|---|---|---|
| run-7ZkA | prod-api | hcp.app/runs/7ZkA | PR #4412 | 3 add, 1 destroy (RDS replica) | high | argus@dock | Rotates read replica AZ. Destroy is the old replica; new one provisioned first. | govind | 2026-05-28 14:11 |
| run-7ZkB | prod-edge | hcp.app/runs/7ZkB | PR #4419 | 2 update (WAF rules) | low | argus@dock | WAF rate-limit bump from 1k to 2k rpm. Reversible via revert PR. | (auto-low) | 2026-05-28 14:33 |
| run-7ZkC | prod-data | hcp.app/runs/7ZkC | PR #4421 | 1 destroy (S3 bucket) | irreversible | argus@dock | Bucket holds 2024 audit logs. Lifecycle policy expired. Recommend hold. | pending | null |

The `tf_run_url` and `github_pr` are pointers. The `agent_summary` and `blast_radius` columns are Dock's contribution, captured the moment the plan completes. See [Cloud 2.0 for engineering](/blog/cloud-2-0-for-engineering) for the broader shift.

## Worked workflow: a high-blast-radius apply

Argus, a planning agent, watches a GitHub PR touching `terraform/prod-api`. On merge, Terraform Cloud queues a run. Argus reads the plan JSON, classifies it against the [dangerous-ops contract](/blog/dangerous-ops-contract), and writes a row with blast_radius = high because the diff destroys an RDS replica.

The row stays `pending` and the on-call engineer is notified. Govind opens it, reads Argus's summary, clicks through to the plan, and signs. Only after both signatures does Dock call apply with Argus's scoped token. This is the [two-key handshake for irreversible operations](/blog/two-key-handshakes-irreversible) applied to infrastructure.

If Govind declines, Dock closes the row with reason captured and discards the run. Argus never retries on its own.

## Why this matters

Terraform Cloud's confirm-and-apply gate assumes a human is reading the plan diff. With agents driving the PRs, the diff is no longer the bottleneck. The interpretation is. Dock holds that interpretation and ties it to a named agent identity, which is auditable through the [agent identity lifecycle](/blog/agent-identity-lifecycle) and surfaced in [agent audit and compliance](/blog/agent-audit-and-compliance) views.

HashiCorp's docs confirm the default: "run plans require confirmation before HCP Terraform will apply them," and the workspace stays locked until apply or discard ([HashiCorp Terraform docs](https://developer.hashicorp.com/terraform/cloud-docs/run/ui)). CNCF's OpenGitOps principles require declarative, versioned, immutable desired state ([OpenGitOps v1.0.0](https://opengitops.dev/)). Dock sits in the seam: GitHub holds the declarative source, Terraform Cloud holds the run, Dock holds the signed approval to bridge them.

Try this pattern on your highest-blast-radius workspace first.

## FAQ

**Does Dock store Terraform state?**
No. State stays in Terraform Cloud. Dock stores a pointer to the run plus the agent's interpretation.

**What if the plan changes between approval and apply?**
Dock re-fetches the plan hash at dispatch time. If the hash differs from the one shown to the reviewer, the row reverts to pending and re-notifies.

**Can the agent apply low-risk changes without a human?**
Yes, if blast_radius is low and the workspace policy allows it. The row still records who decided and why.

**How does this differ from Terraform Cloud's native policy checks?**
Sentinel and OPA evaluate the plan. Dock evaluates the agent's reasoning about the plan and binds it to a human signature.
