# Integrating Sast Into Github Actions Pipeline

> 本技能涵盖将静态应用安全测试（SAST）工具 CodeQL 和 Semgrep 集成到 GitHub Actions CI/CD 管道中。 内容包括配置对 pull request 和推送的自动代码扫描、调整规则以减少误报、将 SARIF 结果上传到 GitHub Advanced Security，以及建立在检测到高严重性漏洞时阻止合并的质量门禁。

- Skill: `killvxk/integrating-sast-into-github-actions-pipeline` (Agent Skill, multi-file: 8 files)
- Install (CLI): `npx skillmds@latest add killvxk/integrating-sast-into-github-actions-pipeline`
- Raw SKILL.md: https://api.skillmd.com/api/skills/killvxk/integrating-sast-into-github-actions-pipeline/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- License: Apache-2.0
- Author: killvxk (https://skillmd.com/u/killvxk)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/killvxk/integrating-sast-into-github-actions-pipeline

---


# 将 SAST 集成到 GitHub Actions 管道

## 使用场景

- 开发团队需要在每个 pull request 上进行自动代码级漏洞检测时
- 安全团队需要跨组织所有仓库强制执行一致的 SAST 时
- 从手动或定期安全审查迁移到持续安全测试时
- 合规框架（SOC 2、PCI DSS、NIST SSDF）要求自动代码分析证据时
- monorepo 中存在多种语言需要在单一工作流下统一扫描时

**不适用于**运行时漏洞检测（使用 DAST）、扫描第三方依赖项（使用 Snyk 等 SCA 工具）或基础设施即代码扫描（使用 Checkov 或 tfsec）。

## 前置条件

- 启用了 GitHub Actions 的 GitHub 仓库
- GitHub Advanced Security 许可证（私有仓库上的 CodeQL 必需；公共仓库免费）
- 用于托管规则和 Semgrep App 仪表板的 Semgrep 账号（提供免费层）
- 支持语言的仓库代码：Python、JavaScript/TypeScript、Java、C/C++、C#、Go、Ruby、Swift、Kotlin

## 操作流程

### 步骤 1：配置 CodeQL 分析工作流

创建在 pull request 和每周计划中运行的 CodeQL 工作流，以捕获现有代码中的漏洞。

```yaml
# .github/workflows/codeql-analysis.yml
name: "CodeQL Analysis"

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]
  schedule:
    - cron: '30 2 * * 1'  # 每周一 2:30

jobs:
  analyze:
    name: Analyze (${{ matrix.language }})
    runs-on: ubuntu-latest
    permissions:
      actions: read
      contents: read
      security-events: write

    strategy:
      fail-fast: false
      matrix:
        language: ['javascript', 'python']

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Initialize CodeQL
        uses: github/codeql-action/init@v3
        with:
          languages: ${{ matrix.language }}
          queries: security-extended,security-and-quality

      - name: Autobuild
        uses: github/codeql-action/autobuild@v3

      - name: Perform CodeQL Analysis
        uses: github/codeql-action/analyze@v3
        with:
          category: "/language:${{ matrix.language }}"
```

### 步骤 2：添加 Semgrep 扫描以支持自定义规则

Semgrep 以更快的扫描速度和对自定义模式规则的支持来补充 CodeQL。配置它将 SARIF 结果上传到相同的 GitHub 安全标签。

```yaml
# .github/workflows/semgrep.yml
name: "Semgrep SAST Scan"

on:
  pull_request:
    branches: [main, develop]
  push:
    branches: [main]

jobs:
  semgrep:
    name: Semgrep Scan
    runs-on: ubuntu-latest
    permissions:
      security-events: write
      contents: read

    container:
      image: semgrep/semgrep:latest

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Run Semgrep
        run: |
          semgrep ci \
            --config auto \
            --config p/owasp-top-ten \
            --config p/cwe-top-25 \
            --sarif --output semgrep-results.sarif \
            --severity ERROR \
            --error
        env:
          SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }}

      - name: Upload SARIF
        if: always()
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: semgrep-results.sarif
          category: semgrep
```

### 步骤 3：为组织模式创建自定义 Semgrep 规则

编写特定于组织的规则，以捕获代码库中独特的模式，例如已弃用的内部 API 或不安全的配置模式。

```yaml
# .semgrep/custom-rules.yml
rules:
  - id: hardcoded-database-url
    patterns:
      - pattern: |
          $DB_URL = "...$PROTO://...:...$PASS@..."
    message: |
      Hardcoded database connection string with credentials detected.
      Use environment variables or a secrets manager instead.
    languages: [python, javascript, typescript]
    severity: ERROR
    metadata:
      cwe: "CWE-798: Use of Hard-coded Credentials"
      owasp: "A07:2021 - Identification and Authentication Failures"

  - id: unsafe-deserialization
    patterns:
      - pattern-either:
          - pattern: pickle.loads(...)
          - pattern: yaml.load(..., Loader=yaml.Loader)
          - pattern: yaml.load(..., Loader=yaml.FullLoader)
    message: |
      Unsafe deserialization detected. Use safe alternatives to prevent
      remote code execution vulnerabilities.
    languages: [python]
    severity: ERROR
    metadata:
      cwe: "CWE-502: Deserialization of Untrusted Data"

  - id: missing-csrf-protection
    patterns:
      - pattern: |
          @app.route("...", methods=["POST"])
          def $FUNC(...):
              ...
      - pattern-not-inside: |
          @csrf.exempt
          ...
    message: "POST endpoint may lack CSRF protection."
    languages: [python]
    severity: WARNING
```

### 步骤 4：使用分支保护建立质量门禁

配置分支保护规则，要求 SAST 检查在合并前通过，防止易受攻击的代码进入生产分支。

```bash
# 使用 GitHub CLI 设置分支保护，要求 SAST 检查
gh api repos/{owner}/{repo}/branches/main/protection \
  --method PUT \
  --field required_status_checks='{"strict":true,"contexts":["Analyze (javascript)","Analyze (python)","Semgrep Scan"]}' \
  --field enforce_admins=true \
  --field required_pull_request_reviews='{"required_approving_review_count":1}'
```

### 步骤 5：调整和抑制误报

通过 CodeQL 查询过滤器和 Semgrep nosemgrep 注解管理误报，以维护开发者对扫描结果的信任。

```yaml
# codeql-config.yml - 自定义 CodeQL 配置
name: "Custom CodeQL Config"
queries:
  - uses: security-extended
  - uses: security-and-quality
  - excludes:
      id: js/unused-local-variable
paths-ignore:
  - '**/test/**'
  - '**/tests/**'
  - '**/vendor/**'
  - '**/node_modules/**'
  - '**/*.test.js'
  - '**/*.spec.py'
```

```python
# 示例：在 Semgrep 中抑制已知误报
import subprocess

def run_safe_command(cmd_list):
    # nosemgrep: python.lang.security.audit.dangerous-subprocess-use
    result = subprocess.run(cmd_list, capture_output=True, text=True, shell=False)
    return result.stdout
```

### 步骤 6：聚合和报告发现

使用 GitHub 安全概览仪表板，并为跨仓库的安全告警配置通知。

```bash
# 通过 GitHub API 查询 SARIF 结果用于报告
gh api repos/{owner}/{repo}/code-scanning/alerts \
  --jq '.[] | select(.state=="open") | {rule: .rule.id, severity: .rule.security_severity_level, file: .most_recent_instance.location.path, line: .most_recent_instance.location.start_line}'

# 按严重性统计未处理告警
gh api repos/{owner}/{repo}/code-scanning/alerts \
  --jq '[.[] | select(.state=="open")] | group_by(.rule.security_severity_level) | map({severity: .[0].rule.security_severity_level, count: length})'
```

## 关键概念

| 术语 | 定义 |
|------|------|
| SAST | 静态应用安全测试 — 在不执行代码的情况下分析源代码以查找安全漏洞 |
| SARIF | 静态分析结果交换格式 — 用于表达静态分析工具结果的标准化 JSON 格式 |
| CodeQL | GitHub 的语义代码分析引擎，将代码视为数据并查询漏洞模式 |
| Semgrep | 使用模式匹配跨多种语言查找漏洞和安全问题的轻量级静态分析工具 |
| Security Extended | 包含除默认集之外额外安全查询的 CodeQL 查询套件，用于更深入分析 |
| 质量门禁 | 自动检查点，除非满足安全标准，否则阻止代码通过管道 |
| 误报 | 错误地将安全代码识别为易受攻击的扫描发现，需要抑制或调整 |

## 工具与系统

- **CodeQL**：具有深度数据流和污点跟踪分析的 GitHub 语义代码分析引擎
- **Semgrep**：具有 3000+ 社区规则和自定义规则支持的快速轻量级模式匹配 SAST 工具
- **GitHub Advanced Security**：在 GitHub 中提供代码扫描、机密扫描和依赖审查的平台
- **SARIF Viewer**：用于在开发期间本地审查 SARIF 结果的 VS Code 扩展
- **GitHub Security Overview**：汇总所有仓库安全告警的组织级仪表板

## 常见场景

### 场景：包含多种语言的 Monorepo 需要统一 SAST

**背景**：平台团队管理包含 Python 微服务、TypeScript 前端和 Go 基础设施工具的 monorepo。安全审查每季度手动进行一次，遗漏了审查间隔的漏洞。

**方法**：
1. 使用覆盖 Python、JavaScript 和 Go 语言的矩阵策略配置 CodeQL
2. 添加带 `--config auto` 的 Semgrep 以自动检测语言并应用相关规则集
3. 创建基于路径的触发器，使只有更改的语言目录触发各自的扫描
4. 使用每个工具和语言的唯一类别将所有 SARIF 结果上传到 GitHub 安全标签
5. 设置分支保护，要求所有 SAST 作业在合并前通过
6. 安排每周全仓库扫描，以捕获来自新发布 CVE 模式的未更改代码中的问题

**注意事项**：将 CodeQL 设置为在每个 PR 上分析所有语言会显著增加 CI 时间。使用路径过滤器仅触发相关语言扫描。Semgrep 的 `--config auto` 可能启用与 CodeQL 发现冲突的规则，创建重复告警。

### 场景：减少高误报率导致的告警疲劳

**背景**：启用 SAST 后，开发者忽略发现，因为 40% 是误报，破坏了安全程序。

**方法**：
1. 导出所有当前告警并将其分类为真正确、误报或信息性
2. 创建自定义 CodeQL 配置，排除产生最多误报的嘈杂查询 ID
3. 为测试文件、生成代码和供应商依赖项编写 `.semgrepignore` 模式
4. 建立每周分类会议，安全和开发主管审查新规则添加
5. 将误报率作为指标跟踪，目标低于 15% 以维护开发者信任

**注意事项**：过度抑制规则以减少噪音可能造成盲点。始终根据 OWASP Top 10 和 CWE Top 25 验证抑制，确保关键漏洞类别仍被覆盖。

## 输出格式

```
SAST 管道扫描报告
==========================
仓库：org/web-application
分支：feature/user-auth-refactor
扫描日期：2026-02-23
提交：a1b2c3d4

CodeQL 结果：
  语言          运行查询数   发现数   严重   高危   中危
  javascript    312          4        1      2      1
  python        287          2        0      1      1

Semgrep 结果：
  规则集             匹配规则数   发现数   错误   警告
  auto               1,847        3        1      2
  owasp-top-ten      186          2        1      1
  custom-rules       12           1        0      1

质量门禁：失败
  阻塞发现：2 个严重/高危问题
  - [严重] CWE-89：src/api/users.py:47 中的 SQL 注入
  - [高危] CWE-79：src/components/Search.tsx:123 中的跨站脚本

必需操作：允许合并之前修复阻塞发现。
```

