From 82f8a87eec9003510bae2ec6bf98b5206b1c1156 Mon Sep 17 00:00:00 2001 From: Ilya Bogin Date: Wed, 23 Sep 2026 10:59:02 +0300 Subject: [PATCH 1/3] ci: Qodo approval bridge (Secure Development Policy v1.1.0) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Records a formal PR approval when Qodo completes its review, quoting the verdict — implements the documented automated change-review control. Reviewing identity, approving identity and author are distinct. Co-Authored-By: Claude Fable 5 --- .github/workflows/auto-approve.yml | 66 ++++++++++++++++++++++++++++++ .pr_agent.toml | 11 +++++ 2 files changed, 77 insertions(+) create mode 100644 .github/workflows/auto-approve.yml create mode 100644 .pr_agent.toml diff --git a/.github/workflows/auto-approve.yml b/.github/workflows/auto-approve.yml new file mode 100644 index 0000000..a612235 --- /dev/null +++ b/.github/workflows/auto-approve.yml @@ -0,0 +1,66 @@ +name: auto-approve + +# Approval bridge for the team's code-review policy (SOC 2 / Vanta "GitHub +# code changes were approved or provided justification"): every PR is reviewed +# automatically by Qodo, findings are advisory, human approval is not +# mandated. Qodo's review lives in a comment, invisible to GitHub's approval +# model — this workflow makes the review visible: when Qodo posts a completed +# review, the PR gets an APPROVED review whose body records Qodo's verdict. +# The approval attests "an automated review happened", NOT "the code is clean". +# A PR merged before Qodo finishes gets no approval. + +on: + issue_comment: + types: [created, edited] + +# Qodo edits its persistent review comment on every re-review; when edits land +# in a burst, only the newest matters. +concurrency: + group: auto-approve-${{ github.event.issue.number }} + cancel-in-progress: true + +jobs: + approve: + name: Approve on Qodo review + # Exact-login match: '[' is illegal in GitHub logins, so the [bot] suffix + # is unforgeable — a prefix match would accept lookalike user accounts. + if: >- + github.event.issue.pull_request && + github.event.comment.user.login == 'qodo-code-review[bot]' && + github.event.comment.user.type == 'Bot' && + contains(github.event.comment.body, 'Code Review by Qodo') + runs-on: ubuntu-latest + timeout-minutes: 5 + permissions: + pull-requests: write + steps: + # Plain gh, not a marketplace action: both auto-approve actions are + # unusable here (fork paywalls private repos; original fails the org's + # verified-creators actions policy). + - name: Approve with the Qodo verdict + env: + GH_TOKEN: ${{ github.token }} + BODY: ${{ github.event.comment.body }} + COMMENT_URL: ${{ github.event.comment.html_url }} + REPO: ${{ github.repository }} + NUM: ${{ github.event.issue.number }} + run: | + set -euo pipefail + # Dedupe: comment edits re-fire this job; approve each head commit once. + head_sha=$(gh api "repos/$REPO/pulls/$NUM" --jq .head.sha) + dup=$(gh api "repos/$REPO/pulls/$NUM/reviews?per_page=100" --paginate \ + --jq "[.[] | select(.user.login==\"github-actions[bot]\" and .state==\"APPROVED\" and .commit_id==\"$head_sha\")] | length") + if [ "$dup" -gt 0 ]; then + echo "Head $head_sha already carries an auto-approval; nothing to do." + exit 0 + fi + # Quote whatever verdict categories the comment carries, without + # encoding Qodo's taxonomy (it changes between releases). A parse + # miss must be visible, not silently degraded. + verdict=$(printf '%s' "$BODY" | grep -oE '[^<]*\([0-9]+\)' | sed 's/<[^>]*>//g' | paste -sd ', ' -) || true + if [ -z "$verdict" ]; then + echo "::warning::No verdict categories parsed from the Qodo comment — its format may have changed; approving with a link only." + verdict="see the review comment" + fi + gh pr review "$NUM" --repo "$REPO" --approve \ + --body "Auto-approved: Qodo review completed — ${verdict}. Findings are advisory per team policy; verdict source: ${COMMENT_URL} [auto-approve.yml]" diff --git a/.pr_agent.toml b/.pr_agent.toml new file mode 100644 index 0000000..b602638 --- /dev/null +++ b/.pr_agent.toml @@ -0,0 +1,11 @@ +# Qodo configuration. +# +# Review-every-push keeps the review in sync with the latest commits, which the +# auto-approve workflow (.github/workflows/auto-approve.yml) depends on: it +# approves the PR whenever Qodo publishes a completed review, quoting the +# verdict. Self-review checkboxes and the classic pr-agent auto-approval keys +# are deliberately absent: the former needs a hidden manual click, the latter +# are dead on this platform (verified 2026-09-07). + +[github_app] +handle_push_trigger = true From fe035ea6eb8cbf3568bbe5a589df3dafec928831 Mon Sep 17 00:00:00 2001 From: Ilya Bogin Date: Wed, 23 Sep 2026 11:49:38 +0300 Subject: [PATCH 2/3] fix: bump anyhow 1.0.104 (RUSTSEC-2026-0285 unblocks cargo-audit gate) Co-Authored-By: Claude Fable 5 --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6529af9..3042cbd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -54,9 +54,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.102" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" [[package]] name = "atomic-waker" From b6ec56f7a99dce2959ecb3199a6ecf723caeaab6 Mon Sep 17 00:00:00 2001 From: Ilya Bogin Date: Wed, 23 Sep 2026 11:55:38 +0300 Subject: [PATCH 3/3] =?UTF-8?q?fix:=20rustls=200.23.45=20(RUSTSEC-2026-028?= =?UTF-8?q?5)=20=E2=80=94=20the=20actual=20audit=20blocker?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- Cargo.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3042cbd..042a1b1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1413,9 +1413,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.38" +version = "0.23.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69f9466fb2c14ea04357e91413efb882e2a6d4a406e625449bc0a5d360d53a21" +checksum = "0d41d731c7d2f962d1ccc364cec258de3c0e93b38c2fb3ba97ac74513048d634" dependencies = [ "aws-lc-rs", "once_cell", @@ -1477,9 +1477,9 @@ checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" [[package]] name = "rustls-webpki" -version = "0.103.13" +version = "0.103.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" +checksum = "f3c3cf1d8b1e7d4927e2d154c3fcb02979afb9939629c62cd9048d4f07b60ac2" dependencies = [ "aws-lc-rs", "ring", @@ -1757,7 +1757,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", - "getrandom 0.4.2", + "getrandom 0.3.4", "once_cell", "rustix", "windows-sys 0.61.2",