terraui 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. terraui-0.1.0/.gitignore +38 -0
  2. terraui-0.1.0/BACKEND_SPEC.md +388 -0
  3. terraui-0.1.0/LICENSE +21 -0
  4. terraui-0.1.0/PKG-INFO +156 -0
  5. terraui-0.1.0/README.md +112 -0
  6. terraui-0.1.0/pyproject.toml +66 -0
  7. terraui-0.1.0/src/terraui/__init__.py +3 -0
  8. terraui-0.1.0/src/terraui/ai/__init__.py +0 -0
  9. terraui-0.1.0/src/terraui/ai/chat.py +98 -0
  10. terraui-0.1.0/src/terraui/cli.py +242 -0
  11. terraui-0.1.0/src/terraui/clouds/__init__.py +0 -0
  12. terraui-0.1.0/src/terraui/clouds/auth.py +76 -0
  13. terraui-0.1.0/src/terraui/clouds/preflight.py +192 -0
  14. terraui-0.1.0/src/terraui/demo.py +106 -0
  15. terraui-0.1.0/src/terraui/discovery/__init__.py +1 -0
  16. terraui-0.1.0/src/terraui/discovery/hcl.py +106 -0
  17. terraui-0.1.0/src/terraui/discovery/scanner.py +115 -0
  18. terraui-0.1.0/src/terraui/execution/__init__.py +0 -0
  19. terraui-0.1.0/src/terraui/execution/command.py +51 -0
  20. terraui-0.1.0/src/terraui/execution/executor.py +176 -0
  21. terraui-0.1.0/src/terraui/models.py +116 -0
  22. terraui-0.1.0/src/terraui/server/__init__.py +1 -0
  23. terraui-0.1.0/src/terraui/server/app.py +364 -0
  24. terraui-0.1.0/src/terraui/shell/__init__.py +0 -0
  25. terraui-0.1.0/src/terraui/shell/pty.py +113 -0
  26. terraui-0.1.0/src/terraui/state/__init__.py +0 -0
  27. terraui-0.1.0/src/terraui/state/inspect.py +53 -0
  28. terraui-0.1.0/src/terraui/store/__init__.py +1 -0
  29. terraui-0.1.0/src/terraui/store/db.py +85 -0
  30. terraui-0.1.0/src/terraui/web/index.html +829 -0
  31. terraui-0.1.0/tests/test_api.py +93 -0
  32. terraui-0.1.0/tests/test_command.py +64 -0
  33. terraui-0.1.0/tests/test_discovery.py +51 -0
  34. terraui-0.1.0/tests/test_preflight.py +85 -0
