[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-79977":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":16,"stars7d":17,"stars30d":18,"stars90d":16,"forks30d":16,"starsTrendScore":16,"compositeScore":19,"rankGlobal":10,"rankLanguage":10,"license":20,"archived":21,"fork":21,"defaultBranch":22,"hasWiki":23,"hasPages":21,"topics":24,"createdAt":10,"pushedAt":10,"updatedAt":29,"readmeContent":30,"aiSummary":31,"trendingCount":16,"starSnapshotCount":16,"syncStatus":17,"lastSyncTime":32,"discoverSource":33},79977,"terraform-review-agent","infiniumtek\u002Fterraform-review-agent","infiniumtek","Reusable GitHub Action that reviews Terraform PRs for security, cost, and style using a LangGraph multi-agent system, posting a single severity-ranked comment.","https:\u002F\u002Finfiniumtek.com",null,"Python",84,12,74,1,0,2,7,3.34,"MIT License",false,"main",true,[25,26,27,28],"ai-agents","ai-tools","cicd","workflow-automation","2026-06-12 02:03:56","# terraform-review-agent\n\n[![CI](https:\u002F\u002Fgithub.com\u002Finfiniumtek\u002Fterraform-review-agent\u002Factions\u002Fworkflows\u002Fci.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Finfiniumtek\u002Fterraform-review-agent\u002Factions\u002Fworkflows\u002Fci.yml)\n[![Build Image](https:\u002F\u002Fgithub.com\u002Finfiniumtek\u002Fterraform-review-agent\u002Factions\u002Fworkflows\u002Fbuild-image.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Finfiniumtek\u002Fterraform-review-agent\u002Factions\u002Fworkflows\u002Fbuild-image.yml)\n[![License: MIT](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FLicense-MIT-green.svg)](LICENSE)\n\n![Python 3.13](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FPython-3.13-3776AB?logo=python&logoColor=white)\n![LangGraph](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FLangGraph-1C3C3C?logo=langchain&logoColor=white)\n![Pydantic v2](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FPydantic-v2-E92063?logo=pydantic&logoColor=white)\n![Docker](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FDocker-2496ED?logo=docker&logoColor=white)\n![Terraform](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FTerraform-844FBA?logo=terraform&logoColor=white)\n![uv](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Fuv-DE5FE9?logo=uv&logoColor=white)\n![Ruff](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FRuff-D7FF64?logo=ruff&logoColor=black)\n![mypy: strict](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Fmypy-strict-2A6DB2?logo=python&logoColor=white)\n\n**LLM providers:**\n![OpenAI](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FOpenAI-412991?logo=openai&logoColor=white)\n![Anthropic](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FAnthropic-191919?logo=anthropic&logoColor=white)\n![Google Gemini](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FGoogle%20Gemini-8E75B2?logo=googlegemini&logoColor=white)\n\nA reusable GitHub Actions workflow that reviews Terraform pull requests with a\nLangGraph multi-agent system and posts a single, severity-ranked sticky comment.\n\nThree specialists run in parallel over the PR's changed Terraform files:\n\n| Agent | Scanners | Looks for |\n|:--|:--|:--|\n| 🔒 **Security** | `tfsec` + `checkov` | misconfigurations, insecure defaults, exposed resources |\n| 💰 **Cost** | `infracost diff` | monthly cost deltas vs. the base branch |\n| 🎨 **Style** | `tflint` + `terraform fmt -check` | lint findings and formatting drift |\n\nScanners own *detection and severity*; an LLM only rewords each finding into a\nconcise, actionable sentence — so the set of findings is deterministic run to\nrun. Results are merged, de-duplicated, severity-ranked, and upserted as one\ncomment (edited in place on every push) rather than stacking up.\n\nEverything runs inside a prebuilt container (`ghcr.io\u002Finfiniumtek\u002Fterraform-review-agent`)\nthat bundles pinned `terraform`, `tfsec`, `tflint`, `infracost`, and `checkov`\nbinaries, so there are **no per-run tool installs**.\n\n---\n\n## Quick start\n\nAdd a workflow to your repo that calls the reusable workflow. A complete,\ncommented sample lives in [`examples\u002Fexample-caller.yml`](examples\u002Fexample-caller.yml);\nthe minimal version:\n\n```yaml\n# .github\u002Fworkflows\u002Fterraform-review.yml\nname: terraform-review\n\non:\n  pull_request:\n    types: [opened, synchronize, reopened, ready_for_review]\n    paths:\n      - \"**\u002F*.tf\"\n      - \"**\u002F*.tfvars\"\n      - \"**\u002F*.tf.json\"\n      - \"**\u002F*.tfvars.json\"\n\njobs:\n  terraform-review:\n    uses: infiniumtek\u002Fterraform-review-agent\u002F.github\u002Fworkflows\u002Fterraform-review.yml@v1\n    permissions:\n      contents: read         # checkout\n      pull-requests: write    # post\u002Fedit the sticky comment\n    with:\n      llm-provider: anthropic\n      llm-model: claude-sonnet-4-5\n      fail-on-severity: high  # fail the check on any high\u002Fcritical finding\n    secrets:\n      anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}\n      infracost-api-key: ${{ secrets.INFRACOST_API_KEY }}   # optional; enables cost agent\n```\n\nPin `@v1` (the major float) or a specific release tag such as `@v1.2.3`. The\n`paths` filter on the trigger decides whether the job spins up at all; the agent\nadditionally early-exits if no Terraform files actually changed.\n\n> **Manual re-runs:** `workflow_dispatch` events carry no PR context, so pass a\n> `pr-number` input when triggering manually. See the example caller for the\n> `github.event.pull_request.number || inputs.pr-number` pattern.\n\n---\n\n## Inputs\n\n| Input | Default | Description |\n|:--|:--|:--|\n| `llm-provider` | `openai` | `openai` \\| `anthropic` \\| `google`. |\n| `llm-model` | `gpt-4o` | Model id — **must match the provider**. The default suits `openai`; set this when choosing another provider (e.g. `claude-sonnet-4-5`). |\n| `fail-on-severity` | `none` | Gate CI when a finding meets\u002Fexceeds this floor: `critical` \\| `high` \\| `medium` \\| `low` \\| `info` \\| `none`. The comment is always posted first; `none` never fails the check. |\n| `pr-number` | `\"\"` | PR to review. Defaults to the triggering `pull_request` event; required for `workflow_dispatch` runs. |\n\n## Secrets\n\n| Secret | Required | Description |\n|:--|:--|:--|\n| `openai-api-key` \u002F `anthropic-api-key` \u002F `google-api-key` | one, matching `llm-provider` | LLM credentials. |\n| `infracost-api-key` | optional | Enables the 💰 cost agent. When unset, cost review is skipped (security + style still run). Get a free key at [infracost.io](https:\u002F\u002Fwww.infracost.io\u002F). |\n| `github-token` | optional | Defaults to the caller's `${{ github.token }}`. Override only if you need broader scope. |\n\n## Permissions\n\nThe calling job needs:\n\n```yaml\npermissions:\n  contents: read          # checkout the PR merge ref\n  pull-requests: write     # create\u002Fedit the sticky comment\n```\n\n---\n\n## Sample comment\n\n> ## Terraform Review Agent\n>\n> **5 findings** in 3 files — 1 critical, 2 high, 1 medium, 1 low\n>\n> _By agent:_ 🔒 Security 2 · 💰 Cost 1 · 🎨 Style 2\n>\n> 💰 **Infracost estimate:** **$520.50\u002Fmo** total · **+$120.00\u002Fmo** from this PR\n>\n> ### 🔴 Critical (1)\n>\n> | Severity | Issue | Location |\n> |:--|:--|:--|\n> | 🔴 🔒 | **S3 bucket has no server-side encryption configured.** \u003Cbr> 💡 Add an `aws_s3_bucket_server_side_encryption_configuration` block. \u003Cbr> \u003Csub>`tfsec:aws-s3-enable-bucket-encryption`\u003C\u002Fsub> | `modules\u002Fs3\u002Fmain.tf:12` |\n>\n> ### 🟠 High (2)\n>\n> | Severity | Issue | Location |\n> |:--|:--|:--|\n> | 🟠 💰 | **Estimated monthly cost change for `aws_instance.web`: +$120.00** \u003Cbr> 💡 Consider a smaller instance type or autoscaling. \u003Cbr> \u003Csub>`infracost:resource-delta`\u003C\u002Fsub> | `.` |\n> | 🟠 🔒 | **S3 bucket access logging is not enabled.** \u003Cbr> 💡 Enable access logging to an audit bucket. \u003Cbr> \u003Csub>`checkov:CKV_AWS_18`\u003C\u002Fsub> | `modules\u002Fs3\u002Fmain.tf:12` |\n>\n> ### 🟡 Medium (1)\n>\n> | Severity | Issue | Location |\n> |:--|:--|:--|\n> | 🟡 🎨 | **variable \"region\" is declared but never used.** \u003Cbr> 💡 Remove the unused variable. \u003Cbr> \u003Csub>`tflint:terraform_unused_declarations`\u003C\u002Fsub> | `main.tf:9` |\n>\n> \u003Cdetails>\u003Csummary>Low &amp; info (1)\u003C\u002Fsummary>\n>\n> #### 🔵 Low (1)\n>\n> | Severity | Issue | Location |\n> |:--|:--|:--|\n> | 🔵 🎨 | **File does not match `terraform fmt` canonical style.** \u003Cbr> 💡 Run `terraform fmt` locally and commit the result. \u003Cbr> \u003Csub>`terraform-fmt:unformatted`\u003C\u002Fsub> | `main.tf` |\n>\n> \u003C\u002Fdetails>\n\nCritical \u002F high \u002F medium findings show inline; `low` and `info` collapse into a\n`\u003Cdetails>` block so the comment stays scannable. Each location links to the\nexact file and line at the PR head. On the next push, this same comment is\nedited in place.\n\n---\n\n## How it works\n\n```\nGitHub PR event\n  └─► reusable workflow (terraform-review.yml)\n        └─► container: ghcr.io\u002Finfiniumtek\u002Fterraform-review-agent:v1\n              └─► python -m terraform_review_agent.entrypoint\n                    └─► LangGraph:\n                          start ─► [security ∥ cost ∥ style] ─► aggregator ─► post_comment\n```\n\n- **start** filters the PR to Terraform files and early-exits if none changed.\n- **security \u002F cost \u002F style** run their scanners, then an LLM rewords the\n  findings (it cannot change severity, file, line, or rule).\n- **aggregator** dedupes by `(file, rule, line)`, severity-ranks, and renders\n  the markdown.\n- **post_comment** upserts the sticky comment via a hidden HTML marker.\n\nScanner versions are pinned in the container image — bumping one is a\nrebuild-image PR in this repo, not an edit to your workflow file.\n\n---\n\n## Local development\n\nRequires Python 3.13 + [uv](https:\u002F\u002Fdocs.astral.sh\u002Fuv\u002F). Scanners only run\ninside the container; the host test suite mocks them.\n\n```bash\nmake install              # create .venv and sync pinned deps\nmake fmt lint type test    # format, lint, mypy --strict, pytest\n```\n\nSee [`CLAUDE.md`](CLAUDE.md) for the full project contract and layout.\n\n### Run the agent against a real PR locally\n\n`make run` executes the CLI **inside the container**, which bundles every\nscanner (`terraform` \u002F `tfsec` \u002F `tflint` \u002F `infracost` \u002F `checkov`) — your host\n`.venv` does not. For an external repo the entrypoint clones the PR's merge ref\ninto a scratch dir, scans it, and upserts the sticky comment on that PR, exactly\nas the reusable workflow does in CI.\n\n1. **Configure `.env`** (copy `.env.example`). For an end-to-end run you need:\n\n   ```env\n   GITHUB_TOKEN=ghp_...            # read access to the repo + write access to its PRs\n   DEFAULT_LLM_PROVIDER=anthropic   # openai | anthropic | google\n   DEFAULT_LLM_MODEL=claude-sonnet-4-5\n   ANTHROPIC_API_KEY=sk-ant-...     # the key matching DEFAULT_LLM_PROVIDER\n   INFRACOST_API_KEY=ico-...        # optional — enables the cost agent\n   ```\n\n2. **Build the image** (bundles the pinned scanners). Re-run only after a\n   dependency or scanner-version bump; `.\u002Fsrc` is bind-mounted, so code edits\n   need no rebuild:\n\n   ```bash\n   make docker-build\n   ```\n\n3. **Review a PR.** Point `--repository`\u002F`--pr-number` at any repo your token\n   can reach. Using the sample Cloud Run service repo\n   [`spanosg131\u002Fgcp-test-cloudrun-service`](https:\u002F\u002Fgithub.com\u002Fspanosg131\u002Fgcp-test-cloudrun-service)\n   — open (or reuse) a PR there that touches a `.tf` file, then:\n\n   ```bash\n   make run ARGS=\"--repository spanosg131\u002Fgcp-test-cloudrun-service --pr-number 2\"\n   ```\n\n   The agent fetches the PR, runs the three specialists, and posts\u002Fedits the\n   sticky comment on PR #2. (You can also set `GITHUB_REPOSITORY` \u002F\n   `GITHUB_PR_NUMBER` in `.env` and run `make run` with no `ARGS`.)\n\n> **Notes**\n> - The token needs `pull-requests: write` to post the comment and read access\n>   to clone the PR; without `INFRACOST_API_KEY` the 💰 cost agent is skipped.\n> - To inspect output without posting, point at a PR in a throwaway repo, or\n>   review the structured logs the run prints to stderr.\n\n---\n\n## License\n\nMIT\n","terraform-review-agent 是一个可重用的 GitHub Action，用于审查 Terraform 拉取请求中的安全、成本和代码风格问题。项目基于 LangGraph 多代理系统运行，并将检查结果以单一严重性排序的评论形式发布到 PR 中。它集成了 `tfsec` 和 `checkov` 用于检测安全配置错误，`infracost diff` 评估成本变化，以及 `tflint` 和 `terraform fmt -check` 确保代码格式一致性和规范性。所有分析工作在一个预构建容器内完成，避免了每次执行时重新安装工具的需求，确保了流程的一致性和效率。此工具非常适合需要自动化 CI\u002FCD 流程中对 Terraform 配置进行质量控制的场景。","2026-06-11 03:58:46","CREATED_QUERY"]