allow custom git domains to support internal dns at companies

This commit is contained in:
Smartsheet-JB-Brown 2025-04-16 18:02:38 -07:00
parent c2d840cc47
commit 9a24ed46a2
2 changed files with 36 additions and 29 deletions

View file

@ -32,19 +32,18 @@ export function isValidGitRepositoryUrl(url: string): boolean {
// - https://gitlab.com/username/repo // - https://gitlab.com/username/repo
// - https://bitbucket.org/username/repo // - https://bitbucket.org/username/repo
const httpsPattern = const httpsPattern =
/^https?:\/\/(github\.com|gitlab\.com|bitbucket\.org|dev\.azure\.com)\/[a-zA-Z0-9_.-]+\/[a-zA-Z0-9_.-]+(\/.+)*(\.git)?$/ /^https?:\/\/[a-zA-Z0-9_.-]+(\.[a-zA-Z0-9_.-]+)*\/[a-zA-Z0-9_.-]+\/[a-zA-Z0-9_.-]+(\/.+)*(\.git)?$/
// SSH pattern // SSH pattern
// Examples: // Examples:
// - git@github.com:username/repo.git // - git@github.com:username/repo.git
// - git@gitlab.com:username/repo.git // - git@gitlab.com:username/repo.git
const sshPattern = /^git@(github\.com|gitlab\.com|bitbucket\.org):([a-zA-Z0-9_.-]+)\/([a-zA-Z0-9_.-]+)(\.git)?$/ const sshPattern = /^git@[a-zA-Z0-9_.-]+(\.[a-zA-Z0-9_.-]+)*:([a-zA-Z0-9_.-]+)\/([a-zA-Z0-9_.-]+)(\.git)?$/
// Git protocol pattern // Git protocol pattern
// Examples: // Examples:
// - git://github.com/username/repo.git // - git://github.com/username/repo.git
const gitProtocolPattern = const gitProtocolPattern = /^git:\/\/[a-zA-Z0-9_.-]+(\.[a-zA-Z0-9_.-]+)*\/[a-zA-Z0-9_.-]+\/[a-zA-Z0-9_.-]+(\.git)?$/
/^git:\/\/(github\.com|gitlab\.com|bitbucket\.org)\/[a-zA-Z0-9_.-]+\/[a-zA-Z0-9_.-]+(\.git)?$/
return httpsPattern.test(trimmedUrl) || sshPattern.test(trimmedUrl) || gitProtocolPattern.test(trimmedUrl) return httpsPattern.test(trimmedUrl) || sshPattern.test(trimmedUrl) || gitProtocolPattern.test(trimmedUrl)
} }
@ -85,7 +84,7 @@ export function validateSourceUrl(url: string): ValidationError[] {
if (!isValidGitRepositoryUrl(url)) { if (!isValidGitRepositoryUrl(url)) {
errors.push({ errors.push({
field: "url", field: "url",
message: "URL must be a valid Git repository URL (e.g., https://github.com/username/repo)", message: "URL must be a valid Git repository URL (e.g., https://git.example.com/username/repo)",
}) })
} }

View file

@ -12,23 +12,31 @@ import { PackageManagerSource } from "../types"
describe("PackageManagerSourceValidation", () => { describe("PackageManagerSourceValidation", () => {
describe("isValidGitRepositoryUrl", () => { describe("isValidGitRepositoryUrl", () => {
const validUrls = [ const validUrls = [
// Public Git hosting services
"https://github.com/username/repo", "https://github.com/username/repo",
"https://github.com/username/repo.git",
"https://gitlab.com/username/repo", "https://gitlab.com/username/repo",
"https://bitbucket.org/username/repo", "https://bitbucket.org/username/repo",
"git@github.com:username/repo.git",
"git@gitlab.com:username/repo.git", // Custom/self-hosted domains
"git://github.com/username/repo.git", "https://git.company.com/username/repo",
"https://git.internal.dev/username/repo.git",
"git@git.company.com:username/repo.git",
"git://git.internal.dev/username/repo.git",
// Subdomains and longer TLDs
"https://git.dev.company.co.uk/username/repo",
"git@git.dev.internal.company.com:username/repo.git",
] ]
const invalidUrls = [ const invalidUrls = [
"", "",
" ", " ",
"not-a-url", "not-a-url",
"http://invalid-domain.com/repo", "https://example.com", // Missing username/repo parts
"https://github.com", // Missing username/repo "git@example.com", // Missing repo part
"git@github.com", // Missing repo "https://git.company.com/repo", // Missing username part
"git://invalid-domain.com/repo.git", "git://example.com/repo", // Missing username part
"https://git.company.com/", // Missing both username and repo
] ]
test.each(validUrls)("should accept valid URL: %s", (url) => { test.each(validUrls)("should accept valid URL: %s", (url) => {
@ -78,7 +86,7 @@ describe("PackageManagerSourceValidation", () => {
expect(errors).toHaveLength(1) expect(errors).toHaveLength(1)
expect(errors[0]).toEqual({ expect(errors[0]).toEqual({
field: "url", field: "url",
message: "URL must be a valid Git repository URL (e.g., https://github.com/username/repo)", message: "URL must be a valid Git repository URL (e.g., https://git.example.com/username/repo)",
}) })
}) })
}) })
@ -115,13 +123,13 @@ describe("PackageManagerSourceValidation", () => {
describe("validateSourceDuplicates", () => { describe("validateSourceDuplicates", () => {
const existingSources: PackageManagerSource[] = [ const existingSources: PackageManagerSource[] = [
{ url: "https://github.com/user1/repo1", name: "Source 1", enabled: true }, { url: "https://git.company.com/user1/repo1", name: "Source 1", enabled: true },
{ url: "https://github.com/user2/repo2", name: "Source 2", enabled: true }, { url: "https://git.company.com/user2/repo2", name: "Source 2", enabled: true },
] ]
test("should accept unique sources", () => { test("should accept unique sources", () => {
const newSource: PackageManagerSource = { const newSource: PackageManagerSource = {
url: "https://github.com/user3/repo3", url: "https://git.company.com/user3/repo3",
name: "Source 3", name: "Source 3",
enabled: true, enabled: true,
} }
@ -131,7 +139,7 @@ describe("PackageManagerSourceValidation", () => {
test("should reject duplicate URLs (case insensitive)", () => { test("should reject duplicate URLs (case insensitive)", () => {
const newSource: PackageManagerSource = { const newSource: PackageManagerSource = {
url: "HTTPS://GITHUB.COM/USER1/REPO1", url: "HTTPS://GIT.COMPANY.COM/USER1/REPO1",
name: "Different Name", name: "Different Name",
enabled: true, enabled: true,
} }
@ -143,7 +151,7 @@ describe("PackageManagerSourceValidation", () => {
test("should reject duplicate names (case insensitive)", () => { test("should reject duplicate names (case insensitive)", () => {
const newSource: PackageManagerSource = { const newSource: PackageManagerSource = {
url: "https://github.com/user3/repo3", url: "https://git.company.com/user3/repo3",
name: "SOURCE 1", name: "SOURCE 1",
enabled: true, enabled: true,
} }
@ -155,9 +163,9 @@ describe("PackageManagerSourceValidation", () => {
test("should detect duplicates within source list", () => { test("should detect duplicates within source list", () => {
const sourcesWithDuplicates: PackageManagerSource[] = [ const sourcesWithDuplicates: PackageManagerSource[] = [
{ url: "https://github.com/user1/repo1", name: "Source 1", enabled: true }, { url: "https://git.company.com/user1/repo1", name: "Source 1", enabled: true },
{ url: "https://github.com/user1/repo1", name: "Source 2", enabled: true }, // Duplicate URL { url: "https://git.company.com/user1/repo1", name: "Source 2", enabled: true }, // Duplicate URL
{ url: "https://github.com/user3/repo3", name: "Source 1", enabled: true }, // Duplicate name { url: "https://git.company.com/user3/repo3", name: "Source 1", enabled: true }, // Duplicate name
] ]
const errors = validateSourceDuplicates(sourcesWithDuplicates) const errors = validateSourceDuplicates(sourcesWithDuplicates)
expect(errors).toHaveLength(4) // Two URL duplicates (bidirectional) and two name duplicates (bidirectional) expect(errors).toHaveLength(4) // Two URL duplicates (bidirectional) and two name duplicates (bidirectional)
@ -178,12 +186,12 @@ describe("PackageManagerSourceValidation", () => {
describe("validateSource", () => { describe("validateSource", () => {
const existingSources: PackageManagerSource[] = [ const existingSources: PackageManagerSource[] = [
{ url: "https://github.com/user1/repo1", name: "Source 1", enabled: true }, { url: "https://git.company.com/user1/repo1", name: "Source 1", enabled: true },
] ]
test("should accept valid source", () => { test("should accept valid source", () => {
const source: PackageManagerSource = { const source: PackageManagerSource = {
url: "https://github.com/user2/repo2", url: "https://git.company.com/user2/repo2",
name: "Source 2", name: "Source 2",
enabled: true, enabled: true,
} }
@ -193,7 +201,7 @@ describe("PackageManagerSourceValidation", () => {
test("should accumulate multiple validation errors", () => { test("should accumulate multiple validation errors", () => {
const source: PackageManagerSource = { const source: PackageManagerSource = {
url: "https://github.com/user1/repo1", // Duplicate URL url: "https://git.company.com/user1/repo1", // Duplicate URL
name: "This name is way too long to be valid\t", // Too long and has tab name: "This name is way too long to be valid\t", // Too long and has tab
enabled: true, enabled: true,
} }
@ -205,8 +213,8 @@ describe("PackageManagerSourceValidation", () => {
describe("validateSources", () => { describe("validateSources", () => {
test("should accept valid source list", () => { test("should accept valid source list", () => {
const sources: PackageManagerSource[] = [ const sources: PackageManagerSource[] = [
{ url: "https://github.com/user1/repo1", name: "Source 1", enabled: true }, { url: "https://git.company.com/user1/repo1", name: "Source 1", enabled: true },
{ url: "https://github.com/user2/repo2", name: "Source 2", enabled: true }, { url: "https://git.company.com/user2/repo2", name: "Source 2", enabled: true },
] ]
const errors = validateSources(sources) const errors = validateSources(sources)
expect(errors).toHaveLength(0) expect(errors).toHaveLength(0)
@ -214,8 +222,8 @@ describe("PackageManagerSourceValidation", () => {
test("should detect multiple issues across sources", () => { test("should detect multiple issues across sources", () => {
const sources: PackageManagerSource[] = [ const sources: PackageManagerSource[] = [
{ url: "https://github.com/user1/repo1", name: "Source 1", enabled: true }, { url: "https://git.company.com/user1/repo1", name: "Source 1", enabled: true },
{ url: "https://github.com/user1/repo1", name: "Source 1", enabled: true }, // Duplicate URL and name { url: "https://git.company.com/user1/repo1", name: "Source 1", enabled: true }, // Duplicate URL and name
{ url: "invalid-url", name: "This name is way too long\t", enabled: true }, // Invalid URL and name { url: "invalid-url", name: "This name is way too long\t", enabled: true }, // Invalid URL and name
] ]
const errors = validateSources(sources) const errors = validateSources(sources)