fix github skill URL validation and registry JSON merging

This commit is contained in:
lxowalle 2026-04-13 00:26:22 +08:00
parent 0205dc614f
commit 0af73b1774
4 changed files with 86 additions and 5 deletions

View file

@ -328,9 +328,35 @@ func (v SecureModelList) MarshalYAML() (any, error) {
} }
func (v *SkillsRegistriesConfig) UnmarshalJSON(data []byte) error { func (v *SkillsRegistriesConfig) UnmarshalJSON(data []byte) error {
var list []*SkillRegistryConfig var list []json.RawMessage
if err := json.Unmarshal(data, &list); err == nil { if err := json.Unmarshal(data, &list); err == nil {
*v = list decodedList := make([]*SkillRegistryConfig, 0, len(list))
for _, item := range list {
var nameOnly struct {
Name string `json:"name"`
}
if err := json.Unmarshal(item, &nameOnly); err != nil {
return err
}
registry := cloneRegistryConfig(findRegistryConfigByName(*v, nameOnly.Name))
if registry == nil {
registry = &SkillRegistryConfig{Name: nameOnly.Name}
}
if err := json.Unmarshal(item, registry); err != nil {
return err
}
decodedList = append(decodedList, registry)
}
if len(*v) > 0 {
for _, registry := range decodedList {
if registry == nil {
continue
}
v.Set(registry.Name, *registry)
}
return nil
}
*v = decodedList
return nil return nil
} }
@ -345,16 +371,16 @@ func (v *SkillsRegistriesConfig) UnmarshalJSON(data []byte) error {
keys = append(keys, name) keys = append(keys, name)
} }
sort.Strings(keys) sort.Strings(keys)
list = make([]*SkillRegistryConfig, 0, len(keys)) decodedList := make([]*SkillRegistryConfig, 0, len(keys))
for _, name := range keys { for _, name := range keys {
var registry SkillRegistryConfig var registry SkillRegistryConfig
if err := json.Unmarshal(legacy[name], &registry); err != nil { if err := json.Unmarshal(legacy[name], &registry); err != nil {
return err return err
} }
registry.Name = name registry.Name = name
list = append(list, &registry) decodedList = append(decodedList, &registry)
} }
*v = list *v = decodedList
return nil return nil
} }

View file

@ -287,6 +287,29 @@ func TestSkillsRegistriesConfigUnmarshalJSONPreservesDefaultRegistries(t *testin
assert.Empty(t, github.Param) assert.Empty(t, github.Param)
} }
func TestSkillsRegistriesConfigUnmarshalJSONListPreservesDefaultRegistries(t *testing.T) {
registries := DefaultConfig().Tools.Skills.Registries
err := json.Unmarshal([]byte(`[
{
"name": "clawhub",
"base_url": "https://clawhub.example.com"
}
]`), &registries)
assert.NoError(t, err)
clawhub, ok := registries.Get("clawhub")
assert.True(t, ok)
assert.True(t, clawhub.Enabled)
assert.Equal(t, "https://clawhub.example.com", clawhub.BaseURL)
github, ok := registries.Get("github")
assert.True(t, ok)
assert.True(t, github.Enabled)
assert.Equal(t, "https://github.com", github.BaseURL)
assert.Empty(t, github.Param)
}
func TestSkillsRegistriesConfigUnmarshalYAMLAppendsNewRegistryToExistingSlice(t *testing.T) { func TestSkillsRegistriesConfigUnmarshalYAMLAppendsNewRegistryToExistingSlice(t *testing.T) {
registries := DefaultConfig().Tools.Skills.Registries registries := DefaultConfig().Tools.Skills.Registries

View file

@ -261,6 +261,14 @@ func parseGitHubRefWithBaseURL(repo, githubBaseURL, defaultRef string) (GitHubRe
if len(parts) < 2 { if len(parts) < 2 {
return GitHubRef{}, fmt.Errorf("invalid GitHub URL") return GitHubRef{}, fmt.Errorf("invalid GitHub URL")
} }
if len(parts) > 2 {
if parts[2] != "tree" && parts[2] != "blob" {
return GitHubRef{}, fmt.Errorf("invalid GitHub repository URL path %q", u.Path)
}
if len(parts) < 4 {
return GitHubRef{}, fmt.Errorf("invalid GitHub %s URL path %q", parts[2], u.Path)
}
}
ref := GitHubRef{ ref := GitHubRef{
Owner: parts[0], Owner: parts[0],
RepoName: parts[1], RepoName: parts[1],

View file

@ -234,6 +234,30 @@ func TestParseGitHubRefWithBaseURL(t *testing.T) {
if !strings.Contains(err.Error(), `invalid GitHub URL host "ghe.example.com"`) { if !strings.Contains(err.Error(), `invalid GitHub URL host "ghe.example.com"`) {
t.Fatalf("unexpected scheme mismatch error = %v", err) t.Fatalf("unexpected scheme mismatch error = %v", err)
} }
_, err = parseGitHubRefWithBaseURL(
"https://github.com/org/repo/pull/2442",
"",
"main",
)
if err == nil {
t.Fatal("parseGitHubRefWithBaseURL() error = nil, want invalid repository URL path error")
}
if !strings.Contains(err.Error(), `invalid GitHub repository URL path "/org/repo/pull/2442"`) {
t.Fatalf("unexpected PR URL error = %v", err)
}
_, err = parseGitHubRefWithBaseURL(
"https://github.com/org/repo/tree",
"",
"main",
)
if err == nil {
t.Fatal("parseGitHubRefWithBaseURL() error = nil, want invalid tree URL path error")
}
if !strings.Contains(err.Error(), `invalid GitHub tree URL path "/org/repo/tree"`) {
t.Fatalf("unexpected short tree URL error = %v", err)
}
} }
func TestSkillInstallerResolveGitHubRefUsesDefaultBranch(t *testing.T) { func TestSkillInstallerResolveGitHubRefUsesDefaultBranch(t *testing.T) {