Files
syft/syft/pkg/cataloger/internal/cpegenerate/terraform.go
T
Tim Olshansky 551442b1bc fix(terraform): generate NVD-style terraform_provider CPEs for terraform lock packages (#5261)
* fix: generate terraform-provider-specific CPEs for terraform lock packages

The terraform-lock-cataloger sets Language to Go, which causes the Go CPE
heuristic to generate application-level CPEs for terraform providers. For
example, registry.terraform.io/grafana/grafana produces the same CPE as
the Grafana application itself, leading grype to flag providers with
unrelated CVEs.

This adds terraform-specific vendor/product candidate functions that
generate CPEs matching the NVD convention for terraform providers
(e.g. terraform-provider-grafana instead of grafana), with terraform
as the target software qualifier.

Signed-off-by: Tim Olshansky <456103+timols@users.noreply.github.com>

* fix: align terraform provider CPEs with NVD terraform_provider convention

NVD records terraform providers with a fixed "terraform_provider" product
and the provider type in target_sw, e.g.
cpe:2.3:a:hashicorp:terraform_provider:*:*:*:*:*:vault:*:*

Generate <namespace>:terraform_provider:<version>:...:<type> instead of
<namespace>:terraform-provider-<type>:<version>:...:terraform, which never
appears in NVD.

Signed-off-by: Tim Olshansky <456103+timols@users.noreply.github.com>

---------

Signed-off-by: Tim Olshansky <456103+timols@users.noreply.github.com>
2026-11-03 22:01:20 -05:00

57 lines
1.5 KiB
Go

package cpegenerate
import (
"strings"
"github.com/anchore/syft/syft/cpe"
"github.com/anchore/syft/syft/pkg"
)
// NVD records terraform providers with a fixed "terraform_provider" product and the provider type in target_sw, e.g.
// cpe:2.3:a:hashicorp:terraform_provider:*:*:*:*:*:vault:*:*
const terraformProviderProduct = "terraform_provider"
func candidateVendorsForTerraformProvider(p pkg.Package) fieldCandidateSet {
vendors := newFieldCandidateSet()
namespace, _ := parseTerraformProviderName(p.Name)
if namespace != "" {
vendors.addValue(namespace)
}
return vendors
}
func candidateProductsForTerraformProvider(p pkg.Package) fieldCandidateSet {
products := newFieldCandidateSet()
_, providerType := parseTerraformProviderName(p.Name)
if providerType != "" {
products.add(fieldCandidate{
value: terraformProviderProduct,
disallowSubSelections: true,
disallowDelimiterVariations: true,
})
}
return products
}
func candidateTargetSwForTerraformProvider(p pkg.Package) []string {
_, providerType := parseTerraformProviderName(p.Name)
if providerType == "" {
return []string{cpe.Any}
}
return []string{providerType}
}
// parseTerraformProviderName extracts the namespace and type from a terraform provider
// source address. The expected format is "registry.terraform.io/<namespace>/<type>".
func parseTerraformProviderName(name string) (namespace, providerType string) {
parts := strings.Split(name, "/")
if len(parts) < 3 {
return "", ""
}
return parts[len(parts)-2], parts[len(parts)-1]
}