jpr5/gh-workflow-scanner
GitHub: jpr5/gh-workflow-scanner
确定性 GitHub Actions 工作流安全扫描器,覆盖 21 条规则并支持自动修复,帮助团队在 CI/CD 流程中持续发现和修复供应链安全隐患。
Stars: 0 | Forks: 0
# Sentinel
**专为 GitHub Actions 工作流设计的确定性安全扫描器**



扫描 GitHub Actions 工作流中的 21 个安全漏洞。无需 AI,无需 gems —— 纯 Ruby stdlib 实现。
文档:https://sentinel.copilotkit.dev
## 安装说明
```
# 一次性执行 (类似 npx — Ruby 3.2+)
gem exec sentinel-ci scan owner/repo
# 或者全局安装
gem install sentinel-ci
sentinel scan owner/repo
# 或者 clone 并直接运行
git clone https://github.com/CopilotKit/sentinel.git
cd sentinel
export GITHUB_TOKEN=$(gh auth token)
bin/sentinel scan owner/repo
```
要求 Ruby 3.2+。除 stdlib(`yaml`、`net/http`、`optparse`、`json`)外无其他依赖。
## 用法
```
# 扫描单个 repo
bin/gh-workflow-scanner owner/repo
# 扫描本地 checkout
bin/gh-workflow-scanner --local /path/to/repo
# 扫描整个 GitHub org
bin/gh-workflow-scanner --org my-org
# JSON 输出,筛选 high 及以上 severity
bin/gh-workflow-scanner --format json --severity high owner/repo
```
## GitHub Action
用作 GitHub Action 以在每个 PR 上自动扫描工作流:
```
- uses: jpr5/gh-workflow-scanner-action@v1
with:
severity: high
```
完整的工作流示例:
```
name: Workflow Security Scan
on:
pull_request:
paths: ['.github/workflows/**']
permissions:
contents: read
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: jpr5/gh-workflow-scanner-action@v1
id: scan
with:
severity: high
fail-on-findings: true
```
**输入参数:**
| 名称 | 默认值 | 描述 |
|------|---------|-------------|
| `severity` | `high` | 最低严重级别:`critical`、`high`、`medium`、`low` |
| `fail-on-findings` | `true` | 如果存在超过阈值的发现则使检查失败 |
**输出结果:**
| 名称 | 描述 |
|------|-------------|
| `findings-count` | 达到或超过严重级别的发现总数 |
| `critical-count` | 严重 级别发现数量 |
| `high-count` | 高危 级别发现数量 |
发现结果将以行内注释的形式显示在 PR diff 中 —— critical/high 显示为错误,medium 显示为警告,low 显示为通知。
## 检查内容
| # | 规则 | 严重性 | 内容 |
|---|------|----------|------|
| 1 | `unpinned-actions` | critical/medium | 标签锁定 actions(第三方为 critical,`actions/*` 为 medium) |
| 2 | `shell-injection-expr` | critical | `run:` 块中存在攻击者可控的 `${{ }}` |
| 3 | `shell-injection-jq` | critical | 双引号 jq/curl 字符串中的 `${VAR}` |
| 4 | `dangerous-triggers` | critical | `pull_request_target` + 拉取 fork 代码 |
| 5 | `missing-persist-credentials` | high | `actions/checkout` 未设置 `persist-credentials: false` |
| 6 | `credential-window` | high | Git 凭证配置位置远离 push 步骤 |
| 7 | `static-aws-credentials` | high | 使用静态 AWS 密钥而非 OIDC 联合身份验证 |
| 8 | `unscoped-app-token` | high | `create-github-app-token` 未进行 `permission-*` 范围限定 |
| 9 | `docker-build-arg-secrets` | high | Docker build-args 中包含 Secrets(在 image 层中可见) |
| 10 | `build-publish-same-job` | high | 在包含发布 Secrets 的同一 job 中进行构建和发布 |
| 11 | `curl-pipe-shell` | high | 无完整性校验的 `curl \| sh` |
| 12 | `missing-permissions` | medium | 缺少顶层 permissions 块 |
| 13 | `git-config-global` | medium | 带有凭证的 `git config --global` |
| 14 | `missing-timeouts` | medium | 缺少 `timeout-minutes` 的 Jobs |
| 15 | `missing-env-protection` | medium | 缺少环境保护的 Publish/deploy jobs |
| 16 | `allow-forks-artifact` | medium | 在特权上下文中下载由 Fork 生成的 artifact |
| 17 | `missing-frozen-lockfile` | medium | 未使用 `--frozen-lockfile` / `npm ci` 进行包安装 |
| 18 | `unpinned-docker-image` | low | 使用 `:latest` 标签的 Docker 镜像 |
| 19 | `overly-broad-triggers` | low | 无 branch/path 过滤器的 Push/PR 触发器 |
| 20 | `missing-dependabot` | low | 缺少针对 github-actions 生态系统的 Dependabot 配置 |
| 21 | `missing-zizmor` | low | 无 zizmor 静态分析工作流 |
## 自动修复
Sentinel 可以自动生成三类规则的修复方案:
```
bin/gh-workflow-scanner --fix owner/repo # future CLI flag
```
或者直接使用 Ruby API:
```
require_relative "lib/auto_fix"
require_relative "lib/sha_resolver"
resolver = ShaResolver.new
patched = AutoFix.apply(finding, raw_yaml, sha_resolver: resolver)
```
**可修复的规则:**
| 规则 | 修复策略 |
|------|-------------|
| `unpinned-actions` | 通过 GitHub API 将 tag 解析为 SHA |
| `shell-injection-expr` | 将表达式移动到步骤级 `env:` 块中 |
| `missing-persist-credentials` | 为 checkout 添加 `persist-credentials: false` |
## PR 机器人
主动扫描热门公共仓库,并为 critical 发现开启修复 PR。
```
ruby bot/scanner_bot.rb --pattern shell-injection --dry-run
```
**特性:**
- GitHub Code Search 查找易受攻击的仓库
- 为可机械化修复的规则自动生成修复 PR
- 频率限制(50 PRs/天),stars 阈值(>100)
- 支持退出,机器人身份清晰明确
- 作为每日 cron 通过 GitHub Actions 运行
## 选项
```
--format FORMAT terminal (default) or json
--severity LEVEL minimum severity: critical, high, medium, low (default: low)
--local PATH scan local directory
--org ORG scan all repos in a GitHub org
--token TOKEN GitHub API token (default: GITHUB_TOKEN env var)
```
## 退出代码
- `0` -- 无 critical 或 high 发现
- `1` -- 存在 critical 或 high 发现
- `2` -- 用法错误
## 架构
```
bin/gh-workflow-scanner # CLI entry point (optparse)
action/
annotate.rb # GitHub Action annotation emitter
lib/
scanner.rb # orchestrator
rule_engine.rb # loads + runs all rules
workflow.rb # YAML parser + helpers
finding.rb # finding data struct
github_client.rb # GitHub API client
local_client.rb # filesystem client
auto_fix.rb # auto-fix engine
sha_resolver.rb # GitHub tag -> SHA resolver
formatter/
terminal.rb # colored terminal output
json.rb # JSON output
rules/
base.rb # abstract rule interface
*.rb # one file per rule (19 rules)
bot/
scanner_bot.rb # PR bot orchestrator
search.rb # GitHub Code Search client
state.rb # JSON-file state tracking
pr_writer.rb # cross-fork PR creation
config.rb # bot configuration
```
## 添加规则
创建 `lib/rules/my_rule.rb`:
```
module Rules
class MyRule < Base
def name = "my-rule"
def description = "What this detects"
def severity = :high # :critical, :high, :medium, :low
def check(workflow)
findings = []
# workflow.uses_actions, workflow.run_blocks, workflow.raw_lines, etc.
# Use finding() helper or construct Finding.new() directly
findings
end
end
end
```
规则会从 `lib/rules/` 自动发现。
## 许可证
MIT
标签:CI/CD安全, DevSecOps, GitHub Actions, GitHub Action插件, Llama, Ruby, StruQ, YAML解析, 上游代理, 动态分析, 安全合规, 工作流安全, 无依赖, 知识库, 确定性扫描, 纯Ruby, 组织安全扫描, 网络代理, 自动化安全检查, 自动笔记, 跨仓库扫描, 软件开发工具包, 错误基检测, 静态代码分析