diff --git a/packages/billing/src/__tests__/org-billing.test.ts b/packages/billing/src/__tests__/org-billing.test.ts index 6f3dfa16e..7a4262b70 100644 --- a/packages/billing/src/__tests__/org-billing.test.ts +++ b/packages/billing/src/__tests__/org-billing.test.ts @@ -190,6 +190,15 @@ describe('Organization Billing', () => { expect(result.error).toBeUndefined() }) + it('should validate and normalize SSH URLs', () => { + const result = validateAndNormalizeRepositoryUrl( + 'git@github.com:user/repo.git', + ) + expect(result.isValid).toBe(true) + expect(result.normalizedUrl).toBe('https://github.com/user/repo') + expect(result.error).toBeUndefined() + }) + it('should reject invalid domains', () => { const result = validateAndNormalizeRepositoryUrl( 'https://example.com/user/repo', @@ -204,6 +213,12 @@ describe('Organization Billing', () => { expect(result.error).toBe('Repository domain not allowed') }) + it('should reject URLs without owner and repo path segments', () => { + const result = validateAndNormalizeRepositoryUrl('https://github.com') + expect(result.isValid).toBe(false) + expect(result.error).toBe('Repository path must include owner and repo') + }) + it('should accept allowed domains', () => { const domains = ['github.com', 'gitlab.com', 'bitbucket.org'] diff --git a/packages/billing/src/org-billing.ts b/packages/billing/src/org-billing.ts index 6740b9410..8035da13e 100644 --- a/packages/billing/src/org-billing.ts +++ b/packages/billing/src/org-billing.ts @@ -498,8 +498,8 @@ export function validateAndNormalizeRepositoryUrl(url: string): { error?: string } { try { - // Basic URL validation - const urlObj = new URL(url.startsWith('http') ? url : `https://${url}`) + const normalized = normalizeRepositoryUrl(url) + const urlObj = new URL(normalized) // Whitelist allowed domains const allowedDomains = ['github.com', 'gitlab.com', 'bitbucket.org'] @@ -507,8 +507,16 @@ export function validateAndNormalizeRepositoryUrl(url: string): { return { isValid: false, error: 'Repository domain not allowed' } } - // Normalize URL format - const normalized = normalizeRepositoryUrl(url) + const pathSegments = urlObj.pathname + .split('/') + .filter((segment) => segment.length > 0) + + if (pathSegments.length < 2) { + return { + isValid: false, + error: 'Repository path must include owner and repo', + } + } return { isValid: true, normalizedUrl: normalized } } catch (error) {