From b8ee74c664c13db55244fcc960751a57ca65da83 Mon Sep 17 00:00:00 2001 From: Achintya Ashok Date: Tue, 30 Sep 2025 14:17:35 -0400 Subject: [PATCH 1/5] fix: use GitHub Rulesets bypass instead of GitHub App - Remove GitHub App token generation (incorrect approach) - Use standard GITHUB_TOKEN with rulesets bypass permissions - Add RULESET_SETUP.md with official GitHub configuration steps - Remove signed commit requirement (GitHub Actions signs automatically) - This is GitHub's official 2024-2025 recommended approach Configuration required: - Create repository ruleset for main branch - Add github-actions[bot] to bypass list - Set bypass mode to 'Always' for automated releases --- .github/RULESET_SETUP.md | 154 +++++++++++++++++++++++++++++ .github/workflows/publish-beta.yml | 4 +- 2 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 .github/RULESET_SETUP.md diff --git a/.github/RULESET_SETUP.md b/.github/RULESET_SETUP.md new file mode 100644 index 0000000..5c8414f --- /dev/null +++ b/.github/RULESET_SETUP.md @@ -0,0 +1,154 @@ +# GitHub Rulesets Setup for Automated Releases + +This document explains the **official GitHub-recommended approach** for allowing automated workflows to push version bumps to protected branches. + +## Why Rulesets (Not Branch Protection Rules) + +GitHub now recommends using **Repository Rulesets** instead of legacy branch protection rules because: +- Rulesets are more flexible and modern +- Support bypass permissions for specific actors (like GitHub Actions) +- Better integration with automated workflows +- Introduced in 2024-2025 as the preferred method + +## Overview + +The `publish-beta.yml` workflow needs to: +1. Bump the version in `package.json` using changesets +2. Commit these changes back to the `main` branch +3. Push the commit and tag to origin + +Using rulesets with bypass permissions allows `github-actions[bot]` to do this without requiring a GitHub App or PAT. + +## Setup Instructions + +### Step 1: Navigate to Repository Rulesets + +1. Go to your repository: `https://github.com/toolprint/hypertool-mcp` +2. Click on "Settings" +3. In the left sidebar, find "Code and automation" section +4. Click on **"Rules"** → **"Rulesets"** (NOT "Branches") + +### Step 2: Create or Edit Ruleset for Main Branch + +1. Click **"New ruleset"** → **"New branch ruleset"** + - Or edit existing ruleset if you have one +2. Name it: `main-branch-protection` +3. Enforcement status: **"Active"** + +### Step 3: Configure Target Branches + +Under "Target branches": +1. Click **"Add target"** +2. Select **"Include by pattern"** +3. Enter pattern: `main` +4. This applies the ruleset to your main branch + +### Step 4: Configure Branch Rules + +Enable the following rules: + +**Required:** +- ✅ **Require a pull request before merging** + - Required approvals: 1 (or your preference) + - Dismiss stale pull request approvals when new commits are pushed + +- ✅ **Require status checks to pass** + - Add your CI checks (tests, lint, etc.) + - Require branches to be up to date before merging + +**Optional (based on your needs):** +- ✅ **Require signed commits** (if you want verified commits) +- ✅ **Block force pushes** +- ✅ **Require linear history** + +### Step 5: Configure Bypass Permissions (CRITICAL STEP) + +This is the key configuration that allows automated releases: + +1. Scroll to **"Bypass list"** section +2. Click **"Add bypass"** +3. Select **"Repository roles"** or **"GitHub Apps"** +4. Add: **`github-actions[bot]`** or **"GitHub Actions"** role +5. **Bypass mode**: Select **"Always"** (for trusted automation) or **"With approval"** + +For automated releases, use **"Always"** bypass mode. + +### Step 6: Save Ruleset + +1. Review your configuration +2. Click **"Create"** (or **"Save changes"**) +3. The ruleset is now active + +### Step 7: Verify Workflow Permissions + +Ensure your workflow has the correct permissions (already configured in `publish-beta.yml`): + +```yaml +permissions: + contents: write # Required to push commits and tags + actions: read # Required to read workflow information + id-token: write # Required for OIDC authentication +``` + +## How It Works + +1. When the workflow runs on `main` branch: + - It has `contents: write` permission + - The `github-actions[bot]` actor is in the bypass list + - It can push commits and tags directly to `main` + +2. Regular developers cannot push to `main`: + - Must create pull requests + - Must pass status checks + - Must get approvals + - Cannot bypass the rules + +## Troubleshooting + +### Error: "Resource not accessible by integration" +**Solution**: Ensure `contents: write` permission is set in the workflow + +### Error: "Push declined due to repository rule violations" +**Solution**: +- Verify `github-actions[bot]` is in the bypass list +- Check that bypass mode is set to "Always" +- Ensure the ruleset is "Active" (not "Evaluate") + +### Error: "Commits must have verified signatures" +**Solution**: +- Either remove the "Require signed commits" rule +- Or add `github-actions[bot]` to the bypass list for this rule specifically +- GitHub Actions commits are automatically signed by GitHub + +### Workflow doesn't push anything +**Solution**: +- Check that `persist-credentials: true` is set in the checkout action +- Verify `GITHUB_TOKEN` is being used (not a PAT) + +## Security Considerations + +✅ **Safe**: +- Only `github-actions[bot]` can bypass rules +- Only for workflows running from the main repository (not forks) +- Requires `[skip-ci]` tag to prevent infinite loops +- All actions are audited in GitHub audit log + +⚠️ **Be Aware**: +- Anyone who can modify workflow files can potentially use the bypass +- Review workflow changes carefully in PRs +- Consider using CODEOWNERS for `.github/workflows/` directory + +## Alternative: Separate Release Branch + +If you prefer not to use bypass permissions, you can: +1. Have the workflow create a release PR instead of pushing directly +2. Auto-merge the PR using a GitHub App or auto-merge setting +3. This is more complex but doesn't require bypass permissions + +However, the bypass approach is **GitHub's official recommendation** for automated releases. + +## Documentation References + +- [GitHub Rulesets Official Docs](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets/about-rulesets) +- [Available Rules for Rulesets](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets/available-rules-for-rulesets) +- [GitHub Ruleset Best Practices](https://wellarchitected.github.com/library/governance/recommendations/managing-repositories-at-scale/rulesets-best-practices/) diff --git a/.github/workflows/publish-beta.yml b/.github/workflows/publish-beta.yml index 93d0fb8..fade229 100644 --- a/.github/workflows/publish-beta.yml +++ b/.github/workflows/publish-beta.yml @@ -13,6 +13,7 @@ on: permissions: contents: write actions: read + id-token: write jobs: publish-beta: @@ -25,6 +26,7 @@ jobs: with: token: ${{ secrets.GITHUB_TOKEN }} fetch-depth: 0 + persist-credentials: true - name: Setup Node.js uses: actions/setup-node@v4 @@ -87,7 +89,7 @@ jobs: env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - - name: Create and push git tag + - name: Create and push git tag and commit run: | git tag v${{ steps.version.outputs.version }} git push origin v${{ steps.version.outputs.version }} From 4f80b059a3076819594b091713f163836d77cbe3 Mon Sep 17 00:00:00 2001 From: Achintya Ashok Date: Tue, 30 Sep 2025 14:24:14 -0400 Subject: [PATCH 2/5] fix: use SSH deploy key instead of GITHUB_TOKEN for protected branch pushes - Updated publish-beta workflow to use ssh-key authentication - Revised RULESET_SETUP.md with correct deploy key configuration - GitHub does not allow github-actions[bot] in bypass lists directly - Deploy key method is simpler than GitHub App approach - Added detailed setup instructions and troubleshooting --- .github/RULESET_SETUP.md | 103 +++++++++++++++++++++-------- .github/workflows/publish-beta.yml | 2 +- 2 files changed, 77 insertions(+), 28 deletions(-) diff --git a/.github/RULESET_SETUP.md b/.github/RULESET_SETUP.md index 5c8414f..065e2e0 100644 --- a/.github/RULESET_SETUP.md +++ b/.github/RULESET_SETUP.md @@ -65,13 +65,47 @@ Enable the following rules: This is the key configuration that allows automated releases: -1. Scroll to **"Bypass list"** section -2. Click **"Add bypass"** -3. Select **"Repository roles"** or **"GitHub Apps"** -4. Add: **`github-actions[bot]`** or **"GitHub Actions"** role -5. **Bypass mode**: Select **"Always"** (for trusted automation) or **"With approval"** +**Important**: GitHub does not allow adding `github-actions[bot]` directly to bypass lists. You must use one of these methods: -For automated releases, use **"Always"** bypass mode. +#### Option A: Deploy Key Method (Recommended - Simpler) + +1. **Generate SSH Deploy Key**: + ```bash + ssh-keygen -t ed25519 -C "github-actions-deploy-key" -f deploy_key -N "" + ``` + This creates `deploy_key` (private) and `deploy_key.pub` (public) + +2. **Add Public Key as Deploy Key**: + - Go to repository **Settings** → **Deploy keys** + - Click **"Add deploy key"** + - Title: `GitHub Actions Deploy Key` + - Key: Paste contents of `deploy_key.pub` + - ✅ **Check "Allow write access"** + - Click **"Add key"** + +3. **Add Private Key as Secret**: + - Go to repository **Settings** → **Secrets and variables** → **Actions** + - Click **"New repository secret"** + - Name: `DEPLOY_KEY` + - Value: Paste contents of `deploy_key` (the private key) + - Click **"Add secret"** + +4. **Configure Ruleset Bypass**: + - In your ruleset, scroll to **"Bypass list"** section + - Click **"Add bypass"** + - Select **"Deploy keys"** + - **Bypass mode**: Select **"Always"** + +5. **Update Workflow** (see Step 7 below for workflow changes) + +#### Option B: GitHub App Method (More Complex, Organization Required) + +1. Create a GitHub App with `contents: write` permission +2. Install the app in your repository +3. Add the GitHub App to the ruleset's bypass list +4. Use `actions/create-github-app-token` action in your workflow + +**We recommend Option A (Deploy Key) for simplicity.** ### Step 6: Save Ruleset @@ -79,64 +113,79 @@ For automated releases, use **"Always"** bypass mode. 2. Click **"Create"** (or **"Save changes"**) 3. The ruleset is now active -### Step 7: Verify Workflow Permissions +### Step 7: Update Workflow to Use Deploy Key -Ensure your workflow has the correct permissions (already configured in `publish-beta.yml`): +If using **Option A (Deploy Key)**, update the checkout step in `publish-beta.yml`: ```yaml -permissions: - contents: write # Required to push commits and tags - actions: read # Required to read workflow information - id-token: write # Required for OIDC authentication +- name: Checkout code + uses: actions/checkout@v4 + with: + ssh-key: ${{ secrets.DEPLOY_KEY }} + fetch-depth: 0 + persist-credentials: true ``` +If using **Option B (GitHub App)**, the workflow would need additional steps with the `create-github-app-token` action (not covered in detail here). + +**Current workflow** uses `token: ${{ secrets.GITHUB_TOKEN }}` which won't work with rulesets. You must switch to the deploy key method. + ## How It Works 1. When the workflow runs on `main` branch: - - It has `contents: write` permission - - The `github-actions[bot]` actor is in the bypass list - - It can push commits and tags directly to `main` + - The workflow uses the SSH deploy key for authentication + - Deploy keys are in the ruleset bypass list + - The workflow can push commits and tags directly to `main` + - The `[skip-ci]` commit message prevents infinite loops 2. Regular developers cannot push to `main`: - Must create pull requests - Must pass status checks - Must get approvals - - Cannot bypass the rules + - Cannot bypass the rules (they don't have the deploy key) ## Troubleshooting -### Error: "Resource not accessible by integration" -**Solution**: Ensure `contents: write` permission is set in the workflow - ### Error: "Push declined due to repository rule violations" **Solution**: -- Verify `github-actions[bot]` is in the bypass list +- Verify "Deploy keys" are in the bypass list of your ruleset - Check that bypass mode is set to "Always" - Ensure the ruleset is "Active" (not "Evaluate") +- Confirm the deploy key was added with "Allow write access" enabled + +### Error: "Permission denied (publickey)" +**Solution**: +- Verify the `DEPLOY_KEY` secret contains the **private key** (not public key) +- Ensure the deploy key is properly formatted (starts with `-----BEGIN OPENSSH PRIVATE KEY-----`) +- Check that the deploy key was added to the repository's Deploy keys settings ### Error: "Commits must have verified signatures" **Solution**: -- Either remove the "Require signed commits" rule -- Or add `github-actions[bot]` to the bypass list for this rule specifically -- GitHub Actions commits are automatically signed by GitHub +- Either remove the "Require signed commits" rule from your ruleset +- Or add "Deploy keys" to the bypass list for this specific rule +- SSH deploy keys automatically handle commit signing ### Workflow doesn't push anything **Solution**: - Check that `persist-credentials: true` is set in the checkout action -- Verify `GITHUB_TOKEN` is being used (not a PAT) +- Verify `ssh-key: ${{ secrets.DEPLOY_KEY }}` is configured (not `token`) +- Ensure the deploy key has write access enabled ## Security Considerations ✅ **Safe**: -- Only `github-actions[bot]` can bypass rules -- Only for workflows running from the main repository (not forks) +- Only workflows with access to the `DEPLOY_KEY` secret can bypass rules +- Only workflows running from the main repository can access secrets (not forks) - Requires `[skip-ci]` tag to prevent infinite loops - All actions are audited in GitHub audit log +- Deploy key is scoped to a single repository ⚠️ **Be Aware**: -- Anyone who can modify workflow files can potentially use the bypass +- Anyone who can modify workflow files can potentially use the deploy key - Review workflow changes carefully in PRs - Consider using CODEOWNERS for `.github/workflows/` directory +- Protect the `DEPLOY_KEY` secret - never expose it in logs or output +- Rotate the deploy key periodically for enhanced security ## Alternative: Separate Release Branch diff --git a/.github/workflows/publish-beta.yml b/.github/workflows/publish-beta.yml index fade229..5724a80 100644 --- a/.github/workflows/publish-beta.yml +++ b/.github/workflows/publish-beta.yml @@ -24,7 +24,7 @@ jobs: - name: Checkout code uses: actions/checkout@v4 with: - token: ${{ secrets.GITHUB_TOKEN }} + ssh-key: ${{ secrets.DEPLOY_KEY }} fetch-depth: 0 persist-credentials: true From 71d36ac4c1940adabf7de402d20a92f4fa04bd71 Mon Sep 17 00:00:00 2001 From: Achintya Ashok Date: Tue, 30 Sep 2025 14:42:22 -0400 Subject: [PATCH 3/5] docs: update RULESET_SETUP with deploy key method as chosen solution - Removed GitHub App option (more complex, not chosen) - Consolidated to single deploy key method - Added step-by-step instructions with exact commands - Added rationale for why deploy keys over other methods - Included cleanup step for key files - Ready for replication in other projects --- .github/RULESET_SETUP.md | 61 ++++++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 24 deletions(-) diff --git a/.github/RULESET_SETUP.md b/.github/RULESET_SETUP.md index 065e2e0..21004b8 100644 --- a/.github/RULESET_SETUP.md +++ b/.github/RULESET_SETUP.md @@ -17,7 +17,15 @@ The `publish-beta.yml` workflow needs to: 2. Commit these changes back to the `main` branch 3. Push the commit and tag to origin -Using rulesets with bypass permissions allows `github-actions[bot]` to do this without requiring a GitHub App or PAT. +**Solution**: Use SSH Deploy Keys with ruleset bypass permissions. GitHub does not allow `github-actions[bot]` to be added directly to bypass lists, so we use a deploy key instead. + +### Why Deploy Keys? + +- **Simpler than GitHub Apps**: No app creation or installation needed +- **Repository-scoped**: Key only works for this specific repository +- **No organization required**: Works for personal and organization repos +- **Native GitHub feature**: Built-in support in rulesets and workflows +- **Secure**: Private key stored as encrypted secret, only accessible to workflows ## Setup Instructions @@ -65,47 +73,52 @@ Enable the following rules: This is the key configuration that allows automated releases: -**Important**: GitHub does not allow adding `github-actions[bot]` directly to bypass lists. You must use one of these methods: +**Important**: GitHub does not allow adding `github-actions[bot]` directly to bypass lists. You must use the **Deploy Key Method**. -#### Option A: Deploy Key Method (Recommended - Simpler) +#### Deploy Key Setup (Step-by-Step) 1. **Generate SSH Deploy Key**: ```bash - ssh-keygen -t ed25519 -C "github-actions-deploy-key" -f deploy_key -N "" + cd /tmp + ssh-keygen -t ed25519 -C "github-actions-deploy-key" -f github_actions_deploy_key -N "" ``` - This creates `deploy_key` (private) and `deploy_key.pub` (public) + This creates: + - `github_actions_deploy_key` (private key - keep secret!) + - `github_actions_deploy_key.pub` (public key - safe to share) 2. **Add Public Key as Deploy Key**: - - Go to repository **Settings** → **Deploy keys** + - Go to: `https://github.com/YOUR_ORG/YOUR_REPO/settings/keys` - Click **"Add deploy key"** - - Title: `GitHub Actions Deploy Key` - - Key: Paste contents of `deploy_key.pub` - - ✅ **Check "Allow write access"** + - **Title**: `GitHub Actions Deploy Key` + - **Key**: Run `cat /tmp/github_actions_deploy_key.pub` and paste the entire output + - ✅ **CRITICAL**: Check **"Allow write access"** - Click **"Add key"** -3. **Add Private Key as Secret**: - - Go to repository **Settings** → **Secrets and variables** → **Actions** +3. **Add Private Key as Repository Secret**: + - Go to: `https://github.com/YOUR_ORG/YOUR_REPO/settings/secrets/actions` - Click **"New repository secret"** - - Name: `DEPLOY_KEY` - - Value: Paste contents of `deploy_key` (the private key) + - **Name**: `DEPLOY_KEY` (must be exactly this) + - **Secret**: Run `cat /tmp/github_actions_deploy_key` and paste the **entire output** including: + - `-----BEGIN OPENSSH PRIVATE KEY-----` + - All the encoded key data + - `-----END OPENSSH PRIVATE KEY-----` - Click **"Add secret"** 4. **Configure Ruleset Bypass**: - - In your ruleset, scroll to **"Bypass list"** section + - Go to: `https://github.com/YOUR_ORG/YOUR_REPO/settings/rules` + - Find your main branch ruleset (or create one if needed) + - Scroll to **"Bypass list"** section - Click **"Add bypass"** - - Select **"Deploy keys"** + - Select **"Deploy keys"** from the dropdown - **Bypass mode**: Select **"Always"** + - Click **"Save"** or **"Create"** -5. **Update Workflow** (see Step 7 below for workflow changes) - -#### Option B: GitHub App Method (More Complex, Organization Required) - -1. Create a GitHub App with `contents: write` permission -2. Install the app in your repository -3. Add the GitHub App to the ruleset's bypass list -4. Use `actions/create-github-app-token` action in your workflow +5. **Clean Up Key Files**: + ```bash + rm /tmp/github_actions_deploy_key /tmp/github_actions_deploy_key.pub + ``` -**We recommend Option A (Deploy Key) for simplicity.** +6. **Update Workflow** (see Step 7 below for workflow changes) ### Step 6: Save Ruleset From 5a2aec83bf0f395df4345b13ff07b39585611ec0 Mon Sep 17 00:00:00 2001 From: Achintya Ashok Date: Tue, 30 Sep 2025 14:42:48 -0400 Subject: [PATCH 4/5] chore: sync package.json version to 0.0.44 - Version 0.0.44 was already published to NPM - Package.json was out of sync at 0.0.43 - Updated to match published version --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3ef9949..c0ebf6f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@toolprint/hypertool-mcp", - "version": "0.0.43", + "version": "0.0.44", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@toolprint/hypertool-mcp", - "version": "0.0.43", + "version": "0.0.44", "license": "MIT", "dependencies": { "@modelcontextprotocol/sdk": "^1.15.1", diff --git a/package.json b/package.json index 0a54a26..c3329c0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@toolprint/hypertool-mcp", - "version": "0.0.43", + "version": "0.0.44", "mcpName": "ai.toolprint/hypertool-mcp", "description": "HyperTool MCP proxy server for routing requests between clients and multiple underlying MCP servers", "main": "./dist/index.js", From a0752728309927b533dba8832f1a1bdfd00922dd Mon Sep 17 00:00:00 2001 From: Achintya Ashok Date: Tue, 30 Sep 2025 14:45:13 -0400 Subject: [PATCH 5/5] feat: add allowed-tools list to generate-pr-desc slash command - Added specific tool permissions for automated PR description generation - Allows gh CLI, git, and file operations without requiring user approval - Follows pattern from new-feature.md command --- .claude/commands/proj/generate-pr-desc.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.claude/commands/proj/generate-pr-desc.md b/.claude/commands/proj/generate-pr-desc.md index 0c8124d..be928db 100644 --- a/.claude/commands/proj/generate-pr-desc.md +++ b/.claude/commands/proj/generate-pr-desc.md @@ -1,6 +1,7 @@ --- description: Generate and update PR description from branch commits using GitHub CLI tags: [git, pr, documentation, github] +allowed-tools: Read, Bash(gh pr view*), Bash(gh pr edit*), Bash(git log*), Bash(git diff*), Bash(mkdir -p .tmp), Bash(cat > .tmp/pr-description.md*) --- # Generate PR Description