Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package grype-db for openSUSE:Factory checked in at 2026-02-12 17:27:14 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/grype-db (Old) and /work/SRC/openSUSE:Factory/.grype-db.new.1977 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "grype-db" Thu Feb 12 17:27:14 2026 rev:30 rq:1332614 version:0.52.0 Changes: -------- --- /work/SRC/openSUSE:Factory/grype-db/grype-db.changes 2026-02-09 15:35:01.455834332 +0100 +++ /work/SRC/openSUSE:Factory/.grype-db.new.1977/grype-db.changes 2026-02-12 17:28:25.990004283 +0100 @@ -1,0 +2,25 @@ +Thu Feb 12 06:11:10 UTC 2026 - Johannes Kastl <[email protected]> + +- Update to version 0.52.0: + * Added Features + - batch database operations to reduce network storage overhead + [#818 @jamestexas] + - support photon OS [#872 @willmurphyscode] + * Additional Changes + - enable photon vunnel provider [#876 @willmurphyscode] + * Dependencies + - chore(deps): Bump the python-minor-and-patch group with 2 + updates (#878) + - chore(deps): update tools to latest versions (#879) + - chore(deps): Bump cryptography from 44.0.1 to 46.0.5 (#877) + - chore(deps): update anchore dependencies (#875) + - chore(deps): Bump boto3 in the python-minor-and-patch group + (#874) + - chore(deps): Bump github.com/go-git/go-git/v5 from 5.16.4 to + 5.16.5 (#873) + - chore(deps): Bump zizmorcore/zizmor-action from 0.4.1 to + 0.5.0 (#870) + - chore(deps): Bump boto3 in the python-minor-and-patch group + (#871) + +------------------------------------------------------------------- Old: ---- grype-db-0.51.0.obscpio New: ---- grype-db-0.52.0.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ grype-db.spec ++++++ --- /var/tmp/diff_new_pack.mXBcGl/_old 2026-02-12 17:28:27.622073520 +0100 +++ /var/tmp/diff_new_pack.mXBcGl/_new 2026-02-12 17:28:27.626073690 +0100 @@ -17,7 +17,7 @@ Name: grype-db -Version: 0.51.0 +Version: 0.52.0 Release: 0 Summary: A vulnerability scanner for container images and filesystems License: Apache-2.0 ++++++ _service ++++++ --- /var/tmp/diff_new_pack.mXBcGl/_old 2026-02-12 17:28:27.670075557 +0100 +++ /var/tmp/diff_new_pack.mXBcGl/_new 2026-02-12 17:28:27.690076405 +0100 @@ -3,7 +3,7 @@ <param name="url">https://github.com/anchore/grype-db</param> <param name="scm">git</param> <param name="exclude">.git</param> - <param name="revision">v0.51.0</param> + <param name="revision">v0.52.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.mXBcGl/_old 2026-02-12 17:28:27.714077423 +0100 +++ /var/tmp/diff_new_pack.mXBcGl/_new 2026-02-12 17:28:27.718077593 +0100 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/anchore/grype-db</param> - <param name="changesrevision">013670be3fbdc9eea9e85f19c549aa48f8320e55</param></service></servicedata> + <param name="changesrevision">42f007c613bf061f626fd92671bbee0f8c9dabb4</param></service></servicedata> (No newline at EOF) ++++++ grype-db-0.51.0.obscpio -> grype-db-0.52.0.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/grype-db-0.51.0/.binny.yaml new/grype-db-0.52.0/.binny.yaml --- old/grype-db-0.51.0/.binny.yaml 2026-02-06 13:53:02.000000000 +0100 +++ new/grype-db-0.52.0/.binny.yaml 2026-02-11 11:56:03.000000000 +0100 @@ -2,7 +2,7 @@ # we want to use a pinned version of binny to manage the toolchain (so binny manages itself!) - name: binny version: - want: v0.11.2 + want: v0.11.3 method: github-release with: repo: anchore/binny @@ -10,7 +10,7 @@ # used for linting - name: golangci-lint version: - want: v2.8.0 + want: v2.9.0 method: github-release with: repo: golangci/golangci-lint diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/grype-db-0.51.0/cmd/grype-db/cli/commands/build.go new/grype-db-0.52.0/cmd/grype-db/cli/commands/build.go --- old/grype-db-0.51.0/cmd/grype-db/cli/commands/build.go 2026-02-06 13:53:02.000000000 +0100 +++ new/grype-db-0.52.0/cmd/grype-db/cli/commands/build.go 2026-02-11 11:56:03.000000000 +0100 @@ -121,6 +121,7 @@ InferNVDFixVersions: cfg.InferNVDFixVersions, Hydrate: cfg.Hydrate, FailOnMissingFixDate: cfg.FailOnMissingFixDate, + BatchSize: cfg.BatchSize, }) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/grype-db-0.51.0/cmd/grype-db/cli/options/build.go new/grype-db-0.52.0/cmd/grype-db/cli/options/build.go --- old/grype-db-0.51.0/cmd/grype-db/cli/options/build.go 2026-02-06 13:53:02.000000000 +0100 +++ new/grype-db-0.52.0/cmd/grype-db/cli/options/build.go 2026-02-11 11:56:03.000000000 +0100 @@ -15,6 +15,7 @@ // bound options SkipValidation bool `yaml:"skip-validation" json:"skip-validation" mapstructure:"skip-validation"` SchemaVersion int `yaml:"schema-version" json:"schema-version" mapstructure:"schema-version"` + BatchSize int `yaml:"batch-size" json:"batch-size" mapstructure:"batch-size"` // unbound options IncludeCPEParts []string `yaml:"include-cpe-parts" json:"include-cpe-parts" mapstructure:"include-cpe-parts"` @@ -28,6 +29,7 @@ DBLocation: DefaultDBLocation(), SkipValidation: false, SchemaVersion: process.DefaultSchemaVersion, + BatchSize: process.DefaultBatchSize, IncludeCPEParts: []string{"a", "h", "o"}, InferNVDFixVersions: true, Hydrate: false, @@ -48,6 +50,12 @@ "DB Schema version to build for", ) + flags.IntVarP( + &o.BatchSize, + "batch-size", "", o.BatchSize, + "number of database operations to batch before flushing to disk (balances throughput with memory usage)", + ) + o.DBLocation.AddFlags(flags) } @@ -59,6 +67,9 @@ if err := Bind(v, "build.schema-version", flags.Lookup("schema")); err != nil { return err } + if err := Bind(v, "build.batch-size", flags.Lookup("batch-size")); err != nil { + return err + } // set default values for non-bound struct items v.SetDefault("build.include-cpe-parts", o.IncludeCPEParts) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/grype-db-0.51.0/config/grype-db/publish-nightly-r2.yaml new/grype-db-0.52.0/config/grype-db/publish-nightly-r2.yaml --- old/grype-db-0.51.0/config/grype-db/publish-nightly-r2.yaml 2026-02-06 13:53:02.000000000 +0100 +++ new/grype-db-0.52.0/config/grype-db/publish-nightly-r2.yaml 2026-02-11 11:56:03.000000000 +0100 @@ -27,6 +27,7 @@ - name: mariner - name: minimos - name: oracle + - name: photon - name: rhel - name: secureos - name: sles diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/grype-db-0.51.0/go.mod new/grype-db-0.52.0/go.mod --- old/grype-db-0.51.0/go.mod 2026-02-06 13:53:02.000000000 +0100 +++ new/grype-db-0.52.0/go.mod 2026-02-11 11:56:03.000000000 +0100 @@ -8,9 +8,9 @@ github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d github.com/adrg/xdg v0.5.3 github.com/anchore/go-logger v0.0.0-20250318195838-07ae343dd722 - github.com/anchore/grype v0.107.1 + github.com/anchore/grype v0.108.0 github.com/anchore/packageurl-go v0.1.1-0.20250220190351-d62adb6e1115 - github.com/anchore/syft v1.41.2 + github.com/anchore/syft v1.42.0 github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de github.com/dave/jennifer v1.7.1 github.com/dustin/go-humanize v1.0.1 @@ -84,7 +84,7 @@ github.com/anchore/go-struct-converter v0.1.0 // indirect github.com/anchore/go-sync v0.0.0-20250714163430-add63db73ad1 // indirect github.com/anchore/go-version v1.2.2-0.20210903204242-51efa5b487c4 // indirect - github.com/anchore/stereoscope v0.1.19 // indirect + github.com/anchore/stereoscope v0.1.20 // indirect github.com/andybalholm/brotli v1.2.0 // indirect github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect github.com/aquasecurity/go-pep440-version v0.0.1 // indirect @@ -114,7 +114,7 @@ github.com/bitnami/go-version v0.0.0-20250505154626-452e8c5ee607 // indirect github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb // indirect github.com/bmatcuk/doublestar/v2 v2.0.4 // indirect - github.com/bmatcuk/doublestar/v4 v4.9.2 // indirect + github.com/bmatcuk/doublestar/v4 v4.10.0 // indirect github.com/bodgit/plumbing v1.3.0 // indirect github.com/bodgit/sevenzip v1.6.1 // indirect github.com/bodgit/windows v1.0.1 // indirect @@ -147,7 +147,7 @@ github.com/deitch/magic v0.0.0-20240306090643-c67ab88f10cb // indirect github.com/diskfs/go-diskfs v1.7.0 // indirect github.com/distribution/reference v0.6.0 // indirect - github.com/docker/cli v29.1.5+incompatible // indirect + github.com/docker/cli v29.2.0+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 @@ -163,12 +163,12 @@ github.com/felixge/fgprof v0.9.5 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.12 // indirect + github.com/gabriel-vasile/mimetype v1.4.13 // indirect github.com/github/go-spdx/v2 v2.3.6 // indirect github.com/glebarez/go-sqlite v1.22.0 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-git/go-billy/v5 v5.7.0 // indirect - github.com/go-git/go-git/v5 v5.16.4 // indirect + github.com/go-git/go-git/v5 v5.16.5 // indirect github.com/go-jose/go-jose/v4 v4.1.2 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/grype-db-0.51.0/go.sum new/grype-db-0.52.0/go.sum --- old/grype-db-0.51.0/go.sum 2026-02-06 13:53:02.000000000 +0100 +++ new/grype-db-0.52.0/go.sum 2026-02-11 11:56:03.000000000 +0100 @@ -152,14 +152,14 @@ github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04/go.mod h1:6dK64g27Qi1qGQZ67gFmBFvEHScy0/C8qhQhNe5B5pQ= github.com/anchore/go-version v1.2.2-0.20210903204242-51efa5b487c4 h1:rmZG77uXgE+o2gozGEBoUMpX27lsku+xrMwlmBZJtbg= github.com/anchore/go-version v1.2.2-0.20210903204242-51efa5b487c4/go.mod h1:Bkc+JYWjMCF8OyZ340IMSIi2Ebf3uwByOk6ho4wne1E= -github.com/anchore/grype v0.107.1 h1:N7EIlJfuq7RKA5nSgXPxOfifyB8EABYd2vP+CJwL1bY= -github.com/anchore/grype v0.107.1/go.mod h1:DilbSyGMuYZREWL/tIZYOA4PedC2X2FOaEMAmQaNGhg= +github.com/anchore/grype v0.108.0 h1:oS2V1Sdc84iymzmBDCVsLi/wHOfxIhENbmXZyn5RuLY= +github.com/anchore/grype v0.108.0/go.mod h1:O2KGWA64GZdEfdE969DBqZBwK5NEx3oC4bWZ5VlJUzs= 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.19 h1:1G5LVmRN1Sz6qNezpVAEeN7QfWwCE9zw9TJK1ZGnkvw= -github.com/anchore/stereoscope v0.1.19/go.mod h1:+laNHlk05xA2YqgEzq8mxkFzclL3NRdeNIsiQQVeZZ4= -github.com/anchore/syft v1.41.2 h1:mC2l3P8dUvBdz+97ZNcKD410s8vGFGFXdZa+neaQEb8= -github.com/anchore/syft v1.41.2/go.mod h1:j8SaTiPQzSxElS0MWw3ML2m2EK4av/7Vm4q8WpwUmYw= +github.com/anchore/stereoscope v0.1.20 h1:32720yZ/YtvzF5tvsoRL/ibdAJzOdIaR444fDXW4arQ= +github.com/anchore/stereoscope v0.1.20/go.mod h1:6Ef0xQAuN2Ito7eV9A9pYjD1x/0cX5fy56MwgEGyrB4= +github.com/anchore/syft v1.42.0 h1:UCoqHhPdmLxCrJmq0qxQxyIs0rf9sqKlG9p9OVs7yO4= +github.com/anchore/syft v1.42.0/go.mod h1:rlZUlW45y8IOR0YO4EivNHXnI51mDCAxmYj9fBW0gmI= 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= @@ -237,8 +237,8 @@ github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI= github.com/bmatcuk/doublestar/v2 v2.0.4 h1:6I6oUiT/sU27eE2OFcWqBhL1SwjyvQuOssxT4a1yidI= github.com/bmatcuk/doublestar/v2 v2.0.4/go.mod h1:QMmcs3H2AUQICWhfzLXz+IYln8lRQmTZRptLie8RgRw= -github.com/bmatcuk/doublestar/v4 v4.9.2 h1:b0mc6WyRSYLjzofB2v/0cuDUZ+MqoGyH3r0dVij35GI= -github.com/bmatcuk/doublestar/v4 v4.9.2/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= +github.com/bmatcuk/doublestar/v4 v4.10.0 h1:zU9WiOla1YA122oLM6i4EXvGW62DvKZVxIe6TYWexEs= +github.com/bmatcuk/doublestar/v4 v4.10.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= github.com/bodgit/plumbing v1.3.0 h1:pf9Itz1JOQgn7vEOE7v7nlEfBykYqvUYioC61TwWCFU= github.com/bodgit/plumbing v1.3.0/go.mod h1:JOTb4XiRu5xfnmdnDJo6GmSbSbtSyufrsyZFByMtKEs= github.com/bodgit/sevenzip v1.6.1 h1:kikg2pUMYC9ljU7W9SaqHXhym5HyKm8/M/jd31fYan4= @@ -351,8 +351,8 @@ github.com/djherbis/times v1.6.0/go.mod h1:gOHeRAz2h+VJNZ5Gmc/o7iD9k4wW7NMVqieYCY99oc0= github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI= github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= -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/cli v29.2.0+incompatible h1:9oBd9+YM7rxjZLfyMGxjraKBKE4/nVyvVfN4qNl9XRM= +github.com/docker/cli v29.2.0+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= @@ -417,8 +417,8 @@ github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= -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/gabriel-vasile/mimetype v1.4.13 h1:46nXokslUBsAJE/wMsp5gtO500a4F3Nkz9Ufpk2AcUM= +github.com/gabriel-vasile/mimetype v1.4.13/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/github/go-spdx/v2 v2.3.6 h1:9flm625VmmTlWXi0YH5W9V8FdMfulvxalHdYnUfoqxc= github.com/github/go-spdx/v2 v2.3.6/go.mod h1:/5rwgS0txhGtRdUZwc02bTglzg6HK3FfuEbECKlK2Sg= @@ -438,8 +438,8 @@ github.com/go-git/go-billy/v5 v5.7.0/go.mod h1:/1IUejTKH8xipsAcdfcSAlUlo2J7lkYV8GTKxAT/L3E= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= -github.com/go-git/go-git/v5 v5.16.4 h1:7ajIEZHZJULcyJebDLo99bGgS0jRrOxzZG4uCk2Yb2Y= -github.com/go-git/go-git/v5 v5.16.4/go.mod h1:4Ge4alE/5gPs30F2H1esi2gPd69R0C39lolkucHBOp8= +github.com/go-git/go-git/v5 v5.16.5 h1:mdkuqblwr57kVfXri5TTH+nMFLNUxIj9Z7F5ykFbw5s= +github.com/go-git/go-git/v5 v5.16.5/go.mod h1:QOMLpNf1qxuSY4StA/ArOdfFR2TrKEjJiye2kel2m+M= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/grype-db-0.51.0/manager/src/grype_db_manager/db/latest.py new/grype-db-0.52.0/manager/src/grype_db_manager/db/latest.py --- old/grype-db-0.51.0/manager/src/grype_db_manager/db/latest.py 2026-02-06 13:53:02.000000000 +0100 +++ new/grype-db-0.52.0/manager/src/grype_db_manager/db/latest.py 2026-02-11 11:56:03.000000000 +0100 @@ -59,7 +59,7 @@ @contextlib.contextmanager def _http_server(directory: str, schema_version: str) -> Iterator[str]: - major_version = schema_version.split(".")[0].removeprefix("v") + major_version = schema_version.split(".", maxsplit=1)[0].removeprefix("v") server_address = ("127.0.0.1", 5555) url = f"http://{server_address[0]}:{server_address[1]}" latest_url = f"{url}/v{major_version}/{LATEST_FILENAME}" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/grype-db-0.51.0/manager/src/grype_db_manager/distribution.py new/grype-db-0.52.0/manager/src/grype_db_manager/distribution.py --- old/grype-db-0.51.0/manager/src/grype_db_manager/distribution.py 2026-02-06 13:53:02.000000000 +0100 +++ new/grype-db-0.52.0/manager/src/grype_db_manager/distribution.py 2026-02-11 11:56:03.000000000 +0100 @@ -116,7 +116,7 @@ def age_from_basename(basename: str) -> int | None: - fields = basename.split(".")[0].split("_") + fields = basename.split(".", maxsplit=1)[0].split("_") if len(fields) < 3: return None diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/grype-db-0.51.0/pkg/process/build.go new/grype-db-0.52.0/pkg/process/build.go --- old/grype-db-0.51.0/pkg/process/build.go 2026-02-06 13:53:02.000000000 +0100 +++ new/grype-db-0.52.0/pkg/process/build.go 2026-02-11 11:56:03.000000000 +0100 @@ -29,6 +29,7 @@ InferNVDFixVersions bool Hydrate bool FailOnMissingFixDate bool // any fixes found without at least one available date will cause a build failure + BatchSize int // number of operations to batch before committing (default: 2000) } func Build(cfg BuildConfig) error { @@ -96,11 +97,17 @@ } func getWriter(cfg BuildConfig) (data.Writer, error) { + // Use default if not configured + batchSize := cfg.BatchSize + if batchSize == 0 { + batchSize = DefaultBatchSize + } + switch cfg.SchemaVersion { case grypeDBv5.SchemaVersion: - return v5.NewWriter(cfg.Directory, cfg.Timestamp, cfg.States) + return v5.NewWriter(cfg.Directory, cfg.Timestamp, cfg.States, batchSize) case grypeDBv6.ModelVersion: - return v6.NewWriter(cfg.Directory, cfg.States, cfg.FailOnMissingFixDate) + return v6.NewWriter(cfg.Directory, cfg.States, cfg.FailOnMissingFixDate, batchSize) default: return nil, fmt.Errorf("unable to create writer: unsupported schema version: %+v", cfg.SchemaVersion) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/grype-db-0.51.0/pkg/process/default_schema_version.go new/grype-db-0.52.0/pkg/process/default_schema_version.go --- old/grype-db-0.51.0/pkg/process/default_schema_version.go 2026-02-06 13:53:02.000000000 +0100 +++ new/grype-db-0.52.0/pkg/process/default_schema_version.go 2026-02-11 11:56:03.000000000 +0100 @@ -2,4 +2,9 @@ import grypeDB "github.com/anchore/grype/grype/db/v6" -const DefaultSchemaVersion = grypeDB.ModelVersion +const ( + DefaultSchemaVersion = grypeDB.ModelVersion + // DefaultBatchSize is the default number of database operations to batch together + // before flushing to disk. This value balances throughput with memory usage. + DefaultBatchSize = 2000 +) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/grype-db-0.51.0/pkg/process/v5/transformers/os/test-fixtures/photon-4.0.json new/grype-db-0.52.0/pkg/process/v5/transformers/os/test-fixtures/photon-4.0.json --- old/grype-db-0.51.0/pkg/process/v5/transformers/os/test-fixtures/photon-4.0.json 1970-01-01 01:00:00.000000000 +0100 +++ new/grype-db-0.52.0/pkg/process/v5/transformers/os/test-fixtures/photon-4.0.json 2026-02-11 11:56:03.000000000 +0100 @@ -0,0 +1,22 @@ +[ + { + "Vulnerability": { + "Description": "", + "FixedIn": [ + { + "Name": "curl", + "NamespaceName": "photon:4.0", + "Version": "7.88.1-4.ph4", + "VersionFormat": "rpm", + "VulnerableRange": "< 7.88.1-4.ph4" + } + ], + "Link": "https://nvd.nist.gov/vuln/detail/CVE-2023-38545", + "Metadata": {}, + "Name": "CVE-2023-38545", + "NamespaceName": "photon:4.0", + "Severity": "Critical", + "CVSS": [] + } + } +] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/grype-db-0.51.0/pkg/process/v5/transformers/os/transform.go new/grype-db-0.52.0/pkg/process/v5/transformers/os/transform.go --- old/grype-db-0.51.0/pkg/process/v5/transformers/os/transform.go 2026-02-06 13:53:02.000000000 +0100 +++ new/grype-db-0.52.0/pkg/process/v5/transformers/os/transform.go 2026-02-11 11:56:03.000000000 +0100 @@ -25,8 +25,8 @@ // Currently known enterprise feed groups are expected to be of the form {distroID}:{version} feedGroupDistroID := feedGroupComponents[0] - // secureos is not supported in the grype v5 schema, so the records should be dropped entirely - if feedGroupDistroID == "secureos" { + // secureos and photon are not supported in the grype v5 schema, so the records should be dropped entirely + if feedGroupDistroID == "secureos" || feedGroupDistroID == "photon" { return nil, nil } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/grype-db-0.51.0/pkg/process/v5/transformers/os/transform_test.go new/grype-db-0.52.0/pkg/process/v5/transformers/os/transform_test.go --- old/grype-db-0.51.0/pkg/process/v5/transformers/os/transform_test.go 2026-02-06 13:53:02.000000000 +0100 +++ new/grype-db-0.52.0/pkg/process/v5/transformers/os/transform_test.go 2026-02-11 11:56:03.000000000 +0100 @@ -443,6 +443,12 @@ // intentionally creates no vulnerabilities to write to the DB }, { + name: "Photon (ignore)", + numEntries: 1, + fixture: "test-fixtures/photon-4.0.json", + // photon is not supported in v5, records should be dropped entirely + }, + { name: "Alpine", numEntries: 1, fixture: "test-fixtures/alpine-3.9.json", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/grype-db-0.51.0/pkg/process/v5/writer.go new/grype-db-0.52.0/pkg/process/v5/writer.go --- old/grype-db-0.51.0/pkg/process/v5/writer.go 2026-02-06 13:53:02.000000000 +0100 +++ new/grype-db-0.52.0/pkg/process/v5/writer.go 2026-02-11 11:56:03.000000000 +0100 @@ -8,6 +8,7 @@ "path" "path/filepath" "strings" + "sync" "time" "github.com/spf13/afero" @@ -33,6 +34,14 @@ dbPath string store grypeDB.Store states provider.States + + // Batching infrastructure + batchSize int + batchBuffer []func() error + mu sync.Mutex // Protect batch state + + // Metrics + totalBatches int } type ProviderMetadata struct { @@ -44,7 +53,7 @@ LastSuccessfulRun time.Time `json:"lastSuccessfulRun"` } -func NewWriter(directory string, dataAge time.Time, states provider.States) (data.Writer, error) { +func NewWriter(directory string, dataAge time.Time, states provider.States, batchSize int) (data.Writer, error) { dbPath := path.Join(directory, grypeDB.VulnerabilityStoreFileName) theStore, err := grypeDBStore.New(dbPath, true) if err != nil { @@ -55,14 +64,21 @@ return nil, fmt.Errorf("unable to set DB ID: %w", err) } + // Use default if not configured + if batchSize == 0 { + batchSize = 2000 + } + return &writer{ - dbPath: dbPath, - store: theStore, - states: states, + dbPath: dbPath, + store: theStore, + states: states, + batchSize: batchSize, + batchBuffer: make([]func() error, 0, batchSize), }, nil } -func (w writer) Write(entries ...data.Entry) error { +func (w *writer) Write(entries ...data.Entry) error { log.WithFields("records", len(entries)).Trace("writing records to DB") for _, entry := range entries { if entry.DBSchemaVersion != grypeDB.SchemaVersion { @@ -71,17 +87,29 @@ switch row := entry.Data.(type) { case grypeDB.Vulnerability: - if err := w.store.AddVulnerability(row); err != nil { - return fmt.Errorf("unable to write vulnerability to store: %w", err) + // Batch the vulnerability write + vuln := row + if err := w.addToBatch(func() error { + return w.store.AddVulnerability(vuln) + }); err != nil { + return fmt.Errorf("unable to batch vulnerability write: %w", err) } case grypeDB.VulnerabilityMetadata: + // Normalize severity before batching normalizeSeverity(&row, w.store) - if err := w.store.AddVulnerabilityMetadata(row); err != nil { - return fmt.Errorf("unable to write vulnerability metadata to store: %w", err) + metadata := row + if err := w.addToBatch(func() error { + return w.store.AddVulnerabilityMetadata(metadata) + }); err != nil { + return fmt.Errorf("unable to batch vulnerability metadata write: %w", err) } case grypeDB.VulnerabilityMatchExclusion: - if err := w.store.AddVulnerabilityMatchExclusion(row); err != nil { - return fmt.Errorf("unable to write vulnerability match exclusion to store: %w", err) + // Batch the exclusion write + exclusion := row + if err := w.addToBatch(func() error { + return w.store.AddVulnerabilityMatchExclusion(exclusion) + }); err != nil { + return fmt.Errorf("unable to batch vulnerability match exclusion write: %w", err) } default: return fmt.Errorf("data entry is not of type vulnerability, vulnerability metadata, or exclusion: %T", row) @@ -91,11 +119,53 @@ return nil } +// addToBatch adds an operation to the batch buffer and flushes if batch size is reached +func (w *writer) addToBatch(op func() error) error { + w.mu.Lock() + defer w.mu.Unlock() + + w.batchBuffer = append(w.batchBuffer, op) + + if len(w.batchBuffer) >= w.batchSize { + return w.flushUnlocked() + } + return nil +} + +// Flush executes all pending operations in the batch buffer +func (w *writer) Flush() error { + w.mu.Lock() + defer w.mu.Unlock() + return w.flushUnlocked() +} + +// flushUnlocked executes all pending operations without acquiring the lock (must be called with lock held) +func (w *writer) flushUnlocked() error { + if len(w.batchBuffer) == 0 { + return nil + } + + log.WithFields( + "operations", len(w.batchBuffer), + "batch_size", w.batchSize, + ).Debug("flushing batch") + + for i, op := range w.batchBuffer { + if err := op(); err != nil { + return fmt.Errorf("batch operation %d failed: %w", i, err) + } + } + + w.batchBuffer = w.batchBuffer[:0] + w.totalBatches++ + return nil +} + // metadataAndClose closes the database and returns its metadata. // The reason this is a compound action is that getting the built time and // schema version from the database is an operation on the open database, // but the checksum must be computed after the database is compacted and closed. -func (w writer) metadataAndClose() (*distribution.Metadata, error) { +func (w *writer) metadataAndClose() (*distribution.Metadata, error) { storeID, err := w.store.GetID() if err != nil { return nil, fmt.Errorf("failed to fetch store ID: %w", err) @@ -120,7 +190,7 @@ } } -func (w writer) ProviderMetadata() *ProviderMetadata { +func (w *writer) ProviderMetadata() *ProviderMetadata { metadata := NewProviderMetadata() // Set provider time from states for _, state := range w.states { @@ -132,7 +202,12 @@ return &metadata } -func (w writer) Close() error { +func (w *writer) Close() error { + // Flush any remaining batched operations + if err := w.Flush(); err != nil { + return fmt.Errorf("unable to flush pending writes: %w", err) + } + metadata, err := w.metadataAndClose() if err != nil { return err @@ -148,7 +223,10 @@ return err } - log.WithFields("path", w.dbPath).Info("database created") + log.WithFields( + "path", w.dbPath, + "total_batches", w.totalBatches, + ).Info("database created") log.WithFields("path", metadataPath).Debug("database metadata created") log.WithFields("path", providerMetadataPath).Debug("provider metadata created") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/grype-db-0.51.0/pkg/process/v6/batching_test.go new/grype-db-0.52.0/pkg/process/v6/batching_test.go --- old/grype-db-0.51.0/pkg/process/v6/batching_test.go 1970-01-01 01:00:00.000000000 +0100 +++ new/grype-db-0.52.0/pkg/process/v6/batching_test.go 2026-02-11 11:56:03.000000000 +0100 @@ -0,0 +1,212 @@ +package v6 + +import ( + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/anchore/grype-db/pkg/data" + "github.com/anchore/grype-db/pkg/process/v6/transformers" + "github.com/anchore/grype-db/pkg/provider" + grypeDB "github.com/anchore/grype/grype/db/v6" +) + +func TestBatchedWritesEquivalence(t *testing.T) { + // Test that batched writes produce identical database output to unbatched writes + // This is the critical correctness test for the batching optimization + + testCases := []struct { + name string + batchSize int + numEntries int + }{ + { + name: "unbatched (batch_size=1)", + batchSize: 1, + numEntries: 50, + }, + { + name: "small batch", + batchSize: 10, + numEntries: 50, + }, + { + name: "large batch", + batchSize: 2000, + numEntries: 50, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + // Create temp directory for database + tmpDir := t.TempDir() + + // Create writer with specified batch size + w, err := NewWriter(tmpDir, provider.States{}, false, tc.batchSize) + require.NoError(t, err) + + // Write test entries + entries := createTestEntries(tc.numEntries) + for _, entry := range entries { + err := w.Write(entry) + require.NoError(t, err) + } + + // Close to flush all batches + err = w.Close() + require.NoError(t, err) + + // Verify database was created + dbPath := filepath.Join(tmpDir, "vulnerability.db") + _, err = os.Stat(dbPath) + require.NoError(t, err, "database file should exist") + + // Open and verify database contents + reader, err := grypeDB.NewReader(grypeDB.Config{DBDirPath: tmpDir}) + require.NoError(t, err) + defer reader.Close() + + // Basic validation: verify we can read data back + // More detailed validation would require actual query methods + // but this proves the database is valid and readable + }) + } +} + +func TestBatchAccumulation(t *testing.T) { + // Test that operations accumulate in buffers before flushing + tmpDir := t.TempDir() + + w, err := NewWriter(tmpDir, provider.States{}, false, 1000) + require.NoError(t, err) + + writerImpl := w.(*writer) + + // Write 50 entries (below batch threshold of 1000) + entries := createTestEntries(50) + for _, entry := range entries { + err := writerImpl.Write(entry) + require.NoError(t, err) + } + + // Verify buffers contain accumulated operations (not flushed yet) + assert.Greater(t, len(writerImpl.parentBuffer), 0, "parent buffer should contain operations") + assert.Greater(t, len(writerImpl.childBuffer), 0, "child buffer should contain operations") + assert.Equal(t, 0, writerImpl.totalParentBatches, "should not have flushed yet") + assert.Equal(t, 0, writerImpl.totalChildBatches, "should not have flushed yet") + + // Close should flush everything + err = writerImpl.Close() + require.NoError(t, err) + + // Verify buffers were flushed + assert.Equal(t, 0, len(writerImpl.parentBuffer), "parent buffer should be empty after close") + assert.Equal(t, 0, len(writerImpl.childBuffer), "child buffer should be empty after close") + assert.Greater(t, writerImpl.totalParentBatches, 0, "should have flushed parent batch") + assert.Greater(t, writerImpl.totalChildBatches, 0, "should have flushed child batch") +} + +func TestBatchMetrics(t *testing.T) { + // Test that batch counts accurately reflect number of flushes + tmpDir := t.TempDir() + + batchSize := 25 + numEntries := 100 + + w, err := NewWriter(tmpDir, provider.States{}, false, batchSize) + require.NoError(t, err) + + writerImpl := w.(*writer) + + // Write entries + entries := createTestEntries(numEntries) + for _, entry := range entries { + err := writerImpl.Write(entry) + require.NoError(t, err) + } + + err = writerImpl.Close() + require.NoError(t, err) + + // Verify batch counts + // With 100 entries, batchSize=25: + // - Parent ops: 100 vulnerabilities / 25 = 4 batches + // - Child ops: depends on children per entry, but should also batch + assert.Greater(t, writerImpl.totalParentBatches, 0, "should have parent batches") + assert.Greater(t, writerImpl.totalChildBatches, 0, "should have child batches") +} + +func TestBatchSizeConfiguration(t *testing.T) { + // Test that batch size defaults and configuration work correctly + tmpDir := t.TempDir() + + tests := []struct { + name string + inputSize int + expectedSize int + }{ + { + name: "default (0 -> 2000)", + inputSize: 0, + expectedSize: 2000, + }, + { + name: "custom size", + inputSize: 500, + expectedSize: 500, + }, + { + name: "unbatched mode", + inputSize: 1, + expectedSize: 1, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + w, err := NewWriter(tmpDir, provider.States{}, false, tt.inputSize) + require.NoError(t, err) + defer w.Close() + + writerImpl := w.(*writer) + assert.Equal(t, tt.expectedSize, writerImpl.parentBatchSize) + assert.Equal(t, tt.expectedSize, writerImpl.childBatchSize) + }) + } +} + +// createTestEntries creates test entries with unique identifiable content +func createTestEntries(count int) []data.Entry { + entries := make([]data.Entry, count) + + for i := 0; i < count; i++ { + entries[i] = data.Entry{ + DBSchemaVersion: grypeDB.ModelVersion, + Data: transformers.RelatedEntries{ + VulnerabilityHandle: &grypeDB.VulnerabilityHandle{ + Name: "CVE-2023-TEST", + ProviderID: "test-provider", + Provider: &grypeDB.Provider{ + ID: "test-provider", + Version: "1.0.0", + }, + BlobValue: &grypeDB.VulnerabilityBlob{ + ID: "CVE-2023-TEST", + }, + }, + Related: []any{ + grypeDB.CWEHandle{ + CVE: "CVE-2023-TEST", + CWE: "CWE-79", + }, + }, + }, + } + } + + return entries +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/grype-db-0.51.0/pkg/process/v6/transformers/os/transform.go new/grype-db-0.52.0/pkg/process/v6/transformers/os/transform.go --- old/grype-db-0.51.0/pkg/process/v6/transformers/os/transform.go 2026-02-06 13:53:02.000000000 +0100 +++ new/grype-db-0.52.0/pkg/process/v6/transformers/os/transform.go 2026-02-11 11:56:03.000000000 +0100 @@ -240,7 +240,7 @@ func getPackageType(osName string) pkg.Type { switch osName { - case "redhat", "amazonlinux", "oraclelinux", "sles", "mariner", "azurelinux": + case "redhat", "amazonlinux", "oraclelinux", "sles", "mariner", "azurelinux", "photon": return pkg.RpmPkg case "ubuntu", "debian", "echo": return pkg.DebPkg diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/grype-db-0.51.0/pkg/process/v6/writer.go new/grype-db-0.52.0/pkg/process/v6/writer.go --- old/grype-db-0.51.0/pkg/process/v6/writer.go 2026-02-06 13:53:02.000000000 +0100 +++ new/grype-db-0.52.0/pkg/process/v6/writer.go 2026-02-11 11:56:03.000000000 +0100 @@ -3,6 +3,7 @@ import ( "fmt" "strings" + "sync" "time" "github.com/anchore/go-logger" @@ -22,6 +23,18 @@ providerCache map[string]grypeDB.Provider states provider.States severityCache map[string]grypeDB.Severity + + // Two-tier batching: parent records (vulnerabilities + providers) and child records (related entries) + // This maintains FK integrity while maximizing batch sizes + parentBatchSize int + childBatchSize int + parentBuffer []func() error + childBuffer []func() error + mu sync.Mutex // Protect batch state + + // Metrics + totalParentBatches int + totalChildBatches int } type ProviderMetadata struct { @@ -33,7 +46,7 @@ LastSuccessfulRun time.Time `json:"lastSuccessfulRun"` } -func NewWriter(directory string, states provider.States, failOnMissingFixDate bool) (data.Writer, error) { +func NewWriter(directory string, states provider.States, failOnMissingFixDate bool, batchSize int) (data.Writer, error) { cfg := grypeDB.Config{ DBDirPath: directory, } @@ -46,6 +59,11 @@ return nil, fmt.Errorf("unable to set DB ID: %w", err) } + // Use default if not configured + if batchSize == 0 { + batchSize = 2000 + } + return &writer{ dbPath: cfg.DBFilePath(), failOnMissingFixDate: failOnMissingFixDate, @@ -53,10 +71,14 @@ store: s, states: states, severityCache: make(map[string]grypeDB.Severity), + parentBatchSize: batchSize, + childBatchSize: batchSize, + parentBuffer: make([]func() error, 0, batchSize), + childBuffer: make([]func() error, 0, batchSize), }, nil } -func (w writer) Write(entries ...data.Entry) error { +func (w *writer) Write(entries ...data.Entry) error { for _, entry := range entries { if entry.DBSchemaVersion != grypeDB.ModelVersion { return fmt.Errorf("wrong schema version: want %+v got %+v", grypeDB.ModelVersion, entry.DBSchemaVersion) @@ -81,17 +103,30 @@ if entry.VulnerabilityHandle != nil { w.fillInMissingSeverity(entry.VulnerabilityHandle) - if err := w.store.AddVulnerabilities(entry.VulnerabilityHandle); err != nil { - return fmt.Errorf("unable to write vulnerability to store: %w", err) + // Add vulnerability to parent batch + // CRITICAL: Use pointer directly (not copy) so ID assignment propagates to child operations + vulnHandle := entry.VulnerabilityHandle + if err := w.addToParentBatch(func() error { + return w.store.AddVulnerabilities(vulnHandle) + }); err != nil { + return fmt.Errorf("unable to batch vulnerability write: %w", err) } } - if entry.Provider != nil { - if err := w.store.AddProvider(*entry.Provider); err != nil { - return fmt.Errorf("unable to write provider to store: %w", err) + // Handle providers for entries without vulnerabilities (EPSS, KEV, etc.) + // AddVulnerabilities() only handles providers implicitly for vulnerability entries + if entry.Provider != nil && entry.VulnerabilityHandle == nil { + provider := *entry.Provider + if err := w.addToParentBatch(func() error { + return w.store.AddProvider(provider) + }); err != nil { + return fmt.Errorf("unable to batch provider write: %w", err) } } + // Add all related entries to child batch + // NOTE: No explicit flush here. Parent batch auto-flushes at threshold. + // Child batch auto-flush will flush parent first to maintain FK integrity. for i := range entry.Related { if err := w.writeRelatedEntry(entry.VulnerabilityHandle, entry.Related[i]); err != nil { return err @@ -108,29 +143,43 @@ case grypeDB.AffectedCPEHandle: return w.writeAffectedCPE(vulnHandle, row) case grypeDB.KnownExploitedVulnerabilityHandle: - return w.store.AddKnownExploitedVulnerabilities(&row) + // Add KEV to child batch - copy to avoid pointer reuse + kevHandle := row + return w.addToChildBatch(func() error { + handleCopy := kevHandle + return w.store.AddKnownExploitedVulnerabilities(&handleCopy) + }) case grypeDB.UnaffectedPackageHandle: return w.writeUnaffectedPackage(vulnHandle, row) case grypeDB.UnaffectedCPEHandle: return w.writeUnaffectedCPE(vulnHandle, row) case grypeDB.EpssHandle: - return w.store.AddEpss(&row) + // Add EPSS to child batch - copy to avoid pointer reuse + epssHandle := row + return w.addToChildBatch(func() error { + handleCopy := epssHandle + return w.store.AddEpss(&handleCopy) + }) case grypeDB.CWEHandle: - return w.store.AddCWE(&row) + // Add CWE to child batch - copy to avoid pointer reuse + cweHandle := row + return w.addToChildBatch(func() error { + handleCopy := cweHandle + return w.store.AddCWE(&handleCopy) + }) case grypeDB.OperatingSystemEOLHandle: - return w.writeOperatingSystemEOL(row) + // Add OS EOL to child batch - copy to avoid pointer reuse + eolHandle := row + return w.addToChildBatch(func() error { + handleCopy := eolHandle + return w.writeOperatingSystemEOL(handleCopy) + }) default: return fmt.Errorf("data entry is not of type vulnerability, vulnerability metadata, or exclusion: %T", row) } } func (w *writer) writeAffectedPackage(vulnHandle *grypeDB.VulnerabilityHandle, row grypeDB.AffectedPackageHandle) error { - if vulnHandle != nil { - row.VulnerabilityID = vulnHandle.ID - } else { - log.WithFields("package", row.Package).Warn("affected package entry does not have a vulnerability ID") - } - if w.failOnMissingFixDate { if err := ensureFixDates(&row); err != nil { fields := logger.Fields{ @@ -150,46 +199,60 @@ } } - if err := w.store.AddAffectedPackages(&row); err != nil { - return fmt.Errorf("unable to write affected-package to store: %w", err) - } - return nil + // Add affected package to child batch - defer VulnerabilityID assignment until flush + pkgHandle := row + return w.addToChildBatch(func() error { + handleCopy := pkgHandle + if vulnHandle != nil { + handleCopy.VulnerabilityID = vulnHandle.ID + } else { + log.WithFields("package", handleCopy.Package).Warn("affected package entry does not have a vulnerability ID") + } + return w.store.AddAffectedPackages(&handleCopy) + }) } func (w *writer) writeAffectedCPE(vulnHandle *grypeDB.VulnerabilityHandle, row grypeDB.AffectedCPEHandle) error { - if vulnHandle != nil { - row.VulnerabilityID = vulnHandle.ID - } else { - log.WithFields("cpe", row.CPE).Warn("affected CPE entry does not have a vulnerability ID") - } - if err := w.store.AddAffectedCPEs(&row); err != nil { - return fmt.Errorf("unable to write affected-cpe to store: %w", err) - } - return nil + // Add affected CPE to child batch - defer VulnerabilityID assignment until flush + // when the parent vulnerability has been written and ID is assigned + cpeHandle := row + return w.addToChildBatch(func() error { + handleCopy := cpeHandle + if vulnHandle != nil { + handleCopy.VulnerabilityID = vulnHandle.ID + } else { + log.WithFields("cpe", handleCopy.CPE).Warn("affected CPE entry does not have a vulnerability ID") + } + return w.store.AddAffectedCPEs(&handleCopy) + }) } func (w *writer) writeUnaffectedPackage(vulnHandle *grypeDB.VulnerabilityHandle, row grypeDB.UnaffectedPackageHandle) error { - if vulnHandle != nil { - row.VulnerabilityID = vulnHandle.ID - } else { - log.WithFields("package", row.Package).Warn("unaffected package entry does not have a vulnerability ID") - } - if err := w.store.AddUnaffectedPackages(&row); err != nil { - return fmt.Errorf("unable to write unaffected-package to store: %w", err) - } - return nil + // Add unaffected package to child batch - defer VulnerabilityID assignment until flush + pkgHandle := row + return w.addToChildBatch(func() error { + handleCopy := pkgHandle + if vulnHandle != nil { + handleCopy.VulnerabilityID = vulnHandle.ID + } else { + log.WithFields("package", handleCopy.Package).Warn("unaffected package entry does not have a vulnerability ID") + } + return w.store.AddUnaffectedPackages(&handleCopy) + }) } func (w *writer) writeUnaffectedCPE(vulnHandle *grypeDB.VulnerabilityHandle, row grypeDB.UnaffectedCPEHandle) error { - if vulnHandle != nil { - row.VulnerabilityID = vulnHandle.ID - } else { - log.WithFields("cpe", row.CPE).Warn("unaffected CPE entry does not have a vulnerability ID") - } - if err := w.store.AddUnaffectedCPEs(&row); err != nil { - return fmt.Errorf("unable to write unaffected-cpe to store: %w", err) - } - return nil + // Add unaffected CPE to child batch - defer VulnerabilityID assignment until flush + cpeHandle := row + return w.addToChildBatch(func() error { + handleCopy := cpeHandle + if vulnHandle != nil { + handleCopy.VulnerabilityID = vulnHandle.ID + } else { + log.WithFields("cpe", handleCopy.CPE).Warn("unaffected CPE entry does not have a vulnerability ID") + } + return w.store.AddUnaffectedCPEs(&handleCopy) + }) } // fillInMissingSeverity will add a severity entry to the vulnerability record if it is missing, empty, or "unknown". @@ -249,12 +312,111 @@ handle.BlobValue.Severities = sevs } -func (w writer) Close() error { +// addToParentBatch adds an operation to parent buffer and flushes when threshold reached +func (w *writer) addToParentBatch(op func() error) error { + w.mu.Lock() + defer w.mu.Unlock() + + w.parentBuffer = append(w.parentBuffer, op) + + // Flush parent batch when it reaches threshold to limit memory usage + if len(w.parentBuffer) >= w.parentBatchSize { + return w.flushParentBatchLocked() + } + return nil +} + +// addToChildBatch adds an operation to child buffer and flushes when threshold reached +func (w *writer) addToChildBatch(op func() error) error { + w.mu.Lock() + defer w.mu.Unlock() + + w.childBuffer = append(w.childBuffer, op) + + // When child buffer is full, flush BOTH buffers (parents first for FK integrity) + if len(w.childBuffer) >= w.childBatchSize { + // Flush parents first to ensure IDs are assigned for children to reference + if err := w.flushParentBatchLocked(); err != nil { + return err + } + // Then flush children + return w.flushChildBatchLocked() + } + return nil +} + +// flushParentBatch executes all pending parent operations in batches of parentBatchSize +func (w *writer) flushParentBatch() error { + w.mu.Lock() + defer w.mu.Unlock() + return w.flushParentBatchLocked() +} + +// flushParentBatchLocked executes all pending parent operations (must be called with lock held) +func (w *writer) flushParentBatchLocked() error { + if len(w.parentBuffer) == 0 { + return nil + } + + log.WithFields("total_operations", len(w.parentBuffer), "batch_size", w.parentBatchSize).Debug("flushing parent operations") + + // Execute all accumulated operations + for j, op := range w.parentBuffer { + if err := op(); err != nil { + return fmt.Errorf("parent operation %d failed: %w", j, err) + } + } + + w.totalParentBatches++ + w.parentBuffer = w.parentBuffer[:0] + return nil +} + +// flushChildBatch executes all pending child operations in batches of childBatchSize +func (w *writer) flushChildBatch() error { + w.mu.Lock() + defer w.mu.Unlock() + return w.flushChildBatchLocked() +} + +// flushChildBatchLocked executes all pending child operations (must be called with lock held) +func (w *writer) flushChildBatchLocked() error { + if len(w.childBuffer) == 0 { + return nil + } + + log.WithFields("total_operations", len(w.childBuffer), "batch_size", w.childBatchSize).Debug("flushing child operations") + + // Execute all accumulated operations + for j, op := range w.childBuffer { + if err := op(); err != nil { + return fmt.Errorf("child operation %d failed: %w", j, err) + } + } + + w.totalChildBatches++ + w.childBuffer = w.childBuffer[:0] + return nil +} + +func (w *writer) Close() error { + // Flush any remaining batched operations (both parent and child) + if err := w.flushParentBatch(); err != nil { + return fmt.Errorf("unable to flush parent batch: %w", err) + } + if err := w.flushChildBatch(); err != nil { + return fmt.Errorf("unable to flush child batch: %w", err) + } + if err := w.store.Close(); err != nil { return fmt.Errorf("unable to close store: %w", err) } - log.WithFields("path", w.dbPath).Info("database created") + log.WithFields( + "path", w.dbPath, + "parent_batches", w.totalParentBatches, + "child_batches", w.totalChildBatches, + ).Info("database created") return nil } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/grype-db-0.51.0/scripts/verify_database_integrity.sh new/grype-db-0.52.0/scripts/verify_database_integrity.sh --- old/grype-db-0.51.0/scripts/verify_database_integrity.sh 1970-01-01 01:00:00.000000000 +0100 +++ new/grype-db-0.52.0/scripts/verify_database_integrity.sh 2026-02-11 11:56:03.000000000 +0100 @@ -0,0 +1,220 @@ +#!/bin/bash +# Database Integrity Verification Script +# +# Compares databases built with different batch sizes to verify batching +# doesn't alter database contents. +# +# Prerequisites: +# - vunnel data must be pulled first (grype-db pull) +# - Requires sqlite3 CLI tool +# +# Usage: +# PROVIDER=wolfi ./scripts/verify_database_integrity.sh + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" + +# Configuration +PROVIDER="${PROVIDER:-wolfi}" +BASELINE_DIR="${BASELINE_DIR:-/tmp/grype-db-baseline}" +OPTIMIZED_DIR="${OPTIMIZED_DIR:-/tmp/grype-db-optimized}" +BATCH_SIZE="${BATCH_SIZE:-2000}" + +echo "======================================" +echo "Database Integrity Verification" +echo "======================================" +echo "Provider: $PROVIDER" +echo "Baseline: $BASELINE_DIR" +echo "Optimized: $OPTIMIZED_DIR" +echo "Batch Size: $BATCH_SIZE" +echo "======================================" + +# Clean up previous runs +echo "" +echo "Cleaning up previous runs..." +rm -rf "$BASELINE_DIR" "$OPTIMIZED_DIR" +mkdir -p "$BASELINE_DIR" "$OPTIMIZED_DIR" + +# Build grype-db binary with current code +echo "" +echo "Building grype-db with batching support..." +cd "$REPO_ROOT" +go build -o /tmp/grype-db-verify-test ./cmd/grype-db + +# Build baseline with batch_size=1 (simulates unbatched behavior) +echo "" +echo "Building baseline database (batch_size=1, unbatched)..." +GRYPE_DB_CONFIG=/tmp/grype-db-test.yaml /tmp/grype-db-verify-test build \ + --schema 6 \ + --batch-size 1 \ + --dir="$BASELINE_DIR" \ + 2>&1 | tee "$BASELINE_DIR/build.log" + +# Build optimized with batch_size=2000 (batched) +echo "" +echo "Building optimized database (batch_size=$BATCH_SIZE, batched)..." +GRYPE_DB_CONFIG=/tmp/grype-db-test.yaml /tmp/grype-db-verify-test build \ + --schema 6 \ + --batch-size "$BATCH_SIZE" \ + --dir="$OPTIMIZED_DIR" \ + 2>&1 | tee "$OPTIMIZED_DIR/build.log" + +# Compare databases +echo "" +echo "======================================" +echo "Comparing Databases" +echo "======================================" + +BASELINE_DB="$BASELINE_DIR/vulnerability.db" +OPTIMIZED_DB="$OPTIMIZED_DIR/vulnerability.db" + +if [ ! -f "$BASELINE_DB" ]; then + echo "ERROR: Baseline database not found at $BASELINE_DB" + exit 1 +fi + +if [ ! -f "$OPTIMIZED_DB" ]; then + echo "ERROR: Optimized database not found at $OPTIMIZED_DB" + exit 1 +fi + +# Compare vulnerability counts (v6 schema uses vulnerability_handles table) +echo "" +echo "Comparing vulnerability counts..." +BASELINE_COUNT=$(sqlite3 "$BASELINE_DB" "SELECT COUNT(*) FROM vulnerability_handles") +OPTIMIZED_COUNT=$(sqlite3 "$OPTIMIZED_DB" "SELECT COUNT(*) FROM vulnerability_handles") + +echo "Baseline vulnerabilities: $BASELINE_COUNT" +echo "Optimized vulnerabilities: $OPTIMIZED_COUNT" + +if [ "$BASELINE_COUNT" != "$OPTIMIZED_COUNT" ]; then + echo "❌ ERROR: Vulnerability count mismatch!" + exit 1 +fi + +echo "✅ Vulnerability counts match" + +# Compare provider counts +echo "" +echo "Comparing provider counts..." +BASELINE_PROVIDERS=$(sqlite3 "$BASELINE_DB" "SELECT COUNT(DISTINCT id) FROM providers") +OPTIMIZED_PROVIDERS=$(sqlite3 "$OPTIMIZED_DB" "SELECT COUNT(DISTINCT id) FROM providers") + +echo "Baseline providers: $BASELINE_PROVIDERS" +echo "Optimized providers: $OPTIMIZED_PROVIDERS" + +if [ "$BASELINE_PROVIDERS" != "$OPTIMIZED_PROVIDERS" ]; then + echo "❌ ERROR: Provider count mismatch!" + exit 1 +fi + +echo "✅ Provider counts match" + +# Check for orphaned records (FK integrity - critical for two-tier batching) +echo "" +echo "Checking for orphaned records (Foreign Key integrity)..." + +# v6 schema tables with vulnerability_id FK +TABLES_V6=("affected_cpe_handles" "affected_package_handles" "unaffected_cpe_handles" "unaffected_package_handles") +# v5 schema uses different table structure - skip for now +ORPHAN_ERRORS=0 + +for table in "${TABLES_V6[@]}"; do + # Check if table exists first (v6 only) + if sqlite3 "$OPTIMIZED_DB" "SELECT name FROM sqlite_master WHERE type='table' AND name='$table';" | grep -q "$table"; then + # Check for NULL or 0 IDs (0 indicates uninitialized/unassigned ID) + ORPHANS=$(sqlite3 "$OPTIMIZED_DB" "SELECT COUNT(*) FROM $table WHERE vulnerability_id IS NULL OR vulnerability_id = 0;") + + if [ "$ORPHANS" -ne "0" ]; then + echo "❌ ERROR: Found $ORPHANS orphaned records in table '$table'" + ORPHAN_ERRORS=1 + else + echo "✅ No orphans in '$table'" + fi + fi +done + +if [ "$ORPHAN_ERRORS" -ne "0" ]; then + echo "❌ FK integrity check failed: Orphaned records detected" + echo " This indicates parent IDs were not properly propagated to child records" + exit 1 +fi + +echo "✅ FK integrity verified - all child records reference valid parents" + +# Compare SQL dumps (sorted for consistent comparison) +echo "" +echo "Comparing SQL dumps (this may take a while)..." +sqlite3 "$BASELINE_DB" .dump | sort > /tmp/baseline.sql +sqlite3 "$OPTIMIZED_DB" .dump | sort > /tmp/optimized.sql + +if diff /tmp/baseline.sql /tmp/optimized.sql > /tmp/db-diff.txt 2>&1; then + echo "✅ Databases are identical (byte-for-byte)" +else + echo "⚠️ Databases differ - reviewing differences..." + + # Check if differences are only in metadata/timestamps + DIFF_LINES=$(wc -l < /tmp/db-diff.txt) + echo "Number of differing lines: $DIFF_LINES" + + # Show first 50 lines of diff + echo "" + echo "First 50 lines of diff:" + head -50 /tmp/db-diff.txt + + echo "" + echo "Full diff saved to: /tmp/db-diff.txt" + echo "" + echo "⚠️ Review the diff to determine if differences are acceptable" + echo " (e.g., timestamp differences, ordering differences)" + + # Don't fail - let the user review +fi + +# Compare table schemas +echo "" +echo "Comparing table schemas..." +sqlite3 "$BASELINE_DB" ".schema" | sort > /tmp/baseline-schema.sql +sqlite3 "$OPTIMIZED_DB" ".schema" | sort > /tmp/optimized-schema.sql + +if diff /tmp/baseline-schema.sql /tmp/optimized-schema.sql > /dev/null 2>&1; then + echo "✅ Schemas are identical" +else + echo "❌ ERROR: Schemas differ!" + diff /tmp/baseline-schema.sql /tmp/optimized-schema.sql + exit 1 +fi + +# Extract performance metrics from logs +echo "" +echo "======================================" +echo "Performance Metrics" +echo "======================================" + +echo "" +echo "Baseline build log:" +grep -E "(total_batches|provider_cache|database created)" "$BASELINE_DIR/build.log" || true + +echo "" +echo "Optimized build log:" +grep -E "(total_batches|provider_cache|database created)" "$OPTIMIZED_DIR/build.log" || true + +echo "" +echo "======================================" +echo "Verification Complete" +echo "======================================" +echo "" +echo "Summary:" +echo " ✅ Vulnerability counts match" +echo " ✅ Provider counts match" +echo " ✅ Schemas are identical" +echo "" +echo "Databases location:" +echo " Baseline: $BASELINE_DB" +echo " Optimized: $OPTIMIZED_DB" +echo "" +echo "To manually inspect the databases:" +echo " sqlite3 $BASELINE_DB" +echo " sqlite3 $OPTIMIZED_DB" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/grype-db-0.51.0/uv.lock new/grype-db-0.52.0/uv.lock --- old/grype-db-0.51.0/uv.lock 2026-02-06 13:53:02.000000000 +0100 +++ new/grype-db-0.52.0/uv.lock 2026-02-11 11:56:03.000000000 +0100 @@ -4,16 +4,16 @@ [[package]] name = "boto3" -version = "1.42.38" +version = "1.42.41" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "botocore" }, { name = "jmespath" }, { name = "s3transfer" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e8/38/1e5eb348e41d97ca2b6164df28501409c2fe9bd34455c256dd87644b7c0e/boto3-1.42.38.tar.gz", hash = "sha256:af2e5c08972d35fa4b4bc457031794343a6ddb1df5692db43302d5b5feaac23e", size = 112852, upload-time = "2026-01-29T20:39:37.786Z" } +sdist = { url = "https://files.pythonhosted.org/packages/85/b0/f2a371146877b4d60cd2a6f51c440503cbf77a73c85347ad282eebe90269/boto3-1.42.41.tar.gz", hash = "sha256:86dd2bc577e33da5cd9f10e21b22cdda01a24f83f31ca1bb5ac1f5f8b8e9e67e", size = 112806, upload-time = "2026-02-03T20:38:58.004Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/98/22e5f4f5ced6cf1aface4b438307a157e9cb7a4bcbd19f4b9dec89b0fe33/boto3-1.42.38-py3-none-any.whl", hash = "sha256:b5a748b3fdddba8aa2988af0e462996ef72dc2760b0eab30329b9d201d4b38f2", size = 140606, upload-time = "2026-01-29T20:39:36.641Z" }, + { url = "https://files.pythonhosted.org/packages/7b/e8/e671b9aed3e8f6bb5f85aed7fd9dd4e79074798b2a14391fab6b6da04ff7/boto3-1.42.41-py3-none-any.whl", hash = "sha256:32470b1d32208e03b47cf6ce4a7adb337b8a1730aaefb97c336cfd4e2be2577f", size = 140602, upload-time = "2026-02-03T20:38:56.352Z" }, ] [[package]] @@ -41,47 +41,50 @@ [[package]] name = "cffi" -version = "1.17.1" +version = "2.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pycparser" }, + { name = "pycparser", marker = "implementation_name != 'PyPy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621, upload-time = "2024-09-04T20:45:21.852Z" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6b/f4/927e3a8899e52a27fa57a48607ff7dc91a9ebe97399b357b85a0c7892e00/cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401", size = 182264, upload-time = "2024-09-04T20:43:51.124Z" }, - { url = "https://files.pythonhosted.org/packages/6c/f5/6c3a8efe5f503175aaddcbea6ad0d2c96dad6f5abb205750d1b3df44ef29/cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf", size = 178651, upload-time = "2024-09-04T20:43:52.872Z" }, - { url = "https://files.pythonhosted.org/packages/94/dd/a3f0118e688d1b1a57553da23b16bdade96d2f9bcda4d32e7d2838047ff7/cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4", size = 445259, upload-time = "2024-09-04T20:43:56.123Z" }, - { url = "https://files.pythonhosted.org/packages/2e/ea/70ce63780f096e16ce8588efe039d3c4f91deb1dc01e9c73a287939c79a6/cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", size = 469200, upload-time = "2024-09-04T20:43:57.891Z" }, - { url = "https://files.pythonhosted.org/packages/1c/a0/a4fa9f4f781bda074c3ddd57a572b060fa0df7655d2a4247bbe277200146/cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", size = 477235, upload-time = "2024-09-04T20:44:00.18Z" }, - { url = "https://files.pythonhosted.org/packages/62/12/ce8710b5b8affbcdd5c6e367217c242524ad17a02fe5beec3ee339f69f85/cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", size = 459721, upload-time = "2024-09-04T20:44:01.585Z" }, - { url = "https://files.pythonhosted.org/packages/ff/6b/d45873c5e0242196f042d555526f92aa9e0c32355a1be1ff8c27f077fd37/cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", size = 467242, upload-time = "2024-09-04T20:44:03.467Z" }, - { url = "https://files.pythonhosted.org/packages/1a/52/d9a0e523a572fbccf2955f5abe883cfa8bcc570d7faeee06336fbd50c9fc/cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", size = 477999, upload-time = "2024-09-04T20:44:05.023Z" }, - { url = "https://files.pythonhosted.org/packages/44/74/f2a2460684a1a2d00ca799ad880d54652841a780c4c97b87754f660c7603/cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f", size = 454242, upload-time = "2024-09-04T20:44:06.444Z" }, - { url = "https://files.pythonhosted.org/packages/f8/4a/34599cac7dfcd888ff54e801afe06a19c17787dfd94495ab0c8d35fe99fb/cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b", size = 478604, upload-time = "2024-09-04T20:44:08.206Z" }, - { url = "https://files.pythonhosted.org/packages/34/33/e1b8a1ba29025adbdcda5fb3a36f94c03d771c1b7b12f726ff7fef2ebe36/cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655", size = 171727, upload-time = "2024-09-04T20:44:09.481Z" }, - { url = "https://files.pythonhosted.org/packages/3d/97/50228be003bb2802627d28ec0627837ac0bf35c90cf769812056f235b2d1/cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0", size = 181400, upload-time = "2024-09-04T20:44:10.873Z" }, - { url = "https://files.pythonhosted.org/packages/5a/84/e94227139ee5fb4d600a7a4927f322e1d4aea6fdc50bd3fca8493caba23f/cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", size = 183178, upload-time = "2024-09-04T20:44:12.232Z" }, - { url = "https://files.pythonhosted.org/packages/da/ee/fb72c2b48656111c4ef27f0f91da355e130a923473bf5ee75c5643d00cca/cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", size = 178840, upload-time = "2024-09-04T20:44:13.739Z" }, - { url = "https://files.pythonhosted.org/packages/cc/b6/db007700f67d151abadf508cbfd6a1884f57eab90b1bb985c4c8c02b0f28/cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", size = 454803, upload-time = "2024-09-04T20:44:15.231Z" }, - { url = "https://files.pythonhosted.org/packages/1a/df/f8d151540d8c200eb1c6fba8cd0dfd40904f1b0682ea705c36e6c2e97ab3/cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", size = 478850, upload-time = "2024-09-04T20:44:17.188Z" }, - { url = "https://files.pythonhosted.org/packages/28/c0/b31116332a547fd2677ae5b78a2ef662dfc8023d67f41b2a83f7c2aa78b1/cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", size = 485729, upload-time = "2024-09-04T20:44:18.688Z" }, - { url = "https://files.pythonhosted.org/packages/91/2b/9a1ddfa5c7f13cab007a2c9cc295b70fbbda7cb10a286aa6810338e60ea1/cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", size = 471256, upload-time = "2024-09-04T20:44:20.248Z" }, - { url = "https://files.pythonhosted.org/packages/b2/d5/da47df7004cb17e4955df6a43d14b3b4ae77737dff8bf7f8f333196717bf/cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", size = 479424, upload-time = "2024-09-04T20:44:21.673Z" }, - { url = "https://files.pythonhosted.org/packages/0b/ac/2a28bcf513e93a219c8a4e8e125534f4f6db03e3179ba1c45e949b76212c/cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", size = 484568, upload-time = "2024-09-04T20:44:23.245Z" }, - { url = "https://files.pythonhosted.org/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736, upload-time = "2024-09-04T20:44:24.757Z" }, - { url = "https://files.pythonhosted.org/packages/86/c5/28b2d6f799ec0bdecf44dced2ec5ed43e0eb63097b0f58c293583b406582/cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", size = 172448, upload-time = "2024-09-04T20:44:26.208Z" }, - { url = "https://files.pythonhosted.org/packages/50/b9/db34c4755a7bd1cb2d1603ac3863f22bcecbd1ba29e5ee841a4bc510b294/cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", size = 181976, upload-time = "2024-09-04T20:44:27.578Z" }, - { url = "https://files.pythonhosted.org/packages/8d/f8/dd6c246b148639254dad4d6803eb6a54e8c85c6e11ec9df2cffa87571dbe/cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", size = 182989, upload-time = "2024-09-04T20:44:28.956Z" }, - { url = "https://files.pythonhosted.org/packages/8b/f1/672d303ddf17c24fc83afd712316fda78dc6fce1cd53011b839483e1ecc8/cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", size = 178802, upload-time = "2024-09-04T20:44:30.289Z" }, - { url = "https://files.pythonhosted.org/packages/0e/2d/eab2e858a91fdff70533cab61dcff4a1f55ec60425832ddfdc9cd36bc8af/cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", size = 454792, upload-time = "2024-09-04T20:44:32.01Z" }, - { url = "https://files.pythonhosted.org/packages/75/b2/fbaec7c4455c604e29388d55599b99ebcc250a60050610fadde58932b7ee/cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", size = 478893, upload-time = "2024-09-04T20:44:33.606Z" }, - { url = "https://files.pythonhosted.org/packages/4f/b7/6e4a2162178bf1935c336d4da8a9352cccab4d3a5d7914065490f08c0690/cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", size = 485810, upload-time = "2024-09-04T20:44:35.191Z" }, - { url = "https://files.pythonhosted.org/packages/c7/8a/1d0e4a9c26e54746dc08c2c6c037889124d4f59dffd853a659fa545f1b40/cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", size = 471200, upload-time = "2024-09-04T20:44:36.743Z" }, - { url = "https://files.pythonhosted.org/packages/26/9f/1aab65a6c0db35f43c4d1b4f580e8df53914310afc10ae0397d29d697af4/cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", size = 479447, upload-time = "2024-09-04T20:44:38.492Z" }, - { url = "https://files.pythonhosted.org/packages/5f/e4/fb8b3dd8dc0e98edf1135ff067ae070bb32ef9d509d6cb0f538cd6f7483f/cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", size = 484358, upload-time = "2024-09-04T20:44:40.046Z" }, - { url = "https://files.pythonhosted.org/packages/f1/47/d7145bf2dc04684935d57d67dff9d6d795b2ba2796806bb109864be3a151/cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", size = 488469, upload-time = "2024-09-04T20:44:41.616Z" }, - { url = "https://files.pythonhosted.org/packages/bf/ee/f94057fa6426481d663b88637a9a10e859e492c73d0384514a17d78ee205/cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", size = 172475, upload-time = "2024-09-04T20:44:43.733Z" }, - { url = "https://files.pythonhosted.org/packages/7c/fc/6a8cb64e5f0324877d503c854da15d76c1e50eb722e320b15345c4d0c6de/cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", size = 182009, upload-time = "2024-09-04T20:44:45.309Z" }, + { url = "https://files.pythonhosted.org/packages/12/4a/3dfd5f7850cbf0d06dc84ba9aa00db766b52ca38d8b86e3a38314d52498c/cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe", size = 184344, upload-time = "2025-09-08T23:22:26.456Z" }, + { url = "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c", size = 180560, upload-time = "2025-09-08T23:22:28.197Z" }, + { url = "https://files.pythonhosted.org/packages/b1/b7/1200d354378ef52ec227395d95c2576330fd22a869f7a70e88e1447eb234/cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92", size = 209613, upload-time = "2025-09-08T23:22:29.475Z" }, + { url = "https://files.pythonhosted.org/packages/b8/56/6033f5e86e8cc9bb629f0077ba71679508bdf54a9a5e112a3c0b91870332/cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93", size = 216476, upload-time = "2025-09-08T23:22:31.063Z" }, + { url = "https://files.pythonhosted.org/packages/dc/7f/55fecd70f7ece178db2f26128ec41430d8720f2d12ca97bf8f0a628207d5/cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5", size = 203374, upload-time = "2025-09-08T23:22:32.507Z" }, + { url = "https://files.pythonhosted.org/packages/84/ef/a7b77c8bdc0f77adc3b46888f1ad54be8f3b7821697a7b89126e829e676a/cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664", size = 202597, upload-time = "2025-09-08T23:22:34.132Z" }, + { url = "https://files.pythonhosted.org/packages/d7/91/500d892b2bf36529a75b77958edfcd5ad8e2ce4064ce2ecfeab2125d72d1/cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26", size = 215574, upload-time = "2025-09-08T23:22:35.443Z" }, + { url = "https://files.pythonhosted.org/packages/44/64/58f6255b62b101093d5df22dcb752596066c7e89dd725e0afaed242a61be/cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9", size = 218971, upload-time = "2025-09-08T23:22:36.805Z" }, + { url = "https://files.pythonhosted.org/packages/ab/49/fa72cebe2fd8a55fbe14956f9970fe8eb1ac59e5df042f603ef7c8ba0adc/cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414", size = 211972, upload-time = "2025-09-08T23:22:38.436Z" }, + { url = "https://files.pythonhosted.org/packages/0b/28/dd0967a76aab36731b6ebfe64dec4e981aff7e0608f60c2d46b46982607d/cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743", size = 217078, upload-time = "2025-09-08T23:22:39.776Z" }, + { url = "https://files.pythonhosted.org/packages/2b/c0/015b25184413d7ab0a410775fdb4a50fca20f5589b5dab1dbbfa3baad8ce/cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5", size = 172076, upload-time = "2025-09-08T23:22:40.95Z" }, + { url = "https://files.pythonhosted.org/packages/ae/8f/dc5531155e7070361eb1b7e4c1a9d896d0cb21c49f807a6c03fd63fc877e/cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5", size = 182820, upload-time = "2025-09-08T23:22:42.463Z" }, + { url = "https://files.pythonhosted.org/packages/95/5c/1b493356429f9aecfd56bc171285a4c4ac8697f76e9bbbbb105e537853a1/cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d", size = 177635, upload-time = "2025-09-08T23:22:43.623Z" }, + { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" }, + { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" }, + { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" }, + { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" }, + { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" }, + { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" }, + { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" }, + { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" }, + { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" }, + { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" }, + { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" }, + { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" }, + { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" }, + { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" }, + { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" }, + { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" }, + { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" }, + { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" }, + { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" }, + { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" }, + { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" }, + { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" }, + { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" }, ] [[package]] @@ -221,37 +224,47 @@ [[package]] name = "cryptography" -version = "44.0.1" +version = "46.0.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c7/67/545c79fe50f7af51dbad56d16b23fe33f63ee6a5d956b3cb68ea110cbe64/cryptography-44.0.1.tar.gz", hash = "sha256:f51f5705ab27898afda1aaa430f34ad90dc117421057782022edf0600bec5f14", size = 710819, upload-time = "2025-02-11T15:50:58.39Z" } +sdist = { url = "https://files.pythonhosted.org/packages/60/04/ee2a9e8542e4fa2773b81771ff8349ff19cdd56b7258a0cc442639052edb/cryptography-46.0.5.tar.gz", hash = "sha256:abace499247268e3757271b2f1e244b36b06f8515cf27c4d49468fc9eb16e93d", size = 750064, upload-time = "2026-02-10T19:18:38.255Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/72/27/5e3524053b4c8889da65cf7814a9d0d8514a05194a25e1e34f46852ee6eb/cryptography-44.0.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bf688f615c29bfe9dfc44312ca470989279f0e94bb9f631f85e3459af8efc009", size = 6642022, upload-time = "2025-02-11T15:49:32.752Z" }, - { url = "https://files.pythonhosted.org/packages/34/b9/4d1fa8d73ae6ec350012f89c3abfbff19fc95fe5420cf972e12a8d182986/cryptography-44.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd7c7e2d71d908dc0f8d2027e1604102140d84b155e658c20e8ad1304317691f", size = 3943865, upload-time = "2025-02-11T15:49:36.659Z" }, - { url = "https://files.pythonhosted.org/packages/6e/57/371a9f3f3a4500807b5fcd29fec77f418ba27ffc629d88597d0d1049696e/cryptography-44.0.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:887143b9ff6bad2b7570da75a7fe8bbf5f65276365ac259a5d2d5147a73775f2", size = 4162562, upload-time = "2025-02-11T15:49:39.541Z" }, - { url = "https://files.pythonhosted.org/packages/c5/1d/5b77815e7d9cf1e3166988647f336f87d5634a5ccecec2ffbe08ef8dd481/cryptography-44.0.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:322eb03ecc62784536bc173f1483e76747aafeb69c8728df48537eb431cd1911", size = 3951923, upload-time = "2025-02-11T15:49:42.461Z" }, - { url = "https://files.pythonhosted.org/packages/28/01/604508cd34a4024467cd4105887cf27da128cba3edd435b54e2395064bfb/cryptography-44.0.1-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:21377472ca4ada2906bc313168c9dc7b1d7ca417b63c1c3011d0c74b7de9ae69", size = 3685194, upload-time = "2025-02-11T15:49:45.226Z" }, - { url = "https://files.pythonhosted.org/packages/c6/3d/d3c55d4f1d24580a236a6753902ef6d8aafd04da942a1ee9efb9dc8fd0cb/cryptography-44.0.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:df978682c1504fc93b3209de21aeabf2375cb1571d4e61907b3e7a2540e83026", size = 4187790, upload-time = "2025-02-11T15:49:48.215Z" }, - { url = "https://files.pythonhosted.org/packages/ea/a6/44d63950c8588bfa8594fd234d3d46e93c3841b8e84a066649c566afb972/cryptography-44.0.1-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:eb3889330f2a4a148abead555399ec9a32b13b7c8ba969b72d8e500eb7ef84cd", size = 3951343, upload-time = "2025-02-11T15:49:50.313Z" }, - { url = "https://files.pythonhosted.org/packages/c1/17/f5282661b57301204cbf188254c1a0267dbd8b18f76337f0a7ce1038888c/cryptography-44.0.1-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:8e6a85a93d0642bd774460a86513c5d9d80b5c002ca9693e63f6e540f1815ed0", size = 4187127, upload-time = "2025-02-11T15:49:52.051Z" }, - { url = "https://files.pythonhosted.org/packages/f3/68/abbae29ed4f9d96596687f3ceea8e233f65c9645fbbec68adb7c756bb85a/cryptography-44.0.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6f76fdd6fd048576a04c5210d53aa04ca34d2ed63336d4abd306d0cbe298fddf", size = 4070666, upload-time = "2025-02-11T15:49:56.56Z" }, - { url = "https://files.pythonhosted.org/packages/0f/10/cf91691064a9e0a88ae27e31779200b1505d3aee877dbe1e4e0d73b4f155/cryptography-44.0.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6c8acf6f3d1f47acb2248ec3ea261171a671f3d9428e34ad0357148d492c7864", size = 4288811, upload-time = "2025-02-11T15:49:59.248Z" }, - { url = "https://files.pythonhosted.org/packages/38/78/74ea9eb547d13c34e984e07ec8a473eb55b19c1451fe7fc8077c6a4b0548/cryptography-44.0.1-cp37-abi3-win32.whl", hash = "sha256:24979e9f2040c953a94bf3c6782e67795a4c260734e5264dceea65c8f4bae64a", size = 2771882, upload-time = "2025-02-11T15:50:01.478Z" }, - { url = "https://files.pythonhosted.org/packages/cf/6c/3907271ee485679e15c9f5e93eac6aa318f859b0aed8d369afd636fafa87/cryptography-44.0.1-cp37-abi3-win_amd64.whl", hash = "sha256:fd0ee90072861e276b0ff08bd627abec29e32a53b2be44e41dbcdf87cbee2b00", size = 3206989, upload-time = "2025-02-11T15:50:03.312Z" }, - { url = "https://files.pythonhosted.org/packages/9f/f1/676e69c56a9be9fd1bffa9bc3492366901f6e1f8f4079428b05f1414e65c/cryptography-44.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:a2d8a7045e1ab9b9f803f0d9531ead85f90c5f2859e653b61497228b18452008", size = 6643714, upload-time = "2025-02-11T15:50:05.555Z" }, - { url = "https://files.pythonhosted.org/packages/ba/9f/1775600eb69e72d8f9931a104120f2667107a0ee478f6ad4fe4001559345/cryptography-44.0.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b8272f257cf1cbd3f2e120f14c68bff2b6bdfcc157fafdee84a1b795efd72862", size = 3943269, upload-time = "2025-02-11T15:50:08.54Z" }, - { url = "https://files.pythonhosted.org/packages/25/ba/e00d5ad6b58183829615be7f11f55a7b6baa5a06910faabdc9961527ba44/cryptography-44.0.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e8d181e90a777b63f3f0caa836844a1182f1f265687fac2115fcf245f5fbec3", size = 4166461, upload-time = "2025-02-11T15:50:11.419Z" }, - { url = "https://files.pythonhosted.org/packages/b3/45/690a02c748d719a95ab08b6e4decb9d81e0ec1bac510358f61624c86e8a3/cryptography-44.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:436df4f203482f41aad60ed1813811ac4ab102765ecae7a2bbb1dbb66dcff5a7", size = 3950314, upload-time = "2025-02-11T15:50:14.181Z" }, - { url = "https://files.pythonhosted.org/packages/e6/50/bf8d090911347f9b75adc20f6f6569ed6ca9b9bff552e6e390f53c2a1233/cryptography-44.0.1-cp39-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4f422e8c6a28cf8b7f883eb790695d6d45b0c385a2583073f3cec434cc705e1a", size = 3686675, upload-time = "2025-02-11T15:50:16.3Z" }, - { url = "https://files.pythonhosted.org/packages/e1/e7/cfb18011821cc5f9b21efb3f94f3241e3a658d267a3bf3a0f45543858ed8/cryptography-44.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:72198e2b5925155497a5a3e8c216c7fb3e64c16ccee11f0e7da272fa93b35c4c", size = 4190429, upload-time = "2025-02-11T15:50:19.302Z" }, - { url = "https://files.pythonhosted.org/packages/07/ef/77c74d94a8bfc1a8a47b3cafe54af3db537f081742ee7a8a9bd982b62774/cryptography-44.0.1-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:2a46a89ad3e6176223b632056f321bc7de36b9f9b93b2cc1cccf935a3849dc62", size = 3950039, upload-time = "2025-02-11T15:50:22.257Z" }, - { url = "https://files.pythonhosted.org/packages/6d/b9/8be0ff57c4592382b77406269b1e15650c9f1a167f9e34941b8515b97159/cryptography-44.0.1-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:53f23339864b617a3dfc2b0ac8d5c432625c80014c25caac9082314e9de56f41", size = 4189713, upload-time = "2025-02-11T15:50:24.261Z" }, - { url = "https://files.pythonhosted.org/packages/78/e1/4b6ac5f4100545513b0847a4d276fe3c7ce0eacfa73e3b5ebd31776816ee/cryptography-44.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:888fcc3fce0c888785a4876ca55f9f43787f4c5c1cc1e2e0da71ad481ff82c5b", size = 4071193, upload-time = "2025-02-11T15:50:26.18Z" }, - { url = "https://files.pythonhosted.org/packages/3d/cb/afff48ceaed15531eab70445abe500f07f8f96af2bb35d98af6bfa89ebd4/cryptography-44.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:00918d859aa4e57db8299607086f793fa7813ae2ff5a4637e318a25ef82730f7", size = 4289566, upload-time = "2025-02-11T15:50:28.221Z" }, - { url = "https://files.pythonhosted.org/packages/30/6f/4eca9e2e0f13ae459acd1ca7d9f0257ab86e68f44304847610afcb813dc9/cryptography-44.0.1-cp39-abi3-win32.whl", hash = "sha256:9b336599e2cb77b1008cb2ac264b290803ec5e8e89d618a5e978ff5eb6f715d9", size = 2772371, upload-time = "2025-02-11T15:50:29.997Z" }, - { url = "https://files.pythonhosted.org/packages/d2/05/5533d30f53f10239616a357f080892026db2d550a40c393d0a8a7af834a9/cryptography-44.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:e403f7f766ded778ecdb790da786b418a9f2394f36e8cc8b796cc056ab05f44f", size = 3207303, upload-time = "2025-02-11T15:50:32.258Z" }, + { url = "https://files.pythonhosted.org/packages/f7/81/b0bb27f2ba931a65409c6b8a8b358a7f03c0e46eceacddff55f7c84b1f3b/cryptography-46.0.5-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:351695ada9ea9618b3500b490ad54c739860883df6c1f555e088eaf25b1bbaad", size = 7176289, upload-time = "2026-02-10T19:17:08.274Z" }, + { url = "https://files.pythonhosted.org/packages/ff/9e/6b4397a3e3d15123de3b1806ef342522393d50736c13b20ec4c9ea6693a6/cryptography-46.0.5-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c18ff11e86df2e28854939acde2d003f7984f721eba450b56a200ad90eeb0e6b", size = 4275637, upload-time = "2026-02-10T19:17:10.53Z" }, + { url = "https://files.pythonhosted.org/packages/63/e7/471ab61099a3920b0c77852ea3f0ea611c9702f651600397ac567848b897/cryptography-46.0.5-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d7e3d356b8cd4ea5aff04f129d5f66ebdc7b6f8eae802b93739ed520c47c79b", size = 4424742, upload-time = "2026-02-10T19:17:12.388Z" }, + { url = "https://files.pythonhosted.org/packages/37/53/a18500f270342d66bf7e4d9f091114e31e5ee9e7375a5aba2e85a91e0044/cryptography-46.0.5-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:50bfb6925eff619c9c023b967d5b77a54e04256c4281b0e21336a130cd7fc263", size = 4277528, upload-time = "2026-02-10T19:17:13.853Z" }, + { url = "https://files.pythonhosted.org/packages/22/29/c2e812ebc38c57b40e7c583895e73c8c5adb4d1e4a0cc4c5a4fdab2b1acc/cryptography-46.0.5-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:803812e111e75d1aa73690d2facc295eaefd4439be1023fefc4995eaea2af90d", size = 4947993, upload-time = "2026-02-10T19:17:15.618Z" }, + { url = "https://files.pythonhosted.org/packages/6b/e7/237155ae19a9023de7e30ec64e5d99a9431a567407ac21170a046d22a5a3/cryptography-46.0.5-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3ee190460e2fbe447175cda91b88b84ae8322a104fc27766ad09428754a618ed", size = 4456855, upload-time = "2026-02-10T19:17:17.221Z" }, + { url = "https://files.pythonhosted.org/packages/2d/87/fc628a7ad85b81206738abbd213b07702bcbdada1dd43f72236ef3cffbb5/cryptography-46.0.5-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:f145bba11b878005c496e93e257c1e88f154d278d2638e6450d17e0f31e558d2", size = 3984635, upload-time = "2026-02-10T19:17:18.792Z" }, + { url = "https://files.pythonhosted.org/packages/84/29/65b55622bde135aedf4565dc509d99b560ee4095e56989e815f8fd2aa910/cryptography-46.0.5-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:e9251e3be159d1020c4030bd2e5f84d6a43fe54b6c19c12f51cde9542a2817b2", size = 4277038, upload-time = "2026-02-10T19:17:20.256Z" }, + { url = "https://files.pythonhosted.org/packages/bc/36/45e76c68d7311432741faf1fbf7fac8a196a0a735ca21f504c75d37e2558/cryptography-46.0.5-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:47fb8a66058b80e509c47118ef8a75d14c455e81ac369050f20ba0d23e77fee0", size = 4912181, upload-time = "2026-02-10T19:17:21.825Z" }, + { url = "https://files.pythonhosted.org/packages/6d/1a/c1ba8fead184d6e3d5afcf03d569acac5ad063f3ac9fb7258af158f7e378/cryptography-46.0.5-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:4c3341037c136030cb46e4b1e17b7418ea4cbd9dd207e4a6f3b2b24e0d4ac731", size = 4456482, upload-time = "2026-02-10T19:17:25.133Z" }, + { url = "https://files.pythonhosted.org/packages/f9/e5/3fb22e37f66827ced3b902cf895e6a6bc1d095b5b26be26bd13c441fdf19/cryptography-46.0.5-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:890bcb4abd5a2d3f852196437129eb3667d62630333aacc13dfd470fad3aaa82", size = 4405497, upload-time = "2026-02-10T19:17:26.66Z" }, + { url = "https://files.pythonhosted.org/packages/1a/df/9d58bb32b1121a8a2f27383fabae4d63080c7ca60b9b5c88be742be04ee7/cryptography-46.0.5-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:80a8d7bfdf38f87ca30a5391c0c9ce4ed2926918e017c29ddf643d0ed2778ea1", size = 4667819, upload-time = "2026-02-10T19:17:28.569Z" }, + { url = "https://files.pythonhosted.org/packages/ea/ed/325d2a490c5e94038cdb0117da9397ece1f11201f425c4e9c57fe5b9f08b/cryptography-46.0.5-cp311-abi3-win32.whl", hash = "sha256:60ee7e19e95104d4c03871d7d7dfb3d22ef8a9b9c6778c94e1c8fcc8365afd48", size = 3028230, upload-time = "2026-02-10T19:17:30.518Z" }, + { url = "https://files.pythonhosted.org/packages/e9/5a/ac0f49e48063ab4255d9e3b79f5def51697fce1a95ea1370f03dc9db76f6/cryptography-46.0.5-cp311-abi3-win_amd64.whl", hash = "sha256:38946c54b16c885c72c4f59846be9743d699eee2b69b6988e0a00a01f46a61a4", size = 3480909, upload-time = "2026-02-10T19:17:32.083Z" }, + { url = "https://files.pythonhosted.org/packages/e2/fa/a66aa722105ad6a458bebd64086ca2b72cdd361fed31763d20390f6f1389/cryptography-46.0.5-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:4108d4c09fbbf2789d0c926eb4152ae1760d5a2d97612b92d508d96c861e4d31", size = 7170514, upload-time = "2026-02-10T19:17:56.267Z" }, + { url = "https://files.pythonhosted.org/packages/0f/04/c85bdeab78c8bc77b701bf0d9bdcf514c044e18a46dcff330df5448631b0/cryptography-46.0.5-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7d1f30a86d2757199cb2d56e48cce14deddf1f9c95f1ef1b64ee91ea43fe2e18", size = 4275349, upload-time = "2026-02-10T19:17:58.419Z" }, + { url = "https://files.pythonhosted.org/packages/5c/32/9b87132a2f91ee7f5223b091dc963055503e9b442c98fc0b8a5ca765fab0/cryptography-46.0.5-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:039917b0dc418bb9f6edce8a906572d69e74bd330b0b3fea4f79dab7f8ddd235", size = 4420667, upload-time = "2026-02-10T19:18:00.619Z" }, + { url = "https://files.pythonhosted.org/packages/a1/a6/a7cb7010bec4b7c5692ca6f024150371b295ee1c108bdc1c400e4c44562b/cryptography-46.0.5-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ba2a27ff02f48193fc4daeadf8ad2590516fa3d0adeeb34336b96f7fa64c1e3a", size = 4276980, upload-time = "2026-02-10T19:18:02.379Z" }, + { url = "https://files.pythonhosted.org/packages/8e/7c/c4f45e0eeff9b91e3f12dbd0e165fcf2a38847288fcfd889deea99fb7b6d/cryptography-46.0.5-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:61aa400dce22cb001a98014f647dc21cda08f7915ceb95df0c9eaf84b4b6af76", size = 4939143, upload-time = "2026-02-10T19:18:03.964Z" }, + { url = "https://files.pythonhosted.org/packages/37/19/e1b8f964a834eddb44fa1b9a9976f4e414cbb7aa62809b6760c8803d22d1/cryptography-46.0.5-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3ce58ba46e1bc2aac4f7d9290223cead56743fa6ab94a5d53292ffaac6a91614", size = 4453674, upload-time = "2026-02-10T19:18:05.588Z" }, + { url = "https://files.pythonhosted.org/packages/db/ed/db15d3956f65264ca204625597c410d420e26530c4e2943e05a0d2f24d51/cryptography-46.0.5-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:420d0e909050490d04359e7fdb5ed7e667ca5c3c402b809ae2563d7e66a92229", size = 3978801, upload-time = "2026-02-10T19:18:07.167Z" }, + { url = "https://files.pythonhosted.org/packages/41/e2/df40a31d82df0a70a0daf69791f91dbb70e47644c58581d654879b382d11/cryptography-46.0.5-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:582f5fcd2afa31622f317f80426a027f30dc792e9c80ffee87b993200ea115f1", size = 4276755, upload-time = "2026-02-10T19:18:09.813Z" }, + { url = "https://files.pythonhosted.org/packages/33/45/726809d1176959f4a896b86907b98ff4391a8aa29c0aaaf9450a8a10630e/cryptography-46.0.5-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:bfd56bb4b37ed4f330b82402f6f435845a5f5648edf1ad497da51a8452d5d62d", size = 4901539, upload-time = "2026-02-10T19:18:11.263Z" }, + { url = "https://files.pythonhosted.org/packages/99/0f/a3076874e9c88ecb2ecc31382f6e7c21b428ede6f55aafa1aa272613e3cd/cryptography-46.0.5-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:a3d507bb6a513ca96ba84443226af944b0f7f47dcc9a399d110cd6146481d24c", size = 4452794, upload-time = "2026-02-10T19:18:12.914Z" }, + { url = "https://files.pythonhosted.org/packages/02/ef/ffeb542d3683d24194a38f66ca17c0a4b8bf10631feef44a7ef64e631b1a/cryptography-46.0.5-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9f16fbdf4da055efb21c22d81b89f155f02ba420558db21288b3d0035bafd5f4", size = 4404160, upload-time = "2026-02-10T19:18:14.375Z" }, + { url = "https://files.pythonhosted.org/packages/96/93/682d2b43c1d5f1406ed048f377c0fc9fc8f7b0447a478d5c65ab3d3a66eb/cryptography-46.0.5-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:ced80795227d70549a411a4ab66e8ce307899fad2220ce5ab2f296e687eacde9", size = 4667123, upload-time = "2026-02-10T19:18:15.886Z" }, + { url = "https://files.pythonhosted.org/packages/45/2d/9c5f2926cb5300a8eefc3f4f0b3f3df39db7f7ce40c8365444c49363cbda/cryptography-46.0.5-cp38-abi3-win32.whl", hash = "sha256:02f547fce831f5096c9a567fd41bc12ca8f11df260959ecc7c3202555cc47a72", size = 3010220, upload-time = "2026-02-10T19:18:17.361Z" }, + { url = "https://files.pythonhosted.org/packages/48/ef/0c2f4a8e31018a986949d34a01115dd057bf536905dca38897bacd21fac3/cryptography-46.0.5-cp38-abi3-win_amd64.whl", hash = "sha256:556e106ee01aa13484ce9b0239bca667be5004efb0aabbed28d353df86445595", size = 3467050, upload-time = "2026-02-10T19:18:18.899Z" }, + { url = "https://files.pythonhosted.org/packages/eb/dd/2d9fdb07cebdf3d51179730afb7d5e576153c6744c3ff8fded23030c204e/cryptography-46.0.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:3b4995dc971c9fb83c25aa44cf45f02ba86f71ee600d81091c2f0cbae116b06c", size = 3476964, upload-time = "2026-02-10T19:18:20.687Z" }, + { url = "https://files.pythonhosted.org/packages/e9/6f/6cc6cc9955caa6eaf83660b0da2b077c7fe8ff9950a3c5e45d605038d439/cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:bc84e875994c3b445871ea7181d424588171efec3e185dced958dad9e001950a", size = 4218321, upload-time = "2026-02-10T19:18:22.349Z" }, + { url = "https://files.pythonhosted.org/packages/3e/5d/c4da701939eeee699566a6c1367427ab91a8b7088cc2328c09dbee940415/cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:2ae6971afd6246710480e3f15824ed3029a60fc16991db250034efd0b9fb4356", size = 4381786, upload-time = "2026-02-10T19:18:24.529Z" }, + { url = "https://files.pythonhosted.org/packages/ac/97/a538654732974a94ff96c1db621fa464f455c02d4bb7d2652f4edc21d600/cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:d861ee9e76ace6cf36a6a89b959ec08e7bc2493ee39d07ffe5acb23ef46d27da", size = 4217990, upload-time = "2026-02-10T19:18:25.957Z" }, + { url = "https://files.pythonhosted.org/packages/ae/11/7e500d2dd3ba891197b9efd2da5454b74336d64a7cc419aa7327ab74e5f6/cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:2b7a67c9cd56372f3249b39699f2ad479f6991e62ea15800973b956f4b73e257", size = 4381252, upload-time = "2026-02-10T19:18:27.496Z" }, + { url = "https://files.pythonhosted.org/packages/bc/58/6b3d24e6b9bc474a2dcdee65dfd1f008867015408a271562e4b690561a4d/cryptography-46.0.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:8456928655f856c6e1533ff59d5be76578a7157224dbd9ce6872f25055ab9ab7", size = 3407605, upload-time = "2026-02-10T19:18:29.233Z" }, ] [[package]] @@ -908,28 +921,27 @@ [[package]] name = "ruff" -version = "0.14.14" +version = "0.15.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2e/06/f71e3a86b2df0dfa2d2f72195941cd09b44f87711cb7fa5193732cb9a5fc/ruff-0.14.14.tar.gz", hash = "sha256:2d0f819c9a90205f3a867dbbd0be083bee9912e170fd7d9704cc8ae45824896b", size = 4515732, upload-time = "2026-01-22T22:30:17.527Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c8/39/5cee96809fbca590abea6b46c6d1c586b49663d1d2830a751cc8fc42c666/ruff-0.15.0.tar.gz", hash = "sha256:6bdea47cdbea30d40f8f8d7d69c0854ba7c15420ec75a26f463290949d7f7e9a", size = 4524893, upload-time = "2026-02-03T17:53:35.357Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/89/20a12e97bc6b9f9f68343952da08a8099c57237aef953a56b82711d55edd/ruff-0.14.14-py3-none-linux_armv6l.whl", hash = "sha256:7cfe36b56e8489dee8fbc777c61959f60ec0f1f11817e8f2415f429552846aed", size = 10467650, upload-time = "2026-01-22T22:30:08.578Z" }, - { url = "https://files.pythonhosted.org/packages/a3/b1/c5de3fd2d5a831fcae21beda5e3589c0ba67eec8202e992388e4b17a6040/ruff-0.14.14-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6006a0082336e7920b9573ef8a7f52eec837add1265cc74e04ea8a4368cd704c", size = 10883245, upload-time = "2026-01-22T22:30:04.155Z" }, - { url = "https://files.pythonhosted.org/packages/b8/7c/3c1db59a10e7490f8f6f8559d1db8636cbb13dccebf18686f4e3c9d7c772/ruff-0.14.14-py3-none-macosx_11_0_arm64.whl", hash = "sha256:026c1d25996818f0bf498636686199d9bd0d9d6341c9c2c3b62e2a0198b758de", size = 10231273, upload-time = "2026-01-22T22:30:34.642Z" }, - { url = "https://files.pythonhosted.org/packages/a1/6e/5e0e0d9674be0f8581d1f5e0f0a04761203affce3232c1a1189d0e3b4dad/ruff-0.14.14-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f666445819d31210b71e0a6d1c01e24447a20b85458eea25a25fe8142210ae0e", size = 10585753, upload-time = "2026-01-22T22:30:31.781Z" }, - { url = "https://files.pythonhosted.org/packages/23/09/754ab09f46ff1884d422dc26d59ba18b4e5d355be147721bb2518aa2a014/ruff-0.14.14-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3c0f18b922c6d2ff9a5e6c3ee16259adc513ca775bcf82c67ebab7cbd9da5bc8", size = 10286052, upload-time = "2026-01-22T22:30:24.827Z" }, - { url = "https://files.pythonhosted.org/packages/c8/cc/e71f88dd2a12afb5f50733851729d6b571a7c3a35bfdb16c3035132675a0/ruff-0.14.14-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1629e67489c2dea43e8658c3dba659edbfd87361624b4040d1df04c9740ae906", size = 11043637, upload-time = "2026-01-22T22:30:13.239Z" }, - { url = "https://files.pythonhosted.org/packages/67/b2/397245026352494497dac935d7f00f1468c03a23a0c5db6ad8fc49ca3fb2/ruff-0.14.14-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:27493a2131ea0f899057d49d303e4292b2cae2bb57253c1ed1f256fbcd1da480", size = 12194761, upload-time = "2026-01-22T22:30:22.542Z" }, - { url = "https://files.pythonhosted.org/packages/5b/06/06ef271459f778323112c51b7587ce85230785cd64e91772034ddb88f200/ruff-0.14.14-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:01ff589aab3f5b539e35db38425da31a57521efd1e4ad1ae08fc34dbe30bd7df", size = 12005701, upload-time = "2026-01-22T22:30:20.499Z" }, - { url = "https://files.pythonhosted.org/packages/41/d6/99364514541cf811ccc5ac44362f88df66373e9fec1b9d1c4cc830593fe7/ruff-0.14.14-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1cc12d74eef0f29f51775f5b755913eb523546b88e2d733e1d701fe65144e89b", size = 11282455, upload-time = "2026-01-22T22:29:59.679Z" }, - { url = "https://files.pythonhosted.org/packages/ca/71/37daa46f89475f8582b7762ecd2722492df26421714a33e72ccc9a84d7a5/ruff-0.14.14-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb8481604b7a9e75eff53772496201690ce2687067e038b3cc31aaf16aa0b974", size = 11215882, upload-time = "2026-01-22T22:29:57.032Z" }, - { url = "https://files.pythonhosted.org/packages/2c/10/a31f86169ec91c0705e618443ee74ede0bdd94da0a57b28e72db68b2dbac/ruff-0.14.14-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:14649acb1cf7b5d2d283ebd2f58d56b75836ed8c6f329664fa91cdea19e76e66", size = 11180549, upload-time = "2026-01-22T22:30:27.175Z" }, - { url = "https://files.pythonhosted.org/packages/fd/1e/c723f20536b5163adf79bdd10c5f093414293cdf567eed9bdb7b83940f3f/ruff-0.14.14-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e8058d2145566510790eab4e2fad186002e288dec5e0d343a92fe7b0bc1b3e13", size = 10543416, upload-time = "2026-01-22T22:30:01.964Z" }, - { url = "https://files.pythonhosted.org/packages/3e/34/8a84cea7e42c2d94ba5bde1d7a4fae164d6318f13f933d92da6d7c2041ff/ruff-0.14.14-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:e651e977a79e4c758eb807f0481d673a67ffe53cfa92209781dfa3a996cf8412", size = 10285491, upload-time = "2026-01-22T22:30:29.51Z" }, - { url = "https://files.pythonhosted.org/packages/55/ef/b7c5ea0be82518906c978e365e56a77f8de7678c8bb6651ccfbdc178c29f/ruff-0.14.14-py3-none-musllinux_1_2_i686.whl", hash = "sha256:cc8b22da8d9d6fdd844a68ae937e2a0adf9b16514e9a97cc60355e2d4b219fc3", size = 10733525, upload-time = "2026-01-22T22:30:06.499Z" }, - { url = "https://files.pythonhosted.org/packages/6a/5b/aaf1dfbcc53a2811f6cc0a1759de24e4b03e02ba8762daabd9b6bd8c59e3/ruff-0.14.14-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:16bc890fb4cc9781bb05beb5ab4cd51be9e7cb376bf1dd3580512b24eb3fda2b", size = 11315626, upload-time = "2026-01-22T22:30:36.848Z" }, - { url = "https://files.pythonhosted.org/packages/2c/aa/9f89c719c467dfaf8ad799b9bae0df494513fb21d31a6059cb5870e57e74/ruff-0.14.14-py3-none-win32.whl", hash = "sha256:b530c191970b143375b6a68e6f743800b2b786bbcf03a7965b06c4bf04568167", size = 10502442, upload-time = "2026-01-22T22:30:38.93Z" }, - { url = "https://files.pythonhosted.org/packages/87/44/90fa543014c45560cae1fffc63ea059fb3575ee6e1cb654562197e5d16fb/ruff-0.14.14-py3-none-win_amd64.whl", hash = "sha256:3dde1435e6b6fe5b66506c1dff67a421d0b7f6488d466f651c07f4cab3bf20fd", size = 11630486, upload-time = "2026-01-22T22:30:10.852Z" }, - { url = "https://files.pythonhosted.org/packages/9e/6a/40fee331a52339926a92e17ae748827270b288a35ef4a15c9c8f2ec54715/ruff-0.14.14-py3-none-win_arm64.whl", hash = "sha256:56e6981a98b13a32236a72a8da421d7839221fa308b223b9283312312e5ac76c", size = 10920448, upload-time = "2026-01-22T22:30:15.417Z" }, + { url = "https://files.pythonhosted.org/packages/bc/88/3fd1b0aa4b6330d6aaa63a285bc96c9f71970351579152d231ed90914586/ruff-0.15.0-py3-none-linux_armv6l.whl", hash = "sha256:aac4ebaa612a82b23d45964586f24ae9bc23ca101919f5590bdb368d74ad5455", size = 10354332, upload-time = "2026-02-03T17:52:54.892Z" }, + { url = "https://files.pythonhosted.org/packages/72/f6/62e173fbb7eb75cc29fe2576a1e20f0a46f671a2587b5f604bfb0eaf5f6f/ruff-0.15.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:dcd4be7cc75cfbbca24a98d04d0b9b36a270d0833241f776b788d59f4142b14d", size = 10767189, upload-time = "2026-02-03T17:53:19.778Z" }, + { url = "https://files.pythonhosted.org/packages/99/e4/968ae17b676d1d2ff101d56dc69cf333e3a4c985e1ec23803df84fc7bf9e/ruff-0.15.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d747e3319b2bce179c7c1eaad3d884dc0a199b5f4d5187620530adf9105268ce", size = 10075384, upload-time = "2026-02-03T17:53:29.241Z" }, + { url = "https://files.pythonhosted.org/packages/a2/bf/9843c6044ab9e20af879c751487e61333ca79a2c8c3058b15722386b8cae/ruff-0.15.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:650bd9c56ae03102c51a5e4b554d74d825ff3abe4db22b90fd32d816c2e90621", size = 10481363, upload-time = "2026-02-03T17:52:43.332Z" }, + { url = "https://files.pythonhosted.org/packages/55/d9/4ada5ccf4cd1f532db1c8d44b6f664f2208d3d93acbeec18f82315e15193/ruff-0.15.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a6664b7eac559e3048223a2da77769c2f92b43a6dfd4720cef42654299a599c9", size = 10187736, upload-time = "2026-02-03T17:53:00.522Z" }, + { url = "https://files.pythonhosted.org/packages/86/e2/f25eaecd446af7bb132af0a1d5b135a62971a41f5366ff41d06d25e77a91/ruff-0.15.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6f811f97b0f092b35320d1556f3353bf238763420ade5d9e62ebd2b73f2ff179", size = 10968415, upload-time = "2026-02-03T17:53:15.705Z" }, + { url = "https://files.pythonhosted.org/packages/e7/dc/f06a8558d06333bf79b497d29a50c3a673d9251214e0d7ec78f90b30aa79/ruff-0.15.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:761ec0a66680fab6454236635a39abaf14198818c8cdf691e036f4bc0f406b2d", size = 11809643, upload-time = "2026-02-03T17:53:23.031Z" }, + { url = "https://files.pythonhosted.org/packages/dd/45/0ece8db2c474ad7df13af3a6d50f76e22a09d078af63078f005057ca59eb/ruff-0.15.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:940f11c2604d317e797b289f4f9f3fa5555ffe4fb574b55ed006c3d9b6f0eb78", size = 11234787, upload-time = "2026-02-03T17:52:46.432Z" }, + { url = "https://files.pythonhosted.org/packages/8a/d9/0e3a81467a120fd265658d127db648e4d3acfe3e4f6f5d4ea79fac47e587/ruff-0.15.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bcbca3d40558789126da91d7ef9a7c87772ee107033db7191edefa34e2c7f1b4", size = 11112797, upload-time = "2026-02-03T17:52:49.274Z" }, + { url = "https://files.pythonhosted.org/packages/b2/cb/8c0b3b0c692683f8ff31351dfb6241047fa873a4481a76df4335a8bff716/ruff-0.15.0-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:9a121a96db1d75fa3eb39c4539e607f628920dd72ff1f7c5ee4f1b768ac62d6e", size = 11033133, upload-time = "2026-02-03T17:53:33.105Z" }, + { url = "https://files.pythonhosted.org/packages/f8/5e/23b87370cf0f9081a8c89a753e69a4e8778805b8802ccfe175cc410e50b9/ruff-0.15.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:5298d518e493061f2eabd4abd067c7e4fb89e2f63291c94332e35631c07c3662", size = 10442646, upload-time = "2026-02-03T17:53:06.278Z" }, + { url = "https://files.pythonhosted.org/packages/e1/9a/3c94de5ce642830167e6d00b5c75aacd73e6347b4c7fc6828699b150a5ee/ruff-0.15.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:afb6e603d6375ff0d6b0cee563fa21ab570fd15e65c852cb24922cef25050cf1", size = 10195750, upload-time = "2026-02-03T17:53:26.084Z" }, + { url = "https://files.pythonhosted.org/packages/30/15/e396325080d600b436acc970848d69df9c13977942fb62bb8722d729bee8/ruff-0.15.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:77e515f6b15f828b94dc17d2b4ace334c9ddb7d9468c54b2f9ed2b9c1593ef16", size = 10676120, upload-time = "2026-02-03T17:53:09.363Z" }, + { url = "https://files.pythonhosted.org/packages/8d/c9/229a23d52a2983de1ad0fb0ee37d36e0257e6f28bfd6b498ee2c76361874/ruff-0.15.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:6f6e80850a01eb13b3e42ee0ebdf6e4497151b48c35051aab51c101266d187a3", size = 11201636, upload-time = "2026-02-03T17:52:57.281Z" }, + { url = "https://files.pythonhosted.org/packages/6f/b0/69adf22f4e24f3677208adb715c578266842e6e6a3cc77483f48dd999ede/ruff-0.15.0-py3-none-win32.whl", hash = "sha256:238a717ef803e501b6d51e0bdd0d2c6e8513fe9eec14002445134d3907cd46c3", size = 10465945, upload-time = "2026-02-03T17:53:12.591Z" }, + { url = "https://files.pythonhosted.org/packages/51/ad/f813b6e2c97e9b4598be25e94a9147b9af7e60523b0cb5d94d307c15229d/ruff-0.15.0-py3-none-win_amd64.whl", hash = "sha256:dd5e4d3301dc01de614da3cdffc33d4b1b96fb89e45721f1598e5532ccf78b18", size = 11564657, upload-time = "2026-02-03T17:52:51.893Z" }, + { url = "https://files.pythonhosted.org/packages/f6/b0/2d823f6e77ebe560f4e397d078487e8d52c1516b331e3521bc75db4272ca/ruff-0.15.0-py3-none-win_arm64.whl", hash = "sha256:c480d632cc0ca3f0727acac8b7d053542d9e114a462a145d0b00e7cd658c515a", size = 10865753, upload-time = "2026-02-03T17:53:03.014Z" }, ] [[package]] ++++++ grype-db.obsinfo ++++++ --- /var/tmp/diff_new_pack.mXBcGl/_old 2026-02-12 17:28:42.410700898 +0100 +++ /var/tmp/diff_new_pack.mXBcGl/_new 2026-02-12 17:28:42.426701577 +0100 @@ -1,5 +1,5 @@ name: grype-db -version: 0.51.0 -mtime: 1770382382 -commit: 013670be3fbdc9eea9e85f19c549aa48f8320e55 +version: 0.52.0 +mtime: 1770807363 +commit: 42f007c613bf061f626fd92671bbee0f8c9dabb4 ++++++ vendor.tar.gz ++++++ /work/SRC/openSUSE:Factory/grype-db/vendor.tar.gz /work/SRC/openSUSE:Factory/.grype-db.new.1977/vendor.tar.gz differ: char 133, line 1
