feat(skills): add validation for skill info and test cases (#231)
Add validation logic for SkillInfo to ensure name and description meet requirements Include test cases covering various validation scenarios Add testify dependency for testing assertions
This commit is contained in:
@@ -2,13 +2,22 @@ package skills
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var namePattern = regexp.MustCompile(`^[a-zA-Z0-9]+(-[a-zA-Z0-9]+)*$`)
|
||||
|
||||
const (
|
||||
MaxNameLength = 64
|
||||
MaxDescriptionLength = 1024
|
||||
)
|
||||
|
||||
type SkillMetadata struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
@@ -21,6 +30,27 @@ type SkillInfo struct {
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
func (info SkillInfo) validate() error {
|
||||
var errs error
|
||||
if info.Name == "" {
|
||||
errs = errors.Join(errs, errors.New("name is required"))
|
||||
} else {
|
||||
if len(info.Name) > MaxNameLength {
|
||||
errs = errors.Join(errs, fmt.Errorf("name exceeds %d characters", MaxNameLength))
|
||||
}
|
||||
if !namePattern.MatchString(info.Name) {
|
||||
errs = errors.Join(errs, errors.New("name must be alphanumeric with hyphens"))
|
||||
}
|
||||
}
|
||||
|
||||
if info.Description == "" {
|
||||
errs = errors.Join(errs, errors.New("description is required"))
|
||||
} else if len(info.Description) > MaxDescriptionLength {
|
||||
errs = errors.Join(errs, fmt.Errorf("description exceeds %d character", MaxDescriptionLength))
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
type SkillsLoader struct {
|
||||
workspace string
|
||||
workspaceSkills string // workspace skills (项目级别)
|
||||
@@ -54,6 +84,11 @@ func (sl *SkillsLoader) ListSkills() []SkillInfo {
|
||||
metadata := sl.getSkillMetadata(skillFile)
|
||||
if metadata != nil {
|
||||
info.Description = metadata.Description
|
||||
info.Name = metadata.Name
|
||||
}
|
||||
if err := info.validate(); err != nil {
|
||||
slog.Warn("invalid skill from workspace", "name", info.Name, "error", err)
|
||||
continue
|
||||
}
|
||||
skills = append(skills, info)
|
||||
}
|
||||
@@ -89,6 +124,11 @@ func (sl *SkillsLoader) ListSkills() []SkillInfo {
|
||||
metadata := sl.getSkillMetadata(skillFile)
|
||||
if metadata != nil {
|
||||
info.Description = metadata.Description
|
||||
info.Name = metadata.Name
|
||||
}
|
||||
if err := info.validate(); err != nil {
|
||||
slog.Warn("invalid skill from global", "name", info.Name, "error", err)
|
||||
continue
|
||||
}
|
||||
skills = append(skills, info)
|
||||
}
|
||||
@@ -123,6 +163,11 @@ func (sl *SkillsLoader) ListSkills() []SkillInfo {
|
||||
metadata := sl.getSkillMetadata(skillFile)
|
||||
if metadata != nil {
|
||||
info.Description = metadata.Description
|
||||
info.Name = metadata.Name
|
||||
}
|
||||
if err := info.validate(); err != nil {
|
||||
slog.Warn("invalid skill from builtin", "name", info.Name, "error", err)
|
||||
continue
|
||||
}
|
||||
skills = append(skills, info)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user