Skip to content

Commit c01f36d

Browse files
authored
fix(api): validate GitHub usernames before downstream API requests (JhaSourav07#1852)
## Description Fixes JhaSourav07#1782 This PR fixes an issue where the `/api/github` endpoint accepted malformed GitHub usernames and allowed them to reach the GitHub API layer, resulting in downstream fetch errors instead of validation failures. ### Changes Made * Added GitHub username validation to `githubParamsSchema` * Rejects usernames containing invalid characters * Rejects whitespace-only usernames * Rejects usernames exceeding GitHub's maximum length limit * Added regression tests covering all of the above scenarios ### Validation Verified that invalid usernames now return a `400 Bad Request` response during request validation rather than triggering downstream GitHub API errors. ## Pillar * [ ] 🎨 Pillar 1 — New Theme Design * [ ] 📐 Pillar 2 — Geometric SVG Improvement * [ ] 🕐 Pillar 3 — Timezone Logic Optimization * [x] 🛠️ Other (Bug fix, refactoring, docs) ## Visual Preview N/A (API validation bug fix) ## Checklist before requesting a review: * [x] I have read the `CONTRIBUTING.md` file. * [x] I have tested these changes locally (`localhost:3000/api/github?username=octocat` and invalid username cases). * [x] I have run `npm run lint` locally and resolved all errors related to my changes. * [x] My commits follow the Conventional Commits format (e.g., `feat(themes): ...`, `fix(calculate): ...`). * [ ] I have updated `README.md` if I added a new theme or URL parameter. * [x] I have starred the repo. * [x] I have made sure that I have only one commit to merge in this PR. * [ ] The SVG output matches the CommitPulse "premium quality" aesthetic standard (not applicable). * [x] (Recommended) I joined the CommitPulse Discord community for contributor discussions, mentorship, and faster PR support.
2 parents 0e7609b + 793a543 commit c01f36d

2 files changed

Lines changed: 31 additions & 1 deletion

File tree

app/api/github/route.test.ts

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,37 @@ describe('GET /api/github', () => {
3030

3131
it('calls getFullDashboardData with { bypassCache: false } when refresh is omitted', async () => {
3232
await GET(makeRequest({ username: 'octocat' }));
33+
expect(getFullDashboardData).toHaveBeenCalledWith('octocat', {
34+
bypassCache: false,
35+
});
36+
});
37+
it('returns 400 when username contains invalid characters', async () => {
38+
const response = await GET(makeRequest({ username: '@@@@@' }));
39+
const body = await response.json();
3340

34-
expect(getFullDashboardData).toHaveBeenCalledWith('octocat', { bypassCache: false });
41+
expect(response.status).toBe(400);
42+
expect(body.error).toContain('Invalid parameters');
43+
});
44+
45+
it('returns 400 when username contains only whitespace', async () => {
46+
const response = await GET(makeRequest({ username: ' ' }));
47+
const body = await response.json();
48+
49+
expect(response.status).toBe(400);
50+
expect(body.error).toContain('Invalid parameters');
51+
});
52+
53+
it('returns 400 when username exceeds GitHub maximum length', async () => {
54+
const response = await GET(
55+
makeRequest({
56+
username: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
57+
})
58+
);
59+
60+
const body = await response.json();
61+
62+
expect(response.status).toBe(400);
63+
expect(body.error).toContain('Invalid parameters');
3564
});
3665

3766
// Test 1 — missing username → 400

lib/validations.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ export const streakParamsSchema = z.object({
245245
export const githubParamsSchema = z.object({
246246
username: z
247247
.string({ error: 'Missing "username" parameter' })
248+
.trim()
248249
.min(1, { message: 'Username is required' })
249250
.max(39, { message: 'GitHub username cannot exceed 39 characters' })
250251
.regex(GITHUB_USERNAME_REGEX, {

0 commit comments

Comments
 (0)