diff --git a/README.md b/README.md index 2b03bd5..2669c2e 100644 --- a/README.md +++ b/README.md @@ -3,16 +3,14 @@ [![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 @@ -23,128 +21,63 @@ After a trusted workflow step has made `plan.json` and its matching saved plan 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. +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. diff --git a/analyze/README.md b/analyze/README.md index aab75e5..f630de5 100644 --- a/analyze/README.md +++ b/analyze/README.md @@ -24,4 +24,4 @@ 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). diff --git a/check/README.md b/check/README.md index c764ee5..1aa5e2c 100644 --- a/check/README.md +++ b/check/README.md @@ -28,4 +28,4 @@ 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). diff --git a/compare/README.md b/compare/README.md index 8a85d4e..e4f5a68 100644 --- a/compare/README.md +++ b/compare/README.md @@ -25,4 +25,4 @@ bodies. A Comparison Form can be reopened by analyze or check, but cannot be used as a compare operand. Successful artifact upload exposes `artifact-id` and `artifact-url`; upload and Summary are enabled by default. -See the complete [compare input and output reference](https://docs.rootform.dev/integrations/github-actions/compare/) and the [GitHub Actions overview](https://docs.rootform.dev/integrations/github-actions/). +See the complete [compare input and output reference](https://docs.rootform.dev/integrations/github-actions/compare/) or return to the [Action quickstart](../README.md). diff --git a/init/README.md b/init/README.md index 3b5fb08..59fd0a1 100644 --- a/init/README.md +++ b/init/README.md @@ -25,4 +25,4 @@ Init runs Rootform preparation only. It never runs Terraform or OpenTofu. Its only output is `version`, the exact verified CLI version. The job-local `ROOTFORM_HOME` is shared with later business actions. -See the complete [init input and output reference](https://docs.rootform.dev/integrations/github-actions/init/) and the [GitHub Actions overview](https://docs.rootform.dev/integrations/github-actions/). +See the complete [init input and output reference](https://docs.rootform.dev/integrations/github-actions/init/) or return to the [Action quickstart](../README.md). diff --git a/scripts/lib/policy.test.ts b/scripts/lib/policy.test.ts index b62900c..d3d9adf 100644 --- a/scripts/lib/policy.test.ts +++ b/scripts/lib/policy.test.ts @@ -48,6 +48,12 @@ describe("product path gate", () => { test.each([ "AGENTS.md", + "README.md", + "setup/README.md", + "init/README.md", + "analyze/README.md", + "compare/README.md", + "check/README.md", ".claude/settings.json", "scripts/verify.ts", "docs/engineering/quality-gates.md", diff --git a/scripts/lib/policy.ts b/scripts/lib/policy.ts index 04907c5..7d3371b 100644 --- a/scripts/lib/policy.ts +++ b/scripts/lib/policy.ts @@ -237,6 +237,7 @@ export function decidePreToolUse(input: HookInput, root: string): PolicyDecision export function isProductPath(path: string): boolean { const normalized = path.replace(/^\.\//, ""); + if (/^(?:setup|init|analyze|compare|check)\/README\.md$/u.test(normalized)) return false; if (["action.yml", "action.yaml"].includes(normalized)) return true; return ["dist/", "setup/", "init/", "analyze/", "compare/", "check/", "src/", "test/"].some( (prefix) => normalized.startsWith(prefix), diff --git a/setup/README.md b/setup/README.md index 654cdd0..9eee87f 100644 --- a/setup/README.md +++ b/setup/README.md @@ -24,4 +24,4 @@ installed executable's digest). They are values, not file paths. Public release installation needs no credential; the optional `github-token` is for GitHub API rate limits and is not sent to Rootform. -See the complete [setup input and output reference](https://docs.rootform.dev/integrations/github-actions/setup/) and the [GitHub Actions overview](https://docs.rootform.dev/integrations/github-actions/). +See the complete [setup input and output reference](https://docs.rootform.dev/integrations/github-actions/setup/) or return to the [Action quickstart](../README.md).