feat: replace the sg-cli passthrough with the Tirith Policy Check action - #182
Open
refeed wants to merge 3 commits into
Open
feat: replace the sg-cli passthrough with the Tirith Policy Check action#182refeed wants to merge 3 commits into
refeed wants to merge 3 commits into
Conversation
Evaluates an organization's StackGuardian policies against a terraform plan in
CI and reports the outcome as a sticky pull-request comment and a check run.
This supersedes the previous contents of this repository -- a 15-line docker
passthrough that ran `sg-cli <operation>` on alpine:3.10 and resolved the CLI
version at image build time, so pinning the action did not pin what it ran.
Anyone depending on that should pin @v1.0.0-beta; there is no automatic
migration, and the README says so.
The action is deliberately thin. Everything that talks to StackGuardian --
masking, packing, uploading, polling, rendering -- is `tirith platform check` in
StackGuardian/tirith, so the same behaviour is available from GitLab, a Makefile
or a laptop. What is left here is only what is genuinely GitHub-specific:
reading the event payload, posting the comment and check run, and setting
outputs.
Notes on two choices that are easy to get wrong:
* TriggerDetails.type is github_action, never github_webhook. The run
controller posts its own comment and check on the webhook path, so claiming
it would double-post on every pull request.
* `neutral` satisfies a required check, so it is only safe for warnings.
Anything unresolved maps to failure, and approval-required maps to
action_required.
The integration tests run the action as a real subprocess against a stub serving
both APIs, with a real tirith installed, and assert that a secret in the plan
appears in no recorded request body and nowhere inside the uploaded archive.
That end-to-end shape is deliberate: testing the masking function in isolation
is what let a leak through once already.
There was a problem hiding this comment.
Pull request overview
This PR replaces the previous sg-cli docker passthrough action with a composite GitHub Action wrapper around tirith platform check, adding GitHub-native reporting (sticky PR comment + check run), safer output handling, and end-to-end integration tests.
Changes:
- Replace the Docker-based
sg-clipassthrough with a composite action that installs and runs Tirith. - Add a stdlib-only Python entrypoint that translates GitHub event context into Tirith inputs and posts GitHub comment/check results.
- Add end-to-end integration tests plus updated docs/examples describing usage and migration.
Reviewed changes
Copilot reviewed 13 out of 14 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
action.yml |
Redefines the action as a composite action with explicit inputs/outputs and a Tirith install + execution flow. |
scripts/main.py |
Implements the action entrypoint: event parsing, trigger details, invoking Tirith, setting outputs, posting comment/check. |
scripts/tirith_action/gh_client.py |
Adds a minimal GitHub REST client to upsert a sticky comment and create a check run. |
scripts/tirith_action/__init__.py |
Declares the helper package. |
tests/test_action_integration.py |
Adds end-to-end tests validating masking/leak prevention, run creation, reporting, and exit codes. |
README.md |
Updates documentation for Tirith Policy Check usage, permissions, inputs/outputs, exit codes, and migration notes. |
examples/basic.yml |
Provides a minimal workflow example demonstrating plan → JSON → policy check. |
examples/monorepo-matrix.yml |
Shows recommended matrix usage with per-stack workflow-id + comment-tag. |
examples/with-state.yml |
Adds an example for pre-apply plan gating + post-apply state checking. |
docs/terragrunt.md |
Adds terragrunt pipeline guidance and phased approaches for multi-unit policy evaluation. |
.github/workflows/test.yml |
Updates CI to run pytest integration tests and adds a smoke test for failure behavior. |
.gitignore |
Ignores Python caches and pytest cache. |
Dockerfile |
Removed (no longer a Docker action). |
entrypoint.sh |
Removed (no longer used). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+121
to
+123
| - name: Install tirith | ||
| shell: bash | ||
| run: pip install --quiet "py-tirith @ git+https://github.com/StackGuardian/tirith@${{ inputs.tirith-version }}" |
| set_output("failed", str(counts.get("failed", 0))) | ||
| set_output("warned", str(counts.get("warned", 0))) | ||
| set_output("results", json.dumps(result.get("policy_results") or {})) | ||
| set_output("results-file", result_path) |
Comment on lines
+267
to
+271
| try: | ||
| with open(markdown_path) as f: | ||
| body = f.read() | ||
| except OSError: | ||
| body = result.get("headline", "Tirith policy check") |
TEMPORARY -- set tirith-version back to a tag before release. A moving ref means a green pipeline can turn red with nothing in the repository changing.
source-dir defaults to "." and the archive packs it, so the action's own tirith-trigger.json -- carrying the PR title, repo URL and actor -- was uploaded to the platform. Verified in a live run. Also documents plainly that the terraform source is uploaded as written, so a secret hardcoded in HCL reaches StackGuardian regardless of masking. The previous wording implied masking covered everything leaving the runner.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Replaces this repository's contents with an action that evaluates StackGuardian policies against a
terraform plan in CI and reports the outcome as a sticky pull-request comment and a check run.
What it supersedes
The previous action was 15 lines: a docker passthrough running
sg-cli <operation>onalpine:3.10(EOL since 2021), which
wget'd the CLI'sreleases/latestat image build time — so pinning theaction did not pin what it ran. One free-form input, no outputs.
Anyone depending on that should pin
@v1.0.0-beta; the README says so. Suggest tagging thisv2rather than moving
@main.The action is deliberately thin
Everything that talks to StackGuardian — masking, packing, uploading, polling, rendering — is
tirith platform check(StackGuardian/tirith#272). What is left here is only what is genuinelyGitHub-specific: reading the event payload, posting the comment and check run, setting outputs.
Keeping the split at that line is the point: a GitLab or Jenkins integration reuses the CLI
unchanged, and this file never becomes the place where platform behaviour is decided.
Two choices that are easy to get wrong
TriggerDetails.typeisgithub_action, nevergithub_webhook. The run controller posts itsown comment and check on the webhook path (
common/vcs.py), so claiming it would double-post onevery pull request.
commentsUrl/checksApiUrlare likewise omitted.neutralsatisfies a required check, so it is only safe for warnings. Anything unresolved mapsto
failure;approval-requiredmaps toaction_required.Testing
The integration tests run the action as a real subprocess against a stub serving both the SG and
GitHub APIs on one port, with a real tirith installed, and assert that a secret in the plan appears
in no recorded request body and nowhere inside the uploaded archive. That end-to-end shape is
deliberate: testing the masking function in isolation is what let a leak through once already.
13 tests. Writing them caught a real defect — the trigger details were built and never passed to the
CLI, so every run would have been recorded as
type: cli.Depends on StackGuardian/tirith#272 (and the
1.2.0tag), StackGuardian/core#1235,StackGuardian/api#1708, StackGuardian/auth#201, StackGuardian/workflow-step-templates#310.