mirror of
https://github.com/anchore/syft.git
synced 2025-11-17 08:23:15 +01:00
fix tests and linting
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
This commit is contained in:
parent
d6512456b3
commit
16fb680b15
@ -10,128 +10,6 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestLinkCatalogersToConfigs(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping integration test in short mode")
|
||||
}
|
||||
|
||||
repoRoot, err := RepoRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
linkages, err := LinkCatalogersToConfigs(repoRoot)
|
||||
require.NoError(t, err)
|
||||
|
||||
// verify we discovered multiple catalogers
|
||||
require.NotEmpty(t, linkages, "should discover at least one cataloger linkage")
|
||||
|
||||
// test cases for known catalogers with configs
|
||||
// NOTE: Some catalogers may not be detected if their Name() method is in a different file
|
||||
// than the constructor function. This is a known limitation.
|
||||
tests := []struct {
|
||||
catalogerName string
|
||||
wantConfig string
|
||||
optional bool // set to true if detection may not work due to cross-file Name() methods
|
||||
}{
|
||||
{
|
||||
catalogerName: "go-module-binary-cataloger",
|
||||
wantConfig: "golang.CatalogerConfig",
|
||||
},
|
||||
{
|
||||
catalogerName: "go-module-file-cataloger",
|
||||
wantConfig: "golang.CatalogerConfig",
|
||||
},
|
||||
{
|
||||
catalogerName: "python-package-cataloger",
|
||||
wantConfig: "python.CatalogerConfig",
|
||||
},
|
||||
{
|
||||
catalogerName: "java-archive-cataloger",
|
||||
wantConfig: "java.ArchiveCatalogerConfig",
|
||||
},
|
||||
{
|
||||
catalogerName: "java-pom-cataloger",
|
||||
wantConfig: "java.ArchiveCatalogerConfig",
|
||||
optional: true, // Name() method in different file
|
||||
},
|
||||
{
|
||||
catalogerName: "dotnet-deps-binary-cataloger",
|
||||
wantConfig: "dotnet.CatalogerConfig",
|
||||
optional: true, // Name() method in different file
|
||||
},
|
||||
{
|
||||
catalogerName: "javascript-lock-cataloger",
|
||||
wantConfig: "javascript.CatalogerConfig",
|
||||
},
|
||||
{
|
||||
catalogerName: "linux-kernel-cataloger",
|
||||
wantConfig: "kernel.LinuxKernelCatalogerConfig",
|
||||
},
|
||||
{
|
||||
catalogerName: "nix-cataloger",
|
||||
wantConfig: "nix.Config",
|
||||
optional: true, // Name() method in different file
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.catalogerName, func(t *testing.T) {
|
||||
config, ok := linkages[tt.catalogerName]
|
||||
if tt.optional && !ok {
|
||||
t.Skipf("cataloger %s not detected (expected due to cross-file Name() method)", tt.catalogerName)
|
||||
return
|
||||
}
|
||||
require.True(t, ok, "should find linkage for cataloger: %s", tt.catalogerName)
|
||||
require.Equal(t, tt.wantConfig, config, "config type should match for cataloger: %s", tt.catalogerName)
|
||||
})
|
||||
}
|
||||
|
||||
// test catalogers without configs (should have empty string)
|
||||
catalogersWithoutConfig := []string{
|
||||
"python-installed-package-cataloger",
|
||||
"java-gradle-lockfile-cataloger",
|
||||
"java-jvm-cataloger",
|
||||
"dotnet-packages-lock-cataloger",
|
||||
"javascript-package-cataloger",
|
||||
}
|
||||
|
||||
for _, catalogerName := range catalogersWithoutConfig {
|
||||
t.Run(catalogerName+"_no_config", func(t *testing.T) {
|
||||
config, ok := linkages[catalogerName]
|
||||
if ok {
|
||||
require.Empty(t, config, "cataloger %s should have empty config", catalogerName)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// print summary for manual inspection
|
||||
t.Logf("Discovered %d cataloger-to-config linkages:", len(linkages))
|
||||
|
||||
// separate into catalogers with and without configs
|
||||
withConfig := make(map[string]string)
|
||||
withoutConfig := make([]string, 0)
|
||||
|
||||
for name, config := range linkages {
|
||||
if config != "" {
|
||||
withConfig[name] = config
|
||||
} else {
|
||||
withoutConfig = append(withoutConfig, name)
|
||||
}
|
||||
}
|
||||
|
||||
t.Logf("Catalogers with configs (%d):", len(withConfig))
|
||||
for name, config := range withConfig {
|
||||
t.Logf(" %s -> %s", name, config)
|
||||
}
|
||||
|
||||
t.Logf("Catalogers without configs (%d):", len(withoutConfig))
|
||||
for _, name := range withoutConfig {
|
||||
t.Logf(" %s", name)
|
||||
}
|
||||
|
||||
// ensure we found at least some catalogers with configs
|
||||
require.GreaterOrEqual(t, len(withConfig), 6, "should find at least 6 catalogers with configs")
|
||||
}
|
||||
|
||||
func TestLinkCatalogersToConfigsFromPath(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
@ -204,7 +82,7 @@ func TestLinkCatalogersToConfigsFromPath(t *testing.T) {
|
||||
name: "selector expression config",
|
||||
fixturePath: "selector-expression-config",
|
||||
expectedLinkages: map[string]string{
|
||||
"rust-cataloger": "cargo.CatalogerConfig",
|
||||
"rust-cataloger": "rust.CatalogerConfig",
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -215,8 +93,9 @@ func TestLinkCatalogersToConfigsFromPath(t *testing.T) {
|
||||
tt.wantErr = require.NoError
|
||||
}
|
||||
|
||||
fixtureDir := filepath.Join("test-fixtures", "config-linking", tt.fixturePath)
|
||||
linkages, err := LinkCatalogersToConfigsFromPath(fixtureDir, fixtureDir)
|
||||
fixtureDir := filepath.Join("testdata", "cataloger", tt.fixturePath)
|
||||
catalogerRoot := filepath.Join(fixtureDir, "cataloger")
|
||||
linkages, err := LinkCatalogersToConfigsFromPath(catalogerRoot, fixtureDir)
|
||||
tt.wantErr(t, err)
|
||||
|
||||
if err != nil {
|
||||
@ -229,51 +108,64 @@ func TestLinkCatalogersToConfigsFromPath(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestExtractConfigTypeName(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping integration test in short mode")
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
fixturePath string
|
||||
catalogerName string
|
||||
expectedConfig string
|
||||
expectedNoConfig bool
|
||||
}{
|
||||
{
|
||||
name: "golang config",
|
||||
catalogerName: "go-module-binary-cataloger",
|
||||
fixturePath: "simple-generic-cataloger",
|
||||
catalogerName: "go-module-cataloger",
|
||||
expectedConfig: "golang.CatalogerConfig",
|
||||
},
|
||||
{
|
||||
name: "python config",
|
||||
name: "python config with constant",
|
||||
fixturePath: "cataloger-with-constant",
|
||||
catalogerName: "python-package-cataloger",
|
||||
expectedConfig: "python.CatalogerConfig",
|
||||
},
|
||||
{
|
||||
name: "java archive config",
|
||||
catalogerName: "java-archive-cataloger",
|
||||
name: "java archive config same file",
|
||||
fixturePath: "custom-cataloger-same-file",
|
||||
catalogerName: "java-pom-cataloger",
|
||||
expectedConfig: "java.ArchiveCatalogerConfig",
|
||||
},
|
||||
{
|
||||
name: "kernel config",
|
||||
name: "kernel config imported type",
|
||||
fixturePath: "imported-config-type",
|
||||
catalogerName: "linux-kernel-cataloger",
|
||||
expectedConfig: "kernel.LinuxKernelCatalogerConfig",
|
||||
},
|
||||
{
|
||||
name: "python installed - no config",
|
||||
catalogerName: "python-installed-package-cataloger",
|
||||
name: "javascript - no config",
|
||||
fixturePath: "no-config-cataloger",
|
||||
catalogerName: "javascript-cataloger",
|
||||
expectedNoConfig: true,
|
||||
},
|
||||
{
|
||||
name: "ruby with mixed naming",
|
||||
fixturePath: "mixed-naming-patterns",
|
||||
catalogerName: "ruby-cataloger",
|
||||
expectedConfig: "ruby.Config",
|
||||
},
|
||||
{
|
||||
name: "rust with selector expression",
|
||||
fixturePath: "selector-expression-config",
|
||||
catalogerName: "rust-cataloger",
|
||||
expectedConfig: "rust.CatalogerConfig",
|
||||
},
|
||||
}
|
||||
|
||||
repoRoot, err := RepoRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
linkages, err := LinkCatalogersToConfigs(repoRoot)
|
||||
require.NoError(t, err)
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
fixtureDir := filepath.Join("testdata", "cataloger", tt.fixturePath)
|
||||
catalogerRoot := filepath.Join(fixtureDir, "cataloger")
|
||||
linkages, err := LinkCatalogersToConfigsFromPath(catalogerRoot, fixtureDir)
|
||||
require.NoError(t, err)
|
||||
|
||||
config, ok := linkages[tt.catalogerName]
|
||||
|
||||
if tt.expectedNoConfig {
|
||||
|
||||
@ -58,6 +58,8 @@ var observationExceptions = map[string]*strset.Set{
|
||||
"linux-kernel-cataloger": strset.New("relationships"),
|
||||
}
|
||||
|
||||
// TestCatalogersInSync ensures that all catalogers from the syft binary are documented in packages.yaml
|
||||
// and vice versa, and that all capability fields are properly filled without TODOs or null values.
|
||||
func TestCatalogersInSync(t *testing.T) {
|
||||
// get canonical list from syft binary
|
||||
catalogersInBinary := getCatalogerNamesFromBinary(t)
|
||||
@ -141,6 +143,8 @@ func validateCapabilitiesFilled(t *testing.T, catalogers []capabilities.Cataloge
|
||||
}
|
||||
}
|
||||
|
||||
// TestPackageTypeCoverage ensures that every package type defined in pkg.AllPkgs is represented in at least
|
||||
// one cataloger's capabilities, preventing orphaned package types that are defined but never documented.
|
||||
func TestPackageTypeCoverage(t *testing.T) {
|
||||
// load catalogers from embedded YAML
|
||||
catalogerEntries, err := capabilities.Packages()
|
||||
@ -184,6 +188,8 @@ func TestPackageTypeCoverage(t *testing.T) {
|
||||
missingTypesWithoutExceptions)
|
||||
}
|
||||
|
||||
// TestMetadataTypeCoverage ensures that every metadata type defined in packagemetadata.AllTypes() is represented
|
||||
// in at least one cataloger's capabilities, preventing orphaned metadata types that are defined but never produced.
|
||||
func TestMetadataTypeCoverage(t *testing.T) {
|
||||
// load catalogers from embedded YAML
|
||||
catalogerEntries, err := capabilities.Packages()
|
||||
@ -231,6 +237,9 @@ func TestMetadataTypeCoverage(t *testing.T) {
|
||||
missingTypesWithoutExceptions)
|
||||
}
|
||||
|
||||
// TestCatalogerStructure validates that catalogers follow structural conventions: generic catalogers must have
|
||||
// parsers and parser-level capabilities, custom catalogers must have detectors and cataloger-level capabilities,
|
||||
// and all catalogers must have an ecosystem set.
|
||||
func TestCatalogerStructure(t *testing.T) {
|
||||
// load catalogers from embedded YAML
|
||||
catalogerEntries, err := capabilities.Packages()
|
||||
@ -269,6 +278,8 @@ func TestCatalogerStructure(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestCatalogerDataQuality checks for data integrity issues in packages.yaml, including duplicate cataloger
|
||||
// names, duplicate parser functions within catalogers, and validates that detector definitions are well-formed.
|
||||
func TestCatalogerDataQuality(t *testing.T) {
|
||||
// load catalogers from embedded YAML
|
||||
catalogerEntries, err := capabilities.Packages()
|
||||
@ -345,7 +356,8 @@ func TestCatalogerDataQuality(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
// TestCapabilitiesAreUpToDate verifies that regeneration runs successfully
|
||||
// TestCapabilitiesAreUpToDate verifies that packages.yaml is up to date by running regeneration and checking
|
||||
// for uncommitted changes. This test only runs in CI to catch cases where code changed but capabilities weren't regenerated.
|
||||
func TestCapabilitiesAreUpToDate(t *testing.T) {
|
||||
if os.Getenv("CI") == "" {
|
||||
t.Skip("skipping regeneration test in local environment")
|
||||
@ -367,8 +379,9 @@ func TestCapabilitiesAreUpToDate(t *testing.T) {
|
||||
require.NoError(t, err, "packages.yaml has uncommitted changes after regeneration. Run 'go generate ./internal/capabilities' locally and commit the changes.")
|
||||
}
|
||||
|
||||
// TestCatalogersHaveTestObservations verifies that all catalogers have test observations,
|
||||
// ensuring they are using the pkgtest helpers
|
||||
// TestCatalogersHaveTestObservations ensures that all custom catalogers (and optionally parsers) have
|
||||
// test observations recorded in test-fixtures/test-observations.json, which proves they are using the
|
||||
// pkgtest.CatalogTester helpers and have test coverage.
|
||||
func TestCatalogersHaveTestObservations(t *testing.T) {
|
||||
repoRoot, err := RepoRoot()
|
||||
require.NoError(t, err)
|
||||
@ -486,6 +499,9 @@ func extractPackageName(catalogerName string) string {
|
||||
return catalogerName
|
||||
}
|
||||
|
||||
// TestConfigCompleteness validates the integrity of config references in packages.yaml, ensuring that all
|
||||
// configs in the configs section are referenced by at least one cataloger, all cataloger config references exist,
|
||||
// and all app-key references in config fields exist in the application section.
|
||||
func TestConfigCompleteness(t *testing.T) {
|
||||
repoRoot, err := RepoRoot()
|
||||
require.NoError(t, err)
|
||||
@ -543,6 +559,8 @@ func TestConfigCompleteness(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestAppConfigFieldsHaveDescriptions ensures that all application config fields discovered from the
|
||||
// options package have descriptions, which are required for user-facing documentation.
|
||||
func TestAppConfigFieldsHaveDescriptions(t *testing.T) {
|
||||
repoRoot, err := RepoRoot()
|
||||
require.NoError(t, err)
|
||||
@ -561,6 +579,8 @@ func TestAppConfigFieldsHaveDescriptions(t *testing.T) {
|
||||
require.Empty(t, missingDescriptions, "the following configs are missing descriptions: %v", missingDescriptions)
|
||||
}
|
||||
|
||||
// TestAppConfigKeyFormat validates that all application config keys follow the expected naming convention
|
||||
// of "ecosystem.field-name" using kebab-case (lowercase with hyphens, no underscores or spaces).
|
||||
func TestAppConfigKeyFormat(t *testing.T) {
|
||||
repoRoot, err := RepoRoot()
|
||||
require.NoError(t, err)
|
||||
@ -579,8 +599,9 @@ func TestAppConfigKeyFormat(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestCapabilityConfigFieldReferences validates that config field names referenced in CapabilitiesV2
|
||||
// conditions actually exist in the cataloger's config struct
|
||||
// TestCapabilityConfigFieldReferences validates that config field names referenced in capability conditions
|
||||
// actually exist in the cataloger's config struct, preventing typos and ensuring capability conditions can
|
||||
// be properly evaluated at runtime.
|
||||
func TestCapabilityConfigFieldReferences(t *testing.T) {
|
||||
repoRoot, err := RepoRoot()
|
||||
require.NoError(t, err)
|
||||
@ -697,7 +718,9 @@ func TestCapabilityConfigFieldReferences(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestCapabilityFieldNaming validates that capability field names follow known patterns
|
||||
// TestCapabilityFieldNaming validates that all capability field names follow known patterns
|
||||
// (e.g., "license", "dependency.depth", "package_manager.files.listing"), catching typos and ensuring
|
||||
// consistency across catalogers.
|
||||
func TestCapabilityFieldNaming(t *testing.T) {
|
||||
repoRoot, err := RepoRoot()
|
||||
require.NoError(t, err)
|
||||
@ -754,7 +777,9 @@ func TestCapabilityFieldNaming(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestCapabilityValueTypes validates that capability field values match expected types
|
||||
// TestCapabilityValueTypes validates that capability field values match their expected types based on the
|
||||
// field name (e.g., boolean fields like "license" must have bool values, array fields like "dependency.depth"
|
||||
// must have []string values), preventing type mismatches that would cause runtime errors.
|
||||
func TestCapabilityValueTypes(t *testing.T) {
|
||||
repoRoot, err := RepoRoot()
|
||||
require.NoError(t, err)
|
||||
@ -870,8 +895,9 @@ func validateCapabilityValueType(fieldPath string, value interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// TestMetadataTypesHaveJSONSchemaTypes validates that metadata_types and json_schema_types are synchronized
|
||||
// in packages.yaml - every metadata type should have a corresponding json_schema_type with correct conversion
|
||||
// TestMetadataTypesHaveJSONSchemaTypes validates that metadata_types and json_schema_types arrays are synchronized
|
||||
// in packages.yaml, ensuring every metadata type (e.g., "pkg.AlpmDBEntry") has a corresponding json_schema_type
|
||||
// (e.g., "AlpmDbEntry") with correct conversion, which is required for JSON schema generation.
|
||||
func TestMetadataTypesHaveJSONSchemaTypes(t *testing.T) {
|
||||
repoRoot, err := RepoRoot()
|
||||
require.NoError(t, err)
|
||||
@ -1230,7 +1256,8 @@ func validateFieldPath(repoRoot, structName string, fieldPath []string) error {
|
||||
}
|
||||
|
||||
// TestCapabilityEvidenceFieldReferences validates that evidence field references in capabilities
|
||||
// actually exist on their corresponding metadata structs
|
||||
// (e.g., "AlpmDBEntry.Files[].Digests") actually exist on their corresponding metadata structs by using
|
||||
// AST parsing to verify the field paths, preventing broken references when structs are refactored.
|
||||
func TestCapabilityEvidenceFieldReferences(t *testing.T) {
|
||||
repoRoot, err := RepoRoot()
|
||||
require.NoError(t, err)
|
||||
@ -1305,8 +1332,9 @@ func TestCapabilityEvidenceFieldReferences(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestDetectorConfigFieldReferences validates that config field names referenced in detector
|
||||
// conditions actually exist in the cataloger's config struct
|
||||
// TestDetectorConfigFieldReferences validates that config field names referenced in detector conditions
|
||||
// actually exist in the cataloger's config struct, ensuring that conditional detectors can properly
|
||||
// evaluate their activation conditions based on configuration.
|
||||
func TestDetectorConfigFieldReferences(t *testing.T) {
|
||||
repoRoot, err := RepoRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
@ -156,25 +156,25 @@ func extractConfigStructTypes(filePath string) ([]string, error) {
|
||||
// 1. Finding files with cataloger imports in options directory
|
||||
// 2. Extracting ecosystem config fields from Catalog struct
|
||||
// 3. Matching file structs against Catalog fields
|
||||
// Returns a map of file path to top-level YAML key
|
||||
func discoverCatalogerConfigs(repoRoot string) (map[string]string, error) {
|
||||
// Returns a map of file path to top-level YAML key and a reverse lookup map of YAML key to struct name
|
||||
func discoverCatalogerConfigs(repoRoot string) (map[string]string, map[string]string, error) {
|
||||
optionsDir := filepath.Join(repoRoot, "cmd", "syft", "internal", "options")
|
||||
catalogFilePath := filepath.Join(optionsDir, "catalog.go")
|
||||
|
||||
// get ecosystem config fields from Catalog struct
|
||||
ecosystemConfigs, err := extractEcosystemConfigFieldsFromCatalog(catalogFilePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if len(ecosystemConfigs) == 0 {
|
||||
return nil, fmt.Errorf("no ecosystem config fields found in Catalog struct")
|
||||
return nil, nil, fmt.Errorf("no ecosystem config fields found in Catalog struct")
|
||||
}
|
||||
|
||||
// find files with cataloger imports
|
||||
candidateFiles, err := findFilesWithCatalogerImports(optionsDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// match candidate files against Catalog ecosystem fields
|
||||
@ -184,7 +184,7 @@ func discoverCatalogerConfigs(repoRoot string) (map[string]string, error) {
|
||||
for _, filePath := range candidateFiles {
|
||||
structTypes, err := extractConfigStructTypes(filePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// check if any struct type matches an ecosystem config
|
||||
@ -207,17 +207,23 @@ func discoverCatalogerConfigs(repoRoot string) (map[string]string, error) {
|
||||
|
||||
if len(missingConfigs) > 0 {
|
||||
sort.Strings(missingConfigs)
|
||||
return nil, fmt.Errorf("could not find files for ecosystem configs: %s", strings.Join(missingConfigs, ", "))
|
||||
return nil, nil, fmt.Errorf("could not find files for ecosystem configs: %s", strings.Join(missingConfigs, ", "))
|
||||
}
|
||||
|
||||
return fileToKey, nil
|
||||
// build reverse lookup map (yamlKey -> structName)
|
||||
keyToStruct := make(map[string]string)
|
||||
for structName, yamlKey := range ecosystemConfigs {
|
||||
keyToStruct[yamlKey] = structName
|
||||
}
|
||||
|
||||
return fileToKey, keyToStruct, nil
|
||||
}
|
||||
|
||||
// DiscoverAppConfigs discovers all application-level cataloger configuration fields
|
||||
// from the options package
|
||||
func DiscoverAppConfigs(repoRoot string) ([]AppConfigField, error) {
|
||||
// discover cataloger config files dynamically
|
||||
configFiles, err := discoverCatalogerConfigs(repoRoot)
|
||||
configFiles, keyToStruct, err := discoverCatalogerConfigs(repoRoot)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to discover cataloger configs: %w", err)
|
||||
}
|
||||
@ -225,7 +231,7 @@ func DiscoverAppConfigs(repoRoot string) ([]AppConfigField, error) {
|
||||
// extract configuration fields from each discovered file
|
||||
var configs []AppConfigField
|
||||
for filePath, topLevelKey := range configFiles {
|
||||
fields, err := extractAppConfigFields(filePath, topLevelKey)
|
||||
fields, err := extractAppConfigFields(filePath, topLevelKey, keyToStruct)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to extract config from %s: %w", filePath, err)
|
||||
}
|
||||
@ -241,7 +247,7 @@ func DiscoverAppConfigs(repoRoot string) ([]AppConfigField, error) {
|
||||
}
|
||||
|
||||
// extractAppConfigFields extracts config fields from an options file
|
||||
func extractAppConfigFields(filePath, topLevelKey string) ([]AppConfigField, error) {
|
||||
func extractAppConfigFields(filePath, topLevelKey string, keyToStruct map[string]string) ([]AppConfigField, error) {
|
||||
fset := token.NewFileSet()
|
||||
f, err := parser.ParseFile(fset, filePath, nil, parser.ParseComments)
|
||||
if err != nil {
|
||||
@ -251,7 +257,7 @@ func extractAppConfigFields(filePath, topLevelKey string) ([]AppConfigField, err
|
||||
var configs []AppConfigField
|
||||
|
||||
// find the main config struct (not nested ones)
|
||||
configStruct, descriptions := findAppConfigStructAndDescriptions(f, topLevelKey)
|
||||
configStruct, descriptions := findAppConfigStructAndDescriptions(f, topLevelKey, keyToStruct)
|
||||
if configStruct == nil {
|
||||
return nil, fmt.Errorf("no config struct found in %s", filePath)
|
||||
}
|
||||
@ -302,26 +308,13 @@ func extractAppConfigFields(filePath, topLevelKey string) ([]AppConfigField, err
|
||||
|
||||
// findAppConfigStructAndDescriptions finds the main config struct and extracts field descriptions
|
||||
// from the DescribeFields method
|
||||
func findAppConfigStructAndDescriptions(f *ast.File, topLevelKey string) (*ast.StructType, map[string]string) {
|
||||
expectedName := determineExpectedConfigName(topLevelKey)
|
||||
configStruct := findConfigStruct(f, expectedName)
|
||||
func findAppConfigStructAndDescriptions(f *ast.File, topLevelKey string, keyToStruct map[string]string) (*ast.StructType, map[string]string) {
|
||||
structName := keyToStruct[topLevelKey]
|
||||
configStruct := findConfigStruct(f, structName)
|
||||
descriptions := extractDescriptionsFromDescribeFields(f)
|
||||
return configStruct, descriptions
|
||||
}
|
||||
|
||||
// determineExpectedConfigName maps the top-level key to the expected config struct name
|
||||
func determineExpectedConfigName(topLevelKey string) string {
|
||||
// handle special cases first
|
||||
switch topLevelKey {
|
||||
case "linux-kernel":
|
||||
return "linuxKernelConfig"
|
||||
case "javascript":
|
||||
return "javaScriptConfig"
|
||||
default:
|
||||
return topLevelKey + "Config"
|
||||
}
|
||||
}
|
||||
|
||||
// findConfigStruct searches for the config struct with the expected name in the AST
|
||||
func findConfigStruct(f *ast.File, expectedName string) *ast.StructType {
|
||||
for _, decl := range f.Decls {
|
||||
|
||||
@ -9,52 +9,6 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestDetermineExpectedConfigName(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
topLevelKey string
|
||||
wantName string
|
||||
}{
|
||||
{
|
||||
name: "linux-kernel special case",
|
||||
topLevelKey: "linux-kernel",
|
||||
wantName: "linuxKernelConfig",
|
||||
},
|
||||
{
|
||||
name: "javascript special case",
|
||||
topLevelKey: "javascript",
|
||||
wantName: "javaScriptConfig",
|
||||
},
|
||||
{
|
||||
name: "standard config golang",
|
||||
topLevelKey: "golang",
|
||||
wantName: "golangConfig",
|
||||
},
|
||||
{
|
||||
name: "standard config python",
|
||||
topLevelKey: "python",
|
||||
wantName: "pythonConfig",
|
||||
},
|
||||
{
|
||||
name: "standard config java",
|
||||
topLevelKey: "java",
|
||||
wantName: "javaConfig",
|
||||
},
|
||||
{
|
||||
name: "standard config dotnet",
|
||||
topLevelKey: "dotnet",
|
||||
wantName: "dotnetConfig",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := determineExpectedConfigName(tt.topLevelKey)
|
||||
require.Equal(t, tt.wantName, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCleanDescription(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
|
||||
@ -33,8 +33,13 @@ var appConfigAnnotationPattern = regexp.MustCompile(`^//\s*app-config:\s*(.+)$`)
|
||||
// Returns map where key is "packageName.StructName" (e.g., "golang.CatalogerConfig")
|
||||
func DiscoverConfigs(repoRoot string) (map[string]ConfigInfo, error) {
|
||||
catalogerRoot := filepath.Join(repoRoot, "syft", "pkg", "cataloger")
|
||||
return DiscoverConfigsFromPath(catalogerRoot)
|
||||
}
|
||||
|
||||
// find all .go files under syft/pkg/cataloger/ recursively
|
||||
// DiscoverConfigsFromPath walks the given directory and discovers all configuration structs
|
||||
// Returns map where key is "packageName.StructName" (e.g., "golang.CatalogerConfig")
|
||||
func DiscoverConfigsFromPath(catalogerRoot string) (map[string]ConfigInfo, error) {
|
||||
// find all .go files under the directory recursively
|
||||
var files []string
|
||||
err := filepath.Walk(catalogerRoot, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
@ -52,7 +57,7 @@ func DiscoverConfigs(repoRoot string) (map[string]ConfigInfo, error) {
|
||||
discovered := make(map[string]ConfigInfo)
|
||||
|
||||
for _, file := range files {
|
||||
configs, err := discoverConfigsInFile(file, repoRoot)
|
||||
configs, err := discoverConfigsInFile(file)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse %s: %w", file, err)
|
||||
}
|
||||
@ -68,19 +73,15 @@ func DiscoverConfigs(repoRoot string) (map[string]ConfigInfo, error) {
|
||||
return discovered, nil
|
||||
}
|
||||
|
||||
func discoverConfigsInFile(path, repoRoot string) (map[string]ConfigInfo, error) {
|
||||
func discoverConfigsInFile(path string) (map[string]ConfigInfo, error) {
|
||||
fset := token.NewFileSet()
|
||||
f, err := parser.ParseFile(fset, path, nil, parser.ParseComments)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// extract package name from file path
|
||||
relPath, err := filepath.Rel(repoRoot, path)
|
||||
if err != nil {
|
||||
relPath = path
|
||||
}
|
||||
packageName := extractPackageNameFromPath(relPath)
|
||||
// extract package name from file path (use absolute path, not relative)
|
||||
packageName := extractPackageNameFromPath(path)
|
||||
if packageName == "" {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@ -2,129 +2,131 @@ package main
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// expected config structs that should be discovered with app-config annotations
|
||||
var expectedCatalogConfigs = []string{
|
||||
func TestDiscoverConfigs(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
fixturePath string
|
||||
expectedConfigs []string
|
||||
verifyConfig func(t *testing.T, configs map[string]ConfigInfo)
|
||||
}{
|
||||
{
|
||||
name: "simple config with annotations",
|
||||
fixturePath: "simple-config",
|
||||
expectedConfigs: []string{
|
||||
"golang.CatalogerConfig",
|
||||
},
|
||||
verifyConfig: func(t *testing.T, configs map[string]ConfigInfo) {
|
||||
golangConfig := configs["golang.CatalogerConfig"]
|
||||
require.Equal(t, "golang", golangConfig.PackageName)
|
||||
require.Equal(t, "CatalogerConfig", golangConfig.StructName)
|
||||
require.Len(t, golangConfig.Fields, 3, "should have 3 annotated fields")
|
||||
|
||||
// verify specific field
|
||||
var foundSearchLocalModCache bool
|
||||
for _, field := range golangConfig.Fields {
|
||||
if field.Name == "SearchLocalModCacheLicenses" {
|
||||
foundSearchLocalModCache = true
|
||||
require.Equal(t, "bool", field.Type)
|
||||
require.Equal(t, "golang.search-local-mod-cache-licenses", field.AppKey)
|
||||
require.Contains(t, field.Description, "searching for go package licenses")
|
||||
}
|
||||
}
|
||||
require.True(t, foundSearchLocalModCache, "should find SearchLocalModCacheLicenses field")
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "nested config struct",
|
||||
fixturePath: "nested-config",
|
||||
expectedConfigs: []string{
|
||||
"golang.CatalogerConfig",
|
||||
"golang.MainModuleVersionConfig",
|
||||
"java.ArchiveCatalogerConfig",
|
||||
},
|
||||
verifyConfig: func(t *testing.T, configs map[string]ConfigInfo) {
|
||||
// verify main config
|
||||
golangConfig := configs["golang.CatalogerConfig"]
|
||||
require.Equal(t, "golang", golangConfig.PackageName)
|
||||
require.Equal(t, "CatalogerConfig", golangConfig.StructName)
|
||||
|
||||
// verify nested config
|
||||
mainModuleConfig := configs["golang.MainModuleVersionConfig"]
|
||||
require.Equal(t, "golang", mainModuleConfig.PackageName)
|
||||
require.Equal(t, "MainModuleVersionConfig", mainModuleConfig.StructName)
|
||||
require.Len(t, mainModuleConfig.Fields, 2, "should have 2 annotated fields")
|
||||
|
||||
// check for specific nested field
|
||||
var foundFromLDFlags bool
|
||||
for _, field := range mainModuleConfig.Fields {
|
||||
if field.Name == "FromLDFlags" {
|
||||
foundFromLDFlags = true
|
||||
require.Equal(t, "bool", field.Type)
|
||||
require.Equal(t, "golang.main-module-version.from-ld-flags", field.AppKey)
|
||||
require.Contains(t, field.Description, "extract version from LD flags")
|
||||
}
|
||||
}
|
||||
require.True(t, foundFromLDFlags, "should find FromLDFlags field")
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multiple configs in different packages",
|
||||
fixturePath: "multiple-configs",
|
||||
expectedConfigs: []string{
|
||||
"python.CatalogerConfig",
|
||||
"dotnet.CatalogerConfig",
|
||||
"kernel.LinuxKernelCatalogerConfig",
|
||||
"javascript.CatalogerConfig",
|
||||
"nix.Config",
|
||||
"java.ArchiveCatalogerConfig",
|
||||
},
|
||||
verifyConfig: func(t *testing.T, configs map[string]ConfigInfo) {
|
||||
// verify python config
|
||||
pythonConfig := configs["python.CatalogerConfig"]
|
||||
require.Equal(t, "python", pythonConfig.PackageName)
|
||||
require.Len(t, pythonConfig.Fields, 1)
|
||||
|
||||
// verify java config
|
||||
javaConfig := configs["java.ArchiveCatalogerConfig"]
|
||||
require.Equal(t, "java", javaConfig.PackageName)
|
||||
require.Len(t, javaConfig.Fields, 1)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "config without annotations",
|
||||
fixturePath: "no-annotations",
|
||||
expectedConfigs: []string{},
|
||||
verifyConfig: func(t *testing.T, configs map[string]ConfigInfo) {
|
||||
// should not discover any configs without annotations
|
||||
require.Empty(t, configs, "should not discover configs without app-config annotations")
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestDiscoverConfigs(t *testing.T) {
|
||||
repoRoot, err := RepoRoot()
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
fixtureDir := filepath.Join("testdata", "config-discovery", tt.fixturePath, "cataloger")
|
||||
configs, err := DiscoverConfigsFromPath(fixtureDir)
|
||||
require.NoError(t, err)
|
||||
|
||||
configs, err := DiscoverConfigs(repoRoot)
|
||||
require.NoError(t, err)
|
||||
// Debug: log what was discovered
|
||||
t.Logf("Discovered %d configs:", len(configs))
|
||||
for key, config := range configs {
|
||||
t.Logf(" %s: %d fields", key, len(config.Fields))
|
||||
}
|
||||
|
||||
// verify we discovered multiple config structs
|
||||
require.NotEmpty(t, configs, "should discover at least one config struct")
|
||||
|
||||
// check for known config structs that have app-config annotations
|
||||
for _, expected := range expectedCatalogConfigs {
|
||||
// verify expected configs were discovered
|
||||
for _, expected := range tt.expectedConfigs {
|
||||
config, ok := configs[expected]
|
||||
require.True(t, ok, "should discover config: %s", expected)
|
||||
require.NotEmpty(t, config.Fields, "config %s should have fields", expected)
|
||||
require.Equal(t, expected, config.PackageName+"."+config.StructName)
|
||||
}
|
||||
|
||||
// verify golang.CatalogerConfig structure
|
||||
golangConfig := configs["golang.CatalogerConfig"]
|
||||
wantGolangConfig := ConfigInfo{
|
||||
PackageName: "golang",
|
||||
StructName: "CatalogerConfig",
|
||||
}
|
||||
if diff := cmp.Diff(wantGolangConfig.PackageName, golangConfig.PackageName); diff != "" {
|
||||
t.Errorf("golang.CatalogerConfig.PackageName mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
if diff := cmp.Diff(wantGolangConfig.StructName, golangConfig.StructName); diff != "" {
|
||||
t.Errorf("golang.CatalogerConfig.StructName mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
require.NotEmpty(t, golangConfig.Fields)
|
||||
|
||||
// check for specific field
|
||||
var foundSearchLocalModCache bool
|
||||
for _, field := range golangConfig.Fields {
|
||||
if field.Name == "SearchLocalModCacheLicenses" {
|
||||
foundSearchLocalModCache = true
|
||||
wantField := ConfigField{
|
||||
Name: "SearchLocalModCacheLicenses",
|
||||
Type: "bool",
|
||||
AppKey: "golang.search-local-mod-cache-licenses",
|
||||
}
|
||||
if diff := cmp.Diff(wantField.Name, field.Name); diff != "" {
|
||||
t.Errorf("SearchLocalModCacheLicenses field Name mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
if diff := cmp.Diff(wantField.Type, field.Type); diff != "" {
|
||||
t.Errorf("SearchLocalModCacheLicenses field Type mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
if diff := cmp.Diff(wantField.AppKey, field.AppKey); diff != "" {
|
||||
t.Errorf("SearchLocalModCacheLicenses field AppKey mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
require.NotEmpty(t, field.Description)
|
||||
require.Contains(t, field.Description, "searching for go package licenses")
|
||||
}
|
||||
}
|
||||
require.True(t, foundSearchLocalModCache, "should find SearchLocalModCacheLicenses field")
|
||||
|
||||
// verify nested config struct
|
||||
golangMainModuleConfig := configs["golang.MainModuleVersionConfig"]
|
||||
wantMainModuleConfig := ConfigInfo{
|
||||
PackageName: "golang",
|
||||
StructName: "MainModuleVersionConfig",
|
||||
}
|
||||
if diff := cmp.Diff(wantMainModuleConfig.PackageName, golangMainModuleConfig.PackageName); diff != "" {
|
||||
t.Errorf("golang.MainModuleVersionConfig.PackageName mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
if diff := cmp.Diff(wantMainModuleConfig.StructName, golangMainModuleConfig.StructName); diff != "" {
|
||||
t.Errorf("golang.MainModuleVersionConfig.StructName mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
require.NotEmpty(t, golangMainModuleConfig.Fields)
|
||||
|
||||
// check for specific nested field
|
||||
var foundFromLDFlags bool
|
||||
for _, field := range golangMainModuleConfig.Fields {
|
||||
if field.Name == "FromLDFlags" {
|
||||
foundFromLDFlags = true
|
||||
wantField := ConfigField{
|
||||
Name: "FromLDFlags",
|
||||
Type: "bool",
|
||||
AppKey: "golang.main-module-version.from-ld-flags",
|
||||
}
|
||||
if diff := cmp.Diff(wantField.Name, field.Name); diff != "" {
|
||||
t.Errorf("FromLDFlags field Name mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
if diff := cmp.Diff(wantField.Type, field.Type); diff != "" {
|
||||
t.Errorf("FromLDFlags field Type mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
if diff := cmp.Diff(wantField.AppKey, field.AppKey); diff != "" {
|
||||
t.Errorf("FromLDFlags field AppKey mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
require.NotEmpty(t, field.Description)
|
||||
}
|
||||
}
|
||||
require.True(t, foundFromLDFlags, "should find FromLDFlags field in MainModuleVersionConfig")
|
||||
|
||||
// print summary for manual inspection
|
||||
t.Logf("Discovered %d config structs:", len(configs))
|
||||
for key, config := range configs {
|
||||
t.Logf(" %s: %d fields", key, len(config.Fields))
|
||||
for _, field := range config.Fields {
|
||||
t.Logf(" - %s (%s): %s", field.Name, field.Type, field.AppKey)
|
||||
if diff := cmp.Diff("", field.Description); diff == "" {
|
||||
t.Logf(" WARNING: field %s has no description", field.Name)
|
||||
}
|
||||
// run custom verification
|
||||
if tt.verifyConfig != nil {
|
||||
tt.verifyConfig(t, configs)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -215,14 +215,20 @@ func parseGenericCatalogerFunction(funcDecl *ast.FuncDecl, filePath, repoRoot st
|
||||
func extractPackageNameFromPath(filePath string) string {
|
||||
parts := strings.Split(filePath, string(filepath.Separator))
|
||||
|
||||
// find the index of "cataloger" in the path
|
||||
// find the LAST occurrence of "cataloger" in the path
|
||||
// (to handle test fixtures with multiple "cataloger" segments)
|
||||
lastCatalogerIndex := -1
|
||||
for i, part := range parts {
|
||||
if part == "cataloger" && i+1 < len(parts) {
|
||||
// return the next segment after "cataloger"
|
||||
return parts[i+1]
|
||||
if part == "cataloger" {
|
||||
lastCatalogerIndex = i
|
||||
}
|
||||
}
|
||||
|
||||
if lastCatalogerIndex != -1 && lastCatalogerIndex+1 < len(parts) {
|
||||
// return the next segment after the last "cataloger"
|
||||
return parts[lastCatalogerIndex+1]
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
|
||||
@ -9,52 +9,6 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// test helper functions
|
||||
|
||||
// parseFuncDecl parses a function declaration from a code string
|
||||
func parseFuncDecl(t *testing.T, code string) *ast.FuncDecl {
|
||||
t.Helper()
|
||||
fset := token.NewFileSet()
|
||||
file, err := parser.ParseFile(fset, "", "package test\n"+code, 0)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, file.Decls, 1, "expected exactly one declaration")
|
||||
funcDecl, ok := file.Decls[0].(*ast.FuncDecl)
|
||||
require.True(t, ok, "expected declaration to be a function")
|
||||
return funcDecl
|
||||
}
|
||||
|
||||
// parseCallExpr parses a call expression from a code string
|
||||
func parseCallExpr(t *testing.T, code string) *ast.CallExpr {
|
||||
t.Helper()
|
||||
expr, err := parser.ParseExpr(code)
|
||||
require.NoError(t, err)
|
||||
callExpr, ok := expr.(*ast.CallExpr)
|
||||
require.True(t, ok, "expected expression to be a call expression")
|
||||
return callExpr
|
||||
}
|
||||
|
||||
// parseCompositeLit parses a composite literal from a code string
|
||||
func parseCompositeLit(t *testing.T, code string) *ast.CompositeLit {
|
||||
t.Helper()
|
||||
expr, err := parser.ParseExpr(code)
|
||||
require.NoError(t, err)
|
||||
lit, ok := expr.(*ast.CompositeLit)
|
||||
require.True(t, ok, "expected expression to be a composite literal")
|
||||
return lit
|
||||
}
|
||||
|
||||
// parseConstDecl parses a const declaration from a code string and returns the GenDecl
|
||||
func parseConstDecl(t *testing.T, code string) *ast.GenDecl {
|
||||
t.Helper()
|
||||
fset := token.NewFileSet()
|
||||
file, err := parser.ParseFile(fset, "", "package test\n"+code, 0)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, file.Decls, 1, "expected exactly one declaration")
|
||||
genDecl, ok := file.Decls[0].(*ast.GenDecl)
|
||||
require.True(t, ok, "expected declaration to be a general declaration")
|
||||
return genDecl
|
||||
}
|
||||
|
||||
func TestReturnsPackageCataloger(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
@ -387,3 +341,49 @@ func TestResolveImportPath(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// test helper functions
|
||||
|
||||
// parseFuncDecl parses a function declaration from a code string
|
||||
func parseFuncDecl(t *testing.T, code string) *ast.FuncDecl {
|
||||
t.Helper()
|
||||
fset := token.NewFileSet()
|
||||
file, err := parser.ParseFile(fset, "", "package test\n"+code, 0)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, file.Decls, 1, "expected exactly one declaration")
|
||||
funcDecl, ok := file.Decls[0].(*ast.FuncDecl)
|
||||
require.True(t, ok, "expected declaration to be a function")
|
||||
return funcDecl
|
||||
}
|
||||
|
||||
// parseCallExpr parses a call expression from a code string
|
||||
func parseCallExpr(t *testing.T, code string) *ast.CallExpr {
|
||||
t.Helper()
|
||||
expr, err := parser.ParseExpr(code)
|
||||
require.NoError(t, err)
|
||||
callExpr, ok := expr.(*ast.CallExpr)
|
||||
require.True(t, ok, "expected expression to be a call expression")
|
||||
return callExpr
|
||||
}
|
||||
|
||||
// parseCompositeLit parses a composite literal from a code string
|
||||
func parseCompositeLit(t *testing.T, code string) *ast.CompositeLit {
|
||||
t.Helper()
|
||||
expr, err := parser.ParseExpr(code)
|
||||
require.NoError(t, err)
|
||||
lit, ok := expr.(*ast.CompositeLit)
|
||||
require.True(t, ok, "expected expression to be a composite literal")
|
||||
return lit
|
||||
}
|
||||
|
||||
// parseConstDecl parses a const declaration from a code string and returns the GenDecl
|
||||
func parseConstDecl(t *testing.T, code string) *ast.GenDecl {
|
||||
t.Helper()
|
||||
fset := token.NewFileSet()
|
||||
file, err := parser.ParseFile(fset, "", "package test\n"+code, 0)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, file.Decls, 1, "expected exactly one declaration")
|
||||
genDecl, ok := file.Decls[0].(*ast.GenDecl)
|
||||
require.True(t, ok, "expected declaration to be a general declaration")
|
||||
return genDecl
|
||||
}
|
||||
|
||||
@ -1,19 +0,0 @@
|
||||
package duplicate
|
||||
|
||||
import (
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
||||
)
|
||||
|
||||
type Config1 struct {
|
||||
Option1 bool
|
||||
}
|
||||
|
||||
func NewDuplicateCataloger1(cfg Config1) pkg.Cataloger {
|
||||
return generic.NewCataloger("duplicate-cataloger").
|
||||
WithParserByGlobs(parse1, "**/*.txt")
|
||||
}
|
||||
|
||||
func parse1(path string, reader any) ([]pkg.Package, []pkg.Relationship, error) {
|
||||
return nil, nil, nil
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
package duplicate
|
||||
|
||||
import (
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
||||
)
|
||||
|
||||
type Config2 struct {
|
||||
Option2 string
|
||||
}
|
||||
|
||||
func NewDuplicateCataloger2(cfg Config2) pkg.Cataloger {
|
||||
return generic.NewCataloger("duplicate-cataloger").
|
||||
WithParserByGlobs(parse2, "**/*.json")
|
||||
}
|
||||
|
||||
func parse2(path string, reader any) ([]pkg.Package, []pkg.Relationship, error) {
|
||||
return nil, nil, nil
|
||||
}
|
||||
@ -1,15 +0,0 @@
|
||||
package kernel
|
||||
|
||||
import (
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
||||
)
|
||||
|
||||
func NewLinuxKernelCataloger(cfg LinuxKernelCatalogerConfig) pkg.Cataloger {
|
||||
return generic.NewCataloger("linux-kernel-cataloger").
|
||||
WithParserByGlobs(parse, "**/vmlinuz")
|
||||
}
|
||||
|
||||
func parse(path string, reader any) ([]pkg.Package, []pkg.Relationship, error) {
|
||||
return nil, nil, nil
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
package ruby
|
||||
|
||||
import (
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Setting bool
|
||||
}
|
||||
|
||||
func NewRubyCataloger(opts Config) pkg.Cataloger {
|
||||
return generic.NewCataloger("ruby-cataloger").
|
||||
WithParserByGlobs(parse, "**/Gemfile")
|
||||
}
|
||||
|
||||
func parse(path string, reader any) ([]pkg.Package, []pkg.Relationship, error) {
|
||||
return nil, nil, nil
|
||||
}
|
||||
@ -1,17 +0,0 @@
|
||||
package binary
|
||||
|
||||
import (
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
||||
)
|
||||
|
||||
type Parser struct{}
|
||||
|
||||
func NewBinaryCataloger(parser Parser) pkg.Cataloger {
|
||||
return generic.NewCataloger("binary-cataloger").
|
||||
WithParserByGlobs(parse, "**/*")
|
||||
}
|
||||
|
||||
func parse(path string, reader any) ([]pkg.Package, []pkg.Relationship, error) {
|
||||
return nil, nil, nil
|
||||
}
|
||||
@ -1,16 +0,0 @@
|
||||
package rust
|
||||
|
||||
import (
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
||||
"github.com/test/cargo"
|
||||
)
|
||||
|
||||
func NewRustCataloger(cfg cargo.CatalogerConfig) pkg.Cataloger {
|
||||
return generic.NewCataloger("rust-cataloger").
|
||||
WithParserByGlobs(parse, "**/Cargo.toml")
|
||||
}
|
||||
|
||||
func parse(path string, reader any) ([]pkg.Package, []pkg.Relationship, error) {
|
||||
return nil, nil, nil
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
package golang
|
||||
|
||||
import (
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
||||
)
|
||||
|
||||
type CatalogerConfig struct {
|
||||
SomeOption bool
|
||||
}
|
||||
|
||||
func NewGoModuleCataloger(cfg CatalogerConfig) pkg.Cataloger {
|
||||
return generic.NewCataloger("go-module-cataloger").
|
||||
WithParserByGlobs(parseGoMod, "**/go.mod")
|
||||
}
|
||||
|
||||
func parseGoMod(path string, reader any) ([]pkg.Package, []pkg.Relationship, error) {
|
||||
return nil, nil, nil
|
||||
}
|
||||
@ -1,6 +1,10 @@
|
||||
package python
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
||||
)
|
||||
@ -11,11 +15,11 @@ type CatalogerConfig struct {
|
||||
Setting string
|
||||
}
|
||||
|
||||
func NewPythonCataloger(cfg CatalogerConfig) pkg.Cataloger {
|
||||
func NewPythonCataloger(_ CatalogerConfig) pkg.Cataloger {
|
||||
return generic.NewCataloger(catalogerName).
|
||||
WithParserByGlobs(parse, "**/*.py")
|
||||
}
|
||||
|
||||
func parse(path string, reader any) ([]pkg.Package, []pkg.Relationship, error) {
|
||||
func parse(_ context.Context, _ file.Resolver, _ *generic.Environment, _ file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
return nil, nil, nil
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
package duplicate1
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Option1 bool
|
||||
}
|
||||
|
||||
func NewDuplicateCataloger(_ Config) pkg.Cataloger {
|
||||
return generic.NewCataloger("duplicate-cataloger").
|
||||
WithParserByGlobs(parse, "**/*.txt")
|
||||
}
|
||||
|
||||
func parse(_ context.Context, _ file.Resolver, _ *generic.Environment, _ file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
return nil, nil, nil
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
package duplicate2
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Option2 string
|
||||
}
|
||||
|
||||
func NewDuplicateCataloger(_ Config) pkg.Cataloger {
|
||||
return generic.NewCataloger("duplicate-cataloger").
|
||||
WithParserByGlobs(parse, "**/*.json")
|
||||
}
|
||||
|
||||
func parse(_ context.Context, _ file.Resolver, _ *generic.Environment, _ file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
return nil, nil, nil
|
||||
}
|
||||
@ -1,6 +1,10 @@
|
||||
package dotnet
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
)
|
||||
|
||||
@ -18,6 +22,6 @@ func (d dotnetCataloger) Name() string {
|
||||
return catalogerName
|
||||
}
|
||||
|
||||
func (d dotnetCataloger) Catalog(resolver any) ([]pkg.Package, []pkg.Relationship, error) {
|
||||
func (d dotnetCataloger) Catalog(_ context.Context, _ file.Resolver) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
return nil, nil, nil
|
||||
}
|
||||
@ -1,6 +1,10 @@
|
||||
package java
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
)
|
||||
|
||||
@ -18,7 +22,7 @@ func (p pomXMLCataloger) Name() string {
|
||||
return pomCatalogerName
|
||||
}
|
||||
|
||||
func (p pomXMLCataloger) Catalog(resolver any) ([]pkg.Package, []pkg.Relationship, error) {
|
||||
func (p pomXMLCataloger) Catalog(_ context.Context, _ file.Resolver) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
@ -0,0 +1,19 @@
|
||||
package kernel
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
||||
)
|
||||
|
||||
func NewLinuxKernelCataloger(_ LinuxKernelCatalogerConfig) pkg.Cataloger {
|
||||
return generic.NewCataloger("linux-kernel-cataloger").
|
||||
WithParserByGlobs(parse, "**/vmlinuz")
|
||||
}
|
||||
|
||||
func parse(_ context.Context, _ file.Resolver, _ *generic.Environment, _ file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
return nil, nil, nil
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
package ruby
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Setting bool
|
||||
}
|
||||
|
||||
func NewRubyCataloger(_ Config) pkg.Cataloger {
|
||||
return generic.NewCataloger("ruby-cataloger").
|
||||
WithParserByGlobs(parse, "**/Gemfile")
|
||||
}
|
||||
|
||||
func parse(_ context.Context, _ file.Resolver, _ *generic.Environment, _ file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
return nil, nil, nil
|
||||
}
|
||||
@ -1,6 +1,10 @@
|
||||
package javascript
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
||||
)
|
||||
@ -10,6 +14,6 @@ func NewJavaScriptCataloger() pkg.Cataloger {
|
||||
WithParserByGlobs(parse, "**/*.js")
|
||||
}
|
||||
|
||||
func parse(path string, reader any) ([]pkg.Package, []pkg.Relationship, error) {
|
||||
func parse(_ context.Context, _ file.Resolver, _ *generic.Environment, _ file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
return nil, nil, nil
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
package binary
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
||||
)
|
||||
|
||||
type Parser struct{}
|
||||
|
||||
func NewBinaryCataloger(_ Parser) pkg.Cataloger {
|
||||
return generic.NewCataloger("binary-cataloger").
|
||||
WithParserByGlobs(parse, "**/*")
|
||||
}
|
||||
|
||||
func parse(_ context.Context, _ file.Resolver, _ *generic.Environment, _ file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
return nil, nil, nil
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
package rust
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
||||
)
|
||||
|
||||
// CatalogerConfig is imported from a selector expression in the real code
|
||||
type CatalogerConfig struct {
|
||||
SomeOption bool
|
||||
}
|
||||
|
||||
func NewRustCataloger(_ CatalogerConfig) pkg.Cataloger {
|
||||
return generic.NewCataloger("rust-cataloger").
|
||||
WithParserByGlobs(parse, "**/Cargo.toml")
|
||||
}
|
||||
|
||||
func parse(_ context.Context, _ file.Resolver, _ *generic.Environment, _ file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
return nil, nil, nil
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
package golang
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
||||
)
|
||||
|
||||
type CatalogerConfig struct {
|
||||
SomeOption bool
|
||||
}
|
||||
|
||||
func NewGoModuleCataloger(_ CatalogerConfig) pkg.Cataloger {
|
||||
return generic.NewCataloger("go-module-cataloger").
|
||||
WithParserByGlobs(parseGoMod, "**/go.mod")
|
||||
}
|
||||
|
||||
func parseGoMod(_ context.Context, _ file.Resolver, _ *generic.Environment, _ file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
return nil, nil, nil
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
package java
|
||||
|
||||
// ArchiveCatalogerConfig contains configuration for the java archive cataloger
|
||||
type ArchiveCatalogerConfig struct {
|
||||
// include archive contents in catalog
|
||||
// app-config: java.use-network
|
||||
UseNetwork bool
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
package python
|
||||
|
||||
// CatalogerConfig contains configuration for the python cataloger
|
||||
type CatalogerConfig struct {
|
||||
// guess unpinned python package requirements
|
||||
// app-config: python.guess-unpinned-requirements
|
||||
GuessUnpinnedRequirements bool
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
package golang
|
||||
|
||||
// MainModuleVersionConfig contains nested configuration for main module version detection
|
||||
type MainModuleVersionConfig struct {
|
||||
// extract version from LD flags
|
||||
// app-config: golang.main-module-version.from-ld-flags
|
||||
FromLDFlags bool
|
||||
|
||||
// extract version from build info
|
||||
// app-config: golang.main-module-version.from-build-info
|
||||
FromBuildInfo bool
|
||||
}
|
||||
|
||||
// CatalogerConfig contains configuration for the golang cataloger
|
||||
type CatalogerConfig struct {
|
||||
// enable searching for go package licenses in the local mod cache
|
||||
// app-config: golang.search-local-mod-cache-licenses
|
||||
SearchLocalModCacheLicenses bool
|
||||
|
||||
// main module version configuration
|
||||
MainModuleVersion MainModuleVersionConfig
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
package javascript
|
||||
|
||||
// CatalogerConfig contains configuration for the javascript cataloger (no annotations)
|
||||
type CatalogerConfig struct {
|
||||
// this field has no app-config annotation
|
||||
SearchRemoteLicenses bool
|
||||
|
||||
// this field also has no annotation
|
||||
IncludeDevDependencies bool
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package golang
|
||||
|
||||
// CatalogerConfig contains configuration for the golang cataloger
|
||||
type CatalogerConfig struct {
|
||||
// enable searching for go package licenses in the local mod cache
|
||||
// app-config: golang.search-local-mod-cache-licenses
|
||||
SearchLocalModCacheLicenses bool
|
||||
|
||||
// base URL for npm registry
|
||||
// app-config: golang.npm-base-url
|
||||
NpmBaseURL string
|
||||
|
||||
// list of globs to search for go.mod files
|
||||
// app-config: golang.search-patterns
|
||||
SearchPatterns []string
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user