From 594b309cdf8f3b9a5da3c0717b5e1a2390a1cfe6 Mon Sep 17 00:00:00 2001 From: Will Murphy Date: Fri, 8 Aug 2025 13:26:15 -0400 Subject: [PATCH] feat: add binary classifier for hashicorp vault (#4121) * add binary classifier for hashicorp vault The Go Binary Cataloger isn't able to parse the version out of the binary shipped in the DockerHub images of hashicorp/vault because the version of the main module isn't set in the binary. Therefore, add a binary classifier cataloger for this binary. Signed-off-by: Will Murphy * chore: add test fixtures, update vault Signed-off-by: Keith Zantow * chore: set binary classifier package type based on PURL Signed-off-by: Keith Zantow * chore: use github.com/hashicorp/vault as package name Signed-off-by: Keith Zantow * chore: update tests Signed-off-by: Keith Zantow --------- Signed-off-by: Will Murphy Signed-off-by: Keith Zantow Co-authored-by: Keith Zantow --- .../cataloger/binary/classifier_cataloger.go | 9 ++++++++ .../binary/classifier_cataloger_test.go | 22 +++++++++++++++++++ syft/pkg/cataloger/binary/classifiers.go | 10 +++++++++ .../snippets/vault/1.19.4/linux-arm64/vault | 11 ++++++++++ .../snippets/vault/1.20.2/linux-amd64/vault | 9 ++++++++ .../binary/test-fixtures/config.yaml | 14 ++++++++++++ 6 files changed, 75 insertions(+) create mode 100644 syft/pkg/cataloger/binary/test-fixtures/classifiers/snippets/vault/1.19.4/linux-arm64/vault create mode 100644 syft/pkg/cataloger/binary/test-fixtures/classifiers/snippets/vault/1.20.2/linux-amd64/vault diff --git a/syft/pkg/cataloger/binary/classifier_cataloger.go b/syft/pkg/cataloger/binary/classifier_cataloger.go index c39b3c6bb..4587a338c 100644 --- a/syft/pkg/cataloger/binary/classifier_cataloger.go +++ b/syft/pkg/cataloger/binary/classifier_cataloger.go @@ -75,6 +75,12 @@ func (c cataloger) Catalog(_ context.Context, resolver file.Resolver) ([]pkg.Pac newPackages: for i := range newPkgs { newPkg := &newPkgs[i] + purlType := pkg.TypeFromPURL(newPkg.PURL) + // for certain results, such as hashicorp vault we are returning a golang PURL, so we can use Golang package type, + // despite not having the known metadata, this should result in downstream grype matching to use the golang matcher + if purlType != pkg.UnknownPkg { + newPkg.Type = purlType + } for j := range packages { p := &packages[j] // consolidate identical packages found in different locations or by different classifiers @@ -92,6 +98,9 @@ func (c cataloger) Catalog(_ context.Context, resolver file.Resolver) ([]pkg.Pac // mergePackages merges information from the extra package into the target package func mergePackages(target *pkg.Package, extra *pkg.Package) { + if extra.Type != pkg.BinaryPkg && target.Type == pkg.BinaryPkg { + target.Type = extra.Type + } // add the locations target.Locations.Add(extra.Locations.ToSlice()...) // update the metadata to indicate which classifiers were used diff --git a/syft/pkg/cataloger/binary/classifier_cataloger_test.go b/syft/pkg/cataloger/binary/classifier_cataloger_test.go index 3d79fc349..70d4aebe7 100644 --- a/syft/pkg/cataloger/binary/classifier_cataloger_test.go +++ b/syft/pkg/cataloger/binary/classifier_cataloger_test.go @@ -1007,6 +1007,28 @@ func Test_Cataloger_PositiveCases(t *testing.T) { Metadata: metadata("consul-binary"), }, }, + { + logicalFixture: "vault/1.20.2/linux-amd64", + expected: pkg.Package{ + Name: "github.com/hashicorp/vault", + Version: "1.20.2", + Type: "golang", + PURL: "pkg:golang/github.com/hashicorp/vault@1.20.2", + Locations: locations("vault"), + Metadata: metadata("hashicorp-vault-binary"), + }, + }, + { + logicalFixture: "vault/1.19.4/linux-arm64", + expected: pkg.Package{ + Name: "github.com/hashicorp/vault", + Version: "1.19.4", + Type: "golang", + PURL: "pkg:golang/github.com/hashicorp/vault@1.19.4", + Locations: locations("vault"), + Metadata: metadata("hashicorp-vault-binary"), + }, + }, { logicalFixture: "erlang/25.3.2.6/linux-amd64", expected: pkg.Package{ diff --git a/syft/pkg/cataloger/binary/classifiers.go b/syft/pkg/cataloger/binary/classifiers.go index 08bfd2a23..b680c2c2a 100644 --- a/syft/pkg/cataloger/binary/classifiers.go +++ b/syft/pkg/cataloger/binary/classifiers.go @@ -448,6 +448,16 @@ func DefaultClassifiers() []binutils.Classifier { PURL: mustPURL("pkg:golang/github.com/hashicorp/consul@version"), CPEs: singleCPE("cpe:2.3:a:hashicorp:consul:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), }, + { + Class: "hashicorp-vault-binary", + FileGlob: "**/vault", + EvidenceMatcher: m.FileContentsVersionMatcher( + // revoke1.18.0 + `(?m)revoke(?P[0-9]+\.[0-9]+\.[0-9]+)`), + Package: "github.com/hashicorp/vault", + PURL: mustPURL("pkg:golang/github.com/hashicorp/vault@version"), + CPEs: singleCPE("cpe:2.3:a:hashicorp:vault:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), + }, { Class: "nginx-binary", FileGlob: "**/nginx", diff --git a/syft/pkg/cataloger/binary/test-fixtures/classifiers/snippets/vault/1.19.4/linux-arm64/vault b/syft/pkg/cataloger/binary/test-fixtures/classifiers/snippets/vault/1.19.4/linux-arm64/vault new file mode 100644 index 000000000..1f4ed3159 --- /dev/null +++ b/syft/pkg/cataloger/binary/test-fixtures/classifiers/snippets/vault/1.19.4/linux-arm64/vault @@ -0,0 +1,11 @@ +name: vault +offset: 191891817 +length: 420 +snippetSha256: fd8eb7979e1e7bbc254f2f7a26f6a70ecb479cc4f50c804f3b0789bc0e229097 +fileSha256: a4754a343e619adef87a1d7e1368a0709ba29802fefbe8d70105c11085becd43 + +### byte snippet to follow ### +ctstreamPragma. +:httpssocks Locked%s.logCT_LOGLOCAL0@level[INFO][WARN]env:///v1/%sDELETEcreateErrorserrorsclient/data/lookupactualAcceptregionawskmsocikmspkcs11%s%s%scloud:%s.%s:revoke1.19.4)(nil))(%#v) {...}frenchCommonArabicBrahmiCarianChakmaCopticGothicHangulHatranHebrewKaithiKhojkiLepchaLycianLydianRejangSyriacTai_LeTangsaTangutTeluguThaanaWanchoYezidiHyphen\u%04x\U%08xgetentpasswd390625%s +%s +%q: %wnumber\uff \ No newline at end of file diff --git a/syft/pkg/cataloger/binary/test-fixtures/classifiers/snippets/vault/1.20.2/linux-amd64/vault b/syft/pkg/cataloger/binary/test-fixtures/classifiers/snippets/vault/1.20.2/linux-amd64/vault new file mode 100644 index 000000000..6aa985438 --- /dev/null +++ b/syft/pkg/cataloger/binary/test-fixtures/classifiers/snippets/vault/1.20.2/linux-amd64/vault @@ -0,0 +1,9 @@ +name: vault +offset: 213670425 +length: 220 +snippetSha256: d9b23916d00e8085a4066974641ef77962f2e0aae6f4244688d2c4fe4286c92b +fileSha256: fb484f1b458e5d2fd28270b406a8b26b28d040dddcaa1d099aa9ee4ac927b730 + +### byte snippet to follow ### +ctstreamPragma. +:httpssocks Locked%s.logCT_LOGLOCAL0@level[INFO][WARN]env:///v1/%sDELETEcreateErrorserrorsclient/data/lookupactualAcceptregionawskmsocikmspkcs11%s%s%scloud:%s.%s:revoke1.20.2)(nil))(%#v) {...}frenchCo \ No newline at end of file diff --git a/syft/pkg/cataloger/binary/test-fixtures/config.yaml b/syft/pkg/cataloger/binary/test-fixtures/config.yaml index a2b23c81a..3ed0334c5 100644 --- a/syft/pkg/cataloger/binary/test-fixtures/config.yaml +++ b/syft/pkg/cataloger/binary/test-fixtures/config.yaml @@ -724,6 +724,20 @@ from-images: paths: - /bin/consul + - version: 1.20.2 + images: + - ref: hashicorp/vault@sha256:5cd2003247e0a574a66c66aee1916b1e9e7f99640298f2e61271a8842d2d2a19 + platform: linux/amd64 + paths: + - /bin/vault + + - version: 1.19.4 + images: + - ref: hashicorp/vault@sha256:b5f675b0bf681568cd7354c697fe4ce953024312d6d23ee7216deda60c192bad + platform: linux/arm64 + paths: + - /bin/vault + - version: 3.0.2 images: - ref: fluent/fluent-bit:3.0.2-amd64@sha256:7e6fe8efd51dda0739e355f58bf5e3b1623cbf2d4a23c06c7a365d9553e2d242