{"slug": "infrafactory", "title": "InfraFactory", "summary": "InfraFactory, an open-source infrastructure-as-code tool, now generates and validates OpenTofu configurations across AWS, GCP, and Scaleway using LLMs against deterministic mock servers in seconds, eliminating the need for cloud credentials or real API calls. The tool closes the slow, expensive feedback loop of hand-iterating Terraform against real clouds by running scenario YAML through a four-layer validation pipeline—static analysis, mock deployment, real deployment, and destruction—with structured failures fed back into subsequent LLM iterations. Users can run end-to-end infrastructure validation locally in approximately 60 seconds using three commands, with the system converging on successful deployments after an average of two LLM iterations.", "body_md": "Scenario-driven OpenTofu generation and validation across **AWS**, **GCP**, and **Scaleway** — generated by an LLM, validated against deterministic mock servers in seconds, optionally deployed against real cloud APIs.\n\nHand-iterating IaC against real cloud APIs is slow, expensive, and flaky. LLMs are good at writing terraform but bad at debugging \"why didn't this apply\" — the error messages are layers deep and the feedback loop is 90 seconds per attempt against a real cloud.\n\nInfraFactory closes that loop. You write a scenario YAML declaring intent (resources + acceptance criteria). The pipeline generates HCL with an LLM, validates it through four layers (static → mock-deploy → real-deploy → destruction), and feeds structured failures back into the next iteration's prompt. Subsecond mock validation, no cloud credentials required.\n\n`infrafactory run scenarios/training/gcp-pubsub.yaml`\n\nagainst `fakegcp`\n\n: scenario YAML → 3-phase LLM generation → 3-layer validation → AI's first iteration fails (fakegcp rejects `google_project_service`\n\n) → feedback fed into the next iteration's prompt → second iteration converges to `Status: success`\n\n. Demonstrates the feedback loop that makes the pipeline robust against partial mock coverage. Re-record with `./docs/demo/record.sh`\n\n(requires `make mocks-up`\n\n+ an LLM credential in env).\n\nActually runs `gcp-pubsub`\n\nthrough the UI: scenario page → click Run → Live page populates with iteration stages live as the AI tries to build the topic + subscription against fakegcp → iteration 1 fails (fakegcp doesn't model `google_project_service`\n\nyet) → AI sees the feedback in iteration 2's prompt and converges → success banner → per-run IaC viewer shows the converged HCL with auto-injected `*_custom_endpoint`\n\noverrides pointing at fakegcp. ~2min end-to-end, 2 LLM iterations. Re-record with `make demo-ui-run`\n\n(needs `make mocks-up`\n\n+ Claude CLI authenticated).\n\nBrowser walkthrough of `full-stack-paris`\n\n(the most resource-dense scenario) — no `infrafactory run`\n\n, just a tour of the Scenario / Runs / Compare / Pitfalls / Diagnostics pages so viewers see the UI surface (24s, no LLM credit needed). Re-record with `make demo-ui`\n\n.\n\nThree commands gets you a working LLM-driven infra pipeline against\nlocal mock servers, validates a real terraform scenario end-to-end,\nand tears everything down cleanly. **No cloud credentials. No real\ncloud calls. ~60 seconds.**\n\n```\n# 1. Clone the four repos side-by-side (sibling layout).\nmkdir -p ~/dev && cd ~/dev\nfor repo in infrafactory fakeaws fakegcp mockway; do\n  git clone https://github.com/redscaresu/$repo.git\ndone\ncd infrafactory\n\n# 2. Bring up the full stack — mockway + fakegcp + fakeaws +\n#    SeaweedFS (S3) + the SvelteKit UI — in one command, backgrounded.\nmake up\n\n# 3. Run the fastest scenario end-to-end (~30s, 1 iteration).\n./bin/infrafactory run scenarios/training/block-paris.yaml --config infrafactory.yaml\n\n# 4. (Optional) point a browser at http://127.0.0.1:4173 to see the\n#    same scenario in the UI with per-iteration stage breakdown.\n\n# 5. Tear it all down.\nmake down\n```\n\nYou should see `Status: success`\n\nand `run/terminal_reason: pass (target_reached)`\n\nafter step 3. The LLM generated a Scaleway Block Storage volume in HCL,\nthe static validator + mockway apply + topology test + destroy/orphan-check\nall passed. The default `run`\n\ntears the resources down at the end of the\ntest cycle (the scenario's `destruction: no_orphans`\n\nacceptance criterion),\nso `http://127.0.0.1:8080/mock/state`\n\nreports empty collections. To inspect\nthe post-apply state, add `--no-destroy`\n\nto the run command.\n\nUse `make status`\n\nat any time to see which of the six ports\n(`8080`\n\n, `8081`\n\n, `8082`\n\n, `9090`\n\n, `9091`\n\n, `4173`\n\n) are listening.\n\n- Go 1.25+\n- OpenTofu (\n[https://opentofu.org](https://opentofu.org)) on PATH - Docker (for the SeaweedFS S3 backend used by AWS scenarios) — only needed when running AWS-cloud scenarios; Scaleway-only and GCP-only demos don't require it\n- An LLM credential, see below\n\nInfraFactory drives generation through the Claude CLI by default —\nsign in with `claude login`\n\nonce and it works out of the box. To use\na different model via OpenRouter instead, export `OPENROUTER_API_KEY`\n\nand set `agent.type: openrouter`\n\nin `infrafactory.yaml`\n\n. Both paths\nhit the same 3-phase generation pipeline (`plan → write HCL → self-review`\n\n); pick whichever fits your budget/latency profile.\n\n| Port | Service | Why |\n|---|---|---|\n| 8080 | mockway | Scaleway HTTP API mock |\n| 8081 | fakegcp | GCP API mock |\n| 8082 | fakeaws | AWS API mock |\n| 9090 | SeaweedFS | S3-compatible backend (Docker; AWS-only scenarios) |\n| 9091 | s3router (S80) | HTTP shim that fans S3 traffic across SeaweedFS (data plane) and fakeaws (`?publicAccessBlock` subresource SeaweedFS doesn't model). `infrafactory.yaml` `s3.url` points here, not directly at SeaweedFS. See `cmd/s3router/` . |\n| 4173 | infrafactory UI | SvelteKit dashboard + scenario runner |\n\nAfter `make up`\n\n, any of these run against the same stack:\n\n```\n./bin/infrafactory run scenarios/training/gcp-full-stack.yaml      # cloud: gcp      → fakegcp\n./bin/infrafactory run scenarios/training/aws-full-stack.yaml      # cloud: aws      → fakeaws\n./bin/infrafactory run scenarios/training/full-stack-paris.yaml    # cloud: scaleway → mockway\n```\n\nThere are 39 scenarios under `scenarios/training/`\n\n. Inspect generated\nHCL at `output/<scenario>/`\n\n(overwritten each run) and immutable\nper-run artifacts at `.infrafactory/runs/<scenario>/<run-id>/`\n\n.\n\nA successful run ends with `Status: success`\n\nand `run/terminal_reason: pass (target_reached)`\n\n. If a validation layer fails, the failure JSON feeds into the next iteration's LLM prompt and the loop retries (default budget: 5 iterations).\n\n`make up`\n\nalready started the UI on `http://127.0.0.1:4173`\n\n. If you'd\nrather start just the UI (without the mocks), use `make run`\n\n.\n\nThe UI provides a scenario browser (edit YAML, see real-time validation), run controls (`--clean`\n\n/ `--no-destroy`\n\n/ Layer-3 toggles), a live page with per-iteration timer and stage indicators, per-run IaC viewer with diffs, and a pitfalls editor. See the UI demo above for the `full-stack-paris`\n\nwalkthrough.\n\n```\nscenario YAML  ──▶  3-phase LLM generation  ──▶  3-layer validation  ──▶  retry on failure\n   (intent)         plan → write HCL → review     static / mock / real     (5x budget)\n```\n\n**Three-phase generation** (`prompts/{aws,gcp,scaleway}/phase{1,2,3}*.md`\n\n):\n\n**Plan architecture**— scenario YAML + T-shirt size mappings → JSON architecture plan** Generate HCL**— architecture + cloud-specific pitfalls + provider schema → OpenTofu`.tf`\n\nfiles**Self-review**— generated HCL → 10-point checklist → corrections or`NO ISSUES FOUND`\n\n**Three-layer validation** (each gates the next):\n\n**Static**—`tofu init/validate/plan`\n\n+ OPA`deny`\n\npolicies on the plan JSON**Mock deploy**—`tofu apply`\n\nagainst the matching mock; topology checks against`/mock/state`\n\n; OPA`deny_state`\n\npolicies; mock-enforced FK integrity**Real deploy**(optional, gated by`validation.layers.sandbox_deploy.enabled`\n\n) —`tofu apply`\n\nagainst the real cloud with auto-destroy on failure\n\nOn failure, the structured failure (`layer`\n\n, `stage`\n\n, `check`\n\n, `detail`\n\n, `failure_class`\n\n) is appended to the next iteration's prompt as a `<feedback>`\n\nblock so the LLM sees what specifically broke.\n\n**Auto-learning loop**: when an iteration self-corrects (iter N+1 succeeds after iter N failed) OR a run terminates with `stuck`\n\n/`repair_budget_exhausted`\n\n, the failure detail is extracted into `pitfalls/<cloud>.yaml`\n\nso future runs of any scenario in that cloud see the lesson up front. Every entry is `source: learned`\n\n— the system seeds itself from real runs and a CI ratchet (`TestPitfallsNoHumanSeeding`\n\n) rejects hand-authored entries.\n\nWhen a run reaches `target_reached`\n\nAFTER ≥1 failing iteration, a second extractor (`source: learned_from_diff`\n\n) diffs the failing iteration's HCL against the passing iteration's HCL and emits the minimal HCL snippet that resolved the failure — prescriptive guidance derived from real runs, not hand-written. This unblocked the \"prompt-collapse\" effort: prescriptive rules in the phase-2 prompts retired as the system's learned pitfalls replaced them. See `ADR-0012`\n\n(and the N11 retirement framework in `ADR-0018`\n\n) for the dynamic-pitfalls contract.\n\nEach cloud has the same set of extension points; the scenario's `cloud:`\n\nfield drives every dispatch.\n\n| Extension point | AWS | GCP | Scaleway |\n|---|---|---|---|\n| Mock server |\n`fakeaws` |\n\n`:8082`\n\n) + [SeaweedFS](https://github.com/seaweedfs/seaweedfs)for S3 (\n\n`:9090`\n\n)[(](https://github.com/redscaresu/fakegcp)`fakegcp`\n\n`:8081`\n\n)[(](https://github.com/redscaresu/mockway)`mockway`\n\n`:8080`\n\n)`hashicorp/aws ~> 5.70`\n\n`hashicorp/google >= 5.0`\n\n(v5 for IAM SA)`scaleway/scaleway >= 2.50`\n\n`prompts/aws/`\n\n`prompts/gcp/`\n\n`prompts/scaleway/`\n\n`pitfalls/aws.yaml`\n\n`pitfalls/gcp.yaml`\n\n`pitfalls/scaleway.yaml`\n\n`policies/aws/`\n\n`policies/gcp/`\n\n`policies/scaleway/`\n\n`scenarios/training/aws-*.yaml`\n\n`scenarios/training/gcp-*.yaml`\n\n`scenarios/training/*-paris.yaml`\n\n`aws-full-stack.yaml`\n\n`gcp-full-stack.yaml`\n\n`full-stack-paris.yaml`\n\nEach first-party mock is wire-shape compatible with the matching real provider, enforced by an `examples/working/<svc>`\n\nsmoke harness in the mock's own repo (`apply → plan -detailed-exitcode 0 → destroy`\n\n). See each mock's README for the API-compatibility contract.\n\nAWS S3 is the exception: bucket sub-resource reads (GetBucketPolicy / GetBucketTagging / etc.) are served by SeaweedFS instead of fakeaws's stripped-down S3 handler — `terraform-provider-aws`\n\n's bucket Read flow needs the full management surface. SeaweedFS doesn't model `?publicAccessBlock`\n\n, so a small reverse-proxy shim (`cmd/s3router/`\n\n, S80) fronts both backends: it routes `?publicAccessBlock`\n\nto fakeaws and fans `PUT/DELETE /<bucket>`\n\nto both so the bucket exists in both stores. Rationale + the SeaweedFS-vs-Adobe-S3Mock-vs-Garage-vs-LocalStack evaluation is documented in [ CONCEPT.md](/redscaresu/infrafactory/blob/main/CONCEPT.md) under \"Third-Party Mock Integration\".\n\nAdding a new cloud requires: prompt templates, pitfalls file, topology derivation rules, mock server, OPA policies, and training scenarios. Dispatch is driven by `cloudMockStateRouter`\n\n, `cloudConstraintPolicies`\n\n, `filterPolicyPathsByCloud`\n\n, `ExtractProviderSchemaForCloud`\n\n, and `detectCloud`\n\n.\n\n| Command | Purpose |\n|---|---|\n`infrafactory init --path <file>` |\nScaffold a new scenario YAML |\n`infrafactory validate <scenario>` |\nLayer 1 static checks only |\n`infrafactory generate <scenario>` |\n3-phase LLM generation only |\n`infrafactory test <scenario>` |\nLayers 1-4 (no retry loop) |\n`infrafactory run <scenario>` |\nFull pipeline with retry loop + holdouts |\n`infrafactory mock start/stop/status/logs` |\nManage the Mockway (Scaleway) mock only. Use `make mocks-up` /`-down` /`-status` /`-logs` to manage all three (mockway/fakegcp/fakeaws). |\n`infrafactory mock reset` |\nReset state across every configured mock backend (mockway + fakegcp + fakeaws + s3 cascade in one call). Use this between scenarios in sweep harnesses instead of bare `curl` to `/mock/reset` — only this path cascades to the SeaweedFS s3 backend. |\n`infrafactory ui` |\nServe the web dashboard |\n\nAuxiliary binary (`bin/n10extract`\n\n, built by `make build`\n\n) drives the\nN10/N13 prescriptive-pitfall extractors against a recorded run\ndirectory and emits a candidate `pitfalls/<cloud>.yaml`\n\nsnippet on\nstdout — used by the N11 retirement protocol's step 2 when the\norganic learning loop hasn't fired for the target pattern. See\n`docs/decisions/0012-dynamic-pitfalls.md`\n\nand\n`docs/decisions/0018-n11-retirement-criteria.md`\n\nfor the\nauto-learning architecture.\n\nKey flags for `run`\n\n: `--clean`\n\n(fresh start), `--no-destroy`\n\n(keep resources for incremental follow-up), `--repair-iterations-max N`\n\n(retry budget, default 5).\n\nScenario YAML declares criteria that gate run success:\n\n| Type | Layer 2 (mock) | Layer 3 (real) |\n|---|---|---|\n`connectivity` |\nTopology graph query | TCP connect with retry |\n`http_probe` |\nTopology graph query | HTTP GET, expect 2xx/3xx |\n`dns_resolution` |\nAuto-pass (informational) | DNS A/AAAA lookup with retry |\n`policy` |\nOPA rules on plan + state | Same |\n`destruction` |\nOrphan check after destroy | Same + real destroy |\n\n```\ninfrafactory/\n├── cmd/infrafactory/      CLI + embedded UI build\n├── internal/\n│   ├── cli/               command tree, runtime wiring\n│   ├── config/            infrafactory.yaml loader\n│   ├── scenario/          YAML loader + JSON schema validation\n│   ├── generator/         3-phase LLM pipeline (Claude / OpenRouter)\n│   ├── harness/           static/mock/destroy primitives + provider schema extraction\n│   ├── feedback/          failure-signature modelling, stuck detection\n│   ├── runstore/          .infrafactory/runs persistence\n│   └── e2e/               cross-repo end-to-end tests\n├── ui/                    SvelteKit dashboard\n├── scenarios/training/    per-cloud training scenarios\n├── prompts/{aws,gcp,scaleway}/  phase 1-3 prompt templates\n├── pitfalls/{aws,gcp,scaleway}.yaml  static + learned pitfalls\n├── policies/{aws,gcp,scaleway}/  OPA rego files\n├── scenario.schema.json   scenario contract\n└── infrafactory.yaml      runtime config contract\n```\n\nPre-commit hook runs gitleaks + `make test`\n\n(Go unit + UI unit + Playwright e2e). Wire it once:\n\n```\nmake install-hooks\n```\n\nCommon targets:\n\n```\nmake test                  # full suite\nmake test-unit             # Go only\nmake ui-test-e2e           # Playwright only\n\n# go-run mock path (foreground subprocesses; quick iteration on mock code):\nmake mocks-up              # start mockway + fakegcp + fakeaws (+ SeaweedFS via Docker)\nmake mocks-down            # stop them all\nmake mocks-status          # show port + PID for each (probes lsof, not just pidfiles)\nmake mocks-restart         # mocks-down + mocks-up; picks up sibling-repo source changes\nmake mockway-restart       # restart just one mock (also: fakegcp-restart, fakeaws-restart)\n\n# container mock path (alternative — needs Docker, no Go install required;\n# wires identical ports 8080/8081/8082 so scenarios + infrafactory.yaml\n# don't care which path is active):\nmake mocks-up-containers   # build + start fakeaws + fakegcp + mockway\nmake mocks-down-containers\nmake mocks-pull            # refresh published GHCR images\n\n# canonical 39-scenario sustain-ratchet sweep (S78). Drives\n# `infrafactory run` across every scenario under scenarios/training/\n# with `infrafactory mock reset` between scenarios. Output lands in\n# /tmp/sweep-39/summary.tsv. Discards pitfall additions (sweep noise).\nmake sweep-39\n\n# session-close hygiene — sweeps lingering sweep scripts, log tails,\n# and stray mock test binaries (compiled to /tmp/ by `go test`) on\n# non-canonical ports. Safe to run any time; idempotent.\nmake clean-bg\n```\n\nWhen working on a sibling mock repo (`../fakegcp`\n\n, `../fakeaws`\n\n,\n`../mockway`\n\n), `make mocks-up`\n\nspins up those mocks via `go run`\n\nwhich compiles ONCE at boot. After committing a change in the\nsibling repo, run `make <mock>-restart`\n\n(e.g. `make fakegcp-restart`\n\n)\nto pick up the new source — otherwise the running mock keeps\nserving the stale binary, a footgun that's wasted several debugging\nsessions worth of time.\n\nGated e2e tests (cross-repo, require `tofu`\n\n+ the sibling mock repos checked out):\n\n```\nINFRAFACTORY_ENABLE_E2E=1 go test ./internal/e2e/...\n```\n\n— component overview and validation-layer details`docs/architecture.md`\n\n— ADRs (dynamic pitfalls, topology derivation, etc.)`docs/decisions/`\n\n— per-scenario pass/fail snapshot + failure classification`docs/scenario-failure-matrix.md`\n\n— entry point for AI agents working on this repo`AGENTS.md`\n\n— code conventions, PR contract, quality gates`CONTRIBUTING.md`\n\n— disclosure policy`SECURITY.md`\n\n`CHANGELOG.md`\n\nApache 2.0 — see [LICENSE](/redscaresu/infrafactory/blob/main/LICENSE).", "url": "https://wpnews.pro/news/infrafactory", "canonical_source": "https://github.com/redscaresu/infrafactory", "published_at": "2026-06-03 15:40:38+00:00", "updated_at": "2026-06-03 15:49:21.214189+00:00", "lang": "en", "topics": ["ai-infrastructure", "ai-tools", "large-language-models", "generative-ai", "mlops"], "entities": ["InfraFactory", "OpenTofu", "AWS", "GCP", "Scaleway", "LLM", "HCL", "fakegcp"], "alternates": {"html": "https://wpnews.pro/news/infrafactory", "markdown": "https://wpnews.pro/news/infrafactory.md", "text": "https://wpnews.pro/news/infrafactory.txt", "jsonld": "https://wpnews.pro/news/infrafactory.jsonld"}}