diff --git a/CLAUDE.md b/CLAUDE.md index f91f294..fda2d4a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -40,7 +40,7 @@ Single entrypoint: `src/entrypoints/run.ts` orchestrates everything — prepare This fork adds Forgejo support via a lean adapter pattern — only 4 genuinely different areas have Forgejo-specific code: -- **`src/platform/detector.ts`** — Three-tier platform detection (explicit input > `FORGEJO` env > `GITHUB_SERVER_URL` heuristic) +- **`src/platform/detector.ts`** — Three-tier platform detection (explicit input > `FORGEJO` env > `GITHUB_SERVER_URL` heuristic) with cross-validation that rejects Forgejo override on github.com - **`src/forgejo/token.ts`** — Direct token handling (skips OIDC exchange) - **`src/forgejo/data/fetcher.ts`** — REST-based data fetching (replaces 3 GraphQL queries with 5-8 parallel REST calls) - **`src/forgejo/comment-logic.ts`** — Forgejo URL patterns for tracking comments @@ -54,9 +54,10 @@ All other `src/github/` modules work on Forgejo via Octokit REST as-is (permissi - `src/entrypoints/run.ts` — Platform branch at top for token setup - `src/modes/tag/index.ts` — Data fetcher swap (`fetchForgejoData` vs `fetchGitHubData`) - `src/github/operations/comments/create-initial.ts` — Platform-aware spinner/URL format -- `src/github/operations/comments/update-with-branch.ts` — Forgejo PR compare URL +- `src/github/operations/comments/update-with-branch.ts` — Forgejo branch link in tracking comment - `src/github/operations/branch.ts` — Uses `repos.getBranch()` on Forgejo (Forgejo has `/git/refs` not `/git/ref`) -- `src/github/validation/actor.ts` — Skipped on Forgejo (no bot accounts) +- `src/github/validation/actor.ts` — Bot-type check skipped on Forgejo; self-trigger guard active +- `src/entrypoints/update-comment-link.ts` — Forgejo PR compare URL (`expand=1` instead of `quick_pull=1`) - `src/mcp/install-mcp-server.ts` — Skips GitHub public MCP server on Forgejo **MCP server names stay the same** (`github_comment`, `github_ci`, etc.) even on Forgejo — changing them would require updating hardcoded tool name lists in `src/modes/tag/index.ts`. diff --git a/docs/forgejo.md b/docs/forgejo.md index 781e662..0df768a 100644 --- a/docs/forgejo.md +++ b/docs/forgejo.md @@ -88,6 +88,8 @@ The action detects the platform using a three-tier strategy: **Recommendation**: Always set `platform: "forgejo"` explicitly. Auto-detection works but the explicit input eliminates ambiguity. +> **Security note**: Setting `platform: "forgejo"` on a `github.com` runner is rejected — the action cross-validates the `GITHUB_SERVER_URL` and falls through to standard detection. This prevents bypassing GitHub-specific security checks (e.g., actor validation). + > **Note for GitHub Enterprise Server (GHES) users**: The tier-3 heuristic classifies any non-`github.com` URL as Forgejo. If you run on GHES (e.g., `https://github.mycompany.com`), you **must** set `platform: "github"` explicitly to avoid misdetection. ## Differences from GitHub @@ -105,15 +107,15 @@ On Forgejo, there is no OIDC token exchange with Anthropic. The action uses the ### API Differences -| Feature | GitHub | Forgejo | -| --------------------- | ------------------------------------------- | ------------------------------------------------------------------- | -| **GraphQL API** | Used for PR/issue data fetching | Not available — REST API only | -| **Data fetching** | Single GraphQL query per entity | 5-8 parallel REST API calls | -| **Actor validation** | Checks for bot/app accounts | Skipped — no bot accounts on Forgejo | -| **GitHub MCP server** | `ghcr.io/github/github-mcp-server` included | Skipped — GitHub-specific | -| **CI/Actions MCP** | Full GitHub Actions API | Works via Octokit REST + `GITHUB_API_URL` | -| **Permission check** | `getCollaboratorPermissionLevel()` | `repos.get()` fallback (workflow tokens lack collaborator endpoint) | -| **Git ref lookup** | `git.getRef()` (`/git/ref/heads/...`) | `repos.getBranch()` (`/git/refs` is plural on Forgejo) | +| Feature | GitHub | Forgejo | +| --------------------- | ------------------------------------------- | --------------------------------------------------------------------- | +| **GraphQL API** | Used for PR/issue data fetching | Not available — REST API only | +| **Data fetching** | Single GraphQL query per entity | 5-8 parallel REST API calls | +| **Actor validation** | Checks for bot/app accounts | Bot-type check skipped; self-trigger guard active | +| **GitHub MCP server** | `ghcr.io/github/github-mcp-server` included | Skipped — GitHub-specific | +| **CI/Actions MCP** | Full GitHub Actions API | Works via Octokit REST + `GITHUB_API_URL` | +| **Permission check** | `getCollaboratorPermissionLevel()` | `getCollaboratorPermissionLevel()` with `repos.get()` fallback on 403 | +| **Git ref lookup** | `git.getRef()` (`/git/ref/heads/...`) | `repos.getBranch()` (`/git/refs` is plural on Forgejo) | ### Webhook & Event Differences @@ -257,12 +259,10 @@ Runs on push to `main` and pull requests. Three parallel jobs: ### `test-action.yml` — Action Self-Test -Tests the action itself on Forgejo in agent mode. Runs weekly and on PRs that modify `src/`, `action.yml`, or `.forgejo/`. Validates: +Tests the action itself on Forgejo in agent mode. Runs weekly and on PRs that modify `src/`, `action.yml`, `.forgejo/`, or `base-action/`. Validates: -- Platform detection returns "forgejo" -- Token authentication works -- Claude Code executes successfully -- Output file is produced +- Claude Code executes successfully with `platform: "forgejo"` +- Output file is produced with expected content ### `upstream-sync.yml` — Upstream Sync Check @@ -349,7 +349,7 @@ All execution modes and trigger types have been validated end-to-end on a Forgej - **GitHub MCP server**: The `ghcr.io/github/github-mcp-server` Docker image is GitHub-specific and is skipped on Forgejo. - **Commit signing**: SSH signing has not been tested on Forgejo. The `use_commit_signing` option (GitHub API signing) won't work since it uses GitHub's commit API. - **`downloadJobLogForWorkflowRun`**: Forgejo's Actions API may lack this endpoint. The CI MCP server attempts it via Octokit REST but may return limited data. -- **Bot filtering**: `allowed_bots` checks won't match `claude[bot]` since Forgejo has no bot accounts. Actor validation is skipped entirely on Forgejo. +- **Bot filtering**: `allowed_bots` checks won't match `claude[bot]` since Forgejo has no bot accounts. Bot-type actor validation is skipped on Forgejo, but self-trigger prevention is active — the action blocks events where the actor matches the configured `bot_name` to prevent infinite loops. - **`pull_request_review` trigger is dead code**: Forgejo sends `pull_request_comment` for both review comments and review submissions. The `pull_request_review` trigger in the workflow never fires — all review-related events are handled through the `pull_request_comment` codepath. - **Review comment tracking comments are always issue comments**: On Forgejo, review comment events lack the top-level `comment` object needed to create PR review comment replies. The tracking comment is always created as a regular issue comment instead. - **Workflow `if:` conditions are unreliable for Forgejo events**: Forgejo does not populate `github.event.comment.body`, `github.event.review.body`, or `github.event.action` in the workflow expression context for several event types. All trigger validation happens in application code (`trigger.ts`), not in workflow conditions. @@ -382,7 +382,7 @@ Forgejo doesn't populate `github.event.comment.body`, `github.event.review.body` ### Workflow `if:` expression fails with "invalid token" error -Forgejo's expression parser rejects `#` characters as invalid tokens. Move any comments outside the `if:` block and use `>-` scalar folding instead of `|` for multi-line expressions. +Forgejo's expression parser may reject `#` characters as invalid tokens when using `|` (literal block) scalars, since each line is preserved and `#` starts a comment that extends to end-of-line. With `>-` (folded scalar), newlines become spaces, and `#` comments may be tolerated by some Forgejo versions — but for maximum compatibility, move comments outside the `if:` block entirely. ### Label trigger fires twice when creating issue with label diff --git a/prds/7-senior-review-forgejo.md b/prds/7-senior-review-forgejo.md index dd61430..a198701 100644 --- a/prds/7-senior-review-forgejo.md +++ b/prds/7-senior-review-forgejo.md @@ -101,7 +101,7 @@ Perform a thorough, documented code review of all Forgejo-related changes. The r - Code comments: are complex decisions documented? - **Deliverable**: Code quality fixes applied -- [ ] **M6: Documentation accuracy review** +- [x] **M6: Documentation accuracy review** - Cross-check `docs/forgejo.md` against actual code behavior - Verify all "Known Limitations" are still accurate - Check that code examples and configuration snippets work