mirror of
https://github.com/anchore/syft.git
synced 2025-11-17 16:33:21 +01:00
add power-user specific fields to syft-json format
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
This commit is contained in:
parent
a3a13b4fe3
commit
7640df99c8
@ -4,10 +4,12 @@ package model
|
|||||||
type Document struct {
|
type Document struct {
|
||||||
Artifacts []Package `json:"artifacts"` // Artifacts is the list of packages discovered and placed into the catalog
|
Artifacts []Package `json:"artifacts"` // Artifacts is the list of packages discovered and placed into the catalog
|
||||||
ArtifactRelationships []Relationship `json:"artifactRelationships"`
|
ArtifactRelationships []Relationship `json:"artifactRelationships"`
|
||||||
Source Source `json:"source"` // Source represents the original object that was cataloged
|
Files []File `json:"files,omitempty"` // note: must have omitempty
|
||||||
Distro Distro `json:"distro"` // Distro represents the Linux distribution that was detected from the source
|
Secrets []Secrets `json:"secrets,omitempty"` // note: must have omitempty
|
||||||
Descriptor Descriptor `json:"descriptor"` // Descriptor is a block containing self-describing information about syft
|
Source Source `json:"source"` // Source represents the original object that was cataloged
|
||||||
Schema Schema `json:"schema"` // Schema is a block reserved for defining the version for the shape of this JSON document and where to find the schema document to validate the shape
|
Distro Distro `json:"distro"` // Distro represents the Linux distribution that was detected from the source
|
||||||
|
Descriptor Descriptor `json:"descriptor"` // Descriptor is a block containing self-describing information about syft
|
||||||
|
Schema Schema `json:"schema"` // Schema is a block reserved for defining the version for the shape of this JSON document and where to find the schema document to validate the shape
|
||||||
}
|
}
|
||||||
|
|
||||||
// Descriptor describes what created the document as well as surrounding metadata
|
// Descriptor describes what created the document as well as surrounding metadata
|
||||||
|
|||||||
25
internal/formats/syftjson/model/file.go
Normal file
25
internal/formats/syftjson/model/file.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/anchore/syft/syft/file"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft/source"
|
||||||
|
)
|
||||||
|
|
||||||
|
type File struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Location source.Coordinates `json:"location"`
|
||||||
|
Metadata *FileMetadataEntry `json:"metadata,omitempty"`
|
||||||
|
Contents string `json:"contents,omitempty"`
|
||||||
|
Digests []file.Digest `json:"digests,omitempty"`
|
||||||
|
Classifications []file.Classification `json:"classifications,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type FileMetadataEntry struct {
|
||||||
|
Mode int `json:"mode"`
|
||||||
|
Type source.FileType `json:"type"`
|
||||||
|
LinkDestination string `json:"linkDestination,omitempty"`
|
||||||
|
UserID int `json:"userID"`
|
||||||
|
GroupID int `json:"groupID"`
|
||||||
|
MIMEType string `json:"mimeType"`
|
||||||
|
}
|
||||||
@ -9,7 +9,7 @@ import (
|
|||||||
"github.com/anchore/syft/syft/source"
|
"github.com/anchore/syft/syft/source"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Package represents a pkg.Package object specialized for JSON marshaling and unmarshaling.
|
// Package represents a pkg.Package object specialized for JSON marshaling and unmarshalling.
|
||||||
type Package struct {
|
type Package struct {
|
||||||
PackageBasicData
|
PackageBasicData
|
||||||
PackageCustomData
|
PackageCustomData
|
||||||
|
|||||||
@ -4,5 +4,5 @@ type Relationship struct {
|
|||||||
Parent string `json:"parent"`
|
Parent string `json:"parent"`
|
||||||
Child string `json:"child"`
|
Child string `json:"child"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Metadata interface{} `json:"metadata"`
|
Metadata interface{} `json:"metadata,omitempty"`
|
||||||
}
|
}
|
||||||
|
|||||||
11
internal/formats/syftjson/model/secrets.go
Normal file
11
internal/formats/syftjson/model/secrets.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/anchore/syft/syft/file"
|
||||||
|
"github.com/anchore/syft/syft/source"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Secrets struct {
|
||||||
|
Location source.Coordinates `json:"location"`
|
||||||
|
Secrets []file.SearchResult `json:"secrets"`
|
||||||
|
}
|
||||||
@ -2,6 +2,10 @@ package syftjson
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft/file"
|
||||||
|
|
||||||
"github.com/anchore/syft/syft/artifact"
|
"github.com/anchore/syft/syft/artifact"
|
||||||
|
|
||||||
@ -16,7 +20,7 @@ import (
|
|||||||
"github.com/anchore/syft/syft/source"
|
"github.com/anchore/syft/syft/source"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: this is export4ed for the use of the power-user command (temp)
|
// TODO: this is exported for the use of the power-user command (temp)
|
||||||
func ToFormatModel(s sbom.SBOM, applicationConfig interface{}) model.Document {
|
func ToFormatModel(s sbom.SBOM, applicationConfig interface{}) model.Document {
|
||||||
src, err := toSourceModel(s.Source)
|
src, err := toSourceModel(s.Source)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -26,6 +30,8 @@ func ToFormatModel(s sbom.SBOM, applicationConfig interface{}) model.Document {
|
|||||||
return model.Document{
|
return model.Document{
|
||||||
Artifacts: toPackageModels(s.Artifacts.PackageCatalog),
|
Artifacts: toPackageModels(s.Artifacts.PackageCatalog),
|
||||||
ArtifactRelationships: toRelationshipModel(s.Relationships),
|
ArtifactRelationships: toRelationshipModel(s.Relationships),
|
||||||
|
Files: toFile(s),
|
||||||
|
Secrets: toSecrets(s.Artifacts.Secrets),
|
||||||
Source: src,
|
Source: src,
|
||||||
Distro: toDistroModel(s.Artifacts.Distro),
|
Distro: toDistroModel(s.Artifacts.Distro),
|
||||||
Descriptor: model.Descriptor{
|
Descriptor: model.Descriptor{
|
||||||
@ -40,6 +46,85 @@ func ToFormatModel(s sbom.SBOM, applicationConfig interface{}) model.Document {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func toSecrets(data map[source.Coordinates][]file.SearchResult) []model.Secrets {
|
||||||
|
results := make([]model.Secrets, 0)
|
||||||
|
for coordinates, secrets := range data {
|
||||||
|
results = append(results, model.Secrets{
|
||||||
|
Location: coordinates,
|
||||||
|
Secrets: secrets,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort by real path then virtual path to ensure the result is stable across multiple runs
|
||||||
|
sort.SliceStable(results, func(i, j int) bool {
|
||||||
|
return results[i].Location.RealPath < results[j].Location.RealPath
|
||||||
|
})
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
|
func toFile(s sbom.SBOM) []model.File {
|
||||||
|
results := make([]model.File, 0)
|
||||||
|
artifacts := s.Artifacts
|
||||||
|
|
||||||
|
for _, coordinates := range sbom.AllCoordinates(s) {
|
||||||
|
var metadata *source.FileMetadata
|
||||||
|
if metadataForLocation, exists := artifacts.FileMetadata[coordinates]; exists {
|
||||||
|
metadata = &metadataForLocation
|
||||||
|
}
|
||||||
|
|
||||||
|
var digests []file.Digest
|
||||||
|
if digestsForLocation, exists := artifacts.FileDigests[coordinates]; exists {
|
||||||
|
digests = digestsForLocation
|
||||||
|
}
|
||||||
|
|
||||||
|
var classifications []file.Classification
|
||||||
|
if classificationsForLocation, exists := artifacts.FileClassifications[coordinates]; exists {
|
||||||
|
classifications = classificationsForLocation
|
||||||
|
}
|
||||||
|
|
||||||
|
var contents string
|
||||||
|
if contentsForLocation, exists := artifacts.FileContents[coordinates]; exists {
|
||||||
|
contents = contentsForLocation
|
||||||
|
}
|
||||||
|
|
||||||
|
results = append(results, model.File{
|
||||||
|
ID: string(coordinates.ID()),
|
||||||
|
Location: coordinates,
|
||||||
|
Metadata: toFileMetadataEntry(coordinates, metadata),
|
||||||
|
Digests: digests,
|
||||||
|
Classifications: classifications,
|
||||||
|
Contents: contents,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort by real path then virtual path to ensure the result is stable across multiple runs
|
||||||
|
sort.SliceStable(results, func(i, j int) bool {
|
||||||
|
return results[i].Location.RealPath < results[j].Location.RealPath
|
||||||
|
})
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
|
func toFileMetadataEntry(coordinates source.Coordinates, metadata *source.FileMetadata) *model.FileMetadataEntry {
|
||||||
|
if metadata == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
mode, err := strconv.Atoi(fmt.Sprintf("%o", metadata.Mode))
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("invalid mode found in file catalog @ location=%+v mode=%q: %+v", coordinates, metadata.Mode, err)
|
||||||
|
mode = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return &model.FileMetadataEntry{
|
||||||
|
Mode: mode,
|
||||||
|
Type: metadata.Type,
|
||||||
|
LinkDestination: metadata.LinkDestination,
|
||||||
|
UserID: metadata.UserID,
|
||||||
|
GroupID: metadata.GroupID,
|
||||||
|
MIMEType: metadata.MIMEType,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func toPackageModels(catalog *pkg.Catalog) []model.Package {
|
func toPackageModels(catalog *pkg.Catalog) []model.Package {
|
||||||
artifacts := make([]model.Package, 0)
|
artifacts := make([]model.Package, 0)
|
||||||
if catalog == nil {
|
if catalog == nil {
|
||||||
|
|||||||
72
internal/mimetype_helper.go
Normal file
72
internal/mimetype_helper.go
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
package internal
|
||||||
|
|
||||||
|
import "github.com/scylladb/go-set/strset"
|
||||||
|
|
||||||
|
var (
|
||||||
|
ArchiveMIMETypeSet = strset.New(
|
||||||
|
// derived from https://en.wikipedia.org/wiki/List_of_archive_formats
|
||||||
|
[]string{
|
||||||
|
// archive only
|
||||||
|
"application/x-archive",
|
||||||
|
"application/x-cpio",
|
||||||
|
"application/x-shar",
|
||||||
|
"application/x-iso9660-image",
|
||||||
|
"application/x-sbx",
|
||||||
|
"application/x-tar",
|
||||||
|
// compression only
|
||||||
|
"application/x-bzip2",
|
||||||
|
"application/gzip",
|
||||||
|
"application/x-lzip",
|
||||||
|
"application/x-lzma",
|
||||||
|
"application/x-lzop",
|
||||||
|
"application/x-snappy-framed",
|
||||||
|
"application/x-xz",
|
||||||
|
"application/x-compress",
|
||||||
|
"application/zstd",
|
||||||
|
// archiving and compression
|
||||||
|
"application/x-7z-compressed",
|
||||||
|
"application/x-ace-compressed",
|
||||||
|
"application/x-astrotite-afa",
|
||||||
|
"application/x-alz-compressed",
|
||||||
|
"application/vnd.android.package-archive",
|
||||||
|
"application/x-freearc",
|
||||||
|
"application/x-arj",
|
||||||
|
"application/x-b1",
|
||||||
|
"application/vnd.ms-cab-compressed",
|
||||||
|
"application/x-cfs-compressed",
|
||||||
|
"application/x-dar",
|
||||||
|
"application/x-dgc-compressed",
|
||||||
|
"application/x-apple-diskimage",
|
||||||
|
"application/x-gca-compressed",
|
||||||
|
"application/java-archive",
|
||||||
|
"application/x-lzh",
|
||||||
|
"application/x-lzx",
|
||||||
|
"application/x-rar-compressed",
|
||||||
|
"application/x-stuffit",
|
||||||
|
"application/x-stuffitx",
|
||||||
|
"application/x-gtar",
|
||||||
|
"application/x-ms-wim",
|
||||||
|
"application/x-xar",
|
||||||
|
"application/zip",
|
||||||
|
"application/x-zoo",
|
||||||
|
}...,
|
||||||
|
)
|
||||||
|
|
||||||
|
ExecutableMIMETypeSet = strset.New(
|
||||||
|
[]string{
|
||||||
|
"application/x-executable",
|
||||||
|
"application/x-mach-binary",
|
||||||
|
"application/x-elf",
|
||||||
|
"application/x-sharedlib",
|
||||||
|
"application/vnd.microsoft.portable-executable",
|
||||||
|
}...,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
func IsArchive(mimeType string) bool {
|
||||||
|
return ArchiveMIMETypeSet.Has(mimeType)
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsExecutable(mimeType string) bool {
|
||||||
|
return ExecutableMIMETypeSet.Has(mimeType)
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user