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
47 changes: 37 additions & 10 deletions auth/aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,41 @@ func (p Provider) NewRESTConfig(ctx context.Context, accessTokens []auth.Token,
}, nil
}

// ParseCodeCommitURL parses an AWS CodeCommit HTTPS Git URL and returns the
// scheme+host, region, and repository name.
// Supports standard, FIPS, and China partition URLs:
//
// https://git-codecommit.{region}.amazonaws.com/v1/repos/{repository}
// https://git-codecommit-fips.{region}.amazonaws.com/v1/repos/{repository}
// https://git-codecommit.{region}.amazonaws.com.cn/v1/repos/{repository}
//
// See: https://docs.aws.amazon.com/codecommit/latest/userguide/regions.html#regions-git
func ParseCodeCommitURL(rawURL string) (host, region, repo string, err error) {
u, err := url.Parse(rawURL)
if err != nil {
return "", "", "", fmt.Errorf("invalid CodeCommit URL %q: %w", rawURL, err)
}
if !strings.EqualFold(u.Scheme, "https") {
return "", "", "", fmt.Errorf("AWS CodeCommit authentication requires an HTTPS Git URL")
}
hostname := u.Hostname()
urlSplit := strings.Split(hostname, ".")
if len(urlSplit) < 4 ||
!(strings.HasPrefix(hostname, "git-codecommit.") || strings.HasPrefix(hostname, "git-codecommit-fips.")) ||
!(strings.HasSuffix(hostname, ".amazonaws.com") || strings.HasSuffix(hostname, ".amazonaws.com.cn")) {
return "", "", "", fmt.Errorf("invalid AWS CodeCommit Git URL: %s", u.Host)
}
region = urlSplit[1]

pathParts := strings.Split(strings.TrimLeft(u.Path, "/"), "/")
if len(pathParts) != 3 || pathParts[0] != "v1" || pathParts[1] != "repos" || pathParts[2] == "" {
return "", "", "", fmt.Errorf("invalid CodeCommit URL %q: path must be /v1/repos/{repository}", rawURL)
}
repo = pathParts[2]
host = fmt.Sprintf("%s://%s", u.Scheme, u.Host)
return host, region, repo, nil
}

// getRegionFromCodeCommitURL extracts the AWS region from a CodeCommit HTTPS
// git URL (e.g. https://git-codecommit.us-east-1.amazonaws.com/...).
// Returns an error if the URL is nil, not HTTPS, or not a valid CodeCommit URL.
Expand All @@ -428,16 +463,8 @@ func getRegionFromCodeCommitURL(gitURL *url.URL) (string, error) {
if gitURL == nil {
return "", fmt.Errorf("Git URL must be specified for AWS CodeCommit authentication")
}
if !strings.EqualFold(gitURL.Scheme, "https") {
return "", fmt.Errorf("AWS CodeCommit authentication requires an HTTPS Git URL")
}
urlSplit := strings.Split(gitURL.Hostname(), ".")
if len(urlSplit) < 4 ||
!(strings.HasPrefix(gitURL.Hostname(), "git-codecommit.") || strings.HasPrefix(gitURL.Hostname(), "git-codecommit-fips.")) ||
!(strings.HasSuffix(gitURL.Hostname(), ".amazonaws.com") || strings.HasSuffix(gitURL.Hostname(), ".amazonaws.com.cn")) {
return "", fmt.Errorf("invalid AWS CodeCommit Git URL: %s", gitURL.Host)
}
return urlSplit[1], nil
_, region, _, err := ParseCodeCommitURL(gitURL.String())
return region, err
}

// GetAccessTokenOptionsForGitRepository implements auth.GitCredentialsProvider.
Expand Down
119 changes: 119 additions & 0 deletions auth/aws/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -604,6 +604,125 @@ func TestProvider_GetAccessTokenOptionsForCluster(t *testing.T) {
g.Expect(o.STSRegion).To(Equal("us-west-2"))
}

