mirror of
https://github.com/anchore/syft.git
synced 2026-02-14 03:26:41 +01:00
fix: encode and decode FileLicenses and FileContents in Syft JSON (#2083)
Signed-off-by: Keith Zantow <kzantow@gmail.com>
This commit is contained in:
parent
3e16c6813f
commit
a46d12270f
@ -3,5 +3,5 @@ package internal
|
|||||||
const (
|
const (
|
||||||
// JSONSchemaVersion is the current schema version output by the JSON encoder
|
// JSONSchemaVersion is the current schema version output by the JSON encoder
|
||||||
// This is roughly following the "SchemaVer" guidelines for versioning the JSON schema. Please see schema/json/README.md for details on how to increment.
|
// This is roughly following the "SchemaVer" guidelines for versioning the JSON schema. Please see schema/json/README.md for details on how to increment.
|
||||||
JSONSchemaVersion = "10.0.1"
|
JSONSchemaVersion = "10.0.2"
|
||||||
)
|
)
|
||||||
|
|||||||
1976
schema/json/schema-10.0.2.json
Normal file
1976
schema/json/schema-10.0.2.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -9,8 +9,17 @@ import (
|
|||||||
|
|
||||||
"github.com/go-test/deep"
|
"github.com/go-test/deep"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
stereoscopeFile "github.com/anchore/stereoscope/pkg/file"
|
||||||
|
"github.com/anchore/syft/internal"
|
||||||
|
"github.com/anchore/syft/syft/cpe"
|
||||||
|
"github.com/anchore/syft/syft/file"
|
||||||
"github.com/anchore/syft/syft/formats/internal/testutils"
|
"github.com/anchore/syft/syft/formats/internal/testutils"
|
||||||
|
"github.com/anchore/syft/syft/linux"
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
"github.com/anchore/syft/syft/sbom"
|
||||||
|
"github.com/anchore/syft/syft/source"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestEncodeDecodeCycle(t *testing.T) {
|
func TestEncodeDecodeCycle(t *testing.T) {
|
||||||
@ -86,3 +95,145 @@ func TestOutOfDateParser(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_encodeDecodeFileMetadata(t *testing.T) {
|
||||||
|
p := pkg.Package{
|
||||||
|
Name: "pkg",
|
||||||
|
Version: "version",
|
||||||
|
FoundBy: "something",
|
||||||
|
Locations: file.NewLocationSet(file.Location{
|
||||||
|
LocationData: file.LocationData{
|
||||||
|
Coordinates: file.Coordinates{
|
||||||
|
RealPath: "/somewhere",
|
||||||
|
FileSystemID: "id",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
LocationMetadata: file.LocationMetadata{
|
||||||
|
Annotations: map[string]string{
|
||||||
|
"key": "value",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
Licenses: pkg.NewLicenseSet(pkg.License{
|
||||||
|
Value: "MIT",
|
||||||
|
SPDXExpression: "MIT",
|
||||||
|
Type: "MIT",
|
||||||
|
URLs: internal.NewStringSet("https://example.org/license"),
|
||||||
|
Locations: file.LocationSet{},
|
||||||
|
}),
|
||||||
|
Language: "language",
|
||||||
|
Type: "type",
|
||||||
|
CPEs: []cpe.CPE{
|
||||||
|
{
|
||||||
|
Part: "a",
|
||||||
|
Vendor: "vendor",
|
||||||
|
Product: "product",
|
||||||
|
Version: "version",
|
||||||
|
Update: "update",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PURL: "pkg:generic/pkg@version",
|
||||||
|
MetadataType: "",
|
||||||
|
Metadata: nil,
|
||||||
|
}
|
||||||
|
p.SetID()
|
||||||
|
|
||||||
|
c := file.Coordinates{
|
||||||
|
RealPath: "some-file",
|
||||||
|
FileSystemID: "some-fs-id",
|
||||||
|
}
|
||||||
|
|
||||||
|
s := sbom.SBOM{
|
||||||
|
Artifacts: sbom.Artifacts{
|
||||||
|
Packages: pkg.NewCollection(p),
|
||||||
|
FileMetadata: map[file.Coordinates]file.Metadata{
|
||||||
|
c: {
|
||||||
|
FileInfo: stereoscopeFile.ManualInfo{
|
||||||
|
NameValue: c.RealPath,
|
||||||
|
ModeValue: 0644,
|
||||||
|
SizeValue: 7,
|
||||||
|
},
|
||||||
|
Path: c.RealPath,
|
||||||
|
Type: stereoscopeFile.TypeRegular,
|
||||||
|
UserID: 1,
|
||||||
|
GroupID: 2,
|
||||||
|
MIMEType: "text/plain",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
FileDigests: map[file.Coordinates][]file.Digest{
|
||||||
|
c: {
|
||||||
|
{
|
||||||
|
Algorithm: "sha1",
|
||||||
|
Value: "d34db33f",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
FileContents: map[file.Coordinates]string{
|
||||||
|
c: "some contents",
|
||||||
|
},
|
||||||
|
FileLicenses: map[file.Coordinates][]file.License{
|
||||||
|
c: {
|
||||||
|
{
|
||||||
|
Value: "MIT",
|
||||||
|
SPDXExpression: "MIT",
|
||||||
|
Type: "MIT",
|
||||||
|
LicenseEvidence: &file.LicenseEvidence{
|
||||||
|
Confidence: 1,
|
||||||
|
Offset: 2,
|
||||||
|
Extent: 3,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
LinuxDistribution: &linux.Release{
|
||||||
|
PrettyName: "some os",
|
||||||
|
Name: "os",
|
||||||
|
ID: "os-id",
|
||||||
|
IDLike: []string{"os"},
|
||||||
|
Version: "version",
|
||||||
|
VersionID: "version",
|
||||||
|
VersionCodename: "codename",
|
||||||
|
BuildID: "build-id",
|
||||||
|
ImageID: "image-id",
|
||||||
|
ImageVersion: "image-version",
|
||||||
|
Variant: "variant",
|
||||||
|
VariantID: "variant-id",
|
||||||
|
HomeURL: "https://example.org/os",
|
||||||
|
SupportURL: "https://example.org/os/support",
|
||||||
|
BugReportURL: "https://example.org/os/bugs",
|
||||||
|
PrivacyPolicyURL: "https://example.org/os/privacy",
|
||||||
|
CPEName: "os-cpe",
|
||||||
|
SupportEnd: "now",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Relationships: nil,
|
||||||
|
Source: source.Description{
|
||||||
|
ID: "some-id",
|
||||||
|
Name: "some-name",
|
||||||
|
Version: "some-version",
|
||||||
|
Metadata: source.FileSourceMetadata{
|
||||||
|
Path: "/some-file-source-path",
|
||||||
|
Digests: []file.Digest{
|
||||||
|
{
|
||||||
|
Algorithm: "sha1",
|
||||||
|
Value: "d34db33f",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MIMEType: "file/zip",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Descriptor: sbom.Descriptor{
|
||||||
|
Name: "syft",
|
||||||
|
Version: "this-version",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
|
err := encoder(buf, s)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
got, err := decoder(buf)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Equal(t, s, *got)
|
||||||
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package model
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/anchore/syft/syft/file"
|
"github.com/anchore/syft/syft/file"
|
||||||
|
"github.com/anchore/syft/syft/license"
|
||||||
)
|
)
|
||||||
|
|
||||||
type File struct {
|
type File struct {
|
||||||
@ -10,6 +11,7 @@ type File struct {
|
|||||||
Metadata *FileMetadataEntry `json:"metadata,omitempty"`
|
Metadata *FileMetadataEntry `json:"metadata,omitempty"`
|
||||||
Contents string `json:"contents,omitempty"`
|
Contents string `json:"contents,omitempty"`
|
||||||
Digests []file.Digest `json:"digests,omitempty"`
|
Digests []file.Digest `json:"digests,omitempty"`
|
||||||
|
Licenses []FileLicense `json:"licenses,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type FileMetadataEntry struct {
|
type FileMetadataEntry struct {
|
||||||
@ -21,3 +23,16 @@ type FileMetadataEntry struct {
|
|||||||
MIMEType string `json:"mimeType"`
|
MIMEType string `json:"mimeType"`
|
||||||
Size int64 `json:"size"`
|
Size int64 `json:"size"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FileLicense struct {
|
||||||
|
Value string `json:"value"`
|
||||||
|
SPDXExpression string `json:"spdxExpression"`
|
||||||
|
Type license.Type `json:"type"`
|
||||||
|
Evidence *FileLicenseEvidence `json:"evidence,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type FileLicenseEvidence struct {
|
||||||
|
Confidence int `json:"confidence"`
|
||||||
|
Offset int `json:"offset"`
|
||||||
|
Extent int `json:"extent"`
|
||||||
|
}
|
||||||
|
|||||||
@ -106,12 +106,31 @@ func toFile(s sbom.SBOM) []model.File {
|
|||||||
contents = contentsForLocation
|
contents = contentsForLocation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var licenses []model.FileLicense
|
||||||
|
for _, l := range artifacts.FileLicenses[coordinates] {
|
||||||
|
var evidence *model.FileLicenseEvidence
|
||||||
|
if e := l.LicenseEvidence; e != nil {
|
||||||
|
evidence = &model.FileLicenseEvidence{
|
||||||
|
Confidence: e.Confidence,
|
||||||
|
Offset: e.Offset,
|
||||||
|
Extent: e.Extent,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
licenses = append(licenses, model.FileLicense{
|
||||||
|
Value: l.Value,
|
||||||
|
SPDXExpression: l.SPDXExpression,
|
||||||
|
Type: l.Type,
|
||||||
|
Evidence: evidence,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
results = append(results, model.File{
|
results = append(results, model.File{
|
||||||
ID: string(coordinates.ID()),
|
ID: string(coordinates.ID()),
|
||||||
Location: coordinates,
|
Location: coordinates,
|
||||||
Metadata: toFileMetadataEntry(coordinates, metadata),
|
Metadata: toFileMetadataEntry(coordinates, metadata),
|
||||||
Digests: digests,
|
Digests: digests,
|
||||||
Contents: contents,
|
Contents: contents,
|
||||||
|
Licenses: licenses,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -34,6 +34,8 @@ func toSyftModel(doc model.Document) (*sbom.SBOM, error) {
|
|||||||
Packages: catalog,
|
Packages: catalog,
|
||||||
FileMetadata: fileArtifacts.FileMetadata,
|
FileMetadata: fileArtifacts.FileMetadata,
|
||||||
FileDigests: fileArtifacts.FileDigests,
|
FileDigests: fileArtifacts.FileDigests,
|
||||||
|
FileContents: fileArtifacts.FileContents,
|
||||||
|
FileLicenses: fileArtifacts.FileLicenses,
|
||||||
LinuxDistribution: toSyftLinuxRelease(doc.Distro),
|
LinuxDistribution: toSyftLinuxRelease(doc.Distro),
|
||||||
},
|
},
|
||||||
Source: *toSyftSourceData(doc.Source),
|
Source: *toSyftSourceData(doc.Source),
|
||||||
@ -66,6 +68,8 @@ func toSyftFiles(files []model.File) sbom.Artifacts {
|
|||||||
ret := sbom.Artifacts{
|
ret := sbom.Artifacts{
|
||||||
FileMetadata: make(map[file.Coordinates]file.Metadata),
|
FileMetadata: make(map[file.Coordinates]file.Metadata),
|
||||||
FileDigests: make(map[file.Coordinates][]file.Digest),
|
FileDigests: make(map[file.Coordinates][]file.Digest),
|
||||||
|
FileContents: make(map[file.Coordinates]string),
|
||||||
|
FileLicenses: make(map[file.Coordinates][]file.License),
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, f := range files {
|
for _, f := range files {
|
||||||
@ -100,6 +104,27 @@ func toSyftFiles(files []model.File) sbom.Artifacts {
|
|||||||
Value: d.Value,
|
Value: d.Value,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if f.Contents != "" {
|
||||||
|
ret.FileContents[coord] = f.Contents
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, l := range f.Licenses {
|
||||||
|
var evidence *file.LicenseEvidence
|
||||||
|
if e := l.Evidence; e != nil {
|
||||||
|
evidence = &file.LicenseEvidence{
|
||||||
|
Confidence: e.Confidence,
|
||||||
|
Offset: e.Offset,
|
||||||
|
Extent: e.Extent,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret.FileLicenses[coord] = append(ret.FileLicenses[coord], file.License{
|
||||||
|
Value: l.Value,
|
||||||
|
SPDXExpression: l.SPDXExpression,
|
||||||
|
Type: l.Type,
|
||||||
|
LicenseEvidence: evidence,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|||||||
@ -312,6 +312,8 @@ func Test_toSyftFiles(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
tt.want.FileContents = make(map[file.Coordinates]string)
|
||||||
|
tt.want.FileLicenses = make(map[file.Coordinates][]file.License)
|
||||||
assert.Equal(t, tt.want, toSyftFiles(tt.files))
|
assert.Equal(t, tt.want, toSyftFiles(tt.files))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user