Token RugCheck MCP

March 22, 2026 · View on GitHub

唯一的部署和运维文档。涵盖首次部署、日常更新、ag402 依赖升级、故障排查。

目录


1. 架构概览

Client (AI Agent)
  │ HTTPS (TLS 终止于 Cloudflare)

Cloudflare CDN (SSL termination, DDoS protection)
  │ HTTP → :80 (Flexible 模式)

┌─────────────────────────────────────────────────┐
│  Docker Compose                                 │
│                                                 │
│  ┌──────────────────────┐  ┌──────────────────┐ │
│  │ ag402-gateway :80    │  │ rugcheck-audit   │ │
│  │ (QuotaAwareGateway)  │  │ :8000 (internal) │ │
│  │                      │  │ 审计引擎         │ │
│  │  免费配额剩余?       │  │                  │ │
│  │  ├─ 是 → HTTP proxy ─┼─▶│                  │ │
│  │  └─ 否 → 402 付费   │  │                  │ │
│  └──────────┬───────────┘  └──────────────────┘ │
│             │                                   │
│        ag402-data (SQLite volume, 重放保护)       │
└─────────────────────────────────────────────────┘

组件说明

组件端口说明
rugcheck-audit127.0.0.1:8000(仅本机)FastAPI 审计服务,不对外暴露
ag402-gateway:80(对外)QuotaAwareGateway:免费配额内直接 HTTP 代理到审计服务,配额耗尽后返回 402 要求支付
ag402-dataDocker volume,存储 SQLite 重放保护数据(必须备份

Cloudflare SSL 方案

本项目采用 Cloudflare Flexible 模式:

客户端 ──HTTPS──▶ Cloudflare ──HTTP:80──▶ 源站 Docker
模式客户端→CloudflareCloudflare→源站源站要求适用场景
Flexible ✅ 采用HTTPSHTTP:80无需 TLS 证书单服务 API,Cloudflare 做 SSL 终止
FullHTTPSHTTPS:443需自签证书需要端到端加密
Full (strict)HTTPSHTTPS:443需 CA 签发证书金融级安全要求

选择 Flexible 的理由

  1. 源站只暴露 HTTP:80,无需配置 TLS 证书,无需 Nginx/Caddy 反代
  2. 客户端到 Cloudflare 全程 HTTPS 加密,满足安全需求
  3. 减少运维复杂度,避免证书续期等问题
  4. Cloudflare 已提供 DDoS 防护和 WAF

重要:如果你之前将 Cloudflare SSL/TLS 改为 Full 或 Full (strict),必须改回 Flexible,否则 Cloudflare 无法连接到源站(源站没有 HTTPS),会导致 5xx 错误。


2. 首次部署

前置条件

项目要求
服务器Ubuntu 22.04+,1 vCPU / 1GB RAM 即可
SSH本地已配置 ssh root@<IP> 免密登录
域名一级子域名(如 rugcheck.aethercore.dev),Cloudflare 代理
钱包Solana 地址(收款用),mainnet 需确保有 USDC ATA

一键部署(推荐)

bash scripts/deploy-oneclick.sh

交互式引导,依次完成:SSH 连接 → 服务器初始化 → 环境配置 → Docker 部署 → 健康检查 → 5 层验证。

脚本会自动:

  • 安装 Docker 和防火墙
  • 克隆代码到 /opt/token-rugcheck
  • 生成 .env 配置文件
  • 构建镜像并启动服务(含最新 ag402 依赖)
  • 运行 5 层验证

手动部署

# 1. 初始化服务器(Docker + 防火墙 + 克隆代码)
scp scripts/setup-server.sh root@<IP>:/tmp/
ssh root@<IP> "bash /tmp/setup-server.sh"

# 2. 生成 .env
bash scripts/generate-env.sh \
  --mode production \
  --address <your_solana_address> \
  --price 0.02 \
  --output .env.production

# 3. 上传 .env 并部署
scp .env.production root@<IP>:/opt/token-rugcheck/.env
ssh root@<IP> "cd /opt/token-rugcheck && \
  docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d --build"

# 4. 验证
bash scripts/verify.sh --server-ip <IP> --domain <domain>

Cloudflare 配置(必做)

  1. DNS:A 记录 → 服务器 IP,开启代理(橙色云朵)
  2. SSL/TLSFlexible
  3. 注意:免费版只支持一级子域 *.example.com,不支持 *.*.example.com

提示:DNS 变更后通常 1-5 分钟生效,可通过 curl -s https://<domain>/health 验证。

首次部署后检查清单

  • curl -s https://<domain>/health 返回 200
  • curl -s https://<domain>/v1/audit/<mint> 返回 402(支付墙生效)
  • Cloudflare SSL/TLS 已设为 Flexible
  • 卖家钱包有 USDC ATA(mainnet 必须)
  • 配置 UptimeRobot 监控 https://<domain>/health

3. 分支策略与发布流程

分支结构

main          ← 生产分支,只接受经过验证的 PR 合入,每次合入打 tag
  └── develop ← 集成分支,功能分支的汇集地,对应 devnet 环境
        └── feature/xxx ← 每个新功能独立分支,本地 test 模式开发
        └── fix/xxx     ← Bug 修复分支

原则:

  • 禁止直接 git push origin main(在 GitHub Settings → Branches 中启用分支保护)
  • 生产服务器部署打了 tag 的版本,自动跟踪 main HEAD
  • quick-update.sh 的第三个参数指定 tag,不传则默认 main 最新(用于紧急修复)

日常开发流程

1. 从 develop 创建功能分支
   git checkout develop && git pull
   git checkout -b feature/my-new-feature

2. 本地开发,用 test 模式验证
   # Docker Compose 从 .env 文件读取环境变量,不能在命令行直接注入
   # 先基于 .env.example 生成本地 test 用 .env:
   cp .env.example .env                     # 复制模板(默认已是 X402_MODE=test)
   # 确认/修改 AG402_ADDRESS 为你的钱包地址,然后:
   docker compose up

3. 完成后 PR → develop(代码审查)

4. develop 在 devnet 环境集成测试通过

5. PR → main(代码审查 + CI 绿灯)

6. 合入后立即打 tag
   git tag -a v1.x.x -m "feat: 描述新功能"
   git push origin v1.x.x

7. 确认后人工部署到生产
   bash scripts/quick-update.sh <IP> <domain> v1.x.x

环境与分支对应关系

环境X402_NETWORK对应分支说明
本地 testmockfeature/*Mock 支付,无需链上,快速迭代
本地/云 devnetdevnetdevelop真实交易逻辑,使用测试 SOL
生产 mainnetmainnetmain (tag)真实 USDC 支付

版本 Tag 规范

遵循语义化版本 vMAJOR.MINOR.PATCH

  • PATCH:bug 修复、文档更新、运维改进
  • MINOR:向后兼容的新功能
  • MAJOR:破坏性变更(API 不兼容、架构重构)
# 打 tag 并推送
git tag -a v1.2.0 -m "feat: add token comparison endpoint"
git push origin v1.2.0

# 查看所有 tag
git tag -l --sort=-version:refname | head -10

设置 GitHub 分支保护(推荐立即配置)

进入 GitHub → Settings → Branches → Add rule:

  • Branch name pattern: main
  • ✅ Require a pull request before merging
  • ✅ Require approvals: 1
  • ✅ Do not allow bypassing the above settings

4. 日常更新(代码 + ag402 依赖)

快速更新(推荐)

推荐方式:部署指定 tag(稳定可控)

# 部署指定 tag(推荐,生产必用)
bash scripts/quick-update.sh <server-ip> <domain> v1.2.0

# 示例
bash scripts/quick-update.sh 140.82.49.221 rugcheck.aethercore.dev v1.2.0

紧急修复:部署 main 最新(省略 tag 参数)

bash scripts/quick-update.sh 140.82.49.221 rugcheck.aethercore.dev

脚本自动执行:拉取指定 ref → 备份数据 → 重新构建(含 ag402 依赖更新) → 重启 → 健康检查 → 验证 → 输出回滚命令。

回滚

部署失败或服务异常时,使用更新结束时脚本打印的回滚命令

  回滚命令:
    bash scripts/quick-update.sh 140.82.49.221 "rugcheck.aethercore.dev" abc1234

或手动回滚到上一个稳定 tag:

bash scripts/quick-update.sh 140.82.49.221 rugcheck.aethercore.dev v1.1.0

部署历史记录在服务器 /opt/token-rugcheck/.deploy_history,可查阅历次部署的 ref 和 commit。

完整重新部署

如需重新配置 .env(比如改钱包地址、改价格、改模式),使用一键部署脚本:

bash scripts/deploy-oneclick.sh

此脚本用于首次部署或完整重新配置(如修改钱包地址、价格、运行模式),始终拉取 main HEAD。日常代码更新请使用 quick-update.sh

仅更新 ag402 依赖

如果只想升级 ag402 库(不改业务代码),SSH 到服务器执行:

ssh root@<IP>
cd /opt/token-rugcheck

# 强制重新构建(不使用缓存,确保拉取最新 ag402)
docker compose -f docker-compose.yml -f docker-compose.prod.yml build --no-cache
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d

# 验证 ag402 版本
docker compose exec ag402-gateway pip show ag402-core ag402-mcp

更新流程中脚本的自动处理

场景脚本行为
指定 tag 部署git fetch --tags + git checkout <tag>,精确锁定版本
指定分支部署git checkout <branch> + git pull,获取分支最新
服务器有未提交文件导致 git pull 冲突自动 git stash --include-untracked 后重试
旧容器未完全停止docker compose down --remove-orphans + 强制清理残留容器
端口被占用(80/8000)自动检测并 kill 占用进程后重试
Docker build 缓存导致 ag402 不更新使用 --no-cache 强制重建
部署完成记录 ref/commit 到 .deploy_history,打印回滚命令

5. 数据备份

ag402-data SQLite 存储支付重放保护数据,丢失会导致重复支付攻击。

# 手动备份
bash scripts/backup-data.sh

# 只保留最近 7 份
bash scripts/backup-data.sh --keep 7

# 备份并 SCP 到远程
BACKUP_REMOTE_HOST=backup-server bash scripts/backup-data.sh --remote scp

# 定时备份(crontab)
0 3 * * * cd /opt/token-rugcheck && bash scripts/backup-data.sh >> /var/log/rugcheck-backup.log 2>&1

6. 日常运维

# SSH 到服务器
ssh root@<IP>
cd /opt/token-rugcheck

# 查看状态
docker compose ps
docker compose logs --tail 50

# 重启
docker compose restart

# 切换模式(修改 .env 后)
docker compose down && docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d

# 改价格
sed -i 's/AG402_PRICE=.*/AG402_PRICE=0.05/' .env
docker compose restart ag402-gateway

# 查看交易历史
docker compose logs ag402-gateway | grep "payment"

# 查看 ag402 依赖版本
docker compose exec ag402-gateway pip show ag402-core ag402-mcp

# 清理磁盘
docker system prune -f

监控

  • /health — 健康检查(200=正常, 503=降级),Docker 通过 curl -sf 轮询
  • /stats — 请求统计(仅 loopback 可访问)
  • /metrics — Prometheus 指标(仅 loopback 可访问),路径已归一化防止基数爆炸
  • 推荐配置 UptimeRobot 监控 https://<domain>/health
  • 生产环境建议设 RUGCHECK_PRODUCTION=true 禁用 /docs

7. 故障排查

诊断流程

容器是否在运行?
  ├─ 否 → docker compose logs --tail 50
  └─ 是 → 端口是否可达?
           ├─ localhost:8000 不通 → 审计服务崩溃,查看 rugcheck-audit 日志
           ├─ localhost:80 不通 → 网关崩溃,查看 ag402-gateway 日志
           └─ 端口正常 → 外部能访问吗?
                         ├─ IP:80 不通 → 防火墙问题 (ufw status)
                         └─ 域名不通 → 检查 Cloudflare DNS 和 SSL 配置

常见问题

问题原因解决
端口已被占用 (port is already allocated)旧容器未完全清理docker ps -a | grep token 找到残留容器 → docker rm -f <id> → 重新启动
git pull 冲突 (Aborting)服务器有未提交/未跟踪文件git stash --include-untracked && git pull origin main(脚本已自动处理)
容器秒退uvloop 与 aiosqlite 冲突确认 Dockerfile 或 .env 有 UVLOOP_INSTALL=0
health 报 degraded启动后无请求,超时误判正常现象,首次请求后恢复
402 但付款后仍 403缺少 USDC ATAdevnet: spl-token create-account 创建 USDC ATA
HTTPS 证书错误使用了二级子域名改用一级子域名(Cloudflare 免费版限制)
域名 HTTPS 返回 5xxCloudflare SSL 设为 Full/Full(strict) 但源站无 TLS改回 Flexible(Cloudflare → SSL/TLS → Flexible)
Docker build OOM服务器内存不足dd if=/dev/zero of=/swapfile bs=1M count=2048 && swapon /swapfile
gateway 启动异常无 SOLANA_PRIVATE_KEYgateway.py 已有 fallback,正常
ag402 版本过旧Docker build 使用了缓存docker compose build --no-cache 强制重建

紧急恢复

如果服务完全无法启动,执行以下步骤:

ssh root@<IP>
cd /opt/token-rugcheck

# 1. 暴力清理所有相关容器和网络
docker compose -f docker-compose.yml -f docker-compose.prod.yml down --remove-orphans --volumes=false
docker ps -a --filter "name=token-rugcheck" -q | xargs -r docker rm -f
docker network prune -f

# 2. 确认端口释放
ss -tlnp | grep -E ':80 |:8000 '
# 如果仍被占用:
# lsof -i :80 和 lsof -i :8000 找到 PID 并 kill

# 3. 清理 git 状态,恢复到上一个稳定 tag
git stash --include-untracked
git clean -fd
git fetch --tags origin
git checkout v1.x.x  # 替换为实际的稳定 tag,参考 .deploy_history

# 4. 重建并启动
docker compose -f docker-compose.yml -f docker-compose.prod.yml build --no-cache
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d

# 5. 验证
docker compose ps
curl -s http://localhost:80/health
curl -s http://localhost:8000/health

8. 配置参考

.env 关键变量

变量必需说明示例
X402_MODE运行模式test / production
X402_NETWORKSolana 网络devnet / mainnet / mock
AG402_ADDRESS收款 Solana 地址YourSo1ana...
AG402_PRICE单次审计价格 (USDC)0.02
AG402_PREPAID_SIGNING_KEY可选预付费凭证 HMAC 签名密钥。设置后启用 prepaid fast-path(每次请求 ~1ms 本地验证,替代 ~500ms 链上验证)。留空则禁用 prepaid。生成:python -c "import secrets; print(secrets.token_hex(32))"
SOLANA_RPC_URL生产强烈推荐Solana RPC 节点(只读,用于支付验证)。默认公共节点有速率限制,高并发时支付验证会超时;生产建议使用私有节点(Helius 免费层即可)https://mainnet.helius-rpc.com/?api-key=xxx
RUGCHECK_PRODUCTION生产推荐禁用 /docs /redoc,production /health 只返回 {"status": ...}true / false
UVLOOP_INSTALL必须设为 0(防止 uvloop/aiosqlite 冲突导致 gateway 崩溃)0
UVICORN_WORKERS可选worker 进程数1(默认)
UVICORN_LIMIT_CONCURRENCY可选最大并发连接数0(无限制)
FREE_QUOTA_ENABLED可选网关免费层开关。true 启用每 IP 每日免费配额,false 所有请求直接走付费true(默认)
GOPLUS_APP_KEY可选GoPlus API key
GOPLUS_APP_SECRET可选GoPlus API secret

9. 安全修复记录

v0.1.1 安全加固 (2025-06)

修复了 4 个安全问题,新增 1 个测试模块,测试从 78 → 117 个:

#修复内容文件严重度说明
S1生产模式网关不再静默降级为 mockgateway.py🔴 高原行为:生产模式下 PaymentVerifier 初始化失败时自动降级为 mock(免费访问)。现行为:sys.exit(1) 拒绝启动,防止付费 API 被免费访问
S2缓存深拷贝防止共享状态污染cache.py🟡 中get()/set() 现在使用 model_copy(deep=True),防止调用者修改 metadata 后污染缓存中的原始数据
S3未知 IP 不再绕过限流server.py🟡 中原行为:request.client 为 None 时 "unknown" IP 被无条件放行。现行为:归入 __unknown__ 统一桶限流
S4代理真实 IP 解析server.py🟡 中新增 _resolve_client_ip() 函数,按 CF-Connecting-IPX-Forwarded-Forrequest.client 优先级解析,确保 Cloudflare 后的限流按真实 IP 生效
S5PLACEHOLDER_ADDRESS 统一导出config.py🟢 低占位地址常量从 config.py 导出,gateway.py 不再维护副本

新增测试

测试文件新增测试数覆盖内容
test_security.py+7网关生产模式崩溃、缓存深拷贝(get/set)、CF/XFF IP 解析、未知 IP 限流、占位地址导出
test_payment_security.py+8 (新文件)402 挑战、伪造支付凭据拒绝、欠付拒绝、错误地址拒绝、重放攻击拒绝、过期凭据拒绝

v0.1.2 安全与运维加固 (2025-07)

修复了 7 个安全/运维问题,测试从 117 → 118 个:

#修复内容文件严重度说明
S6CF-Connecting-IP 信任模型server.py🔴 高原行为:无条件信任 CF-Connecting-IP/X-Forwarded-For,攻击者可伪造 IP 绕过限流。现行为:仅当 socket peer 属于 Cloudflare IP 段或 loopback 时才读取代理头
S7健康检查改用 curlDockerfile, Dockerfile.gateway, docker-compose.yml🟡 中Docker healthcheck 从 Python 脚本改为 curl -sf,减少启动开销,添加 start_period: 10s
S8生产环境禁用 /docsconfig.py, server.py🟡 中RUGCHECK_PRODUCTION=true 时关闭 /docs/redoc/openapi.json,防止 API 文档泄露
S9Prometheus 路径归一化server.py🟡 中未知路径统一返回 "other",防止恶意请求导致 Prometheus 基数爆炸
S10降级报告短缓存server.py, cache.py🟡 中降级(不完整)报告 TTL 仅 10 秒(而非正常 TTL),上游恢复后快速获取新数据
S11uvicorn 多 worker 支持main.py🟢 低支持 UVICORN_WORKERS 环境变量,>1 时使用 factory 模式
S12DailyQuota 定时清理server.py🟢 低后台任务每小时清理非当天的配额条目,防止内存无限增长

新增环境变量RUGCHECK_PRODUCTIONUVICORN_WORKERSUVICORN_LIMIT_CONCURRENCY


v0.1.3 主网上线 + 买方测试脚本 (2026-03)

主网正式上线,地址 https://rugcheck.aethercore.dev。新增 mainnet_buyer_test.py 命令行审计工具。

#修改内容文件说明
F1mainnet_buyer_test.py 改为 CLI 工具mainnet_buyer_test.py从硬编码 3 个 case 改为 argparse 接收任意 mint 地址;支持单个或多个代币;支持 --gateway 指定网关
F2多源私钥加载mainnet_buyer_test.py不再强制 export SOLANA_PRIVATE_KEY;按优先级尝试:环境变量 → ~/.ag402/.env → 解密 ~/.ag402/wallet.key(ag402 setup 加密钱包)
F3修复 wallet.key 解密调用mainnet_buyer_test.py修复 decrypt_private_key 参数顺序错误:原来传 (path, password),实际 API 是 (password, encrypted_data_dict);需先调用 load_encrypted_wallet(path) 加载字典
F4SOL 余额预检mainnet_buyer_test.pyStep 3 新增原生 SOL 余额检查(通过 Solana RPC),不足 0.01 SOL 时提前报错而非让交易失败
F5SOL 余额属性名修复mainnet_buyer_test.pySolanaAdapter 内部属性是 _keypair(带下划线),修复 provider.keypairprovider._keypair
F6InsufficientFundsForRent 错误识别mainnet_buyer_test.py交易失败时检测 InsufficientFundsForRent 错误,给出明确的 "SOL 不足" 提示而非通用 FAIL
F7README 重写README.md以正式上线为核心重写,突出体验地址、快速上手流程、API 响应示例

主网验证结果

  • BONK (DezXAZ...B263) — ✅ 审计成功,正确识别为 SAFE(risk_score=3)
  • TRUMP (6p6x...GiPN) — 交易确认超时(Solana 网络问题,非服务端问题)

v0.1.4 分支保护 + 部署安全加固 (2026-03)

新增分支策略文档,加固部署脚本安全性:

#修改内容文件类型说明
D1新增分支策略与发布流程文档OPERATIONS.md📖 文档新增第 3 节:main/develop/feature 分支规范、环境与分支对应关系、语义化 tag 规范、GitHub 分支保护配置步骤
D2quick-update.sh 支持指定 tag/分支/commit 部署quick-update.sh🔧 功能新增第三个参数 [ref],支持精确锁定版本(v1.2.0)、分支(develop)或 commit hash;默认仍为 main
D3quick-update.sh 部署历史记录quick-update.sh🔧 功能每次部署后写入服务器 .deploy_history(已加入 .gitignore),记录时间、ref、commit、前一个 commit
D4quick-update.sh 自动打印回滚命令quick-update.sh🔧 功能部署成功后打印回滚命令;通过 trap EXIT 确保构建失败、健康检查超时等场景也能输出回滚命令
S13GIT_REF 输入校验防止 shell 注入quick-update.sh🔴 安全[ref] 参数经白名单正则校验(^[a-zA-Z0-9._/-]+$),拒绝含特殊字符的输入,防止通过参数在远端服务器执行任意命令
D5deploy-oneclick.sh 加入职责说明deploy-oneclick.sh📖 文档Phase 5 新增提示,明确此脚本用于首次部署/完整重配,日常更新应使用 quick-update.sh <IP> <domain> <tag>
D6setup-server.sh 加入职责注释setup-server.sh📖 文档说明 setup-server.sh 始终拉取 main HEAD(初始化路径),与 tag 锁定的 quick-update.sh 职责边界明确
D7.gitignore 新增 .deploy_history.gitignore🔒 安全部署历史(含 commit hash 记录)加入忽略列表,防止运维日志意外提交到公开仓库

v0.2.0 Gateway 感知配额 — 免费层 + HTTP 代理架构 (2026-03)

解决 Issue #2:FREE_DAILY_QUOTA 在生产环境中失效(ag402-gateway 无条件返回 402)。新增 QuotaAwareGateway 包装层,在支付墙前提供免费配额。

新增文件

文件说明
src/rugcheck/quota.py共享配额模块:DailyQuota(per-IP 每日计数器)、QuotaResult(冻结数据类)、resolve_client_ip(代理感知 IP 解析)、TRUSTED_PROXY_NETWORKS(Cloudflare IP 段)
src/rugcheck/gateway_wrapper.pyQuotaAwareGateway:包装 X402Gateway,免费配额内 HTTP 代理到审计服务,配额耗尽后 fallthrough 到 402
tests/test_quota.py18 个测试:配额基本行为、每日重置、并发安全、IP 解析、Cloudflare 信任
tests/test_gateway_wrapper.py16 个测试:免费路径、配额递减、402 fallthrough、health bypass、metrics

功能变更

#修改内容文件类型说明
F9QuotaAwareGateway 免费层gateway_wrapper.py🔧 功能每 IP 每天 FREE_DAILY_QUOTA 次免费请求,HTTP 代理到审计服务;配额耗尽后 402 要求付费。响应包含 X-Free-RemainingX-Quota-Tier
F10共享配额模块提取quota.py🔧 重构server.py 提取 DailyQuotaresolve_client_ipTRUSTED_PROXY_NETWORKS 到独立模块,gateway 和 server 共享
F11FREE_QUOTA_ENABLED 开关gateway.py, .env.example🔧 功能新增环境变量 FREE_QUOTA_ENABLED(默认 true),设为 false 则所有请求直接走付费

安全加固

#修复内容文件严重度说明
S17content-encoding 响应损坏修复gateway_wrapper.py🔴 高httpx 透明解压 body 但保留原始 content-encoding 头;移除白名单中的 content-encoding 防止客户端双重解压
S18IPv6 配额绕过修复quota.py🔴 高同一 IPv6 地址不同字符串表示创建独立配额桶;使用 str(ipaddress.ip_address()) 规范化
S19代理头剥离扩展gateway_wrapper.py🟡 中新增 RFC 7230 §6.1 hop-by-hop 头剥离:connection、keep-alive、te、trailer、upgrade
S20TOCTOU 午夜竞态修复quota.py🟡 中_today() 调用移入 asyncio.Lock 内,防止午夜时刻配额多授一次
S21hop-by-hop 响应头过滤gateway_wrapper.py🟡 中_forward_to_gateway 响应过滤 transfer-encoding/connection/content-length
S22URL 路径规范化gateway_wrapper.py🟡 中_build_forward_url 规范化为单前导斜杠,防止协议相对 URL 问题

性能优化

#修改内容文件说明
P1连接池扩容gateway_wrapper.pymax_connections 50→200,max_keepalive_connections 20→50
P2ASGI gateway 客户端复用gateway_wrapper.py付费路径客户端在 lifespan 创建并复用,替代每请求创建
P3配额清理启动即运行gateway_wrapper.py_quota_cleanup_loop 启动即执行一次,不再等待 1 小时
P4cleanup_task 正确等待取消gateway_wrapper.pylifespan shutdown 中 await cleanup_task 防止任务泄漏

测试:78 → 117 → 118 → 119 → 153 个(+34 个新增)

新增环境变量FREE_QUOTA_ENABLED


v0.2.1 Playground CSP 加固 + 全面修复 (2026-03)

消除所有 inline event handler,修复 badge 背景 CSS bug,加强 XSS 防御,提升无障碍和 UX:

#修改内容文件类型说明
S23消除全部 inline onclick (9 处)playground.html🔴 安全onclick="toggleTheme()" 等 9 处 inline handler 全部替换为 data-* + addEventListener。页面 0 个 inline event handler;若将 <script> 提取为外部文件,可进一步收紧 CSP 移除 'unsafe-inline'
S24pair_created_at XSS 修复playground.html🔴 安全ev.pair_created_at 从 API 返回的字符串直接注入 HTML 未经转义;改为 esc(ev.pair_created_at)
S25risk_score / response_time_ms 类型检查playground.html🟡 安全a.risk_scorem.response_time_ms 添加 typeof === 'number' 校验,防止恶意 API 响应注入 HTML
S26badge 背景 CSS 修复playground.html🟡 修复background:${color}22riskColor() 返回 CSS 变量时生成无效 CSS(如 var(--green)22);新增 riskBgLight() 函数返回正确的 rgba() 背景色
S27SVG innerHTML 替换为 replaceChildrenplayground.html🟢 安全svg.innerHTML = '' 替换为 svg.replaceChildren(path),避免 innerHTML 在 SVG 上下文中的潜在风险
S28history addr 转义playground.html🟢 安全搜索历史中截断的地址字符串 x.address.slice(0,6) 补充 esc() 转义
S29外部链接 rel=noopenerplayground.html🟢 安全GitHub 外链添加 rel="noopener noreferrer"
F12搜索历史键盘导航playground.html🔧 功能支持 ArrowDown/ArrowUp 在历史条目间移动,Enter 选中当前高亮条目
F13输入防抖playground.html🔧 优化搜索历史过滤增加 50ms debounce,减少高频 DOM 重建
F14Trending 自动刷新playground.html🔧 功能通过 visibilitychange API 在标签页恢复可见且距上次加载 >5 分钟时自动刷新 trending 数据
D15meta descriptionplayground.html📖 SEO添加 <meta name="description"> 标签

v0.1.8 Playground 主题切换 + 搜索历史 (2026-03)

Playground UI 新增暗色/亮色主题切换和搜索历史功能,同步进行首轮安全加固:

#修改内容文件类型说明
F9暗色/亮色主题切换playground.html🔧 功能CSS 自定义属性实现主题系统,[data-theme="light"] 选择器覆盖暗色变量。localStorage 持久化主题偏好,首次加载自动匹配系统偏好 (prefers-color-scheme)
F10搜索历史playground.html🔧 功能最近 10 次审计记录保存到 localStorage,输入框 focus 时展示下拉列表,支持按地址/名称/符号过滤,单条删除和清空
S20riskColor / riskBg 白名单验证playground.html🔴 安全防止恶意 API 数据通过 style="color:${...}" 注入 CSS;只允许 SAFE/LOW/MEDIUM/HIGH/CRITICAL,其他值返回安全默认色
S21img onerror 改用 addEventListenerplayground.html🟡 安全trending 卡片图片的 onerror 从 inline 改为 data-hide-on-error + DOM 事件监听
S22SVG createElementNSplayground.html🟡 安全主题图标 SVG 路径用 document.createElementNS() 创建,替代 innerHTML 字符串拼接
A1API 字段 null 检查playground.html🟡 健壮性rugcheck_score/contract_address/response_time_ms 添加 null/NaN/类型检查,防止 API 降级时 UI 报错
A2ARIA 无障碍playground.html🟢 可访问性输入框添加 aria-label,状态区域添加 aria-live="polite"
A3移动端响应式playground.html🟢 UX@media(max-width:480px) 断点调整主题按钮尺寸和标题大小

v0.1.7 适配 ag402 v0.1.17 — 幂等预付费 + 安全加固 (2026-03)

升级 ag402 依赖至 v0.1.17,获得 TOCTOU 修复和预付费幂等性支持:

#修改内容文件类型说明
D14依赖版本升级至 >=0.1.17pyproject.toml, Dockerfile.gateway🔧 依赖ag402-mcp / ag402-core 最低版本从 >=0.1.15 升至 >=0.1.17,Dockerfile.gateway 中的固定版本同步更新

ag402 v0.1.16–v0.1.17 上游变更(对本项目透明,无需代码适配)

变更描述
TOCTOU 竞争条件修复两个并发请求用同一 tx_hash 购买时,INSERT OR IGNORE 保证只发出一份凭证
幂等 /prepaid/purchase同一 tx_hash 多次请求返回完全相同的凭证(相同 expiry、签名),超时重试不会被拒绝
预付费发证账本SQLite prepaid_issued 表记录已发证的 tx_hash,网关重启后仍有幂等保护
buyer_address 冲突改返 403原返 409(信息泄露),现返 403
弱签名密钥警告AG402_PREPAID_SIGNING_KEY 短于 32 字符时打印警告
凭证序列化安全to_header_value() 异常时回滚扣减、降级到 on-chain,不再崩溃
新 CLI 命令ag402 prepaid recover / ag402 prepaid pending(买家侧,服务端无感知)

v0.1.6 预付费激活 + 安全加固 (2026-03)

激活 ag402 prepaid 预付费功能,修复两个阻塞上线的部署坑,收紧 production 信息泄露:

#修改内容文件类型说明
F8激活 prepaid 预付费快速通道config.py, gateway.py, .env.example, docker-compose.yml🔧 功能新增 AG402_PREPAID_SIGNING_KEY 配置项并传入 X402Gateway。设置后启用 prepaid fast-path:买家预购套餐后每次请求走本地 HMAC 验证(~1ms),替代链上验证(~500ms)。默认留空=关闭,兼容现有部署
S14production /health 最小化响应server.py🔴 安全RUGCHECK_PRODUCTION=true/health 只返回 {"status": ...},不再暴露版本号、服务名和 upstream 时序信息
S15修复 docker-compose environment 覆盖 .envdocker-compose.yml🔴 安全移除 environment 中的 AG402_PREPAID_SIGNING_KEY=${...} 展开语法——此语法从宿主机 shell 读取变量,优先级高于 env_file,导致 .env 里的值被空字符串覆盖,prepaid 永远失效。改为只通过 env_file: .env 读取
S16修复 generate-env.sh 缺少关键变量scripts/generate-env.sh🔴 安全/运维生成的 .env 补入 UVLOOP_INSTALL=0(缺失会导致 gateway 崩溃)、RUGCHECK_PRODUCTION(生产环境应开启 hardening)、AG402_PREPAID_SIGNING_KEY(提示可选配置)
D12更新依赖最低版本pyproject.toml🔧 依赖ag402-mcp / ag402-core 最低版本从 >=0.1.11 升至 >=0.1.15,确保 prepaid_signing_key 参数可用
D13修正文档错误README.md, OPERATIONS.md📖 文档修正 Provider .env 示例(卖家不需要 SOLANA_PRIVATE_KEY);修正 /health 响应格式说明;补充 AG402_PREPAID_SIGNING_KEY 配置参考;更新 ag402 CLI prepaid 命令

新增测试test_health_production_minimal — 验证 production 模式 /health 严格只返回 {"status": ...} 不含任何额外字段


v0.1.5 文档修正与上线前风险提示 (2026-03)

修正文档错误,补充上线前必知的三项风险:

#修改内容文件类型说明
D8修正本地 test 模式启动命令OPERATIONS.md📖 文档Docker Compose 从 .env 读取变量,不支持命令行内联注入;改为 cp .env.example .env && docker compose up 的正确用法
D9SOLANA_RPC_URL 生产风险说明OPERATIONS.md📖 文档默认公共 RPC 有速率限制,高并发时支付验证超时;配置参考表格新增说明,推荐使用 Helius 私有节点
D10ag402 未锁版本风险OPERATIONS.md📖 文档已知问题表格新增 A8:--no-cache 构建每次拉最新 ag402,上游破坏性变更可能导致部署失败
D11上线前必做事项补充OPERATIONS.md📖 文档需要人工处理表格新增:卖家钱包 USDC ATA 创建(首笔付款前必须)、私有 RPC 配置说明

10. 已知问题

ag402 库的问题(上游,需等待更新)

#问题严重度规避方式
A1ag402 serve 硬编码 host=127.0.0.1🔴 高自建 gateway.py 绕过 CLI
A2uvloop 与 aiosqlite 冲突🔴 高UVLOOP_INSTALL=0
A3缺 USDC ATA 时报 InsufficientFundsForRent🟡 中确保买方钱包有 ≥0.01 SOL;mainnet_buyer_test.py 已增加 SOL 预检和明确提示
A4无私钥时 get_provider() 异常✅ 已修复生产模式直接拒绝启动 (S1)
A5无收入报表 API🟢 低解析日志
A6Solana 主网交易确认超时导致 403🟡 中网络瞬时问题,重试即可;网关返回 Payment not confirmed on-chain
A7ag402 run 不自动解密 wallet.key🟡 中mainnet_buyer_test.py 已自行实现多源私钥加载(F2/F3)
A8ag402 依赖未锁定版本✅ 已修复pyproject.toml 最低版本已锁定为 >=0.1.17,包含 prepaid 功能、TOCTOU 修复及多项安全加固。--no-cache 构建仍拉最新版(>=0.1.17),但不会再拉到缺少这些修复的旧版本

需要人工处理的一次性事项

事项说明
旋转 devnet 私钥旧私钥曾在 Git 历史中,建议生成新密钥对
卖家钱包创建 USDC ATA首笔真实收款前必须完成,否则买家交易报 InsufficientFundsForRent(swap 一次 USDC 即可自动创建)
配置私有 Solana RPC✅ 已配置 Helius mainnet RPC
配置 crontab 定时备份0 3 * * * cd /opt/token-rugcheck && bash scripts/backup-data.sh
部署 UptimeRobot监控 https://<domain>/health
修复 Cloudflare DNSDNS 解析到错误 IP(非服务器 IP),导致 HTTPS 域名不可访问;需在 Cloudflare 面板修正 A 记录指向 140.82.49.221

部署记录

日期版本操作备注
2026-03-23v0.2.1 (pending)未提交CSP 加固:消除全部 inline onclick、badge CSS 修复、pair_created_at XSS 修复、键盘导航、防抖、trending 自动刷新
2026-03-23v0.1.8 (9fd5eaa)08541d3 升级playground 主题切换 + 搜索历史 + 首轮安全加固。所有 4 层验证通过
2026-03-14v0.1.7 (b4485ff)f68a5ce 升级ag402 0.1.19, RUGCHECK_PRODUCTION=true + UVLOOP_INSTALL=0 已加入 .env, mainnet 支付测试通过 (BONK 审计 $0.02), HTTPS 域名待修复 (Cloudflare DNS 问题)

脚本速查

脚本功能用法
deploy-oneclick.sh一键部署(首次部署或完整重新配置,始终拉取 main HEAD)bash scripts/deploy-oneclick.sh
quick-update.sh快速更新(支持 tag/分支/commit,含回滚)bash scripts/quick-update.sh <IP> [domain] [ref]
backup-data.sh数据备份bash scripts/backup-data.sh
setup-server.sh服务器初始化被 deploy-oneclick 调用
generate-env.sh生成 .env被 deploy-oneclick 调用
verify.sh5 层部署验证bash scripts/verify.sh --server-ip <IP>

quick-update.sh 常用命令速查

# 部署指定 tag(生产推荐)
bash scripts/quick-update.sh <IP> <domain> v1.2.0

# 部署 main 最新(紧急修复用)
bash scripts/quick-update.sh <IP> <domain>

# 部署 develop 分支(预发测试)
bash scripts/quick-update.sh <IP> "" develop

# 回滚到指定版本
bash scripts/quick-update.sh <IP> <domain> v1.1.0

# 查看部署历史(在服务器上执行)
cat /opt/token-rugcheck/.deploy_history