Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
stop-slop, taste-skill, terrashark had embedded .git dirs causing Woodpecker clone to fail on submodule update.
156 lines
3.6 KiB
Markdown
156 lines
3.6 KiB
Markdown
# CI Drift
|
|
|
|
Use this guide when pipeline behavior diverges from local behavior or from reviewed intent.
|
|
|
|
## Symptoms
|
|
|
|
- CI plan differs from local plan unexpectedly
|
|
- apply occurs without using reviewed plan artifact
|
|
- provider/runtime drift appears between runs
|
|
- scanner/policy stages are skipped on some paths
|
|
|
|
## Root causes
|
|
|
|
- unpinned runtime/provider versions
|
|
- missing or stale lockfile
|
|
- apply job running `plan` again instead of consuming reviewed artifact
|
|
- inconsistent credentials/auth between plan and apply
|
|
|
|
## Drift prevention baseline
|
|
|
|
- pin runtime and provider ranges
|
|
- commit lockfile and review lockfile changes
|
|
- generate one reviewed plan artifact and apply exactly that artifact
|
|
- run policy/security checks on every path to apply
|
|
- enforce branch protections and environment approvals
|
|
|
|
## Production-ready GitHub Actions template
|
|
|
|
```yaml
|
|
name: terraform-delivery
|
|
|
|
on:
|
|
pull_request:
|
|
paths:
|
|
- '**/*.tf'
|
|
- '**/*.tfvars'
|
|
push:
|
|
branches: [main]
|
|
paths:
|
|
- '**/*.tf'
|
|
- '**/*.tfvars'
|
|
|
|
concurrency:
|
|
group: terraform-${{ github.ref }}
|
|
cancel-in-progress: false
|
|
|
|
permissions:
|
|
contents: read
|
|
id-token: write
|
|
pull-requests: write
|
|
|
|
jobs:
|
|
plan:
|
|
if: github.event_name == 'pull_request'
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: hashicorp/setup-terraform@v3
|
|
- run: terraform fmt -check
|
|
- run: terraform init -backend=false
|
|
- run: terraform validate
|
|
- run: terraform init
|
|
- run: terraform plan -out=plan.bin
|
|
- run: terraform show -json plan.bin > plan.json
|
|
- run: conftest test plan.json --policy policy/
|
|
- uses: actions/upload-artifact@v4
|
|
with:
|
|
name: reviewed-plan
|
|
path: plan.bin
|
|
|
|
apply:
|
|
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
needs: [validate]
|
|
runs-on: ubuntu-latest
|
|
environment: production
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: hashicorp/setup-terraform@v3
|
|
- uses: actions/download-artifact@v4
|
|
with:
|
|
name: reviewed-plan
|
|
- run: terraform init
|
|
- run: terraform apply -auto-approve plan.bin
|
|
```
|
|
|
|
Notes:
|
|
- replace auth steps with OIDC/provider-specific login actions
|
|
- in real repos, split plan/apply workflows if artifact lifetime across events is an issue
|
|
|
|
## Production-ready GitLab CI template
|
|
|
|
```yaml
|
|
stages:
|
|
- validate
|
|
- plan
|
|
- policy
|
|
- apply
|
|
|
|
variables:
|
|
TF_IN_AUTOMATION: "true"
|
|
|
|
validate:
|
|
stage: validate
|
|
image: hashicorp/terraform:1.7
|
|
script:
|
|
- terraform fmt -check
|
|
- terraform init -backend=false
|
|
- terraform validate
|
|
|
|
plan:
|
|
stage: plan
|
|
image: hashicorp/terraform:1.7
|
|
script:
|
|
- terraform init
|
|
- terraform plan -out=plan.bin
|
|
- terraform show -json plan.bin > plan.json
|
|
artifacts:
|
|
paths:
|
|
- plan.bin
|
|
- plan.json
|
|
expire_in: 24h
|
|
|
|
policy:
|
|
stage: policy
|
|
image: openpolicyagent/conftest:latest
|
|
script:
|
|
- conftest test plan.json --policy policy/
|
|
dependencies:
|
|
- plan
|
|
|
|
apply:
|
|
stage: apply
|
|
image: hashicorp/terraform:1.7
|
|
when: manual
|
|
allow_failure: false
|
|
script:
|
|
- terraform init
|
|
- terraform apply -auto-approve plan.bin
|
|
dependencies:
|
|
- plan
|
|
```
|
|
|
|
## LLM mistake checklist
|
|
|
|
Common model mistakes to correct:
|
|
- missing lockfile strategy
|
|
- apply without saved plan artifact
|
|
- no policy stage despite claiming compliance
|
|
- no branch/environment protection discussion
|
|
|
|
## Quick diagnostics
|
|
|
|
- compare runtime versions local vs CI
|
|
- diff lockfile in PR
|
|
- ensure apply consumes `plan.bin` from reviewed plan stage
|
|
- verify policy scanner runs on every apply path
|