Skip to content

Commit b89ba0c

Browse files
Haofeiclaude
andcommitted
Harden GitHub Action trust model (audit 5.1)
The action silently trusted ambient rss/reir on PATH and only failed on missing capabilities, and the README used the mutable @main ref — too weak for a supply-chain gate. - Add fail-on-unknown / fail-on-excess inputs (default true) and pass them (plus --allow-missing when fail-on-missing=false) to `reir report-pr`, so the gate fails closed on absence-of-evidence and over-privilege, not just missing. - The final gate now keys off the policy-aware status and runs when any fail-on-* is enabled. - Warn when falling back to ambient PATH binaries (not provenance-pinned); building from the pinned action checkout stays the trusted path. - README: pin to a release SHA (not @main), show the fail-closed defaults, and add a "not a production enforcement gate yet" warning (independent native/capability audit; author-declared bindings). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 334c86f commit b89ba0c

2 files changed

Lines changed: 46 additions & 10 deletions

File tree

.github/actions/rsscript-review/action.yml

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,15 @@ inputs:
1616
required: false
1717
default: 'true'
1818
fail-on-missing:
19-
description: 'Fail the action if capabilities are missing'
19+
description: 'Fail the action if required capabilities are missing'
20+
required: false
21+
default: 'true'
22+
fail-on-unknown:
23+
description: 'Fail the action if capabilities are unknown (absence of evidence). Recommended true for protected branches.'
24+
required: false
25+
default: 'true'
26+
fail-on-excess:
27+
description: 'Fail the action if granted capabilities exceed requirements (over-privilege). Recommended true for protected branches.'
2028
required: false
2129
default: 'true'
2230

@@ -41,12 +49,16 @@ runs:
4149
shell: bash
4250
run: |
4351
if ! command -v rss &> /dev/null || ! command -v reir &> /dev/null; then
44-
echo "::group::Building RSScript from source"
52+
echo "::group::Building RSScript from the pinned action checkout"
4553
RSSCRIPT_ACTION_ROOT="$(cd "$GITHUB_ACTION_PATH/../../.." && pwd)"
4654
cargo build --quiet --release --manifest-path "$RSSCRIPT_ACTION_ROOT/Cargo.toml" --bin rss -p rsscript
4755
cargo build --quiet --release --manifest-path "$RSSCRIPT_ACTION_ROOT/Cargo.toml" --bin reir -p reir
4856
echo "$RSSCRIPT_ACTION_ROOT/target/release" >> $GITHUB_PATH
4957
echo "::endgroup::"
58+
else
59+
# Ambient binaries are not provenance-pinned. For a protected gate, pin
60+
# this action to a release SHA so the toolchain is built from that ref.
61+
echo "::warning::Using rss/reir already on PATH. These are not provenance-pinned; pin this action to a release SHA for a trusted supply-chain gate ($(command -v rss), $(command -v reir))."
5062
fi
5163
5264
- name: Run RSScript and REIR review
@@ -56,6 +68,9 @@ runs:
5668
INPUT_HEAD: ${{ inputs.head }}
5769
INPUT_GRANTS: ${{ inputs.grants }}
5870
INPUT_TARGET: ${{ inputs.target }}
71+
INPUT_FAIL_ON_MISSING: ${{ inputs.fail-on-missing }}
72+
INPUT_FAIL_ON_UNKNOWN: ${{ inputs.fail-on-unknown }}
73+
INPUT_FAIL_ON_EXCESS: ${{ inputs.fail-on-excess }}
5974
run: |
6075
TEMP_DIR="$(mktemp -d "${RUNNER_TEMP:-/tmp}/rsscript-review.XXXXXX")"
6176
PACKAGE_REVIEW_JSON="$TEMP_DIR/package-review.json"
@@ -85,11 +100,18 @@ runs:
85100
--package-check "$PACKAGE_CHECK_JSON" \
86101
--out "$REQUIRED_REIR_JSON"
87102
103+
# Build the policy flags from inputs so the gate fails closed by default.
104+
REPORT_FLAGS=()
105+
[ "$INPUT_FAIL_ON_MISSING" = "true" ] || REPORT_FLAGS+=(--allow-missing)
106+
[ "$INPUT_FAIL_ON_UNKNOWN" = "true" ] && REPORT_FLAGS+=(--fail-on-unknown)
107+
[ "$INPUT_FAIL_ON_EXCESS" = "true" ] && REPORT_FLAGS+=(--fail-on-excess)
108+
88109
set +e
89110
reir report-pr \
90111
--required "$REQUIRED_REIR_JSON" \
91112
--granted "$INPUT_GRANTS" \
92-
--target "$INPUT_TARGET" > "$REVIEW_OUTPUT_FILE"
113+
--target "$INPUT_TARGET" \
114+
"${REPORT_FLAGS[@]}" > "$REVIEW_OUTPUT_FILE"
93115
EXIT_CODE=$?
94116
set -e
95117
cp "$REVIEW_OUTPUT_FILE" "$COMMENT_FILE"
@@ -109,6 +131,7 @@ runs:
109131
--required "$REQUIRED_REIR_JSON" \
110132
--granted "$INPUT_GRANTS" \
111133
--target "$INPUT_TARGET" \
134+
"${REPORT_FLAGS[@]}" \
112135
--ci-json > "$CI_JSON_FILE"
113136
CI_JSON_EXIT_CODE=$?
114137
set -e
@@ -149,11 +172,11 @@ runs:
149172
--body-file "$COMMENT_FILE"
150173
fi
151174
152-
- name: Gate on missing capabilities
153-
if: inputs.fail-on-missing == 'true'
175+
- name: Gate on capability reconciliation
176+
if: ${{ inputs.fail-on-missing == 'true' || inputs.fail-on-unknown == 'true' || inputs.fail-on-excess == 'true' }}
154177
shell: bash
155178
run: |
156179
if [ "${{ steps.review.outputs.status }}" = "fail" ]; then
157-
echo "::error::RSScript review found missing deployment capabilities. See PR comment for details."
180+
echo "::error::RSScript review failed capability reconciliation (missing/unknown/excess per policy). See PR comment for details."
158181
exit 1
159182
fi

