refactor: move artifact types under artifact package to avoid import cycles (#6652)

Signed-off-by: knqyf263 <knqyf263@gmail.com>
This commit is contained in:
Teppei Fukuda
2024-05-09 20:18:37 +04:00
committed by GitHub
parent 357c358fb1
commit 6a72dd47ae
46 changed files with 631 additions and 627 deletions

View File

@@ -4,12 +4,13 @@ package integration
import (
"fmt"
"github.com/stretchr/testify/assert"
"os"
"strings"
"testing"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/stretchr/testify/assert"
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
"github.com/aquasecurity/trivy/pkg/types"
)
@@ -379,7 +380,7 @@ func TestRepository(t *testing.T) {
},
golden: "testdata/gomod-skip.json.golden",
override: func(_ *testing.T, want, _ *types.Report) {
want.ArtifactType = ftypes.ArtifactFilesystem
want.ArtifactType = artifact.TypeFilesystem
},
},
{
@@ -393,7 +394,7 @@ func TestRepository(t *testing.T) {
},
golden: "testdata/dockerfile-custom-policies.json.golden",
override: func(_ *testing.T, want, got *types.Report) {
want.ArtifactType = ftypes.ArtifactFilesystem
want.ArtifactType = artifact.TypeFilesystem
},
},
}

View File

