Skip to content

Add GitHub Actions native output (annotations + job summary) + reusable action.yml#222

Open
seonghobae wants to merge 2 commits into
developfrom
github-actions-native
Open

Add GitHub Actions native output (annotations + job summary) + reusable action.yml#222
seonghobae wants to merge 2 commits into
developfrom
github-actions-native

Conversation

@seonghobae

Copy link
Copy Markdown
Contributor

Summary

AppGuardrail already ran in GitHub Actions via appguardrail monitor, but only uploaded SARIF. This makes it correspond to the GitHub-native surfaces developers actually watch, and ships a one-line reusable action.

  • Inline PR annotations — inside Actions (GITHUB_ACTIONS=true) the scanner emits ::error (deploy-blocking) / ::warning workflow commands on the exact file/line, so findings appear on the PR diff. GitHub-spec escaping (%0A/%2C/%3A).
  • Job summary — a severity breakdown + top findings written to $GITHUB_STEP_SUMMARY.
  • Auto-on in Actions (no flag); scan --github forces it locally. The existing monitor workflow gains inline annotations with zero changes.
  • action.yml (repo root) — reusable composite action: uses: ContextualWisdomLab/appguardrail@v1 → scan + SARIF upload + deploy gate. Inputs path/sarif/upload-sarif/fail-on-blocking/version; outputs sarif/exit-code.

Stdlib only, no new dependency.

Test plan

  • pytest — 228 passed, incl. tests/test_github_actions.py (annotation levels, GitHub escaping, custom blocking fn, summary markdown, summary-file write, unwritable-path resilience) + module self-check.
  • e2e: GITHUB_ACTIONS=true appguardrail scan <dir> emits ::error/::warning and writes the step summary; --github reproduces it locally.

🤖 Generated with Claude Code

The scanner already ran in GitHub Actions via `monitor` (SARIF upload only).
This makes it correspond to GitHub-native surfaces developers actually watch:

- appguardrail_core/github_actions.py: inside Actions (GITHUB_ACTIONS=true) emit
  `::error`/`::warning` workflow annotations (deploy-blocking -> error) so findings
  show inline on the PR diff, and append a severity-breakdown job summary to
  $GITHUB_STEP_SUMMARY. GitHub-spec escaping (%0A/%2C/%3A). stdlib only.
- `scan --github` forces the same output locally; auto-on inside Actions (no flag).
  The existing monitor workflow gains inline annotations with zero changes.
- action.yml (repo root): reusable composite action — `uses: .../appguardrail@v1`
  runs scan + SARIF upload + deploy gate. inputs path/sarif/upload-sarif/
  fail-on-blocking/version; outputs sarif/exit-code.
- Tests: tests/test_github_actions.py (levels, escaping, custom blocking fn,
  summary markdown, file write, bad-path resilience) + module self-check.
- Verified: full suite 228 passed; e2e scan in a forced Actions env emits
  annotations + writes the step summary.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EywwS2Du8pimW7xqRP3An3
…ative) (#226)

Inline annotations show findings on the diff; this adds the one-place roll-up
reviewers expect — a single sticky PR comment that updates in place per push.

- appguardrail_core/github_comment.py: reads a findings JSON (`scan --findings-json`),
  builds a markdown summary (reuses github_actions.step_summary_md), and upserts a
  comment marked with a hidden anchor via the GitHub REST API (urllib + GITHUB_TOKEN).
  Resolves the PR number from the event payload or refs/pull/N. Any API failure is
  swallowed so it never fails the security gate. stdlib only.
  Run: `python -m appguardrail_core.github_comment <findings.json>`.
- action.yml: scan now also writes findings JSON; a `Post PR comment` step runs on
  pull_request events (new input `pr-comment`, default true; needs pull-requests: write).
- Tests: tests/test_github_comment.py (marker, PR-number resolution, skip paths,
  create-then-update upsert, findings-json loading) + module self-check.
- Verified: full suite 235 passed.


Claude-Session: https://claude.ai/code/session_01EywwS2Du8pimW7xqRP3An3

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
return int(pr["number"])
if event.get("number"):
return int(event["number"])
except (OSError, ValueError, KeyError):
@@ -0,0 +1,66 @@
"""Tests for GitHub Actions native output (appguardrail_core.github_actions)."""

import os
calls = []
state = {"comments": []}

def fake_request(method, url, token, body=None):
@opencode-agent opencode-agent Bot disabled auto-merge July 6, 2026 12:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant