Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package grype for openSUSE:Factory checked 
in at 2025-03-07 16:44:07
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/grype (Old)
 and      /work/SRC/openSUSE:Factory/.grype.new.19136 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "grype"

Fri Mar  7 16:44:07 2025 rev:85 rq:1251111 version:0.89.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/grype/grype.changes      2025-03-06 
14:50:01.436698625 +0100
+++ /work/SRC/openSUSE:Factory/.grype.new.19136/grype.changes   2025-03-07 
16:48:23.737060773 +0100
@@ -1,0 +2,17 @@
+Fri Mar 07 06:41:48 UTC 2025 - opensuse_buildserv...@ojkastl.de
+
+- Update to version 0.89.0:
+  * chore(deps): bump github.com/muesli/termenv from 0.15.2 to
+    0.16.0 (#2509)
+  * chore(deps): bump golang.org/x/tools from 0.30.0 to 0.31.0
+    (#2510)
+  * fix regression to allow for reading listing from local FS
+    (#2508)
+  * chore(deps): bump golang.org/x/time from 0.10.0 to 0.11.0
+    (#2503)
+  * chore(deps): update tools to latest versions (#2506)
+  * Add suggested fixed version when there are multiple fixes
+    available (#2271)
+  * remove v6 development configuration (#2504)
+
+-------------------------------------------------------------------

Old:
----
  grype-0.88.0.obscpio

New:
----
  grype-0.89.0.obscpio

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ grype.spec ++++++
--- /var/tmp/diff_new_pack.maZ307/_old  2025-03-07 16:48:25.253124753 +0100
+++ /var/tmp/diff_new_pack.maZ307/_new  2025-03-07 16:48:25.257124922 +0100
@@ -17,7 +17,7 @@
 
 
 Name:           grype
-Version:        0.88.0
+Version:        0.89.0
 Release:        0
 Summary:        A vulnerability scanner for container images and filesystems
 License:        Apache-2.0

++++++ _service ++++++
--- /var/tmp/diff_new_pack.maZ307/_old  2025-03-07 16:48:25.285126104 +0100
+++ /var/tmp/diff_new_pack.maZ307/_new  2025-03-07 16:48:25.289126272 +0100
@@ -3,7 +3,7 @@
     <param name="url">https://github.com/anchore/grype</param>
     <param name="scm">git</param>
     <param name="exclude">.git</param>
-    <param name="revision">v0.88.0</param>
+    <param name="revision">v0.89.0</param>
     <param name="match-tag">v*</param>
     <param name="versionformat">@PARENT_TAG@</param>
     <param name="versionrewrite-pattern">v(.*)</param>

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.maZ307/_old  2025-03-07 16:48:25.317127454 +0100
+++ /var/tmp/diff_new_pack.maZ307/_new  2025-03-07 16:48:25.321127623 +0100
@@ -1,6 +1,6 @@
 <servicedata>
 <service name="tar_scm">
                 <param name="url">https://github.com/anchore/grype</param>
-              <param 
name="changesrevision">6ee276f0c8363518c08b8d48fae302ee6001c295</param></service></servicedata>
+              <param 
name="changesrevision">1bf47c38bede40dea7b72bbe4712191820f1aa15</param></service></servicedata>
 (No newline at EOF)
 

++++++ grype-0.88.0.obscpio -> grype-0.89.0.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/grype-0.88.0/.binny.yaml new/grype-0.89.0/.binny.yaml
--- old/grype-0.88.0/.binny.yaml        2025-03-05 17:26:43.000000000 +0100
+++ new/grype-0.89.0/.binny.yaml        2025-03-06 17:12:29.000000000 +0100
@@ -98,7 +98,7 @@
   # used for triggering a release
   - name: gh
     version:
-      want: v2.67.0
+      want: v2.68.0
     method: github-release
     with:
       repo: cli/cli
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/grype-0.88.0/go.mod new/grype-0.89.0/go.mod
--- old/grype-0.88.0/go.mod     2025-03-05 17:26:43.000000000 +0100
+++ new/grype-0.89.0/go.mod     2025-03-06 17:12:29.000000000 +0100
@@ -64,14 +64,16 @@
        github.com/wagoodman/go-progress v0.0.0-20230925121702-07e42b3cdba0
        github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8
        golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56
-       golang.org/x/time v0.10.0
-       golang.org/x/tools v0.30.0
+       golang.org/x/time v0.11.0
+       golang.org/x/tools v0.31.0
        gopkg.in/yaml.v3 v3.0.1
        gorm.io/gorm v1.25.12
 )
 
 require github.com/DataDog/zstd v1.5.5 // indirect
 
+require github.com/muesli/termenv v0.16.0
+
 require (
        cel.dev/expr v0.16.1 // indirect
        cloud.google.com/go v0.116.0 // indirect
@@ -211,7 +213,6 @@
        github.com/moby/term v0.5.0 // indirect
        github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
        github.com/muesli/cancelreader v0.2.2 // indirect
-       github.com/muesli/termenv v0.15.2 // indirect
        github.com/ncruces/go-strftime v0.1.9 // indirect
        github.com/nwaples/rardecode v1.1.3 // indirect
        github.com/opencontainers/go-digest v1.0.0 // indirect
@@ -274,14 +275,14 @@
        go.opentelemetry.io/otel/trace v1.33.0 // indirect
        go.uber.org/atomic v1.9.0 // indirect
        go.uber.org/multierr v1.9.0 // indirect
-       golang.org/x/crypto v0.33.0 // indirect
-       golang.org/x/mod v0.23.0 // indirect
-       golang.org/x/net v0.35.0 // indirect
+       golang.org/x/crypto v0.36.0 // indirect
+       golang.org/x/mod v0.24.0 // indirect
+       golang.org/x/net v0.37.0 // indirect
        golang.org/x/oauth2 v0.25.0 // indirect
-       golang.org/x/sync v0.11.0 // indirect
-       golang.org/x/sys v0.30.0 // indirect
-       golang.org/x/term v0.29.0 // indirect
-       golang.org/x/text v0.22.0 // indirect
+       golang.org/x/sync v0.12.0 // indirect
+       golang.org/x/sys v0.31.0 // indirect
+       golang.org/x/term v0.30.0 // indirect
+       golang.org/x/text v0.23.0 // indirect
        golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
        google.golang.org/api v0.215.0 // indirect
        google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 // 
indirect
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/grype-0.88.0/go.sum new/grype-0.89.0/go.sum
--- old/grype-0.88.0/go.sum     2025-03-05 17:26:43.000000000 +0100
+++ new/grype-0.89.0/go.sum     2025-03-06 17:12:29.000000000 +0100
@@ -1337,8 +1337,8 @@
 github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod 
h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
 github.com/muesli/cancelreader v0.2.2 
h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
 github.com/muesli/cancelreader v0.2.2/go.mod 
h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
-github.com/muesli/termenv v0.15.2 
h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
-github.com/muesli/termenv v0.15.2/go.mod 
h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
+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=
@@ -1649,8 +1649,8 @@
 golang.org/x/crypto v0.19.0/go.mod 
h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
 golang.org/x/crypto v0.23.0/go.mod 
h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
 golang.org/x/crypto v0.32.0/go.mod 
h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
-golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
-golang.org/x/crypto v0.33.0/go.mod 
h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
+golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
+golang.org/x/crypto v0.36.0/go.mod 
h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
 golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod 
h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod 
h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod 
h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -1713,8 +1713,8 @@
 golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
 golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
 golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
-golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM=
-golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
+golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
+golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
 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=
@@ -1784,8 +1784,8 @@
 golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
 golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
 golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
-golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
-golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
+golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
+golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
 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=
@@ -1838,8 +1838,8 @@
 golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
 golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
 golang.org/x/sync v0.10.0/go.mod 
h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
-golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
-golang.org/x/sync v0.11.0/go.mod 
h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
+golang.org/x/sync v0.12.0/go.mod 
h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
 golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod 
h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod 
h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod 
h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -1943,8 +1943,8 @@
 golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
-golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
+golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
 golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod 
h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod 
h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod 
h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -1960,8 +1960,8 @@
 golang.org/x/term v0.17.0/go.mod 
h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
 golang.org/x/term v0.20.0/go.mod 
h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
 golang.org/x/term v0.28.0/go.mod 
h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
-golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
-golang.org/x/term v0.29.0/go.mod 
h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
+golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y=
+golang.org/x/term v0.30.0/go.mod 
h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod 
h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod 
h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -1983,16 +1983,16 @@
 golang.org/x/text v0.14.0/go.mod 
h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
 golang.org/x/text v0.15.0/go.mod 
h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
 golang.org/x/text v0.21.0/go.mod 
h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
-golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
-golang.org/x/text v0.22.0/go.mod 
h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
+golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
+golang.org/x/text v0.23.0/go.mod 
h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod 
h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod 
h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod 
h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod 
h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.10.0 h1:3usCWA8tQn0L8+hFJQNgzpWbd89begxN66o1Ojdn5L4=
-golang.org/x/time v0.10.0/go.mod 
h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
+golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
+golang.org/x/time v0.11.0/go.mod 
h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
 golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod 
h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod 
h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod 
h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -2059,8 +2059,8 @@
 golang.org/x/tools v0.7.0/go.mod 
h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
 golang.org/x/tools v0.13.0/go.mod 
h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
 golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod 
h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
-golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY=
-golang.org/x/tools v0.30.0/go.mod 
h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY=
+golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU=
+golang.org/x/tools v0.31.0/go.mod 
h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ=
 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=
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/grype-0.88.0/grype/db/v6/distribution/client.go 
new/grype-0.89.0/grype/db/v6/distribution/client.go
--- old/grype-0.88.0/grype/db/v6/distribution/client.go 2025-03-05 
17:26:43.000000000 +0100
+++ new/grype-0.89.0/grype/db/v6/distribution/client.go 2025-03-06 
17:12:29.000000000 +0100
@@ -44,10 +44,10 @@
 }
 
 type client struct {
-       fs               afero.Fs
-       latestHTTPClient *http.Client
-       updateDownloader file.Getter
-       config           Config
+       fs                afero.Fs
+       dbDownloader      file.Getter
+       listingDownloader file.Getter
+       config            Config
 }
 
 func DefaultConfig() Config {
@@ -72,10 +72,10 @@
        }
 
        return client{
-               fs:               fs,
-               latestHTTPClient: latestClient,
-               updateDownloader: file.NewGetter(cfg.ID, dbClient),
-               config:           cfg,
+               fs:                fs,
+               listingDownloader: file.NewGetter(cfg.ID, latestClient),
+               dbDownloader:      file.NewGetter(cfg.ID, dbClient),
+               config:            cfg,
        }, nil
 }
 
@@ -157,7 +157,7 @@
        u.RawQuery = query.Encode()
 
        // go-getter will automatically extract all files within the archive to 
the temp dir
-       err = c.updateDownloader.GetToDir(tempDir, u.String(), downloadProgress)
+       err = c.dbDownloader.GetToDir(tempDir, u.String(), downloadProgress)
        if err != nil {
                removeAllOrLog(afero.NewOsFs(), tempDir)
                return "", fmt.Errorf("unable to download db: %w", err)
@@ -168,17 +168,23 @@
 
 // Latest loads a LatestDocument from the configured URL.
 func (c client) Latest() (*LatestDocument, error) {
-       resp, err := c.latestHTTPClient.Get(c.latestURL())
+       tempFile, err := afero.TempFile(c.fs, "", "grype-db-listing")
        if err != nil {
-               return nil, fmt.Errorf("unable to fetch latest.json: %w", err)
-       }
-       if resp.StatusCode != http.StatusOK {
-               return nil, fmt.Errorf("unable to fetch latest.json: %s", 
resp.Status)
+               return nil, fmt.Errorf("unable to create listing temp file: 
%w", err)
        }
+       defer func() {
+               err := c.fs.RemoveAll(tempFile.Name())
+               if err != nil {
+                       log.WithFields("error", err, "file", 
tempFile.Name()).Errorf("failed to remove file")
+               }
+       }()
 
-       defer func() { _ = resp.Body.Close() }()
+       err = c.listingDownloader.GetFile(tempFile.Name(), c.latestURL())
+       if err != nil {
+               return nil, fmt.Errorf("unable to download listing: %w", err)
+       }
 
-       return NewLatestFromReader(resp.Body)
+       return NewLatestFromFile(c.fs, tempFile.Name())
 }
 
 func (c client) latestURL() string {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/grype-0.88.0/grype/db/v6/distribution/client_test.go 
new/grype-0.89.0/grype/db/v6/distribution/client_test.go
--- old/grype-0.88.0/grype/db/v6/distribution/client_test.go    2025-03-05 
17:26:43.000000000 +0100
+++ new/grype-0.89.0/grype/db/v6/distribution/client_test.go    2025-03-06 
17:12:29.000000000 +0100
@@ -3,12 +3,11 @@
 import (
        "encoding/json"
        "errors"
-       "net/http"
-       "net/http/httptest"
        "path/filepath"
        "testing"
        "time"
 
+       "github.com/spf13/afero"
        "github.com/stretchr/testify/assert"
        "github.com/stretchr/testify/mock"
        "github.com/stretchr/testify/require"
@@ -18,16 +17,31 @@
        "github.com/anchore/grype/internal/schemaver"
 )
 
-func TestClient_LatestFromURL(t *testing.T) {
+type mockGetter struct {
+       mock.Mock
+}
+
+func (m *mockGetter) GetFile(dst, src string, manuals ...*progress.Manual) 
error {
+       args := m.Called(dst, src, manuals)
+       return args.Error(0)
+}
+
+func (m *mockGetter) GetToDir(dst, src string, manuals ...*progress.Manual) 
error {
+       args := m.Called(dst, src, manuals)
+       return args.Error(0)
+}
+
+func TestClient_Latest(t *testing.T) {
        tests := []struct {
-               name        string
-               setupServer func() *httptest.Server
-               expectedDoc *LatestDocument
-               expectedErr require.ErrorAssertionFunc
+               name           string
+               latestResponse []byte
+               getFileErr     error
+               expectedDoc    *LatestDocument
+               expectedErr    require.ErrorAssertionFunc
        }{
                {
                        name: "go case",
-                       setupServer: func() *httptest.Server {
+                       latestResponse: func() []byte {
                                doc := LatestDocument{
                                        Status: "active",
                                        Archive: Archive{
@@ -39,15 +53,10 @@
                                                Checksum: "checksum123",
                                        },
                                }
-                               data, _ := json.Marshal(doc)
-
-                               return 
httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r 
*http.Request) {
-                                       w.WriteHeader(http.StatusOK)
-                                       w.Header().Set("Content-Type", 
"application/json")
-                                       _, err := w.Write(data)
-                                       require.NoError(t, err)
-                               }))
-                       },
+                               data, err := json.Marshal(doc)
+                               require.NoError(t, err)
+                               return data
+                       }(),
                        expectedDoc: &LatestDocument{
                                Status: "active",
                                Archive: Archive{
@@ -61,28 +70,18 @@
                        },
                },
                {
-                       name: "error response",
-                       setupServer: func() *httptest.Server {
-                               return 
httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r 
*http.Request) {
-                                       
w.WriteHeader(http.StatusInternalServerError)
-                               }))
-                       },
+                       name:        "download error",
+                       getFileErr:  errors.New("failed to download file"),
                        expectedDoc: nil,
                        expectedErr: func(t require.TestingT, err error, _ 
...interface{}) {
                                require.Error(t, err)
-                               require.Contains(t, err.Error(), "500 Internal 
Server Error")
+                               require.Contains(t, err.Error(), "unable to 
download listing")
                        },
                },
                {
-                       name: "malformed JSON response",
-                       setupServer: func() *httptest.Server {
-                               return 
httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r 
*http.Request) {
-                                       w.WriteHeader(http.StatusOK)
-                                       _, err := w.Write([]byte("malformed 
json"))
-                                       require.NoError(t, err)
-                               }))
-                       },
-                       expectedDoc: nil,
+                       name:           "malformed JSON response",
+                       latestResponse: []byte("malformed json"),
+                       expectedDoc:    nil,
                        expectedErr: func(t require.TestingT, err error, _ 
...interface{}) {
                                require.Error(t, err)
                                require.Contains(t, err.Error(), "invalid 
character 'm' looking for beginning of value")
@@ -95,16 +94,28 @@
                        if tt.expectedErr == nil {
                                tt.expectedErr = require.NoError
                        }
+                       mockFs := afero.NewMemMapFs()
+
+                       mg := new(mockGetter)
 
-                       server := tt.setupServer()
-                       defer server.Close()
+                       mg.On("GetFile", mock.Anything, 
"http://localhost:8080/latest.json";, mock.Anything).Run(func(args 
mock.Arguments) {
+                               if tt.getFileErr != nil {
+                                       return
+                               }
+
+                               dst := args.String(0)
+                               err := afero.WriteFile(mockFs, dst, 
tt.latestResponse, 0644)
+                               require.NoError(t, err)
+                       }).Return(tt.getFileErr)
 
                        c, err := NewClient(Config{
-                               LatestURL: server.URL,
+                               LatestURL: "http://localhost:8080/latest.json";,
                        })
                        require.NoError(t, err)
 
                        cl := c.(client)
+                       cl.fs = mockFs
+                       cl.listingDownloader = mg
 
                        doc, err := cl.Latest()
                        tt.expectedErr(t, err)
@@ -113,24 +124,11 @@
                        }
 
                        require.Equal(t, tt.expectedDoc, doc)
+                       mg.AssertExpectations(t)
                })
        }
 }
 
-type mockGetter struct {
-       mock.Mock
-}
-
-func (m *mockGetter) GetFile(dst, src string, manuals ...*progress.Manual) 
error {
-       args := m.Called(dst, src, manuals)
-       return args.Error(0)
-}
-
-func (m *mockGetter) GetToDir(dst, src string, manuals ...*progress.Manual) 
error {
-       args := m.Called(dst, src, manuals)
-       return args.Error(0)
-}
-
 func TestClient_Download(t *testing.T) {
        destDir := t.TempDir()
        archive := &Archive{
@@ -147,7 +145,7 @@
                require.NoError(t, err)
 
                cl := c.(client)
-               cl.updateDownloader = mg
+               cl.dbDownloader = mg
 
                return cl, mg
        }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/grype-0.88.0/grype/db/v6/distribution/latest.go 
new/grype-0.89.0/grype/db/v6/distribution/latest.go
--- old/grype-0.88.0/grype/db/v6/distribution/latest.go 2025-03-05 
17:26:43.000000000 +0100
+++ new/grype-0.89.0/grype/db/v6/distribution/latest.go 2025-03-06 
17:12:29.000000000 +0100
@@ -74,6 +74,15 @@
        return &l, nil
 }
 
+func NewLatestFromFile(fs afero.Fs, path string) (*LatestDocument, error) {
+       fh, err := fs.Open(path)
+       if err != nil {
+               return nil, fmt.Errorf("failed to read listing file: %w", err)
+       }
+       defer fh.Close()
+       return NewLatestFromReader(fh)
+}
+
 func NewArchive(path string, t time.Time, model, revision, addition int) 
(*Archive, error) {
        checksum, err := calculateArchiveDigest(path)
        if err != nil {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/grype-0.88.0/grype/presenter/internal/test_helpers.go 
new/grype-0.89.0/grype/presenter/internal/test_helpers.go
--- old/grype-0.88.0/grype/presenter/internal/test_helpers.go   2025-03-05 
17:26:43.000000000 +0100
+++ new/grype-0.89.0/grype/presenter/internal/test_helpers.go   2025-03-06 
17:12:29.000000000 +0100
@@ -111,7 +111,7 @@
                                        Namespace: "source-1",
                                },
                                Fix: vulnerability.Fix{
-                                       Versions: []string{"the-next-version"},
+                                       Versions: []string{"1.2.1", "2.1.3", 
"3.4.0"},
                                        State:    vulnerability.FixStateFixed,
                                },
                        },
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/grype-0.88.0/grype/presenter/json/test-fixtures/snapshot/TestJsonDirsPresenter.golden
 
new/grype-0.89.0/grype/presenter/json/test-fixtures/snapshot/TestJsonDirsPresenter.golden
--- 
old/grype-0.88.0/grype/presenter/json/test-fixtures/snapshot/TestJsonDirsPresenter.golden
   2025-03-05 17:26:43.000000000 +0100
+++ 
new/grype-0.89.0/grype/presenter/json/test-fixtures/snapshot/TestJsonDirsPresenter.golden
   2025-03-06 17:12:29.000000000 +0100
@@ -20,7 +20,9 @@
     ],
     "fix": {
      "versions": [
-      "the-next-version"
+      "1.2.1",
+      "2.1.3",
+      "3.4.0"
      ],
      "state": "fixed"
     },
@@ -39,6 +41,9 @@
      },
      "found": {
       "constraint": ">= 20"
+     },
+     "fix": {
+      "suggestedVersion": "1.2.1"
      }
     }
    ],
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/grype-0.88.0/grype/presenter/json/test-fixtures/snapshot/TestJsonImgsPresenter.golden
 
new/grype-0.89.0/grype/presenter/json/test-fixtures/snapshot/TestJsonImgsPresenter.golden
--- 
old/grype-0.88.0/grype/presenter/json/test-fixtures/snapshot/TestJsonImgsPresenter.golden
   2025-03-05 17:26:43.000000000 +0100
+++ 
new/grype-0.89.0/grype/presenter/json/test-fixtures/snapshot/TestJsonImgsPresenter.golden
   2025-03-06 17:12:29.000000000 +0100
@@ -20,7 +20,9 @@
     ],
     "fix": {
      "versions": [
-      "the-next-version"
+      "1.2.1",
+      "2.1.3",
+      "3.4.0"
      ],
      "state": "fixed"
     },
@@ -39,6 +41,9 @@
      },
      "found": {
       "constraint": ">= 20"
+     },
+     "fix": {
+      "suggestedVersion": "1.2.1"
      }
     }
    ],
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/grype-0.88.0/grype/presenter/models/document_test.go 
new/grype-0.89.0/grype/presenter/models/document_test.go
--- old/grype-0.88.0/grype/presenter/models/document_test.go    2025-03-05 
17:26:43.000000000 +0100
+++ new/grype-0.89.0/grype/presenter/models/document_test.go    2025-03-06 
17:12:29.000000000 +0100
@@ -103,6 +103,55 @@
        assert.Equal(t, []string{"CVE-1999-0001", "CVE-1999-0003", 
"CVE-1999-0002"}, actualVulnerabilities)
 }
 
+func TestFixSuggestedVersion(t *testing.T) {
+
+       var pkg1 = pkg.Package{
+               ID:      "package-1-id",
+               Name:    "package-1",
+               Version: "1.1.1",
+               Type:    syftPkg.PythonPkg,
+       }
+
+       var match1 = match.Match{
+               Vulnerability: vulnerability.Vulnerability{
+                       Fix: vulnerability.Fix{
+                               Versions: []string{"1.0.0", "1.2.0", "1.1.2"},
+                       },
+                       Reference: vulnerability.Reference{ID: "CVE-1999-0003"},
+               },
+               Package: pkg1,
+               Details: match.Details{
+                       {
+                               Type: match.ExactDirectMatch,
+                       },
+               },
+       }
+
+       matches := match.NewMatches()
+       matches.Add(match1)
+
+       packages := []pkg.Package{pkg1}
+
+       ctx := pkg.Context{
+               Source: &syftSource.Description{
+                       Metadata: syftSource.DirectoryMetadata{},
+               },
+               Distro: &linux.Release{
+                       ID:      "centos",
+                       IDLike:  []string{"rhel"},
+                       Version: "8.0",
+               },
+       }
+       doc, err := NewDocument(clio.Identification{}, packages, ctx, matches, 
nil, NewMetadataMock(), nil, nil, SortByPackage)
+       if err != nil {
+               t.Fatalf("unable to get document: %+v", err)
+       }
+
+       actualSuggestedFixedVersion := 
doc.Matches[0].MatchDetails[0].Fix.SuggestedVersion
+
+       assert.Equal(t, "1.1.2", actualSuggestedFixedVersion)
+}
+
 func TestTimestampValidFormat(t *testing.T) {
 
        matches := match.NewMatches()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/grype-0.88.0/grype/presenter/models/match.go 
new/grype-0.89.0/grype/presenter/models/match.go
--- old/grype-0.88.0/grype/presenter/models/match.go    2025-03-05 
17:26:43.000000000 +0100
+++ new/grype-0.89.0/grype/presenter/models/match.go    2025-03-06 
17:12:29.000000000 +0100
@@ -2,10 +2,13 @@
 
 import (
        "fmt"
+       "sort"
 
        "github.com/anchore/grype/grype/match"
        "github.com/anchore/grype/grype/pkg"
+       "github.com/anchore/grype/grype/version"
        "github.com/anchore/grype/grype/vulnerability"
+       "github.com/anchore/grype/internal/log"
 )
 
 // Match is a single item for the JSON array reported
@@ -22,6 +25,12 @@
        Matcher    string      `json:"matcher"`
        SearchedBy interface{} `json:"searchedBy"` // The specific attributes 
that were used to search (other than package name and version) --this indicates 
"how" the match was made.
        Found      interface{} `json:"found"`      // The specific attributes 
on the vulnerability object that were matched with --this indicates "what" was 
matched on / within.
+       Fix        *FixDetails `json:"fix,omitempty"`
+}
+
+// FixDetails contains any data that is relevant to fixing the vulnerability 
specific to the package searched with
+type FixDetails struct {
+       SuggestedVersion string `json:"suggestedVersion"`
 }
 
 func newMatch(m match.Match, p pkg.Package, metadataProvider 
vulnerability.MetadataProvider) (*Match, error) {
@@ -47,6 +56,8 @@
                }
        }
 