@@ -10,7 +10,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
"github.com/aquasecurity/trivy/pkg/types"
)
@@ -37,7 +37,7 @@ func TestSBOM(t *testing.T) {
golden: "testdata/centos-7.json.golden",
override: func(t *testing.T, want, got *types.Report) {
want.ArtifactName = "testdata/fixtures/sbom/centos-7-cyclonedx.json"
want.ArtifactType = ftypes.ArtifactCycloneDX
want.ArtifactType = artifact.TypeCycloneDX
require.Len(t, got.Results, 1)
want.Results[0].Target = "testdata/fixtures/sbom/centos-7-cyclonedx.json (centos 7.6.1810)"
@@ -76,7 +76,7 @@ func TestSBOM(t *testing.T) {
golden: "testdata/centos-7.json.golden",
override: func(t *testing.T, want, got *types.Report) {
want.ArtifactName = "testdata/fixtures/sbom/centos-7-cyclonedx.intoto.jsonl"
want.ArtifactType = ftypes.ArtifactCycloneDX
want.ArtifactType = artifact.TypeCycloneDX
require.Len(t, got.Results, 1)
want.Results[0].Target = "testdata/fixtures/sbom/centos-7-cyclonedx.intoto.jsonl (centos 7.6.1810)"
@@ -97,7 +97,7 @@ func TestSBOM(t *testing.T) {
golden: "testdata/centos-7.json.golden",
override: func(t *testing.T, want, got *types.Report) {
want.ArtifactName = "testdata/fixtures/sbom/centos-7-spdx.txt"
want.ArtifactType = ftypes.ArtifactSPDX
want.ArtifactType = artifact.TypeSPDX
require.Len(t, got.Results, 1)
want.Results[0].Target = "testdata/fixtures/sbom/centos-7-spdx.txt (centos 7.6.1810)"
@@ -113,7 +113,7 @@ func TestSBOM(t *testing.T) {
golden: "testdata/centos-7.json.golden",
override: func(t *testing.T, want, got *types.Report) {
want.ArtifactName = "testdata/fixtures/sbom/centos-7-spdx.json"
want.ArtifactType = ftypes.ArtifactSPDX
want.ArtifactType = artifact.TypeSPDX
require.Len(t, got.Results, 1)
want.Results[0].Target = "testdata/fixtures/sbom/centos-7-spdx.json (centos 7.6.1810)"

View File

@@ -14,7 +14,7 @@
"packages": [
{
"name": "openssl",
"SPDXID": "SPDXRef-Package-b8061a5279413d55",
"SPDXID": "SPDXRef-Package-32b6b37a6fa2e57f",
"versionInfo": "1.1.1q",
"supplier": "NOASSERTION",
"downloadLocation": "NONE",
@@ -38,7 +38,7 @@
},
{
"name": "pip",
"SPDXID": "SPDXRef-Package-84198b3828050c11",
"SPDXID": "SPDXRef-Package-e260029d0b6fd07b",
"versionInfo": "22.2.2",
"supplier": "NOASSERTION",
"downloadLocation": "NONE",
@@ -103,23 +103,23 @@
},
{
"spdxElementId": "SPDXRef-Filesystem-2e2426fd0f2580ef",
"relatedSpdxElement": "SPDXRef-Package-84198b3828050c11",
"relatedSpdxElement": "SPDXRef-Package-32b6b37a6fa2e57f",
"relationshipType": "CONTAINS"
},
{
"spdxElementId": "SPDXRef-Filesystem-2e2426fd0f2580ef",
"relatedSpdxElement": "SPDXRef-Package-b8061a5279413d55",
"relatedSpdxElement": "SPDXRef-Package-e260029d0b6fd07b",
"relationshipType": "CONTAINS"
},
{
"spdxElementId": "SPDXRef-Package-84198b3828050c11",
"relatedSpdxElement": "SPDXRef-File-7eb62e2a3edddc0a",
"relationshipType": "CONTAINS"
},
{
"spdxElementId": "SPDXRef-Package-b8061a5279413d55",
"spdxElementId": "SPDXRef-Package-32b6b37a6fa2e57f",
"relatedSpdxElement": "SPDXRef-File-600e5e0110a84891",
"relationshipType": "CONTAINS"
},
{
"spdxElementId": "SPDXRef-Package-e260029d0b6fd07b",
"relatedSpdxElement": "SPDXRef-File-7eb62e2a3edddc0a",
"relationshipType": "CONTAINS"
}
]
}

View File

@@ -12,7 +12,7 @@ import (
"github.com/aquasecurity/tml"
"github.com/aquasecurity/trivy/pkg/clock"
cr "github.com/aquasecurity/trivy/pkg/compliance/report"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
"github.com/aquasecurity/trivy/pkg/flag"
"github.com/aquasecurity/trivy/pkg/iac/scan"
pkgReport "github.com/aquasecurity/trivy/pkg/report"
@@ -97,7 +97,7 @@ func Write(ctx context.Context, rep *Report, opt flag.Options, fromCache bool) e
base := types.Report{
CreatedAt: clock.Now(ctx),
ArtifactName: rep.AccountID,
ArtifactType: ftypes.ArtifactAWSAccount,
ArtifactType: artifact.TypeAWSAccount,
Results: filtered,
}

View File

@@ -4,10 +4,13 @@ import (
"context"
"sort"
"github.com/google/go-containerregistry/pkg/v1"
"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
"github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/fanal/walker"
"github.com/aquasecurity/trivy/pkg/misconf"
"github.com/aquasecurity/trivy/pkg/sbom/core"
)
type Option struct {
@@ -72,6 +75,39 @@ func (o *Option) Sort() {
}
type Artifact interface {
Inspect(ctx context.Context) (reference types.ArtifactReference, err error)
Clean(reference types.ArtifactReference) error
Inspect(ctx context.Context) (reference Reference, err error)
Clean(reference Reference) error
}
// Type represents a type of artifact
type Type string
const (
TypeContainerImage Type = "container_image"
TypeFilesystem Type = "filesystem"
TypeRepository Type = "repository"
TypeCycloneDX Type = "cyclonedx"
TypeSPDX Type = "spdx"
TypeAWSAccount Type = "aws_account"
TypeVM Type = "vm"
)
// Reference represents a reference of container image, local filesystem and repository
type Reference struct {
Name string // image name, tar file name, directory or repository name
Type Type
ID string
BlobIDs []string
ImageMetadata ImageMetadata
// SBOM
BOM *core.BOM
}
type ImageMetadata struct {
ID string // image ID
DiffIDs []string // uncompressed layer IDs
RepoTags []string
RepoDigests []string
ConfigFile v1.ConfigFile
}

View File

@@ -73,16 +73,16 @@ func NewArtifact(img types.Image, c cache.ArtifactCache, opt artifact.Option) (a
}, nil
}
func (a Artifact) Inspect(ctx context.Context) (types.ArtifactReference, error) {
func (a Artifact) Inspect(ctx context.Context) (artifact.Reference, error) {
imageID, err := a.image.ID()
if err != nil {
return types.ArtifactReference{}, xerrors.Errorf("unable to get the image ID: %w", err)
return artifact.Reference{}, xerrors.Errorf("unable to get the image ID: %w", err)
}
a.logger.Debug("Detected image ID", log.String("image_id", imageID))
configFile, err := a.image.ConfigFile()
if err != nil {
return types.ArtifactReference{}, xerrors.Errorf("unable to get the image's config file: %w", err)
return artifact.Reference{}, xerrors.Errorf("unable to get the image's config file: %w", err)
}
diffIDs := a.diffIDs(configFile)
@@ -94,7 +94,7 @@ func (a Artifact) Inspect(ctx context.Context) (types.ArtifactReference, error)
return res, nil
} else if !errors.Is(err, errNoSBOMFound) {
// Fail on unexpected error, otherwise it falls into the usual scanning.
return types.ArtifactReference{}, xerrors.Errorf("remote SBOM fetching error: %w", err)
return artifact.Reference{}, xerrors.Errorf("remote SBOM fetching error: %w", err)
}
// Try to detect base layers.
@@ -104,7 +104,7 @@ func (a Artifact) Inspect(ctx context.Context) (types.ArtifactReference, error)
// Convert image ID and layer IDs to cache keys
imageKey, layerKeys, err := a.calcCacheKeys(imageID, diffIDs)
if err != nil {
return types.ArtifactReference{}, err
return artifact.Reference{}, err
}
// Parse histories and extract a list of "created_by"
@@ -112,7 +112,7 @@ func (a Artifact) Inspect(ctx context.Context) (types.ArtifactReference, error)
missingImage, missingLayers, err := a.cache.MissingBlobs(imageKey, layerKeys)
if err != nil {
return types.ArtifactReference{}, xerrors.Errorf("unable to get missing layers: %w", err)
return artifact.Reference{}, xerrors.Errorf("unable to get missing layers: %w", err)
}
missingImageKey := imageKey
@@ -123,15 +123,15 @@ func (a Artifact) Inspect(ctx context.Context) (types.ArtifactReference, error)
}
if err = a.inspect(ctx, missingImageKey, missingLayers, baseDiffIDs, layerKeyMap, configFile); err != nil {
return types.ArtifactReference{}, xerrors.Errorf("analyze error: %w", err)
return artifact.Reference{}, xerrors.Errorf("analyze error: %w", err)
}
return types.ArtifactReference{
return artifact.Reference{
Name: a.image.Name(),
Type: types.ArtifactContainerImage,
Type: artifact.TypeContainerImage,
ID: imageKey,
BlobIDs: layerKeys,
ImageMetadata: types.ImageMetadata{
ImageMetadata: artifact.ImageMetadata{
ID: imageID,
DiffIDs: diffIDs,
RepoTags: a.image.RepoTags(),
@@ -141,7 +141,7 @@ func (a Artifact) Inspect(ctx context.Context) (types.ArtifactReference, error)
}, nil
}
func (Artifact) Clean(_ types.ArtifactReference) error {
func (Artifact) Clean(_ artifact.Reference) error {
return nil
}

View File

@@ -340,7 +340,7 @@ func TestArtifact_Inspect(t *testing.T) {
missingBlobsExpectation cache.ArtifactCacheMissingBlobsExpectation
putBlobExpectations []cache.ArtifactCachePutBlobExpectation
putArtifactExpectations []cache.ArtifactCachePutArtifactExpectation
want types.ArtifactReference
want artifact.Reference
wantErr string
}{
{
@@ -425,12 +425,12 @@ func TestArtifact_Inspect(t *testing.T) {
},
},
},
want: types.ArtifactReference{
want: artifact.Reference{
Name: "../../test/testdata/alpine-311.tar.gz",
Type: types.ArtifactContainerImage,
Type: artifact.TypeContainerImage,
ID: "sha256:c232b7d8ac8aa08aa767313d0b53084c4380d1c01a213a5971bdb039e6538313",
BlobIDs: []string{"sha256:1fd280c63e1416a2261e76454caa19a5b77c6bddedd48309c9687c4fe72b34c0"},
ImageMetadata: types.ImageMetadata{
ImageMetadata: artifact.ImageMetadata{
ID: "sha256:a187dde48cd289ac374ad8539930628314bc581a481cdb41409c9289419ddb72",
DiffIDs: []string{
"sha256:beee9f30bc1f711043e78d4a2be0668955d4b761d587d6f60c2c8dc081efb203",
@@ -1756,9 +1756,9 @@ func TestArtifact_Inspect(t *testing.T) {
},
},
},
want: types.ArtifactReference{
want: artifact.Reference{
Name: "../../test/testdata/vuln-image.tar.gz",
Type: types.ArtifactContainerImage,
Type: artifact.TypeContainerImage,
ID: "sha256:33f9415ed2cd5a9cef5d5144333619745b9ec0f851f0684dd45fa79c6b26a650",
BlobIDs: []string{
"sha256:dd0a4f4754bf4590327be34f4266f63c92184352afadb72e4c9b162f76224000",
@@ -1766,7 +1766,7 @@ func TestArtifact_Inspect(t *testing.T) {
"sha256:b6be0de11c6090f71dea119f43dd360335643420058e317baffb089f0dff4001",
"sha256:37c561c19b169f5f9832f4b0060bf74ebc8d1c9e01662ad4fa21c394da159440",
},
ImageMetadata: types.ImageMetadata{
ImageMetadata: artifact.ImageMetadata{
ID: "sha256:58701fd185bda36cab0557bb6438661831267aa4a9e0b54211c4d5317a48aff4",
DiffIDs: []string{
"sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
@@ -1921,9 +1921,9 @@ func TestArtifact_Inspect(t *testing.T) {
},
},
},
want: types.ArtifactReference{
want: artifact.Reference{
Name: "../../test/testdata/vuln-image.tar.gz",
Type: types.ArtifactContainerImage,
Type: artifact.TypeContainerImage,
ID: "sha256:33f9415ed2cd5a9cef5d5144333619745b9ec0f851f0684dd45fa79c6b26a650",
BlobIDs: []string{
"sha256:e1187118cdbe8893fc2fd4b345f813d195ee6aaeb4820d4576694199f8c10350",
@@ -1931,7 +1931,7 @@ func TestArtifact_Inspect(t *testing.T) {
"sha256:47adac0e28b12338e99dedbd7e8b0ef1f7aaa28e646f637ab2db8908b80704c8",
"sha256:dd1082b33b17401fdc31bcbf60eaaecb9ce29e23956c50db6f34b2cc6cfa13c8",
},
ImageMetadata: types.ImageMetadata{
ImageMetadata: artifact.ImageMetadata{
ID: "sha256:58701fd185bda36cab0557bb6438661831267aa4a9e0b54211c4d5317a48aff4",
DiffIDs: []string{
"sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",

View File

@@ -14,6 +14,7 @@ import (
"golang.org/x/xerrors"
sbomatt "github.com/aquasecurity/trivy/pkg/attestation/sbom"
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
"github.com/aquasecurity/trivy/pkg/fanal/artifact/sbom"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/log"
@@ -24,9 +25,9 @@ import (
var errNoSBOMFound = xerrors.New("remote SBOM not found")
type inspectRemoteSBOM func(context.Context) (ftypes.ArtifactReference, error)
type inspectRemoteSBOM func(context.Context) (artifact.Reference, error)
func (a Artifact) retrieveRemoteSBOM(ctx context.Context) (ftypes.ArtifactReference, error) {
func (a Artifact) retrieveRemoteSBOM(ctx context.Context) (artifact.Reference, error) {
for _, sbomSource := range a.artifactOption.SBOMSources {
var inspect inspectRemoteSBOM
switch sbomSource {
@@ -45,27 +46,27 @@ func (a Artifact) retrieveRemoteSBOM(ctx context.Context) (ftypes.ArtifactRefere
a.logger.Debug("No SBOM found in the source", log.String("source", sbomSource))
continue
} else if err != nil {
return ftypes.ArtifactReference{}, xerrors.Errorf("SBOM searching error: %w", err)
return artifact.Reference{}, xerrors.Errorf("SBOM searching error: %w", err)
}
return ref, nil
}
return ftypes.ArtifactReference{}, errNoSBOMFound
return artifact.Reference{}, errNoSBOMFound
}
func (a Artifact) inspectOCIReferrerSBOM(ctx context.Context) (ftypes.ArtifactReference, error) {
func (a Artifact) inspectOCIReferrerSBOM(ctx context.Context) (artifact.Reference, error) {
digest, err := repoDigest(a.image, a.artifactOption.Insecure)
if err != nil {
return ftypes.ArtifactReference{}, xerrors.Errorf("repo digest error: %w", err)
return artifact.Reference{}, xerrors.Errorf("repo digest error: %w", err)
}
// Fetch referrers
index, err := remote.Referrers(ctx, digest, a.artifactOption.ImageOption.RegistryOptions)
if err != nil {
return ftypes.ArtifactReference{}, xerrors.Errorf("unable to fetch referrers: %w", err)
return artifact.Reference{}, xerrors.Errorf("unable to fetch referrers: %w", err)
}
manifest, err := index.IndexManifest()
if err != nil {
return ftypes.ArtifactReference{}, xerrors.Errorf("unable to get manifest: %w", err)
return artifact.Reference{}, xerrors.Errorf("unable to get manifest: %w", err)
}
for _, m := range lo.FromPtr(manifest).Manifests {
// Unsupported artifact type
@@ -80,20 +81,20 @@ func (a Artifact) inspectOCIReferrerSBOM(ctx context.Context) (ftypes.ArtifactRe
}
return res, nil
}
return ftypes.ArtifactReference{}, errNoSBOMFound
return artifact.Reference{}, errNoSBOMFound
}
func (a Artifact) parseReferrer(ctx context.Context, repo string, desc v1.Descriptor) (ftypes.ArtifactReference, error) {
func (a Artifact) parseReferrer(ctx context.Context, repo string, desc v1.Descriptor) (artifact.Reference, error) {
const fileName string = "referrer.sbom"
repoName := fmt.Sprintf("%s@%s", repo, desc.Digest)
referrer, err := oci.NewArtifact(repoName, true, a.artifactOption.ImageOption.RegistryOptions)
if err != nil {
return ftypes.ArtifactReference{}, xerrors.Errorf("OCI error: %w", err)
return artifact.Reference{}, xerrors.Errorf("OCI error: %w", err)
}
tmpDir, err := os.MkdirTemp("", "trivy-sbom-*")
if err != nil {
return ftypes.ArtifactReference{}, xerrors.Errorf("mkdir temp error: %w", err)
return artifact.Reference{}, xerrors.Errorf("mkdir temp error: %w", err)
}
defer os.RemoveAll(tmpDir)
@@ -102,7 +103,7 @@ func (a Artifact) parseReferrer(ctx context.Context, repo string, desc v1.Descri
MediaType: desc.ArtifactType,
Filename: fileName,
}); err != nil {
return ftypes.ArtifactReference{}, xerrors.Errorf("SBOM download error: %w", err)
return artifact.Reference{}, xerrors.Errorf("SBOM download error: %w", err)
}
res, err := a.inspectSBOMFile(ctx, filepath.Join(tmpDir, fileName))
@@ -116,35 +117,35 @@ func (a Artifact) parseReferrer(ctx context.Context, repo string, desc v1.Descri
return res, nil
}
func (a Artifact) inspectRekorSBOMAttestation(ctx context.Context) (ftypes.ArtifactReference, error) {
func (a Artifact) inspectRekorSBOMAttestation(ctx context.Context) (artifact.Reference, error) {
digest, err := repoDigest(a.image, a.artifactOption.Insecure)
if err != nil {
return ftypes.ArtifactReference{}, xerrors.Errorf("repo digest error: %w", err)
return artifact.Reference{}, xerrors.Errorf("repo digest error: %w", err)
}
client, err := sbomatt.NewRekor(a.artifactOption.RekorURL)
if err != nil {
return ftypes.ArtifactReference{}, xerrors.Errorf("failed to create rekor client: %w", err)
return artifact.Reference{}, xerrors.Errorf("failed to create rekor client: %w", err)
}
raw, err := client.RetrieveSBOM(ctx, digest.DigestStr())
if errors.Is(err, sbomatt.ErrNoSBOMAttestation) {
return ftypes.ArtifactReference{}, errNoSBOMFound
return artifact.Reference{}, errNoSBOMFound
} else if err != nil {
return ftypes.ArtifactReference{}, xerrors.Errorf("failed to retrieve SBOM attestation: %w", err)
return artifact.Reference{}, xerrors.Errorf("failed to retrieve SBOM attestation: %w", err)
}
f, err := os.CreateTemp("", "sbom-*")
if err != nil {
return ftypes.ArtifactReference{}, xerrors.Errorf("failed to create a temporary file: %w", err)
return artifact.Reference{}, xerrors.Errorf("failed to create a temporary file: %w", err)
}
defer os.Remove(f.Name())
if _, err = f.Write(raw); err != nil {
return ftypes.ArtifactReference{}, xerrors.Errorf("copy error: %w", err)
return artifact.Reference{}, xerrors.Errorf("copy error: %w", err)
}
if err = f.Close(); err != nil {
return ftypes.ArtifactReference{}, xerrors.Errorf("failed to close %s: %w", f.Name(), err)
return artifact.Reference{}, xerrors.Errorf("failed to close %s: %w", f.Name(), err)
}
res, err := a.inspectSBOMFile(ctx, f.Name())
if err != nil {
@@ -158,15 +159,15 @@ func (a Artifact) inspectRekorSBOMAttestation(ctx context.Context) (ftypes.Artif
return res, nil
}
func (a Artifact) inspectSBOMFile(ctx context.Context, filePath string) (ftypes.ArtifactReference, error) {
func (a Artifact) inspectSBOMFile(ctx context.Context, filePath string) (artifact.Reference, error) {
ar, err := sbom.NewArtifact(filePath, a.cache, a.artifactOption)
if err != nil {
return ftypes.ArtifactReference{}, xerrors.Errorf("failed to new artifact: %w", err)
return artifact.Reference{}, xerrors.Errorf("failed to new artifact: %w", err)
}
results, err := ar.Inspect(ctx)
if err != nil {
return ftypes.ArtifactReference{}, xerrors.Errorf("failed to inspect: %w", err)
return artifact.Reference{}, xerrors.Errorf("failed to inspect: %w", err)
}
results.Name = a.image.Name()

View File

@@ -56,7 +56,7 @@ func TestArtifact_InspectRekorAttestation(t *testing.T) {
fields fields
artifactOpt artifact.Option
putBlobExpectations []cache.ArtifactCachePutBlobExpectation
want types.ArtifactReference
want artifact.Reference
wantErr string
}{
{
@@ -117,9 +117,9 @@ func TestArtifact_InspectRekorAttestation(t *testing.T) {
artifactOpt: artifact.Option{
SBOMSources: []string{"rekor"},
},
want: types.ArtifactReference{
want: artifact.Reference{
Name: "test/image:10",
Type: types.ArtifactCycloneDX,
Type: artifact.TypeCycloneDX,
ID: "sha256:066b9998617ffb7dfe0a3219ac5c3efc1008a6223606fcf474e7d5c965e4e8da",
BlobIDs: []string{
"sha256:066b9998617ffb7dfe0a3219ac5c3efc1008a6223606fcf474e7d5c965e4e8da",
@@ -206,7 +206,7 @@ func TestArtifact_inspectOCIReferrerSBOM(t *testing.T) {
fields fields
artifactOpt artifact.Option
putBlobExpectations []cache.ArtifactCachePutBlobExpectation
want types.ArtifactReference
want artifact.Reference
wantErr string
}{
{
@@ -265,9 +265,9 @@ func TestArtifact_inspectOCIReferrerSBOM(t *testing.T) {
},
},
},
want: types.ArtifactReference{
want: artifact.Reference{
Name: registry + "/test/image:10",
Type: types.ArtifactCycloneDX,
Type: artifact.TypeCycloneDX,
ID: "sha256:a06ed679a3289fba254040e1ce8f3467fadcc454ee3d0d4720f6978065f56684",
BlobIDs: []string{
"sha256:a06ed679a3289fba254040e1ce8f3467fadcc454ee3d0d4720f6978065f56684",

View File

@@ -68,7 +68,7 @@ func NewArtifact(rootPath string, c cache.ArtifactCache, w Walker, opt artifact.
}, nil
}
func (a Artifact) Inspect(ctx context.Context) (types.ArtifactReference, error) {
func (a Artifact) Inspect(ctx context.Context) (artifact.Reference, error) {
var wg sync.WaitGroup
result := analyzer.NewAnalysisResult()
limit := semaphore.New(a.artifactOption.Parallel)
@@ -80,7 +80,7 @@ func (a Artifact) Inspect(ctx context.Context) (types.ArtifactReference, error)
// Prepare filesystem for post analysis
composite, err := a.analyzer.PostAnalyzerFS()
if err != nil {
return types.ArtifactReference{}, xerrors.Errorf("failed to prepare filesystem for post analysis: %w", err)
return artifact.Reference{}, xerrors.Errorf("failed to prepare filesystem for post analysis: %w", err)
}
err = a.walker.Walk(a.rootPath, a.artifactOption.WalkerOption, func(filePath string, info os.FileInfo, opener analyzer.Opener) error {
@@ -110,7 +110,7 @@ func (a Artifact) Inspect(ctx context.Context) (types.ArtifactReference, error)
return nil
})
if err != nil {
return types.ArtifactReference{}, xerrors.Errorf("walk filesystem: %w", err)
return artifact.Reference{}, xerrors.Errorf("walk filesystem: %w", err)
}
// Wait for all the goroutine to finish.
@@ -118,7 +118,7 @@ func (a Artifact) Inspect(ctx context.Context) (types.ArtifactReference, error)
// Post-analysis
if err = a.analyzer.PostAnalyze(ctx, composite, result, opts); err != nil {
return types.ArtifactReference{}, xerrors.Errorf("post analysis error: %w", err)
return artifact.Reference{}, xerrors.Errorf("post analysis error: %w", err)
}
// Sort the analysis result for consistent results
@@ -137,16 +137,16 @@ func (a Artifact) Inspect(ctx context.Context) (types.ArtifactReference, error)
}
if err = a.handlerManager.PostHandle(ctx, result, &blobInfo); err != nil {
return types.ArtifactReference{}, xerrors.Errorf("failed to call hooks: %w", err)
return artifact.Reference{}, xerrors.Errorf("failed to call hooks: %w", err)
}
cacheKey, err := a.calcCacheKey(blobInfo)
if err != nil {
return types.ArtifactReference{}, xerrors.Errorf("failed to calculate a cache key: %w", err)
return artifact.Reference{}, xerrors.Errorf("failed to calculate a cache key: %w", err)
}
if err = a.cache.PutBlob(cacheKey, blobInfo); err != nil {
return types.ArtifactReference{}, xerrors.Errorf("failed to store blob (%s) in cache: %w", cacheKey, err)
return artifact.Reference{}, xerrors.Errorf("failed to store blob (%s) in cache: %w", cacheKey, err)
}
// get hostname
@@ -159,15 +159,15 @@ func (a Artifact) Inspect(ctx context.Context) (types.ArtifactReference, error)
hostName = filepath.ToSlash(a.rootPath)
}
return types.ArtifactReference{
return artifact.Reference{
Name: hostName,
Type: types.ArtifactFilesystem,
Type: artifact.TypeFilesystem,
ID: cacheKey, // use a cache key as pseudo artifact ID
BlobIDs: []string{cacheKey},
}, nil
}
func (a Artifact) Clean(reference types.ArtifactReference) error {
func (a Artifact) Clean(reference artifact.Reference) error {
return a.cache.DeleteBlobs(reference.BlobIDs)
}

View File

@@ -36,7 +36,7 @@ func TestArtifact_Inspect(t *testing.T) {
disabledAnalyzers []analyzer.Type
disabledHandlers []types.HandlerType
putBlobExpectation cache.ArtifactCachePutBlobExpectation
want types.ArtifactReference
want artifact.Reference
wantErr string
}{
{
@@ -78,9 +78,9 @@ func TestArtifact_Inspect(t *testing.T) {
},
Returns: cache.ArtifactCachePutBlobReturns{},
},
want: types.ArtifactReference{
want: artifact.Reference{
Name: "host",
Type: types.ArtifactFilesystem,
Type: artifact.TypeFilesystem,
ID: "sha256:afc2bc421aac8c61d89d4dd1c1865efb5441e3877c8a4c919232729d7c574dab",
BlobIDs: []string{
"sha256:afc2bc421aac8c61d89d4dd1c1865efb5441e3877c8a4c919232729d7c574dab",
@@ -108,9 +108,9 @@ func TestArtifact_Inspect(t *testing.T) {
},
Returns: cache.ArtifactCachePutBlobReturns{},
},
want: types.ArtifactReference{
want: artifact.Reference{
Name: "host",
Type: types.ArtifactFilesystem,
Type: artifact.TypeFilesystem,
ID: "sha256:7db98974b2231d3e25f4890008c4d42f6f26a7da5a8aba99e954dec97f050bd6",
BlobIDs: []string{
"sha256:7db98974b2231d3e25f4890008c4d42f6f26a7da5a8aba99e954dec97f050bd6",
@@ -193,9 +193,9 @@ func TestArtifact_Inspect(t *testing.T) {
},
Returns: cache.ArtifactCachePutBlobReturns{},
},
want: types.ArtifactReference{
want: artifact.Reference{
Name: "testdata/requirements.txt",
Type: types.ArtifactFilesystem,
Type: artifact.TypeFilesystem,
ID: "sha256:9e999fcf6fd571e175601fb7cc0da28f0d7960e26eab67dad93152e0bebf21ca",
BlobIDs: []string{
"sha256:9e999fcf6fd571e175601fb7cc0da28f0d7960e26eab67dad93152e0bebf21ca",
@@ -228,9 +228,9 @@ func TestArtifact_Inspect(t *testing.T) {
},
Returns: cache.ArtifactCachePutBlobReturns{},
},
want: types.ArtifactReference{
want: artifact.Reference{
Name: "testdata/requirements.txt",
Type: types.ArtifactFilesystem,
Type: artifact.TypeFilesystem,
ID: "sha256:9e999fcf6fd571e175601fb7cc0da28f0d7960e26eab67dad93152e0bebf21ca",
BlobIDs: []string{
"sha256:9e999fcf6fd571e175601fb7cc0da28f0d7960e26eab67dad93152e0bebf21ca",
@@ -279,7 +279,7 @@ func TestTerraformMisconfigurationScan(t *testing.T) {
fields fields
putBlobExpectation cache.ArtifactCachePutBlobExpectation
artifactOpt artifact.Option
want types.ArtifactReference
want artifact.Reference
}{
{
name: "single failure",
@@ -325,9 +325,9 @@ func TestTerraformMisconfigurationScan(t *testing.T) {
},
Returns: cache.ArtifactCachePutBlobReturns{},
},
want: types.ArtifactReference{
want: artifact.Reference{
Name: "testdata/misconfig/terraform/single-failure",
Type: types.ArtifactFilesystem,
Type: artifact.TypeFilesystem,
ID: "sha256:1a6ce0acc3b57eb6c830c96fcd868fec1eb4d3b57ad51e481c76d85f22870a65",
BlobIDs: []string{
"sha256:1a6ce0acc3b57eb6c830c96fcd868fec1eb4d3b57ad51e481c76d85f22870a65",
@@ -410,9 +410,9 @@ func TestTerraformMisconfigurationScan(t *testing.T) {
},
Returns: cache.ArtifactCachePutBlobReturns{},
},
want: types.ArtifactReference{
want: artifact.Reference{
Name: "testdata/misconfig/terraform/multiple-failures",
Type: types.ArtifactFilesystem,
Type: artifact.TypeFilesystem,
ID: "sha256:afc20cf0fc99c62bbc79b00cb9fbc70ba7ee76c946a6d560639ba9279344787d",
BlobIDs: []string{
"sha256:afc20cf0fc99c62bbc79b00cb9fbc70ba7ee76c946a6d560639ba9279344787d",
@@ -440,9 +440,9 @@ func TestTerraformMisconfigurationScan(t *testing.T) {
},
Returns: cache.ArtifactCachePutBlobReturns{},
},
want: types.ArtifactReference{
want: artifact.Reference{
Name: "testdata/misconfig/terraform/no-results",
Type: types.ArtifactFilesystem,
Type: artifact.TypeFilesystem,
ID: "sha256:1827b6a0b0a17e0d623a2045e9d9c331ef613390eda2fed823969ee0dd730257",
BlobIDs: []string{
"sha256:1827b6a0b0a17e0d623a2045e9d9c331ef613390eda2fed823969ee0dd730257",
@@ -489,9 +489,9 @@ func TestTerraformMisconfigurationScan(t *testing.T) {
},
Returns: cache.ArtifactCachePutBlobReturns{},
},
want: types.ArtifactReference{
want: artifact.Reference{
Name: "testdata/misconfig/terraform/passed",
Type: types.ArtifactFilesystem,
Type: artifact.TypeFilesystem,
ID: "sha256:eec58ef10d1b04df4af76b2472e615f8c27e253a16f90d7542670a7001d88915",
BlobIDs: []string{
"sha256:eec58ef10d1b04df4af76b2472e615f8c27e253a16f90d7542670a7001d88915",
@@ -555,9 +555,9 @@ func TestTerraformMisconfigurationScan(t *testing.T) {
},
Returns: cache.ArtifactCachePutBlobReturns{},
},
want: types.ArtifactReference{
want: artifact.Reference{
Name: "testdata/misconfig/terraform/busted-relative-paths/child/main.tf",
Type: types.ArtifactFilesystem,
Type: artifact.TypeFilesystem,
ID: "sha256:8db34d644bfb98077180616caeab0b41a26d9029a47a23d4b36e1d6e45584919",
BlobIDs: []string{
"sha256:8db34d644bfb98077180616caeab0b41a26d9029a47a23d4b36e1d6e45584919",
@@ -605,9 +605,9 @@ func TestTerraformMisconfigurationScan(t *testing.T) {
},
Returns: cache.ArtifactCachePutBlobReturns{},
},
want: types.ArtifactReference{
want: artifact.Reference{
Name: "testdata/misconfig/terraform/tfvar-outside/tf",
Type: types.ArtifactFilesystem,
Type: artifact.TypeFilesystem,
ID: "sha256:eec58ef10d1b04df4af76b2472e615f8c27e253a16f90d7542670a7001d88915",
BlobIDs: []string{
"sha256:eec58ef10d1b04df4af76b2472e615f8c27e253a16f90d7542670a7001d88915",
@@ -695,9 +695,9 @@ func TestTerraformMisconfigurationScan(t *testing.T) {
},
Returns: cache.ArtifactCachePutBlobReturns{},
},
want: types.ArtifactReference{
want: artifact.Reference{
Name: "testdata/misconfig/terraform/relative-paths/child",
Type: types.ArtifactFilesystem,
Type: artifact.TypeFilesystem,
ID: "sha256:f13b89447db61be1c1e4099ef18aec7272091f8f2d3581643a9d1fabc74eda83",
BlobIDs: []string{
"sha256:f13b89447db61be1c1e4099ef18aec7272091f8f2d3581643a9d1fabc74eda83",
@@ -776,7 +776,7 @@ func TestTerraformPlanSnapshotMisconfScan(t *testing.T) {
name string
fields fields
putBlobExpectation cache.ArtifactCachePutBlobExpectation
want types.ArtifactReference
want artifact.Reference
}{
{
name: "single failure",
@@ -814,9 +814,9 @@ func TestTerraformPlanSnapshotMisconfScan(t *testing.T) {
},
Returns: cache.ArtifactCachePutBlobReturns{},
},
want: types.ArtifactReference{
want: artifact.Reference{
Name: "testdata/misconfig/terraformplan/snapshots/single-failure",
Type: types.ArtifactFilesystem,
Type: artifact.TypeFilesystem,
ID: "sha256:732c38451bde877a94d1ff5b6f2019655bed04fd24b1169de195eeee1199045e",
BlobIDs: []string{
"sha256:732c38451bde877a94d1ff5b6f2019655bed04fd24b1169de195eeee1199045e",
@@ -890,9 +890,9 @@ func TestTerraformPlanSnapshotMisconfScan(t *testing.T) {
},
Returns: cache.ArtifactCachePutBlobReturns{},
},
want: types.ArtifactReference{
want: artifact.Reference{
Name: "testdata/misconfig/terraformplan/snapshots/multiple-failures",
Type: types.ArtifactFilesystem,
Type: artifact.TypeFilesystem,
ID: "sha256:752c0b470adfcfe7e21892cf4c6fc3bc28dba873c9c1696f40b71b7a51ad7231",
BlobIDs: []string{
"sha256:752c0b470adfcfe7e21892cf4c6fc3bc28dba873c9c1696f40b71b7a51ad7231",
@@ -930,9 +930,9 @@ func TestTerraformPlanSnapshotMisconfScan(t *testing.T) {
},
Returns: cache.ArtifactCachePutBlobReturns{},
},
want: types.ArtifactReference{
want: artifact.Reference{
Name: "testdata/misconfig/terraformplan/snapshots/passed",
Type: types.ArtifactFilesystem,
Type: artifact.TypeFilesystem,
ID: "sha256:8947704a08f54ab1df32cd905d6bca72edf1785a42702968bafa331172da7176",
BlobIDs: []string{
"sha256:8947704a08f54ab1df32cd905d6bca72edf1785a42702968bafa331172da7176",
@@ -990,7 +990,7 @@ func TestCloudFormationMisconfigurationScan(t *testing.T) {
fields fields
putBlobExpectation cache.ArtifactCachePutBlobExpectation
artifactOpt artifact.Option
want types.ArtifactReference
want artifact.Reference
}{
{
name: "single failure",
@@ -1045,9 +1045,9 @@ func TestCloudFormationMisconfigurationScan(t *testing.T) {
},
Returns: cache.ArtifactCachePutBlobReturns{},
},
want: types.ArtifactReference{
want: artifact.Reference{
Name: "testdata/misconfig/cloudformation/single-failure/src",
Type: types.ArtifactFilesystem,
Type: artifact.TypeFilesystem,
ID: "sha256:889a94522970c6e55f1f7543914b2f0131f79f9c4526445fb95309f64a9947d7",
BlobIDs: []string{
"sha256:889a94522970c6e55f1f7543914b2f0131f79f9c4526445fb95309f64a9947d7",
@@ -1129,9 +1129,9 @@ func TestCloudFormationMisconfigurationScan(t *testing.T) {
},
Returns: cache.ArtifactCachePutBlobReturns{},
},
want: types.ArtifactReference{
want: artifact.Reference{
Name: "testdata/misconfig/cloudformation/multiple-failures/src",
Type: types.ArtifactFilesystem,
Type: artifact.TypeFilesystem,
ID: "sha256:17c9c72a759856445e6d3847b2d5ed90c3bad3e4ee50cea0c812ef53c179f8ca",
BlobIDs: []string{
"sha256:17c9c72a759856445e6d3847b2d5ed90c3bad3e4ee50cea0c812ef53c179f8ca",
@@ -1161,9 +1161,9 @@ func TestCloudFormationMisconfigurationScan(t *testing.T) {
},
Returns: cache.ArtifactCachePutBlobReturns{},
},
want: types.ArtifactReference{
want: artifact.Reference{
Name: "testdata/misconfig/cloudformation/no-results/src",
Type: types.ArtifactFilesystem,
Type: artifact.TypeFilesystem,
ID: "sha256:26c76a2cb55cb0ef2c3a2dd79e237bddb508ca2c4cefdb103698a1972c8a9c2d",
BlobIDs: []string{
"sha256:26c76a2cb55cb0ef2c3a2dd79e237bddb508ca2c4cefdb103698a1972c8a9c2d",
@@ -1219,9 +1219,9 @@ func TestCloudFormationMisconfigurationScan(t *testing.T) {
},
Returns: cache.ArtifactCachePutBlobReturns{},
},
want: types.ArtifactReference{
want: artifact.Reference{
Name: "testdata/misconfig/cloudformation/params/code/src",
Type: types.ArtifactFilesystem,
Type: artifact.TypeFilesystem,
ID: "sha256:267b572211115db6a2a4484a02317fbb6d4f050da0e95b1db4243d49889483de",
BlobIDs: []string{
"sha256:267b572211115db6a2a4484a02317fbb6d4f050da0e95b1db4243d49889483de",
@@ -1277,9 +1277,9 @@ func TestCloudFormationMisconfigurationScan(t *testing.T) {
},
Returns: cache.ArtifactCachePutBlobReturns{},
},
want: types.ArtifactReference{
want: artifact.Reference{
Name: "testdata/misconfig/cloudformation/passed/src",
Type: types.ArtifactFilesystem,
Type: artifact.TypeFilesystem,
ID: "sha256:8ca92725ce2f47b7ffb1b0a9e0359d59ac2b3b3f517ba42f66a859436057e54a",
BlobIDs: []string{
"sha256:8ca92725ce2f47b7ffb1b0a9e0359d59ac2b3b3f517ba42f66a859436057e54a",
@@ -1314,7 +1314,7 @@ func TestDockerfileMisconfigurationScan(t *testing.T) {
fields fields
putBlobExpectation cache.ArtifactCachePutBlobExpectation
artifactOpt artifact.Option
want types.ArtifactReference
want artifact.Reference
}{
{
name: "single failure",
@@ -1365,9 +1365,9 @@ func TestDockerfileMisconfigurationScan(t *testing.T) {
},
Returns: cache.ArtifactCachePutBlobReturns{},
},
want: types.ArtifactReference{
want: artifact.Reference{
Name: "testdata/misconfig/dockerfile/single-failure/src",
Type: types.ArtifactFilesystem,
Type: artifact.TypeFilesystem,
ID: "sha256:627cbf451ec7929dfe5151dfe0e2305ed855906bf79136f198528a0cc3f6e4f9",
BlobIDs: []string{
"sha256:627cbf451ec7929dfe5151dfe0e2305ed855906bf79136f198528a0cc3f6e4f9",
@@ -1423,9 +1423,9 @@ func TestDockerfileMisconfigurationScan(t *testing.T) {
},
Returns: cache.ArtifactCachePutBlobReturns{},
},
want: types.ArtifactReference{
want: artifact.Reference{
Name: "testdata/misconfig/dockerfile/multiple-failures/src",
Type: types.ArtifactFilesystem,
Type: artifact.TypeFilesystem,
ID: "sha256:627cbf451ec7929dfe5151dfe0e2305ed855906bf79136f198528a0cc3f6e4f9",
BlobIDs: []string{
"sha256:627cbf451ec7929dfe5151dfe0e2305ed855906bf79136f198528a0cc3f6e4f9",
@@ -1453,9 +1453,9 @@ func TestDockerfileMisconfigurationScan(t *testing.T) {
},
Returns: cache.ArtifactCachePutBlobReturns{},
},
want: types.ArtifactReference{
want: artifact.Reference{
Name: "testdata/misconfig/dockerfile/no-results/src",
Type: types.ArtifactFilesystem,
Type: artifact.TypeFilesystem,
ID: "sha256:26c76a2cb55cb0ef2c3a2dd79e237bddb508ca2c4cefdb103698a1972c8a9c2d",
BlobIDs: []string{
"sha256:26c76a2cb55cb0ef2c3a2dd79e237bddb508ca2c4cefdb103698a1972c8a9c2d",
@@ -1513,9 +1513,9 @@ func TestDockerfileMisconfigurationScan(t *testing.T) {
},
Returns: cache.ArtifactCachePutBlobReturns{},
},
want: types.ArtifactReference{
want: artifact.Reference{
Name: "testdata/misconfig/dockerfile/passed/src",
Type: types.ArtifactFilesystem,
Type: artifact.TypeFilesystem,
ID: "sha256:4cc7f6bba417cc65c5391bc9c07fd1e205e21bdec87b271889433af18be1e454",
BlobIDs: []string{
"sha256:4cc7f6bba417cc65c5391bc9c07fd1e205e21bdec87b271889433af18be1e454",
@@ -1549,7 +1549,7 @@ func TestKubernetesMisconfigurationScan(t *testing.T) {
fields fields
putBlobExpectation cache.ArtifactCachePutBlobExpectation
artifactOpt artifact.Option
want types.ArtifactReference
want artifact.Reference
}{
{
name: "single failure",
@@ -1605,9 +1605,9 @@ func TestKubernetesMisconfigurationScan(t *testing.T) {
},
Returns: cache.ArtifactCachePutBlobReturns{},
},
want: types.ArtifactReference{
want: artifact.Reference{
Name: "testdata/misconfig/kubernetes/single-failure/src",
Type: types.ArtifactFilesystem,
Type: artifact.TypeFilesystem,
ID: "sha256:d5ca0b4e96aaaeafa424a2250db6297a5182cb6ca5db49bc1ff11790f6cdbee9",
BlobIDs: []string{
"sha256:d5ca0b4e96aaaeafa424a2250db6297a5182cb6ca5db49bc1ff11790f6cdbee9",
@@ -1691,9 +1691,9 @@ func TestKubernetesMisconfigurationScan(t *testing.T) {
},
Returns: cache.ArtifactCachePutBlobReturns{},
},
want: types.ArtifactReference{
want: artifact.Reference{
Name: "testdata/misconfig/kubernetes/multiple-failures/src",
Type: types.ArtifactFilesystem,
Type: artifact.TypeFilesystem,
ID: "sha256:eef9fff2fe8f5c4a123c018b4f91db25d9676e7d171a3a683c2fbfbbbe82fa54",
BlobIDs: []string{
"sha256:eef9fff2fe8f5c4a123c018b4f91db25d9676e7d171a3a683c2fbfbbbe82fa54",
@@ -1721,9 +1721,9 @@ func TestKubernetesMisconfigurationScan(t *testing.T) {
},
Returns: cache.ArtifactCachePutBlobReturns{},
},
want: types.ArtifactReference{
want: artifact.Reference{
Name: "testdata/misconfig/kubernetes/no-results/src",
Type: types.ArtifactFilesystem,
Type: artifact.TypeFilesystem,
ID: "sha256:2b54cf33feaa1fe1f5bf223f873ca6c3f7c3693b0bb3b0ce9e2e7fd79cd37b5a",
BlobIDs: []string{
"sha256:2b54cf33feaa1fe1f5bf223f873ca6c3f7c3693b0bb3b0ce9e2e7fd79cd37b5a",
@@ -1781,9 +1781,9 @@ func TestKubernetesMisconfigurationScan(t *testing.T) {
},
Returns: cache.ArtifactCachePutBlobReturns{},
},
want: types.ArtifactReference{
want: artifact.Reference{
Name: "testdata/misconfig/kubernetes/passed/src",
Type: types.ArtifactFilesystem,
Type: artifact.TypeFilesystem,
ID: "sha256:dc7a0fd3ea2f13b0ea05f4e517a16e602b0fc17fbd72aa5e34107ef12a91a30b",
BlobIDs: []string{
"sha256:dc7a0fd3ea2f13b0ea05f4e517a16e602b0fc17fbd72aa5e34107ef12a91a30b",
@@ -1817,7 +1817,7 @@ func TestAzureARMMisconfigurationScan(t *testing.T) {
fields fields
putBlobExpectation cache.ArtifactCachePutBlobExpectation
artifactOpt artifact.Option
want types.ArtifactReference
want artifact.Reference
}{
{
name: "single failure",
@@ -1870,9 +1870,9 @@ func TestAzureARMMisconfigurationScan(t *testing.T) {
},
Returns: cache.ArtifactCachePutBlobReturns{},
},
want: types.ArtifactReference{
want: artifact.Reference{
Name: "testdata/misconfig/azurearm/single-failure/src",
Type: types.ArtifactFilesystem,
Type: artifact.TypeFilesystem,
ID: "sha256:c1a8bfd544b9041ad194382cc42b54289f70966d061ef501b267aec8fd07c5df",
BlobIDs: []string{
"sha256:c1a8bfd544b9041ad194382cc42b54289f70966d061ef501b267aec8fd07c5df",
@@ -1952,9 +1952,9 @@ func TestAzureARMMisconfigurationScan(t *testing.T) {
},
Returns: cache.ArtifactCachePutBlobReturns{},
},
want: types.ArtifactReference{
want: artifact.Reference{
Name: "testdata/misconfig/azurearm/multiple-failures/src",
Type: types.ArtifactFilesystem,
Type: artifact.TypeFilesystem,
ID: "sha256:75bf0e88f8d2857be90fb8d10a350c04c1532ba7f510e1eb404a8bae30ce97d8",
BlobIDs: []string{
"sha256:75bf0e88f8d2857be90fb8d10a350c04c1532ba7f510e1eb404a8bae30ce97d8",
@@ -1982,9 +1982,9 @@ func TestAzureARMMisconfigurationScan(t *testing.T) {
},
Returns: cache.ArtifactCachePutBlobReturns{},
},
want: types.ArtifactReference{
want: artifact.Reference{
Name: "testdata/misconfig/azurearm/no-results/src",
Type: types.ArtifactFilesystem,
Type: artifact.TypeFilesystem,
ID: "sha256:26c76a2cb55cb0ef2c3a2dd79e237bddb508ca2c4cefdb103698a1972c8a9c2d",
BlobIDs: []string{
"sha256:26c76a2cb55cb0ef2c3a2dd79e237bddb508ca2c4cefdb103698a1972c8a9c2d",
@@ -2038,9 +2038,9 @@ func TestAzureARMMisconfigurationScan(t *testing.T) {
},
Returns: cache.ArtifactCachePutBlobReturns{},
},
want: types.ArtifactReference{
want: artifact.Reference{
Name: "testdata/misconfig/azurearm/passed/src",
Type: types.ArtifactFilesystem,
Type: artifact.TypeFilesystem,
ID: "sha256:b9ba7c4eafec405c8b6998dbb98ee1c7f7830caf8487fd1461433ff82d8779e9",
BlobIDs: []string{
"sha256:b9ba7c4eafec405c8b6998dbb98ee1c7f7830caf8487fd1461433ff82d8779e9",
@@ -2074,7 +2074,7 @@ func TestMixedConfigurationScan(t *testing.T) {
fields fields
putBlobExpectation cache.ArtifactCachePutBlobExpectation
artifactOpt artifact.Option
want types.ArtifactReference
want artifact.Reference
}{
{
name: "single failure each within terraform and cloudformation",
@@ -2157,9 +2157,9 @@ func TestMixedConfigurationScan(t *testing.T) {
},
Returns: cache.ArtifactCachePutBlobReturns{},
},
want: types.ArtifactReference{
want: artifact.Reference{
Name: "testdata/misconfig/mixed/src",
Type: types.ArtifactFilesystem,
Type: artifact.TypeFilesystem,
},
},
}

View File

@@ -6,8 +6,6 @@ import (
context "context"
mock "github.com/stretchr/testify/mock"
types "github.com/aquasecurity/trivy/pkg/fanal/types"
)
// MockArtifact is an autogenerated mock type for the Artifact type
@@ -16,7 +14,7 @@ type MockArtifact struct {
}
type ArtifactCleanArgs struct {
Reference types.ArtifactReference
Reference Reference
ReferenceAnything bool
}
@@ -46,7 +44,7 @@ func (_m *MockArtifact) ApplyCleanExpectations(expectations []ArtifactCleanExpec
}
// Clean provides a mock function with given fields: reference
func (_m *MockArtifact) Clean(reference types.ArtifactReference) error {
func (_m *MockArtifact) Clean(reference Reference) error {
return nil
}
@@ -56,7 +54,7 @@ type ArtifactInspectArgs struct {
}
type ArtifactInspectReturns struct {
Reference types.ArtifactReference
Reference Reference
Err error
}
@@ -82,14 +80,14 @@ func (_m *MockArtifact) ApplyInspectExpectations(expectations []ArtifactInspectE
}
// Inspect provides a mock function with given fields: ctx
func (_m *MockArtifact) Inspect(ctx context.Context) (types.ArtifactReference, error) {
func (_m *MockArtifact) Inspect(ctx context.Context) (Reference, error) {
ret := _m.Called(ctx)
var r0 types.ArtifactReference
if rf, ok := ret.Get(0).(func(context.Context) types.ArtifactReference); ok {
var r0 Reference
if rf, ok := ret.Get(0).(func(context.Context) Reference); ok {
r0 = rf(ctx)
} else {
r0 = ret.Get(0).(types.ArtifactReference)
r0 = ret.Get(0).(Reference)
}
var r1 error

View File

@@ -15,7 +15,6 @@ import (
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
"github.com/aquasecurity/trivy/pkg/fanal/artifact/local"
"github.com/aquasecurity/trivy/pkg/fanal/cache"
"github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/fanal/walker"
)
@@ -62,21 +61,21 @@ func NewArtifact(target string, c cache.ArtifactCache, w Walker, artifactOpt art
return nil, cleanup, errs
}
func (a Artifact) Inspect(ctx context.Context) (types.ArtifactReference, error) {
func (a Artifact) Inspect(ctx context.Context) (artifact.Reference, error) {
ref, err := a.local.Inspect(ctx)
if err != nil {
return types.ArtifactReference{}, xerrors.Errorf("remote repository error: %w", err)
return artifact.Reference{}, xerrors.Errorf("remote repository error: %w", err)
}
if a.url != "" {
ref.Name = a.url
}
ref.Type = types.ArtifactRepository
ref.Type = artifact.TypeRepository
return ref, nil
}
func (Artifact) Clean(_ types.ArtifactReference) error {
func (Artifact) Clean(_ artifact.Reference) error {
return nil
}

View File

@@ -12,12 +12,10 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
"github.com/aquasecurity/trivy/pkg/fanal/cache"
"github.com/aquasecurity/trivy/pkg/fanal/types"
_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/config/all"
_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/secret"
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
"github.com/aquasecurity/trivy/pkg/fanal/cache"
)
func setupGitServer() (*httptest.Server, error) {
@@ -186,15 +184,15 @@ func TestArtifact_Inspect(t *testing.T) {
tests := []struct {
name string
rawurl string
want types.ArtifactReference
want artifact.Reference
wantErr bool
}{
{
name: "happy path",
rawurl: ts.URL + "/test.git",
want: types.ArtifactReference{
want: artifact.Reference{
Name: ts.URL + "/test.git",
Type: types.ArtifactRepository,
Type: artifact.TypeRepository,
ID: "sha256:6a89d4fcd50f840a79da64523c255da80171acd3d286df2acc60056c778d9304",
BlobIDs: []string{
"sha256:6a89d4fcd50f840a79da64523c255da80171acd3d286df2acc60056c778d9304",

View File

@@ -37,23 +37,23 @@ func NewArtifact(filePath string, c cache.ArtifactCache, opt artifact.Option) (a
}, nil
}
func (a Artifact) Inspect(_ context.Context) (types.ArtifactReference, error) {
func (a Artifact) Inspect(_ context.Context) (artifact.Reference, error) {
f, err := os.Open(a.filePath)
if err != nil {
return types.ArtifactReference{}, xerrors.Errorf("failed to open sbom file error: %w", err)
return artifact.Reference{}, xerrors.Errorf("failed to open sbom file error: %w", err)
}
defer f.Close()
// Format auto-detection
format, err := sbom.DetectFormat(f)
if err != nil {
return types.ArtifactReference{}, xerrors.Errorf("failed to detect SBOM format: %w", err)
return artifact.Reference{}, xerrors.Errorf("failed to detect SBOM format: %w", err)
}
log.Info("Detected SBOM format", log.String("format", string(format)))
bom, err := sbom.Decode(f, format)
if err != nil {
return types.ArtifactReference{}, xerrors.Errorf("SBOM decode error: %w", err)
return artifact.Reference{}, xerrors.Errorf("SBOM decode error: %w", err)
}
blobInfo := types.BlobInfo{
@@ -65,23 +65,23 @@ func (a Artifact) Inspect(_ context.Context) (types.ArtifactReference, error) {
cacheKey, err := a.calcCacheKey(blobInfo)
if err != nil {
return types.ArtifactReference{}, xerrors.Errorf("failed to calculate a cache key: %w", err)
return artifact.Reference{}, xerrors.Errorf("failed to calculate a cache key: %w", err)
}
if err = a.cache.PutBlob(cacheKey, blobInfo); err != nil {
return types.ArtifactReference{}, xerrors.Errorf("failed to store blob (%s) in cache: %w", cacheKey, err)
return artifact.Reference{}, xerrors.Errorf("failed to store blob (%s) in cache: %w", cacheKey, err)
}
var artifactType types.ArtifactType
var artifactType artifact.Type
switch format {
case sbom.FormatCycloneDXJSON, sbom.FormatCycloneDXXML, sbom.FormatAttestCycloneDXJSON, sbom.FormatLegacyCosignAttestCycloneDXJSON:
artifactType = types.ArtifactCycloneDX
artifactType = artifact.TypeCycloneDX
case sbom.FormatSPDXTV, sbom.FormatSPDXJSON:
artifactType = types.ArtifactSPDX
artifactType = artifact.TypeSPDX
}
return types.ArtifactReference{
return artifact.Reference{
Name: a.filePath,
Type: artifactType,
ID: cacheKey, // use a cache key as pseudo artifact ID
@@ -92,7 +92,7 @@ func (a Artifact) Inspect(_ context.Context) (types.ArtifactReference, error) {
}, nil
}
func (a Artifact) Clean(reference types.ArtifactReference) error {
func (a Artifact) Clean(reference artifact.Reference) error {
return a.cache.DeleteBlobs(reference.BlobIDs)
}

View File

@@ -22,7 +22,7 @@ func TestArtifact_Inspect(t *testing.T) {
name string
filePath string
putBlobExpectation cache.ArtifactCachePutBlobExpectation
want types.ArtifactReference
want artifact.Reference
wantErr []string
}{
{
@@ -188,9 +188,9 @@ func TestArtifact_Inspect(t *testing.T) {
},
Returns: cache.ArtifactCachePutBlobReturns{},
},
want: types.ArtifactReference{
want: artifact.Reference{
Name: filepath.Join("testdata", "bom.json"),
Type: types.ArtifactCycloneDX,
Type: artifact.TypeCycloneDX,
ID: "sha256:76bc49ae239d24c6a122e730bafb9d5295d0af380492aeb92a3bf34bea3a14ca",
BlobIDs: []string{
"sha256:76bc49ae239d24c6a122e730bafb9d5295d0af380492aeb92a3bf34bea3a14ca",
@@ -360,9 +360,9 @@ func TestArtifact_Inspect(t *testing.T) {
},
Returns: cache.ArtifactCachePutBlobReturns{},
},
want: types.ArtifactReference{
want: artifact.Reference{
Name: filepath.Join("testdata", "sbom.cdx.intoto.jsonl"),
Type: types.ArtifactCycloneDX,
Type: artifact.TypeCycloneDX,
ID: "sha256:76bc49ae239d24c6a122e730bafb9d5295d0af380492aeb92a3bf34bea3a14ca",
BlobIDs: []string{
"sha256:76bc49ae239d24c6a122e730bafb9d5295d0af380492aeb92a3bf34bea3a14ca",

View File

@@ -8,7 +8,7 @@ import (
"golang.org/x/xerrors"
"github.com/aquasecurity/trivy/pkg/cloud/aws/config"
"github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
"github.com/aquasecurity/trivy/pkg/log"
)
@@ -55,10 +55,10 @@ func newAMI(imageID string, storage Storage, region, endpoint string) (*AMI, err
return nil, xerrors.New("no snapshot found")
}
func (a *AMI) Inspect(ctx context.Context) (types.ArtifactReference, error) {
func (a *AMI) Inspect(ctx context.Context) (artifact.Reference, error) {
ref, err := a.EBS.Inspect(ctx)
if err != nil {
return types.ArtifactReference{}, err
return artifact.Reference{}, err
}
ref.Name = a.imageID
return ref, nil

View File

@@ -9,8 +9,8 @@ import (
"golang.org/x/xerrors"
"github.com/aquasecurity/trivy/pkg/cloud/aws/config"
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
"github.com/aquasecurity/trivy/pkg/fanal/cache"
"github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/log"
)
@@ -40,21 +40,21 @@ func newEBS(snapshotID string, vm Storage, region, endpoint string) (*EBS, error
}, nil
}
func (a *EBS) Inspect(ctx context.Context) (types.ArtifactReference, error) {
func (a *EBS) Inspect(ctx context.Context) (artifact.Reference, error) {
sr, err := a.openEBS(ctx)
if err != nil {
return types.ArtifactReference{}, xerrors.Errorf("EBS open error: %w", err)
return artifact.Reference{}, xerrors.Errorf("EBS open error: %w", err)
}
cacheKey, err := a.calcCacheKey(a.snapshotID)
if err != nil {
return types.ArtifactReference{}, xerrors.Errorf("cache key calculation error: %w", err)
return artifact.Reference{}, xerrors.Errorf("cache key calculation error: %w", err)
}
if a.hasCache(cacheKey) {
return types.ArtifactReference{
return artifact.Reference{
Name: a.snapshotID,
Type: types.ArtifactVM,
Type: artifact.TypeVM,
ID: cacheKey, // use a cache key as pseudo artifact ID
BlobIDs: []string{cacheKey},
}, nil
@@ -62,16 +62,16 @@ func (a *EBS) Inspect(ctx context.Context) (types.ArtifactReference, error) {
blobInfo, err := a.Analyze(ctx, sr)
if err != nil {
return types.ArtifactReference{}, xerrors.Errorf("inspection error: %w", err)
return artifact.Reference{}, xerrors.Errorf("inspection error: %w", err)
}
if err = a.cache.PutBlob(cacheKey, blobInfo); err != nil {
return types.ArtifactReference{}, xerrors.Errorf("failed to store blob (%s) in cache: %w", cacheKey, err)
return artifact.Reference{}, xerrors.Errorf("failed to store blob (%s) in cache: %w", cacheKey, err)
}
return types.ArtifactReference{
return artifact.Reference{
Name: a.snapshotID,
Type: types.ArtifactVM,
Type: artifact.TypeVM,
ID: cacheKey, // use a cache key as pseudo artifact ID
BlobIDs: []string{cacheKey},
}, nil
@@ -90,7 +90,7 @@ func (a *EBS) openEBS(ctx context.Context) (*io.SectionReader, error) {
return r, nil
}
func (a *EBS) Clean(_ types.ArtifactReference) error {
func (a *EBS) Clean(_ artifact.Reference) error {
return nil
}

View File

@@ -12,6 +12,7 @@ import (
"github.com/opencontainers/go-digest"
"golang.org/x/xerrors"
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
"github.com/aquasecurity/trivy/pkg/fanal/cache"
"github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/fanal/vm"
@@ -68,24 +69,24 @@ func newFile(filePath string, storage Storage) (*ImageFile, error) {
}, nil
}
func (a *ImageFile) Inspect(ctx context.Context) (types.ArtifactReference, error) {
func (a *ImageFile) Inspect(ctx context.Context) (artifact.Reference, error) {
blobInfo, err := a.Analyze(ctx, a.reader)
if err != nil {
return types.ArtifactReference{}, xerrors.Errorf("inspection error: %w", err)
return artifact.Reference{}, xerrors.Errorf("inspection error: %w", err)
}
cacheKey, err := a.calcCacheKey(blobInfo)
if err != nil {
return types.ArtifactReference{}, xerrors.Errorf("cache calculation error: %w", err)
return artifact.Reference{}, xerrors.Errorf("cache calculation error: %w", err)
}
if err = a.cache.PutBlob(cacheKey, blobInfo); err != nil {
return types.ArtifactReference{}, xerrors.Errorf("failed to store blob (%s) in cache: %w", cacheKey, err)
return artifact.Reference{}, xerrors.Errorf("failed to store blob (%s) in cache: %w", cacheKey, err)
}
return types.ArtifactReference{
return artifact.Reference{
Name: a.filePath,
Type: types.ArtifactVM,
Type: artifact.TypeVM,
ID: cacheKey, // use a cache key as pseudo artifact ID
BlobIDs: []string{cacheKey},
}, nil
@@ -107,7 +108,7 @@ func (a *ImageFile) calcCacheKey(blobInfo types.BlobInfo) (string, error) {
return cacheKey, nil
}
func (a *ImageFile) Clean(reference types.ArtifactReference) error {
func (a *ImageFile) Clean(reference artifact.Reference) error {
_ = a.file.Close()
return a.cache.DeleteBlobs(reference.BlobIDs)
}

View File

@@ -112,7 +112,7 @@ func TestArtifact_Inspect(t *testing.T) {
missingBlobsExpectation cache.ArtifactCacheMissingBlobsExpectation
putBlobExpectation cache.ArtifactCachePutBlobExpectation
putArtifactExpectations []cache.ArtifactCachePutArtifactExpectation
want types.ArtifactReference
want artifact.Reference
wantErr string
}{
{
@@ -136,9 +136,9 @@ func TestArtifact_Inspect(t *testing.T) {
},
},
},
want: types.ArtifactReference{
want: artifact.Reference{
Name: "rawdata.img",
Type: types.ArtifactVM,
Type: artifact.TypeVM,
ID: "sha256:84a726d23c36d0e1857101969b257c1199de5432489d44581750d54ea8eff8cd",
BlobIDs: []string{
"sha256:84a726d23c36d0e1857101969b257c1199de5432489d44581750d54ea8eff8cd",
@@ -172,9 +172,9 @@ func TestArtifact_Inspect(t *testing.T) {
},
},
},
want: types.ArtifactReference{
want: artifact.Reference{
Name: "ebs-012345",
Type: types.ArtifactVM,
Type: artifact.TypeVM,
ID: "sha256:c28da2df41e019b5d18459440178341ec05e9082b12b6f11afe73f0600bfe96a",
BlobIDs: []string{
"sha256:c28da2df41e019b5d18459440178341ec05e9082b12b6f11afe73f0600bfe96a",

View File

@@ -295,13 +295,13 @@ func localImageTestWithNamespace(t *testing.T, namespace string) {
name string
imageName string
tarArchive string
wantMetadata types.ImageMetadata
wantMetadata artifact.ImageMetadata
}{
{
name: "alpine 3.10",
imageName: "ghcr.io/aquasecurity/trivy-test-images:alpine-310",
tarArchive: "../../../../integration/testdata/fixtures/images/alpine-310.tar.gz",
wantMetadata: types.ImageMetadata{
wantMetadata: artifact.ImageMetadata{
ID: "sha256:961769676411f082461f9ef46626dd7a2d1e2b2a38e6a44364bcbecf51e66dd4",
DiffIDs: []string{
"sha256:03901b4a2ea88eeaad62dbe59b072b28b6efa00491962b8741081c5df50c65e0",
@@ -349,7 +349,7 @@ func localImageTestWithNamespace(t *testing.T, namespace string) {
name: "vulnimage",
imageName: "ghcr.io/aquasecurity/trivy-test-images:vulnimage",
tarArchive: "../../../../integration/testdata/fixtures/images/vulnimage.tar.gz",
wantMetadata: types.ImageMetadata{
wantMetadata: artifact.ImageMetadata{
ID: "sha256:c17083664da903e13e9092fa3a3a1aeee2431aa2728298e3dbcec72f26369c41",
DiffIDs: []string{
"sha256:ebf12965380b39889c99a9c02e82ba465f887b45975b6e389d42e9e6a3857888",
@@ -746,12 +746,12 @@ func TestContainerd_PullImage(t *testing.T) {
tests := []struct {
name string
imageName string
wantMetadata types.ImageMetadata
wantMetadata artifact.ImageMetadata
}{
{
name: "remote alpine 3.10",
imageName: "ghcr.io/aquasecurity/trivy-test-images:alpine-310",
wantMetadata: types.ImageMetadata{
wantMetadata: artifact.ImageMetadata{
ID: "sha256:961769676411f082461f9ef46626dd7a2d1e2b2a38e6a44364bcbecf51e66dd4",
DiffIDs: []string{
"sha256:03901b4a2ea88eeaad62dbe59b072b28b6efa00491962b8741081c5df50c65e0",

View File

@@ -1,17 +1,9 @@
package types
import (
"encoding/json"
"strings"
"time"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/package-url/packageurl-go"
"github.com/samber/lo"
"golang.org/x/xerrors"
"github.com/aquasecurity/trivy/pkg/digest"
"github.com/aquasecurity/trivy/pkg/sbom/core"
)
type OS struct {
@@ -66,260 +58,6 @@ type Layer struct {
CreatedBy string `json:",omitempty"`
}
type Relationship int
const (
RelationshipUnknown Relationship = iota
RelationshipRoot
RelationshipDirect
RelationshipIndirect
)
var relationshipNames = [...]string{
"unknown",
"root",
"direct",
"indirect",
}
func (r Relationship) String() string {
if r <= RelationshipUnknown || int(r) >= len(relationshipNames) {
return "unknown"
}
return relationshipNames[r]
}
func (r Relationship) MarshalJSON() ([]byte, error) {
return json.Marshal(r.String())
}
func (r *Relationship) UnmarshalJSON(data []byte) error {
var s string
if err := json.Unmarshal(data, &s); err != nil {
return err
}
for i, name := range relationshipNames {
if s == name {
*r = Relationship(i)
return nil
}
}
return xerrors.Errorf("invalid relationship (%s)", s)
}
type Package struct {
ID string `json:",omitempty"`
Name string `json:",omitempty"`
Identifier PkgIdentifier `json:",omitempty"`
Version string `json:",omitempty"`
Release string `json:",omitempty"`
Epoch int `json:",omitempty"`
Arch string `json:",omitempty"`
Dev bool `json:",omitempty"`
SrcName string `json:",omitempty"`
SrcVersion string `json:",omitempty"`
SrcRelease string `json:",omitempty"`
SrcEpoch int `json:",omitempty"`
Licenses []string `json:",omitempty"`
Maintainer string `json:",omitempty"`
ExternalReferences []ExternalRef `json:"-"`
Modularitylabel string `json:",omitempty"` // only for Red Hat based distributions
BuildInfo *BuildInfo `json:",omitempty"` // only for Red Hat
Indirect bool `json:",omitempty"` // Deprecated: Use relationship. Kept for backward compatibility.
Relationship Relationship `json:",omitempty"`
// Dependencies of this package
// Note: it may have interdependencies, which may lead to infinite loops.
DependsOn []string `json:",omitempty"`
Layer Layer `json:",omitempty"`
// Each package metadata have the file path, while the package from lock files does not have.
FilePath string `json:",omitempty"`
// This is required when using SPDX formats. Otherwise, it will be empty.
Digest digest.Digest `json:",omitempty"`
// lines from the lock file where the dependency is written
Locations Locations `json:",omitempty"`
// Files installed by the package
InstalledFiles []string `json:",omitempty"`
}
// PkgIdentifier represents a software identifiers in one of more of the supported formats.
type PkgIdentifier struct {
UID string `json:",omitempty"` // Calculated by the package struct
PURL *packageurl.PackageURL `json:"-"`
BOMRef string `json:",omitempty"` // For CycloneDX
}
// MarshalJSON customizes the JSON encoding of PkgIdentifier.
func (id *PkgIdentifier) MarshalJSON() ([]byte, error) {
var p string
if id.PURL != nil {
p = id.PURL.String()
}
type Alias PkgIdentifier
return json.Marshal(&struct {
PURL string `json:",omitempty"`
*Alias
}{
PURL: p,
Alias: (*Alias)(id),
})
}
// UnmarshalJSON customizes the JSON decoding of PkgIdentifier.
func (id *PkgIdentifier) UnmarshalJSON(data []byte) error {
type Alias PkgIdentifier
aux := &struct {
PURL string `json:",omitempty"`
*Alias
}{
Alias: (*Alias)(id),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
if aux.PURL != "" {
p, err := packageurl.FromString(aux.PURL)
if err != nil {
return err
} else if len(p.Qualifiers) == 0 {
p.Qualifiers = nil
}
id.PURL = &p
}
return nil
}
func (id *PkgIdentifier) Empty() bool {
return id.UID == "" && id.PURL == nil && id.BOMRef == ""
}
func (id *PkgIdentifier) Match(s string) bool {
// Encode string as PURL
if strings.HasPrefix(s, "pkg:") {
if p, err := packageurl.FromString(s); err == nil {
s = p.String()
}
}
switch {
case id.BOMRef == s:
return true
case id.PURL != nil && id.PURL.String() == s:
return true
}
return false
}
type Dependency struct {
ID string
DependsOn []string
}
type Dependencies []Dependency
func (deps Dependencies) Len() int { return len(deps) }
func (deps Dependencies) Less(i, j int) bool {
return deps[i].ID < deps[j].ID
}
func (deps Dependencies) Swap(i, j int) { deps[i], deps[j] = deps[j], deps[i] }
type Location struct {
StartLine int `json:",omitempty"`
EndLine int `json:",omitempty"`
}
type Locations []Location
func (locs Locations) Len() int { return len(locs) }
func (locs Locations) Less(i, j int) bool {
return locs[i].StartLine < locs[j].StartLine
}
func (locs Locations) Swap(i, j int) { locs[i], locs[j] = locs[j], locs[i] }
type ExternalRef struct {
Type RefType
URL string
}
type RefType string
const (
RefVCS RefType = "vcs"
RefOther RefType = "other"
)
// BuildInfo represents information under /root/buildinfo in RHEL
type BuildInfo struct {
ContentSets []string `json:",omitempty"`
Nvr string `json:",omitempty"`
Arch string `json:",omitempty"`
}
func (pkg *Package) Empty() bool {
return pkg.Name == "" || pkg.Version == ""
}
type Packages []Package
func (pkgs Packages) Len() int {
return len(pkgs)
}
func (pkgs Packages) Swap(i, j int) {
pkgs[i], pkgs[j] = pkgs[j], pkgs[i]
}
func (pkgs Packages) Less(i, j int) bool {
switch {
case pkgs[i].Relationship != pkgs[j].Relationship:
if pkgs[i].Relationship == RelationshipUnknown {
return false
} else if pkgs[j].Relationship == RelationshipUnknown {
return true
}
return pkgs[i].Relationship < pkgs[j].Relationship
case pkgs[i].Name != pkgs[j].Name:
return pkgs[i].Name < pkgs[j].Name
case pkgs[i].Version != pkgs[j].Version:
return pkgs[i].Version < pkgs[j].Version
}
return pkgs[i].FilePath < pkgs[j].FilePath
}
// ParentDeps returns a map where the keys are package IDs and the values are the packages
// that depend on the respective package ID (parent dependencies).
func (pkgs Packages) ParentDeps() map[string]Packages {
parents := make(map[string]Packages)
for _, pkg := range pkgs {
for _, dependOn := range pkg.DependsOn {
parents[dependOn] = append(parents[dependOn], pkg)
}
}
for k, v := range parents {
parents[k] = lo.UniqBy(v, func(pkg Package) string {
return pkg.ID
})
}
return parents
}
type SrcPackage struct {
Name string `json:"name"`
Version string `json:"version"`
BinaryNames []string `json:"binaryNames"`
}
type PackageInfo struct {
FilePath string
Packages Packages
@@ -342,39 +80,6 @@ type File struct {
Content []byte
}
// ArtifactType represents a type of artifact
type ArtifactType string
const (
ArtifactContainerImage ArtifactType = "container_image"
ArtifactFilesystem ArtifactType = "filesystem"
ArtifactRepository ArtifactType = "repository"
ArtifactCycloneDX ArtifactType = "cyclonedx"
ArtifactSPDX ArtifactType = "spdx"
ArtifactAWSAccount ArtifactType = "aws_account"
ArtifactVM ArtifactType = "vm"
)
// ArtifactReference represents a reference of container image, local filesystem and repository
type ArtifactReference struct {
Name string // image name, tar file name, directory or repository name
Type ArtifactType
ID string
BlobIDs []string
ImageMetadata ImageMetadata
// SBOM
BOM *core.BOM
}
type ImageMetadata struct {
ID string // image ID
DiffIDs []string // uncompressed layer IDs
RepoTags []string
RepoDigests []string
ConfigFile v1.ConfigFile
}
// ArtifactInfo is stored in cache
type ArtifactInfo struct {
SchemaVersion int

260
pkg/fanal/types/package.go Normal file
View File

@@ -0,0 +1,260 @@
package types
import (
"encoding/json"
"strings"
"github.com/package-url/packageurl-go"
"github.com/samber/lo"
"golang.org/x/xerrors"
"github.com/aquasecurity/trivy/pkg/digest"
)
type Relationship int
const (
RelationshipUnknown Relationship = iota
RelationshipRoot
RelationshipDirect
RelationshipIndirect
)
var relationshipNames = [...]string{
"unknown",
"root",
"direct",
"indirect",
}
func (r Relationship) String() string {
if r <= RelationshipUnknown || int(r) >= len(relationshipNames) {
return "unknown"
}
return relationshipNames[r]
}
func (r Relationship) MarshalJSON() ([]byte, error) {
return json.Marshal(r.String())
}
func (r *Relationship) UnmarshalJSON(data []byte) error {
var s string
if err := json.Unmarshal(data, &s); err != nil {
return err
}
for i, name := range relationshipNames {
if s == name {
*r = Relationship(i)
return nil
}
}
return xerrors.Errorf("invalid relationship (%s)", s)
}
// PkgIdentifier represents a software identifiers in one of more of the supported formats.
type PkgIdentifier struct {
UID string `json:",omitempty"` // Calculated by the package struct
PURL *packageurl.PackageURL `json:"-"`
BOMRef string `json:",omitempty"` // For CycloneDX
}
// MarshalJSON customizes the JSON encoding of PkgIdentifier.
func (id *PkgIdentifier) MarshalJSON() ([]byte, error) {
var p string
if id.PURL != nil {
p = id.PURL.String()
}
type Alias PkgIdentifier
return json.Marshal(&struct {
PURL string `json:",omitempty"`
*Alias
}{
PURL: p,
Alias: (*Alias)(id),
})
}
// UnmarshalJSON customizes the JSON decoding of PkgIdentifier.
func (id *PkgIdentifier) UnmarshalJSON(data []byte) error {
type Alias PkgIdentifier
aux := &struct {
PURL string `json:",omitempty"`
*Alias
}{
Alias: (*Alias)(id),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
if aux.PURL != "" {
p, err := packageurl.FromString(aux.PURL)
if err != nil {
return err
} else if len(p.Qualifiers) == 0 {
p.Qualifiers = nil
}
id.PURL = &p
}
return nil
}
func (id *PkgIdentifier) Empty() bool {
return id.UID == "" && id.PURL == nil && id.BOMRef == ""
}
func (id *PkgIdentifier) Match(s string) bool {
// Encode string as PURL
if strings.HasPrefix(s, "pkg:") {
if p, err := packageurl.FromString(s); err == nil {
s = p.String()
}
}
switch {
case id.BOMRef == s:
return true
case id.PURL != nil && id.PURL.String() == s:
return true
}
return false
}
type Location struct {
StartLine int `json:",omitempty"`
EndLine int `json:",omitempty"`
}
type Locations []Location
func (locs Locations) Len() int { return len(locs) }
func (locs Locations) Less(i, j int) bool {
return locs[i].StartLine < locs[j].StartLine
}
func (locs Locations) Swap(i, j int) { locs[i], locs[j] = locs[j], locs[i] }
type ExternalRef struct {
Type RefType
URL string
}
type RefType string
const (
RefVCS RefType = "vcs"
RefOther RefType = "other"
)
// BuildInfo represents information under /root/buildinfo in RHEL
type BuildInfo struct {
ContentSets []string `json:",omitempty"`
Nvr string `json:",omitempty"`
Arch string `json:",omitempty"`
}
type Package struct {
ID string `json:",omitempty"`
Name string `json:",omitempty"`
Identifier PkgIdentifier `json:",omitempty"`
Version string `json:",omitempty"`
Release string `json:",omitempty"`
Epoch int `json:",omitempty"`
Arch string `json:",omitempty"`
Dev bool `json:",omitempty"`
SrcName string `json:",omitempty"`
SrcVersion string `json:",omitempty"`
SrcRelease string `json:",omitempty"`
SrcEpoch int `json:",omitempty"`
Licenses []string `json:",omitempty"`
Maintainer string `json:",omitempty"`
ExternalReferences []ExternalRef `json:"-"`
Modularitylabel string `json:",omitempty"` // only for Red Hat based distributions
BuildInfo *BuildInfo `json:",omitempty"` // only for Red Hat
Indirect bool `json:",omitempty"` // Deprecated: Use relationship. Kept for backward compatibility.
Relationship Relationship `json:",omitempty"`
// Dependencies of this package
// Note: it may have interdependencies, which may lead to infinite loops.
DependsOn []string `json:",omitempty"`
Layer Layer `json:",omitempty"`
// Each package metadata have the file path, while the package from lock files does not have.
FilePath string `json:",omitempty"`
// This is required when using SPDX formats. Otherwise, it will be empty.
Digest digest.Digest `json:",omitempty"`
// lines from the lock file where the dependency is written
Locations Locations `json:",omitempty"`
// Files installed by the package
InstalledFiles []string `json:",omitempty"`
}
func (pkg *Package) Empty() bool {
return pkg.Name == "" || pkg.Version == ""
}
type Packages []Package
func (pkgs Packages) Len() int {
return len(pkgs)
}
func (pkgs Packages) Swap(i, j int) {
pkgs[i], pkgs[j] = pkgs[j], pkgs[i]
}
func (pkgs Packages) Less(i, j int) bool {
switch {
case pkgs[i].Relationship != pkgs[j].Relationship:
if pkgs[i].Relationship == RelationshipUnknown {
return false
} else if pkgs[j].Relationship == RelationshipUnknown {
return true
}
return pkgs[i].Relationship < pkgs[j].Relationship
case pkgs[i].Name != pkgs[j].Name:
return pkgs[i].Name < pkgs[j].Name
case pkgs[i].Version != pkgs[j].Version:
return pkgs[i].Version < pkgs[j].Version
}
return pkgs[i].FilePath < pkgs[j].FilePath
}
// ParentDeps returns a map where the keys are package IDs and the values are the packages
// that depend on the respective package ID (parent dependencies).
func (pkgs Packages) ParentDeps() map[string]Packages {
parents := make(map[string]Packages)
for _, pkg := range pkgs {
for _, dependOn := range pkg.DependsOn {
parents[dependOn] = append(parents[dependOn], pkg)
}
}
for k, v := range parents {
parents[k] = lo.UniqBy(v, func(pkg Package) string {
return pkg.ID
})
}
return parents
}
type Dependency struct {
ID string
DependsOn []string
}
type Dependencies []Dependency
func (deps Dependencies) Len() int { return len(deps) }
func (deps Dependencies) Less(i, j int) bool {
return deps[i].ID < deps[j].ID
}
func (deps Dependencies) Swap(i, j int) { deps[i], deps[j] = deps[j], deps[i] }

View File

@@ -379,7 +379,7 @@ func (s *Scanner) clusterInfoToReportResources(allArtifact []*artifacts.Artifact
Version: comp.Version,
Type: core.TypeApplication,
Properties: toProperties(comp.Properties, k8sCoreComponentNamespace),
PkgID: core.PkgID{
PkgIdentifier: ftypes.PkgIdentifier{
PURL: generatePURL(comp.Name, comp.Version, nodeName),
},
}
@@ -406,7 +406,7 @@ func (s *Scanner) clusterInfoToReportResources(allArtifact []*artifacts.Artifact
Type: core.TypeContainerImage,
Name: name,
Version: cDigest,
PkgID: core.PkgID{
PkgIdentifier: ftypes.PkgIdentifier{
PURL: imagePURL.Unwrap(),
},
Properties: []core.Property{
@@ -439,7 +439,7 @@ func (s *Scanner) clusterInfoToReportResources(allArtifact []*artifacts.Artifact
Name: cf.Name,
Version: cf.Version,
Properties: toProperties(cf.Properties, k8sCoreComponentNamespace),
PkgID: core.PkgID{
PkgIdentifier: ftypes.PkgIdentifier{
PURL: generatePURL(cf.Name, cf.Version, nodeName),
},
Root: true,
@@ -512,7 +512,7 @@ func (s *Scanner) nodeComponent(b *core.BOM, nf bom.NodeInfo) *core.Component {
Namespace: k8sCoreComponentNamespace,
},
},
PkgID: core.PkgID{
PkgIdentifier: ftypes.PkgIdentifier{
PURL: generatePURL(kubelet, kubeletVersion, nf.NodeName),
},
}
@@ -534,7 +534,7 @@ func (s *Scanner) nodeComponent(b *core.BOM, nf bom.NodeInfo) *core.Component {
Namespace: k8sCoreComponentNamespace,
},
},
PkgID: core.PkgID{
PkgIdentifier: ftypes.PkgIdentifier{
PURL: packageurl.NewPackageURL(packageurl.TypeGolang, "", runtimeName, runtimeVersion, packageurl.Qualifiers{}, ""),
},
}

View File

@@ -2,6 +2,7 @@ package scanner
import (
"context"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/sbom/core"
"github.com/aquasecurity/trivy/pkg/uuid"
"github.com/stretchr/testify/require"
@@ -99,7 +100,7 @@ func TestScanner_Scan(t *testing.T) {
Namespace: k8sCoreComponentNamespace,
},
},
PkgID: core.PkgID{
PkgIdentifier: ftypes.PkgIdentifier{
PURL: &packageurl.PackageURL{
Type: "golang",
Name: "github.com/containerd/containerd",
@@ -113,7 +114,7 @@ func TestScanner_Scan(t *testing.T) {
Type: core.TypeApplication,
Name: "k8s.io/apiserver",
Version: "1.21.1",
PkgID: core.PkgID{
PkgIdentifier: ftypes.PkgIdentifier{
PURL: &packageurl.PackageURL{
Type: purl.TypeK8s,
Name: "k8s.io/apiserver",
@@ -138,7 +139,7 @@ func TestScanner_Scan(t *testing.T) {
Namespace: k8sCoreComponentNamespace,
},
},
PkgID: core.PkgID{
PkgIdentifier: ftypes.PkgIdentifier{
PURL: &packageurl.PackageURL{
Type: "k8s",
Name: "k8s.io/kubelet",
@@ -150,7 +151,7 @@ func TestScanner_Scan(t *testing.T) {
{
Type: core.TypeApplication,
Name: "node-core-components",
PkgID: core.PkgID{
PkgIdentifier: ftypes.PkgIdentifier{
BOMRef: "3ff14136-e09f-4df9-80ea-000000000006",
},
},
@@ -158,7 +159,7 @@ func TestScanner_Scan(t *testing.T) {
Type: core.TypeContainerImage,
Name: "k8s.gcr.io/kube-apiserver",
Version: "sha256:18e61c783b41758dd391ab901366ec3546b26fae00eef7e223d1f94da808e02f",
PkgID: core.PkgID{
PkgIdentifier: ftypes.PkgIdentifier{
PURL: &packageurl.PackageURL{
Type: "oci",
Name: "kube-apiserver",
@@ -199,7 +200,7 @@ func TestScanner_Scan(t *testing.T) {
Namespace: "",
},
},
PkgID: core.PkgID{
PkgIdentifier: ftypes.PkgIdentifier{
BOMRef: "3ff14136-e09f-4df9-80ea-000000000005",
},
},
@@ -220,7 +221,7 @@ func TestScanner_Scan(t *testing.T) {
Namespace: k8sCoreComponentNamespace,
},
},
PkgID: core.PkgID{
PkgIdentifier: ftypes.PkgIdentifier{
PURL: &packageurl.PackageURL{
Type: purl.TypeK8s,
Name: "k8s.io/kubernetes",
@@ -264,7 +265,7 @@ func TestScanner_Scan(t *testing.T) {
Namespace: k8sCoreComponentNamespace,
},
},
PkgID: core.PkgID{
PkgIdentifier: ftypes.PkgIdentifier{
BOMRef: "3ff14136-e09f-4df9-80ea-000000000004",
},
},

View File

@@ -12,6 +12,7 @@ import (
"golang.org/x/xerrors"
"github.com/aquasecurity/trivy/pkg/clock"
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/purl"
"github.com/aquasecurity/trivy/pkg/types"
@@ -105,7 +106,7 @@ func (w Writer) Write(ctx context.Context, report types.Report) error {
manifest.Name = string(result.Type)
// show path for language-specific packages only
if result.Class == types.ClassLangPkg {
if report.ArtifactType == ftypes.ArtifactContainerImage {
if report.ArtifactType == artifact.TypeContainerImage {
// `RepoDigests` ~= <registry>/<image_name>@sha256:<image_hash>
// `RepoTag` ~= <registry>/<image_name>:<image_tag>
// By concatenating the hash from `RepoDigests` at the end of `RepoTag` we get all the information

View File

@@ -12,7 +12,7 @@ import (
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/vulnerability"
"github.com/aquasecurity/trivy/pkg/clock"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
"github.com/aquasecurity/trivy/pkg/report/predicate"
"github.com/aquasecurity/trivy/pkg/types"
)
@@ -49,7 +49,7 @@ func TestWriter_Write(t *testing.T) {
Result: types.Report{
SchemaVersion: 2,
ArtifactName: "alpine:3.14",
ArtifactType: ftypes.ArtifactType(""),
ArtifactType: artifact.Type(""),
Metadata: types.Metadata{},
Results: types.Results{
{

View File

@@ -13,6 +13,7 @@ import (
"github.com/owenrumney/go-sarif/v2/sarif"
"golang.org/x/xerrors"
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/types"
)
@@ -131,7 +132,7 @@ func (sw *SarifWriter) Write(ctx context.Context, report types.Report) error {
sw.run.Tool.Driver.WithVersion(sw.Version)
sw.run.Tool.Driver.WithFullName("Trivy Vulnerability Scanner")
sw.locationCache = make(map[string][]location)
if report.ArtifactType == ftypes.ArtifactContainerImage {
if report.ArtifactType == artifact.TypeContainerImage {
sw.run.Properties = sarif.Properties{
"imageName": report.ArtifactName,
"repoTags": report.Metadata.RepoTags,

View File

@@ -12,6 +12,7 @@ import (
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/vulnerability"
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/report"
"github.com/aquasecurity/trivy/pkg/types"
@@ -27,7 +28,7 @@ func TestReportWriter_Sarif(t *testing.T) {
name: "report with vulnerabilities",
input: types.Report{
ArtifactName: "debian:9",
ArtifactType: ftypes.ArtifactContainerImage,
ArtifactType: artifact.TypeContainerImage,
Metadata: types.Metadata{
RepoTags: []string{
"debian:9",

View File

@@ -9,7 +9,7 @@ import (
"golang.org/x/xerrors"
cr "github.com/aquasecurity/trivy/pkg/compliance/report"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
"github.com/aquasecurity/trivy/pkg/flag"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/report/cyclonedx"
@@ -82,7 +82,7 @@ func Write(ctx context.Context, report types.Report, option flag.Options) (err e
}
case types.FormatSarif:
target := ""
if report.ArtifactType == ftypes.ArtifactFilesystem {
if report.ArtifactType == artifact.TypeFilesystem {
target = option.Target
}
writer = &SarifWriter{

View File

@@ -3,10 +3,9 @@ package core
import (
"sort"
"github.com/package-url/packageurl-go"
dtypes "github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy/pkg/digest"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/uuid"
)
@@ -124,14 +123,14 @@ type Component struct {
// SPDX: package.licenseConcluded, package.licenseDeclared
Licenses []string
// PkgID has PURL and BOMRef for the component
// PkgIdentifier has PURL and BOMRef for the component
// PURL:
// CycloneDX: component.purl
// SPDX: package.externalRefs.referenceLocator
// BOMRef:
// CycloneDX: component.bom-ref
// SPDX: N/A
PkgID PkgID
PkgIdentifier ftypes.PkgIdentifier
// Supplier is the name of the supplier of the component
// CycloneDX: component.supplier
@@ -188,11 +187,6 @@ type Relationship struct {
Type RelationshipType
}
type PkgID struct {
PURL *packageurl.PackageURL
BOMRef string
}
type Vulnerability struct {
dtypes.Vulnerability
ID string
@@ -222,8 +216,8 @@ func (b *BOM) setupComponent(c *Component) {
if c.id == uuid.Nil {
c.id = uuid.New()
}
if c.PkgID.PURL != nil {
p := c.PkgID.PURL.String()
if c.PkgIdentifier.PURL != nil {
p := c.PkgIdentifier.PURL.String()
b.purls[p] = append(b.purls[p], c.id)
}
sort.Sort(c.Properties)
@@ -281,7 +275,7 @@ func (b *BOM) Root() *Component {
return nil
}
if b.opts.GenerateBOMRef {
root.PkgID.BOMRef = b.bomRef(root)
root.PkgIdentifier.BOMRef = b.bomRef(root)
}
return root
}
@@ -290,7 +284,7 @@ func (b *BOM) Components() map[uuid.UUID]*Component {
// Fill in BOMRefs for components
if b.opts.GenerateBOMRef {
for id, c := range b.components {
b.components[id].PkgID.BOMRef = b.bomRef(c)
b.components[id].PkgIdentifier.BOMRef = b.bomRef(c)
}
}
return b.components
@@ -312,14 +306,14 @@ func (b *BOM) NumComponents() int {
// When multiple lock files have the same dependency with the same name and version, PURL in the BOM can conflict.
// In that case, PURL cannot be used as a unique identifier, and UUIDv4 be used for BOMRef.
func (b *BOM) bomRef(c *Component) string {
if c.PkgID.BOMRef != "" {
return c.PkgID.BOMRef
if c.PkgIdentifier.BOMRef != "" {
return c.PkgIdentifier.BOMRef
}
// Return the UUID of the component if the PURL is not present.
if c.PkgID.PURL == nil {
if c.PkgIdentifier.PURL == nil {
return c.id.String()
}
p := c.PkgID.PURL.String()
p := c.PkgIdentifier.PURL.String()
// Return the UUID of the component if the PURL is not unique in the BOM.
if len(b.purls[p]) > 1 {

View File

@@ -108,12 +108,12 @@ func (m *Marshaler) MarshalComponent(component *core.Component) (*cdx.Component,
}
cdxComponent := &cdx.Component{
BOMRef: component.PkgID.BOMRef,
BOMRef: component.PkgIdentifier.BOMRef,
Type: componentType,
Name: component.Name,
Group: component.Group,
Version: component.Version,
PackageURL: m.PackageURL(component.PkgID.PURL),
PackageURL: m.PackageURL(component.PkgIdentifier.PURL),
Supplier: m.Supplier(component.Supplier),
Hashes: m.Hashes(component.Files),
Licenses: m.Licenses(component.Licenses),

View File

@@ -2,6 +2,7 @@ package cyclonedx_test
import (
"context"
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
"github.com/aquasecurity/trivy/pkg/sbom/core"
"github.com/package-url/packageurl-go"
"testing"
@@ -29,7 +30,7 @@ func TestMarshaler_MarshalReport(t *testing.T) {
Root: true,
Type: core.TypeApplication,
Name: "jackson-databind-2.13.4.1.jar",
PkgID: core.PkgID{
PkgIdentifier: ftypes.PkgIdentifier{
BOMRef: "aff65b54-6009-4c32-968d-748949ef46e8",
},
Properties: []core.Property{
@@ -50,7 +51,7 @@ func TestMarshaler_MarshalReport(t *testing.T) {
inputReport: types.Report{
SchemaVersion: report.SchemaVersion,
ArtifactName: "rails:latest",
ArtifactType: ftypes.ArtifactContainerImage,
ArtifactType: artifact.TypeContainerImage,
Metadata: types.Metadata{
Size: 1024,
OS: &ftypes.OS{
@@ -668,7 +669,7 @@ func TestMarshaler_MarshalReport(t *testing.T) {
inputReport: types.Report{
SchemaVersion: report.SchemaVersion,
ArtifactName: "centos:latest",
ArtifactType: ftypes.ArtifactContainerImage,
ArtifactType: artifact.TypeContainerImage,
Metadata: types.Metadata{
Size: 1024,
OS: &ftypes.OS{
@@ -1229,7 +1230,7 @@ func TestMarshaler_MarshalReport(t *testing.T) {
inputReport: types.Report{
SchemaVersion: report.SchemaVersion,
ArtifactName: "masahiro331/CVE-2021-41098",
ArtifactType: ftypes.ArtifactFilesystem,
ArtifactType: artifact.TypeFilesystem,
Results: types.Results{
{
Target: "Gemfile.lock",
@@ -1445,7 +1446,7 @@ func TestMarshaler_MarshalReport(t *testing.T) {
inputReport: types.Report{
SchemaVersion: report.SchemaVersion,
ArtifactName: "./report.cdx.json",
ArtifactType: ftypes.ArtifactCycloneDX,
ArtifactType: artifact.TypeCycloneDX,
Results: types.Results{
{
Target: "Java",
@@ -1629,7 +1630,7 @@ func TestMarshaler_MarshalReport(t *testing.T) {
inputReport: types.Report{
SchemaVersion: report.SchemaVersion,
ArtifactName: "CVE-2023-34468",
ArtifactType: ftypes.ArtifactFilesystem,
ArtifactType: artifact.TypeFilesystem,
Results: types.Results{
{
Target: "Java",
@@ -1926,7 +1927,7 @@ func TestMarshaler_MarshalReport(t *testing.T) {
inputReport: types.Report{
SchemaVersion: report.SchemaVersion,
ArtifactName: "test-aggregate",
ArtifactType: ftypes.ArtifactRepository,
ArtifactType: artifact.TypeRepository,
Results: types.Results{
{
Target: "Node.js",
@@ -2039,7 +2040,7 @@ func TestMarshaler_MarshalReport(t *testing.T) {
inputReport: types.Report{
SchemaVersion: report.SchemaVersion,
ArtifactName: "empty/path",
ArtifactType: ftypes.ArtifactFilesystem,
ArtifactType: artifact.TypeFilesystem,
Results: types.Results{},
},
want: &cdx.BOM{

View File

@@ -12,6 +12,7 @@ import (
"golang.org/x/xerrors"
"github.com/aquasecurity/trivy/pkg/digest"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/sbom/core"
)
@@ -69,7 +70,7 @@ func (b *BOM) parseBOM(bom *cdx.BOM) error {
if err != nil {
return xerrors.Errorf("failed to parse root component: %w", err)
} else if mComponent != nil {
components[mComponent.PkgID.BOMRef] = mComponent
components[mComponent.PkgIdentifier.BOMRef] = mComponent
}
// Parse dependencies and build relationships
@@ -147,7 +148,7 @@ func (b *BOM) parseComponent(c cdx.Component) (*core.Component, error) {
Digests: b.unmarshalHashes(c.Hashes),
},
},
PkgID: core.PkgID{
PkgIdentifier: ftypes.PkgIdentifier{
PURL: &purl,
BOMRef: c.BOMRef,
},

View File

@@ -135,7 +135,7 @@ func (m *Decoder) decodeComponents(sbom *types.SBOM) error {
}
// Third-party SBOMs may contain packages in types other than "Library"
if c.Type == core.TypeLibrary || c.PkgID.PURL != nil {
if c.Type == core.TypeLibrary || c.PkgIdentifier.PURL != nil {
pkg, err := m.decodeLibrary(c)
if errors.Is(err, ErrUnsupportedType) || errors.Is(err, ErrPURLEmpty) {
continue
@@ -184,7 +184,7 @@ func (m *Decoder) decodeApplication(c *core.Component) *ftypes.Application {
}
func (m *Decoder) decodeLibrary(c *core.Component) (*ftypes.Package, error) {
p := (*purl.PackageURL)(c.PkgID.PURL)
p := (*purl.PackageURL)(c.PkgIdentifier.PURL)
if p == nil {
log.Debug("Skipping a component without PURL",
log.String("name", c.Name), log.String("version", c.Version))
@@ -226,7 +226,7 @@ func (m *Decoder) decodeLibrary(c *core.Component) (*ftypes.Package, error) {
}
}
pkg.Identifier.BOMRef = c.PkgID.BOMRef
pkg.Identifier.BOMRef = c.PkgIdentifier.BOMRef
pkg.Licenses = c.Licenses
for _, f := range c.Files {
@@ -249,10 +249,10 @@ func (m *Decoder) decodeLibrary(c *core.Component) (*ftypes.Package, error) {
// pkgName returns the package name.
// PURL loses case-sensitivity (e.g. Go, Npm, PyPI), so we have to use an original package name.
func (m *Decoder) pkgName(pkg *ftypes.Package, c *core.Component) string {
p := c.PkgID.PURL
p := c.PkgIdentifier.PURL
// A name from PURL takes precedence for CocoaPods since it has subpath.
if c.PkgID.PURL.Type == packageurl.TypeCocoapods {
if c.PkgIdentifier.PURL.Type == packageurl.TypeCocoapods {
return pkg.Name
}

View File

@@ -10,6 +10,7 @@ import (
"golang.org/x/xerrors"
"github.com/aquasecurity/trivy/pkg/digest"
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/purl"
"github.com/aquasecurity/trivy/pkg/sbom/core"
@@ -61,7 +62,7 @@ func (e *Encoder) rootComponent(r types.Report) (*core.Component, error) {
}
switch r.ArtifactType {
case ftypes.ArtifactContainerImage:
case artifact.TypeContainerImage:
root.Type = core.TypeContainerImage
props = append(props, core.Property{
Name: core.PropertyImageID,
@@ -73,16 +74,16 @@ func (e *Encoder) rootComponent(r types.Report) (*core.Component, error) {
return nil, xerrors.Errorf("failed to new package url for oci: %w", err)
}
if p != nil {
root.PkgID.PURL = p.Unwrap()
root.PkgIdentifier.PURL = p.Unwrap()
}
case ftypes.ArtifactVM:
case artifact.TypeVM:
root.Type = core.TypeVM
case ftypes.ArtifactFilesystem:
case artifact.TypeFilesystem:
root.Type = core.TypeFilesystem
case ftypes.ArtifactRepository:
case artifact.TypeRepository:
root.Type = core.TypeRepository
case ftypes.ArtifactCycloneDX:
case artifact.TypeCycloneDX:
return r.BOM.Root(), nil
}
@@ -346,7 +347,7 @@ func (*Encoder) component(result types.Result, pkg ftypes.Package) *core.Compone
SrcName: pkg.SrcName,
SrcVersion: utils.FormatSrcVersion(pkg),
SrcFile: srcFile,
PkgID: core.PkgID{
PkgIdentifier: ftypes.PkgIdentifier{
PURL: pkg.Identifier.PURL,
},
Supplier: pkg.Maintainer,

View File

@@ -2,6 +2,7 @@ package io_test
import (
dtypes "github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/sbom/core"
sbomio "github.com/aquasecurity/trivy/pkg/sbom/io"
@@ -27,7 +28,7 @@ func TestEncoder_Encode(t *testing.T) {
report: types.Report{
SchemaVersion: 2,
ArtifactName: "debian:12",
ArtifactType: ftypes.ArtifactContainerImage,
ArtifactType: artifact.TypeContainerImage,
Metadata: types.Metadata{
OS: &ftypes.OS{
Family: ftypes.Debian,
@@ -116,7 +117,7 @@ func TestEncoder_Encode(t *testing.T) {
Type: core.TypeContainerImage,
Name: "debian:12",
Root: true,
PkgID: core.PkgID{
PkgIdentifier: ftypes.PkgIdentifier{
PURL: &packageurl.PackageURL{
Type: packageurl.TypeOCI,
Name: "debian",
@@ -163,7 +164,7 @@ func TestEncoder_Encode(t *testing.T) {
Value: "debian",
},
},
PkgID: core.PkgID{
PkgIdentifier: ftypes.PkgIdentifier{
BOMRef: "3ff14136-e09f-4df9-80ea-000000000002",
},
},
@@ -181,7 +182,7 @@ func TestEncoder_Encode(t *testing.T) {
Value: "debian",
},
},
PkgID: core.PkgID{
PkgIdentifier: ftypes.PkgIdentifier{
PURL: &packageurl.PackageURL{
Type: packageurl.TypeDebian,
Name: "libc6",
@@ -204,7 +205,7 @@ func TestEncoder_Encode(t *testing.T) {
Value: "debian",
},
},
PkgID: core.PkgID{
PkgIdentifier: ftypes.PkgIdentifier{
PURL: &packageurl.PackageURL{
Type: packageurl.TypeDebian,
Name: "curl",
@@ -237,7 +238,7 @@ func TestEncoder_Encode(t *testing.T) {
Value: "jar",
},
},
PkgID: core.PkgID{
PkgIdentifier: ftypes.PkgIdentifier{
PURL: &packageurl.PackageURL{
Type: packageurl.TypeMaven,
Namespace: "org.apache.xmlgraphics",
@@ -298,7 +299,7 @@ func TestEncoder_Encode(t *testing.T) {
report: types.Report{
SchemaVersion: 2,
ArtifactName: "gobinary",
ArtifactType: ftypes.ArtifactFilesystem,
ArtifactType: artifact.TypeFilesystem,
Results: []types.Result{
{
Target: "test",
@@ -379,7 +380,7 @@ func TestEncoder_Encode(t *testing.T) {
Value: "2",
},
},
PkgID: core.PkgID{
PkgIdentifier: ftypes.PkgIdentifier{
BOMRef: "3ff14136-e09f-4df9-80ea-000000000001",
},
},
@@ -396,7 +397,7 @@ func TestEncoder_Encode(t *testing.T) {
Value: "gobinary",
},
},
PkgID: core.PkgID{
PkgIdentifier: ftypes.PkgIdentifier{
BOMRef: "3ff14136-e09f-4df9-80ea-000000000002",
},
},
@@ -414,7 +415,7 @@ func TestEncoder_Encode(t *testing.T) {
Value: "gobinary",
},
},
PkgID: core.PkgID{
PkgIdentifier: ftypes.PkgIdentifier{
PURL: &packageurl.PackageURL{
Type: packageurl.TypeGolang,
Namespace: "github.com/org",
@@ -438,7 +439,7 @@ func TestEncoder_Encode(t *testing.T) {
Value: "gobinary",
},
},
PkgID: core.PkgID{
PkgIdentifier: ftypes.PkgIdentifier{
PURL: &packageurl.PackageURL{
Type: packageurl.TypeGolang,
Namespace: "github.com/org",
@@ -463,7 +464,7 @@ func TestEncoder_Encode(t *testing.T) {
Value: "gobinary",
},
},
PkgID: core.PkgID{
PkgIdentifier: ftypes.PkgIdentifier{
PURL: &packageurl.PackageURL{
Type: packageurl.TypeGolang,
Namespace: "github.com/org",
@@ -488,7 +489,7 @@ func TestEncoder_Encode(t *testing.T) {
Value: "gobinary",
},
},
PkgID: core.PkgID{
PkgIdentifier: ftypes.PkgIdentifier{
PURL: &packageurl.PackageURL{
Type: packageurl.TypeGolang,
Name: "stdlib",
@@ -537,7 +538,7 @@ func TestEncoder_Encode(t *testing.T) {
report: types.Report{
SchemaVersion: 2,
ArtifactName: "debian:12",
ArtifactType: ftypes.ArtifactContainerImage,
ArtifactType: artifact.TypeContainerImage,
Metadata: types.Metadata{
OS: &ftypes.OS{
Family: ftypes.Debian,

View File

@@ -229,8 +229,8 @@ func (m *Marshaler) packageDownloadLocation(root *core.Component) string {
func (m *Marshaler) rootSPDXPackage(root *core.Component, pkgDownloadLocation string) (*spdx.Package, error) {
var externalReferences []*spdx.PackageExternalReference
// When the target is a container image, add PURL to the external references of the root package.
if root.PkgID.PURL != nil {
externalReferences = append(externalReferences, m.purlExternalReference(root.PkgID.PURL.String()))
if root.PkgIdentifier.PURL != nil {
externalReferences = append(externalReferences, m.purlExternalReference(root.PkgIdentifier.PURL.String()))
}
pkgID, err := calcPkgID(m.hasher, fmt.Sprintf("%s-%s", root.Name, root.Type))
@@ -304,8 +304,8 @@ func (m *Marshaler) spdxPackage(c *core.Component, pkgDownloadLocation string) (
}
var pkgExtRefs []*spdx.PackageExternalReference
if c.PkgID.PURL != nil {
pkgExtRefs = []*spdx.PackageExternalReference{m.purlExternalReference(c.PkgID.PURL.String())}
if c.PkgIdentifier.PURL != nil {
pkgExtRefs = []*spdx.PackageExternalReference{m.purlExternalReference(c.PkgIdentifier.PURL.String())}
}
var digests []digest.Digest
@@ -338,7 +338,7 @@ func (m *Marshaler) spdxPackage(c *core.Component, pkgDownloadLocation string) (
}
func spdxPkgName(component *core.Component) string {
if p := component.PkgID.PURL; p != nil && component.Group != "" {
if p := component.PkgIdentifier.PURL; p != nil && component.Group != "" {
if p.Type == packageurl.TypeMaven || p.Type == packageurl.TypeGradle {
return component.Group + ":" + component.Name
}

View File

@@ -2,6 +2,7 @@ package spdx_test
import (
"context"
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
"github.com/aquasecurity/trivy/pkg/sbom/core"
"github.com/package-url/packageurl-go"
"hash/fnv"
@@ -34,7 +35,7 @@ func TestMarshaler_Marshal(t *testing.T) {
inputReport: types.Report{
SchemaVersion: report.SchemaVersion,
ArtifactName: "rails:latest",
ArtifactType: ftypes.ArtifactContainerImage,
ArtifactType: artifact.TypeContainerImage,
Metadata: types.Metadata{
Size: 1024,
OS: &ftypes.OS{
@@ -358,7 +359,7 @@ func TestMarshaler_Marshal(t *testing.T) {
inputReport: types.Report{
SchemaVersion: report.SchemaVersion,
ArtifactName: "centos:latest",
ArtifactType: ftypes.ArtifactContainerImage,
ArtifactType: artifact.TypeContainerImage,
Metadata: types.Metadata{
Size: 1024,
OS: &ftypes.OS{
@@ -649,7 +650,7 @@ func TestMarshaler_Marshal(t *testing.T) {
inputReport: types.Report{
SchemaVersion: report.SchemaVersion,
ArtifactName: "masahiro331/CVE-2021-41098",
ArtifactType: ftypes.ArtifactFilesystem,
ArtifactType: artifact.TypeFilesystem,
Results: types.Results{
{
Target: "Gemfile.lock",
@@ -818,7 +819,7 @@ func TestMarshaler_Marshal(t *testing.T) {
inputReport: types.Report{
SchemaVersion: report.SchemaVersion,
ArtifactName: "http://test-aggregate",
ArtifactType: ftypes.ArtifactRepository,
ArtifactType: artifact.TypeRepository,
Results: types.Results{
{
Target: "Node.js",
@@ -937,7 +938,7 @@ func TestMarshaler_Marshal(t *testing.T) {
inputReport: types.Report{
SchemaVersion: report.SchemaVersion,
ArtifactName: "empty/path",
ArtifactType: ftypes.ArtifactFilesystem,
ArtifactType: artifact.TypeFilesystem,
Results: types.Results{},
},
wantSBOM: &spdx.Document{
@@ -985,7 +986,7 @@ func TestMarshaler_Marshal(t *testing.T) {
inputReport: types.Report{
SchemaVersion: report.SchemaVersion,
ArtifactName: "secret",
ArtifactType: ftypes.ArtifactFilesystem,
ArtifactType: artifact.TypeFilesystem,
Results: types.Results{
{
Target: "key.pem",
@@ -1047,7 +1048,7 @@ func TestMarshaler_Marshal(t *testing.T) {
inputReport: types.Report{
SchemaVersion: report.SchemaVersion,
ArtifactName: "go-artifact",
ArtifactType: ftypes.ArtifactFilesystem,
ArtifactType: artifact.TypeFilesystem,
Results: types.Results{
{
Target: "/usr/local/bin/test",

View File

@@ -167,7 +167,7 @@ func (s *SPDX) parsePackage(spdxPkg spdx.Package) (*core.Component, error) {
}
// PURL
if component.PkgID.PURL, err = s.parseExternalReferences(spdxPkg.PackageExternalReferences); err != nil {
if component.PkgIdentifier.PURL, err = s.parseExternalReferences(spdxPkg.PackageExternalReferences); err != nil {
return nil, xerrors.Errorf("external references error: %w", err)
}

View File

@@ -169,7 +169,7 @@ func (s Scanner) ScanArtifact(ctx context.Context, options types.ScanOptions) (t
}
// Layer makes sense only when scanning container images
if artifactInfo.Type != ftypes.ArtifactContainerImage {
if artifactInfo.Type != artifact.TypeContainerImage {
removeLayer(results)
}

View File

@@ -37,12 +37,12 @@ func TestScanner_ScanArtifact(t *testing.T) {
CtxAnything: true,
},
Returns: artifact.ArtifactInspectReturns{
Reference: ftypes.ArtifactReference{
Reference: artifact.Reference{
Name: "alpine:3.11",
Type: ftypes.ArtifactContainerImage,
Type: artifact.TypeContainerImage,
ID: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
BlobIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},
ImageMetadata: ftypes.ImageMetadata{
ImageMetadata: artifact.ImageMetadata{
ID: "sha256:e389ae58922402a7ded319e79f06ac428d05698d8e61ecbe88d2cf850e42651d",
DiffIDs: []string{"sha256:9a5d14f9f5503e55088666beef7e85a8d9625d4fa7418e2fe269e9c54bcb853c"},
RepoTags: []string{"alpine:3.11"},
@@ -100,7 +100,7 @@ func TestScanner_ScanArtifact(t *testing.T) {
SchemaVersion: 2,
CreatedAt: time.Date(2021, 8, 25, 12, 20, 30, 5, time.UTC),
ArtifactName: "alpine:3.11",
ArtifactType: ftypes.ArtifactContainerImage,
ArtifactType: artifact.TypeContainerImage,
Metadata: types.Metadata{
OS: &ftypes.OS{
Family: "alpine",
@@ -168,7 +168,7 @@ func TestScanner_ScanArtifact(t *testing.T) {
CtxAnything: true,
},
Returns: artifact.ArtifactInspectReturns{
Reference: ftypes.ArtifactReference{
Reference: artifact.Reference{
Name: "alpine:3.11",
ID: "sha256:e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a",
BlobIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"},

View File

@@ -5,18 +5,19 @@ import (
v1 "github.com/google/go-containerregistry/pkg/v1" // nolint: goimports
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/sbom/core"
)
// Report represents a scan result
type Report struct {
SchemaVersion int `json:",omitempty"`
CreatedAt time.Time `json:",omitempty"`
ArtifactName string `json:",omitempty"`
ArtifactType ftypes.ArtifactType `json:",omitempty"`
Metadata Metadata `json:",omitempty"`
Results Results `json:",omitempty"`
SchemaVersion int `json:",omitempty"`
CreatedAt time.Time `json:",omitempty"`
ArtifactName string `json:",omitempty"`
ArtifactType artifact.Type `json:",omitempty"`
Metadata Metadata `json:",omitempty"`
Results Results `json:",omitempty"`
// parsed SBOM
BOM *core.BOM `json:"-"` // Just for internal usage, not exported in JSON

View File

@@ -44,8 +44,8 @@ func (v *OpenVEX) Filter(result *types.Result, bom *core.BOM) {
func (v *OpenVEX) Matches(vuln types.DetectedVulnerability, bom *core.BOM) []openvex.Statement {
root := bom.Root()
if root != nil && root.PkgID.PURL != nil {
stmts := v.vex.Matches(vuln.VulnerabilityID, root.PkgID.PURL.String(), []string{vuln.PkgIdentifier.PURL.String()})
if root != nil && root.PkgIdentifier.PURL != nil {
stmts := v.vex.Matches(vuln.VulnerabilityID, root.PkgIdentifier.PURL.String(), []string{vuln.PkgIdentifier.PURL.String()})
if len(stmts) != 0 {
return stmts
}

View File

@@ -11,7 +11,7 @@ import (
"github.com/sirupsen/logrus"
"golang.org/x/xerrors"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
"github.com/aquasecurity/trivy/pkg/sbom"
"github.com/aquasecurity/trivy/pkg/sbom/core"
"github.com/aquasecurity/trivy/pkg/sbom/cyclonedx"
@@ -68,7 +68,7 @@ func decodeCycloneDXJSON(r io.ReadSeeker, report types.Report) (VEX, error) {
if err != nil {
return nil, xerrors.Errorf("json decode error: %w", err)
}
if report.ArtifactType != ftypes.ArtifactCycloneDX {
if report.ArtifactType != artifact.TypeCycloneDX {
return nil, xerrors.New("CycloneDX VEX can be used with CycloneDX SBOM")
}
return newCycloneDX(report.BOM, vex), nil

View File

@@ -1,6 +1,7 @@
package vex_test
import (
"github.com/aquasecurity/trivy/pkg/fanal/artifact"
"github.com/aquasecurity/trivy/pkg/sbom/core"
"os"
"testing"
@@ -135,7 +136,7 @@ func TestVEX_Filter(t *testing.T) {
fields: fields{
filePath: "testdata/cyclonedx.json",
report: types.Report{
ArtifactType: ftypes.ArtifactCycloneDX,
ArtifactType: artifact.TypeCycloneDX,
BOM: &core.BOM{
SerialNumber: "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
Version: 1,
@@ -218,7 +219,7 @@ func TestVEX_Filter(t *testing.T) {
fields: fields{
filePath: "testdata/cyclonedx.json",
report: types.Report{
ArtifactType: ftypes.ArtifactCycloneDX,
ArtifactType: artifact.TypeCycloneDX,
BOM: &core.BOM{
SerialNumber: "urn:uuid:wrong",
Version: 1,
@@ -378,7 +379,7 @@ func newTestBOM() *core.BOM {
Root: true,
Type: core.TypeContainerImage,
Name: "debian:12",
PkgID: core.PkgID{
PkgIdentifier: ftypes.PkgIdentifier{
PURL: &packageurl.PackageURL{
Type: packageurl.TypeOCI,
Name: "debian",
@@ -405,7 +406,7 @@ func newTestBOM2() *core.BOM {
Root: true,
Type: core.TypeContainerImage,
Name: "ubuntu:24.04",
PkgID: core.PkgID{
PkgIdentifier: ftypes.PkgIdentifier{
PURL: &packageurl.PackageURL{
Type: packageurl.TypeOCI,
Name: "ubuntu",