{
  "$schema": "https://bestaiskill.com/schemas/agent-install/2.json",
  "skill": "github-sensitive-data-cleanup",
  "built": "2026-10-26",
  "control_level": 4,
  "control_level_label": "L4 高权限",
  "capabilities": [
    "execute_command",
    "network",
    "write_file"
  ],
  "required_controls": {
    "agent": [
      "sandbox_recommended",
      "graded_authorization"
    ],
    "admin": [
      "approval_process",
      "rollback_support",
      "full_audit"
    ]
  },
  "evidence": [
    {
      "file": "scripts/",
      "summary": "Local script execution: `scripts/scan_repo.py` detects binary via `shutil.which(\"gitleaks\")` and executes `gitleaks detect` using `subprocess`."
    },
    {
      "file": "网络端点",
      "summary": "External network access: `safe_push.py` calls `gh` CLI targeting GitHub REST API (`api.github.com`) to query repository `visibility`/`isPrivate` metadata."
    },
    {
      "file": "本地工作目录",
      "summary": "File I/O and artifact output: `scan_repo.py` writes JSON reports to `--output` (creating parent directories as needed); temporary gitleaks files are cleaned up post-scan."
    }
  ],
  "verification": {
    "method": "第二遍独立重读取证（不复用第一遍结论，换角度找茬）：① glob 全量文件清单（含隐藏文件、不尊重 gitignore）核对资产面；② 对四个脚本 + 三份 reference + SKILL.md 逐类 token 扫描（requests/urllib/socket/curl/wget/http(s):// /api_key/token/secret/no-verify/reset --hard/rm -rf/os.remove）判断有无漏掉的网络出口、隐藏脚本与凭证路径；③ 逐条反查 external_deps 的真实调用点行号（gitleaks / git-filter-repo / git 各子命令 / gh / date / uv / brew）；④ 逐条核对 SKILL.md「What the Bundled Scripts Do」与 Step 4/6 的功能声明是否与代码一致（含 7 条安全规则的落地情况）；⑤ 用仓库级 grep + CHANGELOG + marketplace.json 交叉核对上游对该 skill 的定位与版本（v1.1.0，category=security）是否与源码状态相符；⑥ 本地 HEAD 与 LICENSE 核实。",
    "second_pass": [
      {
        "item": "文件清单全量核对（有无未列出的隐藏脚本/数据文件）",
        "status": "ok",
        "detail": "glob（hidden=true, gitignore=false）结果仅 9 个文件：SKILL.md、evals/evals.json、references/{ai_semantic_review_prompt,incident-lessons,tooling_notes}.md、scripts/{rewrite_history,safe_push,scan_repo,verify_cleanup}.py。无隐藏文件、无二进制、无 .pii-patterns 样本、无内置 hook；仓库级的 PII Guard hook（~/scripts/git-pii-guard）与 .githooks/ 属仓库/机器环境，不在 skill 目录内，skill 只是要求不得绕过它。"
      },
      {
        "item": "external_deps 逐条反查调用点",
        "status": "ok",
        "detail": "全部命中：gitleaks → scan_repo.py `gitleaks_bin = shutil.which(\"gitleaks\")` + verify_cleanup.py 同名调用；git-filter-repo → rewrite_history.py `shutil.which(\"git-filter-repo\")` 且随后 `--version` 探测；git → show-ref/status/bundle create/bundle verify/rev-list/grep/log/push 各自 subprocess.run 均可定位；gh → safe_push.py 的 `[\"gh\", \"repo\", \"view\", \"--json\", ...]`；date → scan_repo.py `[\"date\", \"-u\", \"+%Y-%m-%dT%H:%M:%SZ\"]`；uv/brew 只出现在文档命令与 Prerequisites，无对应代码调用（已在条目 note 中说明）。"
      },
      {
        "item": "安全结论反例搜索：是否存在漏掉的网络调用、隐藏外发或混淆内容",
        "status": "ok",
        "detail": "未找到反例，安全结论成立（记录检索范围以免过度外推）：对 skill 目录 grep `requests|urllib|socket|curl|wget|http://|https://` 零命中，且全目录无任何 http(s):// 字面 URL（连「联系 GitHub Support」一段也只用文字）；无 base64/fromhex/codecs/eval/exec/__import__ 等混淆或动态执行构造，无 60 字符以上的不透明长 token；对 git / git-filter-repo / gitleaks / gh / date 之外的二进制调用为零。唯一出网路径是 safe_push.py 经 gh 访问 api.github.com（uv --with gitpython 的包索引访问属 uv 行为而非脚本行为，已在 external_deps 标注 [INFERENCE] 端点）。证明边界：这是对该 commit 下 9 个文件的静态核对，不含运行时行为。"
      },
      {
        "item": "实现原理是否夸大：SKILL.md「What the Bundled Scripts Do」逐条对代码",
        "status": "ok",
        "detail": "四条声明全部落地：scan_repo.py 确实同跑 gitleaks 与自定义 grep 层并输出 JSON；rewrite_history.py 确实先备份再 `git filter-repo --replace-text`，且 `--message-replacements` 确实映射到 `--replace-message`；verify_cleanup.py 确实同时查 blob（git grep 全 commit）与 commit message（`git log --all --format=%H%x1f%B%x1e`），使漏改 message 的重写必然失败；safe_push.py 确实调 gh repo view 并走 lease-first。SKILL.md 未出现代码做不到的承诺。"
      },
      {
        "item": "7 条不可协商安全规则在 SKILL.md 的位置与代码落地情况",
        "status": "ok",
        "detail": "SKILL.md 第 64~77 行「Safety Rules (Non-Negotiable)」编号 1~7：scan-before-decide / backup-before-rewrite / gh repo view 验可见性且不得从 URL 或目录名推断 / 绝不 --no-verify / --force-with-lease 优先且仅在 remote ref stale 时回退 --force / 重写后必须重新扫描 + AI 语义审查 / 公开且带 forks 需格外小心。落地核对：规则 2、4、5 有代码门禁（备份+verify、脚本从不加 --no-verify、lease→stale info→force 一次）；规则 3 有硬门禁（gh 失败或元数据缺 key 即 abort）；规则 1、6、7 依赖 agent 遵守文档与人工动作（scan 结果、--yes、fork 通知），不由代码强制——这是规则与实现的唯一不对称处。"
      },
      {
        "item": "safe_push.py 的 public+forks 判定与 force-with-lease 回退条件",
        "status": "ok",
        "detail": "判定式为 `if not info[\"isPrivate\"] and info[\"forkCount\"] > 0:`，命中时只向 stderr 打印 `WARNING: This is a PUBLIC repository with {forkCount} forks.`，不阻断流程；唯一的硬门禁是缺 --yes 时 exit(1)。回退条件为 `if \"stale info\" in result.stderr.lower():`（对应 git 对 force-with-lease 拒绝时的 (stale info) 文案），回退仅一次 (--force)，再失败即 exit(1)。注意：脚本不校验 remote/branch 是否与默认分支一致，也不在回退前复跑验证——--repo/--remote/--branch 参数的正确性由操作者负责。"
      },
      {
        "item": "文档声明的依赖 gitpython 是否真实被使用",
        "status": "discrepancy",
        "detail": "四处 docstring 与 SKILL.md 多处命令写 `uv run --with gitpython scripts/...`，但四个脚本的 import 块逐行核对后只有 argparse/json/re/shutil/subprocess/sys/tempfile/tomllib/pathlib，零 `import gitpython` 或 `from git import`。即文档要求 uv 从包索引拉一个不使用的第三方包（多余供应链接触面），去掉 `--with gitpython` 不影响任何功能；此外同一份 SKILL.md 内部不一致：Step 4/5/6 的命令写 `uv run scripts/...`（不带 --with），Step 1/1.5 与「What the Bundled Scripts Do」写 `uv run --with gitpython`。"
      },
      {
        "item": "--gitleaks-config 是否被传给 gitleaks 本体",
        "status": "discrepancy",
        "detail": "run_gitleaks 的 cmd 只有 `detect --source --report-format --report-path --verbose`，没有 `--config`；用户私有 gitleaks.toml 仅被 parse_gitleaks_rules 解析出 private-domain-context / private-ip-context 两条 regex 供 Layer 3 的 git grep 使用。SKILL.md 的说法（该 flag 用于从私有配置读取这两条规则）与代码一致，不存在夸大；但若用户以为私有配置会整体驱动 gitleaks 扫描（例如自定义 allowlist/其它私有规则），实际不会——gitleaks 走自身默认配置与仓库本地 .gitleaks.toml。此项为「文档未声明但易误读」的行为差异，非虚假声明。"
      },
      {
        "item": "scan_repo.py run_gitleaks 的第二个参数（输出路径）是否生效",
        "status": "discrepancy",
        "detail": "签名 `run_gitleaks(repo_path: Path, output_path: Path)` 与调用点 `run_gitleaks(repo_path, Path(args.output))` 都暗示 gitleaks 报告写到 --output；实际函数体内 output_path 未被引用，报告始终写进 tempfile 生成的临时 JSON（与 verify_cleanup.py 的实现一致），--output 只用于最终 report 字典的落盘。无功能影响（无数据丢失、无路径穿越），属死参数/命名误导。"
      },
      {
        "item": "重写脚本的备份与可回滚性（是否真能恢复）",
        "status": "ok",
        "detail": "create_backup 执行 `git -C <repo> bundle create <backup> --all` 并立即 `git -C <repo> bundle verify <backup>`，失败抛 RuntimeError 由调用点捕获后 exit(1)，重写尚未开始；重写中途失败时打印备份路径。可回滚性成立（tooling_notes 给出 `git clone backup.bundle restored-repo` 恢复路径），但需注意 bundle 与同名 .json 报告含全部旧历史与敏感明文，落在 --backup 指定位置（文档示例为 /tmp）时需自行清理。"
      },
      {
        "item": "验证器在脏数据上的鲁棒性（Lesson 9 修复是否落地到当前 commit）",
        "status": "ok",
        "detail": "四个脚本所有 subprocess.run 均带 `text=True, errors=\"replace\"`（逐处核对：scan_repo 的 gitleaks/rev-list/grep/date、rewrite_history 的 show-ref/status/bundle/version、verify_cleanup 的 log/gitleaks、safe_push 的 gh/push 两处），verify_cleanup.py 的 check_pattern_in_messages docstring 亦写明解码用 errors=\"replace\" 以免 GBK 提交信息让验证崩溃，并返回 commit_message_commits（前 10 个）以定位而非只计数；incident-lessons Lesson 9 描述的 `git bundle verify` 缺 `-C` 问题在当前 rewrite_history.py 中也已修复（verify 调用带 `-C <repo>`），且 RuntimeError 被 `except (subprocess.CalledProcessError, RuntimeError)` 接住。"
      },
      {
        "item": "上游定位与版本交叉核对（README / marketplace.json / CHANGELOG）",
        "status": "ok",
        "detail": ".claude-plugin/marketplace.json 收录 name=github-sensitive-data-cleanup、source=./github-sensitive-data-cleanup、version=1.1.0、category=security，description 与 SKILL.md frontmatter 同文；README.md 与 README.zh-CN.md 均有该条目（安装命令 `claude plugin install github-sensitive-data-cleanup@daymade-skills`）；CHANGELOG v1.1.0 条目描述的 commit-message 通道与 GBK/--yes/-C 修复与源码现状相符。本地 HEAD = d5c4678cb5d4fd6acc9c922690df035dbd33d247，仓库根 LICENSE 为 MIT（Copyright (c) 2025 daymade），与 meta 固定值一致。"
      },
      {
        "item": "功能声明 vs 实际能力：可见性与 fork 保护是否形成「阻断」",
        "status": "ok",
        "detail": "SKILL.md 用的是 Warns loudly（警告）而非阻断，代码亦只是 stderr 警告，无不一致；真正阻断 public+forks 场景的是 agent 侧的文档指令与 incidents 的升级条件（>50 forks 且含 live credentials 时停下问人）。因此「公开库带 forks 即被阻止推送」是对本 skill 的过度预期，正确表述为「被醒目警告 + 需要 --yes 确认」。"
      }
    ],
    "level": 1,
    "level_label": "V1 已固定",
    "commit": "d5c4678cb5d4fd6acc9c922690df035dbd33d247",
    "sha256": "aa1ae4b1f420e74a65226ac31462f96a5e19e768e2a0b23a80eccdd5ae83373a",
    "reviewed_by": null,
    "reviewed_at": null
  },
  "assessed_at": "2026-10-25",
  "method_version": "2.0",
  "mirror": {
    "archive": "https://skillpub.pages.dev/r2/v/2026-09-15/github-sensitive-data-cleanup.tar.gz",
    "sha256": "aa1ae4b1f420e74a65226ac31462f96a5e19e768e2a0b23a80eccdd5ae83373a",
    "commit": "d5c4678cb5d4fd6acc9c922690df035dbd33d247"
  },
  "original": {
    "github": "https://github.com/daymade/claude-code-skills/tree/main/github-sensitive-data-cleanup",
    "path": "github-sensitive-data-cleanup",
    "commit": "d5c4678cb5d4fd6acc9c922690df035dbd33d247"
  }
}