+       format := version.FormatFromPkg(p)
+
        details := make([]MatchDetails, len(m.Details))
        for idx, d := range m.Details {
                details[idx] = MatchDetails{
@@ -54,13 +65,79 @@
                        Matcher:    string(d.Matcher),
                        SearchedBy: d.SearchedBy,
                        Found:      d.Found,
+                       Fix:        getFix(m, p, format),
                }
        }
 
        return &Match{
-               Vulnerability:          NewVulnerability(m.Vulnerability, 
metadata),
+               Vulnerability:          NewVulnerability(m.Vulnerability, 
metadata, format),
                Artifact:               newPackage(p),
                RelatedVulnerabilities: relatedVulnerabilities,
                MatchDetails:           details,
        }, nil
 }
+
+func getFix(m match.Match, p pkg.Package, format version.Format) *FixDetails {
+       suggested := calculateSuggestedFixedVersion(p, 
m.Vulnerability.Fix.Versions, format)
+       if suggested == "" {
+               return nil
+       }
+       return &FixDetails{
+               SuggestedVersion: suggested,
+       }
+}
+
+func calculateSuggestedFixedVersion(p pkg.Package, fixedVersions []string, 
format version.Format) string {
+       if len(fixedVersions) == 0 {
+               return ""
+       }
+
+       if len(fixedVersions) == 1 {
+               return fixedVersions[0]
+       }
+
+       parseConstraint := func(constStr string) (version.Constraint, error) {
+               constraint, err := version.GetConstraint(constStr, format)
+               if err != nil {
+                       log.WithFields("package", p.Name).Trace("skipping 
sorting fixed versions")
+               }
+               return constraint, err
+       }
+
+       checkSatisfaction := func(constraint version.Constraint, v 
*version.Version) bool {
+               satisfied, err := constraint.Satisfied(v)
+               if err != nil {
+                       log.WithFields("package", p.Name).Trace("error while 
checking version satisfaction for sorting")
+               }
+               return satisfied && err == nil
+       }
+
+       sort.SliceStable(fixedVersions, func(i, j int) bool {
+               v1, err1 := version.NewVersion(fixedVersions[i], format)
+               v2, err2 := version.NewVersion(fixedVersions[j], format)
+               if err1 != nil || err2 != nil {
+                       log.WithFields("package", p.Name).Trace("error while 
parsing version for sorting")
+                       return false
+               }
+
+               packageConstraint, err := parseConstraint(fmt.Sprintf("<=%s", 
p.Version))
+               if err != nil {
+                       return false
+               }
+
+               v1Satisfied := checkSatisfaction(packageConstraint, v1)
+               v2Satisfied := checkSatisfaction(packageConstraint, v2)
+
+               if v1Satisfied != v2Satisfied {
+                       return !v1Satisfied
+               }
+
+               internalConstraint, err := parseConstraint(fmt.Sprintf("<=%s", 
v1.Raw))
+               if err != nil {
+                       return false
+               }
+               return !checkSatisfaction(internalConstraint, v2)
+       })
+
+       return fixedVersions[0]
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/grype-0.88.0/grype/presenter/models/vulnerability.go 
new/grype-0.89.0/grype/presenter/models/vulnerability.go
--- old/grype-0.88.0/grype/presenter/models/vulnerability.go    2025-03-05 
17:26:43.000000000 +0100
+++ new/grype-0.89.0/grype/presenter/models/vulnerability.go    2025-03-06 
17:12:29.000000000 +0100
@@ -1,7 +1,11 @@
 package models
 
 import (
+       "sort"
+
+       "github.com/anchore/grype/grype/version"
        "github.com/anchore/grype/grype/vulnerability"
+       "github.com/anchore/grype/internal/log"
 )
 
 type Vulnerability struct {
@@ -20,7 +24,7 @@
        Link string `json:"link"`
 }
 
-func NewVulnerability(vuln vulnerability.Vulnerability, metadata 
*vulnerability.Metadata) Vulnerability {
+func NewVulnerability(vuln vulnerability.Vulnerability, metadata 
*vulnerability.Metadata, versionFormat version.Format) Vulnerability {
        if metadata == nil {
                return Vulnerability{
                        VulnerabilityMetadata: 
NewVulnerabilityMetadata(vuln.ID, vuln.Namespace, metadata),
@@ -44,9 +48,45 @@
        return Vulnerability{
                VulnerabilityMetadata: NewVulnerabilityMetadata(vuln.ID, 
vuln.Namespace, metadata),
                Fix: Fix{
-                       Versions: fixedInVersions,
+                       Versions: sortVersions(fixedInVersions, versionFormat),
                        State:    string(vuln.Fix.State),
                },
                Advisories: advisories,
        }
 }
+func sortVersions(fixedVersions []string, format version.Format) []string {
+       if len(fixedVersions) <= 1 {
+               return fixedVersions
+       }
+
+       // First, create Version objects from strings (only once)
+       versionObjs := make([]*version.Version, 0, len(fixedVersions))
+       for _, vStr := range fixedVersions {
+               v, err := version.NewVersion(vStr, format)
+               if err != nil {
+                       log.WithFields("version", vStr, "error", 
err).Trace("error parsing version, skipping")
+                       continue
+               }
+               versionObjs = append(versionObjs, v)
+       }
+
+       // Sort the Version objects
+       sort.Slice(versionObjs, func(i, j int) bool {
+               // Compare returns -1 if v[i] < v[j], so we negate for 
descending order
+               // (higher versions first)
+               comparison, err := versionObjs[i].Compare(versionObjs[j])
+               if err != nil {
+                       log.WithFields("error", err).Trace("error comparing 
versions")
+                       return false
+               }
+               return comparison > 0 // Descending order
+       })
+
+       // Convert back to strings
+       result := make([]string, len(versionObjs))
+       for i, v := range versionObjs {
+               result[i] = v.Raw
+       }
+
+       return result
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/grype-0.88.0/grype/presenter/sarif/test-fixtures/snapshot/TestSarifPresenter_directory.golden
 
new/grype-0.89.0/grype/presenter/sarif/test-fixtures/snapshot/TestSarifPresenter_directory.golden
--- 
old/grype-0.88.0/grype/presenter/sarif/test-fixtures/snapshot/TestSarifPresenter_directory.golden
   2025-03-05 17:26:43.000000000 +0100
+++ 
new/grype-0.89.0/grype/presenter/sarif/test-fixtures/snapshot/TestSarifPresenter_directory.golden
   2025-03-06 17:12:29.000000000 +0100
@@ -20,8 +20,8 @@
               },
               "helpUri": "https://github.com/anchore/grype";,
               "help": {
-                "text": "Vulnerability CVE-1999-0001\nSeverity: low\nPackage: 
package-1\nVersion: 1.1.1\nFix Version: the-next-version\nType: rpm\nLocation: 
/some/path/somefile-1.txt\nData Namespace: source-1\nLink: CVE-1999-0001",
-                "markdown": "**Vulnerability CVE-1999-0001**\n| Severity | 
Package | Version | Fix Version | Type | Location | Data Namespace | Link |\n| 
--- | --- | --- | --- | --- | --- | --- | --- |\n| low  | package-1  | 1.1.1  | 
the-next-version  | rpm  | /some/path/somefile-1.txt  | source-1  | 
CVE-1999-0001  |\n"
+                "text": "Vulnerability CVE-1999-0001\nSeverity: low\nPackage: 
package-1\nVersion: 1.1.1\nFix Version: 1.2.1,2.1.3,3.4.0\nType: rpm\nLocation: 
/some/path/somefile-1.txt\nData Namespace: source-1\nLink: CVE-1999-0001",
+                "markdown": "**Vulnerability CVE-1999-0001**\n| Severity | 
Package | Version | Fix Version | Type | Location | Data Namespace | Link |\n| 
--- | --- | --- | --- | --- | --- | --- | --- |\n| low  | package-1  | 1.1.1  | 
1.2.1,2.1.3,3.4.0  | rpm  | /some/path/somefile-1.txt  | source-1  | 
CVE-1999-0001  |\n"
               },
               "properties": {
                 "security-severity": "4.0"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/grype-0.88.0/grype/presenter/sarif/test-fixtures/snapshot/TestSarifPresenter_image.golden
 
new/grype-0.89.0/grype/presenter/sarif/test-fixtures/snapshot/TestSarifPresenter_image.golden
--- 
old/grype-0.88.0/grype/presenter/sarif/test-fixtures/snapshot/TestSarifPresenter_image.golden
       2025-03-05 17:26:43.000000000 +0100
+++ 
new/grype-0.89.0/grype/presenter/sarif/test-fixtures/snapshot/TestSarifPresenter_image.golden
       2025-03-06 17:12:29.000000000 +0100
@@ -20,8 +20,8 @@
               },
               "helpUri": "https://github.com/anchore/grype";,
               "help": {
-                "text": "Vulnerability CVE-1999-0001\nSeverity: low\nPackage: 
package-1\nVersion: 1.1.1\nFix Version: the-next-version\nType: rpm\nLocation: 
somefile-1.txt\nData Namespace: source-1\nLink: CVE-1999-0001",
-                "markdown": "**Vulnerability CVE-1999-0001**\n| Severity | 
Package | Version | Fix Version | Type | Location | Data Namespace | Link |\n| 
--- | --- | --- | --- | --- | --- | --- | --- |\n| low  | package-1  | 1.1.1  | 
the-next-version  | rpm  | somefile-1.txt  | source-1  | CVE-1999-0001  |\n"
+                "text": "Vulnerability CVE-1999-0001\nSeverity: low\nPackage: 
package-1\nVersion: 1.1.1\nFix Version: 1.2.1,2.1.3,3.4.0\nType: rpm\nLocation: 
somefile-1.txt\nData Namespace: source-1\nLink: CVE-1999-0001",
+                "markdown": "**Vulnerability CVE-1999-0001**\n| Severity | 
Package | Version | Fix Version | Type | Location | Data Namespace | Link |\n| 
--- | --- | --- | --- | --- | --- | --- | --- |\n| low  | package-1  | 1.1.1  | 
1.2.1,2.1.3,3.4.0  | rpm  | somefile-1.txt  | source-1  | CVE-1999-0001  |\n"
               },
               "properties": {
                 "security-severity": "4.0"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/grype-0.88.0/grype/presenter/table/__snapshots__/presenter_test.snap 
new/grype-0.89.0/grype/presenter/table/__snapshots__/presenter_test.snap
--- old/grype-0.88.0/grype/presenter/table/__snapshots__/presenter_test.snap    
2025-03-05 17:26:43.000000000 +0100
+++ new/grype-0.89.0/grype/presenter/table/__snapshots__/presenter_test.snap    
2025-03-06 17:12:29.000000000 +0100
@@ -1,15 +1,15 @@
 
 [TestTablePresenter/no_color - 1]
-NAME       INSTALLED  FIXED-IN          TYPE  VULNERABILITY  SEVERITY 
-package-1  1.1.1      the-next-version  rpm   CVE-1999-0001  Low       
-package-2  2.2.2                        deb   CVE-1999-0002  Critical  
+NAME       INSTALLED  FIXED-IN              TYPE  VULNERABILITY  SEVERITY 
+package-1  1.1.1      *1.2.1, 2.1.3, 3.4.0  rpm   CVE-1999-0001  Low       
+package-2  2.2.2                            deb   CVE-1999-0002  Critical  
 
 ---
 
 [TestTablePresenter/with_color - 1]
-NAME       INSTALLED  FIXED-IN          TYPE  VULNERABILITY  SEVERITY 
-package-1  1.1.1      the-next-version  rpm   CVE-1999-0001  Low    
   
-package-2  2.2.2                        deb   CVE-1999-0002  
Critical  
+NAME       INSTALLED  FIXED-IN             TYPE  VULNERABILITY  SEVERITY 
+package-1  1.1.1      
1.2.1,
 2.1.3, 3.4.0  rpm   CVE-1999-0001  Low       
+package-2  2.2.2                           deb   CVE-1999-0002  
Critical  
 
 ---
 
@@ -19,18 +19,18 @@
 ---
 
 [TestHidesIgnoredMatches - 1]
-NAME       INSTALLED  FIXED-IN          TYPE  VULNERABILITY  SEVERITY 
-package-1  1.1.1      the-next-version  rpm   CVE-1999-0001  Low       
-package-2  2.2.2                        deb   CVE-1999-0002  Critical  
+NAME       INSTALLED  FIXED-IN              TYPE  VULNERABILITY  SEVERITY 
+package-1  1.1.1      *1.2.1, 2.1.3, 3.4.0  rpm   CVE-1999-0001  Low       
+package-2  2.2.2                            deb   CVE-1999-0002  Critical  
 
 ---
 
 [TestDisplaysIgnoredMatches - 1]
-NAME       INSTALLED  FIXED-IN          TYPE  VULNERABILITY  SEVERITY          
           
-package-1  1.1.1      the-next-version  rpm   CVE-1999-0001  Low               
            
-package-2  2.2.2                        deb   CVE-1999-0002  Critical          
            
-package-2  2.2.2                        deb   CVE-1999-0001  Low (suppressed)  
            
-package-2  2.2.2                        deb   CVE-1999-0002  Critical 
(suppressed)         
-package-2  2.2.2                        deb   CVE-1999-0004  Critical 
(suppressed by VEX)  
+NAME       INSTALLED  FIXED-IN              TYPE  VULNERABILITY  SEVERITY      
               
+package-1  1.1.1      *1.2.1, 2.1.3, 3.4.0  rpm   CVE-1999-0001  Low           
                
+package-2  2.2.2                            deb   CVE-1999-0002  Critical      
                
+package-2  2.2.2                            deb   CVE-1999-0001  Low 
(suppressed)              
+package-2  2.2.2                            deb   CVE-1999-0002  Critical 
(suppressed)         
+package-2  2.2.2                            deb   CVE-1999-0004  Critical 
(suppressed by VEX)  
 
 ---
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/grype-0.88.0/grype/presenter/table/presenter.go 
new/grype-0.89.0/grype/presenter/table/presenter.go
--- old/grype-0.88.0/grype/presenter/table/presenter.go 2025-03-05 
17:26:43.000000000 +0100
+++ new/grype-0.89.0/grype/presenter/table/presenter.go 2025-03-06 
17:12:29.000000000 +0100
@@ -6,6 +6,7 @@
 
        "github.com/charmbracelet/lipgloss"
        "github.com/olekukonko/tablewriter"
+       "github.com/scylladb/go-set/strset"
 
        "github.com/anchore/grype/grype/presenter/models"
        "github.com/anchore/grype/grype/vulnerability"
@@ -21,20 +22,39 @@
        document       models.Document
        showSuppressed bool
        withColor      bool
+
+       recommendedFixStyle lipgloss.Style
+}
+
+type rows []row
+
+type row struct {
+       Name            string
+       Version         string
+       Fix             string
+       PackageType     string
+       VulnerabilityID string
+       Severity        string
 }
 
 // NewPresenter is a *Presenter constructor
 func NewPresenter(pb models.PresenterConfig, showSuppressed bool) *Presenter {
+       withColor := supportsColor()
+       fixStyle := lipgloss.NewStyle().Border(lipgloss.Border{Left: "*"}, 
false, false, false, true)
+       if withColor {
+               fixStyle = 
lipgloss.NewStyle().Foreground(lipgloss.Color("6")).Bold(true).Underline(true)
+       }
        return &Presenter{
-               document:       pb.Document,
-               showSuppressed: showSuppressed,
-               withColor:      supportsColor(),
+               document:            pb.Document,
+               showSuppressed:      showSuppressed,
+               withColor:           withColor,
+               recommendedFixStyle: fixStyle,
        }
 }
 
 // Present creates a JSON-based reporting
 func (p *Presenter) Present(output io.Writer) error {
-       rs := getRows(p.document, p.showSuppressed)
+       rs := p.getRows(p.document, p.showSuppressed)
 
        if len(rs) == 0 {
                _, err := io.WriteString(output, "No vulnerabilities found\n")
@@ -57,9 +77,16 @@
        table.SetNoWhiteSpace(true)
 
        if p.withColor {
-               for _, row := range rs.Render() {
-                       severityColor := getSeverityColor(row[len(row)-1])
-                       table.Rich(row, []tablewriter.Colors{{}, {}, {}, {}, 
{}, severityColor})
+               for _, row := range rs.Deduplicate() {
+                       severityColor := getSeverityColor(row.Severity)
+                       table.Rich(row.Columns(), []tablewriter.Colors{
+                               {},            // name
+                               {},            // version
+                               {},            // fix
+                               {},            // package type
+                               {},            // vulnerability ID
+                               severityColor, // severity
+                       })
                }
        } else {
                table.AppendBulk(rs.Render())
@@ -70,12 +97,12 @@
        return nil
 }
 
-func getRows(doc models.Document, showSuppressed bool) rows {
+func (p *Presenter) getRows(doc models.Document, showSuppressed bool) rows {
        var rs rows
 
        // generate rows for matching vulnerabilities
        for _, m := range doc.Matches {
-               rs = append(rs, newRow(m, ""))
+               rs = append(rs, p.newRow(m, ""))
        }
 
        // generate rows for suppressed vulnerabilities
@@ -89,7 +116,7 @@
                                        }
                                }
                        }
-                       rs = append(rs, newRow(m.Match, msg))
+                       rs = append(rs, p.newRow(m.Match, msg))
                }
        }
        return rs
@@ -99,41 +126,53 @@
        return lipgloss.NewStyle().Foreground(lipgloss.Color("5")).Render("") 
!= ""
 }
 
-type rows []row
-
-type row struct {
-       Name            string
-       Version         string
-       Fix             string
-       PackageType     string
-       VulnerabilityID string
-       Severity        string
-}
-
-func newRow(m models.Match, severitySuffix string) row {
+func (p *Presenter) newRow(m models.Match, severitySuffix string) row {
        severity := m.Vulnerability.Severity
        if severity != "" {
                severity += severitySuffix
        }
 
-       fixVersion := strings.Join(m.Vulnerability.Fix.Versions, ", ")
-       switch m.Vulnerability.Fix.State {
-       case vulnerability.FixStateWontFix.String():
-               fixVersion = "(won't fix)"
-       case vulnerability.FixStateUnknown.String():
-               fixVersion = ""
-       }
-
        return row{
                Name:            m.Artifact.Name,
                Version:         m.Artifact.Version,
-               Fix:             fixVersion,
+               Fix:             p.formatFix(m),
                PackageType:     string(m.Artifact.Type),
                VulnerabilityID: m.Vulnerability.ID,
                Severity:        severity,
        }
 }
 
+func (p *Presenter) formatFix(m models.Match) string {
+       switch m.Vulnerability.Fix.State {
+       case vulnerability.FixStateWontFix.String():
+               return "(won't fix)"
+       case vulnerability.FixStateUnknown.String():
+               return ""
+       }
+
+       recommended := strset.New()
+       for _, d := range m.MatchDetails {
+               if d.Fix == nil {
+                       continue
+               }
+               if d.Fix.SuggestedVersion != "" {
+                       recommended.Add(d.Fix.SuggestedVersion)
+               }
+       }
+
+       var vers []string
+       hasMultipleVersions := len(m.Vulnerability.Fix.Versions) > 1
+       for _, v := range m.Vulnerability.Fix.Versions {
+               if hasMultipleVersions && recommended.Has(v) {
+                       vers = append(vers, p.recommendedFixStyle.Render(v))
+                       continue
+               }
+               vers = append(vers, v)
+       }
+
+       return strings.Join(vers, ", ")
+}
+
 func (r row) Columns() []string {
        return []string{r.Name, r.Version, r.Fix, r.PackageType, 
r.VulnerabilityID, r.Severity}
 }
@@ -143,6 +182,15 @@
 }
 
 func (rs rows) Render() [][]string {
+       deduped := rs.Deduplicate()
+       out := make([][]string, len(deduped))
+       for idx, r := range deduped {
+               out[idx] = r.Columns()
+       }
+       return out
+}
+
+func (rs rows) Deduplicate() []row {
        // deduplicate
        seen := map[string]row{}
        var deduped rows
@@ -159,11 +207,7 @@
        }
 
        // render final columns
-       out := make([][]string, len(deduped))
-       for idx, r := range deduped {
-               out[idx] = r.Columns()
-       }
-       return out
+       return deduped
 }
 
 func getSeverityColor(severity string) tablewriter.Colors {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/grype-0.88.0/grype/presenter/table/presenter_test.go 
new/grype-0.89.0/grype/presenter/table/presenter_test.go
--- old/grype-0.88.0/grype/presenter/table/presenter_test.go    2025-03-05 
17:26:43.000000000 +0100
+++ new/grype-0.89.0/grype/presenter/table/presenter_test.go    2025-03-06 
17:12:29.000000000 +0100
@@ -4,8 +4,10 @@
        "bytes"
        "testing"
 
+       "github.com/charmbracelet/lipgloss"
        "github.com/gkampitakis/go-snaps/snaps"
        "github.com/google/go-cmp/cmp"
+       "github.com/muesli/termenv"
        "github.com/stretchr/testify/assert"
        "github.com/stretchr/testify/require"
 
@@ -22,11 +24,15 @@
        pkg1 := models.Package{
                ID:      "package-1-id",
                Name:    "package-1",
-               Version: "1.0.1",
+               Version: "2.0.0",
                Type:    syftPkg.DebPkg,
        }
        match1 := models.Match{
                Vulnerability: models.Vulnerability{
+                       Fix: models.Fix{
+                               Versions: []string{"1.0.2", "2.0.1", "3.0.4"},
+                               State:    vulnerability.FixStateFixed.String(),
+                       },
                        VulnerabilityMetadata: models.VulnerabilityMetadata{
                                ID:          "CVE-1999-0001",
                                Namespace:   "source-1",
@@ -48,6 +54,9 @@
                        {
                                Type:    match.ExactDirectMatch.String(),
                                Matcher: match.DpkgMatcher.String(),
+                               Fix: &models.FixDetails{
+                                       SuggestedVersion: "2.0.1",
+                               },
                        },
                },
        }
@@ -61,19 +70,20 @@
                        name:           "create row for vulnerability",
                        match:          match1,
                        severitySuffix: "",
-                       expectedRow:    []string{match1.Artifact.Name, 
match1.Artifact.Version, "", string(match1.Artifact.Type), 
match1.Vulnerability.ID, "Low"},
+                       expectedRow:    []string{match1.Artifact.Name, 
match1.Artifact.Version, "1.0.2, *2.0.1, 3.0.4", string(match1.Artifact.Type), 
match1.Vulnerability.ID, "Low"},
                },
                {
                        name:           "create row for suppressed 
vulnerability",
                        match:          match1,
                        severitySuffix: appendSuppressed,
-                       expectedRow:    []string{match1.Artifact.Name, 
match1.Artifact.Version, "", string(match1.Artifact.Type), 
match1.Vulnerability.ID, "Low (suppressed)"},
+                       expectedRow:    []string{match1.Artifact.Name, 
match1.Artifact.Version, "1.0.2, *2.0.1, 3.0.4", string(match1.Artifact.Type), 
match1.Vulnerability.ID, "Low (suppressed)"},
                },
        }
 
        for _, testCase := range cases {
                t.Run(testCase.name, func(t *testing.T) {
-                       row := newRow(testCase.match, testCase.severitySuffix)
+                       p := NewPresenter(models.PresenterConfig{}, false)
+                       row := p.newRow(testCase.match, testCase.severitySuffix)
                        cols := rows{row}.Render()[0]
 
                        assert.Equal(t, testCase.expectedRow, cols)
@@ -83,11 +93,11 @@
 
 func TestTablePresenter(t *testing.T) {
        pb := internal.GeneratePresenterConfig(t, internal.ImageSource)
-       pres := NewPresenter(pb, false)
 
        t.Run("no color", func(t *testing.T) {
                var buffer bytes.Buffer
-               pres.withColor = false
+               lipgloss.SetColorProfile(termenv.Ascii)
+               pres := NewPresenter(pb, false)
 
                err := pres.Present(&buffer)
                require.NoError(t, err)
@@ -98,7 +108,12 @@
 
        t.Run("with color", func(t *testing.T) {
                var buffer bytes.Buffer
-               pres.withColor = true
+               lipgloss.SetColorProfile(termenv.TrueColor)
+               t.Cleanup(func() {
+                       // don't affect other tests
+                       lipgloss.SetColorProfile(termenv.Ascii)
+               })
+               pres := NewPresenter(pb, false)
 
                err := pres.Present(&buffer)
                require.NoError(t, err)
@@ -226,7 +241,6 @@
        })
 }
 
-// Helper function to create a test row
 func createTestRow(name, version, fix, pkgType, vulnID, severity string, 
fixState vulnerability.FixState) (row, error) {
        m := models.Match{
                Vulnerability: models.Vulnerability{
@@ -246,7 +260,8 @@
                },
        }
 
-       r := newRow(m, "")
+       p := NewPresenter(models.PresenterConfig{}, false)
+       r := p.newRow(m, "")
 
        return r, nil
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/grype-0.88.0/grype/version/version.go 
new/grype-0.89.0/grype/version/version.go
--- old/grype-0.88.0/grype/version/version.go   2025-03-05 17:26:43.000000000 
+0100
+++ new/grype-0.89.0/grype/version/version.go   2025-03-06 17:12:29.000000000 
+0100
@@ -118,3 +118,55 @@
 func (v Version) String() string {
        return fmt.Sprintf("%s (%s)", v.Raw, v.Format)
 }
+
+func (v Version) Compare(other *Version) (int, error) {
+       if other == nil {
+               return -1, ErrNoVersionProvided
+       }
+
+       if other.Format == v.Format {
+               return v.compareSameFormat(other)
+       }
+
+       // different formats, try to convert to a common format
+       common, err := finalizeComparisonVersion(other, v.Format)
+       if err != nil {
+               return -1, err
+       }
+
+       return v.compareSameFormat(common)
+}
+
+func (v Version) compareSameFormat(other *Version) (int, error) {
+       switch v.Format {
+       case SemanticFormat:
+               return v.rich.semVer.verObj.Compare(other.rich.semVer.verObj), 
nil
+       case ApkFormat:
+               return v.rich.apkVer.Compare(other)
+       case DebFormat:
+               return v.rich.debVer.Compare(other)
+       case GolangFormat:
+               return v.rich.golangVersion.Compare(other)
+       case MavenFormat:
+               return v.rich.mavenVer.Compare(other)
+       case RpmFormat:
+               return v.rich.rpmVer.Compare(other)
+       case PythonFormat:
+               return v.rich.pep440version.Compare(other)
+       case KBFormat:
+               return v.rich.kbVer.Compare(other)
+       case GemFormat:
+               return v.rich.semVer.verObj.Compare(other.rich.semVer.verObj), 
nil
+       case PortageFormat:
+               return v.rich.portVer.Compare(other)
+       case JVMFormat:
+               return v.rich.jvmVersion.Compare(other)
+       }
+
+       v1, err := newFuzzyVersion(v.Raw)
+       if err != nil {
+               return -1, fmt.Errorf("unable to parse version (%s) as a fuzzy 
version: %w", v.Raw, err)
+       }
+
+       return v1.Compare(other)
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/grype-0.88.0/grype/version/version_test.go 
new/grype-0.89.0/grype/version/version_test.go
--- old/grype-0.88.0/grype/version/version_test.go      1970-01-01 
01:00:00.000000000 +0100
+++ new/grype-0.89.0/grype/version/version_test.go      2025-03-06 
17:12:29.000000000 +0100
@@ -0,0 +1,133 @@
+package version
+
+import (
+       "testing"
+
+       "github.com/stretchr/testify/assert"
+       "github.com/stretchr/testify/require"
+)
+
+func TestVersionCompare(t *testing.T) {
+       tests := []struct {
+               name           string
+               version1       string
+               version2       string
+               format         Format
+               expectedResult int
+               expectErr      bool
+       }{
+               {
+                       name:           "v1 greater than v2",
+                       version1:       "2.0.0",
+                       version2:       "1.0.0",
+                       format:         SemanticFormat,
+                       expectedResult: 1,
+                       expectErr:      false,
+               },
+               {
+                       name:           "v1 less than v2",
+                       version1:       "1.0.0",
+                       version2:       "2.0.0",
+                       format:         SemanticFormat,
+                       expectedResult: -1,
+                       expectErr:      false,
+               },
+               {
+                       name:           "v1 equal to v2",
+                       version1:       "1.0.0",
+                       version2:       "1.0.0",
+                       format:         SemanticFormat,
+                       expectedResult: 0,
+                       expectErr:      false,
+               },
+               {
+                       name:           "compare with nil version",
+                       version1:       "1.0.0",
+                       version2:       "",
+                       format:         SemanticFormat,
+                       expectedResult: -1,
+                       expectErr:      true,
+               },
+       }
+
+       for _, tc := range tests {
+               t.Run(tc.name, func(t *testing.T) {
+                       v1, err := NewVersion(tc.version1, tc.format)
+                       require.NoError(t, err, "failed to create version1")
+
+                       var v2 *Version
+                       if tc.version2 == "" {
+                               v2 = nil // test nil case
+                       } else if tc.name == "different formats" {
+                               // use a different format for the second version
+                               v2, err = NewVersion(tc.version2, PythonFormat)
+                               require.NoError(t, err, "failed to create 
version2 with different format")
+                       } else {
+                               v2, err = NewVersion(tc.version2, tc.format)
+                               require.NoError(t, err, "failed to create 
version2")
+                       }
+
+                       result, err := v1.Compare(v2)
+
+                       if tc.expectErr {
+                               assert.Error(t, err, "expected an error but got 
none")
+                       } else {
+                               assert.NoError(t, err, "unexpected error during 
comparison")
+                               assert.Equal(t, tc.expectedResult, result, 
"comparison result mismatch")
+                       }
+               })
+       }
+}
+
+func Test_UpgradeUnknownRightSideComparison(t *testing.T) {
+       v1, err := NewVersion("1.0.0", SemanticFormat)
+       require.NoError(t, err)
+
+       // test if we can upgrade an unknown format to a known format when the 
left hand side is known
+       v2, err := NewVersion("1.0.0", UnknownFormat)
+       require.NoError(t, err)
+
+       result, err := v1.Compare(v2)
+       assert.NoError(t, err)
+       assert.Equal(t, 0, result, "versions should be equal after format 
conversion")
+}
+
+func TestVersionCompareSameFormat(t *testing.T) {
+       formats := []struct {
+               name   string
+               format Format
+       }{
+               {"Semantic", SemanticFormat},
+               {"APK", ApkFormat},
+               {"Deb", DebFormat},
+               {"Golang", GolangFormat},
+               {"Maven", MavenFormat},
+               {"RPM", RpmFormat},
+               {"Python", PythonFormat},
+               {"KB", KBFormat},
+               {"Gem", GemFormat},
+               {"Portage", PortageFormat},
+               {"JVM", JVMFormat},
+               {"Unknown", UnknownFormat},
+       }
+
+       for _, fmt := range formats {
+               t.Run(fmt.name, func(t *testing.T) {
+                       // just test that we can create and compare versions of 
this format
+                       // without errors - not testing the actual comparison 
logic
+                       v1, err := NewVersion("1.0.0", fmt.format)
+                       if err != nil {
+                               t.Skipf("Skipping %s format, couldn't create 
version: %v", fmt.name, err)
+                       }
+
+                       v2, err := NewVersion("1.0.0", fmt.format)
+                       if err != nil {
+                               t.Skipf("Skipping %s format, couldn't create 
second version: %v", fmt.name, err)
+                       }
+
+                       result, err := v1.Compare(v2)
+                       assert.NoError(t, err, "comparison error")
+                       assert.Equal(t, 0, result, "equal versions should 
return 0")
+               })
+       }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/grype-0.88.0/test/quality/.grype.yaml 
new/grype-0.89.0/test/quality/.grype.yaml
--- old/grype-0.88.0/test/quality/.grype.yaml   2025-03-05 17:26:43.000000000 
+0100
+++ new/grype-0.89.0/test/quality/.grype.yaml   2025-03-06 17:12:29.000000000 
+0100
@@ -23,8 +23,3 @@
   stock:
     using-cpes: true
 
-# while we are merging https://github.com/anchore/grype/pull/2494 to support 
v6 there are a few examples that are
-# worse, however, the overall matching behavior is correct, thus we should not 
block on these examples
-ignore:
-  - vulnerability: CVE-2012-0979
-  - vulnerability: CVE-2019-5736
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/grype-0.88.0/test/quality/.yardstick.yaml 
new/grype-0.89.0/test/quality/.yardstick.yaml
--- old/grype-0.88.0/test/quality/.yardstick.yaml       2025-03-05 
17:26:43.000000000 +0100
+++ new/grype-0.89.0/test/quality/.yardstick.yaml       2025-03-06 
17:12:29.000000000 +0100
@@ -116,9 +116,7 @@
           # are testing with is not too stale.
           # version: git:current-commit+import-db=db.tar.zst
           # for local build of grype, use for example:
-# we need to disable this while we are in pre-release of v6 (restore after 
release of v6)
-#          version: path:../../+import-db=db.tar.zst
-          version: path:../../
+          version: path:../../+import-db=db.tar.zst
           takes: SBOM
           label: candidate
 
@@ -128,9 +126,7 @@
           # By pinning the DB the grype code itself becomes the independent 
variable under test (and not the
           # every-changing DB). That being said, we should be updating this DB 
periodically to ensure what we
           # are testing with is not too stale.
-# we need to disable this while we are in pre-release of v6 (restore after 
release of v6)
-#          version: latest+import-db=db.tar.zst
-          version: latest
+          version: latest+import-db=db.tar.zst
           takes: SBOM
           label: reference
   pr_vs_latest_via_sbom_2022:
@@ -161,9 +157,7 @@
           # are testing with is not too stale.
           # version: git:current-commit+import-db=db.tar.zst
           # for local build of grype, use for example:
-# we need to disable this while we are in pre-release of v6 (restore after 
release of v6)
-#          version: path:../../+import-db=db.tar.zst
-          version: path:../../
+          version: path:../../+import-db=db.tar.zst
           takes: SBOM
           label: candidate # is candidate better than the current baseline?
 
@@ -173,8 +167,6 @@
           # By pinning the DB the grype code itself becomes the independent 
variable under test (and not the
           # every-changing DB). That being said, we should be updating this DB 
periodically to ensure what we
           # are testing with is not too stale.
-# we need to disable this while we are in pre-release of v6 (restore after 
release of v6)
-#          version: latest+import-db=db.tar.zst
-          version: latest
+          version: latest+import-db=db.tar.zst
           takes: SBOM
           label: reference # this run is the current baseline

++++++ grype.obsinfo ++++++
--- /var/tmp/diff_new_pack.maZ307/_old  2025-03-07 16:48:28.793274152 +0100
+++ /var/tmp/diff_new_pack.maZ307/_new  2025-03-07 16:48:28.797274321 +0100
@@ -1,5 +1,5 @@
 name: grype
-version: 0.88.0
-mtime: 1741192003
-commit: 6ee276f0c8363518c08b8d48fae302ee6001c295
+version: 0.89.0
+mtime: 1741277549
+commit: 1bf47c38bede40dea7b72bbe4712191820f1aa15
 

++++++ vendor.tar.gz ++++++
/work/SRC/openSUSE:Factory/grype/vendor.tar.gz 
/work/SRC/openSUSE:Factory/.grype.new.19136/vendor.tar.gz differ: char 5, line 1

Reply via email to