Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .githooks/commit-msg
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ set -eu

ROOTFORM_REPO_ROOT=$(git rev-parse --show-toplevel)
cd "$ROOTFORM_REPO_ROOT"
bun scripts/check-publication.ts --message-file "$1"
exec bun scripts/check-commit-message.ts --file "$1"
1 change: 1 addition & 0 deletions .githooks/pre-commit
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ set -eu

ROOTFORM_REPO_ROOT=$(git rev-parse --show-toplevel)
cd "$ROOTFORM_REPO_ROOT"
bun scripts/check-publication.ts --staged
exec bun scripts/check-staged.ts
1 change: 1 addition & 0 deletions .githooks/pre-push
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ set -eu

ROOTFORM_REPO_ROOT=$(git rev-parse --show-toplevel)
cd "$ROOTFORM_REPO_ROOT"
bun scripts/check-publication.ts
exec bun scripts/pre-push.ts
28 changes: 4 additions & 24 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,7 @@
<!-- required: replace every prompt and remove this comment -->
## Change

## Spec and outcome
Describe the outcome and its accepted specification or repository scope. Include compatibility or security effects when relevant.

- Spec or repository-only rationale:
- Accepted outcome:
- Explicit non-goals:
## Validation

## Done when and evidence

- Done when command or protocol:
- Evidence path or exact output:
- Full gate: `bun run verify`

## Risk and privacy

- Security/privacy impact:
- Offline and determinism impact:
- Dependency or toolchain change:
- Rollback path:

## Review checklist

- [ ] Scope matches accepted spec or repository-only rationale.
- [ ] Success, boundary, failure, and regression paths have evidence proportional to risk.
- [ ] No secret, real Terraform material, private AI material, or generated noise enters Git.
- [ ] Primary reviewer inspected final diff and recorded remaining limits.
List commands and results that verify this change.
7 changes: 7 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@ jobs:
with:
bun-version: 1.4.0

- name: Validate public contribution text
env:
PUBLIC_TITLE: ${{ github.event.pull_request.title }}
PUBLIC_BODY: ${{ github.event.pull_request.body }}
BASE_SHA: ${{ github.event.pull_request.base.sha }}
run: bun scripts/check-publication.ts --metadata-env --range "$BASE_SHA..HEAD"

- name: Install exact foundation dependencies
run: bun install --frozen-lockfile

Expand Down
33 changes: 33 additions & 0 deletions .github/workflows/published-release-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,36 @@ jobs:
test "$RESOLVED_VERSION" = "$expected_version"
[[ "$INSTALLED_SHA256" =~ ^[0-9a-f]{64}$ ]]
test "$(rootform version)" = "rootform $expected_version"

- name: Check out the published fixture revision
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: rootform-dev/rootform
ref: v${{ steps.rootform.outputs.version }}
path: fixtures
persist-credentials: false

- name: Install exact Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version: 1.4.0

- name: Install locked verification dependencies
run: bun install --frozen-lockfile

- name: Exercise published CLI business paths
env:
ROOTFORM_TEST_FIXTURES: ${{ github.workspace }}/fixtures
ROOTFORM_TEST_VERSION: ${{ steps.rootform.outputs.version }}
ROOTFORM_TEST_TOKEN: ""
ROOTFORM_TEST_EVIDENCE: ${{ runner.temp }}/published-cli-evidence.json
run: bun run test:integration

- name: Preserve business integration evidence
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: published-cli-${{ steps.rootform.outputs.version }}-${{ github.sha }}
path: ${{ runner.temp }}/published-cli-evidence.json
if-no-files-found: warn
retention-days: 90
29 changes: 7 additions & 22 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,28 +63,13 @@ Before changing anything:

Full normative wording lives in `docs/constitution.md`.

## AI collaboration

