diff --git a/internal/presenter/poweruser/json_document.go b/internal/presenter/poweruser/json_document.go index 642d01518..b4e930307 100644 --- a/internal/presenter/poweruser/json_document.go +++ b/internal/presenter/poweruser/json_document.go @@ -9,8 +9,9 @@ type JSONDocument struct { // here should be optional by supplying "omitempty" on these fields hint to the jsonschema generator to not // require these fields. As an accepted rule in this repo all collections should still be initialized in the // context of being used in a JSON document. - FileMetadata []JSONFileMetadata `json:"fileMetadata,omitempty"` // note: must have omitempty - Secrets []JSONSecrets `json:"secrets,omitempty"` // note: must have omitempty + FileClassifications []JSONFileClassifications `json:"fileClassifications,omitempty"` // note: must have omitempty + FileMetadata []JSONFileMetadata `json:"fileMetadata,omitempty"` // note: must have omitempty + Secrets []JSONSecrets `json:"secrets,omitempty"` // note: must have omitempty packages.JSONDocument } @@ -27,8 +28,9 @@ func NewJSONDocument(config JSONDocumentConfig) (JSONDocument, error) { } return JSONDocument{ - FileMetadata: fileMetadata, - Secrets: NewJSONSecrets(config.Secrets), - JSONDocument: pkgsDoc, + FileClassifications: NewJSONFileClassifications(config.FileClassifications), + FileMetadata: fileMetadata, + Secrets: NewJSONSecrets(config.Secrets), + JSONDocument: pkgsDoc, }, nil } diff --git a/internal/presenter/poweruser/json_document_config.go b/internal/presenter/poweruser/json_document_config.go index 606b045b7..7d9cdffc3 100644 --- a/internal/presenter/poweruser/json_document_config.go +++ b/internal/presenter/poweruser/json_document_config.go @@ -9,11 +9,12 @@ import ( ) type JSONDocumentConfig struct { - ApplicationConfig config.Application - PackageCatalog *pkg.Catalog - FileMetadata map[source.Location]source.FileMetadata - FileDigests map[source.Location][]file.Digest - Secrets map[source.Location][]file.SearchResult - Distro *distro.Distro - SourceMetadata source.Metadata + ApplicationConfig config.Application + PackageCatalog *pkg.Catalog + FileMetadata map[source.Location]source.FileMetadata + FileDigests map[source.Location][]file.Digest + FileClassifications map[source.Location][]file.Classification + Secrets map[source.Location][]file.SearchResult + Distro *distro.Distro + SourceMetadata source.Metadata } diff --git a/internal/presenter/poweruser/json_file_classifications.go b/internal/presenter/poweruser/json_file_classifications.go new file mode 100644 index 000000000..c1af9fec0 --- /dev/null +++ b/internal/presenter/poweruser/json_file_classifications.go @@ -0,0 +1,34 @@ +package poweruser + +import ( + "sort" + + "github.com/anchore/syft/syft/file" + "github.com/anchore/syft/syft/source" +) + +type JSONFileClassifications struct { + Location source.Location `json:"location"` + Classification file.Classification `json:"classification"` +} + +func NewJSONFileClassifications(data map[source.Location][]file.Classification) []JSONFileClassifications { + results := make([]JSONFileClassifications, 0) + for location, classifications := range data { + for _, classification := range classifications { + results = append(results, JSONFileClassifications{ + Location: location, + Classification: classification, + }) + } + } + + // sort by real path then virtual path to ensure the result is stable across multiple runs + sort.SliceStable(results, func(i, j int) bool { + if results[i].Location.RealPath == results[j].Location.RealPath { + return results[i].Location.VirtualPath < results[j].Location.VirtualPath + } + return results[i].Location.RealPath < results[j].Location.RealPath + }) + return results +}