Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package syft for openSUSE:Factory checked in at 2026-01-28 15:10:01 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/syft (Old) and /work/SRC/openSUSE:Factory/.syft.new.1928 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "syft" Wed Jan 28 15:10:01 2026 rev:115 rq:1329521 version:1.41.0 Changes: -------- --- /work/SRC/openSUSE:Factory/syft/syft.changes 2026-01-17 14:56:48.716346390 +0100 +++ /work/SRC/openSUSE:Factory/.syft.new.1928/syft.changes 2026-01-28 15:11:06.995901298 +0100 @@ -1,0 +2,20 @@ +Tue Jan 27 12:18:15 UTC 2026 - Johannes Kastl <[email protected]> + +- Update to version 1.41.0: + * Added Features + - detect Debian version from /etc/debian_version [#4569 + @kzantow] + * Bug Fixes + - correctly report supporting evidence for binary packages + [#4558 @kzantow] + * Dependencies + - chore(deps): update anchore dependencies (#4575) + - chore(deps): update tools to latest versions (#4570) + - chore(deps): bump the actions-minor-patch group across 2 + directories with 3 updates (#4568) + - chore(deps): bump the go-minor-patch group with 6 updates + (#4567) + - chore(deps): update tools to latest versions (#4565) + - chore(deps): bump github.com/spdx/tools-golang (#4557) + +------------------------------------------------------------------- Old: ---- syft-1.40.1.obscpio New: ---- syft-1.41.0.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ syft.spec ++++++ --- /var/tmp/diff_new_pack.Iv90Jf/_old 2026-01-28 15:12:54.520380516 +0100 +++ /var/tmp/diff_new_pack.Iv90Jf/_new 2026-01-28 15:12:54.520380516 +0100 @@ -17,7 +17,7 @@ Name: syft -Version: 1.40.1 +Version: 1.41.0 Release: 0 Summary: CLI tool and library for generating a Software Bill of Materials License: Apache-2.0 ++++++ _service ++++++ --- /var/tmp/diff_new_pack.Iv90Jf/_old 2026-01-28 15:12:54.560382182 +0100 +++ /var/tmp/diff_new_pack.Iv90Jf/_new 2026-01-28 15:12:54.564382349 +0100 @@ -3,7 +3,7 @@ <param name="url">https://github.com/anchore/syft</param> <param name="scm">git</param> <param name="exclude">.git</param> - <param name="revision">v1.40.1</param> + <param name="revision">v1.41.0</param> <param name="versionformat">@PARENT_TAG@</param> <param name="versionrewrite-pattern">v(.*)</param> <param name="changesgenerate">enable</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.Iv90Jf/_old 2026-01-28 15:12:54.588383348 +0100 +++ /var/tmp/diff_new_pack.Iv90Jf/_new 2026-01-28 15:12:54.592383515 +0100 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/anchore/syft</param> - <param name="changesrevision">63927ab49feea10a7fd88191acd615667227d338</param></service></servicedata> + <param name="changesrevision">e8b4527bfbb7780cd70f2541fce4dca58803fb53</param></service></servicedata> (No newline at EOF) ++++++ syft-1.40.1.obscpio -> syft-1.41.0.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/syft-1.40.1/.binny.yaml new/syft-1.41.0/.binny.yaml --- old/syft-1.40.1/.binny.yaml 2026-01-15 22:33:35.000000000 +0100 +++ new/syft-1.41.0/.binny.yaml 2026-01-27 11:14:26.000000000 +0100 @@ -90,7 +90,7 @@ # used for running all local and CI tasks - name: task version: - want: v3.46.4 + want: v3.47.0 method: github-release with: repo: go-task/task @@ -98,7 +98,7 @@ # used for triggering a release - name: gh version: - want: v2.85.0 + want: v2.86.0 method: github-release with: repo: cli/cli diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/syft-1.40.1/go.mod new/syft-1.41.0/go.mod --- old/syft-1.40.1/go.mod 2026-01-15 22:33:35.000000000 +0100 +++ new/syft-1.41.0/go.mod 2026-01-27 11:14:26.000000000 +0100 @@ -23,7 +23,7 @@ github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04 github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b github.com/anchore/packageurl-go v0.1.1-0.20250220190351-d62adb6e1115 - github.com/anchore/stereoscope v0.1.18 + github.com/anchore/stereoscope v0.1.19 github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be github.com/aquasecurity/go-pep440-version v0.0.1 github.com/bitnami/go-version v0.0.0-20250131085805-b1f57a8634ef @@ -39,12 +39,12 @@ github.com/dustin/go-humanize v1.0.1 github.com/elliotchance/phpserialize v1.4.0 github.com/facebookincubator/nvdtools v0.1.5 - github.com/github/go-spdx/v2 v2.3.5 + github.com/github/go-spdx/v2 v2.3.6 github.com/gkampitakis/go-snaps v0.5.19 github.com/go-git/go-billy/v5 v5.7.0 github.com/go-git/go-git/v5 v5.16.4 github.com/go-test/deep v1.1.1 - github.com/go-viper/mapstructure/v2 v2.4.0 + github.com/go-viper/mapstructure/v2 v2.5.0 github.com/gohugoio/hashstructure v0.6.0 github.com/google/go-cmp v0.7.0 github.com/google/go-containerregistry v0.20.7 @@ -76,7 +76,7 @@ github.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e github.com/sergi/go-diff v1.4.0 github.com/spdx/gordf v0.0.0-20201111095634-7098f93598fb - github.com/spdx/tools-golang v0.5.6 + github.com/spdx/tools-golang v0.5.7 github.com/spf13/afero v1.15.0 github.com/spf13/cobra v1.10.2 github.com/stretchr/testify v1.11.1 @@ -88,10 +88,10 @@ github.com/zyedidia/generic v1.2.2-0.20230320175451-4410d2372cb1 go.uber.org/goleak v1.3.0 go.yaml.in/yaml/v3 v3.0.4 - golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b - golang.org/x/mod v0.31.0 - golang.org/x/net v0.48.0 - modernc.org/sqlite v1.43.0 + golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 + golang.org/x/mod v0.32.0 + golang.org/x/net v0.49.0 + modernc.org/sqlite v1.44.1 ) require ( @@ -139,7 +139,7 @@ github.com/containerd/typeurl/v2 v2.2.3 // indirect github.com/cyphar/filepath-securejoin v0.6.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/docker/cli v29.1.4+incompatible // indirect + github.com/docker/cli v29.1.5+incompatible // indirect github.com/docker/distribution v2.8.3+incompatible // indirect github.com/docker/docker v28.5.2+incompatible // indirect github.com/docker/docker-credential-helpers v0.9.4 // indirect @@ -199,7 +199,7 @@ github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect github.com/muesli/cancelreader v0.2.2 // indirect github.com/muesli/termenv v0.16.0 // indirect - github.com/ncruces/go-strftime v0.1.9 // indirect + github.com/ncruces/go-strftime v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.1 // indirect github.com/opencontainers/runtime-spec v1.3.0 // indirect github.com/opencontainers/selinux v1.13.1 // indirect @@ -258,7 +258,7 @@ golang.org/x/term v0.39.0 // indirect golang.org/x/text v0.33.0 // indirect golang.org/x/time v0.14.0 - golang.org/x/tools v0.40.0 + golang.org/x/tools v0.41.0 golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect google.golang.org/api v0.256.0 // indirect google.golang.org/genproto v0.0.0-20250922171735-9219d122eba9 // indirect @@ -268,7 +268,7 @@ google.golang.org/protobuf v1.36.10 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v3 v3.0.1 - modernc.org/libc v1.66.10 // indirect + modernc.org/libc v1.67.6 // indirect modernc.org/mathutil v1.7.1 // indirect modernc.org/memory v1.11.0 // indirect ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/syft-1.40.1/go.sum new/syft-1.41.0/go.sum --- old/syft-1.40.1/go.sum 2026-01-15 22:33:35.000000000 +0100 +++ new/syft-1.41.0/go.sum 2026-01-27 11:14:26.000000000 +0100 @@ -152,8 +152,8 @@ github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b/go.mod h1:Bkc+JYWjMCF8OyZ340IMSIi2Ebf3uwByOk6ho4wne1E= github.com/anchore/packageurl-go v0.1.1-0.20250220190351-d62adb6e1115 h1:ZyRCmiEjnoGJZ1+Ah0ZZ/mKKqNhGcUZBl0s7PTTDzvY= github.com/anchore/packageurl-go v0.1.1-0.20250220190351-d62adb6e1115/go.mod h1:KoYIv7tdP5+CC9VGkeZV4/vGCKsY55VvoG+5dadg4YI= -github.com/anchore/stereoscope v0.1.18 h1:Mj34pRtxwfdFJkYKtKjiO9Xn7qs0RTCi59ofRYTSCEU= -github.com/anchore/stereoscope v0.1.18/go.mod h1:y8P4BURfBj0DVRly9cPHsSuZdI/AsZs3ee/x/HusEe4= +github.com/anchore/stereoscope v0.1.19 h1:1G5LVmRN1Sz6qNezpVAEeN7QfWwCE9zw9TJK1ZGnkvw= +github.com/anchore/stereoscope v0.1.19/go.mod h1:+laNHlk05xA2YqgEzq8mxkFzclL3NRdeNIsiQQVeZZ4= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ= github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= @@ -351,8 +351,8 @@ github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/djherbis/times v1.6.0 h1:w2ctJ92J8fBvWPxugmXIv7Nz7Q3iDMKNx9v5ocVH20c= github.com/djherbis/times v1.6.0/go.mod h1:gOHeRAz2h+VJNZ5Gmc/o7iD9k4wW7NMVqieYCY99oc0= -github.com/docker/cli v29.1.4+incompatible h1:AI8fwZhqsAsrqZnVv9h6lbexeW/LzNTasf6A4vcNN8M= -github.com/docker/cli v29.1.4+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v29.1.5+incompatible h1:GckbANUt3j+lsnQ6eCcQd70mNSOismSHWt8vk2AX8ao= +github.com/docker/cli v29.1.5+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM= @@ -420,8 +420,8 @@ github.com/gabriel-vasile/mimetype v1.4.12 h1:e9hWvmLYvtp846tLHam2o++qitpguFiYCKbn0w9jyqw= github.com/gabriel-vasile/mimetype v1.4.12/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/github/go-spdx/v2 v2.3.5 h1:rtRQmzDSq2sU/F2oTIvNQQ+6oInq7yxex5npgY//bJQ= -github.com/github/go-spdx/v2 v2.3.5/go.mod h1:VziiWwQ/hoGS++2ifYyr/za0Ng9rlgMS+c4U7zckrDs= +github.com/github/go-spdx/v2 v2.3.6 h1:9flm625VmmTlWXi0YH5W9V8FdMfulvxalHdYnUfoqxc= +github.com/github/go-spdx/v2 v2.3.6/go.mod h1:/5rwgS0txhGtRdUZwc02bTglzg6HK3FfuEbECKlK2Sg= github.com/gkampitakis/ciinfo v0.3.2 h1:JcuOPk8ZU7nZQjdUhctuhQofk7BGHuIy0c9Ez8BNhXs= github.com/gkampitakis/ciinfo v0.3.2/go.mod h1:1NIwaOcFChN4fa/B0hEBdAb6npDlFL8Bwx4dfRLRqAo= github.com/gkampitakis/go-snaps v0.5.19 h1:hUJlCQOpTt1M+kSisMwioDWZDWpDtdAvUhvWCx1YGW0= @@ -458,8 +458,8 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= -github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= -github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro= +github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= @@ -772,8 +772,8 @@ github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc= github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= -github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= +github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w= +github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= github.com/nix-community/go-nix v0.0.0-20250101154619-4bdde671e0a1 h1:kpt9ZfKcm+EDG4s40hMwE//d5SBgDjUOrITReV2u4aA= github.com/nix-community/go-nix v0.0.0-20250101154619-4bdde671e0a1/go.mod h1:qgCw4bBKZX8qMgGeEZzGFVT3notl42dBjNqO2jut0M0= github.com/nsf/jsondiff v0.0.0-20210926074059-1e845ec5d249 h1:NHrXEjTNQY7P0Zfx1aMrNhpgxHmow66XQtm0aQLY0AE= @@ -898,8 +898,8 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spdx/gordf v0.0.0-20201111095634-7098f93598fb h1:bLo8hvc8XFm9J47r690TUKBzcjSWdJDxmjXJZ+/f92U= github.com/spdx/gordf v0.0.0-20201111095634-7098f93598fb/go.mod h1:uKWaldnbMnjsSAXRurWqqrdyZen1R7kxl8TkmWk2OyM= -github.com/spdx/tools-golang v0.5.6 h1:HUwSJWxyAR7vBstEeZ1+guD6Jcl4TVsKyTBUwT0RjTQ= -github.com/spdx/tools-golang v0.5.6/go.mod h1:jg7w0LOpoNAw6OxKEzCoqPC2GCTj45LyTlVmXubDsYw= +github.com/spdx/tools-golang v0.5.7 h1:+sWcKGnhwp3vLdMqPcLdA6QK679vd86cK9hQWH3AwCg= +github.com/spdx/tools-golang v0.5.7/go.mod h1:jg7w0LOpoNAw6OxKEzCoqPC2GCTj45LyTlVmXubDsYw= github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= @@ -1079,8 +1079,8 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o= -golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8= +golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 h1:mgKeJMpvi0yx/sU5GsxQ7p6s2wtOnGAHZWCHUM4KGzY= +golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -1108,8 +1108,8 @@ golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI= -golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg= +golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c= +golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1154,8 +1154,8 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= -golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= +golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= +golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1342,8 +1342,8 @@ golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= -golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= +golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc= +golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1537,18 +1537,20 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -modernc.org/cc/v4 v4.26.5 h1:xM3bX7Mve6G8K8b+T11ReenJOT+BmVqQj0FY5T4+5Y4= -modernc.org/cc/v4 v4.26.5/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= -modernc.org/ccgo/v4 v4.28.1 h1:wPKYn5EC/mYTqBO373jKjvX2n+3+aK7+sICCv4Fjy1A= -modernc.org/ccgo/v4 v4.28.1/go.mod h1:uD+4RnfrVgE6ec9NGguUNdhqzNIeeomeXf6CL0GTE5Q= +modernc.org/cc/v4 v4.27.1 h1:9W30zRlYrefrDV2JE2O8VDtJ1yPGownxciz5rrbQZis= +modernc.org/cc/v4 v4.27.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= +modernc.org/ccgo/v4 v4.30.1 h1:4r4U1J6Fhj98NKfSjnPUN7Ze2c6MnAdL0hWw6+LrJpc= +modernc.org/ccgo/v4 v4.30.1/go.mod h1:bIOeI1JL54Utlxn+LwrFyjCx2n2RDiYEaJVSrgdrRfM= modernc.org/fileutil v1.3.40 h1:ZGMswMNc9JOCrcrakF1HrvmergNLAmxOPjizirpfqBA= modernc.org/fileutil v1.3.40/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc= modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI= modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito= +modernc.org/gc/v3 v3.1.1 h1:k8T3gkXWY9sEiytKhcgyiZ2L0DTyCQ/nvX+LoCljoRE= +modernc.org/gc/v3 v3.1.1/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY= modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks= modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI= -modernc.org/libc v1.66.10 h1:yZkb3YeLx4oynyR+iUsXsybsX4Ubx7MQlSYEw4yj59A= -modernc.org/libc v1.66.10/go.mod h1:8vGSEwvoUoltr4dlywvHqjtAqHBaw0j1jI7iFBTAr2I= +modernc.org/libc v1.67.6 h1:eVOQvpModVLKOdT+LvBPjdQqfrZq+pC39BygcT+E7OI= +modernc.org/libc v1.67.6/go.mod h1:JAhxUVlolfYDErnwiqaLvUqc8nfb2r6S6slAgZOnaiE= modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI= @@ -1557,8 +1559,8 @@ modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns= modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w= modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE= -modernc.org/sqlite v1.43.0 h1:8YqiFx3G1VhHTXO2Q00bl1Wz9KhS9Q5okwfp9Y97VnA= -modernc.org/sqlite v1.43.0/go.mod h1:+VkC6v3pLOAE0A0uVucQEcbVW0I5nHCeDaBf+DpsQT8= +modernc.org/sqlite v1.44.1 h1:qybx/rNpfQipX/t47OxbHmkkJuv2JWifCMH8SVUiDas= +modernc.org/sqlite v1.44.1/go.mod h1:CzbrU2lSB1DKUusvwGz7rqEKIq+NUd8GWuBBZDs9/nA= modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/syft-1.40.1/syft/linux/identify_release.go new/syft-1.41.0/syft/linux/identify_release.go --- old/syft-1.40.1/syft/linux/identify_release.go 2026-01-15 22:33:35.000000000 +0100 +++ new/syft-1.41.0/syft/linux/identify_release.go 2026-01-27 11:14:26.000000000 +0100 @@ -54,6 +54,12 @@ // ///////////////////////////////////////////////////////////////////////////////////////////////////// } +// after a parser function returns a Release, it may have incomplete information; supplementers can be used to +// fill in missing details based on other files present in the filesystem +var supplementers = []func(file.Resolver, *Release){ + supplementDebianVersion, +} + // IdentifyRelease parses distro-specific files to discover and raise linux distribution release details. func IdentifyRelease(resolver file.Resolver) *Release { logger := log.Nested("operation", "identify-release") @@ -67,6 +73,9 @@ for _, location := range locations { release := tryParseReleaseInfo(resolver, location, logger, entry) if release != nil { + for _, supplementer := range supplementers { + supplementer(resolver, release) + } return release } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/syft-1.40.1/syft/linux/identify_release_test.go new/syft-1.41.0/syft/linux/identify_release_test.go --- old/syft-1.40.1/syft/linux/identify_release_test.go 2026-01-15 22:33:35.000000000 +0100 +++ new/syft-1.41.0/syft/linux/identify_release_test.go 2026-01-27 11:14:26.000000000 +0100 @@ -74,7 +74,7 @@ }, }, { - fixture: "test-fixtures/os/debian", + fixture: "test-fixtures/os/debian/from-os-release", release: &Release{ PrettyName: "Debian GNU/Linux 8 (jessie)", Name: "Debian GNU/Linux", @@ -88,6 +88,20 @@ }, }, { + fixture: "test-fixtures/os/debian/from-debian_version", + release: &Release{ + PrettyName: "Distroless", + Name: "Debian GNU/Linux", + ID: "debian", + IDLike: nil, + Version: "10.8", + VersionID: "10.8", + HomeURL: "https://github.com/GoogleContainerTools/distroless", + SupportURL: "https://github.com/GoogleContainerTools/distroless/blob/master/README.md", + BugReportURL: "https://github.com/GoogleContainerTools/distroless/issues/new", + }, + }, + { fixture: "test-fixtures/os/fedora", release: &Release{ PrettyName: "Fedora Linux 36 (Container Image)", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/syft-1.40.1/syft/linux/supplement_release.go new/syft-1.41.0/syft/linux/supplement_release.go --- old/syft-1.40.1/syft/linux/supplement_release.go 1970-01-01 01:00:00.000000000 +0100 +++ new/syft-1.41.0/syft/linux/supplement_release.go 2026-01-27 11:14:26.000000000 +0100 @@ -0,0 +1,51 @@ +package linux + +import ( + "io" + "regexp" + "strings" + + "github.com/anchore/syft/internal" + "github.com/anchore/syft/internal/log" + "github.com/anchore/syft/syft/file" +) + +func supplementDebianVersion(resolver file.Resolver, release *Release) { + // we're only looking for version information for debian when none is present in /etc/os-release + if release.Version != "" || release.VersionID != "" || !strings.EqualFold(release.ID, "debian") { + return + } + // if we have a debian release with no version, look for a debian_version + locations, err := resolver.FilesByGlob("/etc/debian_version") + if err != nil { + log.Debugf("error reading /etc/debian_version: %v", err) + return + } + for _, location := range locations { + version := readDebianVersionFile(resolver, location) + if version != "" { + release.Version = version + release.VersionID = version + return // keep the first result + } + } +} + +func readDebianVersionFile(resolver file.Resolver, location file.Location) string { + rdr, err := resolver.FileContentsByLocation(location) + if err != nil { + log.Debugf("error getting contents for %s: %v", location.RealPath, err) + return "" + } + defer internal.CloseAndLogError(rdr, location.RealPath) + contents, err := io.ReadAll(rdr) + if err != nil { + log.Debugf("error reading %s: %v", location.RealPath, err) + return "" + } + version := strings.TrimSpace(string(contents)) + if regexp.MustCompile(`^\d+(?:\.\d+)?$`).MatchString(version) { + return version + } + return "" +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/syft-1.40.1/syft/linux/test-fixtures/os/debian/from-debian_version/etc/debian_version new/syft-1.41.0/syft/linux/test-fixtures/os/debian/from-debian_version/etc/debian_version --- old/syft-1.40.1/syft/linux/test-fixtures/os/debian/from-debian_version/etc/debian_version 1970-01-01 01:00:00.000000000 +0100 +++ new/syft-1.41.0/syft/linux/test-fixtures/os/debian/from-debian_version/etc/debian_version 2026-01-27 11:14:26.000000000 +0100 @@ -0,0 +1 @@ +10.8 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/syft-1.40.1/syft/linux/test-fixtures/os/debian/from-debian_version/etc/os-release new/syft-1.41.0/syft/linux/test-fixtures/os/debian/from-debian_version/etc/os-release --- old/syft-1.40.1/syft/linux/test-fixtures/os/debian/from-debian_version/etc/os-release 1970-01-01 01:00:00.000000000 +0100 +++ new/syft-1.41.0/syft/linux/test-fixtures/os/debian/from-debian_version/etc/os-release 2026-01-27 11:14:26.000000000 +0100 @@ -0,0 +1,6 @@ +PRETTY_NAME="Distroless" +NAME="Debian GNU/Linux" +ID="debian" +HOME_URL="https://github.com/GoogleContainerTools/distroless" +SUPPORT_URL="https://github.com/GoogleContainerTools/distroless/blob/master/README.md" +BUG_REPORT_URL="https://github.com/GoogleContainerTools/distroless/issues/new" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/syft-1.40.1/syft/linux/test-fixtures/os/debian/from-os-release/usr/lib/os-release new/syft-1.41.0/syft/linux/test-fixtures/os/debian/from-os-release/usr/lib/os-release --- old/syft-1.40.1/syft/linux/test-fixtures/os/debian/from-os-release/usr/lib/os-release 1970-01-01 01:00:00.000000000 +0100 +++ new/syft-1.41.0/syft/linux/test-fixtures/os/debian/from-os-release/usr/lib/os-release 2026-01-27 11:14:26.000000000 +0100 @@ -0,0 +1,8 @@ +PRETTY_NAME="Debian GNU/Linux 8 (jessie)" +NAME="Debian GNU/Linux" +VERSION_ID="8" +VERSION="8 (jessie)" +ID=debian +HOME_URL="http://www.debian.org/" +SUPPORT_URL="http://www.debian.org/support" +BUG_REPORT_URL="https://bugs.debian.org/" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/syft-1.40.1/syft/linux/test-fixtures/os/debian/usr/lib/os-release new/syft-1.41.0/syft/linux/test-fixtures/os/debian/usr/lib/os-release --- old/syft-1.40.1/syft/linux/test-fixtures/os/debian/usr/lib/os-release 2026-01-15 22:33:35.000000000 +0100 +++ new/syft-1.41.0/syft/linux/test-fixtures/os/debian/usr/lib/os-release 1970-01-01 01:00:00.000000000 +0100 @@ -1,8 +0,0 @@ -PRETTY_NAME="Debian GNU/Linux 8 (jessie)" -NAME="Debian GNU/Linux" -VERSION_ID="8" -VERSION="8 (jessie)" -ID=debian -HOME_URL="http://www.debian.org/" -SUPPORT_URL="http://www.debian.org/support" -BUG_REPORT_URL="https://bugs.debian.org/" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/syft-1.40.1/syft/pkg/cataloger/binary/capabilities.yaml new/syft-1.41.0/syft/pkg/cataloger/binary/capabilities.yaml --- old/syft-1.40.1/syft/pkg/cataloger/binary/capabilities.yaml 2026-01-15 22:33:35.000000000 +0100 +++ new/syft-1.41.0/syft/pkg/cataloger/binary/capabilities.yaml 2026-01-27 11:14:26.000000000 +0100 @@ -111,16 +111,6 @@ type: BinaryPkg - method: glob criteria: - - '**/VERSION*' - packages: - - class: go-binary-hint - name: go - purl: pkg:generic/go - cpes: - - cpe:2.3:a:golang:go:*:*:*:*:*:*:*:* - type: BinaryPkg - - method: glob - criteria: - '**/busybox' packages: - class: busybox-binary diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/syft-1.40.1/syft/pkg/cataloger/binary/classifier_cataloger.go new/syft-1.41.0/syft/pkg/cataloger/binary/classifier_cataloger.go --- old/syft-1.40.1/syft/pkg/cataloger/binary/classifier_cataloger.go 2026-01-15 22:33:35.000000000 +0100 +++ new/syft-1.41.0/syft/pkg/cataloger/binary/classifier_cataloger.go 2026-01-27 11:14:26.000000000 +0100 @@ -64,6 +64,10 @@ var relationships []artifact.Relationship var errs error + // we do not run these classifiers in parallel currently because: when determining primary vs. supporting evidence, + // we take preference to the classifier that was defined first, if we modify this to run in parallel, + // we need to retain this behavior by giving precedence to the classifier defined first in the c.classifiers list; + // if this is ever made parallel, we will need to account for this to have deterministic behavior for _, cls := range c.classifiers { log.WithFields("classifier", cls.Class).Trace("cataloging binaries") newPkgs, err := catalog(resolver, cls) @@ -101,8 +105,26 @@ if extra.Type != pkg.BinaryPkg && target.Type == pkg.BinaryPkg { target.Type = extra.Type } - // add the locations - target.Locations.Add(extra.Locations.ToSlice()...) + addedEvidence := false + // when merging locations together, we need to maintain primary vs. supporting evidence - + // if we are merging two packages together that have overlapping evidence, e.g. libpython + // which are found by 2 different classifiers, we want to deduplicate evidence for the same + // locations when merging so libpython is not considered primary evidence. This allows cases + // where we find python binary with version info coming from libpython to deduplicate the libpython + // entries, but also surface results for libpython separately as primary evidence when there is + // no python binary referencing it + for _, location := range extra.Locations.ToSlice() { + // if we already have the same location, don't include duplicates + if target.Locations.Contains(location) { + continue + } + addedEvidence = true + target.Locations.Add(location) + } + // only include the additional metadata if we added evidence, as it was likely duplicated e.g. libpython + if !addedEvidence { + return + } // update the metadata to indicate which classifiers were used meta, _ := target.Metadata.(pkg.BinarySignature) if m, ok := extra.Metadata.(pkg.BinarySignature); ok { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/syft-1.40.1/syft/pkg/cataloger/binary/classifier_cataloger_test.go new/syft-1.41.0/syft/pkg/cataloger/binary/classifier_cataloger_test.go --- old/syft-1.40.1/syft/pkg/cataloger/binary/classifier_cataloger_test.go 2026-01-15 22:33:35.000000000 +0100 +++ new/syft-1.41.0/syft/pkg/cataloger/binary/classifier_cataloger_test.go 2026-01-27 11:14:26.000000000 +0100 @@ -6,6 +6,7 @@ "flag" "fmt" "io" + "slices" "strings" "testing" @@ -547,6 +548,7 @@ }, }, { + // no python binary, but we find libpython, which is surfaced as primary evidence logicalFixture: "python-shared-lib/3.7.4/linux-amd64", expected: pkg.Package{ Name: "python", @@ -556,7 +558,6 @@ Metadata: metadata("python-binary-lib"), }, }, - { // note: dynamic (non-snippet) test case logicalFixture: "python-slim-shared-libs/3.11/linux-amd64", @@ -569,7 +570,6 @@ Matches: []pkg.ClassifierMatch{ match("python-binary", "python3.11"), match("python-binary", "libpython3.11.so.1.0"), - match("python-binary-lib", "libpython3.11.so.1.0"), }, }, }, @@ -586,7 +586,6 @@ Matches: []pkg.ClassifierMatch{ match("python-binary", "python3.9"), match("python-binary", "libpython3.9.so.1.0"), - match("python-binary-lib", "libpython3.9.so.1.0"), }, }, }, @@ -618,7 +617,6 @@ Matches: []pkg.ClassifierMatch{ match("python-binary", "python3.4"), match("python-binary", "libpython3.4m.so.1.0"), - match("python-binary-lib", "libpython3.4m.so.1.0"), }, }, }, @@ -734,8 +732,8 @@ Name: "go", Version: "1.15", PURL: "pkg:generic/[email protected]", - Locations: locations("VERSION"), - Metadata: metadata("go-binary-hint"), + Locations: locations("bin/go", "VERSION"), + Metadata: metadata("go-binary"), }, }, { @@ -745,8 +743,8 @@ Name: "go", Version: "1.25-d524e1e", PURL: "pkg:generic/[email protected]", - Locations: locations("VERSION.cache"), - Metadata: metadata("go-binary-hint"), + Locations: locations("bin/go", "VERSION.cache"), + Metadata: metadata("go-binary"), }, }, { @@ -1823,17 +1821,6 @@ require.NoError(t, err) for _, p := range packages { - expectedLocations := test.expected.Locations.ToSlice() - gotLocations := p.Locations.ToSlice() - require.Len(t, gotLocations, len(expectedLocations)) - - for i, expectedLocation := range expectedLocations { - gotLocation := gotLocations[i] - if expectedLocation.RealPath != gotLocation.RealPath { - t.Fatalf("locations do not match; expected: %v got: %v", expectedLocations, gotLocations) - } - } - assertPackagesAreEqual(t, test.expected, p) } }) @@ -2023,12 +2010,13 @@ gotLocations := p.Locations.ToSlice() if len(expectedLocations) != len(gotLocations) { - failMessages = append(failMessages, "locations are not equal length") + failMessages = append(failMessages, fmt.Sprintf("locations are not equal: %v != %v", expectedLocations, gotLocations)) } else { - for i, expectedLocation := range expectedLocations { - gotLocation := gotLocations[i] - if expectedLocation.RealPath != gotLocation.RealPath { - failMessages = append(failMessages, fmt.Sprintf("locations do not match; expected: %v got: %v", expectedLocation.RealPath, gotLocation.RealPath)) + for _, expectedLocation := range expectedLocations { + if !slices.ContainsFunc(gotLocations, func(gotLocation file.Location) bool { + return gotLocation.RealPath == expectedLocation.RealPath + }) { + failMessages = append(failMessages, fmt.Sprintf("location not found; expected: %v in set: %v", expectedLocation.RealPath, gotLocations)) } } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/syft-1.40.1/syft/pkg/cataloger/binary/classifiers.go new/syft-1.41.0/syft/pkg/cataloger/binary/classifiers.go --- old/syft-1.40.1/syft/pkg/cataloger/binary/classifiers.go 2026-01-15 22:33:35.000000000 +0100 +++ new/syft-1.41.0/syft/pkg/cataloger/binary/classifiers.go 2026-01-27 11:14:26.000000000 +0100 @@ -71,8 +71,14 @@ { Class: "go-binary", FileGlob: "**/go", - EvidenceMatcher: m.FileContentsVersionMatcher( - `(?m)go(?P<version>[0-9]+\.[0-9]+(\.[0-9]+|beta[0-9]+|alpha[0-9]+|rc[0-9]+)?)\x00`), + EvidenceMatcher: binutils.MatchAny( + m.FileContentsVersionMatcher( + `(?m)go(?P<version>[0-9]+\.[0-9]+(\.[0-9]+|beta[0-9]+|alpha[0-9]+|rc[0-9]+)?)\x00`), + binutils.SupportingEvidenceMatcher("../VERSION*", + m.FileContentsVersionMatcher( + `(?m)go(?P<version>[0-9]+\.[0-9]+(\.[0-9]+|beta[0-9]+|alpha[0-9]+|rc[0-9]+|-[_0-9a-z]+)?)\s`), + ), + ), Package: "go", PURL: mustPURL("pkg:generic/go@version"), CPEs: singleCPE("cpe:2.3:a:golang:go:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), @@ -143,15 +149,6 @@ CPEs: singleCPE("cpe:2.3:a:nodejs:node.js:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), }, { - Class: "go-binary-hint", - FileGlob: "**/VERSION*", - EvidenceMatcher: m.FileContentsVersionMatcher( - `(?m)go(?P<version>[0-9]+\.[0-9]+(\.[0-9]+|beta[0-9]+|alpha[0-9]+|rc[0-9]+)?(-[0-9a-f]{7})?)`), - Package: "go", - PURL: mustPURL("pkg:generic/go@version"), - CPEs: singleCPE("cpe:2.3:a:golang:go:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), - }, - { Class: "busybox-binary", FileGlob: "**/busybox", EvidenceMatcher: m.FileContentsVersionMatcher( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/syft-1.40.1/syft/pkg/cataloger/binary/test-fixtures/classifiers/snippets/go-version-hint/1.15/any/VERSION new/syft-1.41.0/syft/pkg/cataloger/binary/test-fixtures/classifiers/snippets/go-version-hint/1.15/any/VERSION --- old/syft-1.40.1/syft/pkg/cataloger/binary/test-fixtures/classifiers/snippets/go-version-hint/1.15/any/VERSION 2026-01-15 22:33:35.000000000 +0100 +++ new/syft-1.41.0/syft/pkg/cataloger/binary/test-fixtures/classifiers/snippets/go-version-hint/1.15/any/VERSION 2026-01-27 11:14:26.000000000 +0100 @@ -1 +1 @@ -go1.15-beta2 \ No newline at end of file +go1.15 Fri 2003 \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/syft-1.40.1/syft/pkg/cataloger/binary/test-fixtures/classifiers/snippets/go-version-hint/1.15/any/bin/go new/syft-1.41.0/syft/pkg/cataloger/binary/test-fixtures/classifiers/snippets/go-version-hint/1.15/any/bin/go --- old/syft-1.40.1/syft/pkg/cataloger/binary/test-fixtures/classifiers/snippets/go-version-hint/1.15/any/bin/go 1970-01-01 01:00:00.000000000 +0100 +++ new/syft-1.41.0/syft/pkg/cataloger/binary/test-fixtures/classifiers/snippets/go-version-hint/1.15/any/bin/go 2026-01-27 11:14:26.000000000 +0100 @@ -0,0 +1 @@ +no version in this binary \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/syft-1.40.1/syft/pkg/cataloger/binary/test-fixtures/classifiers/snippets/go-version-hint/1.25/any/bin/go new/syft-1.41.0/syft/pkg/cataloger/binary/test-fixtures/classifiers/snippets/go-version-hint/1.25/any/bin/go --- old/syft-1.40.1/syft/pkg/cataloger/binary/test-fixtures/classifiers/snippets/go-version-hint/1.25/any/bin/go 1970-01-01 01:00:00.000000000 +0100 +++ new/syft-1.41.0/syft/pkg/cataloger/binary/test-fixtures/classifiers/snippets/go-version-hint/1.25/any/bin/go 2026-01-27 11:14:26.000000000 +0100 @@ -0,0 +1 @@ +no version in this binary \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/syft-1.40.1/syft/pkg/cataloger/internal/binutils/branching_matcher_test.go new/syft-1.41.0/syft/pkg/cataloger/internal/binutils/branching_matcher_test.go --- old/syft-1.40.1/syft/pkg/cataloger/internal/binutils/branching_matcher_test.go 2026-01-15 22:33:35.000000000 +0100 +++ new/syft-1.41.0/syft/pkg/cataloger/internal/binutils/branching_matcher_test.go 2026-01-27 11:14:26.000000000 +0100 @@ -10,7 +10,7 @@ ) func Test_BranchingMatcher(t *testing.T) { - matchingTest := FileContentsVersionMatcher("", `my-verison:(?<version>\d+\.\d+)`) + matchingTest := FileContentsVersionMatcher("", `my-version:(?<version>\d+\.\d+)`) notMatchingTest := MatchPath("**/not-version*") tests := []struct { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/syft-1.40.1/syft/pkg/cataloger/internal/binutils/classifier.go new/syft-1.41.0/syft/pkg/cataloger/internal/binutils/classifier.go --- old/syft-1.40.1/syft/pkg/cataloger/internal/binutils/classifier.go 2026-01-15 22:33:35.000000000 +0100 +++ new/syft-1.41.0/syft/pkg/cataloger/internal/binutils/classifier.go 2026-01-27 11:14:26.000000000 +0100 @@ -9,6 +9,7 @@ "fmt" "io" "maps" + "path" "regexp" "strconv" "strings" @@ -273,9 +274,7 @@ } for _, p := range pkgs { // set the source binary as the first location - locationSet := file.NewLocationSet(context.Location) - locationSet.Add(p.Locations.ToSlice()...) - p.Locations = locationSet + makePrimaryLocation(&p, context.Location) meta, _ := p.Metadata.(pkg.BinarySignature) p.Metadata = pkg.BinarySignature{ Matches: append([]pkg.ClassifierMatch{ @@ -309,6 +308,28 @@ } } +// SupportingEvidenceMatcher defines an evidence matcher that searches for secondary evidence with path globs +// relative to a primary file, for example: a VERSION file in the same or a parent directory to another binary +func SupportingEvidenceMatcher(relativePathGlob string, evidenceMatcher EvidenceMatcher) EvidenceMatcher { + return func(classifier Classifier, context MatcherContext) ([]pkg.Package, error) { + f := path.Dir(context.Location.RealPath) + f = path.Join(f, relativePathGlob) + f = path.Clean(f) + // this would ideally be RelativeFileByPath but with a glob search: + relativeFiles, err := context.Resolver.FilesByGlob(f) + if err != nil { + return nil, err + } + for _, relativeFile := range relativeFiles { + evidence, err := collectSupportingEvidence(classifier, context, relativeFile, evidenceMatcher) + if evidence != nil || err != nil { + return evidence, err + } + } + return nil, nil + } +} + func getReader(context MatcherContext) (unionreader.UnionReader, error) { if context.GetReader != nil { return context.GetReader(context) @@ -368,3 +389,43 @@ return nil, nil } + +func makePrimaryLocation(p *pkg.Package, primaryLocation file.Location) { + locationSet := file.NewLocationSet(primaryLocation.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)) + for _, l := range p.Locations.ToSlice() { + if locationSet.Contains(l) { // no need for duplicate locations + continue + } + locationSet.Add(l.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.SupportingEvidenceAnnotation)) + } + p.Locations = locationSet +} + +func collectSupportingEvidence(classifier Classifier, context MatcherContext, relativeFile file.Location, evidenceMatcher EvidenceMatcher) ([]pkg.Package, error) { + rdr, err := context.Resolver.FileContentsByLocation(relativeFile) + if err != nil { + return nil, err + } + defer internal.CloseAndLogError(rdr, relativeFile.Path()) + ur, err := unionreader.GetUnionReader(rdr) + if err != nil { + return nil, err + } + newContext := MatcherContext{ + Resolver: context.Resolver, + Location: relativeFile, + GetReader: func(_ MatcherContext) (unionreader.UnionReader, error) { + return ur, nil + }, + } + packages, err := evidenceMatcher(classifier, newContext) + if err != nil { + return nil, err + } + for i := range packages { + p := &(packages[i]) + // relative files are supporting evidence, like a VERSION file near a go binary, mark the results as supporting + makePrimaryLocation(p, context.Location) + } + return packages, nil +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/syft-1.40.1/syft/pkg/cataloger/internal/binutils/classifier_test.go new/syft-1.41.0/syft/pkg/cataloger/internal/binutils/classifier_test.go --- old/syft-1.40.1/syft/pkg/cataloger/internal/binutils/classifier_test.go 2026-01-15 22:33:35.000000000 +0100 +++ new/syft-1.41.0/syft/pkg/cataloger/internal/binutils/classifier_test.go 2026-01-27 11:14:26.000000000 +0100 @@ -12,6 +12,8 @@ "github.com/anchore/syft/syft/cpe" "github.com/anchore/syft/syft/file" "github.com/anchore/syft/syft/internal/unionreader" + "github.com/anchore/syft/syft/source" + "github.com/anchore/syft/syft/source/directorysource" ) func Test_ClassifierCPEs(t *testing.T) { @@ -27,7 +29,7 @@ classifier: Classifier{ Package: "some-app", FileGlob: "**/version.txt", - EvidenceMatcher: FileContentsVersionMatcher("cataloger-name", `(?m)my-verison:(?P<version>[0-9.]+)`), + EvidenceMatcher: FileContentsVersionMatcher("cataloger-name", `(?m)my-version:(?P<version>[0-9.]+)`), CPEs: []cpe.CPE{}, }, cpes: nil, @@ -38,7 +40,7 @@ classifier: Classifier{ Package: "some-app", FileGlob: "**/version.txt", - EvidenceMatcher: FileContentsVersionMatcher("cataloger-name", `(?m)my-verison:(?P<version>[0-9.]+)`), + EvidenceMatcher: FileContentsVersionMatcher("cataloger-name", `(?m)my-version:(?P<version>[0-9.]+)`), CPEs: []cpe.CPE{ cpe.Must("cpe:2.3:a:some:app:*:*:*:*:*:*:*:*", cpe.GeneratedSource), }, @@ -53,7 +55,7 @@ classifier: Classifier{ Package: "some-app", FileGlob: "**/version.txt", - EvidenceMatcher: FileContentsVersionMatcher("cataloger-name", `(?m)my-verison:(?P<version>[0-9.]+)`), + EvidenceMatcher: FileContentsVersionMatcher("cataloger-name", `(?m)my-version:(?P<version>[0-9.]+)`), CPEs: []cpe.CPE{ cpe.Must("cpe:2.3:a:some:app:*:*:*:*:*:*:*:*", cpe.GeneratedSource), cpe.Must("cpe:2.3:a:some:apps:*:*:*:*:*:*:*:*", cpe.GeneratedSource), @@ -182,4 +184,62 @@ } }) } +} + +func Test_SupportingEvidenceMatcher(t *testing.T) { + + tests := []struct { + name string + classifier Classifier + expected string + }{ + { + name: "simple version string regexp", + classifier: Classifier{ + FileGlob: "**/some-binary", + EvidenceMatcher: SupportingEvidenceMatcher("../version.txt", + FileContentsVersionMatcher("cataloger-name", `(?m)my-version:(?P<version>[0-9.]+)`)), + Package: "some-binary", + }, + expected: "1.8", + }, + { + name: "not matching version string regexp", + classifier: Classifier{ + FileGlob: "**/some-binary", + EvidenceMatcher: SupportingEvidenceMatcher("../version.txt", + FileContentsVersionMatcher("cataloger-name", `(?m)my-version:(?P<version>abdd)`)), + Package: "some-binary", + }, + expected: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s, err := directorysource.NewFromPath("test-fixtures") + require.NoError(t, err) + r, err := s.FileResolver(source.AllLayersScope) + require.NoError(t, err) + + results, err := r.FilesByGlob(tt.classifier.FileGlob) + require.NoError(t, err) + for _, result := range results { + got, err := tt.classifier.EvidenceMatcher(tt.classifier, MatcherContext{ + Resolver: r, + Location: result, + GetReader: func(ctx MatcherContext) (unionreader.UnionReader, error) { + return getReader(ctx) + }, + }) + require.NoError(t, err) + if tt.expected != "" { + require.NotEmpty(t, got) + require.Equal(t, tt.expected, got[0].Version) + } else { + require.Empty(t, got) + } + } + }) + } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/syft-1.40.1/syft/pkg/cataloger/internal/binutils/test-fixtures/subdir/some-binary new/syft-1.41.0/syft/pkg/cataloger/internal/binutils/test-fixtures/subdir/some-binary --- old/syft-1.40.1/syft/pkg/cataloger/internal/binutils/test-fixtures/subdir/some-binary 1970-01-01 01:00:00.000000000 +0100 +++ new/syft-1.41.0/syft/pkg/cataloger/internal/binutils/test-fixtures/subdir/some-binary 2026-01-27 11:14:26.000000000 +0100 @@ -0,0 +1 @@ +a binary \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/syft-1.40.1/syft/pkg/cataloger/internal/binutils/test-fixtures/version.txt new/syft-1.41.0/syft/pkg/cataloger/internal/binutils/test-fixtures/version.txt --- old/syft-1.40.1/syft/pkg/cataloger/internal/binutils/test-fixtures/version.txt 2026-01-15 22:33:35.000000000 +0100 +++ new/syft-1.41.0/syft/pkg/cataloger/internal/binutils/test-fixtures/version.txt 2026-01-27 11:14:26.000000000 +0100 @@ -1 +1 @@ -my-verison:1.8 \ No newline at end of file +my-version:1.8 \ No newline at end of file ++++++ syft.obsinfo ++++++ --- /var/tmp/diff_new_pack.Iv90Jf/_old 2026-01-28 15:12:58.444543987 +0100 +++ /var/tmp/diff_new_pack.Iv90Jf/_new 2026-01-28 15:12:58.448544153 +0100 @@ -1,5 +1,5 @@ name: syft -version: 1.40.1 -mtime: 1768512815 -commit: 63927ab49feea10a7fd88191acd615667227d338 +version: 1.41.0 +mtime: 1769508866 +commit: e8b4527bfbb7780cd70f2541fce4dca58803fb53 ++++++ vendor.tar.gz ++++++ /work/SRC/openSUSE:Factory/syft/vendor.tar.gz /work/SRC/openSUSE:Factory/.syft.new.1928/vendor.tar.gz differ: char 133, line 1
