بنقرة واحدة
opensource-preflight
开源发布前综合扫描——一次调用检测密钥泄露、个人信息、内部引用、许可证合规、规范文件缺失和 Git 历史泄露,输出结构化报告并给出修复建议。
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
开源发布前综合扫描——一次调用检测密钥泄露、个人信息、内部引用、许可证合规、规范文件缺失和 Git 历史泄露,输出结构化报告并给出修复建议。
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
| name | opensource-preflight |
| description | 开源发布前综合扫描——一次调用检测密钥泄露、个人信息、内部引用、许可证合规、规范文件缺失和 Git 历史泄露,输出结构化报告并给出修复建议。 |
当用户准备将代码仓库开源发布,或要求进行开源前检查、安全扫描、合规检查时触发此 skill。
| 参数 | 可选值 | 默认值 | 说明 |
|---|---|---|---|
| mode | quick / standard / strict | standard | 扫描深度 |
| path | 目录路径 | 当前工作目录 | 扫描目标 |
| exclude | glob 列表 | node_modules, vendor, *.min.js | 排除路径 |
.opensource-preflight.yml 配置(如有)opensource-preflight-report.md| 等级 | 含义 | 结论影响 |
|---|---|---|
| CRITICAL | 必须修复才能开源 | ✗ 未就绪 |
| HIGH | 强烈建议修复 | ⚠ 需审查 |
| MEDIUM | 建议修复 | ✓ 就绪(附建议) |
| LOW | 可选优化 | ✓ 就绪 |
等级: 全部 CRITICAL
先运行以下命令检测外部工具:
which gitleaks 2>/dev/null && echo "GITLEAKS_AVAILABLE=true"
which trufflehog 2>/dev/null && echo "TRUFFLEHOG_AVAILABLE=true"
如果 gitleaks 可用:
gitleaks detect --source . --no-git --report-format json --report-path /tmp/gitleaks-report.json
如果 trufflehog 可用(作为补充):
trufflehog filesystem . --json > /tmp/trufflehog-report.json
解析 JSON 报告,提取:文件路径、行号、规则名称、匹配内容(脱敏显示前4后4字符)。
依次用 Grep 工具搜索以下模式(排除 exclude 路径):
| 类别 | 正则模式 |
|---|---|
| AWS Access Key | AKIA[0-9A-Z]{16} |
| AWS Secret | aws_secret_access_key\s*[=:]\s*['"]?[A-Za-z0-9/+=]{40} |
| GCP API Key | AIza[0-9A-Za-z\-_]{35} |
| Azure | DefaultEndpointsProtocol=https;AccountName= |
| GitHub Token | (ghp|gho|ghs|github_pat)_[A-Za-z0-9_]{36,} |
| Stripe Live | (sk|pk)_live_[A-Za-z0-9]{24,} |
| Slack Token | xox[bpras]-[A-Za-z0-9\-]{10,} |
| 私钥 | -----BEGIN (RSA|EC|DSA|OPENSSH|PGP) PRIVATE KEY----- |
| 数据库连接串 | (mysql|postgres|mongodb(\+srv)?):\/\/[^:]+:[^@]+@ |
| 通用密码赋值 | (password|passwd|pwd|secret)\s*[=:]\s*['"][^'"]{8,}['"] |
| 高熵字符串 | 在变量赋值上下文中出现的 40+ 字符 Base64/Hex 串 |
对每个匹配结果,检查是否命中以下白名单,命中则排除:
xxx、your-.*-here、<.*>、example、changeme、TODO.example、.sample、.templatesk_test_、pk_test_AAAAAAA...)每个发现记录为:
{layer: 1, severity: "CRITICAL", category: "密钥", file: "path", line: N, summary: "AWS Access Key 泄露", detail: "AKIA****XXXX", fix: "移至环境变量,添加到 .gitignore"}
用 Grep 工具依次搜索:
| 类别 | 正则模式 | 等级 |
|---|---|---|
| 中国身份证 | \b\d{17}[\dXx]\b | CRITICAL |
| 美国 SSN | \b\d{3}-\d{2}-\d{4}\b | CRITICAL |
| 银行卡号 | \b[3-6]\d{12,18}\b(后续 Luhn 校验) | CRITICAL |
| 中国手机号 | \b1[3-9]\d{9}\b | HIGH |
| 国际电话 | \+\d{7,15} | HIGH |
| 邮箱地址 | [a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,} | HIGH |
| 公网 IPv4 | \b(?!10\.|127\.|172\.(1[6-9]|2\d|3[01])\.|192\.168\.)\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b | HIGH |
| 中文地址 | 含"省""市""区""街""号"的连续中文文本 | MEDIUM |
对每个匹配结果,根据上下文调整等级:
test/、mock/、fixture/、__tests__/ → 降一级但保留package.json 的 author/contributors 字段 → 标记为 LOW(预期行为)console.log、logger.、log.)→ 附加"运行时泄露风险"警告// TODO 或 # FIXME 注释中 → 保持原等级排除以下情况:
example.com、test.com、test.org、localhost、placeholder.com13800138000、10000000000000-00-0000、123-45-6789对疑似银行卡号,执行以下验证:
{layer: 2, severity: "HIGH", category: "PII", file: "path", line: N, summary: "真实手机号", detail: "138****1234", fix: "替换为假数据或移至环境配置"}
用 Grep 工具依次搜索:
| 类别 | 正则模式 | 等级 |
|---|---|---|
| 内网域名 | [a-zA-Z0-9-]+\.(internal|local|corp|intranet|private)\b | HIGH |
| RFC 1918 URL | https?:\/\/(10\.|172\.(1[6-9]|2\d|3[01])\.|192\.168\.)\d{1,3}\.\d{1,3} | HIGH |
| K8s 内部服务 | [a-z-]+\.svc\.cluster\.local | MEDIUM |
| 内部工具 | (jira|confluence|gitlab|jenkins|grafana|kibana)\.[a-zA-Z0-9-]+\.(com|net|org|io) | MEDIUM |
| 硬编码主机名 | (prod|staging|dev|qa)-(db|redis|api|web|app|cache)-\d+ | HIGH |
| 内部邮件组 | (team|dev|eng|ops|infra)-[a-z]+@ | MEDIUM |
| VPN/内网路径 | (vpn|intranet|internal)\.[a-zA-Z] | HIGH |
如果 .opensource-preflight.yml 中定义了 internal_domains,额外匹配:
.example、.sample、.template 文件中 → 降为 LOWlocalhost:3000 类开发端口出现在 README/文档中 → LOW*.yaml、*.yml(Helm/K8s manifests)→ MEDIUM(预期但仍标记)docker-compose.yml 的 service 名 → LOW(本地开发配置){layer: 3, severity: "HIGH", category: "内部引用", file: "path", line: N, summary: "内网域名泄露", detail: "api.mycompany.internal", fix: "替换为环境变量或配置文件,从代码中移除硬编码"}
模式要求: standard 及以上
用 Glob 工具搜索:LICENSE*、COPYING*、LICENCE*
读取项目 manifest 文件(package.json、Cargo.toml、pyproject.toml、setup.py、go.mod),检查:
license 字段是否存在Node 项目:
npx license-checker --json --production > /tmp/licenses.json 2>/dev/null
如果命令不可用,读取 node_modules/*/package.json 的 license 字段(仅扫描直接依赖)。
Python 项目:
pip-licenses --format=json > /tmp/licenses.json 2>/dev/null
如果命令不可用,从 requirements.txt 列出依赖名,逐个检查已知 license。
Rust 项目:
cargo-license --json > /tmp/licenses.json 2>/dev/null
兼容性判定矩阵:
项目 License 为 MIT 时,以下依赖 license 不兼容(HIGH):
- GPL-2.0, GPL-3.0, AGPL-3.0
项目 License 为 Apache-2.0 时,以下不兼容(HIGH):
- GPL-2.0, AGPL-3.0
项目 License 为 GPL-3.0 时,以下不兼容(HIGH):
- 专有许可 (proprietary)
需要注意但不阻断(MEDIUM):
- LGPL(需确认链接方式)
- MPL-2.0(文件级 copyleft)
检查 LICENSE 文件中的年份,如果比当前年份早 2 年以上 → LOW
{layer: 4, severity: "HIGH", category: "许可证", file: "package.json", line: null, summary: "依赖 license 不兼容", detail: "lodash-gpl (GPL-3.0) 与项目 MIT 不兼容", fix: "寻找替代包或更换项目 license"}
模式要求: standard 及以上
用 Glob 工具检查以下文件是否存在:
| 文件 | standard | strict | 缺失等级 |
|---|---|---|---|
| README.md | 必须 | 必须 | MEDIUM |
| .gitignore | 必须 | 必须 | MEDIUM |
| CONTRIBUTING.md | 建议 | 必须 | LOW / MEDIUM |
| CODE_OF_CONDUCT.md | 可选 | 建议 | LOW |
| CHANGELOG.md | 可选 | 建议 | LOW |
| SECURITY.md | 建议 | 必须 | LOW / MEDIUM |
| .github/ISSUE_TEMPLATE/ | 可选 | 建议 | LOW |
| .github/PULL_REQUEST_TEMPLATE.md | 可选 | 建议 | LOW |
读取 README.md 内容,检查:
检测项目语言(通过文件扩展名),验证 .gitignore 是否覆盖:
| 语言标志 | 必须忽略 |
|---|---|
*.js/*.ts | node_modules/、dist/、.env* |
*.py | __pycache__/、*.pyc、.venv/、.env* |
*.rs | target/、.env* |
*.go | vendor/(如使用)、.env* |
| 通用 | .DS_Store、Thumbs.db、*.log、.idea/、.vscode/(settings) |
缺少条目 → LOW(建议添加)
读取 manifest 文件,检查是否缺少:
description → LOWrepository / homepage → LOWprivate: true 仍存在 → MEDIUM(开源应移除){layer: 5, severity: "MEDIUM", category: "规范", file: "README.md", line: null, summary: "README 缺少安装说明", detail: "未找到 install/setup 相关段落", fix: "添加 ## 安装 段落,说明如何安装和运行项目"}
模式要求: standard(最近 50 次 commit)/ strict(全部历史) quick 模式跳过此层。
which trufflehog 2>/dev/null && echo "TRUFFLEHOG_AVAILABLE=true"
which gitleaks 2>/dev/null && echo "GITLEAKS_AVAILABLE=true"
如果 trufflehog 可用:
trufflehog git file://. --only-verified --json > /tmp/trufflehog-history.json
如果 gitleaks 可用:
gitleaks detect --source . --log-opts="--all" --report-format json --report-path /tmp/gitleaks-history.json
根据模式确定范围:
--all执行以下扫描命令:
# 检查被删除的敏感文件
git log --all --diff-filter=D --name-only --pretty=format:"%H %ai" -- '*.env' '*.env.*' '*.pem' '*.key' '*.p12' '*.pfx' 'credentials.json' '*secret*'
# 搜索历史中的密钥模式
git log --all -p -S "AKIA" --pretty=format:"COMMIT:%H DATE:%ai" | head -200
git log --all -p -S "BEGIN RSA PRIVATE KEY" --pretty=format:"COMMIT:%H DATE:%ai" | head -200
git log --all -p -S "password" --pretty=format:"COMMIT:%H DATE:%ai" -- '*.env' '*.yml' '*.yaml' '*.json' '*.toml' | head -200
git log --all --format="%ae" | sort -u
检查是否有内部邮箱(匹配 internal_domains 配置,或通用模式如含 corp、internal 的域名)→ MEDIUM
git rev-list --objects --all | git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' | awk '/^blob/ && $3 > 10485760 {print $3, $4}'
发现 >10MB 文件 → LOW
对历史泄露问题,给出具体修复命令:
清理敏感文件历史:
# 推荐:git-filter-repo(需 pip install git-filter-repo)
git filter-repo --path <敏感文件路径> --invert-paths
# 备选:BFG Repo-Cleaner
bfg --delete-files <文件名> .
git reflog expire --expire=now --all && git gc --prune=now
重写作者邮箱:
# 创建 mailmap 文件
echo "New Name <public@email.com> Old Name <internal@corp.com>" > .mailmap
git filter-repo --mailmap .mailmap
全新开源(从内部 repo 迁移):
# 压缩为干净的 initial commit
git checkout --orphan clean-main
git add -A
git commit -m "Initial open-source release"
git branch -D main
git branch -m main
{layer: 6, severity: "CRITICAL", category: "历史", file: null, line: null, summary: "历史 commit 中发现 AWS 密钥", detail: "commit a3f2c1d (2025-03-14) 曾包含 AKIA****XXXX", fix: "使用 git-filter-repo 清理历史,或 squash 为干净的 initial commit"}
扫描完成后,按以下格式输出终端摘要:
═══════════════════════════════════════════════
Opensource Preflight 扫描报告 — 模式: {mode}
═══════════════════════════════════════════════
CRITICAL {n} 个问题(必须修复才能开源)
HIGH {n} 个问题
MEDIUM {n} 个问题
LOW {n} 个问题
─── CRITICAL ───────────────────────────────────
[{category}] {file}:{line} — {summary}
...
─── HIGH ───────────────────────────────────────
[{category}] {file}:{line} — {summary}
...
─── MEDIUM ─────────────────────────────────────
[{category}] {file}:{line} — {summary}
...
═══════════════════════════════════════════════
结论: {verdict}
完整报告: ./opensource-preflight-report.md
═══════════════════════════════════════════════
✗ 未就绪 — 不可开源发布⚠ 需审查 — 建议修复后再发布✓ 就绪(附建议)✓ 完全就绪将完整报告写入项目根目录 opensource-preflight-report.md,结构如下:
# Opensource Preflight 扫描报告
**扫描时间:** YYYY-MM-DD HH:mm
**扫描模式:** {mode}
**扫描路径:** {path}
**结论:** {verdict}
## 摘要
| 等级 | 数量 |
|------|------|
| CRITICAL | N |
| HIGH | N |
| MEDIUM | N |
| LOW | N |
## 第 1 层:密钥与凭证
| # | 等级 | 文件 | 行 | 问题 | 修复建议 |
|---|------|------|-----|------|----------|
| 1 | CRITICAL | src/config.ts | 14 | 硬编码数据库密码 | 移至环境变量 |
## 第 2 层:个人信息
(同上表格结构)
## 第 3 层:内部引用
(同上表格结构)
## 第 4 层:许可证合规
(同上表格结构)
## 第 5 层:开源规范文件
(同上表格结构)
## 第 6 层:Git 历史
(同上表格结构)
## 推荐操作
按优先级排列的修复步骤:
1. **[CRITICAL]** 立即移除 `.env.production` 并添加到 .gitignore
2. **[CRITICAL]** 清理 git 历史中的 AWS 密钥
3. **[HIGH]** 替换测试数据中的真实手机号为假数据
...
扫描完成并输出报告后,针对 CRITICAL 和 HIGH 级别问题,逐个给出修复方案并询问用户:
以下操作可在用户确认后自动执行:
.env* 文件添加到 .gitignoreprocess.env.DB_PASSWORD)package.json 中的 private: true以下操作只提供命令,不自动执行:
git-filter-repo)对每个可自动修复的问题,询问:
"发现 {N} 个可自动修复的问题。是否逐个确认修复?(Y/n)"
如果用户同意,逐个展示修复内容并执行。每次修复后提交一个 commit。
| 扫描层 | quick | standard | strict |
|---|---|---|---|
| 1. 密钥与凭证 | ✓ | ✓ | ✓ |
| 2. 个人信息 | ✓ | ✓ | ✓ |
| 3. 内部引用 | ✓ | ✓ | ✓ |
| 4. 许可证合规 | ✗ | ✓ | ✓(含兼容性矩阵) |
| 5. 开源规范 | ✗ | ✓ | ✓(含全部可选文件) |
| 6. Git 历史 | ✗ | 最近 50 次 commit | 全部历史 |