tinydarkforge/SecGate
GitHub: tinydarkforge/SecGate
一款轻量级 CI/CD 安全门禁编排工具,将五款主流开源扫描器统一调度并输出标准化报告与退出码,在发现高危问题时自动阻断构建流水线。
Stars: 0 | Forks: 0
```
╔═══════╗ █████ █████ █████ █████ █████ █████ █████
║ ╔═══╗ ║ █ █ █ █ █ █ █ █
║ ║ ⊙ ║ ║ █████ ████ █ █ ███ █████ █ ████
║ ╚═══╝ ║ █ █ █ █ █ █ █ █ █
╠═══════╣ █████ █████ █████ █████ █ █ █ █████
║ ░░░░░ ║
╔═══╬═══════╬═══╗ ━━━━━━━━━━━━━ SECURITY GATE ━━━━━━━━━━━━━
║ ║ [===] ║ ║ Semgrep · Gitleaks · osv-scanner · Trivy
╚═══╬═══════╬═══╝ · npm audit — one command, one report,
║ ║ ║ ║ one exit code. MIT · No account · No tel.
╚═╝ ╚═╝
```
## ░▒▓█ 太长不看
```
npx @tinydarkforge/secgate .
```
对当前目录运行所有五个扫描器,输出一份 JSON 报告、一份独立的 HTML 报告,以及(可选的)SARIF 报告。检测结果干净时退出码为 `0`,存在 CRITICAL/HIGH 级别结果时退出码为 `1`。这就是本产品的全部功能。
## ░▒▓█ 目前功能
SecGate 封装了五个现有的开源扫描器,对指定目录运行它们,并生成:
- **一份统一的 JSON 报告**,汇总所有扫描器的结果
- **一份独立的 HTML 报告**,带有按扫描器区分的标签页、暗黑模式、无任何外部资源依赖
- **一份 SARIF 2.1.0 文件**,可直接上传至 GitHub Code Scanning
- **一个统一的退出码** —— 当存在 CRITICAL 或 HIGH 级别的发现时为 `1`;用于阻断 CI 流水线
SecGate 并不附带自己的分析引擎。每一项发现均源于这五个底层工具之一。其核心价值在于**任务编排、结果标准化和单一退出码。**
## ░▒▓█ 扫描器
| 扫描器 | 类别 | 备注 |
|---------------|---------------------------|-----------------------------------------------------------------------|
| **Semgrep** | SAST (静态代码) | OSS 规则集。支持 10+ 种语言。可通过 `customSemgrepRules` 扩展。 |
| **Gitleaks** | 密钥与凭证 | 工作树 + git 历史(当 `.git/` 存在时)。密钥会被脱敏。 |
| **npm audit** | Node 依赖 (SCA) | 当 `package.json` 存在时运行。使用 GitHub advisory DB。 |
| **osv-scanner** | 多语言 SCA | npm, PyPI, Go, Cargo, Maven, RubyGems, Packagist, NuGet, Pub. |
| **Trivy** | IaC + 许可证 + 镜像 | Terraform, Kubernetes, Dockerfile, CloudFormation。基础镜像 CVE。 |
缺失的扫描器二进制文件会被**优雅地跳过**,并在报告中注明。不强制要求任何扫描器;SecGate 会使用 `$PATH` 上可用的任何工具。
## ░▒▓█ 产品定位
SecGate **不是** SOC 平台、合规工具或漏洞管理系统。它是一个 **CI 门禁**,聚合扫描器输出并在发现严重问题时使构建失败。
| 替代方案 | 何时应选择它而非 SecGate |
|--------------------|-----------------------------------------------------------------|
| **Trivy standalone** | 仅扫描容器且不需要 SAST 或密钥检测。 |
| **Semgrep OSS** | 仅需要带自定义规则的 SAST。 |
| **Snyk** | 需要托管的漏洞库、分诊 UX、Jira 同步 —— 以及预算。|
| **Aikido** | 想要 SaaS 仪表盘,并接受托管账户模式。 |
**SecGate 的定位:** 零配置编排,无需账户,无遥测,仅本地输出,MIT 许可证。如果你需要 SaaS 级别的分诊或合规工作流,请购买 Snyk 或 Aikido。完整对比矩阵:[`docs/comparison.md`](docs/comparison.md)。
## ░▒▓█ 产品愿景
SecGate 将成为更广泛安全工作流的开源输入层。**核心 CLI** —— 扫描编排、SARIF 输出、基线、抑制、HTML 报告 —— 将**永远保持 MIT 许可并免费**。未来的付费扩展可能会增加托管仪表盘、组织级策略管理、合规证据包,以及为需要比本地门禁更多功能的团队提供的多仓库聚合。这些目前尚不存在。OSS 边界定义在 [`OPEN-CORE.md`](OPEN-CORE.md) 中。
## ░▒▓█ 前置条件
Node.js `>=18`。外部扫描器可选 —— 只需安装你想运行的工具即可。
```
# macOS
brew install semgrep gitleaks osv-scanner trivy
# Linux
pip install semgrep
# gitleaks: https://github.com/gitleaks/gitleaks#installing
# osv-scanner: https://github.com/google/osv-scanner#installation
# trivy: https://aquasecurity.github.io/trivy/latest/getting-started/installation/
```
## ░▒▓█ 安装
### 通过 npm 安装(推荐)
```
npm install -g @tinydarkforge/secgate
```
### 通过 npx 一次性运行(无需安装)
```
npx @tinydarkforge/secgate .
```
### 从源码构建
```
git clone https://github.com/tinydarkforge/SecGate.git
cd SecGate
npm install
chmod +x secgate.js
sudo ln -sf "$(pwd)/secgate.js" /usr/local/bin/secgate
```
## ░▒▓█ 使用方法
```
# 扫描当前目录 (dry-run,默认)
secgate .
# 通过自动修复进行扫描 (仅限 npm audit fix — 请参阅以下警告)
secgate . --apply
# 带有调试输出的扫描
secgate . --debug
# 扫描特定路径
secgate /path/to/project
# 将报告写入自定义目录 (默认: 目标)
secgate /path/to/project --output-dir /tmp/reports
# 从报告中剥离绝对路径 (当 CI=true 时自动开启)
secgate /path/to/project --strip-paths
# 版本 / 帮助
secgate --version
secgate --help
```
**退出码**
| 代码 | 含义 |
|:----:|----------------------------------------------------|
| `0` | PASS —— 没有 CRITICAL 或 HIGH 级别的发现 |
| `1` | FAIL —— 存在 CRITICAL 或 HIGH 级别的发现 |
| `2` | 无效目标或 CLI 错误 |
## ░▒▓█ 安全 —— 在不受信任的仓库中使用 `--apply`
**已到位的加固措施:**
- 在 `--apply` 下执行所有 npm 命令时都会带上 `--ignore-scripts` 参数 —— 目标 `package.json`(或其依赖)中的恶意 `preinstall` / `postinstall` 脚本**不会被执行**。
- `--apply` **受限执行**:除非设置了 `SECGATE_CONFIRM_APPLY=1`(CI / 非交互模式)或用户在交互式 TTY 提示符下输入 `y`,否则拒绝运行。
- 每一次 `--apply` 执行都会被记录在报告的 `auditLog` 字段中,并附带时间戳和目标镜像输出到 stderr。
**操作指南:**
- **不要在不受信任或新克隆的第三方仓库上运行 `--apply`。** 先运行 dry-run(试运行),审查结果后再做决定。
- 在 CI 中,首选 dry-run(`secgate .`)并依靠退出码来作为门禁。如果必须使用 `--apply`,请在设置了 `SECGATE_CONFIRM_APPLY=1` 的隔离临时 runner 中执行。
- 报告文件默认输出到目标目录。使用 `--output-dir` 重定向;当 `cwd !== target` 时会在 stderr 打印警告。
- 在 CI 中,会自动启用 `--strip-paths` 以防止主机路径泄露到上传的构建产物中。
## ░▒▓█ 配置
在你的扫描目标目录下创建 `.secgate.config.json`。所有字段均为可选。
```
{
"failOn": ["critical", "high"],
"scanners": {
"semgrep": true,
"gitleaks": true,
"npm": true,
"osv": true,
"trivy": false
},
"severityOverrides": [
{ "rule": "npm-audit.lodash", "severity": "LOW" },
{ "rule": "trivy-DS*", "severity": "MEDIUM" }
],
"ignore": ["CVE-2024-12345", "npm:some-old-package*"],
"baselineFile": ".secgate-baseline.json",
"customSemgrepRules": "./rules/"
}
```
JSON Schema: [`docs/config.schema.json`](docs/config.schema.json)
### 字段说明
| 字段 | 类型 | 默认值 | 描述 |
|----------------------|-----------------|----------------------------|-----------------------------------------------------------------------------|
| `failOn` | `string[]` | `["critical","high"]` | 导致退出码为 `1` 的严重性级别 |
| `scanners` | `object` | 所有为 `true` | 将任何扫描器设置为 `false` 以跳过它 |
| `severityOverrides` | `array` | `[]` | 覆盖匹配签名的严重性(支持 glob 通配符 `*`) |
| `ignore` | `string[]` | `[]` | 丢弃签名匹配的发现结果(支持 glob 通配符 `*`) |
| `baselineFile` | `string` | `.secgate-baseline.json` | 基线文件的路径(相对于目标目录) |
| `customSemgrepRules` | `string\|null` | `null` | 传递给 semgrep 的额外 `--config=` 参数 |
### 优先级
```
CLI flag > .secgate.config.json > built-in defaults
```
- `--baseline` 和 `--update-baseline` 仅支持通过 CLI 指定(无等效的配置项)。
- 缺失配置文件:静默处理,应用默认值。无效 JSON:记录错误,应用默认值。
### 基线工作流
```
# 1. 接受当前状态作为 baseline
secgate . --update-baseline
# 2. 在后续运行中,仅在出现全新发现时失败
secgate . --baseline
```
将 `.secgate-baseline.json` 提交到你的代码库中。被基线化的发现结果在报告中会带有 `baseline` 标记,并被排除在失败门禁之外。
### 内联抑制
在标记行或其紧邻的上一行添加注释:
```
// secgate:ignore
db.query(userInput);
db.execute(sql); // secgate:ignore my.rule.id
/* secgate:ignore my.rule.id */
dangerousCall();
```
被抑制的发现结果不计入统计计数器。报告的 `suppressions` 部分会记录每条规则的计数以供审计。
## ░▒▓█ CI / CD
### GitHub Actions —— 最小配置
```
# .github/workflows/secgate.yml
- name: Run SecGate
run: npx @tinydarkforge/secgate .
# exits 1 on CRITICAL or HIGH findings — blocks the pipeline
```
### 非阻塞(仅生成报告)
```
- name: Run SecGate
run: npx @tinydarkforge/secgate . || true
- name: Upload report
uses: actions/upload-artifact@v4
with:
name: secgate-report
path: |
secgate-v7-report.json
*.html
```
### 作为复合 GitHub Action 使用
本仓库的 `.github/actions/secgate/` 目录中提供了一个复合 action。
```
- name: SecGate Security Gate
id: secgate
uses: tinydarkforge/SecGate/.github/actions/secgate@main
with:
target: "."
apply: "false"
fail-on: "critical,high"
format: "json,html,sarif"
- name: Upload HTML + JSON
if: always()
uses: actions/upload-artifact@v4
with:
name: secgate-report
path: |
secgate-v7-report.json
*.html
- name: Upload SARIF to Code Scanning
if: always() && steps.secgate.outputs.sarif-path != ''
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: ${{ steps.secgate.outputs.sarif-path }}
category: secgate
```
**Action 输入**
| 输入 | 默认值 | 描述 |
|-----------|------------------|----------------------------------------------------------|
| `target` | `.` | 要扫描的目录 |
| `apply` | `false` | 执行可修复的补救措施 |
| `fail-on` | `critical,high` | 导致步骤失败的严重性级别 |
| `format` | `json,html` | 输出格式 —— 以逗号分隔:`json`, `html`, `sarif`|
**Action 输出**
| 输出 | 描述 |
|---------------|---------------------------------------------------------------|
| `report-path` | `secgate-v7-report.json` 的路径 |
| `sarif-path` | `.sarif.json` 的路径(仅当格式包含 SARIF 时设置) |
**在生产工作流中请固定到完整的 commit SHA**:
```
uses: tinydarkforge/SecGate/.github/actions/secgate@
```
完整的参考工作流请参见 [`.github/workflows/example-secgate.yml`](.github/workflows/example-secgate.yml)。
## ░▒▓█ SARIF 输出
SecGate 会与 JSON 和 HTML 并行输出 [SARIF 2.1.0](https://sarifweb.azurewebsites.net/)。SARIF 是 GitHub Code Scanning、GitLab SAST 及其他平台使用的标准格式。
```
secgate . --format sarif
# 写入: secgate-v7-report.json, .html, .sarif.json
```
`--format` 标志接受逗号分隔的列表。`sarif` 是**增量附加的** —— JSON 和 HTML 始终会被写入:
```
secgate . --format json,html,sarif # same as above
secgate . --format sarif # also writes JSON + HTML
```
### SARIF 结构
- 每个扫描器对应一个 `runs[]` 条目:`semgrep`、`gitleaks`、`npm`、`osv`、`trivy`、`trivyImage`(共 6 个)。
- 每项发现映射为一个 `result`,包含 `ruleId = signature`,`level` 由严重性派生,当存在文件/行数据时包含 `locations[].physicalLocation`。
- `properties["security-severity"]` 携带用于 GitHub 排序的 CVSS 风格分数:`CRITICAL = 9.5`、`HIGH = 7.5`、`MEDIUM = 5`、`LOW = 2`、`UNKNOWN = 0`。
### 上传至 GitHub Code Scanning
```
- name: Run SecGate
id: secgate
run: npx @tinydarkforge/secgate . --format sarif
- name: Upload SARIF
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: .sarif.json
category: secgate
```
## ░▒▓█ 报告输出
每次运行会生成:
- **`secgate-v7-report.json`** —— 机器可读,schema 见下方。
- **`.html`** —— 独立的 HTML 报告,带有按扫描器区分的标签页、暗黑模式、无任何外部资源依赖。文件名由目标目录名派生。
- **`.sarif.json`** —— SARIF 2.1.0 文件(仅当传入 `--format sarif` 时生成)。
### JSON schema
```
{
"version": "0.2.3",
"timestamp": "ISO 8601",
"target": "/absolute/path",
"mode": "dry-run | apply",
"status": "PASS | FAIL",
"summary": {
"critical": 0,
"high": 0,
"medium": 0,
"low": 0,
"unknown": 0
},
"tools": {
"semgrep": "ran | clean | skipped | error | pending",
"gitleaks": "ran | clean | skipped | error | pending",
"npm": "ran | clean | skipped | error | pending",
"osv": "ran | clean | skipped | error | pending",
"trivy": "ran | clean | skipped | error | pending",
"trivyImage": "ran | clean | skipped | error | pending"
},
"findings": [
{
"tool": "gitleaks | semgrep | npm | osv | trivy | trivyImage",
"type": "secret | code | dependency | iac | license",
"severity": "CRITICAL | HIGH | MEDIUM | LOW | UNKNOWN",
"signature": "rule or package ID",
"message": "description",
"file": "relative or absolute path, or null",
"line": 42,
"col": 5,
"endLine": 42,
"fixable": false,
"fixableBy": "auto | manual | null"
}
],
"intelligence": {
"riskScore": 0,
"attackSurface": ["secret", "dependency", "iac", "license", "code"],
"reasoning": [{ "issue": "...", "why": "..." }],
"recommendations": ["..."]
},
"remediation": {
"plan": [{
"issue": "...",
"patch": {
"action": "...",
"cmd": "display string or null",
"exec": { "binary": "npm", "args": ["audit", "fix", "--ignore-scripts"], "cwd": "..." }
}
}],
"stagedChanges": [],
"executed": [],
"blocked": [],
"confidence": 100
},
"auditLog": [
{
"timestamp": "ISO 8601",
"event": "apply_start | apply_confirmed | apply_exec | apply_ok | apply_fail",
"target": "target path or repo basename (if --strip-paths)"
}
]
}
```
### 严重性层级
在 `addFinding()` 入口处,每一项发现都会被标准化为以下五个层级之一:
| 层级 | 含义 |
|-------------|------------------------------------------------------------------------------------------|
| **CRITICAL**| 当前可被利用 —— 密钥、CVSS ≥ 9、硬编码凭证的 SAST 规则 |
| **HIGH** | 高危影响 —— CVSS 7.0–8.9、Semgrep `ERROR`、上游评级为 `HIGH` |
| **MEDIUM** | 具有实质影响 —— CVSS 4.0–6.9、`WARNING`、`MODERATE` |
| **LOW** | 仅提供信息 —— CVSS < 4.0、`INFO`、`NOTE` |
| **UNKNOWN** | 上游未提供严重性或提供了无法识别的值 —— 展示出来而不是错误计数 |
### 可修复性
- `fixableBy: "auto"` —— `patch()` 返回一个可执行命令;`--apply` 会运行它(目前仅支持 `npm audit fix`)。
- `fixableBy: "manual"` —— 存在补丁但需要人工干预(升级、轮换、重构)。
- `fixable: true` 是 `fixableBy === "auto"` 的镜像,用于 CI 的便捷性。
### 工具状态
| 状态 | 含义 |
|-------------|------------------------------------------------------------------------------|
| `ran` | 工具已执行,存在发现结果 |
| `clean` | 工具已执行无发现结果 |
| `skipped` | 工具未安装,或目标不适用(无 `package.json`、无 lockfile)|
| `error` | 工具生成了无法解析的输出 —— 使用 `--debug` 重新运行 |
| `pending` | 工具未运行(不应出现在最终报告中) |
## ░▒▓█ 风险评分
发现结果在入口处会被应用静态权重进行评分:
| 严重性 | 权重 |
|----------|:------:|
| CRITICAL | 10 |
| HIGH | 6 |
| MEDIUM | 3 |
| LOW | 1 |
报告中的 `riskScore` 是所有发现结果的这些权重之和。这是一个**启发式计数值**,不是 CVSS、不是 EPSS,也不是漏洞利用概率建模。用它来对比同一仓库随时间变化的扫描结果 —— 而不是作为绝对的安全态势评分。
## ░▒▓█ 文档
| 文档 | 包含内容 |
|--------------------------------------------------------|--------------------------------------------------------------------------------|
| [`OPEN-CORE.md`](OPEN-CORE.md) | OSS 核心边界与付费扩展路线图 |
| [`docs/comparison.md`](docs/comparison.md) | 对比 Snyk / Trivy / Semgrep / Aikido 的功能矩阵 |
| [`docs/coverage.md`](docs/coverage.md) | 扫描器到类别的矩阵及明确的盲区 |
| [`docs/tuning.md`](docs/tuning.md) | 阈值、基线、抑制,CI 与本地的默认值 |
| [`docs/threat-model.md`](docs/threat-model.md) | STRIDE 分析、信任边界、缓解措施 |
| [`docs/adr/`](docs/adr/) | 架构决策记录 |
| [`SECURITY.md`](SECURITY.md) | 漏洞报告、SLA、协调披露、供应链信任 |
| [`CONTRIBUTING.md`](CONTRIBUTING.md) | 开发环境配置、分支与提交规范、PR 检查清单 |
## ░▒▓█ 贡献
参见 [`CONTRIBUTING.md`](CONTRIBUTING.md)。请按照 [`SECURITY.md`](SECURITY.md) 中的说明私下报告漏洞 —— **不要为安全报告开启公开 issue**。
## ░▒▓█ 许可证
[MIT](LICENSE) — © TinyDarkForge
```
╔═══╗
║ ⊙ ║ "BLOCK. SCAN. GATE."
╚═══╝
```
标签:AI SOC, AI推理, CISA项目, DevSecOps, Gitleaks, GNU通用公共许可证, MITM代理, Node.js, npm audit, npm包, osv-scanner, SAST, Semgrep, StruQ, Web截图, WordPress安全扫描, 上游代理, 代码安全, 依赖漏洞扫描, 安全合规, 安全网关, 容器安全, 漏洞枚举, 盲注攻击, 结构化查询, 网络代理, 自动修复, 自动化安全, 自定义脚本, 错误基检测, 静态代码分析, 风险评分