Skip to content

feat(server): Add GitHub repository size check before processing - #1412

Open
yamadashy wants to merge 3 commits into
mainfrom
feat/server-github-repo-size-check
Open

feat(server): Add GitHub repository size check before processing#1412
yamadashy wants to merge 3 commits into
mainfrom
feat/server-github-repo-size-check

Conversation

@yamadashy

@yamadashy yamadashy commented Apr 6, 2026

Copy link
Copy Markdown
Owner

Add a pre-download size check for GitHub repositories to prevent processing oversized repos that would exhaust server resources.

  • Query GitHub API (/repos/{owner}/{repo}) to get repository size before downloading
  • Reject repositories exceeding 500MB with a 422 error and a clear message
  • Fail open: if the API is unreachable or the repo is non-GitHub, processing continues normally
  • Run the check after cache lookup to avoid unnecessary API calls
  • Export parseGitHubRepoInfo and GitHubRepoInfo from the repomix package for server-side URL parsing

Checklist

  • Run npm run test
  • Run npm run lint

Open with Devin

Check repository size via GitHub API before downloading and processing.
Repositories exceeding 500MB are rejected with a 422 error to prevent
resource exhaustion on the server.

The check runs after cache lookup (to avoid unnecessary API calls) and
fails open — if the GitHub API is unreachable or the repo is non-GitHub,
processing continues normally.

Also exports `parseGitHubRepoInfo` and `GitHubRepoInfo` from the repomix
package to support server-side repository URL parsing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Apr 6, 2026

Copy link
Copy Markdown
Contributor

⚡ Performance Benchmark

Latest commit:ae43543 refactor(server): Rename GITHUB_TOKEN to GITHUB_TOKEN_REPO_SIZE_CHECK
Status:✅ Benchmark complete!
Ubuntu:1.50s (±0.03s) → 1.50s (±0.01s) · -0.01s (-0.5%)
macOS:0.97s (±0.11s) → 0.97s (±0.16s) · -0.00s (-0.2%)
Windows:1.85s (±0.09s) → 1.82s (±0.15s) · -0.03s (-1.8%)
Details
  • Packing the repomix repository with node bin/repomix.cjs
  • Warmup: 2 runs (discarded), interleaved execution
  • Measurement: 20 runs / 30 on macOS (median ± IQR)
  • Workflow run
History

ce37173 feat(server): Add GITHUB_TOKEN support for repo size check API

Ubuntu:1.89s (±0.04s) → 1.89s (±0.06s) · +0.00s (+0.2%)
macOS:1.16s (±0.20s) → 1.14s (±0.19s) · -0.02s (-1.7%)
Windows:1.95s (±0.19s) → 1.96s (±0.16s) · +0.01s (+0.4%)

b2257d5 feat(server): Add GitHub repository size check before processing

Ubuntu:1.50s (±0.02s) → 1.50s (±0.03s) · +0.01s (+0.5%)
macOS:0.90s (±0.07s) → 0.88s (±0.08s) · -0.02s (-2.4%)
Windows:1.93s (±0.05s) → 1.92s (±0.08s) · -0.01s (-0.4%)

@coderabbitai

coderabbitai Bot commented Apr 6, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0be4557d-fd45-4de6-ba11-926258b7a64f

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR extends the module's public API by exporting Git repository parsing utilities and introduces GitHub repository size validation during remote repository processing to prevent large repositories from being packed.

Changes

Cohort / File(s) Summary
Public API Extensions
src/index.ts
Added exports for parseGitHubRepoInfo function and GitHubRepoInfo type from the git remote parsing module.
Size Validation Utility
website/server/src/domains/pack/utils/gitHubRepoSize.ts
New module that implements checkGitHubRepoSize() to fetch GitHub repository metadata, validate size against 500MB limit, and throw AppError with HTTP 422 status if exceeded.
Integration
website/server/src/domains/pack/remoteRepo.ts
Added invocation of checkGitHubRepoSize(repoUrl) before processing, introducing a pre-validation step in the remote repository packing workflow.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and accurately summarizes the main change: adding a GitHub repository size check before processing.
Description check ✅ Passed The description is comprehensive with clear implementation details and includes the required checklist with both items marked as completed.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/server-github-repo-size-check

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a size check for GitHub repositories before they are processed, setting a maximum limit of 500MB. The implementation includes a new utility to fetch repository metadata via the GitHub API. Feedback highlights that the specific 422 error thrown for oversized repositories may be swallowed by existing generic error handling in the calling function, and suggests using authenticated API requests to avoid strict rate limits on public-facing servers.

}

