Data boundary
Infragr.am’s security model rests on one rule: the Terraform plan never leaves your runner. Your workflow plans and sanitizes, an independent scanner checks the result, and only a bundle describing your resources and how they connect is uploaded.
Never leaves your runner
Section titled “Never leaves your runner”| Item | Why |
|---|---|
Raw plan and terraform show -json output |
Read locally by the collector, then discarded with the runner. |
.tf source files |
Only the names referenced inside locals blocks are read. Never values. |
| State, backend configuration | Never read by the Action. |
*.tfvars, vars, TF_VAR_* |
Passed to Terraform. The Action doesn’t forward them. |
| Cloud credentials | Exist only in your workflow, for terraform plan. Infragr.am never asks for them. |
| Any value Terraform marks sensitive | Removed by the collector. |
| Attributes named like credentials | Removed by the collector. See the full list. |
What is sent
Section titled “What is sent”One JSON document, the bundle, that matches a published schema:
- Resources: address, type, name, module, provider, planned actions (
create,update, …), and the attributes left after sanitization, such as names, tags, CIDR blocks, ports, regions and availability zones. - References: which resource refers to which, as your configuration writes them, for example
aws_instance.web→aws_subnet.privateviasubnet_id. - Symbols: which resources
localsand module inputs and outputs point to, used to connect resources across modules. - Sanitization counters: how many sensitive paths and credential-like keys were removed.
Alongside the bundle, the Action sends the GitHub event name, the pull request number, and the environment you set. Your identity comes from the OIDC token GitHub issues to the workflow.
What is read from .tf files
Section titled “What is read from .tf files”Terraform’s JSON plan doesn’t include locals. Registry modules wire resources through them all the time, for example vpc_id = local.vpc_id, so without them a diagram would lose those connections. The collector therefore reads the configuration directory it just planned, and only this much of it:
- only
localsblocks, and within them, - only the local’s name and the references inside its expression.
It never reads an attribute’s value, file contents, or anything outside locals. A local holding a literal contributes nothing at all:
locals { db_password = "hunter2" # → nothing vpc_id = module.vpc.vpc_id # → module.vpc.vpc_id label = "prefix-${aws_vpc.main.cidr_block}-suffix" # → aws_vpc.main}A test in the collector, TestScanLocalsNeverEmitsValues, enforces this.
The collector is built from source
Section titled “The collector is built from source”The Action doesn’t download a prebuilt binary. Every run builds infragram-collect from the public, MIT-licensed source at the exact ref your workflow uses, with go build -trimpath. The bundle is written to disk readable only by its owner (0600) and deleted when the step ends.
To make the code that runs fixed and reviewable, pin the Action to a full commit SHA instead of @v1:
- uses: Tekchbila-Studios/infragram-action@<40-character-commit-sha> # v1.0.4On the server
Section titled “On the server”- Bundles are validated against the schema with no unknown fields. Credential-like keys are checked a second time, and a bundle that fails either check is refused.
- Size limits: at most 3 MB, 20,000 resources, and 100,000 references.
- Bundles are stored in private, encrypted object storage, used to render your diagrams, and deleted automatically after 30 days.
- Diagrams are served through links that expire after a few minutes, generated only after the viewer is authorized for that repository.
- Access follows GitHub: who can see a repository’s diagrams is decided from their GitHub access to the repository’s installation, keyed on GitHub’s immutable numeric IDs, so a renamed or transferred repository doesn’t change who has access.
Builds Infragr.am refuses
Section titled “Builds Infragr.am refuses”pull_request_target. That event runs with the base repository’s secrets while checking out pull request code, so builds triggered by it are rejected.- Ownership mismatch. If a repository moves to a different account than the one that activated it, builds are refused until it is activated again.
Defense in depth, not proof
Section titled “Defense in depth, not proof”Sanitization removes what it knows to look for. Gitleaks independently looks for anything shaped like a secret. Neither can prove that arbitrary data holds no secret. Before adopting the Action, review the collector source and the schema, and audit a real bundle from your own plan.