advanced-security/dismiss-alerts
GitHub: advanced-security/dismiss-alerts
一个 GitHub Action,根据 SARIF 文件中的抑制数据自动驳回或重新打开 GitHub 代码扫描告警。
Stars: 22 | Forks: 5
# 驳回警报操作
`dismiss alerts` 操作根据 SARIF 文件中的 `suppression` [属性](https://docs.oasis-open.org/sarif/sarif/v2.0/csprd02/sarif-v2.0-csprd02.html#_Toc10127852)来[驳回](https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/managing-code-scanning-alerts-for-your-repository)代码扫描警报。
此操作有两个必填的输入字段:
- `sarif-upload-id` - SARIF 标识符
- `sarif-file` - SARIF 文件的位置,或包含 SARIF 文件的目录。如果提供的是目录,所有 `.sarif` 和 `.sarif.json` 文件都将被递归处理。
## 高层架构
刚刚上传的本地 SARIF 文件会被解析为两组:包含非空 `suppressions[]` 的结果(驳回候选)和不包含该字段的结果(重新打开的候选)。同时,系统会通过 [Code Scanning Alerts API](https://docs.github.com/en/rest/code-scanning/code-scanning#list-code-scanning-alerts-for-a-repository) 查询仓库中所有已打开和已驳回的警报(范围限定为从 SARIF 自身读取的工具名称)。这两个列表使用相同的警报标识符(rule id + 文件 + 行 + 列)进行映射。任何匹配到的警报尚未被驳回的被抑制结果,都会通过向该警报自身的 API `url` 发送 PATCH 请求进行更新,将 `state` 设置为 `dismissed`,`dismissed reason` 设置为 `won't fix`,并将 `dismissed comment` 设置为 `Suppressed via SARIF`。反之,任何带有 `Suppressed via SARIF` 注释且已驳回的警报,如果在 SARIF 中不再有匹配的被抑制结果,则会被重新打开。
以下是从开发者添加抑制注释到警报在 GitHub 上被驳回(或重新打开)的完整端到端流程:
```
flowchart TD
A["👩💻 Developer adds
a suppression
comment"] --> B["🔍 CodeQL runs its
normal queries plus
an alert-suppression
query"] B --> C["📄 SARIF produced:
matches get a
suppressions[] entry"] C --> D["☁️ SARIF uploaded
to GitHub"] D --> E["⏳ dismiss-alerts waits
for upload
processing to finish"] E --> F["🗂️ dismiss-alerts parses
the local SARIF:
suppressed vs. normal"] F --> G["🌐 dismiss-alerts fetches
current alerts from
the Alerts API"] G --> H["🔗 Match by rule id,
file, line, column"] H --> I{"Suppressed,
still open?"} H --> J{"Not suppressed,
was dismissed?"} I -->|yes| K["✅ Dismiss alert
won't fix /
Suppressed via SARIF"] J -->|yes| L["♻️ Re-open
the alert"] ``` ## 入门指南 CodeQL 会根据 `alert-suppression` 查询的结果在其 SARIF 输出中填充 `suppression` 属性。用户可以提供自定义的警报抑制查询,或者使用我们提供的查询(`//lgtm` 或 `//codeql` 风格的注释)。 ### 示例 - CodeQL ``` name: "CodeQL Advanced" on: push: branches: [main] pull_request: branches: [main] schedule: - cron: "31 7 * * 3" jobs: analyze: name: Analyze (${{ matrix.language }}) runs-on: ubuntu-latest permissions: security-events: write packages: read actions: read contents: read strategy: fail-fast: false matrix: include: - language: java-kotlin build-mode: none query: codeql/java-queries:AlertSuppression.ql steps: - name: Checkout repository uses: actions/checkout@v4 - name: Initialize CodeQL uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} build-mode: ${{ matrix.build-mode }} packs: ${{ matrix.query }} - name: Perform CodeQL Analysis # define an 'id' for the analysis step id: analyze uses: github/codeql-action/analyze@v2 with: category: "/language:${{matrix.language}}" # define the output folder for SARIF files output: sarif-results - name: Dismiss alerts if: github.ref == 'refs/heads/main' uses: advanced-security/dismiss-alerts@v2 with: # specify a 'sarif-id' and 'sarif-file' sarif-id: ${{ steps.analyze.outputs.sarif-id }} sarif-file: sarif-results/${{ matrix.language }}.sarif env: GITHUB_TOKEN: ${{ github.token }} ``` ### 第三方生成的 SARIF 文件 `dismiss-alerts` 操作可以与来自第三方提供商的 SARIF 文件一起使用。 ``` on: push: jobs: check-codeql-versions: runs-on: ubuntu-latest permissions: security-events: write steps: - name: Checkout code uses: actions/checkout@v3 - name: Run SAST scan run: sast-scan.sh --output=scan-results.sarif - name: Upload scan results # define an 'id' for the upload step id: upload uses: github/codeql-action/upload-sarif@v2 with: # specify the SARIF file to upload sarif_file: scan-results.sarif wait-for-processing: true - name: Dismiss alerts if: github.ref == 'refs/heads/main' uses: advanced-security/dismiss-alerts@v1 with: # specify a 'sarif-id' and 'sarif-file' sarif-id: ${{ steps.upload.outputs.sarif-id }} sarif-file: scan-results.sarif env: GITHUB_TOKEN: ${{ github.token }} ``` ### 使用包含多个 SARIF 文件的目录 像 Checkov 这样的工具可以在目录中输出多个 SARIF 文件。`sarif-file` 输入支持单个文件路径和目录路径。如果提供的是目录,所有 `.sarif` 和 `.sarif.json` 文件都将被递归处理。 ``` on: push: jobs: checkov-scan: runs-on: ubuntu-latest permissions: security-events: write steps: - name: Checkout code uses: actions/checkout@v3 - name: Run Checkov run: | mkdir -p checkov-results checkov --directory . --output sarif --output-file-path checkov-results - name: Upload scan results # define an 'id' for the upload step id: upload uses: github/codeql-action/upload-sarif@v2 with: # specify the directory containing SARIF files sarif_file: checkov-results wait-for-processing: true - name: Dismiss alerts if: github.ref == 'refs/heads/main' uses: advanced-security/dismiss-alerts@v1 with: # specify a 'sarif-id' and directory containing SARIF files sarif-id: ${{ steps.upload.outputs.sarif-id }} sarif-file: checkov-results env: GITHUB_TOKEN: ${{ github.token }} ``` ## 功能与限制 ### 抑制注释的工作原理 支持两种注释风格: - **`lgtm[rule-id]`** - 抑制与注释位于**同一行**的警报。 - **`codeql[rule-id]`** - 抑制位于**下一行**的警报(注释必须位于警报的*前一行*)。 例如,以下是来自 [`crate/crate-python`](https://github.com/crate/crate-python/blob/main/src/crate/client/__init__.py) 的一个真实抑制注释: ``` # codeql[py/unused-global-variable] apilevel = "2.0" threadsafety = 1 paramstyle = "pyformat" ``` ``` # codeql[py/unused-global-variable] apilevel = "2.0" # codeql[py/unused-global-variable] threadsafety = 1 # codeql[py/unused-global-variable] paramstyle = "pyformat" ``` - 此操作应仅在默认分支上运行,因为警报的驳回状态是一个全局属性。如果此操作在推送到功能分支或 pull request 的事件上运行,那么被抑制的警报也会在默认分支上被驳回。 - 当在包含警报的行上添加抑制注释时,该警报将被关闭,并且重复的警报将被标记为已修复。这是因为代码扫描使用警报所在行内容的哈希值作为唯一标识符。插入的抑制注释更改了该行的内容,因此也更改了警报的哈希值。由于警报哈希值不再匹配,原始警报会被视为 `fixed`(已修复),并在原位置创建一个新警报。由于抑制注释的作用,这个新警报会立即被标记为 `dismissed`(已驳回)。为避免此问题,建议使用允许将抑制标记放置在警报前一行的抑制风格。
a suppression
comment"] --> B["🔍 CodeQL runs its
normal queries plus
an alert-suppression
query"] B --> C["📄 SARIF produced:
matches get a
suppressions[] entry"] C --> D["☁️ SARIF uploaded
to GitHub"] D --> E["⏳ dismiss-alerts waits
for upload
processing to finish"] E --> F["🗂️ dismiss-alerts parses
the local SARIF:
suppressed vs. normal"] F --> G["🌐 dismiss-alerts fetches
current alerts from
the Alerts API"] G --> H["🔗 Match by rule id,
file, line, column"] H --> I{"Suppressed,
still open?"} H --> J{"Not suppressed,
was dismissed?"} I -->|yes| K["✅ Dismiss alert
won't fix /
Suppressed via SARIF"] J -->|yes| L["♻️ Re-open
the alert"] ``` ## 入门指南 CodeQL 会根据 `alert-suppression` 查询的结果在其 SARIF 输出中填充 `suppression` 属性。用户可以提供自定义的警报抑制查询,或者使用我们提供的查询(`//lgtm` 或 `//codeql` 风格的注释)。 ### 示例 - CodeQL ``` name: "CodeQL Advanced" on: push: branches: [main] pull_request: branches: [main] schedule: - cron: "31 7 * * 3" jobs: analyze: name: Analyze (${{ matrix.language }}) runs-on: ubuntu-latest permissions: security-events: write packages: read actions: read contents: read strategy: fail-fast: false matrix: include: - language: java-kotlin build-mode: none query: codeql/java-queries:AlertSuppression.ql steps: - name: Checkout repository uses: actions/checkout@v4 - name: Initialize CodeQL uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} build-mode: ${{ matrix.build-mode }} packs: ${{ matrix.query }} - name: Perform CodeQL Analysis # define an 'id' for the analysis step id: analyze uses: github/codeql-action/analyze@v2 with: category: "/language:${{matrix.language}}" # define the output folder for SARIF files output: sarif-results - name: Dismiss alerts if: github.ref == 'refs/heads/main' uses: advanced-security/dismiss-alerts@v2 with: # specify a 'sarif-id' and 'sarif-file' sarif-id: ${{ steps.analyze.outputs.sarif-id }} sarif-file: sarif-results/${{ matrix.language }}.sarif env: GITHUB_TOKEN: ${{ github.token }} ``` ### 第三方生成的 SARIF 文件 `dismiss-alerts` 操作可以与来自第三方提供商的 SARIF 文件一起使用。 ``` on: push: jobs: check-codeql-versions: runs-on: ubuntu-latest permissions: security-events: write steps: - name: Checkout code uses: actions/checkout@v3 - name: Run SAST scan run: sast-scan.sh --output=scan-results.sarif - name: Upload scan results # define an 'id' for the upload step id: upload uses: github/codeql-action/upload-sarif@v2 with: # specify the SARIF file to upload sarif_file: scan-results.sarif wait-for-processing: true - name: Dismiss alerts if: github.ref == 'refs/heads/main' uses: advanced-security/dismiss-alerts@v1 with: # specify a 'sarif-id' and 'sarif-file' sarif-id: ${{ steps.upload.outputs.sarif-id }} sarif-file: scan-results.sarif env: GITHUB_TOKEN: ${{ github.token }} ``` ### 使用包含多个 SARIF 文件的目录 像 Checkov 这样的工具可以在目录中输出多个 SARIF 文件。`sarif-file` 输入支持单个文件路径和目录路径。如果提供的是目录,所有 `.sarif` 和 `.sarif.json` 文件都将被递归处理。 ``` on: push: jobs: checkov-scan: runs-on: ubuntu-latest permissions: security-events: write steps: - name: Checkout code uses: actions/checkout@v3 - name: Run Checkov run: | mkdir -p checkov-results checkov --directory . --output sarif --output-file-path checkov-results - name: Upload scan results # define an 'id' for the upload step id: upload uses: github/codeql-action/upload-sarif@v2 with: # specify the directory containing SARIF files sarif_file: checkov-results wait-for-processing: true - name: Dismiss alerts if: github.ref == 'refs/heads/main' uses: advanced-security/dismiss-alerts@v1 with: # specify a 'sarif-id' and directory containing SARIF files sarif-id: ${{ steps.upload.outputs.sarif-id }} sarif-file: checkov-results env: GITHUB_TOKEN: ${{ github.token }} ``` ## 功能与限制 ### 抑制注释的工作原理 支持两种注释风格: - **`lgtm[rule-id]`** - 抑制与注释位于**同一行**的警报。 - **`codeql[rule-id]`** - 抑制位于**下一行**的警报(注释必须位于警报的*前一行*)。 例如,以下是来自 [`crate/crate-python`](https://github.com/crate/crate-python/blob/main/src/crate/client/__init__.py) 的一个真实抑制注释: ``` # codeql[py/unused-global-variable] apilevel = "2.0" threadsafety = 1 paramstyle = "pyformat" ``` ``` # codeql[py/unused-global-variable] apilevel = "2.0" # codeql[py/unused-global-variable] threadsafety = 1 # codeql[py/unused-global-variable] paramstyle = "pyformat" ``` - 此操作应仅在默认分支上运行,因为警报的驳回状态是一个全局属性。如果此操作在推送到功能分支或 pull request 的事件上运行,那么被抑制的警报也会在默认分支上被驳回。 - 当在包含警报的行上添加抑制注释时,该警报将被关闭,并且重复的警报将被标记为已修复。这是因为代码扫描使用警报所在行内容的哈希值作为唯一标识符。插入的抑制注释更改了该行的内容,因此也更改了警报的哈希值。由于警报哈希值不再匹配,原始警报会被视为 `fixed`(已修复),并在原位置创建一个新警报。由于抑制注释的作用,这个新警报会立即被标记为 `dismissed`(已驳回)。为避免此问题,建议使用允许将抑制标记放置在警报前一行的抑制风格。
标签:DevSecOps, GitHub Actions, SARIF, 上游代理, 网络调试, 自动化, 自动化攻击, 自动笔记