Compare commits

...
7 Commits
Author SHA1 Message Date
Benji VisserandAlex Goodman 0891d35e07 include image labels in cycloneDX SBOM (#2294)
* include image labels in SBOM

Signed-off-by: Benji Visser <benji@093b.org>

* update tests

Signed-off-by: Benji Visser <benji@093b.org>

* gocritic

Signed-off-by: Benji Visser <benji@093b.org>

* add properties

Signed-off-by: Benji Visser <benji@093b.org>

* add decoder

Signed-off-by: Benji Visser <benji@093b.org>

* update golden snapshots

Signed-off-by: Benji Visser <benji@093b.org>

* decodeProperties

Signed-off-by: Benji Visser <benji@093b.org>

* add test

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

* remove the snapshot test changes

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

* restore snapshots

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

---------

Signed-off-by: Benji Visser <benji@093b.org>
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
Co-authored-by: Alex Goodman <wagoodman@users.noreply.github.com>
2023-11-08 23:13:04 +00:00
Alex Goodman 502971a1b2 Add accessPath on Location objects to syft-json output (#2287)
* add accessPath on Location objects to syft-json output

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

* generate json schema v12.0.1

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

---------

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2023-11-08 17:05:30 -06:00
Colm O hEigeartaighandAlex Goodman dc14dbb326 SPDX file has duplicate sha256 tag in versionInfo (#2300)
* SPDX file has duplicate sha256 tag in versionInfo

Signed-off-by: Colm O hEigeartaigh <coheigea@apache.org>

* add tests

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

---------

Signed-off-by: Colm O hEigeartaigh <coheigea@apache.org>
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
Co-authored-by: Alex Goodman <wagoodman@users.noreply.github.com>
2023-11-08 22:49:31 +00:00
Colm O hEigeartaigh bae5a2e741 Check maven central as well for licenses in parents poms for nested jars (#2302)
Signed-off-by: Colm O hEigeartaigh <coheigea@apache.org>
2023-11-08 10:26:12 -08:00
dependabot[bot] 220655743b chore(deps): bump github.com/spf13/cobra from 1.7.0 to 1.8.0 (#2293)
Bumps [github.com/spf13/cobra](https://github.com/spf13/cobra) from 1.7.0 to 1.8.0.
- [Release notes](https://github.com/spf13/cobra/releases)
- [Commits](https://github.com/spf13/cobra/compare/v1.7.0...v1.8.0)

---
updated-dependencies:
- dependency-name: github.com/spf13/cobra
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-08 10:23:40 -08:00
anchore-actions-token-generator[bot]andspiffcs 9fce006b8f chore(deps): update tools to latest versions (#2301)
Signed-off-by: GitHub <noreply@github.com>
Co-authored-by: spiffcs <spiffcs@users.noreply.github.com>
2023-11-08 09:33:59 -08:00
Keith Zantow d91c2dd842 fix: identify cyclone-json without $schema (#2303)
Signed-off-by: Keith Zantow <kzantow@gmail.com>
2023-11-08 11:54:22 -05:00
25 changed files with 2449 additions and 43 deletions
+1 -1
View File
@@ -29,7 +29,7 @@ tools:
- name: cosign
version:
want: v2.2.0
want: v2.2.1
method: github-release
with:
repo: sigstore/cosign
+1 -1
View File
@@ -62,7 +62,7 @@ require (
github.com/sergi/go-diff v1.3.1
github.com/spdx/tools-golang v0.5.3
github.com/spf13/afero v1.10.0
github.com/spf13/cobra v1.7.0
github.com/spf13/cobra v1.8.0
github.com/stretchr/testify v1.8.4
github.com/vbatts/go-mtree v0.5.3
github.com/vifraa/gopom v1.0.0
+3 -2
View File
@@ -202,6 +202,7 @@ github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
@@ -713,8 +714,8 @@ github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU
github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA=
github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48=
github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4=
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
+1 -1
View File
@@ -3,5 +3,5 @@ package internal
const (
// 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.
JSONSchemaVersion = "12.0.0"
JSONSchemaVersion = "12.0.1"
)
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -20,8 +20,8 @@ type LocationData struct {
Coordinates `cyclonedx:""` // Empty string here means there is no intermediate property name, e.g. syft:locations:0:path without "coordinates"
// note: it is IMPORTANT to ignore anything but the coordinates for a Location when considering the ID (hash value)
// since the coordinates are the minimally correct ID for a location (symlinks should not come into play)
VirtualPath string `hash:"ignore" json:"-"` // The path to the file which may or may not have hardlinks / symlinks
ref file.Reference `hash:"ignore"` // The file reference relative to the stereoscope.FileCatalog that has more information about this location.
VirtualPath string `hash:"ignore" json:"accessPath"` // The path to the file which may or may not have hardlinks / symlinks
ref file.Reference `hash:"ignore"` // The file reference relative to the stereoscope.FileCatalog that has more information about this location.
}
func (l LocationData) Reference() file.Reference {
@@ -179,7 +179,7 @@ func (l Location) String() string {
str += fmt.Sprintf("RealPath=%q", l.RealPath)
if l.VirtualPath != "" {
if l.VirtualPath != "" && l.VirtualPath != l.RealPath {
str += fmt.Sprintf(" VirtualPath=%q", l.VirtualPath)
}
@@ -213,6 +213,12 @@ func extractComponents(meta *cyclonedx.Metadata) source.Description {
switch c.Type {
case cyclonedx.ComponentTypeContainer:
var labels map[string]string
if meta.Properties != nil {
labels = decodeProperties(*meta.Properties, "syft:image:labels:")
}
return source.Description{
ID: "",
// TODO: can we decode alias name-version somehow? (it isn't be encoded in the first place yet)
@@ -221,6 +227,7 @@ func extractComponents(meta *cyclonedx.Metadata) source.Description {
UserInput: c.Name,
ID: c.BOMRef,
ManifestDigest: c.Version,
Labels: labels,
},
}
case cyclonedx.ComponentTypeFile:
@@ -97,7 +97,6 @@ func Test_decode(t *testing.T) {
CPE: "cpe:2.3:*:another:package:2:*:*:*:*:*:*:*",
PackageURL: "pkg:apk/alpine/alpine-baselayout@3.2.0-r16?arch=x86_64&upstream=alpine-baselayout&distro=alpine-3.14.2",
Properties: &[]cyclonedx.Property{
{
Name: "foundBy",
Value: "apkdb-cataloger",
+11 -1
View File
@@ -121,7 +121,8 @@ func toBomDescriptor(name, version string, srcMetadata source.Description) *cycl
Version: version,
},
},
Component: toBomDescriptorComponent(srcMetadata),
Properties: toBomProperties(srcMetadata),
Component: toBomDescriptorComponent(srcMetadata),
}
}
@@ -190,6 +191,15 @@ func toDependencies(relationships []artifact.Relationship) []cyclonedx.Dependenc
return result
}
func toBomProperties(srcMetadata source.Description) *[]cyclonedx.Property {
metadata, ok := srcMetadata.Metadata.(source.StereoscopeImageSourceMetadata)
if ok {
props := encodeProperties(metadata.Labels, "syft:image:labels")
return &props
}
return nil
}
func toBomDescriptorComponent(srcMetadata source.Description) *cyclonedx.Component {
name := srcMetadata.Name
version := srcMetadata.Version
@@ -5,12 +5,14 @@ import (
"testing"
"github.com/CycloneDX/cyclonedx-go"
"github.com/google/go-cmp/cmp"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/sbom"
"github.com/anchore/syft/syft/source"
)
func Test_formatCPE(t *testing.T) {
@@ -138,3 +140,95 @@ func Test_relationships(t *testing.T) {
})
}
}
func Test_toBomDescriptor(t *testing.T) {
type args struct {
name string
version string
srcMetadata source.Description
}
tests := []struct {
name string
args args
want *cyclonedx.Metadata
}{
{
name: "with image labels source metadata",
args: args{
name: "test-image",
version: "1.0.0",
srcMetadata: source.Description{
Metadata: source.StereoscopeImageSourceMetadata{
Labels: map[string]string{
"key1": "value1",
},
},
},
},
want: &cyclonedx.Metadata{
Timestamp: "",
Lifecycles: nil,
Tools: &[]cyclonedx.Tool{
{
Vendor: "anchore",
Name: "test-image",
Version: "1.0.0",
Hashes: nil,
ExternalReferences: nil,
},
},
Authors: nil,
Component: &cyclonedx.Component{
BOMRef: "",
MIMEType: "",
Type: "container",
Supplier: nil,
Author: "",
Publisher: "",
Group: "",
Name: "",
Version: "",
Description: "",
Scope: "",
Hashes: nil,
Licenses: nil,
Copyright: "",
CPE: "",
PackageURL: "",
SWID: nil,
Modified: nil,
Pedigree: nil,
ExternalReferences: nil,
Properties: nil,
Components: nil,
Evidence: nil,
ReleaseNotes: nil,
},
Manufacture: nil,
Supplier: nil,
Licenses: nil,
Properties: &[]cyclonedx.Property{
{
Name: "syft:image:labels:key1",
Value: "value1",
},
}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
subject := toBomDescriptor(tt.args.name, tt.args.version, tt.args.srcMetadata)
require.NotEmpty(t, subject.Component.BOMRef)
subject.Timestamp = "" // not under test
require.NotNil(t, subject.Component)
require.NotEmpty(t, subject.Component.BOMRef)
subject.Component.BOMRef = "" // not under test
if d := cmp.Diff(tt.want, subject); d != "" {
t.Errorf("toBomDescriptor() mismatch (-want +got):\n%s", d)
}
})
}
}
@@ -1,6 +1,8 @@
package cyclonedxhelpers
import (
"strings"
"github.com/CycloneDX/cyclonedx-go"
"github.com/anchore/syft/syft/format/common"
@@ -19,3 +21,14 @@ func encodeProperties(obj interface{}, prefix string) (out []cyclonedx.Property)
}
return
}
func decodeProperties(properties []cyclonedx.Property, prefix string) map[string]string {
labels := make(map[string]string)
for _, property := range properties {
if strings.HasPrefix(property.Name, prefix) {
labelName := strings.TrimPrefix(property.Name, prefix)
labels[labelName] = property.Value
}
}
return labels
}
+3 -9
View File
@@ -4,7 +4,6 @@ import (
"encoding/json"
"fmt"
"io"
"strings"
"github.com/CycloneDX/cyclonedx-go"
@@ -75,7 +74,7 @@ func (d decoder) Identify(reader io.ReadSeeker) (sbom.FormatID, string) {
return "", ""
}
id, version := getFormatInfo(doc.JSONSchema, doc.BOMFormat, doc.SpecVersion)
id, version := getFormatInfo(doc.BOMFormat, doc.SpecVersion)
if version == "" || id != ID {
// not a cyclonedx json document that we support
return "", ""
@@ -84,18 +83,13 @@ func (d decoder) Identify(reader io.ReadSeeker) (sbom.FormatID, string) {
return id, version
}
func getFormatInfo(schemaURI, bomFormat string, specVersion any) (sbom.FormatID, string) {
if !strings.Contains(schemaURI, "cyclonedx.org/schema/bom") {
// not a cyclonedx json document
return "", ""
}
func getFormatInfo(bomFormat string, specVersion any) (sbom.FormatID, string) {
if bomFormat != "CycloneDX" {
// not a cyclonedx json document
return "", ""
}
// by this point this looks to be valid cyclonedx json, but we need to know the version
// by this point, it looks to be cyclonedx json, but we need to know the version
var (
version string
+15
View File
@@ -103,6 +103,21 @@ func TestDecoder_Identify(t *testing.T) {
})
}
cases = append(cases, []testCase{
{
name: "no-schema-1.4",
file: "test-fixtures/identify/micronaut-1.4.json",
id: ID,
version: "1.4",
},
{
name: "no-schema-1.5",
file: "test-fixtures/identify/micronaut-1.5.json",
id: ID,
version: "1.5",
},
}...)
for _, test := range cases {
t.Run(test.name, func(t *testing.T) {
reader, err := os.Open(test.file)
@@ -0,0 +1,28 @@
{
"bomFormat": "CycloneDX",
"specVersion": "1.4",
"version": 1,
"components": [
{
"type": "library",
"group": "io.netty",
"name": "netty-codec-http2",
"version": "4.1.73.Final",
"properties": [
{
"name": "syft:cpe23",
"value": "cpe:2.3:a:codec:codec:4.1.73.Final:*:*:*:*:*:*:*"
},
{
"name": "syft:cpe23",
"value": "cpe:2.3:a:codec:netty-codec-http2:4.1.73.Final:*:*:*:*:*:*:*"
},
{
"name": "syft:cpe23",
"value": "cpe:2.3:a:codec:netty_codec_http2:4.1.73.Final:*:*:*:*:*:*:*"
}
]
}
],
"serialNumber": "urn:uuid:43538af4-f715-3d85-9629-336fdd3790ad"
}
@@ -0,0 +1,28 @@
{
"bomFormat": "CycloneDX",
"specVersion": "1.5",
"version": 1,
"components": [
{
"type": "library",
"group": "io.netty",
"name": "netty-codec-http2",
"version": "4.1.73.Final",
"properties": [
{
"name": "syft:cpe23",
"value": "cpe:2.3:a:codec:codec:4.1.73.Final:*:*:*:*:*:*:*"
},
{
"name": "syft:cpe23",
"value": "cpe:2.3:a:codec:netty-codec-http2:4.1.73.Final:*:*:*:*:*:*:*"
},
{
"name": "syft:cpe23",
"value": "cpe:2.3:a:codec:netty_codec_http2:4.1.73.Final:*:*:*:*:*:*:*"
}
]
}
],
"serialNumber": "urn:uuid:f4-f715-3d85-9629-336fdd3790ad"
}
+1 -1
View File
@@ -117,7 +117,7 @@ func TestEncodeFullJSONDocument(t *testing.T) {
Artifacts: sbom.Artifacts{
Packages: catalog,
FileMetadata: map[file.Coordinates]file.Metadata{
file.NewLocation("/a/place").Coordinates: {
file.NewVirtualLocation("/a/place", "/a/symlink/to/place").Coordinates: {
FileInfo: stereoFile.ManualInfo{
NameValue: "/a/place",
ModeValue: 0775,
@@ -8,7 +8,8 @@
"foundBy": "the-cataloger-1",
"locations": [
{
"path": "/some/path/pkg1"
"path": "/some/path/pkg1",
"accessPath": "/some/path/pkg1"
}
],
"licenses": [
@@ -48,7 +49,8 @@
"foundBy": "the-cataloger-2",
"locations": [
{
"path": "/some/path/pkg1"
"path": "/some/path/pkg1",
"accessPath": "/some/path/pkg1"
}
],
"licenses": [],
@@ -8,7 +8,8 @@
"foundBy": "the-cataloger-1",
"locations": [
{
"path": "/a/place/a"
"path": "/a/place/a",
"accessPath": "/a/place/a"
}
],
"licenses": [
@@ -43,7 +44,8 @@
"foundBy": "the-cataloger-2",
"locations": [
{
"path": "/b/place/b"
"path": "/b/place/b",
"accessPath": "/b/place/b"
}
],
"licenses": [],
@@ -9,7 +9,8 @@
"locations": [
{
"path": "/somefile-1.txt",
"layerID": "sha256:100d5a55f9032faead28b7427fa3e650e4f0158f86ea89d06e1489df00cb8c6f"
"layerID": "sha256:100d5a55f9032faead28b7427fa3e650e4f0158f86ea89d06e1489df00cb8c6f",
"accessPath": "/somefile-1.txt"
}
],
"licenses": [
@@ -45,7 +46,8 @@
"locations": [
{
"path": "/somefile-2.txt",
"layerID": "sha256:000fb9200890d3a19138478b20023023c0dce1c54352007c2863716780f049eb"
"layerID": "sha256:000fb9200890d3a19138478b20023023c0dce1c54352007c2863716780f049eb",
"accessPath": "/somefile-2.txt"
}
],
"licenses": [],
+5 -2
View File
@@ -444,7 +444,7 @@ func (j *archiveParser) discoverPkgsFromAllMavenFiles(parentPkg *pkg.Package) ([
pomProject = proj
}
pkgFromPom := newPackageFromMavenData(propertiesObj, pomProject, parentPkg, j.location)
pkgFromPom := newPackageFromMavenData(propertiesObj, pomProject, parentPkg, j.location, j.cfg)
if pkgFromPom != nil {
pkgs = append(pkgs, *pkgFromPom)
}
@@ -635,7 +635,7 @@ func pomProjectByParentPath(archivePath string, location file.Location, extractP
// newPackageFromMavenData processes a single Maven POM properties for a given parent package, returning all listed Java packages found and
// associating each discovered package to the given parent package. Note the pom.xml is optional, the pom.properties is not.
func newPackageFromMavenData(pomProperties pkg.JavaPomProperties, parsedPomProject *parsedPomProject, parentPkg *pkg.Package, location file.Location) *pkg.Package {
func newPackageFromMavenData(pomProperties pkg.JavaPomProperties, parsedPomProject *parsedPomProject, parentPkg *pkg.Package, location file.Location, cfg Config) *pkg.Package {
// keep the artifact name within the virtual path if this package does not match the parent package
vPathSuffix := ""
groupID := ""
@@ -660,6 +660,9 @@ func newPackageFromMavenData(pomProperties pkg.JavaPomProperties, parsedPomProje
var pkgPomProject *pkg.JavaPomProject
licenses := make([]pkg.License, 0)
if parsedPomProject != nil {
if cfg.UseNetwork {
findPomLicenses(parsedPomProject, cfg)
}
pkgPomProject = parsedPomProject.JavaPomProject
licenses = append(licenses, parsedPomProject.Licenses...)
}
@@ -1089,7 +1089,7 @@ func Test_newPackageFromMavenData(t *testing.T) {
}
test.expectedParent.Locations = locations
actualPackage := newPackageFromMavenData(test.props, test.project, test.parent, file.NewLocation(virtualPath))
actualPackage := newPackageFromMavenData(test.props, test.project, test.parent, file.NewLocation(virtualPath), Config{})
if test.expectedPackage == nil {
require.Nil(t, actualPackage)
} else {
-4
View File
@@ -108,10 +108,6 @@ func deriveIDFromFile(cfg FileConfig) (artifact.ID, string) {
info += fmt.Sprintf(":%s@%s", cfg.Alias.Name, cfg.Alias.Version)
}
if d != "" {
d = fmt.Sprintf("sha256:%s", d)
}
return artifactIDFromDigest(digest.SHA256.FromString(info).String()), d
}
+15 -10
View File
@@ -211,10 +211,11 @@ func createArchive(t testing.TB, sourceDirPath, destinationArchivePath string, l
func Test_FileSource_ID(t *testing.T) {
tests := []struct {
name string
cfg FileConfig
want artifact.ID
wantErr require.ErrorAssertionFunc
name string
cfg FileConfig
want artifact.ID
wantDigest string
wantErr require.ErrorAssertionFunc
}{
{
name: "empty",
@@ -236,9 +237,10 @@ func Test_FileSource_ID(t *testing.T) {
wantErr: require.Error,
},
{
name: "with path",
cfg: FileConfig{Path: "./test-fixtures/image-simple/Dockerfile"},
want: artifact.ID("db7146472cf6d49b3ac01b42812fb60020b0b4898b97491b21bb690c808d5159"),
name: "with path",
cfg: FileConfig{Path: "./test-fixtures/image-simple/Dockerfile"},
want: artifact.ID("db7146472cf6d49b3ac01b42812fb60020b0b4898b97491b21bb690c808d5159"),
wantDigest: "sha256:38601c0bb4269a10ce1d00590ea7689c1117dd9274c758653934ab4f2016f80f",
},
{
name: "with path and alias",
@@ -249,7 +251,8 @@ func Test_FileSource_ID(t *testing.T) {
Version: "version-me-this!",
},
},
want: artifact.ID("3c713003305ac6605255cec8bf4ea649aa44b2b9a9f3a07bd683869d1363438a"),
want: artifact.ID("3c713003305ac6605255cec8bf4ea649aa44b2b9a9f3a07bd683869d1363438a"),
wantDigest: "sha256:38601c0bb4269a10ce1d00590ea7689c1117dd9274c758653934ab4f2016f80f",
},
{
name: "other fields do not affect ID",
@@ -259,7 +262,8 @@ func Test_FileSource_ID(t *testing.T) {
Paths: []string{"a", "b"},
},
},
want: artifact.ID("db7146472cf6d49b3ac01b42812fb60020b0b4898b97491b21bb690c808d5159"),
want: artifact.ID("db7146472cf6d49b3ac01b42812fb60020b0b4898b97491b21bb690c808d5159"),
wantDigest: "sha256:38601c0bb4269a10ce1d00590ea7689c1117dd9274c758653934ab4f2016f80f",
},
}
for _, tt := range tests {
@@ -272,7 +276,8 @@ func Test_FileSource_ID(t *testing.T) {
if err != nil {
return
}
assert.Equalf(t, tt.want, s.ID(), "ID()")
assert.Equalf(t, tt.want, s.ID(), "ID() mismatch")
assert.Equalf(t, tt.wantDigest, s.digestForVersion, "digestForVersion mismatch")
})
}
}
@@ -18,6 +18,7 @@ type StereoscopeImageSourceMetadata struct {
Architecture string `json:"architecture"`
Variant string `json:"architectureVariant,omitempty"`
OS string `json:"os"`
Labels map[string]string `json:"labels,omitempty"`
}
// StereoscopeLayerMetadata represents all static metadata that defines what a container image layer is.
@@ -48,6 +49,7 @@ func NewStereoscopeImageMetadata(img *image.Image, userInput string) Stereoscope
Architecture: img.Metadata.Architecture,
Variant: img.Metadata.Variant,
OS: img.Metadata.OS,
Labels: img.Metadata.Config.Config.Labels,
}
// populate image metadata
+1
View File
@@ -192,6 +192,7 @@ func imageMetadataFromStereoscopeImage(img *image.Image, reference string) Stere
Architecture: img.Metadata.Architecture,
Variant: img.Metadata.Variant,
OS: img.Metadata.OS,
Labels: img.Metadata.Config.Config.Labels,
}
}