github mattrobinsonsre/terrapod v1.8.0

one hour ago

Terrapod is a free, open-source, self-hosted platform replacement for Terraform Enterprise. v1.8.0 makes the governance layer both stronger and easier to operate: policy sets can share data files, the AI plan summary can gate an apply, policy sets are finally manageable as code, and the pull-request comment says what changed, what it costs and what gated it.

Read before upgrading

Every VCS-connected workspace now gets the pull-request status table. Previously only apply_then_merge workspaces did. This is the most visible change in the release: if you have VCS-connected workspaces on the default workflow, Terrapod starts commenting on their pull requests where it did not before.

In the same move the older per-workspace "Terrapod — <workspace>" comment mostly stops appearing — it is now posted only when an AI summary is ready, and ai_summary.enabled is off by default. So a default deployment swaps one comment style for another rather than gaining a second. The comment marker is also now scoped per commit, which means comments written by v1.7.x are never matched or edited again: they stay frozen on in-flight pull requests, and a new comment is created per push instead of one being edited forever. The table itself drops its Mode column and gains Cost Δ.

Shared policy evaluation fails OPEN on a lagging runner, silently. The new shared-evaluation flag is carried to the runner in the policy bundle. A runner too old to understand it ignores the flag and evaluates each policy alone, without the set's data files — and a rule reading data.approved_cidrs is then undefined rather than failing, so it never matches. The set reports a clean pass it has not earned: empty deny, exit 0, no error anywhere.

A policy that instead calls a helper from a support file fails visibly (it does not compile alone, so the set reports errored), but the data case is silent. Upgrade your runners before enabling shared-evaluation on any set you rely on. Sets that leave it off are unaffected on every runner version.

Checkov moves 3.3.17 → 3.3.19 and OPA 1.20.2 → 1.21.0. New Checkov findings can appear on an unchanged plan, so a workspace with security-scan-enforcement: enforced that passed yesterday can fail today. These are Helm values (registry.platform_tools.*), so you can pin the old versions if you would rather move deliberately.

Bulk update now honours sixteen keys it previously ignored — the security-scan-*, ai-*, terragrunt-*, auto-merge* and drift-* families, plus slack-channel, debug-mode, vcs-workflow, plan-expiry-seconds and trigger-prefixes. A saved bulk-update payload carrying any of them now changes workspaces it used to leave alone. Re-read any stored payload before running it.

Booleans are type-checked rather than coerced. auto-merge, terragrunt-enabled, drift-detection-enabled and debug-mode now reject the string "false", 0 and 1 with a 422 on create and update. A client that stringifies booleans will break — the previous behaviour silently enabled settings that were being asked for as off.

Policy sets whose directory contains *_test.rego will go amber. Those files are correctly skipped, and a skipped file is now recorded on vcs-last-error instead of vanishing. Since *_test.rego is OPA's own convention, conventionally structured policy repositories pick up a non-null vcs-last-error on their next sync with no configuration change. It is informational, but it is a field worth alerting on, so expect the alert.

Supported release lines become 1.8 and 1.7. v1.6 leaves support with this release; v1.7 continues to receive security fixes only.

Highlights

  • Shared policy evaluation — a policy set can carry .yaml/.yml/.json data files and .rego helpers beside its policies and evaluate them together in one opa eval, so policies stop inlining their own copy of the same allowlist. Opt-in per set, because results then report per-set rather than per-policy: every file shares package terrapod, so OPA cannot attribute a denial to the file that produced it. After enabling it on an existing set the repository is re-read for you — the poller skips a repository whose head has not moved, so there is no commit coming to populate the files.
  • The AI plan summary as a policy gate — operator-written natural-language deny criteria plus a risk threshold, ruled on by the summary's own model call, so gating costs no additional tokens. Advisory or mandatory, with an admin override that works even when no verdict was ever recorded. Off by default; an errored verdict blocks under a mandatory gate, because a verdict that could not be reached is not consent.
  • Policy sets as code — terrapod_policy_set and terrapod_policy in the Terraform provider, plus a read-only policy-set MCP tool. The one gate that could previously only be click-opped.
  • Per-workspace runner debug mode — keeps a failed runner pod alive so you can kubectl exec in and reproduce a credential, DNS or mount failure with the run's real environment. Off by default and bounded by its own window. Two things to know before turning it on: while a pod lingers it holds the run's auth token and its decrypted terraform.tfvars.json, and the run stays in progress for the length of the hold — which also holds that workspace's apply queue. Delete the pod when you have your answer and both end immediately.
  • Per-workspace settings reachable from every surface — twelve settings bulk update could not set, ten the autodiscovery rule template could not carry, and five that workspace create silently dropped (including vcs-workflow, where asking for apply_then_merge quietly produced the default). A parity gate now fails the build on the next one.
  • The PR comment says what changed, what it costs and what gated it — plan shape, cost delta and gate verdicts in one attestation, and every command gets an acknowledgement saying why a dropped one was dropped.

Bug Fixes

  • Two shared-evaluation policy sets in one run no longer contaminate each other. Every set wrote into one directory and opa eval loads a directory recursively, so one set could be evaluated with another's rules and data — turning an advisory rule into a blocking one under the wrong set's name.
  • A skipped policy file (over the 1 MiB cap, not UTF-8, or named *_test.rego) no longer silently deletes its policy while reporting a clean sync.
  • terraform apply on a new terrapod_policy_set no longer fails with a 422 when enforcement_level is omitted, and a set created as code is no longer created disabled.
  • Switching shared-evaluation on through the API or the provider now re-reads the repository, as the Sync button does. Without it the set evaluated with no data files and a mandatory gate reported a pass it had not earned.
  • An admin's override of a run held with no verdict is no longer erased when the verdict lands late, which had left an applied run reading as one the gate failed to stop.
  • A mandatory AI gate holding a run with no verdict is now visible to the SDK and to MCP, and is bounded: the summariser is re-enqueued if its work was lost, and the hold acquires a stated reason rather than waiting forever.
  • An autodiscovery rule can no longer template apply_then_merge together with auto-apply — a pairing every other write path refuses, which would have auto-applied from unmerged branches in every directory the rule discovered.
  • A PR comment no longer offers terrapod apply for a run a gate will refuse, and a refused apply now says why instead of silently doing nothing.
  • A passing mention of Terrapod in prose no longer draws a reaction and a usage comment on unrelated pull requests.
  • Closed-pull-request reconciliation now runs for merge_then_apply workspaces too, cancelling their speculative runs instead of letting them run to completion.

Security

  • Page routes carry security headers, and the X-Forwarded-For trust model is now peer-based rather than header-based.
  • The token signing key Secret rolls the API atomically when it changes, manifest renderers no longer mint a fresh one on every render, and it is rendered only where an API is actually deployed.

Status

Stable. Backward compatible: every contract snapshot — routes, response attributes, the runner wire protocol, config keys, Helm values, the Go SDK surface, the provider schema and the MCP tool catalogue — grew and lost nothing.

Note for anyone upgrading from v1.7.4 or v1.7.5: those two releases landed on the 1.7 line after this one branched, and all of their fixes are carried here — run tasks at the pre_plan and pre_apply boundaries, the Safari tofu login fix, the redirect_uri validation and the signing-key work all shipped in v1.7.5 and are present in v1.8.0. They are listed above only where v1.8.0 changes them further.

Full Changelog: v1.7.5...v1.8.0

Don't miss a new terrapod release

NewReleases is sending notifications on new releases.