From 857516879b445f2326250bc4df86f4ba28f6db47 Mon Sep 17 00:00:00 2001 From: Thomas Gosteli Date: Thu, 24 Oct 2024 10:31:08 +0200 Subject: [PATCH 1/6] feat(cataloger): add a terraform provider cataloger Signed-off-by: Thomas Gosteli --- go.mod | 7 ++ go.sum | 14 ++++ internal/task/package_tasks.go | 2 + .../internal/spdxutil/helpers/source_info.go | 2 + .../spdxutil/helpers/source_info_test.go | 8 +++ syft/pkg/cataloger/terraform/cataloger.go | 12 ++++ .../pkg/cataloger/terraform/cataloger_test.go | 72 +++++++++++++++++++ syft/pkg/cataloger/terraform/parse_tf_lock.go | 65 +++++++++++++++++ .../two-providers/.terraform.lock.hcl | 45 ++++++++++++ syft/pkg/type.go | 6 ++ syft/pkg/type_test.go | 4 ++ 11 files changed, 237 insertions(+) create mode 100644 syft/pkg/cataloger/terraform/cataloger.go create mode 100644 syft/pkg/cataloger/terraform/cataloger_test.go create mode 100644 syft/pkg/cataloger/terraform/parse_tf_lock.go create mode 100644 syft/pkg/cataloger/terraform/test-fixtures/two-providers/.terraform.lock.hcl diff --git a/go.mod b/go.mod index 3cb4ecb038f..d104b003989 100644 --- a/go.mod +++ b/go.mod @@ -89,6 +89,7 @@ require google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirec require ( github.com/BurntSushi/toml v1.4.0 github.com/OneOfOne/xxhash v1.2.8 + github.com/hashicorp/hcl/v2 v2.22.0 github.com/adrg/xdg v0.5.3 github.com/magiconair/properties v1.8.7 golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 @@ -104,8 +105,11 @@ require ( github.com/Microsoft/go-winio v0.6.2 // indirect github.com/Microsoft/hcsshim v0.11.7 // indirect github.com/ProtonMail/go-crypto v1.0.0 // indirect + github.com/agext/levenshtein v1.2.1 // indirect github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092 // indirect github.com/andybalholm/brotli v1.0.4 // indirect + github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect + github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect github.com/aquasecurity/go-version v0.0.0-20210121072130-637058cfe492 // indirect github.com/atotto/clipboard v0.1.4 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect @@ -173,6 +177,7 @@ require ( github.com/mattn/go-runewidth v0.0.16 // indirect github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/locker v1.0.1 // indirect @@ -224,6 +229,7 @@ require ( github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect + github.com/zclconf/go-cty v1.13.0 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect go.opentelemetry.io/otel v1.24.0 // indirect @@ -236,6 +242,7 @@ require ( golang.org/x/sys v0.27.0 // indirect golang.org/x/term v0.26.0 // indirect golang.org/x/text v0.20.0 // indirect + golang.org/x/tools v0.23.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c // indirect google.golang.org/grpc v1.62.1 // indirect diff --git a/go.sum b/go.sum index 4a71e1afe38..f48fd62d558 100644 --- a/go.sum +++ b/go.sum @@ -89,6 +89,8 @@ github.com/acobaugh/osrelease v0.1.0 h1:Yb59HQDGGNhCj4suHaFQQfBps5wyoKLSSX/J/+Ui github.com/acobaugh/osrelease v0.1.0/go.mod h1:4bFEs0MtgHNHBrmHCt67gNisnabCRAlzdVasCEGHTWY= github.com/adrg/xdg v0.5.3 h1:xRnxJXne7+oWDatRhR1JLnvuccuIeCoBu2rtuLqQB78= github.com/adrg/xdg v0.5.3/go.mod h1:nlTsY+NNiCBGCK2tpm09vRqfVzrc2fLmXGpBLF0zlTQ= +github.com/agext/levenshtein v1.2.1 h1:QmvMAjj2aEICytGiWzmxoE0x2KZvE0fvmqMOfy2tjT8= +github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -124,6 +126,10 @@ github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHG github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw= +github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= +github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY= +github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46 h1:vmXNl+HDfqqXgr0uY1UgK1GAhps8nbAAtqHNBcgyf+4= github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46/go.mod h1:olhPNdiiAAMiSujemd1O/sc6GcyePr23f/6uGKtthNg= github.com/aquasecurity/go-version v0.0.0-20210121072130-637058cfe492 h1:rcEG5HI490FF0a7zuvxOxen52ddygCfNVjP0XOCMl+M= @@ -459,6 +465,8 @@ github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/hcl/v2 v2.22.0 h1:hkZ3nCtqeJsDhPRFz5EA9iwcG1hNWGePOTw6oyul12M= +github.com/hashicorp/hcl/v2 v2.22.0/go.mod h1:62ZYHrXgPoX8xBnzl8QzbWq4dyDsDtfCRgIq1rbJEvA= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= @@ -568,6 +576,8 @@ github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HK github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM= +github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= @@ -816,6 +826,10 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/zclconf/go-cty v1.13.0 h1:It5dfKTTZHe9aeppbNOda3mN7Ag7sg6QkBNm6TkyFa0= +github.com/zclconf/go-cty v1.13.0/go.mod h1:YKQzy/7pZ7iq2jNFzy5go57xdxdWoLLpaEp4u238AE0= +github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940 h1:4r45xpDWB6ZMSMNJFMOjqrGHynW3DIBuR2H9j0ug+Mo= +github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940/go.mod h1:CmBdvvj3nqzfzJ6nTCIwDTPZ56aVGvDrmztiO5g3qrM= github.com/zyedidia/generic v1.2.2-0.20230320175451-4410d2372cb1 h1:V+UsotZpAVvfj3X/LMoEytoLzSiP6Lg0F7wdVyu9gGg= github.com/zyedidia/generic v1.2.2-0.20230320175451-4410d2372cb1/go.mod h1:ly2RBz4mnz1yeuVbQA/VFwGjK3mnHGRj1JuoG336Bis= go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= diff --git a/internal/task/package_tasks.go b/internal/task/package_tasks.go index 431c77590f4..cb5b69f57bf 100644 --- a/internal/task/package_tasks.go +++ b/internal/task/package_tasks.go @@ -31,6 +31,7 @@ import ( sbomCataloger "github.com/anchore/syft/syft/pkg/cataloger/sbom" "github.com/anchore/syft/syft/pkg/cataloger/swift" "github.com/anchore/syft/syft/pkg/cataloger/swipl" + "github.com/anchore/syft/syft/pkg/cataloger/terraform" "github.com/anchore/syft/syft/pkg/cataloger/wordpress" ) @@ -151,5 +152,6 @@ func DefaultPackageTaskFactories() PackageTaskFactories { ), newSimplePackageTaskFactory(sbomCataloger.NewCataloger, "sbom"), // note: not evidence of installed packages newSimplePackageTaskFactory(wordpress.NewWordpressPluginCataloger, pkgcataloging.DirectoryTag, pkgcataloging.ImageTag, "wordpress"), + newSimplePackageTaskFactory(terraform.NewTerraformCataloger, pkgcataloging.DirectoryTag, "terraform"), } } diff --git a/syft/format/internal/spdxutil/helpers/source_info.go b/syft/format/internal/spdxutil/helpers/source_info.go index bf8b2721870..6ea2a67f990 100644 --- a/syft/format/internal/spdxutil/helpers/source_info.go +++ b/syft/format/internal/spdxutil/helpers/source_info.go @@ -70,6 +70,8 @@ func SourceInfo(p pkg.Package) string { answer = "acquired package info from GitHub Actions workflow file or composite action file" case pkg.WordpressPluginPkg: answer = "acquired package info from found wordpress plugin PHP source files" + case pkg.TerraformPkg: + answer = "acquired package info from Terraform dependency lock file" default: answer = "acquired package info from the following paths" } diff --git a/syft/format/internal/spdxutil/helpers/source_info_test.go b/syft/format/internal/spdxutil/helpers/source_info_test.go index d7da0eab133..309d79bbf6b 100644 --- a/syft/format/internal/spdxutil/helpers/source_info_test.go +++ b/syft/format/internal/spdxutil/helpers/source_info_test.go @@ -303,6 +303,14 @@ func Test_SourceInfo(t *testing.T) { "acquired package info from found wordpress plugin PHP source files", }, }, + { + input: pkg.Package{ + Type: pkg.TerraformPkg, + }, + expected: []string{ + "acquired package info from Terraform dependency lock file", + }, + }, } var pkgTypes []pkg.Type for _, test := range tests { diff --git a/syft/pkg/cataloger/terraform/cataloger.go b/syft/pkg/cataloger/terraform/cataloger.go new file mode 100644 index 00000000000..efdd0940c02 --- /dev/null +++ b/syft/pkg/cataloger/terraform/cataloger.go @@ -0,0 +1,12 @@ +package terraform + +import ( + "github.com/anchore/syft/syft/pkg" + "github.com/anchore/syft/syft/pkg/cataloger/generic" +) + +func NewTerraformCataloger() pkg.Cataloger { + return generic.NewCataloger("terraform-cataloger"). + WithParserByGlobs(parseTerraformLock, "**/.terraform.lock.hcl"). + WithProcessors() +} diff --git a/syft/pkg/cataloger/terraform/cataloger_test.go b/syft/pkg/cataloger/terraform/cataloger_test.go new file mode 100644 index 00000000000..7fc1d44161c --- /dev/null +++ b/syft/pkg/cataloger/terraform/cataloger_test.go @@ -0,0 +1,72 @@ +package terraform + +import ( + "path/filepath" + "testing" + + "github.com/anchore/syft/syft/file" + "github.com/anchore/syft/syft/internal/fileresolver" + "github.com/anchore/syft/syft/pkg" + "github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest" +) + +func TestTerraformCataloger(t *testing.T) { + c := NewTerraformCataloger() + + fileLoc := file.NewLocation(".terraform.lock.hcl") + location := fileLoc.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation) + + awsProviderPkg := pkg.Package{ + Name: "registry.terraform.io/hashicorp/aws", + Version: "5.72.1", + FoundBy: "terraform-cataloger", + Locations: file.NewLocationSet(location), + Type: pkg.TerraformPkg, + PURL: "pkg:terraform/registry.terraform.io/hashicorp/aws@5.72.1", + Metadata: []pkg.KeyValue{ + { + Key: "constraints", + Value: "5.72.1", + }, + }, + } + awsProviderPkg.SetID() + + gcpProviderPkg := pkg.Package{ + Name: "registry.terraform.io/hashicorp/google", + Version: "6.8.0", + FoundBy: "terraform-cataloger", + Locations: file.NewLocationSet(location), + Type: pkg.TerraformPkg, + PURL: "pkg:terraform/registry.terraform.io/hashicorp/google@6.8.0", + Metadata: []pkg.KeyValue{ + { + Key: "constraints", + Value: "6.8.0", + }, + }, + } + gcpProviderPkg.SetID() + + tests := []struct { + name string + expected []pkg.Package + }{ + { + name: "two-providers", + expected: []pkg.Package{ + awsProviderPkg, + gcpProviderPkg, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + pkgtest.NewCatalogTester(). + WithResolver(fileresolver.NewFromUnindexedDirectory(filepath.Join("test-fixtures", tt.name))). + Expects(tt.expected, nil). + TestCataloger(t, c) + }) + } +} diff --git a/syft/pkg/cataloger/terraform/parse_tf_lock.go b/syft/pkg/cataloger/terraform/parse_tf_lock.go new file mode 100644 index 00000000000..9a957b5c86c --- /dev/null +++ b/syft/pkg/cataloger/terraform/parse_tf_lock.go @@ -0,0 +1,65 @@ +package terraform + +import ( + "context" + "fmt" + "io" + + "github.com/anchore/packageurl-go" + "github.com/hashicorp/hcl/v2/hclsimple" + + "github.com/anchore/syft/syft/artifact" + "github.com/anchore/syft/syft/file" + "github.com/anchore/syft/syft/pkg" + "github.com/anchore/syft/syft/pkg/cataloger/generic" +) + +type lockFile struct { + Providers []struct { + URL string `hcl:",label"` + Constraints string `hcl:"constraints"` + Version string `hcl:"version"` + Hashes []string `hcl:"hashes"` + } `hcl:"provider,block"` +} + +func parseTerraformLock(_ context.Context, resolver file.Resolver, env *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) { + var lockFile lockFile + + contents, err := io.ReadAll(reader) + if err != nil { + return nil, nil, fmt.Errorf("failed to read terraform lock file: %w", err) + } + + err = hclsimple.Decode(reader.RealPath, contents, nil, &lockFile) + if err != nil { + return nil, nil, fmt.Errorf("failed to decode terraform lock file: %w", err) + } + + pkgs := make([]pkg.Package, 0, len(lockFile.Providers)) + + for _, provider := range lockFile.Providers { + pkg := pkg.Package{ + Name: provider.URL, + Version: provider.Version, + FoundBy: "terraform-cataloger", + Locations: file.NewLocationSet(reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)), + //Licenses: nil, + //Language: nil, + Type: pkg.TerraformPkg, + //CPEs: nil, + PURL: packageurl.NewPackageURL(packageurl.TypeTerraform, "", provider.URL, provider.Version, nil, "").String(), + Metadata: []pkg.KeyValue{ + { + Key: "constraints", + Value: provider.Constraints, + }, + }, + } + pkg.SetID() + + pkgs = append(pkgs, pkg) + } + + return pkgs, nil, nil +} diff --git a/syft/pkg/cataloger/terraform/test-fixtures/two-providers/.terraform.lock.hcl b/syft/pkg/cataloger/terraform/test-fixtures/two-providers/.terraform.lock.hcl new file mode 100644 index 00000000000..6c92fa85ff2 --- /dev/null +++ b/syft/pkg/cataloger/terraform/test-fixtures/two-providers/.terraform.lock.hcl @@ -0,0 +1,45 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/aws" { + version = "5.72.1" + constraints = "5.72.1" + hashes = [ + "h1:jhd5O5o0CfZCNEwwN0EiDAzb7ApuFrtxJqa6HXW4EKE=", + "zh:0dea6843836e926d33469b48b948744079023816d16a2ff7666bcfb6aa3522d4", + "zh:195fa9513f75800a0d62797ebec75ee73e9b8c28d713fe9b63d3b1d1eec129b3", + "zh:1ed92f3961715bf0e024bcde3c12dfbdc50b00c1f8a43cc00802cfc45a256208", + "zh:2ac687e3a52606466cae4a6813e81d923042488df88d2424e28d3f8530f091bb", + "zh:32e7ca75f9314557daada3c44628fe1f3bf964a4f833bfb4b2295d833fe64b6f", + "zh:374ee0e6b4327cc6ef666908ce5d6450a3a56e90cd2b785e83c2bcfc100021d2", + "zh:5500fd6fdac44f96411fcf9c6d01691159ec35455ed127eb4c3a498e1cc92a64", + "zh:723a2dc4b064c12e7ee62ad4fbfd72fa5e025206ea47b735994ef53f3c373152", + "zh:89d97b87605f1d734f27e642567cbecf785b521af8ea81dac55c77ccde876221", + "zh:951ee1e5731e8d65d521d71b95927e55055b3c4656eef6d46fa580a63328befc", + "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", + "zh:9b2b362470b64ec227b2da64762ab8bc4111c6b80365fd9d82fc5e1e33f44038", + "zh:aa6e57d0cb974ff0da5dee5d43ad2745cbbc4a2b507d4c799839b9fa96daf688", + "zh:ba0d14c4a6b7aa844a830d47c0bf995b632e37f0795394b5b60c638b62b7fc03", + "zh:c9764065a9c5d324db0b02bd201b9e3a2118e49c4960884acdeea377173302e9", + ] +} + +provider "registry.terraform.io/hashicorp/google" { + version = "6.8.0" + constraints = "6.8.0" + hashes = [ + "h1:GlCaVPk6eKMg2ZbRY7C5tUeHGNIABT+qFtMl8+XWZHM=", + "zh:1b78f4451f1617092eb6891c9c13eda79671060601c40947feea6794c732157a", + "zh:4c6d7231ce32c6ff2a98218ef363c133d27d423b009354e7fe18459d9feb41d4", + "zh:6ae0112e9c733ab6c72436a334ffe3f197a613bb04f49538462b83b236d37a2d", + "zh:8bd5651838ad674e0a173a453b76c80b94d08ebcb8ea0b6263ce6da0599b42f5", + "zh:94ee7bcd77b0b7c2777113e35282da014e61e813fe46c058a49bf3d616fecdf4", + "zh:c0bf014422c2971985d34ad45ddb6aa737373398f83b325884ea5608ac1264aa", + "zh:c2cbbf0c249c3d1842ad0ad77fb7ef85bd3e92c688618c4087173bc1d69cd098", + "zh:cefa3e06cb353d08b83dafa6135cd78e17540ae735b7c5687833cc1925c3fd8e", + "zh:d20bc0216bf7f054f6318467d3902ced05e9f0bfa500ee55bf43b1b41ef0b854", + "zh:e54ad5959e53b9e9acafc243d6f4039ab5005cec32c7435a122da964888d184c", + "zh:e833c8de147268b3ffc14c60915eccb9347ade5f25b37b3771240a4d68b6aac4", + "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", + ] +} diff --git a/syft/pkg/type.go b/syft/pkg/type.go index 7cebaa8e1da..fd5255e30f4 100644 --- a/syft/pkg/type.go +++ b/syft/pkg/type.go @@ -45,6 +45,7 @@ const ( SwiplPackPkg Type = "swiplpack" OpamPkg Type = "opam" WordpressPluginPkg Type = "wordpress-plugin" + TerraformPkg Type = "terraform" ) // AllPkgs represents all supported package types @@ -83,6 +84,7 @@ var AllPkgs = []Type{ SwiplPackPkg, OpamPkg, WordpressPluginPkg, + TerraformPkg, } // PackageURLType returns the PURL package type for the current package. @@ -151,6 +153,8 @@ func (t Type) PackageURLType() string { return "opam" case WordpressPluginPkg: return "wordpress-plugin" + case TerraformPkg: + return "terraform" default: // TODO: should this be a "generic" purl type instead? return "" @@ -231,6 +235,8 @@ func TypeByName(name string) Type { return OpamPkg case "wordpress-plugin": return WordpressPluginPkg + case "terraform": + return TerraformPkg default: return UnknownPkg } diff --git a/syft/pkg/type_test.go b/syft/pkg/type_test.go index 6607abd0634..a1368930d07 100644 --- a/syft/pkg/type_test.go +++ b/syft/pkg/type_test.go @@ -119,6 +119,10 @@ func TestTypeFromPURL(t *testing.T) { purl: "pkg:opam/ocaml-base-compiler@5.2.0", expected: OpamPkg, }, + { + purl: "pkg:terraform/registry.terraform.io/hashicorp/aws@5.72.1", + expected: TerraformPkg, + }, } var pkgTypes []string From b0520292716059cd60eb80d2eebd94ea432b5e4e Mon Sep 17 00:00:00 2001 From: Thomas Gosteli Date: Thu, 24 Oct 2024 13:13:59 +0200 Subject: [PATCH 2/6] docs(README): add terraform to supported ecosystems Signed-off-by: Thomas Gosteli --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index d159255607e..c4b8de60ec5 100644 --- a/README.md +++ b/README.md @@ -146,6 +146,7 @@ Note that flags using the @ can be used for earlier versions of each sp - Rust (cargo.lock) - Swift (cocoapods, swift-package-manager) - Wordpress plugins +- Terraform providers (.terraform.lock.hcl) ## Documentation From 8c56a1a4f4d84769fa389041d38ba73bf912453a Mon Sep 17 00:00:00 2001 From: Thomas Gosteli Date: Thu, 24 Oct 2024 13:34:24 +0200 Subject: [PATCH 3/6] build: fix integration test and lint errors Signed-off-by: Thomas Gosteli --- .../catalog_packages_cases_test.go | 7 ++++++ .../test/integration/catalog_packages_test.go | 1 + .../terraform/.terraform.lock.hcl | 25 +++++++++++++++++++ syft/pkg/cataloger/terraform/parse_tf_lock.go | 2 +- syft/pkg/type.go | 2 +- 5 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 cmd/syft/internal/test/integration/test-fixtures/image-pkg-coverage/terraform/.terraform.lock.hcl diff --git a/cmd/syft/internal/test/integration/catalog_packages_cases_test.go b/cmd/syft/internal/test/integration/catalog_packages_cases_test.go index d9da923be67..2a68de19fc3 100644 --- a/cmd/syft/internal/test/integration/catalog_packages_cases_test.go +++ b/cmd/syft/internal/test/integration/catalog_packages_cases_test.go @@ -418,6 +418,13 @@ var dirOnlyTestCases = []testCase{ "ocaml-base-compiler": "4.14.0", }, }, + { + name: "find terraform packages", + pkgType: pkg.TerraformPkg, + pkgInfo: map[string]string{ + "registry.terraform.io/hashicorp/aws": "5.72.1", + }, + }, } var commonTestCases = []testCase{ diff --git a/cmd/syft/internal/test/integration/catalog_packages_test.go b/cmd/syft/internal/test/integration/catalog_packages_test.go index 371ddb4e59b..6a1a9dbb348 100644 --- a/cmd/syft/internal/test/integration/catalog_packages_test.go +++ b/cmd/syft/internal/test/integration/catalog_packages_test.go @@ -82,6 +82,7 @@ func TestPkgCoverageImage(t *testing.T) { definedPkgs.Remove(string(pkg.OpamPkg)) definedPkgs.Remove(string(pkg.GithubActionPkg)) definedPkgs.Remove(string(pkg.GithubActionWorkflowPkg)) + definedPkgs.Remove(string(pkg.TerraformPkg)) var cases []testCase cases = append(cases, commonTestCases...) diff --git a/cmd/syft/internal/test/integration/test-fixtures/image-pkg-coverage/terraform/.terraform.lock.hcl b/cmd/syft/internal/test/integration/test-fixtures/image-pkg-coverage/terraform/.terraform.lock.hcl new file mode 100644 index 00000000000..b602dc8382d --- /dev/null +++ b/cmd/syft/internal/test/integration/test-fixtures/image-pkg-coverage/terraform/.terraform.lock.hcl @@ -0,0 +1,25 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/aws" { + version = "5.72.1" + constraints = ">= 5.72.0" + hashes = [ + "h1:jhd5O5o0CfZCNEwwN0EiDAzb7ApuFrtxJqa6HXW4EKE=", + "zh:0dea6843836e926d33469b48b948744079023816d16a2ff7666bcfb6aa3522d4", + "zh:195fa9513f75800a0d62797ebec75ee73e9b8c28d713fe9b63d3b1d1eec129b3", + "zh:1ed92f3961715bf0e024bcde3c12dfbdc50b00c1f8a43cc00802cfc45a256208", + "zh:2ac687e3a52606466cae4a6813e81d923042488df88d2424e28d3f8530f091bb", + "zh:32e7ca75f9314557daada3c44628fe1f3bf964a4f833bfb4b2295d833fe64b6f", + "zh:374ee0e6b4327cc6ef666908ce5d6450a3a56e90cd2b785e83c2bcfc100021d2", + "zh:5500fd6fdac44f96411fcf9c6d01691159ec35455ed127eb4c3a498e1cc92a64", + "zh:723a2dc4b064c12e7ee62ad4fbfd72fa5e025206ea47b735994ef53f3c373152", + "zh:89d97b87605f1d734f27e642567cbecf785b521af8ea81dac55c77ccde876221", + "zh:951ee1e5731e8d65d521d71b95927e55055b3c4656eef6d46fa580a63328befc", + "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", + "zh:9b2b362470b64ec227b2da64762ab8bc4111c6b80365fd9d82fc5e1e33f44038", + "zh:aa6e57d0cb974ff0da5dee5d43ad2745cbbc4a2b507d4c799839b9fa96daf688", + "zh:ba0d14c4a6b7aa844a830d47c0bf995b632e37f0795394b5b60c638b62b7fc03", + "zh:c9764065a9c5d324db0b02bd201b9e3a2118e49c4960884acdeea377173302e9", + ] +} diff --git a/syft/pkg/cataloger/terraform/parse_tf_lock.go b/syft/pkg/cataloger/terraform/parse_tf_lock.go index 9a957b5c86c..9719563ae69 100644 --- a/syft/pkg/cataloger/terraform/parse_tf_lock.go +++ b/syft/pkg/cataloger/terraform/parse_tf_lock.go @@ -23,7 +23,7 @@ type lockFile struct { } `hcl:"provider,block"` } -func parseTerraformLock(_ context.Context, resolver file.Resolver, env *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) { +func parseTerraformLock(_ context.Context, _ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) { var lockFile lockFile contents, err := io.ReadAll(reader) diff --git a/syft/pkg/type.go b/syft/pkg/type.go index fd5255e30f4..54da790fab8 100644 --- a/syft/pkg/type.go +++ b/syft/pkg/type.go @@ -174,7 +174,7 @@ func TypeFromPURL(p string) Type { return TypeByName(ptype) } -//nolint:funlen +//nolint:funlen,gocyclo func TypeByName(name string) Type { switch name { case packageurl.TypeDebian: From 8c06316b8ee84920ebd3564b458f2e0d8ade61e4 Mon Sep 17 00:00:00 2001 From: Thomas Gosteli Date: Fri, 25 Oct 2024 10:43:18 +0200 Subject: [PATCH 4/6] fix: update JSON schema with TerraformLockEntry Signed-off-by: Thomas Gosteli --- internal/constants.go | 2 +- schema/json/schema-16.0.19.json | 2756 +++++++++++++++++ schema/json/schema-latest.json | 31 +- .../helpers/originator_supplier_test.go | 8 + syft/internal/packagemetadata/generated.go | 1 + syft/internal/packagemetadata/names.go | 1 + .../pkg/cataloger/terraform/cataloger_test.go | 47 +- syft/pkg/cataloger/terraform/parse_tf_lock.go | 26 +- .../two-providers/.terraform.lock.hcl | 2 +- syft/pkg/terraform.go | 9 + 10 files changed, 2854 insertions(+), 29 deletions(-) create mode 100644 schema/json/schema-16.0.19.json create mode 100644 syft/pkg/terraform.go diff --git a/internal/constants.go b/internal/constants.go index 4dd27cf7953..469f075c89c 100644 --- a/internal/constants.go +++ b/internal/constants.go @@ -3,5 +3,5 @@ package internal const ( // JSONSchemaVersion is the current schema version output by the JSON encoder // This is roughly following the "SchemaVer" guidelines for versioning the JSON schema. Please see schema/json/README.md for details on how to increment. - JSONSchemaVersion = "16.0.18" + JSONSchemaVersion = "16.0.19" ) diff --git a/schema/json/schema-16.0.19.json b/schema/json/schema-16.0.19.json new file mode 100644 index 00000000000..33514a1cc76 --- /dev/null +++ b/schema/json/schema-16.0.19.json @@ -0,0 +1,2756 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "anchore.io/schema/syft/json/16.0.19/document", + "$ref": "#/$defs/Document", + "$defs": { + "AlpmDbEntry": { + "properties": { + "basepackage": { + "type": "string" + }, + "package": { + "type": "string" + }, + "version": { + "type": "string" + }, + "description": { + "type": "string" + }, + "architecture": { + "type": "string" + }, + "size": { + "type": "integer" + }, + "packager": { + "type": "string" + }, + "url": { + "type": "string" + }, + "validation": { + "type": "string" + }, + "reason": { + "type": "integer" + }, + "files": { + "items": { + "$ref": "#/$defs/AlpmFileRecord" + }, + "type": "array" + }, + "backup": { + "items": { + "$ref": "#/$defs/AlpmFileRecord" + }, + "type": "array" + }, + "provides": { + "items": { + "type": "string" + }, + "type": "array" + }, + "depends": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "basepackage", + "package", + "version", + "description", + "architecture", + "size", + "packager", + "url", + "validation", + "reason", + "files", + "backup" + ] + }, + "AlpmFileRecord": { + "properties": { + "path": { + "type": "string" + }, + "type": { + "type": "string" + }, + "uid": { + "type": "string" + }, + "gid": { + "type": "string" + }, + "time": { + "type": "string", + "format": "date-time" + }, + "size": { + "type": "string" + }, + "link": { + "type": "string" + }, + "digest": { + "items": { + "$ref": "#/$defs/Digest" + }, + "type": "array" + } + }, + "type": "object" + }, + "ApkDbEntry": { + "properties": { + "package": { + "type": "string" + }, + "originPackage": { + "type": "string" + }, + "maintainer": { + "type": "string" + }, + "version": { + "type": "string" + }, + "architecture": { + "type": "string" + }, + "url": { + "type": "string" + }, + "description": { + "type": "string" + }, + "size": { + "type": "integer" + }, + "installedSize": { + "type": "integer" + }, + "pullDependencies": { + "items": { + "type": "string" + }, + "type": "array" + }, + "provides": { + "items": { + "type": "string" + }, + "type": "array" + }, + "pullChecksum": { + "type": "string" + }, + "gitCommitOfApkPort": { + "type": "string" + }, + "files": { + "items": { + "$ref": "#/$defs/ApkFileRecord" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "package", + "originPackage", + "maintainer", + "version", + "architecture", + "url", + "description", + "size", + "installedSize", + "pullDependencies", + "provides", + "pullChecksum", + "gitCommitOfApkPort", + "files" + ] + }, + "ApkFileRecord": { + "properties": { + "path": { + "type": "string" + }, + "ownerUid": { + "type": "string" + }, + "ownerGid": { + "type": "string" + }, + "permissions": { + "type": "string" + }, + "digest": { + "$ref": "#/$defs/Digest" + } + }, + "type": "object", + "required": [ + "path" + ] + }, + "BinarySignature": { + "properties": { + "matches": { + "items": { + "$ref": "#/$defs/ClassifierMatch" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "matches" + ] + }, + "CConanFileEntry": { + "properties": { + "ref": { + "type": "string" + } + }, + "type": "object", + "required": [ + "ref" + ] + }, + "CConanInfoEntry": { + "properties": { + "ref": { + "type": "string" + }, + "package_id": { + "type": "string" + } + }, + "type": "object", + "required": [ + "ref" + ] + }, + "CConanLockEntry": { + "properties": { + "ref": { + "type": "string" + }, + "package_id": { + "type": "string" + }, + "prev": { + "type": "string" + }, + "requires": { + "items": { + "type": "string" + }, + "type": "array" + }, + "build_requires": { + "items": { + "type": "string" + }, + "type": "array" + }, + "py_requires": { + "items": { + "type": "string" + }, + "type": "array" + }, + "options": { + "$ref": "#/$defs/KeyValues" + }, + "path": { + "type": "string" + }, + "context": { + "type": "string" + } + }, + "type": "object", + "required": [ + "ref" + ] + }, + "CConanLockV2Entry": { + "properties": { + "ref": { + "type": "string" + }, + "packageID": { + "type": "string" + }, + "username": { + "type": "string" + }, + "channel": { + "type": "string" + }, + "recipeRevision": { + "type": "string" + }, + "packageRevision": { + "type": "string" + }, + "timestamp": { + "type": "string" + } + }, + "type": "object", + "required": [ + "ref" + ] + }, + "CPE": { + "properties": { + "cpe": { + "type": "string" + }, + "source": { + "type": "string" + } + }, + "type": "object", + "required": [ + "cpe" + ] + }, + "ClassifierMatch": { + "properties": { + "classifier": { + "type": "string" + }, + "location": { + "$ref": "#/$defs/Location" + } + }, + "type": "object", + "required": [ + "classifier", + "location" + ] + }, + "CocoaPodfileLockEntry": { + "properties": { + "checksum": { + "type": "string" + } + }, + "type": "object", + "required": [ + "checksum" + ] + }, + "Coordinates": { + "properties": { + "path": { + "type": "string" + }, + "layerID": { + "type": "string" + } + }, + "type": "object", + "required": [ + "path" + ] + }, + "DartPubspecLockEntry": { + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "hosted_url": { + "type": "string" + }, + "vcs_url": { + "type": "string" + } + }, + "type": "object", + "required": [ + "name", + "version" + ] + }, + "Descriptor": { + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "configuration": true + }, + "type": "object", + "required": [ + "name", + "version" + ] + }, + "Digest": { + "properties": { + "algorithm": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object", + "required": [ + "algorithm", + "value" + ] + }, + "Document": { + "properties": { + "artifacts": { + "items": { + "$ref": "#/$defs/Package" + }, + "type": "array" + }, + "artifactRelationships": { + "items": { + "$ref": "#/$defs/Relationship" + }, + "type": "array" + }, + "files": { + "items": { + "$ref": "#/$defs/File" + }, + "type": "array" + }, + "source": { + "$ref": "#/$defs/Source" + }, + "distro": { + "$ref": "#/$defs/LinuxRelease" + }, + "descriptor": { + "$ref": "#/$defs/Descriptor" + }, + "schema": { + "$ref": "#/$defs/Schema" + } + }, + "type": "object", + "required": [ + "artifacts", + "artifactRelationships", + "source", + "distro", + "descriptor", + "schema" + ] + }, + "DotnetDepsEntry": { + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "path": { + "type": "string" + }, + "sha512": { + "type": "string" + }, + "hashPath": { + "type": "string" + } + }, + "type": "object", + "required": [ + "name", + "version", + "path", + "sha512", + "hashPath" + ] + }, + "DotnetPortableExecutableEntry": { + "properties": { + "assemblyVersion": { + "type": "string" + }, + "legalCopyright": { + "type": "string" + }, + "comments": { + "type": "string" + }, + "internalName": { + "type": "string" + }, + "companyName": { + "type": "string" + }, + "productName": { + "type": "string" + }, + "productVersion": { + "type": "string" + } + }, + "type": "object", + "required": [ + "assemblyVersion", + "legalCopyright", + "companyName", + "productName", + "productVersion" + ] + }, + "DpkgDbEntry": { + "properties": { + "package": { + "type": "string" + }, + "source": { + "type": "string" + }, + "version": { + "type": "string" + }, + "sourceVersion": { + "type": "string" + }, + "architecture": { + "type": "string" + }, + "maintainer": { + "type": "string" + }, + "installedSize": { + "type": "integer" + }, + "provides": { + "items": { + "type": "string" + }, + "type": "array" + }, + "depends": { + "items": { + "type": "string" + }, + "type": "array" + }, + "preDepends": { + "items": { + "type": "string" + }, + "type": "array" + }, + "files": { + "items": { + "$ref": "#/$defs/DpkgFileRecord" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "package", + "source", + "version", + "sourceVersion", + "architecture", + "maintainer", + "installedSize", + "files" + ] + }, + "DpkgFileRecord": { + "properties": { + "path": { + "type": "string" + }, + "digest": { + "$ref": "#/$defs/Digest" + }, + "isConfigFile": { + "type": "boolean" + } + }, + "type": "object", + "required": [ + "path", + "isConfigFile" + ] + }, + "ELFSecurityFeatures": { + "properties": { + "symbolTableStripped": { + "type": "boolean" + }, + "stackCanary": { + "type": "boolean" + }, + "nx": { + "type": "boolean" + }, + "relRO": { + "type": "string" + }, + "pie": { + "type": "boolean" + }, + "dso": { + "type": "boolean" + }, + "safeStack": { + "type": "boolean" + }, + "cfi": { + "type": "boolean" + }, + "fortify": { + "type": "boolean" + } + }, + "type": "object", + "required": [ + "symbolTableStripped", + "nx", + "relRO", + "pie", + "dso" + ] + }, + "ElfBinaryPackageNoteJsonPayload": { + "properties": { + "type": { + "type": "string" + }, + "architecture": { + "type": "string" + }, + "osCPE": { + "type": "string" + }, + "os": { + "type": "string" + }, + "osVersion": { + "type": "string" + }, + "system": { + "type": "string" + }, + "vendor": { + "type": "string" + }, + "sourceRepo": { + "type": "string" + }, + "commit": { + "type": "string" + } + }, + "type": "object" + }, + "ElixirMixLockEntry": { + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "pkgHash": { + "type": "string" + }, + "pkgHashExt": { + "type": "string" + } + }, + "type": "object", + "required": [ + "name", + "version", + "pkgHash", + "pkgHashExt" + ] + }, + "ErlangRebarLockEntry": { + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "pkgHash": { + "type": "string" + }, + "pkgHashExt": { + "type": "string" + } + }, + "type": "object", + "required": [ + "name", + "version", + "pkgHash", + "pkgHashExt" + ] + }, + "Executable": { + "properties": { + "format": { + "type": "string" + }, + "hasExports": { + "type": "boolean" + }, + "hasEntrypoint": { + "type": "boolean" + }, + "importedLibraries": { + "items": { + "type": "string" + }, + "type": "array" + }, + "elfSecurityFeatures": { + "$ref": "#/$defs/ELFSecurityFeatures" + } + }, + "type": "object", + "required": [ + "format", + "hasExports", + "hasEntrypoint", + "importedLibraries" + ] + }, + "File": { + "properties": { + "id": { + "type": "string" + }, + "location": { + "$ref": "#/$defs/Coordinates" + }, + "metadata": { + "$ref": "#/$defs/FileMetadataEntry" + }, + "contents": { + "type": "string" + }, + "digests": { + "items": { + "$ref": "#/$defs/Digest" + }, + "type": "array" + }, + "licenses": { + "items": { + "$ref": "#/$defs/FileLicense" + }, + "type": "array" + }, + "executable": { + "$ref": "#/$defs/Executable" + }, + "unknowns": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "id", + "location" + ] + }, + "FileLicense": { + "properties": { + "value": { + "type": "string" + }, + "spdxExpression": { + "type": "string" + }, + "type": { + "type": "string" + }, + "evidence": { + "$ref": "#/$defs/FileLicenseEvidence" + } + }, + "type": "object", + "required": [ + "value", + "spdxExpression", + "type" + ] + }, + "FileLicenseEvidence": { + "properties": { + "confidence": { + "type": "integer" + }, + "offset": { + "type": "integer" + }, + "extent": { + "type": "integer" + } + }, + "type": "object", + "required": [ + "confidence", + "offset", + "extent" + ] + }, + "FileMetadataEntry": { + "properties": { + "mode": { + "type": "integer" + }, + "type": { + "type": "string" + }, + "linkDestination": { + "type": "string" + }, + "userID": { + "type": "integer" + }, + "groupID": { + "type": "integer" + }, + "mimeType": { + "type": "string" + }, + "size": { + "type": "integer" + } + }, + "type": "object", + "required": [ + "mode", + "type", + "userID", + "groupID", + "mimeType", + "size" + ] + }, + "GoModuleBuildinfoEntry": { + "properties": { + "goBuildSettings": { + "$ref": "#/$defs/KeyValues" + }, + "goCompiledVersion": { + "type": "string" + }, + "architecture": { + "type": "string" + }, + "h1Digest": { + "type": "string" + }, + "mainModule": { + "type": "string" + }, + "goCryptoSettings": { + "items": { + "type": "string" + }, + "type": "array" + }, + "goExperiments": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "goCompiledVersion", + "architecture" + ] + }, + "GoModuleEntry": { + "properties": { + "h1Digest": { + "type": "string" + } + }, + "type": "object" + }, + "HaskellHackageStackEntry": { + "properties": { + "pkgHash": { + "type": "string" + } + }, + "type": "object" + }, + "HaskellHackageStackLockEntry": { + "properties": { + "pkgHash": { + "type": "string" + }, + "snapshotURL": { + "type": "string" + } + }, + "type": "object" + }, + "IDLikes": { + "items": { + "type": "string" + }, + "type": "array" + }, + "JavaArchive": { + "properties": { + "virtualPath": { + "type": "string" + }, + "manifest": { + "$ref": "#/$defs/JavaManifest" + }, + "pomProperties": { + "$ref": "#/$defs/JavaPomProperties" + }, + "pomProject": { + "$ref": "#/$defs/JavaPomProject" + }, + "digest": { + "items": { + "$ref": "#/$defs/Digest" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "virtualPath" + ] + }, + "JavaJvmInstallation": { + "properties": { + "release": { + "$ref": "#/$defs/JavaVMRelease" + }, + "files": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "release", + "files" + ] + }, + "JavaManifest": { + "properties": { + "main": { + "$ref": "#/$defs/KeyValues" + }, + "sections": { + "items": { + "$ref": "#/$defs/KeyValues" + }, + "type": "array" + } + }, + "type": "object" + }, + "JavaPomParent": { + "properties": { + "groupId": { + "type": "string" + }, + "artifactId": { + "type": "string" + }, + "version": { + "type": "string" + } + }, + "type": "object", + "required": [ + "groupId", + "artifactId", + "version" + ] + }, + "JavaPomProject": { + "properties": { + "path": { + "type": "string" + }, + "parent": { + "$ref": "#/$defs/JavaPomParent" + }, + "groupId": { + "type": "string" + }, + "artifactId": { + "type": "string" + }, + "version": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "type": "object", + "required": [ + "path", + "groupId", + "artifactId", + "version", + "name" + ] + }, + "JavaPomProperties": { + "properties": { + "path": { + "type": "string" + }, + "name": { + "type": "string" + }, + "groupId": { + "type": "string" + }, + "artifactId": { + "type": "string" + }, + "version": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "extraFields": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object", + "required": [ + "path", + "name", + "groupId", + "artifactId", + "version" + ] + }, + "JavaVMRelease": { + "properties": { + "implementor": { + "type": "string" + }, + "implementorVersion": { + "type": "string" + }, + "javaRuntimeVersion": { + "type": "string" + }, + "javaVersion": { + "type": "string" + }, + "javaVersionDate": { + "type": "string" + }, + "libc": { + "type": "string" + }, + "modules": { + "items": { + "type": "string" + }, + "type": "array" + }, + "osArch": { + "type": "string" + }, + "osName": { + "type": "string" + }, + "osVersion": { + "type": "string" + }, + "source": { + "type": "string" + }, + "buildSource": { + "type": "string" + }, + "buildSourceRepo": { + "type": "string" + }, + "sourceRepo": { + "type": "string" + }, + "fullVersion": { + "type": "string" + }, + "semanticVersion": { + "type": "string" + }, + "buildInfo": { + "type": "string" + }, + "jvmVariant": { + "type": "string" + }, + "jvmVersion": { + "type": "string" + }, + "imageType": { + "type": "string" + }, + "buildType": { + "type": "string" + } + }, + "type": "object" + }, + "JavascriptNpmPackage": { + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "author": { + "type": "string" + }, + "homepage": { + "type": "string" + }, + "description": { + "type": "string" + }, + "url": { + "type": "string" + }, + "private": { + "type": "boolean" + } + }, + "type": "object", + "required": [ + "name", + "version", + "author", + "homepage", + "description", + "url", + "private" + ] + }, + "JavascriptNpmPackageLockEntry": { + "properties": { + "resolved": { + "type": "string" + }, + "integrity": { + "type": "string" + } + }, + "type": "object", + "required": [ + "resolved", + "integrity" + ] + }, + "JavascriptYarnLockEntry": { + "properties": { + "resolved": { + "type": "string" + }, + "integrity": { + "type": "string" + } + }, + "type": "object", + "required": [ + "resolved", + "integrity" + ] + }, + "KeyValue": { + "properties": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object", + "required": [ + "key", + "value" + ] + }, + "KeyValues": { + "items": { + "$ref": "#/$defs/KeyValue" + }, + "type": "array" + }, + "License": { + "properties": { + "value": { + "type": "string" + }, + "spdxExpression": { + "type": "string" + }, + "type": { + "type": "string" + }, + "urls": { + "items": { + "type": "string" + }, + "type": "array" + }, + "locations": { + "items": { + "$ref": "#/$defs/Location" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "value", + "spdxExpression", + "type", + "urls", + "locations" + ] + }, + "LinuxKernelArchive": { + "properties": { + "name": { + "type": "string" + }, + "architecture": { + "type": "string" + }, + "version": { + "type": "string" + }, + "extendedVersion": { + "type": "string" + }, + "buildTime": { + "type": "string" + }, + "author": { + "type": "string" + }, + "format": { + "type": "string" + }, + "rwRootFS": { + "type": "boolean" + }, + "swapDevice": { + "type": "integer" + }, + "rootDevice": { + "type": "integer" + }, + "videoMode": { + "type": "string" + } + }, + "type": "object", + "required": [ + "name", + "architecture", + "version" + ] + }, + "LinuxKernelModule": { + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "sourceVersion": { + "type": "string" + }, + "path": { + "type": "string" + }, + "description": { + "type": "string" + }, + "author": { + "type": "string" + }, + "license": { + "type": "string" + }, + "kernelVersion": { + "type": "string" + }, + "versionMagic": { + "type": "string" + }, + "parameters": { + "patternProperties": { + ".*": { + "$ref": "#/$defs/LinuxKernelModuleParameter" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "LinuxKernelModuleParameter": { + "properties": { + "type": { + "type": "string" + }, + "description": { + "type": "string" + } + }, + "type": "object" + }, + "LinuxRelease": { + "properties": { + "prettyName": { + "type": "string" + }, + "name": { + "type": "string" + }, + "id": { + "type": "string" + }, + "idLike": { + "$ref": "#/$defs/IDLikes" + }, + "version": { + "type": "string" + }, + "versionID": { + "type": "string" + }, + "versionCodename": { + "type": "string" + }, + "buildID": { + "type": "string" + }, + "imageID": { + "type": "string" + }, + "imageVersion": { + "type": "string" + }, + "variant": { + "type": "string" + }, + "variantID": { + "type": "string" + }, + "homeURL": { + "type": "string" + }, + "supportURL": { + "type": "string" + }, + "bugReportURL": { + "type": "string" + }, + "privacyPolicyURL": { + "type": "string" + }, + "cpeName": { + "type": "string" + }, + "supportEnd": { + "type": "string" + } + }, + "type": "object" + }, + "Location": { + "properties": { + "path": { + "type": "string" + }, + "layerID": { + "type": "string" + }, + "accessPath": { + "type": "string" + }, + "annotations": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object", + "required": [ + "path", + "accessPath" + ] + }, + "LuarocksPackage": { + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "license": { + "type": "string" + }, + "homepage": { + "type": "string" + }, + "description": { + "type": "string" + }, + "url": { + "type": "string" + }, + "dependencies": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object", + "required": [ + "name", + "version", + "license", + "homepage", + "description", + "url", + "dependencies" + ] + }, + "MicrosoftKbPatch": { + "properties": { + "product_id": { + "type": "string" + }, + "kb": { + "type": "string" + } + }, + "type": "object", + "required": [ + "product_id", + "kb" + ] + }, + "NixStoreEntry": { + "properties": { + "outputHash": { + "type": "string" + }, + "output": { + "type": "string" + }, + "files": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "outputHash", + "files" + ] + }, + "OpamPackage": { + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "licenses": { + "items": { + "type": "string" + }, + "type": "array" + }, + "url": { + "type": "string" + }, + "checksum": { + "items": { + "type": "string" + }, + "type": "array" + }, + "homepage": { + "type": "string" + }, + "dependencies": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "name", + "version", + "licenses", + "url", + "checksum", + "homepage", + "dependencies" + ] + }, + "Package": { + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "type": { + "type": "string" + }, + "foundBy": { + "type": "string" + }, + "locations": { + "items": { + "$ref": "#/$defs/Location" + }, + "type": "array" + }, + "licenses": { + "$ref": "#/$defs/licenses" + }, + "language": { + "type": "string" + }, + "cpes": { + "$ref": "#/$defs/cpes" + }, + "purl": { + "type": "string" + }, + "metadataType": { + "type": "string" + }, + "metadata": { + "anyOf": [ + { + "type": "null" + }, + { + "$ref": "#/$defs/AlpmDbEntry" + }, + { + "$ref": "#/$defs/ApkDbEntry" + }, + { + "$ref": "#/$defs/BinarySignature" + }, + { + "$ref": "#/$defs/CConanFileEntry" + }, + { + "$ref": "#/$defs/CConanInfoEntry" + }, + { + "$ref": "#/$defs/CConanLockEntry" + }, + { + "$ref": "#/$defs/CConanLockV2Entry" + }, + { + "$ref": "#/$defs/CocoaPodfileLockEntry" + }, + { + "$ref": "#/$defs/DartPubspecLockEntry" + }, + { + "$ref": "#/$defs/DotnetDepsEntry" + }, + { + "$ref": "#/$defs/DotnetPortableExecutableEntry" + }, + { + "$ref": "#/$defs/DpkgDbEntry" + }, + { + "$ref": "#/$defs/ElfBinaryPackageNoteJsonPayload" + }, + { + "$ref": "#/$defs/ElixirMixLockEntry" + }, + { + "$ref": "#/$defs/ErlangRebarLockEntry" + }, + { + "$ref": "#/$defs/GoModuleBuildinfoEntry" + }, + { + "$ref": "#/$defs/GoModuleEntry" + }, + { + "$ref": "#/$defs/HaskellHackageStackEntry" + }, + { + "$ref": "#/$defs/HaskellHackageStackLockEntry" + }, + { + "$ref": "#/$defs/JavaArchive" + }, + { + "$ref": "#/$defs/JavaJvmInstallation" + }, + { + "$ref": "#/$defs/JavascriptNpmPackage" + }, + { + "$ref": "#/$defs/JavascriptNpmPackageLockEntry" + }, + { + "$ref": "#/$defs/JavascriptYarnLockEntry" + }, + { + "$ref": "#/$defs/LinuxKernelArchive" + }, + { + "$ref": "#/$defs/LinuxKernelModule" + }, + { + "$ref": "#/$defs/LuarocksPackage" + }, + { + "$ref": "#/$defs/MicrosoftKbPatch" + }, + { + "$ref": "#/$defs/NixStoreEntry" + }, + { + "$ref": "#/$defs/OpamPackage" + }, + { + "$ref": "#/$defs/PhpComposerInstalledEntry" + }, + { + "$ref": "#/$defs/PhpComposerLockEntry" + }, + { + "$ref": "#/$defs/PhpPeclEntry" + }, + { + "$ref": "#/$defs/PortageDbEntry" + }, + { + "$ref": "#/$defs/PythonPackage" + }, + { + "$ref": "#/$defs/PythonPipRequirementsEntry" + }, + { + "$ref": "#/$defs/PythonPipfileLockEntry" + }, + { + "$ref": "#/$defs/PythonPoetryLockEntry" + }, + { + "$ref": "#/$defs/RDescription" + }, + { + "$ref": "#/$defs/RpmArchive" + }, + { + "$ref": "#/$defs/RpmDbEntry" + }, + { + "$ref": "#/$defs/RubyGemspec" + }, + { + "$ref": "#/$defs/RustCargoAuditEntry" + }, + { + "$ref": "#/$defs/RustCargoLockEntry" + }, + { + "$ref": "#/$defs/SwiftPackageManagerLockEntry" + }, + { + "$ref": "#/$defs/SwiplpackPackage" + }, + { + "$ref": "#/$defs/TerraformLockEntry" + }, + { + "$ref": "#/$defs/WordpressPluginEntry" + } + ] + } + }, + "type": "object", + "required": [ + "id", + "name", + "version", + "type", + "foundBy", + "locations", + "licenses", + "language", + "cpes", + "purl" + ] + }, + "PhpComposerAuthors": { + "properties": { + "name": { + "type": "string" + }, + "email": { + "type": "string" + }, + "homepage": { + "type": "string" + } + }, + "type": "object", + "required": [ + "name" + ] + }, + "PhpComposerExternalReference": { + "properties": { + "type": { + "type": "string" + }, + "url": { + "type": "string" + }, + "reference": { + "type": "string" + }, + "shasum": { + "type": "string" + } + }, + "type": "object", + "required": [ + "type", + "url", + "reference" + ] + }, + "PhpComposerInstalledEntry": { + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "source": { + "$ref": "#/$defs/PhpComposerExternalReference" + }, + "dist": { + "$ref": "#/$defs/PhpComposerExternalReference" + }, + "require": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + }, + "provide": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + }, + "require-dev": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + }, + "suggest": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + }, + "license": { + "items": { + "type": "string" + }, + "type": "array" + }, + "type": { + "type": "string" + }, + "notification-url": { + "type": "string" + }, + "bin": { + "items": { + "type": "string" + }, + "type": "array" + }, + "authors": { + "items": { + "$ref": "#/$defs/PhpComposerAuthors" + }, + "type": "array" + }, + "description": { + "type": "string" + }, + "homepage": { + "type": "string" + }, + "keywords": { + "items": { + "type": "string" + }, + "type": "array" + }, + "time": { + "type": "string" + } + }, + "type": "object", + "required": [ + "name", + "version", + "source", + "dist" + ] + }, + "PhpComposerLockEntry": { + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "source": { + "$ref": "#/$defs/PhpComposerExternalReference" + }, + "dist": { + "$ref": "#/$defs/PhpComposerExternalReference" + }, + "require": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + }, + "provide": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + }, + "require-dev": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + }, + "suggest": { + "patternProperties": { + ".*": { + "type": "string" + } + }, + "type": "object" + }, + "license": { + "items": { + "type": "string" + }, + "type": "array" + }, + "type": { + "type": "string" + }, + "notification-url": { + "type": "string" + }, + "bin": { + "items": { + "type": "string" + }, + "type": "array" + }, + "authors": { + "items": { + "$ref": "#/$defs/PhpComposerAuthors" + }, + "type": "array" + }, + "description": { + "type": "string" + }, + "homepage": { + "type": "string" + }, + "keywords": { + "items": { + "type": "string" + }, + "type": "array" + }, + "time": { + "type": "string" + } + }, + "type": "object", + "required": [ + "name", + "version", + "source", + "dist" + ] + }, + "PhpPeclEntry": { + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "license": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "name", + "version" + ] + }, + "PortageDbEntry": { + "properties": { + "installedSize": { + "type": "integer" + }, + "files": { + "items": { + "$ref": "#/$defs/PortageFileRecord" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "installedSize", + "files" + ] + }, + "PortageFileRecord": { + "properties": { + "path": { + "type": "string" + }, + "digest": { + "$ref": "#/$defs/Digest" + } + }, + "type": "object", + "required": [ + "path" + ] + }, + "PythonDirectURLOriginInfo": { + "properties": { + "url": { + "type": "string" + }, + "commitId": { + "type": "string" + }, + "vcs": { + "type": "string" + } + }, + "type": "object", + "required": [ + "url" + ] + }, + "PythonFileDigest": { + "properties": { + "algorithm": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object", + "required": [ + "algorithm", + "value" + ] + }, + "PythonFileRecord": { + "properties": { + "path": { + "type": "string" + }, + "digest": { + "$ref": "#/$defs/PythonFileDigest" + }, + "size": { + "type": "string" + } + }, + "type": "object", + "required": [ + "path" + ] + }, + "PythonPackage": { + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "author": { + "type": "string" + }, + "authorEmail": { + "type": "string" + }, + "platform": { + "type": "string" + }, + "files": { + "items": { + "$ref": "#/$defs/PythonFileRecord" + }, + "type": "array" + }, + "sitePackagesRootPath": { + "type": "string" + }, + "topLevelPackages": { + "items": { + "type": "string" + }, + "type": "array" + }, + "directUrlOrigin": { + "$ref": "#/$defs/PythonDirectURLOriginInfo" + }, + "requiresPython": { + "type": "string" + }, + "requiresDist": { + "items": { + "type": "string" + }, + "type": "array" + }, + "providesExtra": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "name", + "version", + "author", + "authorEmail", + "platform", + "sitePackagesRootPath" + ] + }, + "PythonPipRequirementsEntry": { + "properties": { + "name": { + "type": "string" + }, + "extras": { + "items": { + "type": "string" + }, + "type": "array" + }, + "versionConstraint": { + "type": "string" + }, + "url": { + "type": "string" + }, + "markers": { + "type": "string" + } + }, + "type": "object", + "required": [ + "name", + "versionConstraint" + ] + }, + "PythonPipfileLockEntry": { + "properties": { + "hashes": { + "items": { + "type": "string" + }, + "type": "array" + }, + "index": { + "type": "string" + } + }, + "type": "object", + "required": [ + "hashes", + "index" + ] + }, + "PythonPoetryLockDependencyEntry": { + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "optional": { + "type": "boolean" + }, + "markers": { + "type": "string" + }, + "extras": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "name", + "version", + "optional" + ] + }, + "PythonPoetryLockEntry": { + "properties": { + "index": { + "type": "string" + }, + "dependencies": { + "items": { + "$ref": "#/$defs/PythonPoetryLockDependencyEntry" + }, + "type": "array" + }, + "extras": { + "items": { + "$ref": "#/$defs/PythonPoetryLockExtraEntry" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "index", + "dependencies" + ] + }, + "PythonPoetryLockExtraEntry": { + "properties": { + "name": { + "type": "string" + }, + "dependencies": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "name", + "dependencies" + ] + }, + "RDescription": { + "properties": { + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "author": { + "type": "string" + }, + "maintainer": { + "type": "string" + }, + "url": { + "items": { + "type": "string" + }, + "type": "array" + }, + "repository": { + "type": "string" + }, + "built": { + "type": "string" + }, + "needsCompilation": { + "type": "boolean" + }, + "imports": { + "items": { + "type": "string" + }, + "type": "array" + }, + "depends": { + "items": { + "type": "string" + }, + "type": "array" + }, + "suggests": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "Relationship": { + "properties": { + "parent": { + "type": "string" + }, + "child": { + "type": "string" + }, + "type": { + "type": "string" + }, + "metadata": true + }, + "type": "object", + "required": [ + "parent", + "child", + "type" + ] + }, + "RpmArchive": { + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "epoch": { + "oneOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ] + }, + "architecture": { + "type": "string" + }, + "release": { + "type": "string" + }, + "sourceRpm": { + "type": "string" + }, + "size": { + "type": "integer" + }, + "vendor": { + "type": "string" + }, + "modularityLabel": { + "type": "string" + }, + "provides": { + "items": { + "type": "string" + }, + "type": "array" + }, + "requires": { + "items": { + "type": "string" + }, + "type": "array" + }, + "files": { + "items": { + "$ref": "#/$defs/RpmFileRecord" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "name", + "version", + "epoch", + "architecture", + "release", + "sourceRpm", + "size", + "vendor", + "files" + ] + }, + "RpmDbEntry": { + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "epoch": { + "oneOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ] + }, + "architecture": { + "type": "string" + }, + "release": { + "type": "string" + }, + "sourceRpm": { + "type": "string" + }, + "size": { + "type": "integer" + }, + "vendor": { + "type": "string" + }, + "modularityLabel": { + "type": "string" + }, + "provides": { + "items": { + "type": "string" + }, + "type": "array" + }, + "requires": { + "items": { + "type": "string" + }, + "type": "array" + }, + "files": { + "items": { + "$ref": "#/$defs/RpmFileRecord" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "name", + "version", + "epoch", + "architecture", + "release", + "sourceRpm", + "size", + "vendor", + "files" + ] + }, + "RpmFileRecord": { + "properties": { + "path": { + "type": "string" + }, + "mode": { + "type": "integer" + }, + "size": { + "type": "integer" + }, + "digest": { + "$ref": "#/$defs/Digest" + }, + "userName": { + "type": "string" + }, + "groupName": { + "type": "string" + }, + "flags": { + "type": "string" + } + }, + "type": "object", + "required": [ + "path", + "mode", + "size", + "digest", + "userName", + "groupName", + "flags" + ] + }, + "RubyGemspec": { + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "files": { + "items": { + "type": "string" + }, + "type": "array" + }, + "authors": { + "items": { + "type": "string" + }, + "type": "array" + }, + "homepage": { + "type": "string" + } + }, + "type": "object", + "required": [ + "name", + "version" + ] + }, + "RustCargoAuditEntry": { + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "source": { + "type": "string" + } + }, + "type": "object", + "required": [ + "name", + "version", + "source" + ] + }, + "RustCargoLockEntry": { + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "source": { + "type": "string" + }, + "checksum": { + "type": "string" + }, + "dependencies": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "name", + "version", + "source", + "checksum", + "dependencies" + ] + }, + "Schema": { + "properties": { + "version": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "type": "object", + "required": [ + "version", + "url" + ] + }, + "Source": { + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "type": { + "type": "string" + }, + "metadata": true + }, + "type": "object", + "required": [ + "id", + "name", + "version", + "type", + "metadata" + ] + }, + "SwiftPackageManagerLockEntry": { + "properties": { + "revision": { + "type": "string" + } + }, + "type": "object", + "required": [ + "revision" + ] + }, + "SwiplpackPackage": { + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "author": { + "type": "string" + }, + "authorEmail": { + "type": "string" + }, + "packager": { + "type": "string" + }, + "packagerEmail": { + "type": "string" + }, + "homepage": { + "type": "string" + }, + "dependencies": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "name", + "version", + "author", + "authorEmail", + "packager", + "packagerEmail", + "homepage", + "dependencies" + ] + }, + "TerraformLockEntry": { + "properties": { + "url": { + "type": "string" + }, + "constraints": { + "type": "string" + }, + "version": { + "type": "string" + }, + "hashes": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "url", + "constraints", + "version", + "hashes" + ] + }, + "WordpressPluginEntry": { + "properties": { + "pluginInstallDirectory": { + "type": "string" + }, + "author": { + "type": "string" + }, + "authorUri": { + "type": "string" + } + }, + "type": "object", + "required": [ + "pluginInstallDirectory" + ] + }, + "cpes": { + "items": { + "$ref": "#/$defs/CPE" + }, + "type": "array" + }, + "licenses": { + "items": { + "$ref": "#/$defs/License" + }, + "type": "array" + } + } +} diff --git a/schema/json/schema-latest.json b/schema/json/schema-latest.json index 936582e2d22..33514a1cc76 100644 --- a/schema/json/schema-latest.json +++ b/schema/json/schema-latest.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "anchore.io/schema/syft/json/16.0.18/document", + "$id": "anchore.io/schema/syft/json/16.0.19/document", "$ref": "#/$defs/Document", "$defs": { "AlpmDbEntry": { @@ -1756,6 +1756,9 @@ { "$ref": "#/$defs/SwiplpackPackage" }, + { + "$ref": "#/$defs/TerraformLockEntry" + }, { "$ref": "#/$defs/WordpressPluginEntry" } @@ -2694,6 +2697,32 @@ "dependencies" ] }, + "TerraformLockEntry": { + "properties": { + "url": { + "type": "string" + }, + "constraints": { + "type": "string" + }, + "version": { + "type": "string" + }, + "hashes": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object", + "required": [ + "url", + "constraints", + "version", + "hashes" + ] + }, "WordpressPluginEntry": { "properties": { "pluginInstallDirectory": { diff --git a/syft/format/internal/spdxutil/helpers/originator_supplier_test.go b/syft/format/internal/spdxutil/helpers/originator_supplier_test.go index 4ed8fc2ca7f..3979b79fc2c 100644 --- a/syft/format/internal/spdxutil/helpers/originator_supplier_test.go +++ b/syft/format/internal/spdxutil/helpers/originator_supplier_test.go @@ -371,6 +371,14 @@ func Test_OriginatorSupplier(t *testing.T) { originator: "", supplier: "", }, + { + name: "from terraform lock", + input: pkg.Package{ + Metadata: pkg.TerraformLockEntry{}, + }, + originator: "", + supplier: "", + }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { diff --git a/syft/internal/packagemetadata/generated.go b/syft/internal/packagemetadata/generated.go index d22cfcd77b8..f4734968ff3 100644 --- a/syft/internal/packagemetadata/generated.go +++ b/syft/internal/packagemetadata/generated.go @@ -52,6 +52,7 @@ func AllTypes() []any { pkg.RustCargoLockEntry{}, pkg.SwiftPackageManagerResolvedEntry{}, pkg.SwiplPackEntry{}, + pkg.TerraformLockEntry{}, pkg.WordpressPluginEntry{}, pkg.YarnLockEntry{}, } diff --git a/syft/internal/packagemetadata/names.go b/syft/internal/packagemetadata/names.go index b382dceebe7..9a4d42adbcd 100644 --- a/syft/internal/packagemetadata/names.go +++ b/syft/internal/packagemetadata/names.go @@ -109,6 +109,7 @@ var jsonTypes = makeJSONTypes( jsonNamesWithoutLookup(pkg.RustBinaryAuditEntry{}, "rust-cargo-audit-entry", "RustCargoPackageMetadata"), // the legacy value is split into two types, where the other is preferred jsonNames(pkg.WordpressPluginEntry{}, "wordpress-plugin-entry", "WordpressMetadata"), jsonNames(pkg.LuaRocksPackage{}, "luarocks-package"), + jsonNames(pkg.TerraformLockEntry{}, "terraform-lock-entry", "TerraformMetadata"), ) func expandLegacyNameVariants(names ...string) []string { diff --git a/syft/pkg/cataloger/terraform/cataloger_test.go b/syft/pkg/cataloger/terraform/cataloger_test.go index 7fc1d44161c..695c578fc33 100644 --- a/syft/pkg/cataloger/terraform/cataloger_test.go +++ b/syft/pkg/cataloger/terraform/cataloger_test.go @@ -23,10 +23,27 @@ func TestTerraformCataloger(t *testing.T) { Locations: file.NewLocationSet(location), Type: pkg.TerraformPkg, PURL: "pkg:terraform/registry.terraform.io/hashicorp/aws@5.72.1", - Metadata: []pkg.KeyValue{ - { - Key: "constraints", - Value: "5.72.1", + Metadata: pkg.TerraformLockEntry{ + URL: "registry.terraform.io/hashicorp/aws", + Version: "5.72.1", + Constraints: "> 5.72.0", + Hashes: []string{ + "h1:jhd5O5o0CfZCNEwwN0EiDAzb7ApuFrtxJqa6HXW4EKE=", + "zh:0dea6843836e926d33469b48b948744079023816d16a2ff7666bcfb6aa3522d4", + "zh:195fa9513f75800a0d62797ebec75ee73e9b8c28d713fe9b63d3b1d1eec129b3", + "zh:1ed92f3961715bf0e024bcde3c12dfbdc50b00c1f8a43cc00802cfc45a256208", + "zh:2ac687e3a52606466cae4a6813e81d923042488df88d2424e28d3f8530f091bb", + "zh:32e7ca75f9314557daada3c44628fe1f3bf964a4f833bfb4b2295d833fe64b6f", + "zh:374ee0e6b4327cc6ef666908ce5d6450a3a56e90cd2b785e83c2bcfc100021d2", + "zh:5500fd6fdac44f96411fcf9c6d01691159ec35455ed127eb4c3a498e1cc92a64", + "zh:723a2dc4b064c12e7ee62ad4fbfd72fa5e025206ea47b735994ef53f3c373152", + "zh:89d97b87605f1d734f27e642567cbecf785b521af8ea81dac55c77ccde876221", + "zh:951ee1e5731e8d65d521d71b95927e55055b3c4656eef6d46fa580a63328befc", + "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", + "zh:9b2b362470b64ec227b2da64762ab8bc4111c6b80365fd9d82fc5e1e33f44038", + "zh:aa6e57d0cb974ff0da5dee5d43ad2745cbbc4a2b507d4c799839b9fa96daf688", + "zh:ba0d14c4a6b7aa844a830d47c0bf995b632e37f0795394b5b60c638b62b7fc03", + "zh:c9764065a9c5d324db0b02bd201b9e3a2118e49c4960884acdeea377173302e9", }, }, } @@ -39,10 +56,24 @@ func TestTerraformCataloger(t *testing.T) { Locations: file.NewLocationSet(location), Type: pkg.TerraformPkg, PURL: "pkg:terraform/registry.terraform.io/hashicorp/google@6.8.0", - Metadata: []pkg.KeyValue{ - { - Key: "constraints", - Value: "6.8.0", + Metadata: pkg.TerraformLockEntry{ + URL: "registry.terraform.io/hashicorp/google", + Version: "6.8.0", + Constraints: "6.8.0", + Hashes: []string{ + "h1:GlCaVPk6eKMg2ZbRY7C5tUeHGNIABT+qFtMl8+XWZHM=", + "zh:1b78f4451f1617092eb6891c9c13eda79671060601c40947feea6794c732157a", + "zh:4c6d7231ce32c6ff2a98218ef363c133d27d423b009354e7fe18459d9feb41d4", + "zh:6ae0112e9c733ab6c72436a334ffe3f197a613bb04f49538462b83b236d37a2d", + "zh:8bd5651838ad674e0a173a453b76c80b94d08ebcb8ea0b6263ce6da0599b42f5", + "zh:94ee7bcd77b0b7c2777113e35282da014e61e813fe46c058a49bf3d616fecdf4", + "zh:c0bf014422c2971985d34ad45ddb6aa737373398f83b325884ea5608ac1264aa", + "zh:c2cbbf0c249c3d1842ad0ad77fb7ef85bd3e92c688618c4087173bc1d69cd098", + "zh:cefa3e06cb353d08b83dafa6135cd78e17540ae735b7c5687833cc1925c3fd8e", + "zh:d20bc0216bf7f054f6318467d3902ced05e9f0bfa500ee55bf43b1b41ef0b854", + "zh:e54ad5959e53b9e9acafc243d6f4039ab5005cec32c7435a122da964888d184c", + "zh:e833c8de147268b3ffc14c60915eccb9347ade5f25b37b3771240a4d68b6aac4", + "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", }, }, } diff --git a/syft/pkg/cataloger/terraform/parse_tf_lock.go b/syft/pkg/cataloger/terraform/parse_tf_lock.go index 9719563ae69..a5c7832c4b1 100644 --- a/syft/pkg/cataloger/terraform/parse_tf_lock.go +++ b/syft/pkg/cataloger/terraform/parse_tf_lock.go @@ -14,17 +14,12 @@ import ( "github.com/anchore/syft/syft/pkg/cataloger/generic" ) -type lockFile struct { - Providers []struct { - URL string `hcl:",label"` - Constraints string `hcl:"constraints"` - Version string `hcl:"version"` - Hashes []string `hcl:"hashes"` - } `hcl:"provider,block"` +type terraformLockFile struct { + Providers []pkg.TerraformLockEntry `hcl:"provider,block"` } func parseTerraformLock(_ context.Context, _ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) { - var lockFile lockFile + var lockFile terraformLockFile contents, err := io.ReadAll(reader) if err != nil { @@ -44,17 +39,12 @@ func parseTerraformLock(_ context.Context, _ file.Resolver, _ *generic.Environme Version: provider.Version, FoundBy: "terraform-cataloger", Locations: file.NewLocationSet(reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)), - //Licenses: nil, - //Language: nil, + Licenses: pkg.NewLicenseSet(), // TODO: license could be found in .terraform/providers/${name}/${version}/${arch}/LICENSE.txt + // TODO: Language? Type: pkg.TerraformPkg, - //CPEs: nil, - PURL: packageurl.NewPackageURL(packageurl.TypeTerraform, "", provider.URL, provider.Version, nil, "").String(), - Metadata: []pkg.KeyValue{ - { - Key: "constraints", - Value: provider.Constraints, - }, - }, + // TODO: CPEs? + PURL: packageurl.NewPackageURL(packageurl.TypeTerraform, "", provider.URL, provider.Version, nil, "").String(), + Metadata: provider, } pkg.SetID() diff --git a/syft/pkg/cataloger/terraform/test-fixtures/two-providers/.terraform.lock.hcl b/syft/pkg/cataloger/terraform/test-fixtures/two-providers/.terraform.lock.hcl index 6c92fa85ff2..2f1ac3894e8 100644 --- a/syft/pkg/cataloger/terraform/test-fixtures/two-providers/.terraform.lock.hcl +++ b/syft/pkg/cataloger/terraform/test-fixtures/two-providers/.terraform.lock.hcl @@ -3,7 +3,7 @@ provider "registry.terraform.io/hashicorp/aws" { version = "5.72.1" - constraints = "5.72.1" + constraints = "> 5.72.0" hashes = [ "h1:jhd5O5o0CfZCNEwwN0EiDAzb7ApuFrtxJqa6HXW4EKE=", "zh:0dea6843836e926d33469b48b948744079023816d16a2ff7666bcfb6aa3522d4", diff --git a/syft/pkg/terraform.go b/syft/pkg/terraform.go new file mode 100644 index 00000000000..9e4b1b9db1e --- /dev/null +++ b/syft/pkg/terraform.go @@ -0,0 +1,9 @@ +package pkg + +// TerraformLockEntry represents a single entry in a Terraform dependency lock file (.terraform.lock.hcl). +type TerraformLockEntry struct { + URL string `hcl:",label" json:"url"` + Constraints string `hcl:"constraints" json:"constraints"` + Version string `hcl:"version" json:"version"` + Hashes []string `hcl:"hashes" json:"hashes"` +} From 2c97d5de47f3f213a2fd27adb1924a1632bb809b Mon Sep 17 00:00:00 2001 From: Alex Goodman Date: Tue, 12 Nov 2024 09:47:15 -0500 Subject: [PATCH 5/6] minor review adjustments Signed-off-by: Alex Goodman --- go.mod | 2 +- internal/task/package_tasks.go | 2 +- syft/internal/packagemetadata/names.go | 2 +- syft/pkg/cataloger/terraform/cataloger.go | 7 ++--- .../pkg/cataloger/terraform/cataloger_test.go | 6 ++-- syft/pkg/cataloger/terraform/parse_tf_lock.go | 9 +++--- syft/pkg/type.go | 28 +++++++++---------- 7 files changed, 27 insertions(+), 29 deletions(-) diff --git a/go.mod b/go.mod index d104b003989..d7f4b3aabf9 100644 --- a/go.mod +++ b/go.mod @@ -89,8 +89,8 @@ require google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirec require ( github.com/BurntSushi/toml v1.4.0 github.com/OneOfOne/xxhash v1.2.8 - github.com/hashicorp/hcl/v2 v2.22.0 github.com/adrg/xdg v0.5.3 + github.com/hashicorp/hcl/v2 v2.22.0 github.com/magiconair/properties v1.8.7 golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 ) diff --git a/internal/task/package_tasks.go b/internal/task/package_tasks.go index cb5b69f57bf..35442e145a2 100644 --- a/internal/task/package_tasks.go +++ b/internal/task/package_tasks.go @@ -152,6 +152,6 @@ func DefaultPackageTaskFactories() PackageTaskFactories { ), newSimplePackageTaskFactory(sbomCataloger.NewCataloger, "sbom"), // note: not evidence of installed packages newSimplePackageTaskFactory(wordpress.NewWordpressPluginCataloger, pkgcataloging.DirectoryTag, pkgcataloging.ImageTag, "wordpress"), - newSimplePackageTaskFactory(terraform.NewTerraformCataloger, pkgcataloging.DirectoryTag, "terraform"), + newSimplePackageTaskFactory(terraform.NewLockCataloger, pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, "terraform"), } } diff --git a/syft/internal/packagemetadata/names.go b/syft/internal/packagemetadata/names.go index 9a4d42adbcd..7f433ab12dc 100644 --- a/syft/internal/packagemetadata/names.go +++ b/syft/internal/packagemetadata/names.go @@ -109,7 +109,7 @@ var jsonTypes = makeJSONTypes( jsonNamesWithoutLookup(pkg.RustBinaryAuditEntry{}, "rust-cargo-audit-entry", "RustCargoPackageMetadata"), // the legacy value is split into two types, where the other is preferred jsonNames(pkg.WordpressPluginEntry{}, "wordpress-plugin-entry", "WordpressMetadata"), jsonNames(pkg.LuaRocksPackage{}, "luarocks-package"), - jsonNames(pkg.TerraformLockEntry{}, "terraform-lock-entry", "TerraformMetadata"), + jsonNames(pkg.TerraformLockEntry{}, "terraform-lock-entry"), ) func expandLegacyNameVariants(names ...string) []string { diff --git a/syft/pkg/cataloger/terraform/cataloger.go b/syft/pkg/cataloger/terraform/cataloger.go index efdd0940c02..893c0b54a57 100644 --- a/syft/pkg/cataloger/terraform/cataloger.go +++ b/syft/pkg/cataloger/terraform/cataloger.go @@ -5,8 +5,7 @@ import ( "github.com/anchore/syft/syft/pkg/cataloger/generic" ) -func NewTerraformCataloger() pkg.Cataloger { - return generic.NewCataloger("terraform-cataloger"). - WithParserByGlobs(parseTerraformLock, "**/.terraform.lock.hcl"). - WithProcessors() +func NewLockCataloger() pkg.Cataloger { + return generic.NewCataloger("terraform-lock-cataloger"). + WithParserByGlobs(parseTerraformLock, "**/.terraform.lock.hcl") } diff --git a/syft/pkg/cataloger/terraform/cataloger_test.go b/syft/pkg/cataloger/terraform/cataloger_test.go index 695c578fc33..dda41bdd7fa 100644 --- a/syft/pkg/cataloger/terraform/cataloger_test.go +++ b/syft/pkg/cataloger/terraform/cataloger_test.go @@ -11,7 +11,7 @@ import ( ) func TestTerraformCataloger(t *testing.T) { - c := NewTerraformCataloger() + c := NewLockCataloger() fileLoc := file.NewLocation(".terraform.lock.hcl") location := fileLoc.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation) @@ -19,7 +19,7 @@ func TestTerraformCataloger(t *testing.T) { awsProviderPkg := pkg.Package{ Name: "registry.terraform.io/hashicorp/aws", Version: "5.72.1", - FoundBy: "terraform-cataloger", + FoundBy: "terraform-lock-cataloger", Locations: file.NewLocationSet(location), Type: pkg.TerraformPkg, PURL: "pkg:terraform/registry.terraform.io/hashicorp/aws@5.72.1", @@ -52,7 +52,7 @@ func TestTerraformCataloger(t *testing.T) { gcpProviderPkg := pkg.Package{ Name: "registry.terraform.io/hashicorp/google", Version: "6.8.0", - FoundBy: "terraform-cataloger", + FoundBy: "terraform-lock-cataloger", Locations: file.NewLocationSet(location), Type: pkg.TerraformPkg, PURL: "pkg:terraform/registry.terraform.io/hashicorp/google@6.8.0", diff --git a/syft/pkg/cataloger/terraform/parse_tf_lock.go b/syft/pkg/cataloger/terraform/parse_tf_lock.go index a5c7832c4b1..1976fd978f1 100644 --- a/syft/pkg/cataloger/terraform/parse_tf_lock.go +++ b/syft/pkg/cataloger/terraform/parse_tf_lock.go @@ -5,9 +5,9 @@ import ( "fmt" "io" - "github.com/anchore/packageurl-go" "github.com/hashicorp/hcl/v2/hclsimple" + "github.com/anchore/packageurl-go" "github.com/anchore/syft/syft/artifact" "github.com/anchore/syft/syft/file" "github.com/anchore/syft/syft/pkg" @@ -34,10 +34,9 @@ func parseTerraformLock(_ context.Context, _ file.Resolver, _ *generic.Environme pkgs := make([]pkg.Package, 0, len(lockFile.Providers)) for _, provider := range lockFile.Providers { - pkg := pkg.Package{ + p := pkg.Package{ Name: provider.URL, Version: provider.Version, - FoundBy: "terraform-cataloger", Locations: file.NewLocationSet(reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)), Licenses: pkg.NewLicenseSet(), // TODO: license could be found in .terraform/providers/${name}/${version}/${arch}/LICENSE.txt // TODO: Language? @@ -46,9 +45,9 @@ func parseTerraformLock(_ context.Context, _ file.Resolver, _ *generic.Environme PURL: packageurl.NewPackageURL(packageurl.TypeTerraform, "", provider.URL, provider.Version, nil, "").String(), Metadata: provider, } - pkg.SetID() + p.SetID() - pkgs = append(pkgs, pkg) + pkgs = append(pkgs, p) } return pkgs, nil, nil diff --git a/syft/pkg/type.go b/syft/pkg/type.go index 54da790fab8..27b6c773eea 100644 --- a/syft/pkg/type.go +++ b/syft/pkg/type.go @@ -33,6 +33,7 @@ const ( LinuxKernelModulePkg Type = "linux-kernel-module" NixPkg Type = "nix" NpmPkg Type = "npm" + OpamPkg Type = "opam" PhpComposerPkg Type = "php-composer" PhpPeclPkg Type = "php-pecl" PortagePkg Type = "portage" @@ -43,9 +44,8 @@ const ( RustPkg Type = "rust-crate" SwiftPkg Type = "swift" SwiplPackPkg Type = "swiplpack" - OpamPkg Type = "opam" - WordpressPluginPkg Type = "wordpress-plugin" TerraformPkg Type = "terraform" + WordpressPluginPkg Type = "wordpress-plugin" ) // AllPkgs represents all supported package types @@ -72,6 +72,7 @@ var AllPkgs = []Type{ LinuxKernelModulePkg, NixPkg, NpmPkg, + OpamPkg, PhpComposerPkg, PhpPeclPkg, PortagePkg, @@ -82,9 +83,8 @@ var AllPkgs = []Type{ RustPkg, SwiftPkg, SwiplPackPkg, - OpamPkg, - WordpressPluginPkg, TerraformPkg, + WordpressPluginPkg, } // PackageURLType returns the PURL package type for the current package. @@ -133,14 +133,16 @@ func (t Type) PackageURLType() string { return packageurl.TypePyPi case PortagePkg: return "portage" + case LuaRocksPkg: + return packageurl.TypeLuaRocks case NixPkg: return "nix" case NpmPkg: return packageurl.TypeNPM + case OpamPkg: + return "opam" case Rpkg: return packageurl.TypeCran - case LuaRocksPkg: - return packageurl.TypeLuaRocks case RpmPkg: return packageurl.TypeRPM case RustPkg: @@ -149,12 +151,10 @@ func (t Type) PackageURLType() string { return packageurl.TypeSwift case SwiplPackPkg: return "swiplpack" - case OpamPkg: - return "opam" - case WordpressPluginPkg: - return "wordpress-plugin" case TerraformPkg: return "terraform" + case WordpressPluginPkg: + return "wordpress-plugin" default: // TODO: should this be a "generic" purl type instead? return "" @@ -225,18 +225,18 @@ func TypeByName(name string) Type { return LinuxKernelModulePkg case "nix": return NixPkg + case "opam": + return OpamPkg case packageurl.TypeCran: return Rpkg case packageurl.TypeSwift: return SwiftPkg case "swiplpack": return SwiplPackPkg - case "opam": - return OpamPkg - case "wordpress-plugin": - return WordpressPluginPkg case "terraform": return TerraformPkg + case "wordpress-plugin": + return WordpressPluginPkg default: return UnknownPkg } From 4483e79fc197cdf7ffc84f0a0d1a4f91e13247b9 Mon Sep 17 00:00:00 2001 From: Thomas Gosteli Date: Wed, 13 Nov 2024 15:53:40 +0100 Subject: [PATCH 6/6] resolve language/CPE TODOs --- .../test/integration/catalog_packages_cases_test.go | 5 +++-- syft/pkg/cataloger/terraform/cataloger_test.go | 2 ++ syft/pkg/cataloger/terraform/parse_tf_lock.go | 9 ++++----- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/cmd/syft/internal/test/integration/catalog_packages_cases_test.go b/cmd/syft/internal/test/integration/catalog_packages_cases_test.go index 2a68de19fc3..09dbd8bf385 100644 --- a/cmd/syft/internal/test/integration/catalog_packages_cases_test.go +++ b/cmd/syft/internal/test/integration/catalog_packages_cases_test.go @@ -419,8 +419,9 @@ var dirOnlyTestCases = []testCase{ }, }, { - name: "find terraform packages", - pkgType: pkg.TerraformPkg, + name: "find terraform packages", + pkgType: pkg.TerraformPkg, + pkgLanguage: pkg.Go, pkgInfo: map[string]string{ "registry.terraform.io/hashicorp/aws": "5.72.1", }, diff --git a/syft/pkg/cataloger/terraform/cataloger_test.go b/syft/pkg/cataloger/terraform/cataloger_test.go index dda41bdd7fa..1a03f489369 100644 --- a/syft/pkg/cataloger/terraform/cataloger_test.go +++ b/syft/pkg/cataloger/terraform/cataloger_test.go @@ -22,6 +22,7 @@ func TestTerraformCataloger(t *testing.T) { FoundBy: "terraform-lock-cataloger", Locations: file.NewLocationSet(location), Type: pkg.TerraformPkg, + Language: pkg.Go, PURL: "pkg:terraform/registry.terraform.io/hashicorp/aws@5.72.1", Metadata: pkg.TerraformLockEntry{ URL: "registry.terraform.io/hashicorp/aws", @@ -55,6 +56,7 @@ func TestTerraformCataloger(t *testing.T) { FoundBy: "terraform-lock-cataloger", Locations: file.NewLocationSet(location), Type: pkg.TerraformPkg, + Language: pkg.Go, PURL: "pkg:terraform/registry.terraform.io/hashicorp/google@6.8.0", Metadata: pkg.TerraformLockEntry{ URL: "registry.terraform.io/hashicorp/google", diff --git a/syft/pkg/cataloger/terraform/parse_tf_lock.go b/syft/pkg/cataloger/terraform/parse_tf_lock.go index 1976fd978f1..cde3ac9907d 100644 --- a/syft/pkg/cataloger/terraform/parse_tf_lock.go +++ b/syft/pkg/cataloger/terraform/parse_tf_lock.go @@ -39,11 +39,10 @@ func parseTerraformLock(_ context.Context, _ file.Resolver, _ *generic.Environme Version: provider.Version, Locations: file.NewLocationSet(reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)), Licenses: pkg.NewLicenseSet(), // TODO: license could be found in .terraform/providers/${name}/${version}/${arch}/LICENSE.txt - // TODO: Language? - Type: pkg.TerraformPkg, - // TODO: CPEs? - PURL: packageurl.NewPackageURL(packageurl.TypeTerraform, "", provider.URL, provider.Version, nil, "").String(), - Metadata: provider, + Language: pkg.Go, + Type: pkg.TerraformPkg, + PURL: packageurl.NewPackageURL(packageurl.TypeTerraform, "", provider.URL, provider.Version, nil, "").String(), + Metadata: provider, } p.SetID()