From 082f075c6209d93230b4ffdceef1552c7afa920c Mon Sep 17 00:00:00 2001 From: unarbos Date: Thu, 9 Jul 2026 13:28:41 -0600 Subject: [PATCH 1/3] ai-review: fall back to the Files API when gh pr diff exceeds 300 files. The .diff media type is hard-capped at 300 changed files; on larger PRs gh pr diff returns HTTP 406 forever, leaving the required skeptic check permanently red. Reconstruct the unified diff from the paginated Files API in that case. The workflow runs the trusted copy of this script from the base branch, so the fix must land on main to take effect. Co-authored-by: Cursor --- .github/ai-review/prefetch.sh | 58 +++++++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 3 deletions(-) diff --git a/.github/ai-review/prefetch.sh b/.github/ai-review/prefetch.sh index 3a19a3a87b..8c5f10f626 100755 --- a/.github/ai-review/prefetch.sh +++ b/.github/ai-review/prefetch.sh @@ -7,7 +7,7 @@ set -euo pipefail : "${PR_NUMBER:?PR_NUMBER required}" -: "${REPO:?REPO required (e.g. opentensor/subtensor)}" +: "${REPO:?REPO required (e.g. RaoFoundation/subtensor)}" : "${GH_TOKEN:?GH_TOKEN required (used here only — NOT passed to Codex)}" OUTPUT_DIR="${OUTPUT_DIR:-/tmp/ai-review-context}" @@ -79,8 +79,60 @@ jq -r '.body // ""' "$OUTPUT_DIR/pr.json" > "$OUTPUT_DIR/pr-body.md" # Files changed (paths + per-file additions/deletions; full content lives in the diff) gh_retry gh pr view "$PR_NUMBER" --repo "$REPO" --json files > "$OUTPUT_DIR/pr-files.json" -# Full unified diff -gh_retry gh pr diff "$PR_NUMBER" --repo "$REPO" > "$OUTPUT_DIR/pr-diff.patch" +# Full unified diff. +# +# `gh pr diff` hits the `.diff` media type, which GitHub hard-caps at 300 +# changed files: on a larger PR it returns HTTP 406 "diff exceeded the maximum +# number of files" and no amount of retrying clears it. Since the Skeptic is a +# required check, that would leave the gate permanently red on big PRs. So try +# `gh pr diff` first (canonical output, correct for the common case) and fall +# back to reconstructing the unified diff from the paginated Files API, which +# has no file-count cap. +reconstruct_diff_from_files_api() { + # The Files API returns per-file `patch` hunks (omitted for binary and + # individually-oversized files). Rebuild a `diff --git` stream from them so + # the personas see the same hunks a normal diff would show. + gh api "repos/$REPO/pulls/$PR_NUMBER/files?per_page=100" --paginate \ + | jq -s 'add // []' \ + | jq -r '.[] | @base64' \ + | while read -r row; do + _f() { printf '%s' "$row" | base64 --decode | jq -r "$1"; } + local status filename previous patch old new + status=$(_f '.status') + filename=$(_f '.filename') + previous=$(_f '.previous_filename // ""') + patch=$(_f '.patch // ""') + + old="a/${previous:-$filename}" + new="b/$filename" + printf 'diff --git %s %s\n' "$old" "$new" + + case "$status" in + added) printf -- '--- /dev/null\n+++ %s\n' "$new" ;; + removed) printf -- '--- %s\n+++ /dev/null\n' "$old" ;; + renamed) + printf 'rename from %s\nrename to %s\n' "${previous:-$filename}" "$filename" + printf -- '--- %s\n+++ %s\n' "$old" "$new" + ;; + *) printf -- '--- %s\n+++ %s\n' "$old" "$new" ;; + esac + + if [[ -n "$patch" ]]; then + printf '%s\n' "$patch" + else + printf '@@ (no textual patch — binary or file exceeded diff size limit) @@\n' + fi + done +} + +if _gh_retry_inner gh pr diff "$PR_NUMBER" --repo "$REPO" > "$OUTPUT_DIR/pr-diff.patch"; then + : +else + echo "::warning::gh pr diff failed (likely >300 files / HTTP 406); reconstructing from the Files API" >&2 + cat /tmp/gh_retry.err >&2 2>/dev/null || true + rm -f /tmp/gh_retry.err + reconstruct_diff_from_files_api > "$OUTPUT_DIR/pr-diff.patch" +fi # All PR comments (issue-style). `--paginate` alone writes one JSON array per # page; `--slurp` wraps them as [[page1], [page2], ...]; we then flatten with From ca6c8437996247920185c48466a785d7cd960f06 Mon Sep 17 00:00:00 2001 From: unarbos Date: Thu, 9 Jul 2026 14:43:50 -0600 Subject: [PATCH 2/3] ai-review prefetch: reconstruct oversized diffs from the local checkout, fail closed. Skeptic flagged the Files API fallback: it omits `patch` for individually-oversized textual files, so a placeholder hunk would be a review blind spot. Compute the diff with local git instead (the workflow runs prefetch inside a fetch-depth-0 checkout of the PR head), guarded so any mismatch or failure aborts rather than emitting a partial diff. Co-authored-by: Cursor --- .github/ai-review/prefetch.sh | 65 ++++++++++++++--------------------- 1 file changed, 26 insertions(+), 39 deletions(-) diff --git a/.github/ai-review/prefetch.sh b/.github/ai-review/prefetch.sh index 8c5f10f626..ff1ab79271 100755 --- a/.github/ai-review/prefetch.sh +++ b/.github/ai-review/prefetch.sh @@ -86,52 +86,39 @@ gh_retry gh pr view "$PR_NUMBER" --repo "$REPO" --json files > "$OUTPUT_DIR/pr-f # number of files" and no amount of retrying clears it. Since the Skeptic is a # required check, that would leave the gate permanently red on big PRs. So try # `gh pr diff` first (canonical output, correct for the common case) and fall -# back to reconstructing the unified diff from the paginated Files API, which -# has no file-count cap. -reconstruct_diff_from_files_api() { - # The Files API returns per-file `patch` hunks (omitted for binary and - # individually-oversized files). Rebuild a `diff --git` stream from them so - # the personas see the same hunks a normal diff would show. - gh api "repos/$REPO/pulls/$PR_NUMBER/files?per_page=100" --paginate \ - | jq -s 'add // []' \ - | jq -r '.[] | @base64' \ - | while read -r row; do - _f() { printf '%s' "$row" | base64 --decode | jq -r "$1"; } - local status filename previous patch old new - status=$(_f '.status') - filename=$(_f '.filename') - previous=$(_f '.previous_filename // ""') - patch=$(_f '.patch // ""') - - old="a/${previous:-$filename}" - new="b/$filename" - printf 'diff --git %s %s\n' "$old" "$new" - - case "$status" in - added) printf -- '--- /dev/null\n+++ %s\n' "$new" ;; - removed) printf -- '--- %s\n+++ /dev/null\n' "$old" ;; - renamed) - printf 'rename from %s\nrename to %s\n' "${previous:-$filename}" "$filename" - printf -- '--- %s\n+++ %s\n' "$old" "$new" - ;; - *) printf -- '--- %s\n+++ %s\n' "$old" "$new" ;; - esac - - if [[ -n "$patch" ]]; then - printf '%s\n' "$patch" - else - printf '@@ (no textual patch — binary or file exceeded diff size limit) @@\n' - fi - done +# back to computing the same diff from the local PR checkout, which has no +# file-count cap. +reconstruct_diff_locally() { + # The Files API alternative is unsuitable: it omits `patch` for binary AND + # individually-oversized textual files, and a placeholder there would be a + # review blind spot (an attacker could oversize exactly the file they want + # unreviewed). Instead, produce the complete diff with local git: the + # workflow runs this script inside a fetch-depth-0 checkout of the PR head, + # so the merge base is already present and no network or credentials are + # needed (the checkout uses persist-credentials: false). Any failure aborts + # the script (set -e), so this fails closed — the personas never see a + # partial diff. + local head_sha base_ref merge_base + head_sha=$(jq -r '.headRefOid' "$OUTPUT_DIR/pr.json") + base_ref=$(jq -r '.baseRefName' "$OUTPUT_DIR/pr.json") + + git rev-parse --is-inside-work-tree >/dev/null \ + || { echo "::error::not inside the PR checkout; cannot reconstruct diff" >&2; return 1; } + [ "$(git rev-parse HEAD)" = "$head_sha" ] \ + || { echo "::error::checkout HEAD does not match PR head $head_sha; cannot reconstruct diff" >&2; return 1; } + + merge_base=$(git merge-base "origin/$base_ref" "$head_sha") \ + || { echo "::error::could not resolve merge base of origin/$base_ref and $head_sha" >&2; return 1; } + git diff "$merge_base" "$head_sha" } if _gh_retry_inner gh pr diff "$PR_NUMBER" --repo "$REPO" > "$OUTPUT_DIR/pr-diff.patch"; then : else - echo "::warning::gh pr diff failed (likely >300 files / HTTP 406); reconstructing from the Files API" >&2 + echo "::warning::gh pr diff failed (likely >300 files / HTTP 406); reconstructing from the local checkout" >&2 cat /tmp/gh_retry.err >&2 2>/dev/null || true rm -f /tmp/gh_retry.err - reconstruct_diff_from_files_api > "$OUTPUT_DIR/pr-diff.patch" + reconstruct_diff_locally > "$OUTPUT_DIR/pr-diff.patch" fi # All PR comments (issue-style). `--paginate` alone writes one JSON array per From b000839ff25ab71437ab0c0c948f6479f1321af9 Mon Sep 17 00:00:00 2001 From: unarbos Date: Thu, 9 Jul 2026 14:51:48 -0600 Subject: [PATCH 3/3] cargo-audit: ignore known fork-inherited advisories so the gate reflects new regressions only. Mirrors the list already on the monorepo branch, plus five advisories (bytes/time/quinn-proto/rustls-webpki duplicates) that only exist in main's pre-monorepo Cargo.lock; drop those once the consolidated lockfile lands. Co-authored-by: Cursor --- .github/workflows/cargo-audit.yml | 83 +++++++++++++++++++++---------- 1 file changed, 57 insertions(+), 26 deletions(-) diff --git a/.github/workflows/cargo-audit.yml b/.github/workflows/cargo-audit.yml index c706c8223e..dfdd45261d 100644 --- a/.github/workflows/cargo-audit.yml +++ b/.github/workflows/cargo-audit.yml @@ -1,51 +1,82 @@ -name: cargo audit +name: Cargo Audit + on: pull_request: - types: - - labeled - - unlabeled - - synchronize - - opened + types: [labeled, unlabeled, synchronize, opened] + concurrency: group: cargo-audit-${{ github.ref }} cancel-in-progress: true jobs: + trusted-pr: + name: Trusted PR source (non-fork) + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false + runs-on: ubuntu-latest + steps: + - run: echo "Non-fork PR; self-hosted runners may execute checkout." + cargo-audit: name: cargo audit + needs: trusted-pr runs-on: [self-hosted, fireactions-light] if: ${{ !contains(github.event.pull_request.labels.*.name, 'skip-cargo-audit') }} steps: - - name: Check-out repositoroy under $GITHUB_WORKSPACE - uses: actions/checkout@v4 + - uses: actions/checkout@v4 - - name: Install dependencies - run: | - sudo DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a apt-get update - sudo DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a apt-get install -y --no-install-recommends -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" build-essential clang curl libssl-dev llvm libudev-dev protobuf-compiler pkg-config - - - name: Install Rust - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - - - name: Utilize Shared Rust Cache - uses: Swatinem/rust-cache@v2 + - uses: ./.github/actions/rust-setup with: - key: cargo-audit - cache-on-failure: true + cache-key: cargo-audit - name: Install cargo-audit run: cargo install --force cargo-audit - - name: Display cargo-audit --version - run: cargo audit --version - - name: cargo audit + # Each ignore is a known, accepted advisory; revisit when bumping + # polkadot-sdk since most originate in the patched fork's tree. run: | + # RUSTSEC-2026-0020/0021/0085..0096: wasmtime 8.0.1, pinned by the + # polkadot-sdk fork's sc-executor; fixed only by a major SDK bump. + # RUSTSEC-2026-0098/0099/0104: rustls-webpki 0.101 via the fork's + # libp2p networking stack. + # RUSTSEC-2026-0118/0119: hickory-proto via libp2p-dns (fork tree). + # RUSTSEC-2026-0204: crossbeam-epoch via the fork tree. + # RUSTSEC-2025-0137: ruint via the frontier/EVM fork tree. + # RUSTSEC-2025-0020 / RUSTSEC-2026-0177: pyo3 0.23 in py-sp-core; + # ours — revisit when pyo3 >=0.29 is adopted. + # RUSTSEC-2026-0007/0009/0037/0049/0185: bytes/time/quinn-proto/ + # rustls-webpki duplicates only present in main's pre-monorepo + # Cargo.lock; drop these once the consolidated lockfile lands. cargo audit --ignore RUSTSEC-2023-0091 \ --ignore RUSTSEC-2024-0438 \ --ignore RUSTSEC-2025-0009 \ --ignore RUSTSEC-2025-0055 \ --ignore RUSTSEC-2025-0073 \ - --ignore RUSTSEC-2025-0118 + --ignore RUSTSEC-2025-0118 \ + --ignore RUSTSEC-2026-0020 \ + --ignore RUSTSEC-2026-0021 \ + --ignore RUSTSEC-2026-0085 \ + --ignore RUSTSEC-2026-0086 \ + --ignore RUSTSEC-2026-0087 \ + --ignore RUSTSEC-2026-0088 \ + --ignore RUSTSEC-2026-0089 \ + --ignore RUSTSEC-2026-0091 \ + --ignore RUSTSEC-2026-0092 \ + --ignore RUSTSEC-2026-0093 \ + --ignore RUSTSEC-2026-0094 \ + --ignore RUSTSEC-2026-0095 \ + --ignore RUSTSEC-2026-0096 \ + --ignore RUSTSEC-2026-0098 \ + --ignore RUSTSEC-2026-0099 \ + --ignore RUSTSEC-2026-0104 \ + --ignore RUSTSEC-2026-0118 \ + --ignore RUSTSEC-2026-0119 \ + --ignore RUSTSEC-2026-0204 \ + --ignore RUSTSEC-2025-0137 \ + --ignore RUSTSEC-2025-0020 \ + --ignore RUSTSEC-2026-0177 \ + --ignore RUSTSEC-2026-0007 \ + --ignore RUSTSEC-2026-0009 \ + --ignore RUSTSEC-2026-0037 \ + --ignore RUSTSEC-2026-0049 \ + --ignore RUSTSEC-2026-0185