From 729be04bf8c20be4f26c768814c8b00ddb54e7fe Mon Sep 17 00:00:00 2001 From: JOY <5027251+JOY@users.noreply.github.com> Date: Mon, 21 Sep 2026 22:51:46 +0700 Subject: [PATCH] chore(ci): one-off workflow to dismiss CodeQL alert 1567 via GITHUB_TOKEN The operator gh token lacks the security_events scope required by the code scanning alert dismissal endpoint, and adding a scope is a credential change. A workflow_dispatch job with security-events: write performs the dismissal with GITHUB_TOKEN instead. Remove this file after the alert is dismissed. --- .github/workflows/oneoff-dismiss-alert.yml | 34 ++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 .github/workflows/oneoff-dismiss-alert.yml diff --git a/.github/workflows/oneoff-dismiss-alert.yml b/.github/workflows/oneoff-dismiss-alert.yml new file mode 100644 index 0000000000..230a0efa52 --- /dev/null +++ b/.github/workflows/oneoff-dismiss-alert.yml @@ -0,0 +1,34 @@ +name: One-off - dismiss CodeQL alert 1567 + +# One-off utility: dismisses CodeQL alert 1567 (js/path-injection, +# LocalStorage.removeFile) which was hardened in PR #43 with a containment +# guard and verified not attacker-reachable. The interactive CLI dismissal +# needs a security_events scope the operator token does not carry, so this +# runs with GITHUB_TOKEN security-events:write instead. +# REMOVE THIS FILE after the alert is dismissed. + +on: + workflow_dispatch: + +permissions: + security-events: write + +jobs: + dismiss: + runs-on: ubuntu-latest + steps: + - name: Dismiss alert + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh api -X PUT repos/DOS/Crove-Post/code-scanning/alerts/1567 \ + -f state=dismissed \ + -f reason=false_positive \ + -f comment="Hardened in PR #43 and verified not attacker-reachable: (1) containment guard in LocalStorage.removeFile - the requested path is resolved and rejected unless it stays inside the upload directory (path.relative / isAbsolute / '..' rejection); (2) caller audit: every removeFile caller passes server-generated values (multer-generated public URL, internally constructed date-based keys, DB-stored generated names); no public API or user input flows into removeFile. CodeQL dataflow reports residual taint through the guard; the guard is kept as defense-in-depth." \ + --jq '{state: .state, dismissed_reason: .dismissed_reason}' + - name: Verify + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh api "repos/DOS/Crove-Post/code-scanning/alerts?ref=dev&state=dismissed" \ + --jq '.[] | select(.number == 1567) | {number: .number, state: .state, dismissed_reason: .dismissed_reason}'