| 492 | } |
| 493 | |
| 494 | func cleanFilesystemSkillRelativePath(relativePath string) (string, error) { |
| 495 | cleaned := filepath.Clean(strings.TrimSpace(relativePath)) |
| 496 | switch { |
| 497 | case cleaned == ".", cleaned == "": |
| 498 | return "", errors.New("skill file path is required") |
| 499 | case filepath.IsAbs(cleaned): |
| 500 | return "", errors.New("skill file path must be relative") |
| 501 | case cleaned == "..", strings.HasPrefix(cleaned, ".."+string(filepath.Separator)): |
| 502 | return "", errors.New("skill file path must stay within the skill directory") |
| 503 | default: |
| 504 | return cleaned, nil |
| 505 | } |
| 506 | } |
| 507 | |
| 508 | func renderSkillXML(skill *skills.Skill, content string, resources []string) (string, error) { |
| 509 | if skill == nil { |