Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions .github/workflows/review-gate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# Fails when cubic did not complete a review, or when CodeRabbit was off or errored.
# Passes with a warning when CodeRabbit is only rate limited.
# Reads check runs only. Check titles are matched as text: update them here
# when a vendor renames one.
name: review-gate
on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
permissions:
checks: read
pull-requests: read # list the PR commits
# A newer push to the same PR cancels the run that still polls the older commit.
concurrency:
group: review-gate-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
review-gate:
# Bot-authored dependency PRs and draft PRs: the job is skipped, which passes a required check.
if: >-
github.event.pull_request.user.login != 'dependabot[bot]' &&
github.event.pull_request.user.login != 'renovate[bot]' &&
github.event.pull_request.draft == false
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- name: Wait for both bots, then decide
env:
GH_TOKEN: ${{ github.token }}
REPO: ${{ github.repository }}
SHA: ${{ github.event.pull_request.head.sha }}
PR: ${{ github.event.pull_request.number }}
run: |
set -euo pipefail
# Latest check run of one app on this commit, as JSON; "null" when none or on an API error.
# gh prints an HTTP error body to stdout, so on failure the value is replaced, not appended to;
# the error text on stderr stays in the log. $2 (optional) is the exact check name:
# CodeRabbit publishes other checks under the same app, for example CodeRabbit Security.
latest() {
local out
out=$(gh api "repos/$REPO/commits/$SHA/check-runs?app_id=$1${2:+&check_name=$2}&filter=latest&per_page=100" \
--jq '[.check_runs[] | {id, status, conclusion, title: .output.title}] | max_by(.id)') || out=null
echo "$out"
}
# True when CodeRabbit finished a review on any commit of this PR
# (the commits endpoint returns at most 250 commits).
cr_reviewed_before() {
local shas c n
shas=$(gh api --paginate "repos/$REPO/pulls/$PR/commits?per_page=100" --jq '.[].sha') \
|| { echo "::error::could not list the PR commits"; exit 1; }
for c in $shas; do
# filter=all: a later failed attempt on a commit does not hide its finished review
n=$(gh api "repos/$REPO/commits/$c/check-runs?app_id=347564&check_name=CodeRabbit&filter=all&per_page=100" \
--jq '[.check_runs[] | select(.output.title=="Finished" and .conclusion=="success")] | length') || n=0
Comment thread
ricardofrantz marked this conversation as resolved.
Resolved
Comment thread
ricardofrantz marked this conversation as resolved.
Resolved
[ "$n" != 0 ] && return 0
done
return 1
}
cr=null; cu=null
for i in $(seq 1 36); do # 36 polls, 30 s apart, the last at 17.5 min
cr=$(latest 347564 CodeRabbit) # CodeRabbit app, review check
cu=$(latest 1082092) # cubic app
[ "$(jq -r '.status' <<<"$cr")" = completed ] && [ "$(jq -r '.status' <<<"$cu")" = completed ] && break
if [ "$i" -lt 36 ]; then sleep 30; fi
done
echo "CodeRabbit: $cr"; echo "cubic: $cu"
cr_title=$(jq -r 'if .status=="completed" then .title else "missing" end' <<<"$cr")
cr_concl=$(jq -r '.conclusion // "none"' <<<"$cr")
cu_title=$(jq -r 'if .status=="completed" then .title else "missing" end' <<<"$cu")
cu_concl=$(jq -r '.conclusion // "none"' <<<"$cu")
if [ "$cu_title" != "AI review completed" ] || [ "$cu_concl" != success ]; then
echo "::error::cubic did not complete a review: $cu_title ($cu_concl)"; exit 1
fi
case "$cr_concl" in
failure|cancelled|timed_out|action_required|stale|none) echo "::error::CodeRabbit check did not pass: $cr_title ($cr_concl)"; exit 1 ;;
esac
case "$cr_title" in
"Finished")
[ "$cr_concl" = success ] || { echo "::error::CodeRabbit finished without success ($cr_concl)"; exit 1; } ;;
"Review rate limited") echo "::warning::CodeRabbit rate limited; cubic reviewed." ;;
"Path filters excluded"*|"No files to review") echo "::notice::CodeRabbit: $cr_title" ;;
# CodeRabbit reviews the opening push only (auto_incremental_review false); cubic reviews every push.
# Accept the skip only when CodeRabbit finished a review on an earlier commit of this PR.
"Review skipped: incremental reviews are disabled"|"Incremental review skipped")
if cr_reviewed_before; then
echo "::warning::CodeRabbit reviews the opening push only; comment '@coderabbitai review' for this commit."
else
echo "::error::CodeRabbit never finished a review on this PR; comment '@coderabbitai full review', then re-run this job once that review has finished."; exit 1
fi ;;
*) echo "::error::CodeRabbit did not review: $cr_title ($cr_concl)"; exit 1 ;;
esac
45 changes: 45 additions & 0 deletions .github/workflows/scorecard.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# OpenSSF Scorecard: supply-chain checks, weekly and on branch-protection changes.
# Based on the template in https://github.com/ossf/scorecard-action
name: Scorecard supply-chain security
on:
branch_protection_rule:
schedule:
- cron: '17 4 * * 1'
push:
branches: [main]
workflow_dispatch:
permissions:
contents: read
jobs:
analysis:
name: Scorecard analysis
runs-on: ubuntu-latest
timeout-minutes: 15
# Scorecard rejects a manual run on a non-default branch
if: github.event_name != 'workflow_dispatch' || github.ref_name == github.event.repository.default_branch
permissions:
security-events: write # upload SARIF to code scanning
id-token: write # publish results to the OpenSSF API
contents: read
actions: read
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Run analysis
uses: ossf/scorecard-action@fa7117db83c52d787ae5a89f350999701505d78e # v2.5.0
with:
results_file: results.sarif
results_format: sarif
publish_results: true
- name: Upload artifact
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: SARIF file
path: results.sarif
retention-days: 5
- name: Upload to code scanning
uses: github/codeql-action/upload-sarif@9b3254085494b55a0f7c4c2b3d2d52cc712ce370 # v4.39.1
with:
sarif_file: results.sarif
Loading