From 5c540d05ea084b873b4b82df4b6776aafaa3459c Mon Sep 17 00:00:00 2001 From: Codex Date: Sat, 18 Jul 2026 05:56:59 -0400 Subject: [PATCH] feat: harden and relaunch the open-source skill --- .editorconfig | 12 + .gitattributes | 4 + .github/ISSUE_TEMPLATE/config.yml | 8 + .github/repository-metadata.yml | 26 ++ .github/workflows/validate.yml | 20 + CHANGELOG.md | 35 ++ CONTRIBUTING.md | 5 +- CONTRIBUTORS.md | 4 + README.md | 245 +++++------- SECURITY.md | 29 +- SKILL.md | 36 +- agents/openai.yaml | 10 + assets/social-preview.png | Bin 0 -> 93083 bytes assets/social-preview.svg | 62 +++ examples/README.md | 70 ++++ references/automation-templates.md | 14 +- references/github-access-guide.md | 579 ++++------------------------- references/release-workflow.md | 4 +- references/response-templates.md | 8 +- references/triage-workflow.md | 2 +- scripts/validate-skill.mjs | 94 +++++ 21 files changed, 564 insertions(+), 703 deletions(-) create mode 100644 .editorconfig create mode 100644 .gitattributes create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/repository-metadata.yml create mode 100644 .github/workflows/validate.yml create mode 100644 CHANGELOG.md create mode 100644 CONTRIBUTORS.md create mode 100644 agents/openai.yaml create mode 100644 assets/social-preview.png create mode 100644 assets/social-preview.svg create mode 100644 examples/README.md create mode 100644 scripts/validate-skill.mjs diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..1014ba7 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 2 +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..f47922c --- /dev/null +++ b/.gitattributes @@ -0,0 +1,4 @@ +* text=auto eol=lf +*.png binary +*.jpg binary +*.zip binary diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..7fc6446 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: false +contact_links: + - name: Questions and workflow discussions + url: https://github.com/hyt315/github-oss-ops/discussions + about: Ask usage questions or discuss workflow design here. + - name: Report a security vulnerability privately + url: https://github.com/hyt315/github-oss-ops/security/advisories/new + about: Do not disclose credentials or vulnerability details in a public issue. diff --git a/.github/repository-metadata.yml b/.github/repository-metadata.yml new file mode 100644 index 0000000..c77571b --- /dev/null +++ b/.github/repository-metadata.yml @@ -0,0 +1,26 @@ +repository: hyt315/github-oss-ops +description: Approval-gated Agent Skill for GitHub Issue triage, PR review assistance, releases and repository health reporting. +topics: + - agent-skills + - github + - github-actions + - issue-triage + - maintainer-tools + - open-source + - pull-request-review + - release-automation + - repository-management + - workflow-automation +features: + issues: true + discussions: true + private-vulnerability-reporting: true +ruleset: + target: main + require-pull-request: true + require-status-check: validate + block-force-push: true + block-deletion: true +release: + tag: v1.1.0 + title: GitHub OSS Ops v1.1.0 diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml new file mode 100644 index 0000000..b03ffd2 --- /dev/null +++ b/.github/workflows/validate.yml @@ -0,0 +1,20 @@ +name: Validate + +on: + pull_request: + push: + branches: [main] + +permissions: + contents: read + +jobs: + validate: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + node-version: "20" + - name: Validate skill package + run: node scripts/validate-skill.mjs diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..cf3a300 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,35 @@ +# Changelog + +All notable changes to GitHub OSS Ops are documented here. + +## [1.1.0] - 2026-07-18 + +### Added + +- Three end-to-end examples with explicit read/write approval boundaries. +- Cross-platform static validator and GitHub Actions validation workflow. +- Agent metadata, repository metadata, contributor attribution and a social-preview asset. + +### Changed + +- Corrected Codex installation to the current `~/.agents/skills` location and clarified ChatGPT/Codex naming. +- Reworked authentication around public read-only access, official GitHub OAuth/MCP, authenticated GitHub CLI and least-privilege fine-grained PATs. +- Rewrote the project landing page around outcomes, examples, downloads and a five-minute first run. + +### Security + +- Removed credential discovery that searched user directories or printed extracted tokens. +- Prohibited asking users to paste credentials into chat or persisting credentials in the skill directory. +- Replaced public vulnerability reporting with GitHub Private Vulnerability Reporting. + +## [1.0.2] - 2026-07-18 + +- Aligned MCP tool names with the then-current consolidated GitHub MCP tools. + +## [1.0.1] - 2026-07-18 + +- Replaced non-functional HTML anchors with Markdown headings. + +## [1.0.0] - 2026-07-18 + +- Initial public release. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1df7903..d74e459 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -15,8 +15,9 @@ 1. **Fork** 本仓库 2. **创建分支**:`git checkout -b feature/你的功能名` 3. **提交改动**:使用 Conventional Commits 格式(`feat:` / `fix:` / `docs:` 等) -4. **推送分支**:`git push origin feature/你的功能名` -5. **提交 Pull Request**:填写 PR 模板,说明改动内容和原因 +4. **运行验证**:`node scripts/validate-skill.mjs` +5. **推送分支**:`git push origin feature/你的功能名` +6. **提交 Pull Request**:填写 PR 模板,说明改动内容和原因 ### 贡献 Skill 逻辑 diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md new file mode 100644 index 0000000..9dd30cd --- /dev/null +++ b/CONTRIBUTORS.md @@ -0,0 +1,4 @@ +# Contributors + +- [hyt315](https://github.com/hyt315) — creator, product direction and release ownership. +- [ChatGPT (Codex)](https://github.com/codex) — security review, workflow design, validation, documentation and open-source release engineering. diff --git a/README.md b/README.md index 164a55f..408b82a 100644 --- a/README.md +++ b/README.md @@ -1,201 +1,148 @@ -# 🛠️ GitHub 开源项目运营 / GitHub OSS Ops +# GitHub OSS Ops -
+[中文](#中文) · [English](#english) -**开源发布后的"AI 客服":Issue 智能分流、PR 辅助审查、版本管理、运营报告,一站式搞定** +[![Validate](https://github.com/hyt315/github-oss-ops/actions/workflows/validate.yml/badge.svg)](https://github.com/hyt315/github-oss-ops/actions/workflows/validate.yml) +[![Release](https://img.shields.io/github/v/release/hyt315/github-oss-ops)](https://github.com/hyt315/github-oss-ops/releases/latest) +[![Downloads](https://img.shields.io/github/downloads/hyt315/github-oss-ops/total)](https://github.com/hyt315/github-oss-ops/releases) +[![Contributors](https://img.shields.io/github/contributors/hyt315/github-oss-ops)](CONTRIBUTORS.md) +[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) -**AI-powered operations for open-source repos: smart Issue triage, PR review assistance, release management, and ops reporting** +给独立维护者和小团队使用的 GitHub 运营 Agent Skill:扫描 Issue/PR、生成可审查草稿、辅助版本发布,并把所有外部写操作留在明确批准之后。 -[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) -[![Version](https://img.shields.io/badge/version-1.0.2-green.svg)]() -[![SKILL.md](https://img.shields.io/badge/Agent%20Skill-SKILL.md-green)](SKILL.md) - -[English](#english) | [中文](#中文) +```bash +git clone https://github.com/hyt315/github-oss-ops.git ~/.agents/skills/github-oss-ops +``` -
+[安装为 Agent Skill](#安装为-agent-skill) · [查看三个真实工作流](examples/README.md) · [下载最新版](https://github.com/hyt315/github-oss-ops/releases/latest) ---- +![GitHub OSS Ops workflow: scan, triage, draft, approve, act and report](assets/social-preview.png) ## 中文 -## 📖 这是什么? - -**GitHub 开源项目运营** 是一个 AI Agent Skill,专为已发布的开源项目日常维护设计。它能自动扫描 Issue/PR、智能分类打标签、起草回复、审查代码、管理 Release 版本、处理过期 Issue,甚至生成运营报告。 - -> 💡 与 [github-oss-prep](https://github.com/hyt315/github-oss-prep) 配合使用:oss-prep 负责项目发布准备,本技能负责发布后的日常运营。 - -### ✨ 核心功能 - -| 功能模块 | 说明 | -|----------|------| -| 🔍 **Issue 扫描** | 扫描未读 Issue,按类型智能分类(Bug/Feature/Question/文档) | -| ✍️ **智能回复** | 基于模板自动起草回复,支持流转状态、打标签 | -| 📋 **PR 审查** | 按规则审查 PR 标题格式、改动影响、敏感信息、工作流对齐 | -| 📦 **版本管理** | 自动生成 Release Notes,基于 Conventional Commits 计算版本号 | -| 🧹 **过期清理** | 扫描过期 Issue/PR,起草关闭或提醒回复 | -| 📊 **运营报告** | 生成统计报告:新建/关闭趋势、响应时间、活跃贡献者排行 | -| ⚙️ **自动化配置** | 生成 GitHub Actions 工作流,配置 Issue 自动管理 | +### 它解决什么问题 ---- +项目发布只是开始。维护者还要反复查看 Issue、确认重复问题、审查 PR、跟踪 CI、整理版本说明和处理长期无响应内容。GitHub OSS Ops 把这些步骤组织成可复核的工作流,同时保留人的最终决定权。 -## 🚀 快速开始 +| 工作流 | Skill 会做什么 | 默认边界 | +| --- | --- | --- | +| Issue 分流 | 聚合新 Issue、判断类型/优先级/重复项、起草回复 | 读取可直接进行;评论、标签和关闭需批准 | +| PR 辅助审查 | 汇总 diff、CI、风险、测试和发布影响 | 不伪装成人工审查,不在未批准时提交 Review | +| Release 管理 | 根据已合并改动建议 SemVer、生成说明、核对版本一致性 | Tag、Release 和推送分别确认 | +| Stale 管理 | 识别长期无响应内容并提出分批处理建议 | 不自动批量关闭 | +| 运营报告 | 输出响应时间、积压、合并和版本节奏 | 区分事实、推断与建议 | -这是一个 AI Agent Skill,安装到任意 AI 编程助手后即可使用。 +### 三个可复核示例 -### 怎么用 +仓库包含三个完整示例,展示输入、只读分析、批准点与预期输出: -安装后直接告诉 AI 助手你的需求: +1. [新 Issue 分流与重复检测](examples/README.md#示例一新-issue-分流) +2. [PR 风险审查与 CI 诊断](examples/README.md#示例二pr-风险审查) +3. [周报与 Release 草稿](examples/README.md#示例三周报与-release-草稿) -- "看看这个仓库有什么新 Issue?" -- "帮我审查这个 PR" -- "这个 Issue 该怎么回复?" -- "生成这周的运营报告" -- "帮我管理过期 Issue" +### 安装为 Agent Skill -每个操作都会先生成草稿展示给你确认,明确同意后才执行。 +必须保留完整仓库结构;`SKILL.md` 会引用 `references/`。 ---- +| 平台 | 用户级安装 | 调用方式 | +| --- | --- | --- | +| ChatGPT(Codex 模式)/ Codex CLI | `git clone https://github.com/hyt315/github-oss-ops.git ~/.agents/skills/github-oss-ops` | 提示词中使用 `$github-oss-ops`,或通过 `/skills` 选择 | +| Claude Code | `git clone https://github.com/hyt315/github-oss-ops.git ~/.claude/skills/github-oss-ops` | 要求 Claude 使用 `github-oss-ops` skill | +| Cursor | `git clone https://github.com/hyt315/github-oss-ops.git ~/.cursor/skills/github-oss-ops` | 要求 Cursor Agent 使用 `github-oss-ops` skill | -## 📥 安装 / Installation +项目级安装可分别使用 `.agents/skills/github-oss-ops`、`.claude/skills/github-oss-ops` 或 `.cursor/skills/github-oss-ops`。新安装没有被发现时,重启对应 Agent。 -| 平台 | 安装命令 | -|------|----------| -| **Claude Code** | `git clone https://github.com/hyt315/github-oss-ops.git ~/.claude/skills/github-oss-ops` | -| **Codex** | `git clone https://github.com/hyt315/github-oss-ops.git ~/.codex/skills/github-oss-ops` | -| **Cursor** | `git clone https://github.com/hyt315/github-oss-ops.git ~/.cursor/skills/github-oss-ops` | +Windows PowerShell: -> 安装后 Skill 自动生效,无需额外配置。需要 GitHub 访问权限(PAT 或 MCP),首次使用时 Skill 会自动引导配置。 - ---- - -## 📥 下载 / Download - -| 方式 | 命令 / 链接 | -|------|------------| -| **HTTPS** | `git clone https://github.com/hyt315/github-oss-ops.git` | -| **SSH** | `git clone git@github.com:hyt315/github-oss-ops.git` | -| **GitHub CLI** | `gh repo clone hyt315/github-oss-ops` | -| **ZIP 源码** | [下载 ZIP](https://github.com/hyt315/github-oss-ops/archive/refs/heads/main.zip) | -| **Tar 源码** | [下载 Tar](https://github.com/hyt315/github-oss-ops/archive/refs/heads/main.tar.gz) | +```powershell +git clone https://github.com/hyt315/github-oss-ops.git "$HOME\.agents\skills\github-oss-ops" +``` ---- +### 下载 -## 💡 核心理念 +```bash +# HTTPS +git clone https://github.com/hyt315/github-oss-ops.git -- **只起草,不发送**:所有操作都先生成草稿展示给你,确认后才执行 -- **渐进式运营**:不需要一次配置全部,按需使用各功能模块 -- **维护者视角**:帮助个人维护者或小型团队降低维护负担 +# SSH +git clone git@github.com:hyt315/github-oss-ops.git ---- +# GitHub CLI +gh repo clone hyt315/github-oss-ops -## 📁 文件结构 +# main 分支 ZIP +curl -L https://github.com/hyt315/github-oss-ops/archive/refs/heads/main.zip -o github-oss-ops-main.zip -``` -github-oss-ops/ -├── SKILL.md # Skill 核心定义 -├── README.md # 本文件 -├── LICENSE # MIT 协议 -├── .gitignore # Git 忽略规则 -├── CONTRIBUTING.md # 贡献指南 -├── CODE_OF_CONDUCT.md # 行为准则 -├── SECURITY.md # 安全策略 -├── .github/ -│ ├── pull_request_template.md # PR 模板 -│ └── ISSUE_TEMPLATE/ -│ ├── bug_report.yml # Bug 报告表单 -│ ├── feature_request.yml # 功能建议表单 -│ └── doc_improvement.yml # 文档改进表单 -└── references/ # 参考文件 - ├── automation-templates.md # 自动化配置模板 - ├── github-access-guide.md # GitHub 访问指南 - ├── triage-workflow.md # Issue 分流工作流 - ├── response-templates.md # 回复模板库 - ├── pr-review-guide.md # PR 审查指南 - └── release-workflow.md # 发版工作流 +# 只查看技能合同(单文件不是完整安装) +curl -L https://raw.githubusercontent.com/hyt315/github-oss-ops/main/SKILL.md -o SKILL.md ``` ---- +浏览器入口:[最新 Release](https://github.com/hyt315/github-oss-ops/releases/latest) · [main ZIP](https://github.com/hyt315/github-oss-ops/archive/refs/heads/main.zip) -## 🤝 贡献 +### 五分钟开始 -请参阅 [CONTRIBUTING.md](CONTRIBUTING.md)。 +安装后可以直接说: ---- - -## 📄 许可 +```text +使用 $github-oss-ops 扫描 hyt315/notebook-video 最近 7 天的 Issue、PR 和 CI。 +先做只读分析,给出需要关注的项目和回复草稿;未经我确认不要评论、打标签、关闭、合并或发布。 +``` -[MIT](LICENSE) +公开仓库的只读分析不需要 Token。需要写入 GitHub 时,优先使用平台官方 GitHub 连接、GitHub 官方 MCP 的 OAuth,或已登录的 `gh`;再考虑最小权限、限定仓库、设置有效期的 fine-grained PAT。 ---- +Skill 不会要求你把 Token 发到聊天中,不会扫描用户主目录寻找凭据,也不会打印或写入 Token。完整认证与故障排查见 [references/github-access-guide.md](references/github-access-guide.md)。 -## English +### 安全模型 -## 📖 What is this? +- 只读扫描、分类和草稿生成可以直接执行。 +- 评论、标签、指派、关闭、合并、推送、规则修改和 Release 都是外部写操作,必须在目标与内容明确后获得批准。 +- 安全漏洞只进入 GitHub Private Vulnerability Reporting 等私密渠道。 +- 批量操作先小批预览,并设置上限;不自动关闭、不自动合并。 +- 所有统计报告标注时间窗口,不把缺失数据写成事实。 -**GitHub OSS Ops** is an AI Agent Skill for day-to-day open-source repository maintenance. It automates Issue triage, drafts replies, assists with PR reviews, manages releases, handles stale items, and generates operations reports. +### 仓库结构与验证 -> 💡 Works alongside [github-oss-prep](https://github.com/hyt315/github-oss-prep): oss-prep handles project launch prep, this skill handles post-launch operations. +- `SKILL.md`:主工作流与批准边界。 +- `references/`:分流、回复、PR、Release、认证和自动化参考。 +- `examples/`:三个端到端输出示例。 +- `scripts/validate-skill.mjs`:结构、链接、版本和隐私静态检查。 +- `.github/workflows/validate.yml`:PR 与主分支 CI。 -### ✨ Core Features - -| Module | Description | -|--------|-------------| -| 🔍 **Issue Scanning** | Scan unread Issues, auto-classify by type (Bug/Feature/Question/Docs) | -| ✍️ **Smart Replies** | Draft context-aware replies based on templates with status/label suggestions | -| 📋 **PR Review** | Rule-based PR review: title format, impact, sensitive info, workflow alignment | -| 📦 **Release Management** | Auto-generate release notes, calculate Semantic Version from Conventional Commits | -| 🧹 **Stale Cleanup** | Scan stale Issues/PRs, draft close or reminder replies | -| 📊 **Ops Reports** | Generate stats: open/close trends, response times, active contributors | -| ⚙️ **Automation Setup** | Generate GitHub Actions workflows for automated Issue management | +```bash +node scripts/validate-skill.mjs +``` ---- +### 许可证与贡献 -## 🚀 Quick Start +项目使用 [MIT License](LICENSE)。参与前请阅读 [CONTRIBUTING.md](CONTRIBUTING.md)、[CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)、[SECURITY.md](SECURITY.md) 和 [CONTRIBUTORS.md](CONTRIBUTORS.md)。 -This is an AI Agent Skill — install it in any AI coding assistant and it's ready to use. +## English -### How to use +GitHub OSS Ops is an approval-gated Agent Skill for maintainers who need repeatable Issue triage, PR review assistance, release preparation, stale-item review and repository health reporting. -Once installed, simply tell your AI assistant what you need: +### Key behavior -- "Check for new Issues in this repo" -- "Review this PR for me" -- "How should I reply to this Issue?" -- "Generate this week's operations report" -- "Help me clean up stale Issues" +- Public read-only analysis works without credentials. +- The skill drafts before it comments, labels, closes, merges, pushes or releases. +- Authentication prefers an official GitHub connection or OAuth, then an authenticated GitHub CLI, then a repository-scoped fine-grained PAT. +- It never searches a home directory for credentials, prints tokens or asks users to paste secrets into chat. +- Three inspectable workflows live in [examples/README.md](examples/README.md). -Every action drafts first, shows you for review, then executes only after your approval. +### Install ---- +```bash +# Codex / ChatGPT Codex mode +git clone https://github.com/hyt315/github-oss-ops.git ~/.agents/skills/github-oss-ops -## 📁 File Structure +# Claude Code +git clone https://github.com/hyt315/github-oss-ops.git ~/.claude/skills/github-oss-ops +# Cursor +git clone https://github.com/hyt315/github-oss-ops.git ~/.cursor/skills/github-oss-ops ``` -github-oss-ops/ -├── SKILL.md # Core skill definition -├── README.md # This file -├── LICENSE # MIT License -├── .gitignore # Git ignore rules -├── CONTRIBUTING.md # Contribution guide -├── CODE_OF_CONDUCT.md # Code of conduct -├── SECURITY.md # Security policy -├── .github/ -│ ├── pull_request_template.md # PR template -│ └── ISSUE_TEMPLATE/ -│ ├── bug_report.yml # Bug report form -│ ├── feature_request.yml # Feature request form -│ └── doc_improvement.yml # Docs improvement form -└── references/ # Reference documents (6 files) -``` - ---- - -## 🤝 Contributing - -See [CONTRIBUTING.md](CONTRIBUTING.md). ---- +Validate with `node scripts/validate-skill.mjs`. See the Chinese section above for download methods, operating boundaries and the repository map. -## 📄 License +### Sources -[MIT](LICENSE) +The authentication and tool guidance follows the [official GitHub MCP Server](https://github.com/github/github-mcp-server) and GitHub's documentation for [fine-grained personal access tokens](https://docs.github.com/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens), [repository topics](https://docs.github.com/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/classifying-your-repository-with-topics) and [private vulnerability reporting](https://docs.github.com/code-security/security-advisories/working-with-repository-security-advisories/configuring-private-vulnerability-reporting-for-a-repository). diff --git a/SECURITY.md b/SECURITY.md index f9fb15d..735e06c 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,24 +1,23 @@ -# 安全策略 / Security Policy +# Security Policy -## 报告漏洞 / Reporting a Vulnerability +## Reporting a vulnerability -如果你发现安全漏洞,请通过以下方式报告: +Report vulnerabilities through [GitHub Private Vulnerability Reporting](https://github.com/hyt315/github-oss-ops/security/advisories/new). -If you discover a security vulnerability, please report it via: +Do not open a public Issue containing exploit details, credentials, private repository data or personal information. If Private Vulnerability Reporting is unavailable, open a public Issue that only asks the maintainer to enable a private channel; do not include sensitive details. -- **GitHub Issues**: [提交安全报告](https://github.com/hyt315/github-oss-ops/issues/new?template=bug_report.yml)(请勿公开敏感细节) -- **Private vulnerability reporting**: 本仓库已启用 GitHub 私密漏洞报告功能 +## Credential safety -我们将尽快确认并修复。 +GitHub OSS Ops must never: -We will acknowledge and address the report as quickly as possible. +- ask a user to paste a PAT, API key or password into chat; +- search a home directory, editor configuration, MCP configuration or shell history for credentials; +- print, log, commit or persist credentials in the skill directory; +- place credentials in a Git remote URL; +- request broader GitHub permissions than the approved operation requires. -## 支持版本 / Supported Versions +If a credential appears in chat, logs or a commit, stop the affected write operation, advise immediate revocation/rotation and verify the repository history before release. -| 版本 / Version | 支持状态 / Supported | -|---------------|:-------------------:| -| latest | ✅ | +## Supported versions -## 免责声明 / Disclaimer - -本 Skill 仅处理公开数据,不会收集或存储用户凭据。 +Only the latest published release is actively supported. diff --git a/SKILL.md b/SKILL.md index 6902406..ef5b238 100644 --- a/SKILL.md +++ b/SKILL.md @@ -1,7 +1,7 @@ --- name: github-oss-ops -version: 1.0.2 -description: Use when managing open source GitHub repositories — covers Issue triage, smart replies, PR review assistance, version/release management, stale management, and operations reporting. Triggers: Issue 管理、分流、triage、看看有没有新 Issue、PR 审查、回复 Issue、版本号、发版、Release、changelog、过期 Issue、stale、运营报告、开源项目运营、oss ops、project operations. +version: 1.1.0 +description: Use when maintaining an open-source GitHub repository after launch, including Issue triage, reply drafting, PR review assistance, CI diagnosis, release preparation, stale-item review, repository health reporting, and approval-gated GitHub writes. Triggers include Issue 管理、分流、triage、PR 审查、回复 Issue、版本号、发版、Release、changelog、过期 Issue、stale、运营报告、开源项目运营、oss ops, and project operations. --- # GitHub 开源项目运营 @@ -10,30 +10,30 @@ description: Use when managing open source GitHub repositories — covers Issue ## 核心理念 -- **只起草,不发送**:所有回复和标签操作都先展示给用户确认,明确同意才执行 +- **读写分离**:公开信息读取、分析和草稿可直接进行;评论、标签、关闭、合并、推送、设置和发布等外部写操作必须明确目标与内容,并在执行前获得批准 - **维护者视角**:帮助个人维护者或小型团队高效管理项目,降低维护负担 - **渐进式运营**:不需要一次配置全部,按需使用各功能模块 - **与 github-oss-prep 配合**:oss-prep 负责发布,本技能负责发布后的日常运营 +- **凭据零采集**:不要求用户把 Token 发到聊天,不搜索用户目录或配置文件提取凭据,不打印、记录或写入凭据 +- **能力发现优先**:根据当前平台实际提供的 GitHub 连接、MCP、CLI 或 API 能力选择路径,不假定某个工具名永久存在 --- ## 前置条件 -需要 GitHub 访问凭据(三选一): +公开仓库的只读扫描不要求认证。只有读取私有数据或执行写操作时才需要 GitHub 授权。 -1. **GitHub PAT**(推荐 Fine-grained PAT,Classic PAT 亦可) - - Fine-grained PAT(`github_pat_` 前缀):可限定仓库和权限,更安全 - - Classic PAT(`ghp_` 前缀):需 `repo` 权限,配置最简单 -2. **GitHub MCP 工具**(推荐):官方 `github/github-mcp-server`,通过 Docker 运行 - - 可用工具:`list_issues`、`issue_read`、`issue_write`、`add_issue_comment` 等 -3. **GitHub CLI(`gh`)**:安装 `gh` 并执行 `gh auth login`,适合交互式操作 -4. **curl + REST API**:以上均不可用时的回退方案 +按以下优先级使用当前环境已经提供的能力: -配置方式(PAT): -- 环境变量:设置 `GITHUB_TOKEN` 或 `GITHUB_PERSONAL_ACCESS_TOKEN` -- MCP Server 配置文件:将 PAT 填入对应工具的 `env` 中 +1. **平台官方 GitHub 连接器或 GitHub 官方远程 MCP(OAuth)**:由受信任界面完成授权。 +2. **已认证的 GitHub CLI**:先运行 `gh auth status`;未登录时让用户在受信任终端完成 `gh auth login --web`。 +3. **GitHub 官方本地 MCP Server**:适合需要本地宿主或受控 toolsets 的环境。 +4. **Fine-grained PAT**:仅在用户明确选择时使用,限定仓库、最小权限并设置有效期,由受信任的密码输入或环境管理接收。 +5. **公开 REST API / 网页**:作为只读或人工交接回退。 -详细的 PAT 生成步骤(含 Fine-grained PAT)、各工具 MCP 配置模板、GitHub CLI 用法、MCP 工具清单和 curl + REST API 回退方案,参见 [references/github-access-guide.md](references/github-access-guide.md)。 +不得从用户主目录、编辑器配置、MCP JSON、Shell 历史或进程环境中主动寻找 Token;不得输出 Token 值。不得把 Classic PAT 描述为默认或最简单的推荐方案。 + +授权方式、最小权限、能力探测和回退流程见 [references/github-access-guide.md](references/github-access-guide.md)。 --- @@ -71,7 +71,7 @@ Step 9: 自动化配置(按需生成 GitHub Actions 模板) 2. 如果是,提取 `owner/repo` 信息 3. 如果不是,询问用户要管理哪个仓库 -确认仓库后,检查仓库是否为公开仓库(本技能面向开源项目)。 +确认仓库后,记录 `owner/repo`、默认分支、可见性和当前用户权限。若是公开仓库,先完成无需认证的只读工作;若是私有仓库,说明本技能仍可使用,但它不属于公开开源运营场景,且必须通过受信任连接获得授权。 --- @@ -500,8 +500,8 @@ Step 9: 自动化配置(按需生成 GitHub Actions 模板) | 没有未关闭的 Issue | 输出"一切正常",不生成多余报告 | | Issue 数量超过 100 | 分批处理,优先处理最近的 | | API 速率限制 | 等待或提示用户稍后重试(已认证 5000 次/小时,未认证 60 次/小时) | -| MCP 工具不可用 | 回退到 GitHub CLI(`gh`)或 curl + REST API | -| Docker 未运行 | MCP Server 无法启动,提示用户启动 Docker 或使用 `gh` CLI / curl 回退方案 | +| MCP 工具不可用 | 继续完成公开只读分析;写操作回退到已认证的 `gh`、受信任连接或人工交接 | +| Docker 未运行 | 优先使用官方远程 MCP/OAuth、`gh` 或网页,不把 Docker 作为阻塞条件 | | Windows PowerShell 环境 | curl 示例中 `$GITHUB_TOKEN` 需改为 `$env:GITHUB_TOKEN`,行续接符 `\` 改为 `` ` `` | | Fine-grained PAT 权限不足 | 提示用户检查 PAT 的仓库范围和权限级别(Issues/PR 需 Read and write) | | 用户取消操作 | 不执行任何已准备好的操作 | diff --git a/agents/openai.yaml b/agents/openai.yaml new file mode 100644 index 0000000..a779b2a --- /dev/null +++ b/agents/openai.yaml @@ -0,0 +1,10 @@ +interface: + display_name: GitHub OSS Ops + short_description: Operate open-source GitHub repositories with approval-gated workflows + default_prompt: Use $github-oss-ops to scan this repository, draft a prioritized maintenance plan, and request approval before any external write. +policy: + products: + - chatgpt + - codex + - api + allow_implicit_invocation: true diff --git a/assets/social-preview.png b/assets/social-preview.png new file mode 100644 index 0000000000000000000000000000000000000000..4b0f17438ef4ca5ccc0769518cbbd37298eba71e GIT binary patch literal 93083 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

+yXa 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 z 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 + + + + + + + + + + + + + + + AGENT SKILL · MAINTAINER WORKFLOW + GitHub OSS Ops + Triage, review, release and report — with approval before every write. + + + + + SCAN + Issues · PRs · CI + + + + + TRIAGE + Risk · Priority + + + + + DRAFT + Reply · Review + + + + + APPROVE + Human checkpoint + + + + + ACT + Write · Release + + + + + REPORT + Health · Follow-up + + + + + READ WITHOUT CREDENTIALS + · + WRITE ONLY AFTER APPROVAL + diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..a1b65f8 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,70 @@ +# GitHub OSS Ops examples + +These examples make the skill's output and approval boundaries inspectable before installation. Repository names and issue text are illustrative; the workflow and fields are the enforced contract. + +## 示例一:新 Issue 分流 + +**Prompt** + +```text +扫描 owner/repo 最近 7 天的新 Issue。识别重复项、类型、优先级和需要补充的信息。先给草稿,不要写入 GitHub。 +``` + +**Expected read-only output** + +```text +时间窗口:2026-07-11 至 2026-07-18 +Issue #42 — Windows 渲染失败 +分类:type:bug / priority:high +证据:包含可复现命令;CI 中 Windows job 同类失败 +可能重复:#37(相同错误码,仍需维护者确认) +建议:请求系统版本和最小复现仓库 +草稿:感谢反馈。为了确认是否与 #37 相同,请补充…… + +待批准写操作:添加 type:bug、priority:high;发送上述评论。 +``` + +只有用户确认具体 Issue、标签和评论内容后,才执行写操作。 + +## 示例二:PR 风险审查 + +**Prompt** + +```text +审查 PR #57。检查改动范围、测试、敏感信息、CI、兼容性和发布影响,不要提交 Review 或合并。 +``` + +**Expected output** + +```text +结论:Request changes(草稿) +高风险:工作流从 pull_request 改为 pull_request_target,并读取 PR 分支脚本 +中风险:新增依赖未更新锁文件 +已通过:单元测试、格式检查 +缺失:威胁说明、最小权限 permissions +建议 Review:请恢复 pull_request,或说明为何必须使用 pull_request_target…… + +待批准写操作:提交 Request changes Review。 +``` + +## 示例三:周报与 Release 草稿 + +**Prompt** + +```text +生成本周运营报告,并根据 v1.2.0 之后已合并 PR 起草下一版 Release。不要创建 Tag 或 Release。 +``` + +**Expected output** + +```text +统计窗口:2026-07-11 00:00Z 至 2026-07-18 00:00Z +新 Issue 8 / 关闭 6 / 净增加 2 +新 PR 5 / 合并 4 / 关闭未合并 1 +首次响应中位数:9.4 小时(样本 7) +建议版本:v1.3.0 +依据:2 个向后兼容功能、3 个修复、1 个文档更新 +Release 草稿:Added … / Fixed … / Documentation … + +待批准写操作:版本文件 PR、Tag、GitHub Release(分别确认)。 +``` diff --git a/references/automation-templates.md b/references/automation-templates.md index 8ead3bf..940ccca 100644 --- a/references/automation-templates.md +++ b/references/automation-templates.md @@ -38,7 +38,7 @@ jobs: stale: runs-on: ubuntu-latest steps: - - uses: actions/stale@v10 + - uses: actions/stale@1e223db275d687790206a7acac4d1a11bd6fe629 # v10 with: # Issue 配置 days-before-issue-stale: 30 # 30 天无活动标记 stale @@ -126,7 +126,7 @@ jobs: label: runs-on: ubuntu-latest steps: - - uses: github/issue-labeler@v3.4 + - uses: github/issue-labeler@c1b0f9f52a63158c4adc09425e858e87b32e9685 # v3.4 with: configuration-path: .github/labeler.yml enable-versioned-regex: 0 @@ -160,7 +160,7 @@ jobs: welcome: runs-on: ubuntu-latest steps: - - uses: actions/first-interaction@v3 + - uses: actions/first-interaction@1c4688942c71f71d4f5502a26ea67c331730fa4d # v3 with: issue_message: | ## Welcome! 👋 @@ -169,7 +169,7 @@ jobs: A few tips: - Please make sure you've searched existing issues to avoid duplicates - - Check [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines + - Check [CONTRIBUTING.md](https://github.com/${{ github.repository }}/blob/${{ github.event.repository.default_branch }}/CONTRIBUTING.md) for guidelines - Be patient — maintainers will review your issue as soon as possible We appreciate your contribution! @@ -224,7 +224,7 @@ jobs: assign: runs-on: ubuntu-latest steps: - - uses: pozil/auto-assign-issue@v4 + - uses: pozil/auto-assign-issue@af6beea6bdf1e8eb373f061c5bc168681fc6d011 # v4.0.1 with: repo-token: ${{ secrets.GITHUB_TOKEN }} assignees: your-github-username # 替换为你的 GitHub 用户名 @@ -236,7 +236,7 @@ jobs: 如果有多个维护者,可以用轮询(round-robin)方式分配: ```yaml - - uses: pozil/auto-assign-issue@v4 + - uses: pozil/auto-assign-issue@af6beea6bdf1e8eb373f061c5bc168681fc6d011 # v4.0.1 with: repo-token: ${{ secrets.GITHUB_TOKEN }} assignees: user1, user2, user3 @@ -269,7 +269,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check issue health - uses: actions/github-script@v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | const { data: issues } = await github.rest.issues.listForRepo({ diff --git a/references/github-access-guide.md b/references/github-access-guide.md index a325bfb..cc95d8f 100644 --- a/references/github-access-guide.md +++ b/references/github-access-guide.md @@ -1,550 +1,119 @@ -# GitHub 访问配置指南 +# GitHub access guide -> 本技能需要 GitHub 访问凭据才能操作 Issue 和 PR。本文件说明如何获取和配置。 +This guide defines how GitHub OSS Ops selects an access path without collecting credentials. ---- +## Decision order -## 目录 +### 1. Public read-only work -- [什么是 PAT](#什么是-pat) -- [第一步:生成 PAT](#第一步生成-pat) -- [第二步:配置到 MCP Server](#第二步配置到-mcp-server) -- [第三步:验证](#第三步验证) -- [GitHub CLI(gh)方式](#github-cligh-方式) -- [Token 自动发现策略](#token-自动发现策略) -- [MCP 工具清单](#mcp-工具清单) -- [curl + REST API 回退方案](#curl--rest-api-回退方案) -- [常见问题](#常见问题) +Public repository metadata, files, Issues, PRs, releases and Actions status can usually be read without authentication. Complete all useful read-only analysis first. Authentication failure must not block an offline draft or manual handoff. ---- +### 2. Official GitHub connection or remote MCP -## 什么是 PAT +Prefer a platform-provided GitHub connector or the [official GitHub MCP Server](https://github.com/github/github-mcp-server). The hosted remote server supports OAuth in compatible hosts and avoids manually handling a PAT. -PAT(Personal Access Token)是 GitHub 的个人访问令牌,用于 API 认证。GitHub 提供两种: +Do not assume fixed tool names. Inspect the capabilities exposed by the current host, then map the operation by purpose: -- **Classic PAT**(`ghp_` 前缀):传统令牌,通过 scope 授权,权限范围较宽 -- **Fine-grained PAT**(`github_pat_` 前缀):细粒度令牌,可限定到特定仓库,更安全但配置更复杂 +| Purpose | Typical capability | +| --- | --- | +| Repository files and metadata | repository/file read | +| Issue list, details and comments | issue read/list | +| Issue labels, state and comments | issue write/comment | +| PR diff, checks, reviews and merge | pull-request read/write/review | +| Workflow runs and logs | Actions list/get | +| Tags and releases | release/tag API, GitHub CLI or REST fallback | -### 如何选择 +The official MCP Server supports toolsets and individual-tool allow-lists. Enable only the groups needed for the task; read-only mode is appropriate for audits. -| 特性 | Classic PAT | Fine-grained PAT | -|------|-------------|------------------| -| 权限粒度 | 按 scope(如 `repo`) | 按仓库 + 按权限(如 `Issues: Write`) | -| 仓库范围 | 所有可访问仓库 | 可限定到特定仓库 | -| 安全性 | 较低(泄露即全仓库) | 较高(泄露仅限授权仓库) | -| 过期时间 | 可设 No expiration | 必须设过期时间(最长 1 年) | -| 配置难度 | 简单(勾选 `repo`) | 稍复杂(逐项选择权限) | -| GitHub 推荐 | 兼容性最好 | **推荐用于生产环境** | +### 3. GitHub CLI -**本技能推荐**:个人项目用 Classic PAT(配置最简单),正式维护的开源项目用 Fine-grained PAT(更安全)。 - ---- - -## 第一步:生成 PAT - -### 方式 A:生成 Classic PAT(简单) - -1. 打开 https://github.com/settings/tokens/new - -2. 点击 **Generate new token (classic)** - -3. 填写: - - **Note**:`github-oss-ops`(备注名称,随意) - - **Expiration**:选择过期时间(建议 90 天,不建议 No expiration) - - **Select scopes**:勾选 `repo`(完整仓库访问权限) - -4. 点击 **Generate token** - -5. **立即复制 token**(`ghp_` 开头的字符串),页面刷新后无法再次查看 - -### 方式 B:生成 Fine-grained PAT(更安全) - -1. 打开 https://github.com/settings/personal-access-tokens/new - -2. 填写: - - **Token name**:`github-oss-ops` - - **Expiration**:建议 90 天(最长 1 年,到期需重新生成) - - **Repository access**:选择 **Only select repositories**,勾选要管理的仓库 - -3. 在 **Repository permissions** 中,按需勾选以下权限: - - | 权限 | 级别 | 用途 | - |------|------|------| - | Issues | Read and write | Issue 管理(读取、更新、评论) | - | Pull requests | Read and write | PR 管理(读取、审查、合并) | - | Metadata | Read-only | 仓库基本信息(必选) | - | Labels | Read and write | 标签管理 | - | Contents | Read-only | 读取文件(PR 改动分析) | - | Commit statuses | Read-only | CI/CD 状态检查 | - | Members | Read-only | 贡献者信息 | - -4. 点击 **Generate token** - -5. **立即复制 token**(`github_pat_` 开头的字符串) - ---- - -## 第二步:配置到 MCP Server - -GitHub 官方 MCP Server(`github/github-mcp-server`)提供两种部署方式: - -- **远程服务器**(推荐):GitHub 托管,通过 OAuth 认证,无需 Docker -- **本地服务器**:通过 Docker 运行,使用 PAT 认证 - -> **重要**:旧的 `@modelcontextprotocol/server-github`(npx 方式)已不再维护,请迁移至官方 `github/github-mcp-server`。下方配置均使用官方版本。 - -### 前置条件(本地服务器方式) - -- 安装 [Docker](https://www.docker.com/) 并确保 Docker 正在运行 -- Docker 镜像:`ghcr.io/github/github-mcp-server`(公开镜像,无需登录) - -### Cursor - -编辑 `~/.cursor/mcp.json`: - -```json -{ - "mcpServers": { - "github": { - "command": "docker", - "args": [ - "run", "-i", "--rm", - "-e", "GITHUB_PERSONAL_ACCESS_TOKEN", - "ghcr.io/github/github-mcp-server" - ], - "env": { - "GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_你的token" - } - } - } -} -``` - -### Claude Desktop - -编辑配置文件: -- macOS:`~/Library/Application Support/Claude/claude_desktop_config.json` -- Windows:`%APPDATA%\Claude\claude_desktop_config.json` - -```json -{ - "mcpServers": { - "github": { - "command": "docker", - "args": [ - "run", "-i", "--rm", - "-e", "GITHUB_PERSONAL_ACCESS_TOKEN", - "ghcr.io/github/github-mcp-server" - ], - "env": { - "GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_你的token" - } - } - } -} -``` - -### Windsurf - -编辑 `~/.codeium/mcp_config.json`: - -```json -{ - "mcpServers": { - "github": { - "command": "docker", - "args": [ - "run", "-i", "--rm", - "-e", "GITHUB_PERSONAL_ACCESS_TOKEN", - "ghcr.io/github/github-mcp-server" - ], - "env": { - "GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_你的token" - } - } - } -} -``` - -> 注意:Windsurf 可能不支持环境变量引用,需要直接在 `env` 中硬编码 token。 - -### VS Code / GitHub Copilot - -在项目根目录创建或编辑 `.vscode/mcp.json`: - -```json -{ - "inputs": [ - { - "type": "promptString", - "id": "github_token", - "description": "GitHub Personal Access Token", - "password": true - } - ], - "servers": { - "github": { - "command": "docker", - "args": [ - "run", "-i", "--rm", - "-e", "GITHUB_PERSONAL_ACCESS_TOKEN", - "ghcr.io/github/github-mcp-server" - ], - "env": { - "GITHUB_PERSONAL_ACCESS_TOKEN": "${input:github_token}" - } - } - } -} -``` - -> 注意:VS Code 使用 `servers` 而非 `mcpServers` 作为顶层键名。`${input:github_token}` 方式会在首次使用时弹窗输入 token,避免硬编码。 - -### 远程服务器方式(无需 Docker) - -如果你的 MCP 客户端支持远程 MCP 服务器(VS Code 1.101+、Claude Desktop、Cursor 等),可以直接使用 GitHub 托管的远程服务器,通过 OAuth 认证,无需 PAT 和 Docker: - -```json -{ - "servers": { - "github": { - "type": "http", - "url": "https://api.githubcopilot.com/mcp/" - } - } -} -``` - -首次使用时会弹出浏览器窗口完成 OAuth 授权。详见 [GitHub MCP Server 文档](https://github.com/github/github-mcp-server)。 - -### 通用方式(环境变量) - -如果不想使用 MCP,也可以直接设置环境变量,配合 GitHub CLI 或 curl 使用: - -```powershell -# Windows PowerShell -$env:GITHUB_TOKEN = "ghp_你的token" -``` - -```bash -# Linux / macOS -export GITHUB_TOKEN="ghp_你的token" -``` - ---- - -## 第三步:验证 - -### 验证 PAT - -```bash -# Linux / macOS -curl -sI -H "Authorization: token $GITHUB_TOKEN" \ - https://api.github.com/user -``` - -```powershell -# Windows PowerShell -curl -sI -H "Authorization: token $env:GITHUB_TOKEN" ` - https://api.github.com/user -``` - -响应头中 `x-oauth-scopes` 应包含 `repo`(Classic PAT),如: -``` -x-oauth-scopes: repo, workflow -``` - -> Fine-grained PAT 的响应头中 `x-oauth-scopes` 为空,需检查 `x-accepted-github-permissions` 确认权限。 - -### 验证 MCP Server - -启动 MCP 客户端后,尝试调用一个简单工具(如 `list_issues`),如果返回数据说明配置成功。如果报错,检查 Docker 是否运行、token 是否正确。 - ---- - -## GitHub CLI(gh)方式 - -除了 MCP 和 curl,GitHub 官方 CLI 工具 `gh` 是更便捷的替代方案,语法简洁且支持认证管理。 - -### 安装 - -| 平台 | 安装命令 | -|------|----------| -| Windows (winget) | `winget install GitHub.cli` | -| Windows (scoop) | `scoop install gh` | -| macOS (Homebrew) | `brew install gh` | -| Linux (apt) | `sudo apt install gh` | - -详见 https://cli.github.com/ - -### 认证 +Check authentication without exposing credentials: ```bash -# 交互式登录(推荐,支持浏览器 OAuth) -gh auth login - -# 使用 PAT 登录 -gh auth login --with-token < token.txt - -# 检查认证状态 gh auth status - -# 刷新权限(如需额外 scope) -gh auth refresh -s read:project ``` -### 常用 Issue 管理命令 +If authentication is missing, the user should complete the browser flow in a trusted terminal: ```bash -# 列出未关闭的 Issue -gh issue list --repo owner/repo --state open - -# 查看某个 Issue 详情 -gh issue view 123 --repo owner/repo - -# 创建 Issue -gh issue create --repo owner/repo --title "Bug: xxx" --body "描述" - -# 添加标签 -gh issue edit 123 --repo owner/repo --add-label "type:bug,priority:P1" - -# 添加评论 -gh issue comment 123 --repo owner/repo --body "回复内容" - -# 关闭 Issue -gh issue close 123 --repo owner/repo --comment "已修复" +gh auth login --web ``` -### 常用 PR 管理命令 +Useful commands: ```bash -# 列出未关闭的 PR -gh pr list --repo owner/repo --state open - -# 查看 PR 详情(含改动文件) -gh pr view 456 --repo owner/repo -gh pr diff 456 --repo owner/repo - -# 审查 PR -gh pr review 456 --repo owner/repo --approve --body "LGTM" -gh pr review 456 --repo owner/repo --request-changes --body "需要修改" - -# 合并 PR -gh pr merge 456 --repo owner/repo --squash --delete-branch +gh issue list --repo OWNER/REPO --state open +gh pr checks 42 --repo OWNER/REPO +gh pr view 42 --repo OWNER/REPO --json files,reviews,statusCheckRollup +gh release list --repo OWNER/REPO ``` -> `gh` CLI 适合交互式操作和简单脚本。批量操作和复杂逻辑建议使用 MCP 工具或 REST API。 - ---- +### 4. Fine-grained PAT -## Token 自动发现策略 +Use a PAT only when the user explicitly chooses it and no safer authorized connection is available. -技能运行时按以下优先级自动查找 Token: +- Prefer a fine-grained PAT over a classic PAT. +- Limit repository access to the target repository. +- Grant read-only permissions for audits. +- Add write permissions only for the approved operation. +- Set an expiration date and rotate on suspected exposure. +- Let a trusted password prompt, credential manager or environment manager receive it. -1. **环境变量**:读取 `GITHUB_TOKEN` 或 `GITHUB_PERSONAL_ACCESS_TOKEN` - - bash:`echo $GITHUB_TOKEN` - - PowerShell:`$env:GITHUB_TOKEN` +Never ask the user to paste it into chat. Never inspect configuration files to extract it. Never print it to confirm that it exists. -2. **MCP 配置文件**:在用户主目录下搜索包含 GitHub MCP 配置的 JSON 文件(深度 3 层) - - Windows:`Get-ChildItem -Path $HOME -Recurse -Depth 3 -Filter *.json` - - 匹配内容包含 `GITHUB_PERSONAL_ACCESS_TOKEN` 或 `mcpServers.*github` 的文件 +## Minimum-permission examples -3. **兜底路径**(自动发现失败时参考): - - | 路径 | 工具 | - |------|------| - | `~/.cursor/mcp.json` | Cursor | - | `%APPDATA%\Claude\claude_desktop_config.json` | Claude Desktop (Windows) | - | `~/.codeium/mcp_config.json` | Windsurf | - | `.vscode/mcp.json` | VS Code | - -找到配置文件后,解析 JSON 提取 Token: - -```python -import json -d = json.load(open("<配置文件路径>")) -for key in ('mcpServers', 'servers', 'mcp'): - servers = d.get(key, {}) - if 'github' in servers: - token = servers['github'].get('env', {}).get('GITHUB_PERSONAL_ACCESS_TOKEN', '') - if token: - print(token) - break -``` +| Operation | Repository permission | +| --- | --- | +| Read public Issues and PRs | none for public data; otherwise Issues/PR read | +| Comment or label an Issue | Issues read/write | +| Review or merge a PR | Pull requests read/write; Contents write may also be required | +| Read workflow results | Actions read | +| Create a Release | Contents write | +| Change repository settings | Administration write | -如所有方式都找不到,引导用户按上方步骤配置 PAT。 +Permission names and availability can vary by token type and repository ownership. Verify against GitHub's current authorization screen rather than copying a broad scope list. ---- +## REST fallback -## MCP 工具清单 - -本技能使用的 GitHub MCP 工具(基于官方 `github/github-mcp-server` 现行工具名): - -> 官方 server 已把多个读取类工具整合为「通用工具 + `method` 参数」:`issue_read` 取代旧的 `get_issue`;`pull_request_read` 取代 `get_pull_request` / `get_pull_request_files` / `get_pull_request_status` 等;`issue_write` 取代 `create_issue` / `update_issue`;`pull_request_review_write` 取代 `create_pull_request_review`。若你的 MCP 客户端只暴露实际工具列表,以其为准。 - -### Issue 操作 - -| 工具 | 功能 | 底层 API | -|------|------|----------| -| `list_issues` | 列出仓库的 Issue(支持过滤状态、标签) | `GET /repos/{owner}/{repo}/issues` | -| `issue_read`(method: `get`) | 获取单个 Issue 详情 | `GET /repos/{owner}/{repo}/issues/{number}` | -| `issue_write` | 创建或更新 Issue(标签、状态、指派人) | `POST` / `PATCH /repos/{owner}/{repo}/issues` | -| `add_issue_comment` | 添加 Issue 评论 | `POST /repos/{owner}/{repo}/issues/{number}/comments` | -| `search_issues` | 搜索 Issue | `GET /search/issues` | - -### PR 操作 - -| 工具 | 功能 | 底层 API | -|------|------|----------| -| `list_pull_requests` | 列出 PR | `GET /repos/{owner}/{repo}/pulls` | -| `pull_request_read`(method: `get`) | 获取 PR 详情 | `GET /repos/{owner}/{repo}/pulls/{number}` | -| `pull_request_read`(method: `get_files`) | 获取 PR 改动文件 | `GET /repos/{owner}/{repo}/pulls/{number}/files` | -| `pull_request_read`(method: `get_status`) | 获取 PR 检查状态 | `GET /repos/{owner}/{repo}/commits/{sha}/status` | -| `pull_request_read`(method: `get_comments`) | 获取 PR 评论 | `GET /repos/{owner}/{repo}/pulls/{number}/comments` | -| `pull_request_read`(method: `get_reviews`) | 获取 PR 审查 | `GET /repos/{owner}/{repo}/pulls/{number}/reviews` | -| `pull_request_review_write` | 提交 PR 审查意见 | `POST /repos/{owner}/{repo}/pulls/{number}/reviews` | -| `merge_pull_request` | 合并 PR | `PUT /repos/{owner}/{repo}/pulls/{number}/merge` | - -### 其他 - -| 工具 | 功能 | -|------|------| -| `search_repositories` | 搜索仓库 | -| `get_file_contents` | 读取仓库文件 | -| `list_commits` | 列出提交历史 | -| `search_code` | 搜索代码 | -| `search_users` | 搜索用户 | - ---- - -## curl + REST API 回退方案 - -当 MCP 工具不可用时,通过 curl 直接调用 GitHub REST API: - -> **Windows PowerShell 用户注意**: -> - 环境变量引用:将 `$GITHUB_TOKEN` 替换为 `$env:GITHUB_TOKEN` -> - 行续接符:将 `\` 替换为 `` ` ``(反引号) -> - JSON 字符串:PowerShell 中单引号内的 JSON 不需要转义,但双引号内的需要 -> - 推荐使用 `gh` CLI 替代 curl,语法更简洁且跨平台 - -### 列出 Issue +Use the current `Bearer` authorization form when an already-provisioned environment variable is available through a trusted runtime: ```bash -# Linux / macOS -curl -s -H "Authorization: token $GITHUB_TOKEN" \ +curl --fail-with-body \ + -H "Authorization: Bearer $GITHUB_TOKEN" \ -H "Accept: application/vnd.github+json" \ - "https://api.github.com/repos///issues?state=open&per_page=100" + -H "X-GitHub-Api-Version: 2022-11-28" \ + https://api.github.com/repos/OWNER/REPO ``` -```powershell -# Windows PowerShell -curl -s -H "Authorization: token $env:GITHUB_TOKEN" ` - -H "Accept: application/vnd.github+json" ` - "https://api.github.com/repos///issues?state=open&per_page=100" -``` +Do not run commands that echo the variable. Do not embed credentials in the URL. Redact request headers from debugging logs. -### 获取 Issue 详情 +## Approval boundary -```bash -curl -s -H "Authorization: token $GITHUB_TOKEN" \ - "https://api.github.com/repos///issues/" -``` +Read-only calls can proceed when they are within the repository the user placed in scope. Before a write, show: -### 添加 Issue 评论 +1. repository and exact target; +2. proposed content or state change; +3. whether it is reversible; +4. expected follow-up, such as CI or notification effects. -```bash -curl -s -X POST -H "Authorization: token $GITHUB_TOKEN" \ - -H "Accept: application/vnd.github+json" \ - "https://api.github.com/repos///issues//comments" \ - -d '{"body":"评论内容"}' -``` - -### 更新 Issue(添加标签) - -```bash -curl -s -X PATCH -H "Authorization: token $GITHUB_TOKEN" \ - -H "Accept: application/vnd.github+json" \ - "https://api.github.com/repos///issues/" \ - -d '{"labels":["type:bug","priority:P1"]}' -``` - -### 列出 PR - -```bash -curl -s -H "Authorization: token $GITHUB_TOKEN" \ - "https://api.github.com/repos///pulls?state=open" -``` - -### 获取 PR 改动文件 - -```bash -curl -s -H "Authorization: token $GITHUB_TOKEN" \ - "https://api.github.com/repos///pulls//files" -``` +Approval for one comment does not authorize closing an Issue, merging a PR, publishing a Release or changing repository settings. -### 提交 PR 审查 +## Failure handling -```bash -curl -s -X POST -H "Authorization: token $GITHUB_TOKEN" \ - -H "Accept: application/vnd.github+json" \ - "https://api.github.com/repos///pulls//reviews" \ - -d '{"body":"审查意见","event":"COMMENT"}' -``` - -> `event` 可选值:`APPROVE`(批准)、`REQUEST_CHANGES`(需要修改)、`COMMENT`(仅评论) - -### 列出标签 - -```bash -curl -s -H "Authorization: token $GITHUB_TOKEN" \ - "https://api.github.com/repos///labels" -``` +| Failure | Response | +| --- | --- | +| Public API rate limit | Continue with cloned files/local Git data; report freshness limits | +| Authentication missing | Finish read-only/offline work; request trusted authorization only for the blocked write | +| 401 | Do not retry repeatedly; verify auth state and rotate only if the credential is invalid | +| 403 | Check repository selection and minimum permission for the exact operation | +| 404 on a private repository | Treat as possible permission failure without revealing repository existence | +| Connector or MCP unavailable | Use `gh`, public API or manual handoff; do not install an unofficial abandoned server | +| Credential exposed | Stop, revoke/rotate, scan Git history and remove the value before continuing | -### 创建标签 - -```bash -curl -s -X POST -H "Authorization: token $GITHUB_TOKEN" \ - -H "Accept: application/vnd.github+json" \ - "https://api.github.com/repos///labels" \ - -d '{"name":"type:bug","color":"d73a4a","description":"Confirmed bug"}' -``` - -### 搜索 Issue - -```bash -curl -s -H "Authorization: token $GITHUB_TOKEN" \ - "https://api.github.com/search/issues?q=repo:/+is:issue+is:open+关键词" -``` +## Authoritative references -### API 速率限制 - -- 已认证请求:5000 次/小时 -- 未认证请求:60 次/小时 -- 如遇到 `403 rate limit exceeded`,等待重置或减少操作频率 -- `actions/stale` 的 `operations-per-run` 参数可限制每次运行处理数量 -- 可通过 `GET /rate_limit` 接口查看当前剩余配额 - ---- - -## 常见问题 - -| 问题 | 解决 | -|------|------| -| token 生成后找不到 | 确保在 "Tokens (classic)" 页面生成 Classic PAT,在 "Fine-grained tokens" 页面生成 Fine-grained PAT | -| 403 Forbidden | Classic PAT 的 scope 不够(重新勾选 `repo`);Fine-grained PAT 权限不足(检查 Issues/PR 权限是否为 Read and write) | -| 401 Bad credentials | token 过期或被撤销,重新生成 | -| Docker 拉取镜像失败 | 执行 `docker logout ghcr.io` 后重试,或检查 Docker 是否运行 | -| MCP 工具列表为空 | MCP Server 未启动,检查 Docker 是否运行、配置文件 JSON 是否正确 | -| MCP Server 启动后立即退出 | 检查 token 是否有效,Docker 日志中通常有错误信息 | -| API 返回空结果 | 确认仓库是公开仓库,或 token 有访问私有仓库的权限 | -| PAT 被自动删除了 | GitHub 会清理一年未使用的 Classic PAT;Fine-grained PAT 到期后自动失效 | -| Fine-grained PAT 无法操作 | 确认 Repository access 中已勾选目标仓库,且权限级别足够 | - -### 安全提醒 - -- PAT 等同密码,不要分享给任何人 -- 不要提交到公开仓库(建议在 `.gitignore` 中添加 `.env`) -- 建议设置过期时间,定期轮换(Fine-grained PAT 强制设过期时间) -- GitHub 会自动删除一年未使用的 Classic PAT -- 优先使用 Fine-grained PAT,将权限限制在特定仓库 -- 如怀疑 token 泄露,立即在 GitHub Settings → Tokens 中撤销 +- [GitHub MCP Server](https://github.com/github/github-mcp-server) +- [Managing personal access tokens](https://docs.github.com/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens) +- [Permissions required for fine-grained PATs](https://docs.github.com/rest/authentication/permissions-required-for-fine-grained-personal-access-tokens) +- [GitHub CLI authentication](https://cli.github.com/manual/gh_auth_login) diff --git a/references/release-workflow.md b/references/release-workflow.md index e9ae91c..5c7c7b7 100644 --- a/references/release-workflow.md +++ b/references/release-workflow.md @@ -214,7 +214,7 @@ GET /repos/{owner}/{repo}/pulls?state=closed&sort=updated&direction=desc ```bash curl -X POST \ - -H "Authorization: token $GITHUB_TOKEN" \ + -H "Authorization: Bearer $GITHUB_TOKEN" \ -H "Accept: application/vnd.github+json" \ https://api.github.com/repos/{owner}/{repo}/releases \ -d '{ @@ -229,7 +229,7 @@ curl -X POST \ ### 方式二:通过 MCP 工具 -目前 GitHub MCP Server 没有直接的 `create_release` 工具。使用 curl 回退方案或通过 `create_or_update_file` 先推送版本文件变更,再用 `gh` CLI 创建 Release: +先检查当前 GitHub 连接或 MCP 是否暴露 Release/Tag 写入能力。工具能力会更新,不要把某个工具名或缺失状态写死;没有相应能力时,使用已认证的 `gh` CLI 或 REST API: ```bash gh release create v1.3.0 --title "v1.3.0" --notes "### Added..." --target main diff --git a/references/response-templates.md b/references/response-templates.md index 8d6f8fb..081fcf6 100644 --- a/references/response-templates.md +++ b/references/response-templates.md @@ -136,7 +136,7 @@ Feel free to open another issue if you have other ideas. 如果需要更多帮助,建议: - 查阅文档:{文档链接} -- 在 [Discussions](../../discussions) 中提问(问答类讨论更方便检索) +- 在 Discussions 中提问:{repo_url}/discussions(问答类讨论更方便检索) ``` **英文**: @@ -147,7 +147,7 @@ Here's how to solve this: If you need more help: - Check the docs: {docs link} -- Ask in [Discussions](../../discussions) (Q&A discussions are easier to search) +- Ask in Discussions: {repo_url}/discussions (Q&A discussions are easier to search) ``` ### 信息不足 @@ -254,7 +254,7 @@ Please do not discuss this vulnerability publicly until a fix is released. 几个小提示: - 提交 Issue 时可以使用模板,这样信息更完整 -- 如果想贡献代码,可以先看看 [CONTRIBUTING.md](../../blob/main/CONTRIBUTING.md) +- 如果想贡献代码,可以先看看:{repo_url}/blob/{default_branch}/CONTRIBUTING.md - 有任何问题随时在这里问 期待你的参与! @@ -266,7 +266,7 @@ Thanks for your first contribution! Welcome to the project. A few tips: - Using issue templates helps provide complete information -- If you'd like to contribute code, check out [CONTRIBUTING.md](../../blob/main/CONTRIBUTING.md) first +- If you'd like to contribute code, check: {repo_url}/blob/{default_branch}/CONTRIBUTING.md first - Feel free to ask any questions here Looking forward to your contributions! diff --git a/references/triage-workflow.md b/references/triage-workflow.md index 3fb7c60..832ad10 100644 --- a/references/triage-workflow.md +++ b/references/triage-workflow.md @@ -126,7 +126,7 @@ for label in '{"name":"type:bug","color":"d73a4a","description":"Confirmed bug"} '{"name":"resolution:invalid","color":"cfd3d7","description":"Invalid issue"}' \ '{"name":"good first issue","color":"7057ff","description":"Good for newcomers"}' \ '{"name":"help wanted","color":"008672","description":"Contributions welcome"}'; do - curl -s -X POST -H "Authorization: token $GITHUB_TOKEN" \ + curl --fail-with-body -X POST -H "Authorization: Bearer $GITHUB_TOKEN" \ -H "Accept: application/vnd.github+json" \ "https://api.github.com/repos///labels" \ -d "$label" diff --git a/scripts/validate-skill.mjs b/scripts/validate-skill.mjs new file mode 100644 index 0000000..04b0f46 --- /dev/null +++ b/scripts/validate-skill.mjs @@ -0,0 +1,94 @@ +import fs from 'node:fs'; +import path from 'node:path'; + +const root = process.cwd(); +const expectedName = 'github-oss-ops'; +const expectedVersion = '1.1.0'; +const required = [ + 'SKILL.md', 'README.md', 'LICENSE', 'CHANGELOG.md', 'CONTRIBUTING.md', + 'CODE_OF_CONDUCT.md', 'SECURITY.md', 'CONTRIBUTORS.md', + '.github/pull_request_template.md', '.github/ISSUE_TEMPLATE/config.yml', + '.github/repository-metadata.yml', 'agents/openai.yaml', 'examples/README.md', +]; + +const fail = (message) => { + console.error(`Validation failed: ${message}`); + process.exitCode = 1; +}; + +for (const relative of required) { + if (!fs.existsSync(path.join(root, relative))) fail(`missing ${relative}`); +} + +const skill = fs.readFileSync(path.join(root, 'SKILL.md'), 'utf8'); +const readme = fs.readFileSync(path.join(root, 'README.md'), 'utf8'); +const changelog = fs.readFileSync(path.join(root, 'CHANGELOG.md'), 'utf8'); +const metadata = fs.readFileSync(path.join(root, '.github/repository-metadata.yml'), 'utf8'); + +if (!skill.startsWith('---\n')) fail('SKILL.md must start with YAML frontmatter'); +if (!skill.includes(`name: ${expectedName}`)) fail('SKILL.md name mismatch'); +if (!skill.includes(`version: ${expectedVersion}`)) fail('SKILL.md version mismatch'); +if (!/^description:\s*.+/m.test(skill)) fail('SKILL.md description is missing'); +if (!changelog.includes(`## [${expectedVersion}]`)) fail('CHANGELOG version mismatch'); +if (!metadata.includes(`tag: v${expectedVersion}`)) fail('repository release metadata mismatch'); + +for (const fragment of [ + `~/.agents/skills/${expectedName}`, + `~/.claude/skills/${expectedName}`, + `~/.cursor/skills/${expectedName}`, + 'https://github.com/hyt315/github-oss-ops/releases/latest', + 'examples/README.md', +]) { + if (!readme.includes(fragment)) fail(`README missing ${fragment}`); +} + +const ignored = new Set(['.git']); +const files = []; +const walk = (directory) => { + for (const entry of fs.readdirSync(directory, {withFileTypes: true})) { + if (ignored.has(entry.name)) continue; + const absolute = path.join(directory, entry.name); + if (entry.isDirectory()) walk(absolute); + else files.push(absolute); + } +}; +walk(root); + +const textExtensions = new Set(['.md', '.yml', '.yaml', '.json', '.mjs', '.js', '.txt']); +const secretPatterns = [ + /ghp_[A-Za-z0-9]{20,}/, + /github_pat_[A-Za-z0-9_]{20,}/, + /-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----/, + /AKIA[0-9A-Z]{16}/, +]; +const bannedSafetyPatterns = [ + /~\/\.codex\/skills\/github-oss-ops/, + /Get-ChildItem\s+-Path\s+\$HOME\s+-Recurse/i, + /print\s*\(\s*token\s*\)/i, + /echo\s+\$GITHUB_(?:TOKEN|PERSONAL_ACCESS_TOKEN)/, +]; + +for (const file of files) { + if (!textExtensions.has(path.extname(file))) continue; + const text = fs.readFileSync(file, 'utf8'); + for (const pattern of secretPatterns) { + if (pattern.test(text)) fail(`credential-like value in ${path.relative(root, file)}`); + } + for (const pattern of bannedSafetyPatterns) { + if (pattern.test(text)) fail(`unsafe credential or install guidance in ${path.relative(root, file)}`); + } + + if (path.extname(file) === '.md') { + for (const match of text.matchAll(/\[[^\]]*\]\(([^)]+)\)/g)) { + const target = match[1].trim().split(/\s+/)[0]; + if (/^(?:https?:|mailto:|#)/.test(target)) continue; + const local = decodeURIComponent(target.split('#')[0]); + if (!local) continue; + if (!fs.existsSync(path.resolve(path.dirname(file), local))) { + fail(`broken local link ${target} in ${path.relative(root, file)}`); + } + } + } +} + +if (!process.exitCode) console.log(`${expectedName} v${expectedVersion} validation passed`);