| package bundle |
|
|
| import ( |
| "path" |
| "strings" |
| ) |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| type IndirectionAnalyzer struct{} |
|
|
| func (IndirectionAnalyzer) Name() string { return "indirection" } |
|
|
| func (IndirectionAnalyzer) Handles(kind FileKind) bool { return kind == KindSkillMd } |
|
|
| |
| |
| var indirectionVerbs = []string{ |
| "run", "execute", "exec", "source", "invoke", "launch", "call", |
| "read", "open", "follow", "load", "import", "apply", "use", |
| "see", "refer to", "process", "parse", "handles the rest", |
| "steps in", "instructions in", "as described in", "build", "compile", |
| } |
|
|
| func (IndirectionAnalyzer) Analyze(f *File, b *Bundle) ([]Finding, error) { |
| if f == nil || b == nil || b.Skill == nil { |
| return nil, nil |
| } |
|
|
| corpus := strings.ToLower(b.Skill.Body + "\n" + b.Skill.Description + "\n" + strings.Join(b.Skill.Triggers, "\n")) |
|
|
| var out []Finding |
| for _, sib := range b.Files { |
| if sib == nil { |
| continue |
| } |
| if !sib.Referenced && !delegationMentions(corpus, sib) { |
| continue |
| } |
|
|
| |
| if sib.IsSymlink && (sib.SymlinkEscapes || isExecutableKind(targetKind(sib))) { |
| out = append(out, Finding{ |
| Analyzer: "indirection", |
| File: sib.RelPath, |
| Signal: "symlinked-executable-reference", |
| Severity: SevHigh, |
| Detail: "SKILL.md references a symlink to an executable/out-of-bundle target: " + sib.SymlinkTarget, |
| Corroborated: true, |
| }) |
| continue |
| } |
|
|
| switch sib.Kind { |
| case KindShell, KindPythonSource, KindScriptOther, KindArchive, KindNativeBinary, KindWasm, KindPyc: |
| |
| |
| corroborated := targetHasBehavior(b, sib) |
| out = append(out, Finding{ |
| Analyzer: "indirection", |
| File: sib.RelPath, |
| Signal: "delegates-to-bundled-script", |
| Severity: SevHigh, |
| Detail: "SKILL.md delegates execution to a bundled " + sib.Kind.String() + " file", |
| Structural: true, |
| Corroborated: corroborated, |
| }) |
| case KindData, KindText: |
| |
| |
| |
| |
| |
| |
| |
| corroborated := targetHasBehavior(b, sib) |
| out = append(out, Finding{ |
| Analyzer: "indirection", |
| File: sib.RelPath, |
| Signal: "delegates-to-data", |
| Severity: SevHigh, |
| Detail: "SKILL.md delegates to a bundled data file (instructions inside it execute)", |
| Structural: true, |
| Corroborated: corroborated, |
| }) |
| case KindImage: |
| |
| |
| |
| corroborated := targetHasBehavior(b, sib) |
| out = append(out, Finding{ |
| Analyzer: "indirection", |
| File: sib.RelPath, |
| Signal: "delegates-to-image", |
| Severity: SevHigh, |
| Detail: "SKILL.md delegates to a bundled image (a multimodal agent reads its embedded steps)", |
| Structural: true, |
| Corroborated: corroborated, |
| }) |
| case KindMarkdown: |
| |
| default: |
| |
| out = append(out, Finding{ |
| Analyzer: "indirection", |
| File: sib.RelPath, |
| Signal: "references-unscanned-filetype", |
| Severity: SevHigh, |
| Detail: "SKILL.md references a sibling whose type no content analyzer can inspect", |
| Structural: true, |
| Corroborated: false, |
| }) |
| } |
| } |
|
|
| return dedupeFindings(out), nil |
| } |
|
|
| |
| |
| |
| func delegationMentions(corpus string, sib *File) bool { |
| base := strings.ToLower(path.Base(sib.RelPath)) |
| rel := strings.ToLower(sib.RelPath) |
| if base == "" { |
| return false |
| } |
| for _, form := range []string{base, rel, "./" + base, "`" + base + "`"} { |
| idx := strings.Index(corpus, form) |
| for idx >= 0 { |
| if nearIndirectionVerb(corpus, idx) { |
| return true |
| } |
| next := strings.Index(corpus[idx+1:], form) |
| if next < 0 { |
| break |
| } |
| idx = idx + 1 + next |
| } |
| } |
| return false |
| } |
|
|
| |
| |
| func nearIndirectionVerb(corpus string, idx int) bool { |
| start := idx - 80 |
| if start < 0 { |
| start = 0 |
| } |
| window := corpus[start:idx] |
| |
| if strings.HasSuffix(strings.TrimRight(window, " "), "(") || |
| strings.Contains(window, "](") || strings.Contains(window, "`") { |
| return true |
| } |
| return matchedAny(window, indirectionVerbs) |
| } |
|
|
| |
| |
| |
| func targetHasBehavior(b *Bundle, target *File) bool { |
| findings := AnalyzeFile(target, b) |
| for _, fnd := range findings { |
| if fnd.Structural { |
| continue |
| } |
| if fnd.Severity >= SevHigh || fnd.Corroborated { |
| return true |
| } |
| } |
| return false |
| } |
|
|
| |
| |
| |
| func targetFindingExists(b *Bundle, target *File, all []Finding) bool { |
| if target == nil { |
| return false |
| } |
| for _, fnd := range all { |
| if fnd.File != target.RelPath { |
| continue |
| } |
| if fnd.Structural { |
| continue |
| } |
| if fnd.Severity >= SevHigh || fnd.Corroborated { |
| return true |
| } |
| } |
| return false |
| } |
|
|
| |
| |
| |
| func targetKind(sib *File) FileKind { |
| return sib.Kind |
| } |
|
|
| func isExecutableKind(k FileKind) bool { |
| switch k { |
| case KindShell, KindPythonSource, KindScriptOther, KindPyc, KindNativeBinary, KindWasm: |
| return true |
| default: |
| return false |
| } |
| } |
|
|