|
| 1 | +# RAC PR-gate composite action (v0.21.14, ADR-049 / ADR-063). |
| 2 | +# |
| 3 | +# Carries the full RAC contract into a single required pull-request check: |
| 4 | +# install RAC and run `rac gate` — one command that enforces validation, |
| 5 | +# relationship integrity, and review under the corpus enforcement policy |
| 6 | +# (`.rac/config.yaml`), emitting one SARIF document (ADR-054). The single SARIF |
| 7 | +# is uploaded to GitHub Code Scanning under one category (`rac-gate`), and the |
| 8 | +# CLI exit code is re-surfaced. The action is a thin consumer (ADR-063): all |
| 9 | +# analysis and enforcement policy live in the package (ADR-015 / ADR-049); the |
| 10 | +# action never reinterprets findings or decides what is blocking. |
| 11 | +# |
| 12 | +# The Watchkeeper action lives at `watchkeeper/github/` and the validate |
| 13 | +# (Registrar) action at `registrar/github/`; this gate is referenced as |
| 14 | +# `uses: itsthelore/rac-ci/gatekeeper/github@<ref>`. |
| 15 | +name: "RAC PR gate" |
| 16 | +description: >- |
| 17 | + Enforce a requirements-as-code (RAC) corpus on a pull request with a single |
| 18 | + `rac gate` command — validation, relationship integrity, and review under the |
| 19 | + corpus enforcement policy — surfaced inline via GitHub Code Scanning (SARIF) as |
| 20 | + a required status check. A thin wrapper over the `rac` CLI. |
| 21 | +author: "Tom Ballard" |
| 22 | + |
| 23 | +branding: |
| 24 | + icon: "shield" |
| 25 | + color: "purple" |
| 26 | + |
| 27 | +inputs: |
| 28 | + path: |
| 29 | + description: "The RAC corpus directory to enforce (passed to `rac gate`)." |
| 30 | + required: false |
| 31 | + default: "rac" |
| 32 | + upload-sarif: |
| 33 | + description: >- |
| 34 | + Upload SARIF to GitHub Code Scanning (`true` or `false`). Requires the job |
| 35 | + to grant `security-events: write`. |
| 36 | + required: false |
| 37 | + default: "true" |
| 38 | + sarif-dir: |
| 39 | + description: "Directory the single `gate.sarif` document is written to." |
| 40 | + required: false |
| 41 | + default: "rac-sarif" |
| 42 | + rac-version: |
| 43 | + description: >- |
| 44 | + Exact rac-core version to install from PyPI. Empty installs the |
| 45 | + latest release. |
| 46 | + required: false |
| 47 | + default: "" |
| 48 | + |
| 49 | +runs: |
| 50 | + using: "composite" |
| 51 | + steps: |
| 52 | + - uses: actions/setup-python@v5 |
| 53 | + with: |
| 54 | + python-version: "3.12" |
| 55 | + |
| 56 | + - name: Install RAC |
| 57 | + shell: bash |
| 58 | + env: |
| 59 | + RAC_VERSION: ${{ inputs.rac-version }} |
| 60 | + run: | |
| 61 | + python -m pip install --quiet --upgrade pip |
| 62 | + if [ -n "$RAC_VERSION" ]; then |
| 63 | + python -m pip install --quiet "rac-core==$RAC_VERSION" |
| 64 | + else |
| 65 | + python -m pip install --quiet rac-core |
| 66 | + fi |
| 67 | +
|
| 68 | + # The CLI is the source of truth (ADR-058). `set +e` lets a non-zero exit |
| 69 | + # still produce SARIF for upload; the exit code is re-surfaced below. One |
| 70 | + # command, one SARIF document — `rac gate` already composes validation, |
| 71 | + # relationships, and review under the corpus enforcement policy. |
| 72 | + - name: Run RAC gate (SARIF) |
| 73 | + id: gate |
| 74 | + shell: bash |
| 75 | + env: |
| 76 | + INPUT_PATH: ${{ inputs.path }} |
| 77 | + SARIF_DIR: ${{ inputs.sarif-dir }} |
| 78 | + run: | |
| 79 | + set +e |
| 80 | + mkdir -p "$SARIF_DIR" |
| 81 | + rac gate "$INPUT_PATH" --sarif > "$SARIF_DIR/gate.sarif" |
| 82 | + code=$? |
| 83 | + echo "gate exited $code" |
| 84 | + echo "exit_code=$code" >> "$GITHUB_OUTPUT" |
| 85 | +
|
| 86 | + # A single SARIF document uploaded under one Code Scanning category. The gate |
| 87 | + # is one tool ("rac") producing one run, so one categorised analysis suffices. |
| 88 | + - name: Upload gate SARIF |
| 89 | + if: ${{ always() && inputs.upload-sarif == 'true' }} |
| 90 | + uses: github/codeql-action/upload-sarif@v3 |
| 91 | + with: |
| 92 | + sarif_file: ${{ inputs.sarif-dir }}/gate.sarif |
| 93 | + category: rac-gate |
| 94 | + |
| 95 | + # Any non-zero CLI exit fails the check; the Code Scanning annotations show |
| 96 | + # every finding, blocking and advisory. What is blocking is decided by the |
| 97 | + # engine under the corpus enforcement policy (ADR-049), not here. |
| 98 | + - name: Report result |
| 99 | + shell: bash |
| 100 | + env: |
| 101 | + EXIT_CODE: ${{ steps.gate.outputs.exit_code }} |
| 102 | + run: | |
| 103 | + if [ "$EXIT_CODE" != "0" ]; then |
| 104 | + echo "::error::RAC PR gate failed (exit $EXIT_CODE) — see the Code Scanning annotations." |
| 105 | + exit "$EXIT_CODE" |
| 106 | + fi |
| 107 | + echo "RAC PR gate passed." |
0 commit comments