S1YOL/portcullis
GitHub: S1YOL/portcullis
Portcullis 是一个零依赖的 PR 安全门禁工具,在代码审查阶段拦截密钥泄露、依赖项 CVE 和 IaC/CI 配置错误。
Stars: 0 | Forks: 0
# Portcullis
**一个用于 pull request 的左移安全门禁。** Portcullis 会扫描每个 PR,查找硬编码的 **secrets**、**易受攻击的依赖项**以及**基础设施 / CI 配置错误**,将扫描结果发布回 PR,将其作为 SARIF 上传至 GitHub 的 **Security tab**,并在超过您设定的严重性阈值时**使构建失败** —— 从而确保问题在代码审查中被发现,而不是遗留到生产环境中。
## 为什么需要
大多数团队发现安全问题的途径通常都不太理想:要么是没人看的扫描器报告,要么是发生了安全事件。Portcullis 将检查环节放在**开发者已经在的地方** —— pull request —— 并使其成为一个**门禁**,而不仅仅是建议。
- **Secrets** - git 历史记录中泄露的密钥就像一颗随时引爆的定时炸弹。
- **依赖项** - 大多数被利用的漏洞都是第三方包中已知的 CVE。
- **IaC / CI** - 使用 `pull_request_target` 检出 fork 代码,或者将 security group 开放给 `0.0.0.0/0`,是导致 pipeline 和云账户被接管的常见原因。
只需一个 action 即可涵盖这三个方面,并且**零运行时依赖**(纯 Python 标准库 —— 无需 pip install,自身也没有供应链攻击面)。
## 检查内容
| 领域 | 示例 | 判定依据 |
|---|---|---|
| **Secrets** | AWS / GitHub / Slack / Google / Stripe token、私钥、JWT,以及通用的针对高熵特征的扫描 | 精心维护的正则表达式 + Shannon 熵 |
| **依赖项 (SCA)** | `requirements.txt`、`package.json`、`go.mod` 锁定版本中的已知 CVE | 免费的 [OSV.dev](https://osv.dev) API - 无需密钥 |
| **IaC / CI** | `curl \| sh`、root container、未锁定的 action、`pull_request_target` 检出、脚本注入、开放的 security group、通配符 IAM | 内置规则集 |
完整规则参考:[`docs/rules.md`](docs/rules.md)。
**实时 secret 验证。** 在 `verify-secrets: true` 模式下运行时,Portcullis 会确认检测到的 token 是否*当前实际有效*(例如 GitHub PAT)。经验证有效的 secret 将被升级为 **Critical** 级别 —— 这不再是疑似泄漏,而是确实发生了泄漏。
## 快速开始 (GitHub Action)
添加 `.github/workflows/security.yml`:
```
name: Security
on: [pull_request]
permissions:
contents: read
pull-requests: write # PR comment
security-events: write # SARIF upload
jobs:
portcullis:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- id: scan
uses: S1YOL/portcullis@v1
continue-on-error: true # let SARIF upload even when the gate fails
with:
fail-on: high
verify-secrets: 'true'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: portcullis.sarif
category: portcullis
- if: steps.scan.outputs.blocked == 'true'
run: exit 1 # enforce the gate
```
就是这样。在下一个 PR 中,您将获得 diff 上的内联注释、总结性评论、**Security** tab 中的警报,以及如果超过阈值时显示的失败检查。
## 快速开始 (CLI)
```
# 无需安装 - 它是 standard-library Python。
python -m portcullis path/to/repo --fail-on high --sarif results.sarif
# 只有一个 scanner,并验证它发现的任何 secrets 是否为 live:
python -m portcullis . --only secrets --verify-secrets
# 仅生成报告(从不会导致 build 失败):
python -m portcullis . --fail-on none
```
当门禁通过时退出代码为 `0`,阻断时为 `1` —— 因此它可以直接接入任何 CI 系统,而不仅限于 GitHub。
## 示例
针对内置的 [`examples/vulnerable-sample`](examples/vulnerable-sample) 运行:
```
Portcullis - scan results
----------------------------------------------
Critical 3
High 11
Medium 13
Low 1
----------------------------------------------
Total: 28 finding(s)
[CRIT] pyyaml 5.1 - CVE-2020-1747
requirements.txt:2
[HIGH] GitHub Personal Access / App Token
app_config.py:11
[HIGH] pull_request_target checks out untrusted PR code
.github/workflows/ci.yml:5
[HIGH] Security group open to the entire internet
main.tf:10
...
Portcullis gate: 14 finding(s) at or above 'High' - failing the build.
```
## 配置
| 输入项 | 默认值 | 描述 |
|---|---|---|
| `path` | `.` | 要扫描的目录。 |
| `fail-on` | `high` | 导致构建失败的最低严重级别:`critical`/`high`/`medium`/`low`/`none`。 |
| `only` | *(全部)* | 逗号分隔的子集:`secrets,deps,iac`。 |
| `verify-secrets` | `false` | 在支持的场景下对检测到的 secret 进行实时验证。 |
| `sarif-file` | `portcullis.sarif` | 写入 SARIF 2.1.0 的位置。 |
| `comment-pr` | `true` | 在 PR 上发布/更新结果评论。 |
输出项:`findings`(计数)和 `blocked`(`true`/`false`)。
## 工作原理
```
manifests / source tree
|
|-- secrets : regex + entropy (+ optional live verification)
|-- deps : parse pins -> OSV.dev -> known CVEs
|-- iac : curated Dockerfile / GitHub Actions / Terraform rules
|
v
findings --> SARIF 2.1.0 --> GitHub code scanning (Security tab)
--> Markdown --> PR comment + Actions step summary
--> policy gate --> exit code (pass / fail)
```
所有内容都共享同一个 `Finding` 模型,因此添加扫描器或规则只是一个局部的微小改动。
## 开发说明
```
pip install -r requirements-dev.txt
ruff check portcullis/ tests/ --select E,F,W --ignore E501,E402
python -m pytest tests/ -v
```
Portcullis 会进行自我测试:[`.github/workflows/security.yml`](.github/workflows/security.yml) 会在本仓库中运行此 action。
## 关联项目
Portcullis 是应用安全的**左移 / 静态**部分。它的兄弟项目 [**W3BSP1D3R**](https://github.com/S1YOL/W3BSP1D3R) 则是**运行时 / DAST**部分 —— 这是一个用于攻击实时应用以发现漏洞的 Web 漏洞扫描器。它们共同涵盖了整个 SDLC 的安全:在 PR 中拦截问题,*并在*运行时进行验证。
## 许可证
MIT - 查看 [LICENSE](LICENSE)。
标签:DevSecOps, Python, StruQ, 上游代理, 代码安全, 文档安全, 无后门, 漏洞枚举, 逆向工具, 静态应用安全测试