README.md

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,16 +67,29 @@ raw artifact.
6767
## GitHub Action
6868

6969
```yaml
70-
- uses: Haofei/rsscript/.github/actions/rsscript-review@main
70+
# Pin to a release SHA for a trusted gate; @main is a mutable ref.
71+
- uses: Haofei/rsscript/.github/actions/rsscript-review@<commit-sha>
7172
with:
7273
head: my-service/
7374
grants: infra/prod-grants.reir.json
7475
target: prod
76+
# Fail closed by default: missing, unknown (absence of evidence), and
77+
# excess (over-privilege) all block. Override per input if you must.
78+
fail-on-missing: 'true'
79+
fail-on-unknown: 'true'
80+
fail-on-excess: 'true'
7581
```
7682
77-
The action posts a PR comment with the review decision and exits non-zero on missing capabilities.
78-
For production use, pin this action to a commit SHA. The toolchain and artifact
79-
schemas are still `0.1.x` prototype surfaces.
83+
The action posts a PR comment with the review decision and exits non-zero when
84+
capability reconciliation fails under the policy above.
85+
86+
> **Not a production enforcement gate yet.** The toolchain and artifact schemas
87+
> are `0.1.x` prototype surfaces. Before relying on this to authorize a deploy:
88+
> pin the action to a release SHA (not `@main`), do not depend on ambient
89+
> `rss`/`reir` binaries on `PATH` (the action warns when it finds them), keep the
90+
> fail-on-unknown / fail-on-excess defaults on, and pair it with an independent
91+
> native/capability audit — capability bindings are author declarations unless
92+
> separately verified.
8093

8194
## Install
8295

0 commit comments

Comments
 (0)