docs: add Terraform drift detection tutorial#300
Conversation
|
Claude finished @mintlify[bot]'s task in 1m 43s —— View job Review of PR #300 — Terraform drift detection tutorial
Overall assessmentStrong tutorial. The content is well-structured, follows the Diataxis tutorial model (teaches by doing, builds incrementally), and the two-mechanism framing gives the reader a clear mental model before diving into implementation. Navigation entry is correctly placed under Tutorials > Security. All internal links resolve. No relative links found. FindingsCriticalNone. Improvement (5 findings — all British spelling)CLAUDE.md mandates American spelling. Five instances of British spelling found across the tutorial — inline comments with suggested fixes posted on each:
Suggestion (1 finding)
Summary
Top priority: Fix the British spellings (all mechanical, one find-and-replace). The rest of the tutorial — structure, accuracy, component usage, link format, frontmatter — is solid and ready to ship. |
|
|
||
| <CardGroup cols={2}> | ||
| <Card title="Mechanism A — statefile provenance" icon="fingerprint"> | ||
| Prove that every statefile in use was produced by your pipeline. A statefile your pipeline doesn't recognise is, by definition, the product of an apply that bypassed CI. A plan can't catch this: a laptop apply updates the statefile and the world together, so they still agree and the plan comes back empty. Detecting it needs a record of where the statefile came from. |
There was a problem hiding this comment.
Improvement (style): CLAUDE.md requires American spelling. recognise → recognize.
| Prove that every statefile in use was produced by your pipeline. A statefile your pipeline doesn't recognise is, by definition, the product of an apply that bypassed CI. A plan can't catch this: a laptop apply updates the statefile and the world together, so they still agree and the plan comes back empty. Detecting it needs a record of where the statefile came from. | |
| Prove that every statefile in use was produced by your pipeline. A statefile your pipeline doesn't recognize is, by definition, the product of an apply that bypassed CI. A plan can't catch this: a laptop apply updates the statefile and the world together, so they still agree and the plan comes back empty. Detecting it needs a record of where the statefile came from. |
| </Accordion> | ||
|
|
||
| <Accordion title="Race conditions are bounded, not eliminated" icon="clock"> | ||
| Two timing windows exist in theory. First, between an apply finishing and the statefile being captured for a provenance check, a concurrent unauthorised change could slip in. In practice the Terraform lock prevents a concurrent apply from starting until the lock is released, which keeps this theoretical. Second, if the statefile changes between a snapshot being taken and being evaluated, that snapshot is simply stale — the next cycle picks up the new state. Understand both; rely on locking and ordering to keep them harmless. |
There was a problem hiding this comment.
Improvement (style): British spelling — unauthorised → unauthorized.
| Two timing windows exist in theory. First, between an apply finishing and the statefile being captured for a provenance check, a concurrent unauthorised change could slip in. In practice the Terraform lock prevents a concurrent apply from starting until the lock is released, which keeps this theoretical. Second, if the statefile changes between a snapshot being taken and being evaluated, that snapshot is simply stale — the next cycle picks up the new state. Understand both; rely on locking and ordering to keep them harmless. | |
| Two timing windows exist in theory. First, between an apply finishing and the statefile being captured for a provenance check, a concurrent unauthorized change could slip in. In practice the Terraform lock prevents a concurrent apply from starting until the lock is released, which keeps this theoretical. Second, if the statefile changes between a snapshot being taken and being evaluated, that snapshot is simply stale — the next cycle picks up the new state. Understand both; rely on locking and ordering to keep them harmless. |
| Two independent conditions then report the same Kosli Environment as non-compliant, mapping cleanly onto the two mechanisms: | ||
|
|
||
| 1. **The statefile in S3 no longer matches an attestation** — it was produced by an apply outside CI. The reporter Lambda detects this on its own, with no scheduled plan involved. This is **Mechanism A**, the one a plan can never catch. | ||
| 2. **The drift marker no longer matches its attestation** — the periodic drift detector found a non-empty plan and overwrote `drift.plan.json` in S3 with fresh, un-attested content. The next snapshot sees an unrecognised artifact. This is **Mechanism B**. |
There was a problem hiding this comment.
Improvement (style): unrecognised → unrecognized (American spelling per CLAUDE.md).
| 2. **The drift marker no longer matches its attestation** — the periodic drift detector found a non-empty plan and overwrote `drift.plan.json` in S3 with fresh, un-attested content. The next snapshot sees an unrecognised artifact. This is **Mechanism B**. | |
| 2. **The drift marker no longer matches its attestation** — the periodic drift detector found a non-empty plan and overwrote `drift.plan.json` in S3 with fresh, un-attested content. The next snapshot sees an unrecognized artifact. This is **Mechanism B**. |
|
|
||
| ## Part 3 — Reference implementation: `kosli-dev/tf` | ||
|
|
||
| Everything above is implemented at [github.com/kosli-dev/tf](https://github.com/kosli-dev/tf). It has two parts: a thin Terraform wrapper (`tf`) and a set of reusable GitHub Actions workflows, both open source under the MIT licence. The workflows attest the statefile and drift marker into a Kosli Environment, and the Kosli reporter Lambda is what continuously detects and reports drift. You can call the workflows directly, or borrow their shape for your own CI. |
There was a problem hiding this comment.
Improvement (style): Two British spellings: licence → license, unrecognised → unrecognized.
| Everything above is implemented at [github.com/kosli-dev/tf](https://github.com/kosli-dev/tf). It has two parts: a thin Terraform wrapper (`tf`) and a set of reusable GitHub Actions workflows, both open source under the MIT licence. The workflows attest the statefile and drift marker into a Kosli Environment, and the Kosli reporter Lambda is what continuously detects and reports drift. You can call the workflows directly, or borrow their shape for your own CI. | |
| Everything above is implemented at [github.com/kosli-dev/tf](https://github.com/kosli-dev/tf). It has two parts: a thin Terraform wrapper (`tf`) and a set of reusable GitHub Actions workflows, both open source under the MIT license. The workflows attest the statefile and drift marker into a Kosli Environment, and the Kosli reporter Lambda is what continuously detects and reports drift. You can call the workflows directly, or borrow their shape for your own CI. |
| - **`apply.yml`** — the plan steps plus `tf apply`, then a reset-drift-detection job that writes a fresh `{sha, drift: false}` marker to S3 (the known-good baseline for the next drift run). | ||
| - **`detect-drift.yml`** — the detector. Reads the baseline marker, and only if `drift == false` runs a plan against the baseline SHA. A non-empty plan overwrites the marker with `{sha, drift: <timestamp>}`; otherwise it records a no-drift summary. | ||
|
|
||
| With Kosli enabled (the intended, full setup), `apply.yml` additionally attests the plan, the apply log, the statefile and the drift marker into your Kosli Environment. Those attested artifacts are what the Kosli reporter Lambda checks the live S3 files against — so an out-of-CI apply (an unrecognised statefile) or a flagged marker shows up as a non-compliant Environment. |
There was a problem hiding this comment.
Improvement (style): unrecognised → unrecognized.
| With Kosli enabled (the intended, full setup), `apply.yml` additionally attests the plan, the apply log, the statefile and the drift marker into your Kosli Environment. Those attested artifacts are what the Kosli reporter Lambda checks the live S3 files against — so an out-of-CI apply (an unrecognised statefile) or a flagged marker shows up as a non-compliant Environment. | |
| With Kosli enabled (the intended, full setup), `apply.yml` additionally attests the plan, the apply log, the statefile and the drift marker into your Kosli Environment. Those attested artifacts are what the Kosli reporter Lambda checks the live S3 files against — so an out-of-CI apply (an unrecognized statefile) or a flagged marker shows up as a non-compliant Environment. |
| "s3://$STATE_BUCKET/terraform/$REPO/drift.plan.json" | ||
| curl -sf -X POST "$SLACK_WEBHOOK" -H 'Content-type: application/json' \ | ||
| --data "{\"text\":\"Drift detected in $GITHUB_REPOSITORY against $SHA\"}" | ||
| ``` |
There was a problem hiding this comment.
Suggestion: The YAML block ends abruptly without closing the jobs: → detect: → steps: structure — the last step (Alert + record drift) has no final dedent or trailing .... While GitHub Actions is forgiving about this, adding the closing empty line would make the example cleaner to copy-paste.
|
Preview deployment for your docs. Learn more about Mintlify Previews.
|
Adds a new tutorial covering Terraform drift detection with Kosli, based on the source Google Doc.
What's new
tutorials/terraform_drift_detection.mdx— full tutorial covering:kosli-dev/tfreference wrapper and reusable workflowsLive page will be at
/tutorials/terraform_drift_detection.Generated by Mintlify Agent.
Requested by: graham@kosli.com via Slack
Mintlify session: slack_1775036725.228749_D0AM66349C1