feat: Gitea 发布 skill:隐私检查 + 建仓 + 增量推送 + 回读远程验证

This commit is contained in:
NightStar
2026-09-20 11:46:27 +08:00
parent 3515d014b1
commit df0204dff9
2 changed files with 600 additions and 239 deletions
+66 -31
View File
@@ -1,62 +1,97 @@
---
name: "publish-to-gitea"
description: "将文件/目录发布到 Gitea 仓库 — 自动隐私检查、创建公开仓库、Git 推送"
description: "推到 gitea/发布到仓库/建 repo 推上去/把某个 git 仓库推上去时用:跑 gitea_push.py(隐私检查 → 建仓 → 对齐远程 → 推送)→ **回读远程验证**。含脚本覆盖不到的隐私盲区与 tea 建仓坑。"
---
# Publish to Gitea — 发布到 Gitea 仓库
将文件/目录推送到 Gitea 仓库(git.yoresee.cc),自动隐私检查、创建公开仓库、一键推送。
把文件/目录或一个已有 git 仓库推送到 Gitea(git.yoresee.cc)。
**不属于本 skill**:在本机**正在开发的仓库里**提交并推分支 → 直接在该仓库 `git push <remote> <branch>`(凭据走已配好的 `!tea login helper`)。push 被拒先按 `diagnose-git-push-permission` 诊断——「仓库已存在但你是 `push:false`」是常见原因,别急着建新仓(非 admin 也建不了别人的命名空间)。
## 触发条件
用户说出类似以下话语时触发:
- "把这个推送到 gitea"
- "发布到仓库"
- "创建 repo 推上去"
- "publish to git"
- "推到 git.yoresee.cc"
「把这个推送到 gitea」「发布到仓库」「创建 repo 推上去」「publish to git」「推到 git.yoresee.cc」
## 流程
### 1. 确定要推送的内容
从上下文中推断要推送的文件/目录。常见场景:
- 用户刚创建/修改了一个 skill → 推送整个 skill 目录
- 用户说"把这个脚本推上去" → 推送脚本文件
- 用户指定了具体路径 → 直接用
- 用户刚写的 skill / 脚本 / 项目目录 → 推那个目录
- 用户指定路径 → 直接用
- 内容是一个**已有 git 仓库**(有 `.git`、提交历史要保)→ 用 `--from-git`(见 §3)
### 2. 确定仓库名和描述
- **仓库名**:从内容推断,kebab-case 格式
- **描述**:一句话说明用途
- 用户没明确说则主动确认
仓库名 kebab-case,描述一句话。用户没明说则主动确认(仓库默认**公开**)。
### 3. 执行推送
```bash
cd /root/.openclaw/workspace && python3 scripts/gitea_push.py <repo_name> "<description>" <files...>
cd /root/.openclaw/workspace
python3 scripts/gitea_push.py <repo_name> "<description>" [paths...]
```
脚本自动完成:
1. 🔍 隐私检查(检测 open_id、API key、token、IP 等敏感模式)
2. 📦 创建 Gitea **公开**仓库(已存在则复用现有仓库)
3. 📄 收集文件(排除 .git、node_modules 等)
4. 🚀 Git 增量提交 → push(**已存在仓库先拉取远程历史,正常 commit + push,不使用 --force**;全新仓库直接首推)
5. 🔗 返回仓库 URL
| 场景 | 命令 |
|---|---|
| 目录/文件 → 仓库 | `gitea_push.py my-proj "描述" ./src` |
| 推已有 git 仓库(**保留完整提交历史**) | `gitea_push.py my-proj "描述" --from-git /root/my-proj` |
| 只检查不推送 | `... --dry-run` |
### 4. 反馈
常用选项:`--from-git DIR`(推仓库自身提交,不自动提交脏工作区)、`--owner`(默认 `NightStar`)、`--branch`(默认 `master`)、`--message`(自定义提交信息)、`--private`、`--exclude PATTERN`(可重复)、`--allow-leaks`、`--no-scan`、`--quiet`。
推送成功后告诉用户仓库地址。
脚本四步:隐私检查 → 确保仓库存在(无则建,有则复用并**拉远程历史对齐**,不用 `--force`)→ 准备/提交 → 推送(被拒自动 `fetch + rebase` 重试 3 次)。
如果脚本检测到疑似隐私数据泄露,**必须停下来询问用户是否继续**——不可自动跳过。
**退出码**:`0` 成功 / `1` 一般错误 / `2` 隐私检查未通过 / `3` 推送被拒。成功后 stdout 是 JSON(`url` / `clone` / `branch`)。
## 安全约束
### 4. 回读远程验证(必做,别信脚本自报)
- ⚠️ 推送前必须过隐私检查
- 仓库默认**公开**(public),不设 private
- 不要推送 .git 目录、node_modules、二进制文件
- 如果之前泄露过隐私并已 amend,确认后再推
⚠️ **脚本打印「✓ 推送成功」不等于远程真的收到了。** 实测踩过:脚本报成功,回读发现远程只有一个空 README,文件一个没上去(内部 `git add` 未执行的 bug)。凡涉及「推没推上去」的结论,一律回读远程:
```bash
GIT_SSH_COMMAND="ssh -o StrictHostKeyChecking=accept-new" \
git clone --depth 1 git@git.yoresee.cc:<owner>/<repo>.git /tmp/<repo>-verify
find /tmp/<repo>-verify -type f -not -path "*/.git/*" | sed "s|/tmp/<repo>-verify/||" | sort
```
判据:期望的文件都在、内容对(抽读 1-2 个);`git log --oneline` 能看到本次提交。`--from-git` 模式再核提交数(`git rev-list --count HEAD`)与本地一致。**验完删掉临时 clone。**
### 5. 反馈
告诉用户仓库地址 + 验证结论(哪些文件在、提交 sha)。若脚本报隐私命中,**必须停下问用户**,不可自动跳过(用户确认无误才加 `--allow-leaks`)。
## 隐私检查:脚本已覆盖的 + 仍需手工补的
脚本扫 48 种文本扩展名(含 `.html/.htm/.css/.vue/.go/.tsx/.env/.svg/.scss` 等)与常见文件名(`Dockerfile/.env/.npmrc/...`),模式含 GitHub PAT、`sk-`/`sk-sp-`、AWS `AKIA`、Slack `xox`、飞书 `cli_`/`ou_`、`Bearer`、PEM 私钥、明文口令赋值,以及**公网 IP**(`127./10./192.168./172.16-31./169.254./0./255.` 这类不算,RFC 5737 文档专用段 `192.0.2./198.51.100./203.0.113.` 也不算)。改动或新增扫描范围前先看脚本里的 `SCAN_EXTS` / `SECRET_PATTERNS`,别凭记忆断言「扫不到」。
⚠️ **仍需手工看的一条:项目自己排除的文件,正是不能公开的。**
先看目标目录的 `.dockerignore` / `.gitignore`。实测某项目把 `data/keywords.src.json`(明文关键词表)排除出部署产物,却随仓库推成了**公开可见**——等于把解谜答案公开。同类信号:`*.src.json`、`*.key`、`*.secret.*`、被 ignore 的配置或原始数据。
发现就问用户三选一:改 private(`--private`,但建仓后改可见性要去 Gitea 页面/API)、`git rm --cached` 后加进 ignore、或明确接受公开。**不要默认推送。**
判读命中的邮箱**逐条看域名**:`.example` / `.invalid` 是拟真噪音,真实域名才算泄露。
## 建仓相关的两个坑
⚠️ **`tea` 0.15.0 给自己命名空间建仓不能传 `--owner`**:`tea repos create --name X --owner NightStar ...` 回 `Error: not found`,**省略 `--owner` 才成功**(大小写无关,实测小写同样失败)。脚本已内部规避(owner == 登录用户时省略该参数);手工用 `tea` 建仓时照此办理。只有建到组织/他人命名空间才需要 `--owner`。
⚠️ **全新仓库的 `Initial commit`**:脚本用 `tea ... --init` 建仓,远程因此多一个只含 README 的 `Initial commit`。脚本靠 `git reset --mixed` 对齐远程历史(只移动 HEAD、**不碰工作区**,避免覆盖同名文件)。若脚本的对齐/重试仍失败,手工兜底:
```bash
cd <目录> && git init -b master -c user.name=<名> -c user.email=<邮箱>
git remote add origin git@git.yoresee.cc:<owner>/<repo>.git
export GIT_SSH_COMMAND="ssh -o StrictHostKeyChecking=accept-new"
git fetch origin && git reset --mixed origin/master # 不要用 --hard:会覆盖同名文件
git add -A && git commit -m "<描述>" && git push -u origin master
```
别用 `--force`(会抹掉远程那个 commit)。
## 完成判据
远程回读通过:期望文件都在、内容正确、`git log` 有本次提交(`--from-git` 模式另核提交数与本地一致);仓库 URL 已告知用户;若曾出现隐私命中,用户已明确表态。
## 脚本依赖
`scripts/gitea_push.py` — Gitea 推送脚本,基于 tea CLI。
`/root/.openclaw/workspace/scripts/gitea_push.py` — 基于 `tea` CLI;**不在本 skill 目录内**,所以要先 `cd /root/.openclaw/workspace` 再用相对路径调它。