@@ -0,0 +1,38 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .eggs/
6
+ build/
7
+ dist/
8
+ *.egg
9
+
10
+ # Virtual envs
11
+ .venv/
12
+ venv/
13
+ env/
14
+
15
+ # Tooling / caches
16
+ .pytest_cache/
17
+ .mypy_cache/
18
+ .ruff_cache/
19
+ .coverage
20
+ htmlcov/
21
+
22
+ # Local runtime / scratch
23
+ *.out
24
+ pytest.out
25
+ terraui.db
26
+ *.sqlite
27
+ *.sqlite3
28
+
29
+ # Editors / OS
30
+ .vscode/
31
+ .idea/
32
+ .DS_Store
33
+ Thumbs.db
34
+
35
+ # Secrets / env
36
+ .env
37
+ .env.*
38
+ !.env.example
@@ -0,0 +1,388 @@
1
+ # TerraUi — Backend Build Prompt / Engineering Spec
2
+
3
+ > Hand this document to an engineer (or to Claude Code) as the build brief for the
4
+ > TerraUi backend. The frontend (`TerraUi.dc.html`) is the source of truth for the
5
+ > product surface; this spec defines the engine that makes it real.
6
+
7
+ ---
8
+
9
+ ## 0. Mission
10
+
11
+ TerraUi is a **local-first control plane for Terraform and Terragrunt**. An org points it at
12
+ the directory that holds all their IaC repos; TerraUi discovers every unit (standalone
13
+ Terraform *and* Terragrunt), and gives a single web UI to:
14
+
15
+ - inventory every stack across clouds (AWS, GCP, Azure) and environments,
16
+ - run `plan` / `apply` / `destroy` with a flag picker, streamed live,
17
+ - detect and reconcile **drift**,
18
+ - view **diffs** and full plan output,
19
+ - see **who holds the state lock** and acquire/release it,
20
+ - read **history / audit** (who changed what, from which PR/commit),
21
+ - orchestrate **Terragrunt dependency-ordered** `run-all`,
22
+ - generate plans from **GitHub & GitLab PRs**,
23
+ - expose a **Cloud Shell** (real terminal) wired to the user's local shell + cloud SDKs,
24
+ - answer questions via an **AI assistant**.
25
+
26
+ Install path the user expects:
27
+
28
+ ```bash
29
+ pip install terraui
30
+ cd ~/acme/infra # the folder that contains all IaC repos
31
+ terraui start # discovers everything, opens http://localhost:8787
32
+ ```
33
+
34
+ **Core principle:** TerraUi runs commands on the *user's own machine*, using the *user's own
35
+ shell* (PowerShell on Windows, zsh/bash on macOS & Linux) and the *user's existing cloud
36
+ credentials*. It never stores secrets and never invents its own auth — it shells out exactly
37
+ as the engineer would by hand.
38
+
39
+ ---
40
+
41
+ ## 1. Tech stack
42
+
43
+ | Concern | Choice | Notes |
44
+ |---|---|---|
45
+ | Language | **Python 3.10+** | Matches `pip install` expectation. |
46
+ | Web framework | **FastAPI** + **Uvicorn** | REST + WebSocket in one app. |
47
+ | Async | `asyncio` + `anyio` | Subprocess streaming, concurrency. |
48
+ | CLI | **Typer** (or Click) | `terraui start|server|agent|scan`. |
49
+ | Terminal | **ptyprocess** / `pywinpty` (Windows) + **xterm.js** on the front | Real PTY. |
50
+ | HCL parsing | **python-hcl2** + targeted regex fallbacks | Parse providers, backends, deps. |
51
+ | Local store | **SQLite** (local mode) → **Postgres** (server mode) via SQLAlchemy | Runs, audit, drift snapshots. |
52
+ | Realtime | WebSockets | Run output, terminal, drift events. |
53
+ | Packaging | **pyproject.toml** (hatchling/poetry), console_scripts entry point | Ships the built frontend as package data. |
54
+
55
+ The compiled frontend (a single self-contained HTML bundle of `TerraUi.dc.html`) is shipped
56
+ inside the wheel and served at `/`. `terraui start` opens the browser to it.
57
+
58
+ ---
59
+
60
+ ## 2. CLI surface
61
+
62
+ ```
63
+ terraui start [PATH] # local mode: scan PATH (default cwd), serve UI + executor
64
+ --port 8787
65
+ --scan ./live ./modules # extra roots / globs
66
+ --no-open # don't auto-open browser
67
+ --shell powershell|zsh|bash # override detected shell
68
+ --drift-interval 30m # background drift scan cadence (0 = off)
69
+
70
+ terraui scan [PATH] --json # print discovered units as JSON, no server (CI/debug)
71
+
72
+ terraui server --config terraui.yaml # team mode: central control plane (SSO, RBAC, Postgres)
73
+ terraui agent --server URL --label prod-runner # remote executor that registers with a server
74
+ ```
75
+
76
+ Local mode = single binary, single user, zero infra. Server mode = shared deployment;
77
+ **agents** hold the cloud creds and do the execution, the server never does (see §11).
78
+
79
+ ---
80
+
81
+ ## 3. Architecture
82
+
83
+ ```
84
+ ┌──────────────────────────────────────────────┐
85
+ Browser ──► │ FastAPI app │
86
+ (TerraUi UI) │ ├─ REST /api/... (inventory, runs) │
87
+ ▲ WS │ ├─ WS /ws/run/{id} (live plan output) │
88
+ └─────────┤ ├─ WS /ws/term/{id} (PTY terminal) │
89
+ │ ├─ Discovery service (HCL walk + parse) │
90
+ │ ├─ Execution engine (subprocess/PTY) │
91
+ │ ├─ Auth probe (aws/gcloud/az) │
92
+ │ ├─ State+lock inspector (per backend) │
93
+ │ ├─ Drift scheduler │
94
+ │ ├─ VCS connectors (GitHub/GitLab) │
95
+ │ └─ AI service (LLM proxy + repo RAG) │
96
+ └──────────────────────────────────────────────┘
97
+ │ subprocess (user's shell)
98
+
99
+ terraform / terragrunt / aws / gcloud / az on the local machine
100
+ ```
101
+
102
+ ---
103
+
104
+ ## 4. Discovery service
105
+
106
+ On `start`, walk the scan roots and build the stack inventory.
107
+
108
+ **Detection rules**
109
+ - A directory with `*.tf` files → a **Terraform unit**.
110
+ - A directory with `terragrunt.hcl` → a **Terragrunt unit** (takes precedence; the surrounding
111
+ `live/<env>/<stack>` convention defines env + stack name).
112
+ - Read the `terraform { backend "<type>" { ... } }` block to find the **state location**
113
+ (s3/gcs/azurerm/local/remote) and any **lock table/lease**.
114
+ - Parse `provider "<name>" { ... }` and `required_providers` to infer the **cloud**
115
+ (`aws`→AWS, `google`/`google-beta`→GCP, `azurerm`→Azure). A unit may be multi-cloud.
116
+ - For Terragrunt, parse `dependency "<x>" { config_path = ... }` and `dependencies { paths = [...] }`
117
+ to build the **DAG** used for `run-all` ordering.
118
+ - Derive **environment** from path (`live/prod/...`, `*-prod`, workspace) — make this
119
+ configurable via `terraui.yaml` overrides.
120
+
121
+ **Output:** a normalized model the frontend consumes (one row per stack):
122
+
123
+ ```jsonc
124
+ {
125
+ "id": "eks-prod",
126
+ "name": "eks-cluster",
127
+ "env": "prod",
128
+ "tool": "terragrunt", // or "terraform"
129
+ "clouds": ["aws"],
130
+ "path": "live/prod/eks-cluster",
131
+ "vcs": { "host": "github", "repo": "acme/infra-live", "subdir": "live/prod/eks-cluster" },
132
+ "backend": { "type": "s3", "bucket": "acme-tfstate", "key": "prod/eks.tfstate",
133
+ "lock": { "type": "dynamodb", "table": "acme-tf-locks" } },
134
+ "deps": ["net-prod"],
135
+ "resourceCount": 88,
136
+ "status": "drift|healthy|running|error|plan_pending",
137
+ "drift": 3,
138
+ "lock": null
139
+ }
140
+ ```
141
+
142
+ Discovery must be **incremental & watchable** — re-scan on file change (watchdog) so the UI
143
+ stays live as repos change. Cache parse results keyed by file mtime.
144
+
145
+ ---
146
+
147
+ ## 5. Execution engine
148
+
149
+ The heart of the product. Runs `terraform`/`terragrunt` as a child process **in the unit's
150
+ directory**, using the user's shell, streaming output to the browser.
151
+
152
+ **Requirements**
153
+ - Build the command from a structured request (see flag model below) — never string-concat
154
+ untrusted input; pass args as a list, validate the action against an allow-list
155
+ (`plan|apply|destroy|init|validate|output|state list|force-unlock`).
156
+ - Spawn via the detected shell so the user's PATH, profile, and cloud CLI shims are present:
157
+ - Windows: `pwsh -NoLogo -Command <cmd>` (fallback `powershell.exe`).
158
+ - macOS/Linux: `$SHELL -lc <cmd>` (login shell to load creds/profile).
159
+ - Stream **stdout+stderr** line-buffered over `WS /ws/run/{run_id}`. Emit structured events:
160
+ `{type:"line", stream:"stdout", text}`, `{type:"status", status}`, `{type:"summary", add, change, destroy}`.
161
+ - Parse `terraform plan -json` / `-detailed-exitcode` to populate the **diff** and the
162
+ `+add ~change -destroy` summary the UI shows. Prefer `-json` for machine parsing; keep the
163
+ raw text for the log pane.
164
+ - Persist every run: id, stack, action, full command, actor, trigger (manual/PR/merge/drift/schedule),
165
+ exit code, duration, summary, and the complete log. This is the **audit trail**.
166
+ - Concurrency: serialize runs per stack (one lock per state); allow parallel across independent
167
+ stacks. For Terragrunt `run-all`, resolve the DAG and execute level-by-level honoring `--terragrunt-parallelism`.
168
+
169
+ **Flag model** (mirrors the UI's run picker — `cmdVM` in the frontend):
170
+
171
+ ```jsonc
172
+ {
173
+ "stackId": "rds-prod",
174
+ "action": "plan", // plan | apply | destroy
175
+ "runAll": false, // terragrunt run-all
176
+ "flags": {
177
+ "refresh": true, // -refresh=false when false
178
+ "lock": true, // -lock=false when false
179
+ "autoApprove": false, // -auto-approve (apply/destroy only)
180
+ "noColor": false, // -no-color
181
+ "nonInteractive": true, // --terragrunt-non-interactive
182
+ "parallelism": 10, // -parallelism=N
183
+ "target": "", // -target=ADDR (repeatable)
184
+ "varFile": "env/prod.tfvars" // -var-file=FILE (repeatable)
185
+ }
186
+ }
187
+ ```
188
+
189
+ `build_command()` must produce exactly what the UI previews, e.g.
190
+ `terragrunt run-all plan -var-file=env/prod.tfvars --terragrunt-non-interactive`.
191
+
192
+ ---
193
+
194
+ ## 6. Cloud Shell (PTY terminal)
195
+
196
+ A genuine interactive terminal, not a fake. `WS /ws/term/{session}` bridges xterm.js to a PTY
197
+ running the user's shell in the IaC root. Supports `aws`, `gcloud`, `az`, `terraform`,
198
+ `terragrunt`, `git`, etc. — anything on the user's PATH.
199
+
200
+ - Use `ptyprocess` (POSIX) / `pywinpty` (Windows). Forward keystrokes, stream output, handle
201
+ resize (`SIGWINCH` / pty set-size) from the client's `cols/rows`.
202
+ - The "Run on shell" button in the UI's flag modal sends a composed command into this session
203
+ (or a dedicated run session) so plan/apply output streams in the same place.
204
+ - Reflect the active shell (PowerShell/zsh/bash) in the prompt; allow switching the executor shell.
205
+
206
+ ---
207
+
208
+ ## 7. Cloud SDK auth detection
209
+
210
+ Probe each cloud's CLI and surface status in the top bar + Cloud Shell. Run these read-only
211
+ checks (cache results ~60s, re-probe on demand and after a login):
212
+
213
+ | Cloud | Probe command | Authenticated when |
214
+ |---|---|---|
215
+ | **AWS** | `aws sts get-caller-identity` | exit 0; show Account + Arn + region |
216
+ | **GCP** | `gcloud auth application-default print-access-token` **and** `gcloud auth list` | ADC token prints **and** an active account exists |
217
+ | **Azure** | `az account show` | exit 0; show subscription name/id |
218
+
219
+ **GCP needs both logins** — document and surface this clearly:
220
+ - `gcloud auth login` → user identity for the `gcloud` CLI.
221
+ - `gcloud auth application-default login` → **ADC**, which the Terraform `google` provider uses.
222
+
223
+ If a probe fails / token expired → mark the cloud **re-auth** (amber), gate affected stacks,
224
+ and offer the exact remediation command (`az login`, `aws sso login --profile …`,
225
+ `gcloud auth application-default login`) runnable straight from the Cloud Shell. Detect SDK
226
+ presence + versions (`aws --version`, `gcloud --version`, `az version`) and warn if missing,
227
+ with install links.
228
+
229
+ ---
230
+
231
+ ## 8. State & lock inspection
232
+
233
+ Per backend type, without mutating state:
234
+
235
+ - **Read state / resource list:** `terraform state list` + `terraform show -json` (run in unit dir).
236
+ - **Locks:**
237
+ - S3 + **DynamoDB**: read the lock item from the lock table → who/when/lock-id.
238
+ - **GCS**: object generation/metadata lock.
239
+ - **azurerm**: blob **lease** state.
240
+ - Surface lock holder, age, and lock-id in the UI. Support **acquire/release**:
241
+ release maps to `terraform force-unlock <LOCK_ID>` (guarded — require confirmation + RBAC in
242
+ server mode).
243
+ - Optional **state versioning/history** (bucket versioning, or TerraUi-side snapshots) for the
244
+ "who changed what" timeline.
245
+
246
+ ---
247
+
248
+ ## 9. Drift detection
249
+
250
+ - Scheduled background scan (default every 30m, `--drift-interval`): per stack run
251
+ `terraform plan -detailed-exitcode -refresh-only` (exit code 2 = drift) or parse a normal
252
+ `-json` plan for changes not originating from config.
253
+ - Store drift snapshots: per-resource, attribute-level `state` vs `actual` (exactly what the
254
+ Drift tab renders). Emit a WS event so the sidebar badge and dashboard metric update live.
255
+ - "Reconcile" action → opens the run picker pre-set to `plan` for that stack.
256
+
257
+ ---
258
+
259
+ ## 10. VCS integration (GitHub & GitLab)
260
+
261
+ - OAuth/App install or PAT. Register **webhooks**: on PR/MR open & push, identify affected
262
+ stacks (changed paths ∩ discovered units) and run a **speculative plan**; post the
263
+ `+add ~change -destroy` summary + a link back to TerraUi as a PR/MR comment + status check.
264
+ - On merge to the default branch → optionally trigger `apply` (policy-gated).
265
+ - Record the PR/MR number, branch, commit SHA, and author on the run so the Runs/audit view can
266
+ show "GH #482 / GL !113 — title" with the engineer behind it (matches the frontend's run rows).
267
+ - Abstract a `VCSProvider` interface; implement `GitHubProvider` and `GitLabProvider`.
268
+
269
+ ---
270
+
271
+ ## 11. Team mode & scaling (future-ready from day one)
272
+
273
+ Design the local app so the same core promotes to a shared deployment without a rewrite:
274
+
275
+ - **Server mode** (`terraui server`): central FastAPI + Postgres, serves the UI to many users.
276
+ - **Agents** (`terraui agent`): remote executors that register with the server, hold the cloud
277
+ creds for their environment, pull run jobs from a queue, and stream output back. The server
278
+ **never** holds cloud secrets.
279
+ - **Job queue / workers:** Redis or Postgres-backed (e.g. `arq`/Celery) for fan-out and
280
+ run-all orchestration across agents.
281
+ - **AuthN/Z:** OIDC/SAML SSO; **RBAC** with per-environment apply approvals; optional policy
282
+ gate (**OPA / Sentinel**) evaluated on the plan before apply is allowed.
283
+ - **Multi-tenant:** org → projects → stacks; row-level scoping in Postgres.
284
+ - **Observability:** structured logs, Prometheus metrics, OpenTelemetry traces on runs.
285
+
286
+ Keep all execution behind an `Executor` interface with `LocalExecutor` (subprocess/PTY) and
287
+ `AgentExecutor` (remote) implementations — local and server modes differ only in which executor
288
+ and store are wired in.
289
+
290
+ ---
291
+
292
+ ## 12. AI assistant
293
+
294
+ - Endpoint `POST /api/ai/chat` proxying an LLM. **Never** put model keys in the browser; the
295
+ server holds them (env/secret store).
296
+ - Ground answers in the user's repos: build a lightweight index (RAG) over discovered HCL,
297
+ backend configs, latest plan/drift snapshots, and run history, so questions like
298
+ "why is eks-cluster drifting?" use real context.
299
+ - Allow the assistant to call **read-only** tools (state list, plan summary, auth status, dep
300
+ graph) but require explicit human approval before any mutating action — surface that guarantee
301
+ in the UI ("never applies without approval").
302
+ - Stream tokens over SSE/WS for a responsive chat.
303
+
304
+ ---
305
+
306
+ ## 13. API surface (align with the frontend)
307
+
308
+ REST (JSON):
309
+ ```
310
+ GET /api/stacks → inventory (see §4 model)
311
+ GET /api/stacks/{id} → detail + backend + deps + activity
312
+ GET /api/stacks/{id}/state → resource list
313
+ GET /api/stacks/{id}/drift → attribute-level drift snapshot
314
+ POST /api/stacks/{id}/lock → acquire | DELETE → release (force-unlock)
315
+ POST /api/runs → start a run (flag model §5) → {runId}
316
+ GET /api/runs → history (filter: pr|manual|schedule|drift)
317
+ GET /api/runs/{id} → run detail + full log
318
+ GET /api/graph?env=prod → Terragrunt DAG + run-all order
319
+ GET /api/clouds → auth status per cloud (§7)
320
+ POST /api/ai/chat → assistant
321
+ GET /api/health
322
+ ```
323
+ WebSocket:
324
+ ```
325
+ /ws/run/{runId} → live run events (line/status/summary)
326
+ /ws/term/{session} → PTY terminal I/O + resize
327
+ /ws/events → inventory/drift/lock change push (UI live updates)
328
+ ```
329
+
330
+ ---
331
+
332
+ ## 14. Security
333
+
334
+ - No secret storage. Use the cloud SDK credential chains already on the machine/agent.
335
+ - Command allow-list + argument validation; never shell-interpolate user strings — pass argv.
336
+ - Bind local mode to `127.0.0.1` by default; CSRF/Origin checks on WS upgrades.
337
+ - Server mode: TLS, SSO, RBAC, signed agent registration, full audit log of every run & lock op.
338
+ - Redact secrets from streamed logs (provider env vars, tokens) before persistence.
339
+
340
+ ---
341
+
342
+ ## 15. Packaging & layout
343
+
344
+ ```
345
+ terraui/
346
+ ├─ pyproject.toml # [project.scripts] terraui = "terraui.cli:app"
347
+ ├─ terraui/
348
+ │ ├─ cli.py # Typer app: start/server/agent/scan
349
+ │ ├─ server/app.py # FastAPI factory, routers, WS
350
+ │ ├─ discovery/ # walk + HCL parse + DAG
351
+ │ ├─ exec/ # Executor, LocalExecutor, AgentExecutor, PTY
352
+ │ ├─ clouds/ # aws/gcp/azure auth probes
353
+ │ ├─ state/ # backend-specific state + lock inspectors
354
+ │ ├─ drift/ # scheduler + snapshots
355
+ │ ├─ vcs/ # github.py, gitlab.py
356
+ │ ├─ ai/ # chat + RAG
357
+ │ ├─ store/ # SQLAlchemy models, sqlite/postgres
358
+ │ └─ web/ # bundled frontend (TerraUi.html) as package data
359
+ └─ tests/
360
+ ```
361
+
362
+ > Implementation note: this repo uses a `src/terraui/` layout (PyPI best practice). The
363
+ > `exec/` module is named `execution/` (avoids shadowing the Python builtin); the bundled
364
+ > frontend lives at `src/terraui/web/index.html`.
365
+
366
+ ---
367
+
368
+ ## 16. Milestones
369
+
370
+ 1. **M1 — Inventory + UI shell:** discovery, `terraui start`, serve frontend, stacks list, state read.
371
+ 2. **M2 — Execution:** flag-model runs (plan/apply/destroy) streamed over WS; run history/audit; PTY Cloud Shell.
372
+ 3. **M3 — Drift + locks:** scheduled drift scans, attribute diffs, lock inspect/acquire/release.
373
+ 4. **M4 — Terragrunt orchestration:** DAG + dependency-ordered `run-all`.
374
+ 5. **M5 — VCS:** GitHub/GitLab webhooks, speculative PR plans, status checks, apply-on-merge.
375
+ 6. **M6 — AI assistant:** grounded chat with read-only tool access.
376
+ 7. **M7 — Server mode:** agents, SSO, RBAC, Postgres, policy gates — the scale story.
377
+
378
+ ---
379
+
380
+ ## 17. Acceptance (local mode MVP)
381
+
382
+ ```bash
383
+ pip install terraui && cd ~/acme/infra && terraui start
384
+ ```
385
+ …must: discover every Terraform & Terragrunt unit; show them grouped by env/cloud; report
386
+ AWS/GCP/Azure auth status; let me open a stack, pick flags, run a streamed `plan`, see the diff,
387
+ view drift, see who holds the lock, read run history with the triggering PR — and open a Cloud
388
+ Shell that runs `az login` / `gcloud auth application-default login` against my real machine.
terraui-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Preet
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
terraui-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,156 @@
1
+ Metadata-Version: 2.4
2
+ Name: terraui
3
+ Version: 0.1.0
4
+ Summary: Local-first control plane for Terraform & Terragrunt — inventory, plan/apply, drift, locks and a cloud shell, in one UI.
5
+ Project-URL: Homepage, https://gitlab.com/terraui/terraui
6
+ Project-URL: Repository, https://gitlab.com/terraui/terraui.git
7
+ Project-URL: Issues, https://gitlab.com/terraui/terraui/-/issues
8
+ Author: Preet
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: control-plane,devops,drift,iac,infrastructure,terraform,terragrunt
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: Console
14
+ Classifier: Environment :: Web Environment
15
+ Classifier: Framework :: FastAPI
16
+ Classifier: Intended Audience :: Developers
17
+ Classifier: Intended Audience :: System Administrators
18
+ Classifier: License :: OSI Approved :: MIT License
19
+ Classifier: Operating System :: OS Independent
20
+ Classifier: Programming Language :: Python :: 3
21
+ Classifier: Programming Language :: Python :: 3.10
22
+ Classifier: Programming Language :: Python :: 3.11
23
+ Classifier: Programming Language :: Python :: 3.12
24
+ Classifier: Programming Language :: Python :: 3.13
25
+ Classifier: Topic :: Software Development :: Build Tools
26
+ Classifier: Topic :: System :: Systems Administration
27
+ Requires-Python: >=3.10
28
+ Requires-Dist: fastapi>=0.110
29
+ Requires-Dist: httpx>=0.27
30
+ Requires-Dist: python-hcl2>=4.3; python_version < '4'
31
+ Requires-Dist: typer>=0.12
32
+ Requires-Dist: uvicorn[standard]>=0.29
33
+ Provides-Extra: ai
34
+ Requires-Dist: anthropic>=0.40; extra == 'ai'
35
+ Provides-Extra: dev
36
+ Requires-Dist: build>=1.2; extra == 'dev'
37
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
38
+ Requires-Dist: pytest>=8; extra == 'dev'
39
+ Requires-Dist: twine>=5; extra == 'dev'
40
+ Provides-Extra: pty
41
+ Requires-Dist: ptyprocess>=0.7; (sys_platform != 'win32') and extra == 'pty'
42
+ Requires-Dist: pywinpty>=2.0; (sys_platform == 'win32') and extra == 'pty'
43
+ Description-Content-Type: text/markdown
44
+
45
+ # TerraUi
46
+
47
+ A **local-first control plane for Terraform & Terragrunt**. Point it at the folder
48
+ that holds all your IaC repos; it discovers every unit, and gives one web UI to
49
+ inventory stacks, run `plan`/`apply`/`destroy` (streamed live), detect drift, read
50
+ state and locks, browse the Terragrunt dependency graph, open a cloud shell, and
51
+ ask an AI assistant.
52
+
53
+ This repo implements the `TerraUi.dc.html` design (the product surface) plus the
54
+ backend from `BACKEND_SPEC.md`. It ships as a Python package with the compiled
55
+ frontend bundled and served at `/`.
56
+
57
+ ```bash
58
+ pip install -e . # from this repo (Python 3.10+)
59
+ cd ~/acme/infra # the folder containing your IaC repos
60
+ terraui start # discovers everything, opens http://localhost:8787
61
+ ```
62
+
63
+ No IaC in the current folder? `terraui start` falls back to a fully-populated
64
+ **demo dataset** (the one from the design) so you can explore the whole UI.
65
+
66
+ ## Cloud SDK setup (gcloud / aws / az)
67
+
68
+ TerraUi shells out to your existing cloud CLIs — it never stores credentials. On
69
+ first `terraui start` it runs a **read-only** check of the providers your stacks
70
+ actually use and, if anything is missing, points you at `terraui setup`:
71
+
72
+ ```bash
73
+ terraui setup # per provider: detect → offer install → offer login
74
+ ```
75
+
76
+ `setup` is **per-provider and skippable** — if you only use GCP, skip AWS and
77
+ Azure and configure them later. It shows the exact install/login command before
78
+ running it and asks for confirmation; nothing happens silently. GCP runs **both**
79
+ required logins (`gcloud auth login` for the CLI and
80
+ `gcloud auth application-default login` for the Terraform provider).
81
+
82
+ ## CLI
83
+
84
+ ```
85
+ terraui start [PATH] Local mode: scan PATH (default cwd), serve UI + executor
86
+ --port 8787 Port (default 8787)
87
+ --scan ./live ./mods Extra roots to scan
88
+ --no-open Don't auto-open the browser
89
+ --shell powershell|zsh|bash
90
+ --drift-interval 30m Background drift cadence (0 = off)
91
+ --demo Force the bundled demo dataset
92
+ --check Run interactive cloud-SDK setup before serving
93
+ --skip-checks Skip the cloud-SDK status check
94
+
95
+ terraui setup [PATH] Detect / install / authenticate cloud SDKs (per-provider, skippable)
96
+ --providers aws,gcp,azure Limit to specific providers
97
+ --yes Non-interactive (install only; skip browser logins)
98
+
99
+ terraui scan [PATH] --json Print discovered units as JSON (CI / debug)
100
+ terraui server --config … Team mode (scaffold — see BACKEND_SPEC §11)
101
+ terraui agent --server … Remote executor (scaffold)
102
+ ```
103
+
104
+ ## What's implemented
105
+
106
+ | Area | Status |
107
+ |---|---|
108
+ | Discovery (HCL walk, backend/provider/deps parse, Terragrunt DAG) | ✅ `discovery/` |
109
+ | Execution engine (flag model → `build_command`, streamed over WS, persisted) | ✅ `execution/`, `store/` |
110
+ | Cloud auth probes (AWS / GCP-with-ADC / Azure) | ✅ `clouds/` |
111
+ | State & lock read (`terraform state list`, acquire/release) | ✅ `state/` |
112
+ | Drift (per-stack snapshots; demo data, live scan scaffolded) | ◑ `drift` endpoint |
113
+ | Cloud Shell PTY (pywinpty / ptyprocess, subprocess fallback) | ✅ `shell/` |
114
+ | AI assistant (Claude `claude-haiku-4-5` proxy + offline fallback) | ✅ `ai/` |
115
+ | Frontend bundle (all views, drawer, flag modal, toast) | ✅ `web/index.html` |
116
+ | VCS webhooks, server/agent mode, RBAC, policy gates | ☐ scaffolded (§10–11) |
117
+
118
+ The command the UI previews is exactly the command the executor runs —
119
+ `buildCmdStr` (frontend) and `build_command` (backend) are kept identical and
120
+ unit-tested against the spec example
121
+ (`terragrunt run-all plan -var-file=env/prod.tfvars --terragrunt-non-interactive`).
122
+
123
+ ## Architecture
124
+
125
+ ```
126
+ Browser (web/index.html)
127
+ REST /api/* inventory, runs, drift, locks, graph, clouds, ai
128
+ WS /ws/run/{id} live plan/apply output
129
+ WS /ws/term/{sess} PTY terminal
130
+
131
+ FastAPI app (server/app.py)
132
+ discovery · execution · clouds · state · drift · ai · store
133
+ │ subprocess (user's shell)
134
+
135
+ terraform / terragrunt / aws / gcloud / az on the local machine
136
+ ```
137
+
138
+ ## Develop
139
+
140
+ ```bash
141
+ pip install -e ".[dev,pty]"
142
+ pytest # command builder, discovery, API smoke tests
143
+ terraui start --demo # run the UI against the demo dataset
144
+ ```
145
+
146
+ The AI assistant proxies to Claude when `ANTHROPIC_API_KEY` is set (model
147
+ `claude-haiku-4-5`); otherwise it returns grounded canned answers. The key never
148
+ reaches the browser.
149
+
150
+ ## Security
151
+
152
+ Local mode binds to `127.0.0.1`. No secrets are stored — TerraUi shells out using
153
+ the cloud SDK credential chains already on your machine. Commands are built from a
154
+ structured flag model and passed as argv (never shell-interpolated); the action is
155
+ checked against an allow-list. Secrets are redacted from streamed logs before they
156
+ are persisted. See `BACKEND_SPEC.md` §14 for the full model.