diff --git a/pkg/skills/installer.go b/pkg/skills/installer.go index 44a08d65e..e51115faa 100644 --- a/pkg/skills/installer.go +++ b/pkg/skills/installer.go @@ -168,6 +168,36 @@ func parseGitHubRefPathParts(repoURL *url.URL, githubBaseURL string) []string { return parts[len(baseParts):] } +func isSupportedGitHubURL(repoURL *url.URL, githubBaseURL string) bool { + if repoURL == nil { + return false + } + if matchesGitHubWebBase(repoURL, "https://github.com") { + return true + } + trimmedBaseURL := strings.TrimSpace(githubBaseURL) + if trimmedBaseURL == "" { + return false + } + return matchesGitHubWebBase(repoURL, trimmedBaseURL) +} + +func matchesGitHubWebBase(repoURL *url.URL, webBaseURL string) bool { + baseURL, err := url.Parse(strings.TrimSpace(webBaseURL)) + if err != nil { + return false + } + if !strings.EqualFold(repoURL.Host, baseURL.Host) { + return false + } + basePath := strings.Trim(baseURL.Path, "/") + if basePath == "" { + return true + } + repoPath := strings.Trim(repoURL.Path, "/") + return repoPath == basePath || strings.HasPrefix(repoPath, basePath+"/") +} + func splitGitHubTreeOrBlobRefPath(parts []string, defaultRef string) (string, string) { if len(parts) == 0 { return defaultRef, "" @@ -216,6 +246,9 @@ func parseGitHubRefWithBaseURL(repo, githubBaseURL, defaultRef string) (GitHubRe if err != nil { return GitHubRef{}, fmt.Errorf("invalid URL: %w", err) } + if !isSupportedGitHubURL(u, githubBaseURL) { + return GitHubRef{}, fmt.Errorf("invalid GitHub URL host %q", u.Host) + } parts := parseGitHubRefPathParts(u, githubBaseURL) if len(parts) < 2 { return GitHubRef{}, fmt.Errorf("invalid GitHub URL") diff --git a/pkg/skills/installer_test.go b/pkg/skills/installer_test.go index 32c88ff22..0829317c4 100644 --- a/pkg/skills/installer_test.go +++ b/pkg/skills/installer_test.go @@ -89,6 +89,12 @@ func TestParseGitHubRef(t *testing.T) { wantRef: "main", wantSubPath: "", }, + { + name: "invalid non github host", + repo: "https://gitlab.com/sipeed/picoclaw/-/tree/main/skills/test", + wantErr: true, + wantErrContain: `invalid GitHub URL host "gitlab.com"`, + }, } for _, tt := range tests { @@ -182,6 +188,18 @@ func TestParseGitHubRefWithBaseURL(t *testing.T) { if ref.SubPath != ".agents/skills/pr-review" { t.Fatalf("subPath = %q, want .agents/skills/pr-review", ref.SubPath) } + + _, err = parseGitHubRefWithBaseURL( + "https://gitlab.example.com/org/repo/-/tree/dev/skills/test", + "https://ghe.example.com/git", + "main", + ) + if err == nil { + t.Fatal("parseGitHubRefWithBaseURL() error = nil, want invalid host error") + } + if !strings.Contains(err.Error(), `invalid GitHub URL host "gitlab.example.com"`) { + t.Fatalf("unexpected error = %v", err) + } } func TestSkillInstallerResolveGitHubRefUsesDefaultBranch(t *testing.T) {