mirror of
https://github.com/anchore/syft.git
synced 2026-10-30 14:02:26 +01:00
* fix(ai): use go.yaml.in/yaml/v3 to parse model card frontmatter gopkg.in/yaml.v3 panics on some malformed merge-key payloads (for example "<<:\r? 0:"), which crashed the gguf and safetensors catalogers when a model README contained such frontmatter. Switch the Hugging Face frontmatter parser to the maintained go.yaml.in/yaml/v3 fork, which is already used by the other catalogers and returns an error instead of panicking. The existing error path logs and skips the frontmatter. Fixes #5327 Signed-off-by: tk1475 <118763009+tk1475@users.noreply.github.com> Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore: finish moving off gopkg.in/yaml.v3 - move the snap catalogers and `internal/capabilities` to `go.yaml.in/yaml/v3`. The snap parsers decode yaml from scanned sources and hit the same merge-key panic as #5327 - enable `depguard` with a deny rule for `gopkg.in/yaml.v3` so it can't be reintroduced Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> --------- Signed-off-by: tk1475 <118763009+tk1475@users.noreply.github.com> Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: Alex Goodman <wagoodman@users.noreply.github.com>
133 lines
3.2 KiB
Go
133 lines
3.2 KiB
Go
// Package capabilities provides discovery and tracking of cataloger capabilities.
|
|
package capabilities
|
|
|
|
import (
|
|
"embed"
|
|
"fmt"
|
|
"io/fs"
|
|
"path/filepath"
|
|
"sort"
|
|
|
|
"github.com/scylladb/go-set/strset"
|
|
"go.yaml.in/yaml/v3"
|
|
|
|
"github.com/anchore/syft/internal/task"
|
|
)
|
|
|
|
//go:generate go run ./generate
|
|
|
|
//go:embed appconfig.yaml
|
|
var appconfigYAML []byte
|
|
|
|
var catalogerFiles *embed.FS
|
|
|
|
func RegisterCatalogerFiles(f embed.FS) {
|
|
catalogerFiles = &f
|
|
}
|
|
|
|
// LoadDocument loads and returns the complete document including configs and app-configs
|
|
func LoadDocument() (*Document, error) {
|
|
if catalogerFiles == nil {
|
|
return nil, fmt.Errorf("cataloger files not registered")
|
|
}
|
|
|
|
// parse application config
|
|
var appDoc struct {
|
|
Application []ApplicationConfigField `yaml:"application"`
|
|
}
|
|
if err := yaml.Unmarshal(appconfigYAML, &appDoc); err != nil {
|
|
return nil, fmt.Errorf("failed to parse appconfig.yaml: %w", err)
|
|
}
|
|
|
|
// walk the embedded filesystem to find all cataloger capabilities.yaml files
|
|
var catalogersDoc Document
|
|
catalogersDoc.ApplicationConfig = appDoc.Application
|
|
catalogersDoc.Configs = make(map[string]CatalogerConfigEntry)
|
|
|
|
err := fs.WalkDir(catalogerFiles, ".", func(path string, d fs.DirEntry, err error) error {
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// skip non-yaml files and directories
|
|
if d.IsDir() || filepath.Ext(path) != ".yaml" || path == "." {
|
|
return nil
|
|
}
|
|
|
|
// read the file
|
|
data, err := catalogerFiles.ReadFile(path)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to read %s: %w", path, err)
|
|
}
|
|
|
|
// parse the file
|
|
var capDoc struct {
|
|
Configs map[string]CatalogerConfigEntry `yaml:"configs"`
|
|
Catalogers []CatalogerEntry `yaml:"catalogers"`
|
|
}
|
|
if err := yaml.Unmarshal(data, &capDoc); err != nil {
|
|
return fmt.Errorf("failed to parse %s: %w", path, err)
|
|
}
|
|
|
|
// merge configs
|
|
for k, v := range capDoc.Configs {
|
|
catalogersDoc.Configs[k] = v
|
|
}
|
|
|
|
// merge catalogers
|
|
catalogersDoc.Catalogers = append(catalogersDoc.Catalogers, capDoc.Catalogers...)
|
|
|
|
return nil
|
|
})
|
|
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to walk cataloger capabilities: %w", err)
|
|
}
|
|
|
|
// sort catalogers by name for consistency
|
|
sort.Slice(catalogersDoc.Catalogers, func(i, j int) bool {
|
|
return catalogersDoc.Catalogers[i].Name < catalogersDoc.Catalogers[j].Name
|
|
})
|
|
|
|
return &catalogersDoc, nil
|
|
}
|
|
|
|
// Packages loads and returns all cataloger capabilities from the embedded YAML file
|
|
func Packages() ([]CatalogerEntry, error) {
|
|
doc, err := LoadDocument()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return doc.Catalogers, nil
|
|
}
|
|
|
|
// CatalogerInfo represents a cataloger's name and selection tags
|
|
type CatalogerInfo struct {
|
|
Name string
|
|
Selectors []string // tags for cataloger name selection
|
|
}
|
|
|
|
// ExtractCatalogerInfo extracts cataloger names and their selection tags from tasks
|
|
func ExtractCatalogerInfo(tasks []task.Task) []CatalogerInfo {
|
|
var infos []CatalogerInfo
|
|
|
|
for _, tsk := range tasks {
|
|
var selectors []string
|
|
name := tsk.Name()
|
|
|
|
if s, ok := tsk.(task.Selector); ok {
|
|
set := strset.New(s.Selectors()...)
|
|
set.Remove(name)
|
|
selectors = set.List()
|
|
sort.Strings(selectors)
|
|
}
|
|
|
|
infos = append(infos, CatalogerInfo{
|
|
Name: name,
|
|
Selectors: selectors,
|
|
})
|
|
}
|
|
|
|
return infos
|
|
}
|