GraphIaC
Project description
GraphIaC
Early Alpha — Experimental Software GraphIaC is in early alpha. APIs will change, features are incomplete, and it has not been tested in production. Use at your own risk.
A graph-based Infrastructure-as-Code framework for AWS. Model your cloud infrastructure as a directed graph — nodes are AWS resources, edges are the connections and permissions between them — in a small declarative language, with a live browser UI to edit, plan, and apply it.
The Problem
Tools like Terraform and Pulumi make it easy to define individual resources. The hard part is wiring them together: IAM policies, invoke permissions, service integrations. That boilerplate is repetitive, error-prone, and the main source of permission debugging in real projects. Most IaC tools treat it as an afterthought, burying it inside resource definitions in ways that make the code hard to read and impossible to reuse.
The Approach
GraphIaC promotes connections to first-class citizens. When you write cf -> bucket, the edge already knows it means an Origin Access Control bucket policy — it queries the graph for the relevant ARNs and provisions everything itself. You declare the connection; the edge handles the boilerplate.
Because AWS permission patterns are stable, that knowledge gets written once into the edge class and reused everywhere. And because the infrastructure is a graph, the diagram you see in the UI is never out of date — it is the code.
Quick Start
1. Install (or upgrade):
pip install --upgrade GraphIaC
Using the graphiac-deploy role from examples/get-started/? After upgrading, re-run its setup — new versions add AWS actions the live role doesn't know until re-synced (the symptom is a surprising AccessDenied).
2. Have an AWS profile ready. GraphIaC uses your local AWS credentials (~/.aws/credentials), selected by profile name. The profile needs permissions for whatever you plan to manage (for early testing, an admin-ish sandbox account is the practical choice).
3. Write an infra file. Infrastructure is described in a small language (files end in .giac). A complete static website:
# site.giac — Route53 -> CloudFront (HTTPS) -> S3
domain = "example.com"
hz : HostedZone(domain_name: domain)
cert : ACMCertificate(domain_name: domain)
bucket : S3Bucket("example-com-site")
cf : CloudFrontDistribution(domain_name: domain)
cert -> hz # DNS validation records, automatically
cert -> cf # viewer certificate; cf waits until the cert is ISSUED
cf -> bucket # OAC: only this distribution can read the bucket
cf -> hz : (domain_name: domain) # A alias record
4. Start the server and open the UI:
python -m GraphIaC <your-profile> --infra_file site.giac serve
# GraphIaC serving site.giac at http://127.0.0.1:8642
Open http://127.0.0.1:8642. You get:
- Editor (left) — your
.giacsource, re-parsed as you type; errors and warnings appear inline with line numbers. 💾 save writes it back to the file on disk. - Diagram (right) — the live graph. Solid arrows are provisioned connections (each one is an IAM policy, bucket policy, DNS record, or integration you didn't have to write). Dashed teal arrows are data dependencies.
- ▷ plan — diffs your source against the state DB and live AWS, and shows the result both as a log (
+create,~update,-delete,↳import,⊘blocked) and as badges on the diagram. - ▶ run — applies the plan to AWS (asks for confirmation first).
- ✓ verify — an independent audit: reads live AWS state and runs per-resource security/config checks.
- ⇄ desugar — shows your source with every shorthand resolved: constants substituted, inferred edge types written out, defaults made explicit.
The SQLite state DB is created next to the infra file (site.giac → site.db).
The server binds 127.0.0.1 only and has no authentication — don't expose the port.
Things to know before pointing it at a real account
planandverifyare read-only.runis what changes AWS.- Removing a node from the source schedules its deletion. Once a resource is tracked in the state DB, deleting its line means the next plan shows
- will be deletedand the next run deletes it from AWS. Check the plan before running. - Resources that already exist in AWS are imported, not recreated — see below.
The Language in Sixty Seconds
Five ideas, nothing more (full spec: dsl/spec.md):
name = "value" # a constant, substituted at parse time
label : Type(field: value) # a node — the label IS its identity, and
# defaults into the type's name field
a -> b # an edge — its type is INFERRED from the
# node-type pair; `: Type(args)` overrides
other.field # an attribute reference — a data dependency
# resolved from live AWS state at plan time
# comment
Name defaulting: my-site-bucket : S3Bucket needs nothing else — the label names the bucket. One rule replaces the id/name split: the label names the thing everywhere, unless you say otherwise.
Edge inference: every edge is uniquely determined by its endpoints — cf -> bucket can only mean the OAC edge, cert -> hz only DNS validation. You point; the edge knows. Arrow direction doesn't matter; the parser normalizes it.
Slow resources & BLOCKED: some resources take hours to become usable (ACM certificate validation is the classic). There is no phase logic in the source. An edge can gate its destination — cert -> cf holds the distribution ⊘ BLOCKED (greyed out in the diagram) until the certificate is ISSUED — and an attribute reference like cert.arn blocks the same way until it resolves from live AWS state. Blocked resources are simply skipped; run again later and the planner picks up where AWS left off.
Headless CLI (no UI)
Every UI action works directly on a .giac file — useful for scripts and CI:
python -m GraphIaC <profile> --infra_file site.giac plan # preview changes
python -m GraphIaC <profile> --infra_file site.giac run # apply
python -m GraphIaC <profile> --infra_file site.giac verify # audit; exits 1 on failure
python -m GraphIaC <profile> --infra_file site.giac diagram # Graphviz PNG (needs pygraphviz)
Importing Existing Resources
If you built infrastructure by hand (or with another tool) before adopting GraphIaC, you don't tear it down. Import is automatic: when a node is declared in your source and exists in AWS but isn't in the state DB yet, plan marks it ↳ import — the next run records its live state without touching AWS.
# adopt a site that already exists
bucket : S3Bucket("my-site-prod", region: "us-east-2")
cf : CloudFrontDistribution(domain_name: "example.com",
cert_arn: "arn:aws:acm:us-east-1:...:certificate/...")
Worth knowing:
- Declare only the fields you care about. Drift is checked only on fields you explicitly set, so a sparse declaration won't false-positive against the fully-populated AWS resource.
- Lookup is by natural key. Most nodes can be found by bucket name, domain, or zone name — you usually don't need to hunt down ARNs or IDs first.
- Edges are re-asserted, not imported. They're idempotent: on the first run they re-apply against the existing wiring (a no-op if it's already in place) and are tracked from then on.
What's in the Box
Current node types: S3, CloudFront (distributions + functions), Route53, ACM, IAM roles, Lambda, DynamoDB, API Gateway (HTTP APIs), SES, and the edges that wire them together — DNS validation, OAC bucket policies, alias records, execution-role policies, route integrations + invoke permissions, and more. The full inference table is in dsl/spec.md; the sandbox's error messages will tell you when no edge exists between two types yet.
Python API
GraphIaC is DSL-first, but the underlying Python interface is still available — every node and edge is a Pydantic model you can compose in code (GraphIaC.init, add_node, add_edge, plan, run, verify), and --infra_file infra.py files exposing an infra(state) function still work with the CLI. Expect the DSL path to be the one that gets the attention going forward.
Running Tests
pytest tests/test_dsl.py tests/test_dsl_load.py tests/test_server.py # engine + DSL (no AWS; uses moto)
node --test src/GraphIaC/web/ # the JS parser twin
AWS_PROFILE=your-profile pytest tests/aws/ # real-AWS integration tests
The two DSL parsers (JavaScript for the editor, Python for the engine) are kept in sync by a shared fixture corpus in dsl/fixtures/ — both suites run it.
AWS integration tests generate randomized resource names, clean up after themselves (including on failure), and default to us-east-2. Without AWS_PROFILE set they're skipped automatically.
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file graphiac-0.0.29.tar.gz.
File metadata
- Download URL: graphiac-0.0.29.tar.gz
- Upload date:
- Size: 108.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ead284fbbc14b4bb883c32296806f5ee5f6ed77de1abef877d94ff71c6a0c29f
|
|
| MD5 |
8c1ae5449703249e65609b65108e09d9
|
|
| BLAKE2b-256 |
164abf5b87b38245fc26912ae4fa3ea7596e2a4cf3503f8f562c9966495ce45c
|
File details
Details for the file graphiac-0.0.29-py3-none-any.whl.
File metadata
- Download URL: graphiac-0.0.29-py3-none-any.whl
- Upload date:
- Size: 103.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3fd35ae7e51df179887c54c4c5c9716dec27d21b2c15b4a4ec15fbb4af86a724
|
|
| MD5 |
b1f4064e6384a386bff5a31b07bee40a
|
|
| BLAKE2b-256 |
eeec3eae8d593d4c2de1feb77f691b0ee957dd05f01c1efbdd7bf6544d2a3702
|