Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions packages/billing/src/__tests__/org-billing.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -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']

Expand Down
16 changes: 12 additions & 4 deletions packages/billing/src/org-billing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -498,17 +498,25 @@ 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']
if (!allowedDomains.includes(urlObj.hostname)) {
return { isValid: false, error: 'Repository domain not allowed' }
}
Comment on lines 504 to 508
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.

P2 Duplicated domain list — simplification opportunity

allowedDomains here and knownHosts inside normalizeRepositoryUrl both hard-code the identical three values (github.com, gitlab.com, bitbucket.org). Extracting a single shared constant (e.g. ALLOWED_REPO_HOSTS) would eliminate the duplication and make future additions change-once.

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/billing/src/org-billing.ts
Line: 504-508

Comment:
**Duplicated domain list — simplification opportunity**

`allowedDomains` here and `knownHosts` inside `normalizeRepositoryUrl` both hard-code the identical three values (`github.com`, `gitlab.com`, `bitbucket.org`). Extracting a single shared constant (e.g. `ALLOWED_REPO_HOSTS`) would eliminate the duplication and make future additions change-once.

How can I resolve this? If you propose a fix, please make it concise.


// 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) {
Expand Down
Loading