// Check repository size before processing
await checkGitHubRepoSize(repoUrl);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The AppError thrown by checkGitHubRepoSize (with a 422 status) will be caught by the generic catch block at the end of this function (line 109). That block wraps all errors in a new AppError with a 500 status and a generic message about the repository not being public. This defeats the purpose of providing a specific 422 error for oversized repositories. You should update the catch block at line 109 to check if the error is already an AppError and re-throw it if so.

Comment on lines +22 to +28
const response = await fetch(url, {
headers: {
Accept: 'application/vnd.github.v3+json',
'User-Agent': 'Repomix',
},
signal: AbortSignal.timeout(GITHUB_API_TIMEOUT_MS),
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Unauthenticated requests to the GitHub API are subject to a strict rate limit (60 requests per hour per IP). On a public-facing server, this limit can be exhausted quickly, causing the size check to "fail open" and return null for most requests. Consider using an authenticated request if a GitHub token is available in the environment variables (e.g., by adding an Authorization: token <TOKEN> header).

@codecov

codecov Bot commented Apr 6, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 87.26%. Comparing base (9d5b928) to head (ae43543).
⚠️ Report is 834 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1412      +/-   ##
==========================================
- Coverage   87.42%   87.26%   -0.17%     
==========================================
  Files         116      117       +1     
  Lines        4397     4420      +23     
  Branches     1020     1021       +1     
==========================================
+ Hits         3844     3857      +13     
- Misses        553      563      +10     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@claude

claude Bot commented Apr 6, 2026

Copy link
Copy Markdown
Contributor

Code Review: feat(server): Add GitHub repository size check before processing

Overall: Clean, well-scoped PR that adds a sensible safeguard against processing oversized GitHub repos. The fail-open design and placement after cache lookup are good architectural choices. A few items worth considering below.


Noteworthy Findings

1. Unauthenticated GitHub API rate limit (60 req/hour) could be exhausted under moderate load

The size check uses unauthenticated GitHub API requests, which are limited to 60/hour per IP. Under sustained traffic, most requests will hit rate limits and fall through to fail-open — effectively disabling the size check. Consider supporting an optional GITHUB_TOKEN environment variable to increase the limit to 5,000/hour.

2. No tests included

The PR adds a new utility file with non-trivial logic (API calls, error handling, size comparison) but includes no tests. Key test cases to consider:

  • Repo exceeding 500MB throws AppError with status 422
  • API failures (timeout, 5xx, 404) silently allow processing
  • Non-GitHub URLs skip the check entirely
  • Boundary condition: size exactly at 500MB limit

The codebase has established patterns for mocking fetch in tests (see gitHubArchiveApi.test.ts).

3. Missing dependency injection (project convention)

Per CLAUDE.md guidelines, dependencies should be injected through a deps object parameter for testability. The checkGitHubRepoSize function calls parseGitHubRepoInfo and fetch directly. Consider:

export const checkGitHubRepoSize = async (
  repoUrl: string,
  deps = { parseGitHubRepoInfo, fetchGitHubRepoSize },
): Promise<void> => {
  // ...
};

This follows the pattern used in fileProcess.ts and securityCheck.ts.

4. Silent error swallowing — consider trace-level logging

The catch block in fetchGitHubRepoSize silently returns null. The established pattern in the codebase (e.g., gitRemoteParse.ts) uses logger.trace() for similar cases. Adding trace logging would help with debugging without affecting production behavior:

catch (error) {
  logger.trace(`Failed to fetch GitHub repo size: ${error}`);
  return null;
}
5. GitHub API `size` field accuracy caveat

GitHub's size field represents the packed git object database size in KB, not the working directory size. Actual clone size can differ significantly (2-3x larger with full history). The 500MB limit effectively protects against very large repos, but the relationship between API-reported size and actual resource consumption during processing is approximate. Worth documenting this in a comment.

6. Timeout could be reduced

The 10-second timeout is generous — GitHub API typically responds in <500ms. A 3-5 second timeout would release resources faster during API outages while still providing ample margin for normal responses.


What looks good

  • Placement after cache lookup avoids unnecessary API calls
  • Fail-open design prevents the size check from breaking legitimate workflows
  • Proper use of encodeURIComponent for URL construction
  • AbortSignal.timeout() is the modern, clean approach
  • 422 status code is semantically appropriate
  • Clean separation: parsing logic stays in core library, API interaction stays in server

🤖 Generated with Claude Code

Use GITHUB_TOKEN environment variable when calling GitHub API to
increase rate limit from 60 to 5,000 requests per hour.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Apr 6, 2026

Copy link
Copy Markdown

Deploying repomix with  Cloudflare Pages  Cloudflare Pages

Latest commit: ae43543
Status: ✅  Deploy successful!
Preview URL: https://4558d743.repomix.pages.dev
Branch Preview URL: https://feat-server-github-repo-size.repomix.pages.dev

View logs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@website/server/src/domains/pack/utils/gitHubRepoSize.ts`:
- Line 1: Remove the named type import GitHubRepoInfo from the repomix import
and instead derive the type locally from parseGitHubRepoInfo; replace the import
line to only import parseGitHubRepoInfo and add a local type alias such as type
GitHubRepoInfo = NonNullable<ReturnType<typeof parseGitHubRepoInfo>> (and update
any usages in this file to use that local GitHubRepoInfo type) so the code no
longer relies on a non-exported declaration.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 4a196284-7c03-4f77-8e0c-72afaf5cd3a7

📥 Commits

Reviewing files that changed from the base of the PR and between ffe6770 and b2257d5.

📒 Files selected for processing (3)
  • src/index.ts
  • website/server/src/domains/pack/remoteRepo.ts
  • website/server/src/domains/pack/utils/gitHubRepoSize.ts

@@ -0,0 +1,70 @@
import { type GitHubRepoInfo, parseGitHubRepoInfo } from 'repomix';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "1) Verify failing import site"
rg -n "import \\{\\s*type\\s+GitHubRepoInfo\\s*,\\s*parseGitHubRepoInfo\\s*\\} from 'repomix'" --type ts

echo "2) Verify root package source re-export"
rg -n "export type \\{\\s*GitHubRepoInfo\\s*\\}" src/index.ts

echo "3) Verify source declaration/export exists"
rg -n "export (interface|type) GitHubRepoInfo" src/core/git/gitRemoteParse.ts

echo "4) If declaration files are present, verify public d.ts actually contains it"
fd -i "index.d.ts" | xargs -r rg -n "GitHubRepoInfo"

Repository: yamadashy/repomix

Length of output: 483


🏁 Script executed:

# Check if there are any TypeScript errors in the actual file
cat -n website/server/src/domains/pack/utils/gitHubRepoSize.ts

# Check if the file actually uses GitHubRepoInfo to confirm it's needed
rg -A 5 "GitHubRepoInfo" website/server/src/domains/pack/utils/gitHubRepoSize.ts

# Verify the package.json exports/types configuration
cat package.json | head -50

Repository: yamadashy/repomix

Length of output: 5778


🏁 Script executed:

# Check if lib directory and declaration file exist
ls -la lib/ 2>/dev/null | head -20 || echo "lib/ directory does not exist"

# Check if lib/index.d.ts has GitHubRepoInfo export
if [ -f lib/index.d.ts ]; then
  echo "=== Checking lib/index.d.ts for GitHubRepoInfo ==="
  rg "GitHubRepoInfo" lib/index.d.ts
else
  echo "lib/index.d.ts does not exist"
fi

# Verify tsconfig.build.json to understand what gets compiled
echo "=== tsconfig.build.json ==="
cat tsconfig.build.json 2>/dev/null | head -30

Repository: yamadashy/repomix

Length of output: 314


🏁 Script executed:

# Check website package.json to see how it imports repomix
cat website/server/package.json | grep -A 5 -B 5 "repomix" || echo "No repomix reference in website package.json"

# Check if there's a monorepo config (pnpm-workspace.yaml, lerna.json, etc.)
ls -la | grep -E "(pnpm-workspace|lerna|workspaces)"

# Check the root package.json workspaces config
cat package.json | grep -A 10 "workspaces"

Repository: yamadashy/repomix

Length of output: 513


🏁 Script executed:

# Check .gitignore to confirm lib/ is excluded
cat .gitignore | grep -E "^lib|^/lib"

# Verify: src/index.ts DOES export GitHubRepoInfo
echo "=== Verifying src/index.ts export ==="
grep -n "GitHubRepoInfo" src/index.ts

# Check src/core/git/gitRemoteParse.ts to see the actual type definition
echo "=== Type definition in source ==="
sed -n '5,20p' src/core/git/gitRemoteParse.ts

Repository: yamadashy/repomix

Length of output: 765


🏁 Script executed:

# Verify that parseGitHubRepoInfo return type allows null (to confirm NonNullable is needed)
echo "=== Check parseGitHubRepoInfo signature ==="
rg -A 5 "export.*parseGitHubRepoInfo" src/core/git/gitRemoteParse.ts | head -20

# Check if lib/index.d.ts gets regenerated during build
echo "=== Check if build script creates lib/ ==="
cat package.json | grep -A 2 '"build"'

# Verify the actual return type by checking function definition
echo "=== Full parseGitHubRepoInfo function ==="
rg -B 2 "export const parseGitHubRepoInfo" src/core/git/gitRemoteParse.ts

Repository: yamadashy/repomix

Length of output: 806


Remove GitHubRepoInfo from the repomix import and derive the type locally from parseGitHubRepoInfo.

The type GitHubRepoInfo is not exposed in the compiled declaration files (lib/index.d.ts), causing TS2305. The suggested approach using NonNullable<ReturnType<typeof parseGitHubRepoInfo>> is more robust as it derives the type directly from the function signature rather than relying on the re-export.

Suggested fix
-import { type GitHubRepoInfo, parseGitHubRepoInfo } from 'repomix';
+import { parseGitHubRepoInfo } from 'repomix';
+
+type GitHubRepoInfo = NonNullable<ReturnType<typeof parseGitHubRepoInfo>>;
🧰 Tools
🪛 GitHub Actions: autofix.ci

[error] 1-1: TypeScript (tsgo) failed with TS2305: Module 'repomix' has no exported member 'GitHubRepoInfo'.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@website/server/src/domains/pack/utils/gitHubRepoSize.ts` at line 1, Remove
the named type import GitHubRepoInfo from the repomix import and instead derive
the type locally from parseGitHubRepoInfo; replace the import line to only
import parseGitHubRepoInfo and add a local type alias such as type
GitHubRepoInfo = NonNullable<ReturnType<typeof parseGitHubRepoInfo>> (and update
any usages in this file to use that local GitHubRepoInfo type) so the code no
longer relies on a non-exported declaration.

Use a more descriptive environment variable name to clarify its purpose.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Apr 6, 2026

Copy link
Copy Markdown
Contributor

Code Review (Follow-up): feat(server): Add GitHub repository size check before processing

The previous review covered the major points well (missing tests, DI, logging, timeout). Here are additional findings worth considering.


New Findings

1. No runtime validation of data.size — silent bypass risk

In gitHubRepoSize.ts, the API response is cast without validation:

const data = (await response.json()) as GitHubRepoResponse;
return data.size;

If the GitHub API ever returns a response without a size field (schema change, unexpected response body on edge cases), data.size is undefined. Then undefined > MAX_REPO_SIZE_KB evaluates to false in JavaScript — silently bypassing the size check. This is distinct from the intentional fail-open on API errors.

Suggested fix:

const data = (await response.json()) as Record<string, unknown>;
if (typeof data.size !== 'number') return null;
return data.size;

2. Consider caching the size check result separately

Every unique (repoUrl, format, options) combination that misses the output cache independently calls the GitHub API — even for the same repository. For a popular repo requested with different format/option combinations, this burns through rate-limit tokens unnecessarily.

A lightweight size cache keyed on owner/repo with a short TTL (e.g., 5 minutes) would deduplicate these calls and reduce rate-limit pressure significantly.

3. token auth scheme is deprecated — use Bearer

headers.Authorization = `token ${token}`;

GitHub has deprecated the token scheme in favor of Bearer. While both still work, the modern form is:

headers.Authorization = `Bearer ${token}`;

4. GitHub API size excludes LFS objects

The /repos/{owner}/{repo} endpoint's size field reports the packed git object database size, excluding Git LFS objects. Repos with large binary/dataset assets stored via LFS will report a small size but consume significant resources during processing. Worth adding a brief code comment noting this limitation.

5. No observability on API failures — silent degradation

When the GitHub API returns a non-200 response (rate-limited, server error), the function silently returns null. This is correct for availability, but operators have no way to know the guard has stopped working. A logger.warn or logger.debug call when response.ok is false (especially on 429 status) would make rate-limit exhaustion visible in production logs.


Items from bot reviews evaluated

  • CodeRabbit suggested deriving GitHubRepoInfo locally instead of importing it. This is a false positive — the PR itself exports GitHubRepoInfo from the repomix package (src/index.ts line 23), so the import is valid.
  • Gemini flagged the 422 error being swallowed by the catch block. This is also a false positivecheckGitHubRepoSize is called before the try block (line 26 vs line 50 in remoteRepo.ts), so AppError propagates correctly through handlePackError.

Summary

The previous review's top items (missing tests, missing DI) remain the most important blockers. The runtime data.size validation gap (finding #1 above) is the most actionable new finding — it's a one-line fix that prevents a subtle silent bypass.

🤖 Generated with Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant