syft/internal/capabilities/internal/load_capabilities.go
dependabot[bot] 3ea6a03cd0
chore(deps): bump the go-minor-patch group with 3 updates (#4524)
* chore(deps): bump the go-minor-patch group with 3 updates

Bumps the go-minor-patch group with 3 updates: [github.com/BurntSushi/toml](https://github.com/BurntSushi/toml), [github.com/go-git/go-git/v5](https://github.com/go-git/go-git) and [github.com/invopop/jsonschema](https://github.com/invopop/jsonschema).


Updates `github.com/BurntSushi/toml` from 1.5.0 to 1.6.0
- [Release notes](https://github.com/BurntSushi/toml/releases)
- [Commits](https://github.com/BurntSushi/toml/compare/v1.5.0...v1.6.0)

Updates `github.com/go-git/go-git/v5` from 5.16.3 to 5.16.4
- [Release notes](https://github.com/go-git/go-git/releases)
- [Commits](https://github.com/go-git/go-git/compare/v5.16.3...v5.16.4)

Updates `github.com/invopop/jsonschema` from 0.7.0 to 0.13.0
- [Commits](https://github.com/invopop/jsonschema/compare/v0.7.0...v0.13.0)

---
updated-dependencies:
- dependency-name: github.com/BurntSushi/toml
  dependency-version: 1.6.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: go-minor-patch
- dependency-name: github.com/go-git/go-git/v5
  dependency-version: 5.16.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: go-minor-patch
- dependency-name: github.com/invopop/jsonschema
  dependency-version: 0.13.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: go-minor-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* port breaking jsonschema lib changes

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* regenerate the existing json schema with new generation code

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Alex Goodman <wagoodman@users.noreply.github.com>
2026-01-06 15:25:43 +00:00

95 lines
3.0 KiB
Go

package internal
import (
"fmt"
"os"
"path/filepath"
"gopkg.in/yaml.v3"
"github.com/anchore/syft/internal/capabilities"
)
// LoadCapabilities loads the capabilities document from a YAML file.
// Returns both the parsed document and the original YAML node tree to preserve comments.
// Exported for use by the generator in generate/main.go
func LoadCapabilities(catalogerDir, repoRoot string) (*capabilities.Document, map[string]*yaml.Node, error) {
// load all cataloger/*/capabilities.yaml files
files, err := filepath.Glob(filepath.Join(catalogerDir, "*", CapabilitiesFilename))
if err != nil {
return nil, nil, fmt.Errorf("failed to glob capabilities files: %w", err)
}
mergedDoc := &capabilities.Document{
Configs: make(map[string]capabilities.CatalogerConfigEntry),
Catalogers: []capabilities.CatalogerEntry{},
}
nodeMap := make(map[string]*yaml.Node)
// load each package file
for _, file := range files {
data, err := os.ReadFile(file)
if err != nil {
return nil, nil, fmt.Errorf("failed to read %s: %w", file, err)
}
// parse into node tree to preserve comments
var rootNode yaml.Node
if err := yaml.Unmarshal(data, &rootNode); err != nil {
return nil, nil, fmt.Errorf("failed to parse %s into node tree: %w", file, err)
}
// parse into struct
var doc struct {
Configs map[string]capabilities.CatalogerConfigEntry `yaml:"configs"`
Catalogers []capabilities.CatalogerEntry `yaml:"catalogers"`
}
if err := yaml.Unmarshal(data, &doc); err != nil {
fmt.Printf("\n=== DEBUG: YAML Parse Error in %s ===\n", file)
fmt.Printf("Error: %v\n\n", err)
fmt.Printf("=== FULL FILE CONTENT ===\n%s\n=== END FILE ===\n", string(data))
return nil, nil, fmt.Errorf("failed to parse %s into struct: %w", file, err)
}
// merge configs
for k, v := range doc.Configs {
mergedDoc.Configs[k] = v
}
// merge catalogers
mergedDoc.Catalogers = append(mergedDoc.Catalogers, doc.Catalogers...)
// store node tree by ecosystem directory name
// path is like "/path/to/syft/pkg/cataloger/alpine/capabilities.yaml"
ecosystem := filepath.Base(filepath.Dir(file))
nodeMap[ecosystem] = &rootNode
}
// load appconfig.yaml separately (from internal/capabilities/)
appconfigPath := AppconfigPath(repoRoot)
if _, err := os.Stat(appconfigPath); err == nil {
data, err := os.ReadFile(appconfigPath)
if err != nil {
return nil, nil, fmt.Errorf("failed to read appconfig.yaml: %w", err)
}
var appDoc struct {
Application []capabilities.ApplicationConfigField `yaml:"application"`
}
if err := yaml.Unmarshal(data, &appDoc); err != nil {
return nil, nil, fmt.Errorf("failed to parse appconfig.yaml: %w", err)
}
mergedDoc.ApplicationConfig = appDoc.Application
// load node tree for appconfig
var appNode yaml.Node
if err := yaml.Unmarshal(data, &appNode); err != nil {
return nil, nil, fmt.Errorf("failed to parse appconfig.yaml into node tree: %w", err)
}
nodeMap["appconfig"] = &appNode
}
return mergedDoc, nodeMap, nil
}