func TestParseCodeCommitURL(t *testing.T) {
for _, tt := range []struct {
name string
rawURL string
wantHost string
wantRegion string
wantRepo string
wantErr string
}{
// --- positive cases ---
{
name: "standard URL us-east-1",
rawURL: "https://git-codecommit.us-east-1.amazonaws.com/v1/repos/my-repo",
wantHost: "https://git-codecommit.us-east-1.amazonaws.com",
wantRegion: "us-east-1",
wantRepo: "my-repo",
},
{
name: "standard URL eu-west-1",
rawURL: "https://git-codecommit.eu-west-1.amazonaws.com/v1/repos/flux-repo",
wantHost: "https://git-codecommit.eu-west-1.amazonaws.com",
wantRegion: "eu-west-1",
wantRepo: "flux-repo",
},
{
name: "FIPS URL us-west-2",
rawURL: "https://git-codecommit-fips.us-west-2.amazonaws.com/v1/repos/secure-repo",
wantHost: "https://git-codecommit-fips.us-west-2.amazonaws.com",
wantRegion: "us-west-2",
wantRepo: "secure-repo",
},
{
name: "China partition URL",
rawURL: "https://git-codecommit.cn-north-1.amazonaws.com.cn/v1/repos/china-repo",
wantHost: "https://git-codecommit.cn-north-1.amazonaws.com.cn",
wantRegion: "cn-north-1",
wantRepo: "china-repo",
},
{
name: "repo name with hyphens",
rawURL: "https://git-codecommit.ap-southeast-1.amazonaws.com/v1/repos/my-great-repo-123",
wantHost: "https://git-codecommit.ap-southeast-1.amazonaws.com",
wantRegion: "ap-southeast-1",
wantRepo: "my-great-repo-123",
},
// --- negative cases: scheme ---
{
name: "HTTP scheme rejected",
rawURL: "http://git-codecommit.us-east-1.amazonaws.com/v1/repos/r",
wantErr: "AWS CodeCommit authentication requires an HTTPS Git URL",
},
{
name: "SSH scheme rejected",
rawURL: "ssh://git-codecommit.us-east-1.amazonaws.com/v1/repos/r",
wantErr: "AWS CodeCommit authentication requires an HTTPS Git URL",
},
{
name: "empty string rejected (no scheme)",
rawURL: "",
wantErr: "AWS CodeCommit authentication requires an HTTPS Git URL",
},
// --- negative cases: host ---
{
name: "non-CodeCommit host",
rawURL: "https://github.com/org/repo",
wantErr: "invalid AWS CodeCommit Git URL: github.com",
},
{
name: "codecommit-like but wrong suffix",
rawURL: "https://git-codecommit.us-east-1.example.com/v1/repos/r",
wantErr: "invalid AWS CodeCommit Git URL: git-codecommit.us-east-1.example.com",
},
// --- negative cases: path ---
{
name: "missing v1/repos prefix",
rawURL: "https://git-codecommit.us-east-1.amazonaws.com/repos/my-repo",
wantErr: `invalid CodeCommit URL "https://git-codecommit.us-east-1.amazonaws.com/repos/my-repo": path must be /v1/repos/{repository}`,
},
{
name: "empty repository name",
rawURL: "https://git-codecommit.us-east-1.amazonaws.com/v1/repos/",
wantErr: `invalid CodeCommit URL "https://git-codecommit.us-east-1.amazonaws.com/v1/repos/": path must be /v1/repos/{repository}`,
},
{
name: "path has no repo segment",
rawURL: "https://git-codecommit.us-east-1.amazonaws.com/v1/repos",
wantErr: `invalid CodeCommit URL "https://git-codecommit.us-east-1.amazonaws.com/v1/repos": path must be /v1/repos/{repository}`,
},
{
name: "extra path segments",
rawURL: "https://git-codecommit.us-east-1.amazonaws.com/v1/repos/r/extra",
wantErr: `invalid CodeCommit URL "https://git-codecommit.us-east-1.amazonaws.com/v1/repos/r/extra": path must be /v1/repos/{repository}`,
},
// --- edge cases ---
{
name: "unparseable URL",
rawURL: "://not a url",
wantErr: `invalid CodeCommit URL "://not a url":`,
},
} {
t.Run(tt.name, func(t *testing.T) {
g := NewWithT(t)
host, region, repo, err := aws.ParseCodeCommitURL(tt.rawURL)
if tt.wantErr != "" {
g.Expect(err).To(HaveOccurred())
g.Expect(err.Error()).To(ContainSubstring(tt.wantErr))
g.Expect(host).To(BeEmpty())
g.Expect(region).To(BeEmpty())
g.Expect(repo).To(BeEmpty())
} else {
g.Expect(err).NotTo(HaveOccurred())
g.Expect(host).To(Equal(tt.wantHost))
g.Expect(region).To(Equal(tt.wantRegion))
g.Expect(repo).To(Equal(tt.wantRepo))
}
})
}
}

func TestProvider_GetAccessTokenOptionsForGitRepository(t *testing.T) {
for _, tt := range []struct {
name string
Expand Down