tg12/phantomstars

GitHub: tg12/phantomstars

phantomstars 是一个自动化工具,用于检测和追踪 GitHub 上的虚假互动,以维护开源平台的信任信号。

Stars: 30 | Forks: 2

phantomstars Python 3.13 Apache 2.0 GitHub Actions Daily

phantomstars

自动检测与追踪 GitHub 上的虚假互动

一个 JS Labs 项目 — 隶属于 AI Slop Intelligence 计划的一部分。
每日运行。为每个可疑账户评分。检测协调的机器人活动。
直接在受影响的仓库上提交 Issue,以便维护者采取行动。

BTC   3QjWqhQbHdHgWeYHTpmorP8Pe1wgDjJy54
ETH   0x5851e6145F4773d1585b8686095FB16E368a4dA1
ZEC   t1KSR5YkNPbjqRSCoLKo5AddFWdm9Kzxh1B

## 为何存在 GitHub Stars 是一种信任信号。开发者通过它来决定评估什么、依赖什么、推荐什么。这个信号正在被系统性地破坏。 在 2024-2026 年的 AI 热潮中,一个机器人农场产业应运而生,为低质量、通常带有恶意的仓库制造可信度。一个在 48 小时内获得 800 Stars 的项目,对于正在扫描搜索结果的开发者来说,看起来是合法的。这就是目的所在。虚假互动的目标不是 Stars 本身;而是这些 Stars 产生的社会认同,以及这种社会认同所影响的下游决策。 这种模式是可以识别的。账户在同一周创建,没有简介,没有关注者,没有原创仓库,在 2 小时内给相同的 15 个仓库点 Star。这不是一个活动,而是每天同时运行的数十个活动,涉及数千个账户。数据显示,有些仓库的 185 个互动者中有 185 个是机器人。100% 的虚假比例。整个热门榜排名完全建立在虚无之上。 **phantomstars** 之所以被构建,是因为这个问题是可控的。就目前而言,GitHub 公开 API 中的信噪比仍然足够高,协调的活动会留下清晰的指纹。该项目读取这些指纹,发布原始数据,并直接通知受影响的仓库维护者。 这是 [JS Labs](https://labs.jamessawyer.co.uk/) 开展的更广泛的 [AI Slop Intelligence](https://labs.jamessawyer.co.uk/ai-slop-intelligence-dashboards/) 工作的一部分,持续研究低质量 AI 生成内容涌入开发者生态系统的机制和可衡量影响。虚假互动不是边缘问题。它是让低质内容触达真实用户的分发机制。 ## 功能 **phantomstars** 运行一个每日的 GitHub Actions 作业,它: 1. 抓取 [GitHub Trending](https://github.com/trending) 页面,获取今日获得 Stars 的仓库 2. 查询 GitHub Search API,获取过去 **7 天** 创建且 Star 活动突然增加的仓库(更宽的时间窗口能捕获仅扫描 24 小时可能错过的多日活动) 3. 通过 Events API 拉取近期的互动事件(每个仓库过去 24 小时的 Star、Fork) 4. 通过 GraphQL 获取每个互动账户的完整资料:**账户创建日期**、关注者/关注数、简介、仓库历史 5. 根据一个综合启发式模型对每个账户进行评分:账户年龄、资料完整度、仓库模式、活动历史 6. 使用时间戳聚类和并查集算法检测**协调活动**:在 3 小时窗口内互动的可疑账户集群 7. 将所有可疑账户追加到一个仅追加的 JSONL 账本中,并提交回此仓库 8. 发布每个仓库的情报源,显示哪些仓库正被针对以及虚假比例 9. **直接在目标仓库上提交 GitHub Issue**,以便维护者在自己的 Issue 跟踪器中看到活动数据 10. 将格式化的扫描报告写入 GitHub Actions 作业摘要 无需服务器。无需数据库。无基础设施费用。 ## 常见问题 ### 它会通知目标仓库吗? **会。** 当一个仓库的虚假比例超过 40% 或检测到协调活动时,phantomstars 会直接在该仓库上创建一个 Issue。该 Issue 包含完整的可疑账户表、活动成员、综合评分和账户创建日期:维护者调查并向 GitHub 报告所需的一切信息。 如果目标仓库禁用了 Issue,通知将被静默跳过并记录在扫描日志中。 ### 我可以请求检查某个特定仓库吗? 可以。 - 对于普通的一次性检查,请以 `owner/repo` 格式提交一个仓库并运行定向扫描。 - 对于终身审计请求,请使用一次性终身模式。它与每日扫描是分开的。 为何分开: - 普通扫描模型专为近期的公开互动设计,运营成本低。 - 终身审计可能涉及大型仓库的数万个 Stars 和数千个 Fork。 - 对于一次性调查这是可行的,但对于默认的每日路径来说,它太昂贵且太慢。 - 因此,终身请求仅在明确的一次性模式下运行,并设有保障措施。 ### 我可以报告误判吗? 可以。如果你的账户出现在 `data/suspects.jsonl` 中,并且你认为分类不正确,请使用提供的模板[提交一个误判 Issue](../../issues/new?template=false_positive.yml)。在添加到允许列表之前,报告会被人工审核。允许列表存储在 `data/allowlist.txt` 中;列出的账户将从所有未来扫描和可疑账户账本中排除。 ### 活动 ID 是什么? 活动 ID(例如 `c-a3f9b2e1`)是一个**确定性的 8 字符十六进制指纹**,由该活动中排序后的成员登录名集合的 SHA-256 哈希值派生而来。同一组账户在独立的扫描运行中将产生相同的活动 ID,从而支持长期跟踪。它不是仓库名、用户名或任何外部标识符。 **稳定性:** 只要活动的成员集合保持不变,ID 就是稳定的。如果在扫描之间机器人被添加或暂停,ID 就会改变,因为成员关系发生了变化。这是预期的行为,反映了机器人农场组成在现实世界中的漂移。 ### 它会检查账户创建日期吗? 会。每个账户的创建日期通过 GitHub GraphQL API(`createdAt` 字段)获取,并存储在每个可疑记录的 `account_created_at` 字段中。它也是账户年龄评分的主要输入,这是针对虚假账户最强的单一信号。在互动后 2 天内创建的账户仅凭年龄就会得到 1.0 分。 ### 它的置信度如何? 单个评分具有显著的误判率。一个资料稀疏的新开发者单独可能得到 0.75+ 分。该工具通过要求活动级别的证据来应对这一点,然后才提交 Issue;单个可疑账户是不够的。一个由 40 多个账户组成的协调集群,全部在同一周创建,全部评分 0.75+,全部在 90 分钟内互动,那就不同了。这才是置信度变得可操作的地方。 数据始终是概率性的。Issue 正文明确说明了这一点。目标是给维护者信号和原始证据,以便他们做出自己的判断。 ## 实时仪表盘 | 日期 | 已扫描 | 可能虚假 | 可疑 | 活动数 | 新增虚假 (24小时) | |------|---------|-------------|------------|-----------|-----------------| | 2026-05-19 | 2012 | 499 | 1513 | 31 | 323 | | 2026-05-18 | 8838 | 670 | 7950 | 128 | 340 | | 2026-05-17 | 8015 | 831 | 5709 | 82 | 831 | ## 今日最受针对的仓库 | 仓库 | 互动者 | 可能虚假 | 已知虚假 % | 虚假比例 % | 活动数 | |------|----------|-------------|--------------|------------|-----------| | DuskMosquito/Lossless-Scaling-Desktop-2026 | 299 | 155 | 0.0% | 51.8% | 1 | | Dangerous-hole/Pumpfun_AI_Trading_Bot | 143 | 111 | 65.0% | 77.6% | 1 | | pro-tech-killers/coinbase-trading-bot | 143 | 111 | 65.0% | 77.6% | 1 | | haiddrrs/Steam-Tools | 298 | 53 | 20.8% | 17.8% | 1 | | AbhishekK130804/Claude-Mythos-AI-Anthropic-App | 299 | 52 | 21.4% | 17.4% | 1 | | dex-original/okx-agent-trade-kit | 59 | 51 | 54.2% | 86.4% | 1 | | pro-tech-killers/binance-trading-bot | 60 | 51 | 53.3% | 85.0% | 1 | | ZoyaMalhotra/DualSenseX-DSX-Steam-Edition | 298 | 51 | 20.8% | 17.1% | 1 | | xw7872081123/wallpaper-engine-steam | 298 | 50 | 19.5% | 16.8% | 1 | | thongthaibm/Lossless-Scaling-LSFG | 297 | 50 | 19.5% | 16.8% | 1 | | labelprosecutorwatt/FL-Studio-2026-Full-Cracked-Edition | 297 | 41 | 19.5% | 13.8% | 1 | | cat9999aaa/thinshell | 169 | 38 | 0.0% | 22.5% | 1 | | heyFive-dev/Polymarket-Arbitrage-Trading-Bot-v2 | 34 | 29 | 55.9% | 85.3% | 1 | | Flizorules05/ROM-MGBA-Pokemon-Emulator-PC | 152 | 23 | 13.8% | 15.1% | 1 | | BasZ4ll/Stable-Diffusion-WebUI | 148 | 19 | 14.2% | 12.8% | 1 | | pedrodg28/yuzu-emu | 151 | 19 | 15.2% | 12.6% | 1 | | zigabratun/Umbrella-HWID-Tool | 121 | 18 | 6.6% | 14.9% | 1 | | arnabchoudhury404/hydra-launcher | 143 | 18 | 14.0% | 12.6% | 1 | | python-telegramBot/ai-auto-trading | 21 | 17 | 38.1% | 81.0% | 1 | | Sunislazi/rbxfpsunlocker-boost-More-240FPS | 146 | 17 | 13.7% | 11.6% | 1 | | DEV-OCR/polymarket-arbitrage-trading-bot | 22 | 16 | 40.9% | 72.7% | 1 | | POLYMARKET-TRADER-LAB/Polymarket-trading-bot | 24 | 16 | 37.5% | 66.7% | 1 | | cdanielc293/Jenny-Mod-All-Versions | 120 | 16 | 7.5% | 13.3% | 1 | | ZhuLinsen/daily_stock_analysis | 265 | 16 | 0.0% | 6.0% | 1 | | thinkpixelIab/polymarket-ai-trading | 19 | 15 | 36.8% | 78.9% | 1 | ## 评分模型 每个账户根据四个信号获得一个综合可疑评分(0.0 = 正常,1.0 = 可能虚假): | 信号 | 权重 | 测量方式 | |--------|--------|-------------| | 账户年龄 | 35% | `< 2 天` → 1.00 · `< 7 天` → 0.90 · `< 30 天` → 0.55 · `< 90 天` → 0.20 · 更老 → 0.00 | | 资料完整度 | 30% | 加分项:无简介 (+0.25),无所在地 (+0.15),无公司 (+0.10),零关注者 (+0.30),零关注数 (+0.10),机器人模式用户名 (+0.20) | | 仓库模式 | 25% | 零仓库 → 0.90 · 所有仓库均为 Fork → 0.80 · Fork 比例 >85% → 0.55 | | 活动历史 | 10% | 账户超过 14 天但零仓库 + 零社交图谱 → 0.80(幽灵账户)。仅零仓库 → 0.60。全部 Fork + 无社交图谱 → 0.50 | **分类阈值:** | 评分 | 分类 | |-------|---------------| | ≥ 0.75 | `可能虚假` | | ≥ 0.45 | `可疑` | | < 0.45 | `正常`(不存储) | ### 活动检测 一个**活动**是指一组 ≥ 4 个可疑账户,它们都在 3 小时窗口内与同一个仓库互动。该算法使用并查集构建连通分量;在窗口内共同互动的账户被合并,任何超过最小规模的连通分量都会被标记为协调活动。 活动 ID 是排序后的成员集合的稳定 SHA-256 指纹。只要成员关系不变,在连续几天检测到的同一活动将具有相同的 ID。 **为何活动才是真正的信号:** 单个评分具有显著的误判率。一个资料稀疏的新开发者单独可能得到 0.80 分。但四十个账户全部评分 0.75+,全部在同一周创建,全部在 90 分钟内给同一个仓库点 Star,这就不是巧合了。活动信号是数据变得可操作的地方:它是可疑数据点与协调操作证据之间的区别。 ## 数据格式 所有发现都被提交到 [`data/suspects.jsonl`](data/suspects.jsonl) 和 [`data/repos.jsonl`](data/repos.jsonl),每行一个 JSON 记录,仅追加。GitHub Actions 作业摘要(每次运行后在 Actions UI 中可见)提供了格式化的每次扫描报告。 **suspects.jsonl** — 每次扫描中每个被标记账户一条记录: ``` { "login": "user98432", "account_age_score": 0.9, "profile_score": 0.8, "repo_pattern_score": 0.8, "activity_score": 0.85, "composite": 0.842, "classification": "likely_fake", "campaign_id": "c-a3f9b2e1", "scan_date": "2026-05-17", "account_created_at": "2026-05-15", "target_repos": ["owner/repo-a", "owner/repo-b"] } ``` **repos.jsonl** — 每次扫描中每个目标仓库一条记录: ``` { "full_name": "owner/suspicious-repo", "total_scanned": 87, "likely_fake": 62, "suspicious": 18, "known_likely_fake": 27, "known_likely_fake_ratio": 0.310, "repeat_offenders": 11, "fakeness_ratio": 0.713, "classification": "likely_fake", "campaign_count": 3, "scan_date": "2026-05-17" } ``` **查询示例:** ``` # 所有今天出现的 likely_fake 账户 jq 'select(.scan_date == "2026-05-17" and .classification == "likely_fake") | .login' data/suspects.jsonl # 在过去3天内创建且被标记的账户 jq 'select(.account_created_at >= "2026-05-14") | [.login, .account_created_at, .classification] | @tsv' -r data/suspects.jsonl # 哪些 repos 今天被针对,按 fakeness 比率排序 jq 'select(.scan_date == "2026-05-17") | [.full_name, .fakeness_ratio, .likely_fake] | @tsv' -r data/repos.jsonl | sort -t$'\''\t'\'' -k2 -rn # 来自之前出现的 likely_fake 账户中,具有最高 recycled-bot 占比的 repos jq 'select(.scan_date == "2026-05-17") | [.full_name, .known_likely_fake_ratio, .repeat_offenders] | @tsv' -r data/repos.jsonl | sort -t$'\''\t'\'' -k2 -rn # 特定活动的所有成员 jq 'select(.campaign_id == "c-a3f9b2e1") | [.login, .account_created_at, .composite] | @tsv' -r data/suspects.jsonl # 特定账户针对的 repos jq 'select(.login == "user98432") | .target_repos[]' data/suspects.jsonl # 高置信度 repos:fakeness 比率超过 60% jq 'select(.fakeness_ratio >= 0.6) | [.full_name, .fakeness_ratio, .campaign_count] | @tsv' -r data/repos.jsonl | sort -t$'\t' -k2 -rn ``` ## 设置 ### 1. Fork 此仓库 你的 Fork 拥有数据。每次每日运行后,结果会被提交回你 Fork 仓库的 `data/suspects.jsonl` 和 `data/repos.jsonl` 中。 ### 2. 添加 GitHub PAT 密钥 创建一个 **classic** Personal Access Token,权限范围包括: - `public_repo`:读取公开仓库事件和 Stargazer,在公开仓库上创建 Issue - `read:user`:通过 GraphQL 获取用户资料 **Settings → Secrets and variables → Actions → New repository secret** → 将其命名为 `GH_TOKEN`。 ### 3. 启用 Actions 在你的 Fork 上 **Actions → Enable GitHub Actions**。工作流在 **每天英国时间 07:00** 使用 `Europe/London` 时钟运行: - 英国夏令时期间 **UTC 06:00** - 格林威治标准时间期间 **UTC 07:00** 无需额外的调度环境变量。GitHub Actions cron 仅使用 UTC,因此工作流会在两个 UTC 小时触发,但仅在伦敦当地时间是 07:00 时才继续。可通过 **Actions → Daily Phantom Stars Scan → Run workflow** 手动触发。 每次运行后,格式化的扫描报告可在 **Actions → [运行记录] → Summary** 中查看。 ### 4. 本地运行 ``` git clone https://github.com/YOUR_USERNAME/phantomstars.git cd phantomstars python -m venv venv && source venv/bin/activate pip install -e . GH_TOKEN=ghp_your_token python -m phantomstars.main ``` 设置完成后,进行临时本地运行: ``` GH_TOKEN=ghp_your_token python -m phantomstars.main ``` 扫描单个仓库而不是正常的发现集: ``` PHANTOMSTARS_TARGET_REPO=owner/repo GH_TOKEN=ghp_your_token python -m phantomstars.main ``` ### 一次性请求 用户可以通过两种方式请求一次性仓库检查: 1. 打开 `Repo Check Request` Issue 模板,提供目标仓库和请求深度。 2. 使用 **Actions -> Daily Phantom Stars Scan -> Run workflow** 并可选设置: - `target_repo`:`owner/repo` - `request_depth`:`recent` 或 `lifetime-request` 当前行为: - `recent`:立即运行针对性的近期互动扫描。 - `lifetime-request`:运行针对性的终身扫描,仅扫描该仓库的历史 Star 和 Fork。 - 每日计划扫描保持不变,继续使用近期互动方法。 终身模式的保障措施: - 仅适用于明确的一次性针对性请求 - 在扫描开始前受配置的仓库大小限制约束 - 比每日扫描更慢且 API 调用量更大 ## 项目结构 ``` phantomstars/ ├── .github/ │ ├── workflows/daily-scan.yml # Runs daily at 07:00 Europe/London │ └── ISSUE_TEMPLATE/false_positive.yml ├── src/phantomstars/ │ ├── config.py # All constants, no argparse, no env parsing │ ├── models.py # Frozen dataclasses │ ├── github_client.py # REST + GraphQL, tenacity retries, rate-limit aware │ ├── heuristics.py # Per-user composite scoring engine │ ├── campaigns.py # Timestamp clustering + union-find │ ├── storage.py # JSONL append + query helpers │ ├── reporter.py # README dashboard injector │ ├── notifier.py # GitHub Issues notifier (files on targeted repos) │ └── main.py # Orchestration entry point ├── tests/ │ ├── conftest.py │ ├── test_heuristics.py │ └── test_campaigns.py ├── data/ │ ├── suspects.jsonl # Append-only account findings ledger │ ├── repos.jsonl # Append-only per-repo intelligence │ └── allowlist.txt # Accounts excluded from future scans └── pyproject.toml ``` ## 局限性与已知失败模式 - **Events API 上限:** 每个仓库最多 300 个近期事件。一天内获得数千 Star 的仓库覆盖不全。 - **搜索索引延迟:** GitHub 的搜索索引是最终一致的。在扫描边界前几秒创建的仓库可能会被遗漏。 - **启发式漂移:** 机器人运营者会适应。评分权重可能需要定期调整;请调整 `config.py` 中的常量。 - **单个误判:** 一个资料稀疏的新开发者单独可能得到 0.75+ 分。活动成员身份才是高置信度的信号。 - **活动 ID 漂移:** 如果机器人农场的成员在扫描之间发生变化(机器人被暂停、新机器人添加),活动 ID 就会改变。这反映了活动的实际演变,而不是 bug。 - **速率限制:** 使用已认证的 PAT 每小时 5,000 次 API 请求。对于标准的 Trending 页面大小来说完全在限制之内。 - **Issue 被禁用:** 一些目标仓库禁用了 Issue。这些仓库的通知会被静默跳过。 ## 误判处理流程 如果你的账户出现在 `data/suspects.jsonl` 中,并且你认为分类不正确: 1. 找到你的条目:`jq 'select(.login == "YOUR_LOGIN")' data/suspects.jsonl` 2. 使用你的登录名、分类、扫描日期和解释[提交一个误判 Issue](../../issues/new?template=false_positive.yml) 3. 报告会被人工审核。经核实的误判会被添加到 `data/allowlist.txt`,并从所有未来扫描中排除。 注意:创建 Issue 不会修改或删除任何现有数据。可疑账户账本是仅追加的。允许列表仅影响未来的扫描。 ## 贡献 ``` pip install -e ".[dev]" python -m black . python -m ruff check . python -m mypy src python -m pytest ``` 所有四项检查都必须通过才能合并 PR。 ## 免责声明 此工具使用官方 GitHub API 对公开 GitHub 数据进行只读分析。在目标仓库上提交的 Issue 包含概率性发现,并明确标注为自动化结果。发现是指标,而非指控。误判存在且属于预期之内。 以 AI 作为编码伙伴构建,以应对部分由 AI 造成的生态系统问题。 ## 许可证 Apache 2.0。参见 [LICENSE](LICENSE) ## 作者 由 **tg12** 构建 · [GitHub](https://github.com/tg12) 一个 **[JS Labs](https://labs.jamessawyer.co.uk/)** 项目 · [AI Slop Intelligence Dashboards](https://labs.jamessawyer.co.uk/ai-slop-intelligence-dashboards/)
标签:AI滥用防范, Bot农场检测, GitHub Actions, GitHub安全, Python开发, SEO检索词, 仓库清理, 代码托管平台安全, 信任信号分析, 功能关键词, 协调攻击检测, 反欺诈系统, 威胁情报, 开发者工具, 开源仓库维护, 开源框架, 技术栈, 持续集成, 日常运行, 时序数据库, 社交媒体欺诈, 网络安全, 自动化监控, 自动报告系统, 自动笔记, 虚假互动检测, 账户信誉评分, 逆向工具, 隐私保护, 零基础设施