- Primary agent owns plan, cross-cutting decisions, integration, final review,
and completion claim.
- Prefer doing the work in the primary agent when it already holds the
necessary context.
- Delegate only self-contained tasks with non-overlapping scopes; use subagents
primarily for bounded investigation, isolated implementation, or independent
verification.
- Never ask multiple subagents to independently read the same broad set of
files. Provide distilled context in the task instead.
- Do not delegate simple edits, mechanical refactors, or work touching tightly
coupled files.
- On any 429 or rate-limit failure, do not spawn replacement agents; continue
sequentially in the primary agent.
- Assign one writer per file. Parallel writers must own disjoint paths.
- Every subtask returns evidence: paths and lines, commands run, observed
output, limitations, and changed files.
- Primary agent rereads the final diff and reruns gates. Subagent claims are
not proof.
- Never expose private prompts, transcripts, routing configuration, memory, or
credentials in commits or logs.
## Public contribution boundary

Keep private notes, prompts, research and session reports outside this checkout.
Public files, commits, pull requests and reports describe product behavior,
contributor commands, validation and required technical provenance. Validate
messages before sending them; diagnostics never reproduce sensitive values.
Configure `git config core.hooksPath .githooks` before contributing.

## Toolchain and dependencies

Expand Down
202 changes: 69 additions & 133 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,148 +3,84 @@
[![Quality](https://github.com/rootform-dev/action/actions/workflows/ci.yml/badge.svg?branch=dev)](https://github.com/rootform-dev/action/actions/workflows/ci.yml)
[![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)

Review Terraform or OpenTofu plan and state exports, or reuse a saved Rootform
Form, in GitHub Actions. Rootform interprets the evidence and owns comparison,
Policy results, and exit codes. The Action installs the published CLI and
reports its results. It never runs Terraform or OpenTofu, executes providers,
or contacts a cloud account.
Analyze Terraform or OpenTofu plan and state exports, compare revisions and
check Policies in GitHub Actions. The Action installs a verified Rootform CLI;
Rootform owns interpretation, reports and exit codes. It runs no Terraform or OpenTofu,
executes no providers and makes no cloud calls.

## Quickstart

After a trusted workflow step has made `plan.json` and its matching saved plan
`plan.tfplan` available in the workspace, add this step:
Make `plan.json` and its matching saved plan `plan.tfplan` available first:

```yaml
- uses: rootform-dev/action@v1
id: rootform
with:
version: 0.1.0
version: <rootform-version>
input: plan.json
plan-file: plan.tfplan
```

The root Action infers analysis or comparison from the inputs. To check
Policies, set `check: true` for the project's locked selections, or supply a
Policy selector or Policy Pack. Nothing is selected implicitly. Use the
`form`, `report`, or other output paths in later steps of the same job.

## Guides and full reference

The root Action is the normal starting point. Reach for a standalone primitive
when you want an explicit install, preparation, analysis, comparison, or check
step. Setup and init are optional because business actions install and prepare
what they need.

| Action | Use | Guide |
| --- | --- | --- |
| Root | Analyze or compare, optionally check and comment | [Quickstart](#quickstart) |
| Setup | Install the verified CLI for later steps | [Setup](setup/README.md) |
| Init | Prepare lock-selected external content | [Init](init/README.md) |
| Analyze | Produce a Form and reports from one input | [Analyze](analyze/README.md) |
| Compare | Compare before and after evidence | [Compare](compare/README.md) |
| Check | Evaluate selected Policies directly | [Check](check/README.md) |

Canonical Rootform user documentation contains the complete input/output
contract:

- [GitHub Actions overview](https://docs.rootform.dev/integrations/github-actions/)
- [Root Action reference](https://docs.rootform.dev/integrations/github-actions/action/)
- [Setup reference](https://docs.rootform.dev/integrations/github-actions/setup/)
- [Init reference](https://docs.rootform.dev/integrations/github-actions/init/)
- [Analyze reference](https://docs.rootform.dev/integrations/github-actions/analyze/)
- [Compare reference](https://docs.rootform.dev/integrations/github-actions/compare/)
- [Check reference](https://docs.rootform.dev/integrations/github-actions/check/)

## Version, permissions, and data

Give `version` an exact published Rootform CLI version. There is no `latest`
or version-range lookup. A later Rootform Action step in the same job may reuse
the exact version installed and verified by an earlier step. Public release
installation needs no credential; `github-token` defaults to `github.token`
for GitHub API rate limits and root Action comments, and is never passed to the
CLI. The installer verifies release digests, the archive checksum, and the
executable hash before use. Use a full commit SHA when you need an immutable
Action ref. All entrypoints use Node 24 and require Actions Runner 2.327.1 or
newer. Normal use needs only `contents: read`.

Once selected content is available, Rootform analysis, comparison, and Policy
evaluation are network-free. When raw evidence or Policy selection needs
project content, the Action asks Rootform to prepare the exact external content
selected by the project's `rootform.lock`.
`locked: true` requires and preserves that existing lock; the Action never
creates or edits it. `offline: true` requests local verified content only.

File outputs are reusable paths, never Form or report bodies. The analyze
and compare actions return `form`, `report`, and `html` paths. Check returns
`form`, `result`, `report`, `sarif`, and the exact `exit-code`; compare exposes
one Comparison Form, not separate before/after Form paths. A path works only
within its job. Use an artifact ID or URL to transfer evidence between jobs.

Summary and artifact upload are enabled by default for business actions.
Artifacts contain only valid Forms and derived reports, never raw plan/state
exports, saved binary plans, arbitrary project files, credentials, or the
Rootform home. Derived Forms and reports can disclose infrastructure topology;
disable Summary or upload when that audience should not see them. Artifact
retention defaults to seven days and accepts 1–90 days, subject to the
repository limit. Default names are unique per invocation, including matrix
jobs. If setting `artifact-name`, make it unique for every upload. GitHub
Enterprise Server does not support this artifact transport; set
`upload-artifact: false` there.

Eligible fork pull request workflows can read caches from the base repository.
Set `cache: false` if lock-selected Dialect or Policy Pack sources should not
be readable by pull request authors. See GitHub's
[cache access rules](https://docs.github.com/en/actions/reference/workflows-and-actions/dependency-caching).

Rootform's exact check exit code remains authoritative. Available outputs,
Summary, artifacts, and an eligible comment are published before a nonzero
check fails the step. Use GitHub's step-level `continue-on-error` if later
steps must run; no Action input changes the verdict.

## Pull request comments

Only the root Action supports opt-in comments. Comments are limited to
same-repository `pull_request` events; fork pull requests receive no comment.
Business entrypoints and init reject `pull_request_target` before installing
the CLI. Commenting requires `pull-requests: write` and `actions: read`, in
addition to `contents: read`, and is supported on GitHub.com.

Every workflow that may report on a pull request must share the same job-level
concurrency group, based only on the PR number, with cancellation disabled.
This prevents concurrent comment writers across workflows. Make the matching
`plan.json` and `plan.tfplan` available before the shown Action step:

```yaml
on:
pull_request:

permissions:
contents: read
pull-requests: write
actions: read

jobs:
report:
runs-on: ubuntu-latest
concurrency:
group: rootform-pr-${{ github.event.pull_request.number }}
cancel-in-progress: false
steps:
- uses: rootform-dev/action@v1
with:
version: 0.1.0
input: plan.json
plan-file: plan.tfplan
comment: true
```

The Action checks the current pull request HEAD, workflow run, and attempt
before writing. GitHub's comment API has no atomic conditional update, so shared
concurrency is part of the comment contract. Comments and enabled evidence
channels may expose topology; choose their audience accordingly.

## License

Rootform Action source is licensed under [Apache License 2.0](LICENSE).
Rootform binary release terms are separate and ship with each distribution
archive.
Replace `<rootform-version>` with an exact published CLI version. The Action
major tag `v1` is independent of the CLI version.

The root Action infers analysis or comparison. Set `check: true` to evaluate
the project's locked Policy selections, or supply an explicit Policy selector
or Policy Pack. Nothing is selected implicitly.

Reuse `steps.rootform.outputs.form` and `steps.rootform.outputs.report` in later
steps of the same job. File outputs contain paths, never report bodies.
[Outputs and exit status](https://docs.rootform.dev/reference/outputs/)
and the [Action reference](https://docs.rootform.dev/integrations/github-actions/action/)
list the complete contract.

## Choose an entrypoint

Business actions install and prepare what they need; setup and init are optional.

| Action | Purpose |
| --- | --- |
| [Root](https://docs.rootform.dev/integrations/github-actions/action/) | Analyze or compare, optionally check and comment |
| [Setup](setup/README.md) | Install the verified CLI for later steps |
| [Init](init/README.md) | Prepare lock-selected external content |
| [Analyze](analyze/README.md) | Produce a Form and reports from one input |
| [Compare](compare/README.md) | Compare before and after evidence |
| [Check](check/README.md) | Evaluate selected Policies |

## Versions and permissions

- `version` must name an exact published CLI version. A later Action step can
reuse the version already verified in the same job.
- Use a full commit SHA for an immutable Action reference.
- Entrypoints use Node 24 and require Actions Runner 2.327.1 or later.
- Normal use needs `contents: read`. Public installation needs no credential;
`github-token` serves GitHub API rate limits and comments, never the CLI.

`locked: true` requires and preserves `rootform.lock`. `offline: true` uses
verified local content only. Analysis, comparison and Policy evaluation remain
network-free once selected content is available.

## Reports and pull request comments

Artifacts contain only Forms and derived reports, never raw evidence, saved
plans, credentials or the Rootform home. Summary and upload are enabled by
default. Forms and reports can
reveal topology; disable the channels that should not share it. On GitHub
Enterprise Server, set `upload-artifact: false`. Fork workflows can read eligible
[base-repository caches](https://docs.github.com/en/actions/reference/workflows-and-actions/dependency-caching);
set `cache: false` for private lock-selected content.

Policy outputs are published before a nonzero check fails the step. Use GitHub's
`continue-on-error` when later steps must run; the CLI verdict stays authoritative.

Only the root Action supports opt-in `comment: true`, on same-repository
`pull_request` events. Fork pull requests receive no comment; business actions
and init reject `pull_request_target`. Comments need `pull-requests: write` and
`actions: read`. All comment writers must share a job-level concurrency group
`rootform-pr-${{ github.event.pull_request.number }}` with `cancel-in-progress: false`.
See the [comment workflow](https://docs.rootform.dev/integrations/github-actions/action/).

## Contribute and license

[Contributing](CONTRIBUTING.md) covers local validation.
Source: [Apache-2.0](LICENSE). Binary release terms ship with each CLI archive.
6 changes: 4 additions & 2 deletions analyze/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ steps:
- uses: rootform-dev/action/analyze@v1
id: analysis
with:
version: 0.1.0
version: <rootform-version>
input: ${{ runner.temp }}/plan.json
plan-file: ${{ runner.temp }}/plan.tfplan
```
Expand All @@ -24,4 +24,6 @@ upload also exposes `artifact-id` and `artifact-url`; the default artifact
contains only the Form and derived reports. Summary and upload are enabled by
default. Set `upload-artifact: false` when the evidence should stay in the job.

See the complete [analyze input and output reference](https://docs.rootform.dev/integrations/github-actions/analyze/) and the [GitHub Actions overview](https://docs.rootform.dev/integrations/github-actions/).
See the complete [analyze input and output reference](https://docs.rootform.dev/integrations/github-actions/analyze/) or return to the [Action quickstart](../README.md).

Replace `<rootform-version>` with an exact published CLI version.
6 changes: 4 additions & 2 deletions check/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ steps:
- uses: rootform-dev/action/check@v1
id: policy-check
with:
version: 0.1.0
version: <rootform-version>
input: ${{ runner.temp }}/plan.json
plan-file: ${{ runner.temp }}/plan.tfplan
policy-pack: ./policies/team
Expand All @@ -28,4 +28,6 @@ failure; GitHub's `continue-on-error` controls later workflow steps. Artifacts
and Summary are enabled by default. Successful upload also exposes
`artifact-id` and `artifact-url`.

See the complete [check input and output reference](https://docs.rootform.dev/integrations/github-actions/check/) and the [GitHub Actions overview](https://docs.rootform.dev/integrations/github-actions/).
See the complete [check input and output reference](https://docs.rootform.dev/integrations/github-actions/check/) or return to the [Action quickstart](../README.md).

Replace `<rootform-version>` with an exact published CLI version.
Loading
Loading