mirror of
https://github.com/anchore/syft.git
synced 2025-11-17 16:33:21 +01:00
feat: add Debian archive (.deb) file cataloger (#3704)
* feat: add Debian archive (.deb) file cataloger Add a cataloger that parses Debian package (.deb) archive files directly, allowing Syft to discover packages from .deb files without requiring them to be installed on the system. This implements issue #3315. Key features: - Parse .deb AR archives to extract package metadata - Support for gzip, xz, and zstd compressed control files - Extract package metadata from control files - Process file information from md5sums files - Mark configuration files from conffiles entries - Handle trailing slashes in archive member names Signed-off-by: Alan Pope <alan.pope@anchore.com> * chore: run go mod tidy to fix failing workflow Signed-off-by: Alan Pope <alan.pope@anchore.com> * add license processing to dpkg archive cataloger + add tests Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * update json schema with dpkg archive type Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * update comments Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> --------- Signed-off-by: Alan Pope <alan.pope@anchore.com> Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> Co-authored-by: Alex Goodman <wagoodman@users.noreply.github.com>
This commit is contained in:
parent
be0959cabf
commit
5fa8e9c6e9
12
go.mod
12
go.mod
@ -27,6 +27,7 @@ require (
|
|||||||
// go: warning: github.com/andybalholm/brotli@v1.0.1: retracted by module author: occasional panics and data corruption
|
// go: warning: github.com/andybalholm/brotli@v1.0.1: retracted by module author: occasional panics and data corruption
|
||||||
github.com/aquasecurity/go-pep440-version v0.0.1
|
github.com/aquasecurity/go-pep440-version v0.0.1
|
||||||
github.com/bitnami/go-version v0.0.0-20250131085805-b1f57a8634ef
|
github.com/bitnami/go-version v0.0.0-20250131085805-b1f57a8634ef
|
||||||
|
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb
|
||||||
github.com/bmatcuk/doublestar/v4 v4.8.1
|
github.com/bmatcuk/doublestar/v4 v4.8.1
|
||||||
github.com/charmbracelet/bubbles v0.20.0
|
github.com/charmbracelet/bubbles v0.20.0
|
||||||
github.com/charmbracelet/bubbletea v1.3.4
|
github.com/charmbracelet/bubbletea v1.3.4
|
||||||
@ -57,6 +58,7 @@ require (
|
|||||||
github.com/kastenhq/goversion v0.0.0-20230811215019-93b2f8823953
|
github.com/kastenhq/goversion v0.0.0-20230811215019-93b2f8823953
|
||||||
github.com/knqyf263/go-rpmdb v0.1.1
|
github.com/knqyf263/go-rpmdb v0.1.1
|
||||||
github.com/magiconair/properties v1.8.9
|
github.com/magiconair/properties v1.8.9
|
||||||
|
github.com/mholt/archives v0.1.0
|
||||||
github.com/mitchellh/go-homedir v1.1.0
|
github.com/mitchellh/go-homedir v1.1.0
|
||||||
github.com/mitchellh/hashstructure/v2 v2.0.2
|
github.com/mitchellh/hashstructure/v2 v2.0.2
|
||||||
github.com/mitchellh/mapstructure v1.5.0
|
github.com/mitchellh/mapstructure v1.5.0
|
||||||
@ -102,6 +104,7 @@ require (
|
|||||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||||
github.com/Microsoft/hcsshim v0.11.7 // indirect
|
github.com/Microsoft/hcsshim v0.11.7 // indirect
|
||||||
github.com/ProtonMail/go-crypto v1.1.5 // indirect
|
github.com/ProtonMail/go-crypto v1.1.5 // indirect
|
||||||
|
github.com/STARRY-S/zip v0.2.1 // indirect
|
||||||
github.com/agext/levenshtein v1.2.1 // indirect; indirectt
|
github.com/agext/levenshtein v1.2.1 // indirect; indirectt
|
||||||
github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092 // indirect
|
github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092 // indirect
|
||||||
github.com/andybalholm/brotli v1.1.1 // indirect
|
github.com/andybalholm/brotli v1.1.1 // indirect
|
||||||
@ -111,6 +114,9 @@ require (
|
|||||||
github.com/atotto/clipboard v0.1.4 // indirect
|
github.com/atotto/clipboard v0.1.4 // indirect
|
||||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||||
github.com/becheran/wildmatch-go v1.0.0 // indirect
|
github.com/becheran/wildmatch-go v1.0.0 // indirect
|
||||||
|
github.com/bodgit/plumbing v1.3.0 // indirect
|
||||||
|
github.com/bodgit/sevenzip v1.6.0 // indirect
|
||||||
|
github.com/bodgit/windows v1.0.1 // indirect
|
||||||
github.com/charmbracelet/harmonica v0.2.0 // indirect
|
github.com/charmbracelet/harmonica v0.2.0 // indirect
|
||||||
github.com/charmbracelet/x/ansi v0.8.0 // indirect
|
github.com/charmbracelet/x/ansi v0.8.0 // indirect
|
||||||
github.com/charmbracelet/x/term v0.2.1 // indirect
|
github.com/charmbracelet/x/term v0.2.1 // indirect
|
||||||
@ -134,7 +140,7 @@ require (
|
|||||||
github.com/docker/go-connections v0.5.0 // indirect
|
github.com/docker/go-connections v0.5.0 // indirect
|
||||||
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // indirect
|
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // indirect
|
||||||
github.com/docker/go-units v0.5.0 // indirect
|
github.com/docker/go-units v0.5.0 // indirect
|
||||||
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect
|
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 // indirect
|
||||||
github.com/edsrzf/mmap-go v1.1.0 // indirect
|
github.com/edsrzf/mmap-go v1.1.0 // indirect
|
||||||
github.com/emirpasic/gods v1.18.1 // indirect
|
github.com/emirpasic/gods v1.18.1 // indirect
|
||||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
|
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
|
||||||
@ -154,6 +160,7 @@ require (
|
|||||||
github.com/golang/snappy v0.0.4 // indirect
|
github.com/golang/snappy v0.0.4 // indirect
|
||||||
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd // indirect
|
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd // indirect
|
||||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||||
|
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
||||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||||
github.com/huandu/xstrings v1.5.0 // indirect
|
github.com/huandu/xstrings v1.5.0 // indirect
|
||||||
github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0 // indirect
|
github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0 // indirect
|
||||||
@ -186,6 +193,7 @@ require (
|
|||||||
github.com/muesli/termenv v0.16.0 // indirect
|
github.com/muesli/termenv v0.16.0 // indirect
|
||||||
github.com/ncruces/go-strftime v0.1.9 // indirect
|
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||||
github.com/nwaples/rardecode v1.1.3 // indirect
|
github.com/nwaples/rardecode v1.1.3 // indirect
|
||||||
|
github.com/nwaples/rardecode/v2 v2.0.0-beta.4.0.20241112120701-034e449c6e78 // indirect
|
||||||
github.com/opencontainers/image-spec v1.1.1 // indirect
|
github.com/opencontainers/image-spec v1.1.1 // indirect
|
||||||
github.com/opencontainers/runtime-spec v1.1.0 // indirect
|
github.com/opencontainers/runtime-spec v1.1.0 // indirect
|
||||||
github.com/opencontainers/selinux v1.11.0 // indirect
|
github.com/opencontainers/selinux v1.11.0 // indirect
|
||||||
@ -206,6 +214,7 @@ require (
|
|||||||
github.com/shopspring/decimal v1.4.0 // indirect
|
github.com/shopspring/decimal v1.4.0 // indirect
|
||||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||||
github.com/skeema/knownhosts v1.3.1 // indirect
|
github.com/skeema/knownhosts v1.3.1 // indirect
|
||||||
|
github.com/sorairolake/lzip-go v0.3.5 // indirect
|
||||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||||
github.com/spf13/cast v1.7.0 // indirect
|
github.com/spf13/cast v1.7.0 // indirect
|
||||||
github.com/spf13/pflag v1.0.6 // indirect
|
github.com/spf13/pflag v1.0.6 // indirect
|
||||||
@ -234,6 +243,7 @@ require (
|
|||||||
go.opentelemetry.io/otel/trace v1.33.0 // indirect
|
go.opentelemetry.io/otel/trace v1.33.0 // indirect
|
||||||
go.uber.org/atomic v1.9.0 // indirect
|
go.uber.org/atomic v1.9.0 // indirect
|
||||||
go.uber.org/multierr v1.9.0 // indirect
|
go.uber.org/multierr v1.9.0 // indirect
|
||||||
|
go4.org v0.0.0-20230225012048-214862532bf5 // indirect
|
||||||
golang.org/x/crypto v0.36.0 // indirect
|
golang.org/x/crypto v0.36.0 // indirect
|
||||||
golang.org/x/sync v0.12.0 // indirect
|
golang.org/x/sync v0.12.0 // indirect
|
||||||
golang.org/x/sys v0.31.0 // indirect
|
golang.org/x/sys v0.31.0 // indirect
|
||||||
|
|||||||
28
go.sum
28
go.sum
@ -82,6 +82,8 @@ github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8
|
|||||||
github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
|
github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
|
||||||
github.com/ProtonMail/go-crypto v1.1.5 h1:eoAQfK2dwL+tFSFpr7TbOaPNUbPiJj4fLYwwGE1FQO4=
|
github.com/ProtonMail/go-crypto v1.1.5 h1:eoAQfK2dwL+tFSFpr7TbOaPNUbPiJj4fLYwwGE1FQO4=
|
||||||
github.com/ProtonMail/go-crypto v1.1.5/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
|
github.com/ProtonMail/go-crypto v1.1.5/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
|
||||||
|
github.com/STARRY-S/zip v0.2.1 h1:pWBd4tuSGm3wtpoqRZZ2EAwOmcHK6XFf7bU9qcJXyFg=
|
||||||
|
github.com/STARRY-S/zip v0.2.1/go.mod h1:xNvshLODWtC4EJ702g7cTYn13G53o1+X9BWnPFpcWV4=
|
||||||
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8=
|
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8=
|
||||||
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo=
|
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo=
|
||||||
github.com/acobaugh/osrelease v0.1.0 h1:Yb59HQDGGNhCj4suHaFQQfBps5wyoKLSSX/J/+UifRE=
|
github.com/acobaugh/osrelease v0.1.0 h1:Yb59HQDGGNhCj4suHaFQQfBps5wyoKLSSX/J/+UifRE=
|
||||||
@ -151,8 +153,16 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r
|
|||||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||||
github.com/bitnami/go-version v0.0.0-20250131085805-b1f57a8634ef h1:TSFnfbbu2oAOuWbeDDTtwXWE6z+PmpgbSsMBeV7l0ww=
|
github.com/bitnami/go-version v0.0.0-20250131085805-b1f57a8634ef h1:TSFnfbbu2oAOuWbeDDTtwXWE6z+PmpgbSsMBeV7l0ww=
|
||||||
github.com/bitnami/go-version v0.0.0-20250131085805-b1f57a8634ef/go.mod h1:9iglf1GG4oNRJ39bZ5AZrjgAFD2RwQbXw6Qf7Cs47wo=
|
github.com/bitnami/go-version v0.0.0-20250131085805-b1f57a8634ef/go.mod h1:9iglf1GG4oNRJ39bZ5AZrjgAFD2RwQbXw6Qf7Cs47wo=
|
||||||
|
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb h1:m935MPodAbYS46DG4pJSv7WO+VECIWUQ7OJYSoTrMh4=
|
||||||
|
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI=
|
||||||
github.com/bmatcuk/doublestar/v4 v4.8.1 h1:54Bopc5c2cAvhLRAzqOGCYHYyhcDHsFF4wWIR5wKP38=
|
github.com/bmatcuk/doublestar/v4 v4.8.1 h1:54Bopc5c2cAvhLRAzqOGCYHYyhcDHsFF4wWIR5wKP38=
|
||||||
github.com/bmatcuk/doublestar/v4 v4.8.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
|
github.com/bmatcuk/doublestar/v4 v4.8.1/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.0 h1:a4R0Wu6/P1o1pP/3VV++aEOcyeBxeO/xE2Y9NSTrr6A=
|
||||||
|
github.com/bodgit/sevenzip v1.6.0/go.mod h1:zOBh9nJUof7tcrlqJFv1koWRrhz3LbDbUNngkuZxLMc=
|
||||||
|
github.com/bodgit/windows v1.0.1 h1:tF7K6KOluPYygXa3Z2594zxlkbKPAOvqr97etrGNIz4=
|
||||||
|
github.com/bodgit/windows v1.0.1/go.mod h1:a6JLwrB4KrTR5hBpp8FI9/9W9jJfeQ2h4XDXU74ZCdM=
|
||||||
github.com/bradleyjkemp/cupaloy/v2 v2.8.0 h1:any4BmKE+jGIaMpnU8YgH/I2LPiLBufr6oMMlVBbn9M=
|
github.com/bradleyjkemp/cupaloy/v2 v2.8.0 h1:any4BmKE+jGIaMpnU8YgH/I2LPiLBufr6oMMlVBbn9M=
|
||||||
github.com/bradleyjkemp/cupaloy/v2 v2.8.0/go.mod h1:bm7JXdkRd4BHJk9HpwqAI8BoAY1lps46Enkdqw6aRX0=
|
github.com/bradleyjkemp/cupaloy/v2 v2.8.0/go.mod h1:bm7JXdkRd4BHJk9HpwqAI8BoAY1lps46Enkdqw6aRX0=
|
||||||
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
|
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
|
||||||
@ -257,8 +267,8 @@ github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ
|
|||||||
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
|
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
|
||||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||||
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||||
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 h1:iFaUwBSo5Svw6L7HYpRu/0lE3e0BaElwnNO1qkNQxBY=
|
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 h1:2tV76y6Q9BB+NEBasnqvs7e49aEBFI8ejC89PSnWH+4=
|
||||||
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s=
|
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s=
|
||||||
github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
|
github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
|
||||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||||
@ -473,6 +483,8 @@ github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b
|
|||||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||||
|
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
|
||||||
|
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||||
github.com/hashicorp/hcl/v2 v2.23.0 h1:Fphj1/gCylPxHutVSEOf2fBOh1VE4AuLV7+kbJf3qos=
|
github.com/hashicorp/hcl/v2 v2.23.0 h1:Fphj1/gCylPxHutVSEOf2fBOh1VE4AuLV7+kbJf3qos=
|
||||||
@ -578,6 +590,8 @@ github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh
|
|||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
|
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
|
||||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||||
|
github.com/mholt/archives v0.1.0 h1:FacgJyrjiuyomTuNA92X5GyRBRZjE43Y/lrzKIlF35Q=
|
||||||
|
github.com/mholt/archives v0.1.0/go.mod h1:j/Ire/jm42GN7h90F5kzj6hf6ZFzEH66de+hmjEKu+I=
|
||||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||||
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
||||||
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
|
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
|
||||||
@ -632,6 +646,8 @@ github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdh
|
|||||||
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||||
github.com/nwaples/rardecode v1.1.3 h1:cWCaZwfM5H7nAD6PyEdcVnczzV8i/JtotnyW/dD9lEc=
|
github.com/nwaples/rardecode v1.1.3 h1:cWCaZwfM5H7nAD6PyEdcVnczzV8i/JtotnyW/dD9lEc=
|
||||||
github.com/nwaples/rardecode v1.1.3/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
|
github.com/nwaples/rardecode v1.1.3/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
|
||||||
|
github.com/nwaples/rardecode/v2 v2.0.0-beta.4.0.20241112120701-034e449c6e78 h1:MYzLheyVx1tJVDqfu3YnN4jtnyALNzLvwl+f58TcvQY=
|
||||||
|
github.com/nwaples/rardecode/v2 v2.0.0-beta.4.0.20241112120701-034e449c6e78/go.mod h1:yntwv/HfMc/Hbvtq9I19D1n58te3h6KsqCf3GxyfBGY=
|
||||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||||
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
|
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
|
||||||
@ -701,6 +717,7 @@ github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7
|
|||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/rust-secure-code/go-rustaudit v0.0.0-20250226111315-e20ec32e963c h1:8gOLsYwaY2JwlTMT4brS5/9XJdrdIbmk2obvQ748CC0=
|
github.com/rust-secure-code/go-rustaudit v0.0.0-20250226111315-e20ec32e963c h1:8gOLsYwaY2JwlTMT4brS5/9XJdrdIbmk2obvQ748CC0=
|
||||||
github.com/rust-secure-code/go-rustaudit v0.0.0-20250226111315-e20ec32e963c/go.mod h1:kwM/7r/rVluTE8qJbHAffduuqmSv4knVQT2IajGvSiA=
|
github.com/rust-secure-code/go-rustaudit v0.0.0-20250226111315-e20ec32e963c/go.mod h1:kwM/7r/rVluTE8qJbHAffduuqmSv4knVQT2IajGvSiA=
|
||||||
|
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk=
|
||||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||||
github.com/saferwall/pe v1.5.6 h1:DrRLnoQFxHWJ5lJUmrH7X2L0xeUu6SUS95Dc61eW2Yc=
|
github.com/saferwall/pe v1.5.6 h1:DrRLnoQFxHWJ5lJUmrH7X2L0xeUu6SUS95Dc61eW2Yc=
|
||||||
github.com/saferwall/pe v1.5.6/go.mod h1:mJx+PuptmNpoPFBNhWs/uDMFL/kTHVZIkg0d4OUJFbQ=
|
github.com/saferwall/pe v1.5.6/go.mod h1:mJx+PuptmNpoPFBNhWs/uDMFL/kTHVZIkg0d4OUJFbQ=
|
||||||
@ -737,6 +754,8 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ
|
|||||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8=
|
github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8=
|
||||||
github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY=
|
github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY=
|
||||||
|
github.com/sorairolake/lzip-go v0.3.5 h1:ms5Xri9o1JBIWvOFAorYtUNik6HI3HgBTkISiqu0Cwg=
|
||||||
|
github.com/sorairolake/lzip-go v0.3.5/go.mod h1:N0KYq5iWrMXI0ZEXKXaS9hCyOjZUQdBDEIbXfoUwbdk=
|
||||||
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
|
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
|
||||||
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
|
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
|
||||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
@ -884,6 +903,8 @@ go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9i
|
|||||||
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
|
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
|
||||||
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
|
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
|
||||||
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
||||||
|
go4.org v0.0.0-20230225012048-214862532bf5 h1:nifaUDeh+rPaBCMPMQHZmvJf+QdpLFnuQPwx+LxVmtc=
|
||||||
|
go4.org v0.0.0-20230225012048-214862532bf5/go.mod h1:F57wTi5Lrj6WLyswp5EYV1ncrEbFGHD4hhz6S1ZYeaU=
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
@ -982,6 +1003,7 @@ golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qx
|
|||||||
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
|
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
|
golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
|
||||||
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
@ -1089,11 +1111,13 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y=
|
golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y=
|
||||||
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
|
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
|||||||
@ -3,5 +3,5 @@ package internal
|
|||||||
const (
|
const (
|
||||||
// JSONSchemaVersion is the current schema version output by the JSON encoder
|
// JSONSchemaVersion is the current schema version output by the JSON encoder
|
||||||
// This is roughly following the "SchemaVer" guidelines for versioning the JSON schema. Please see schema/json/README.md for details on how to increment.
|
// This is roughly following the "SchemaVer" guidelines for versioning the JSON schema. Please see schema/json/README.md for details on how to increment.
|
||||||
JSONSchemaVersion = "16.0.22"
|
JSONSchemaVersion = "16.0.23"
|
||||||
)
|
)
|
||||||
|
|||||||
@ -63,6 +63,7 @@ func DefaultPackageTaskFactories() Factories {
|
|||||||
|
|
||||||
// OS package declared catalogers ///////////////////////////////////////////////////////////////////////////
|
// OS package declared catalogers ///////////////////////////////////////////////////////////////////////////
|
||||||
newSimplePackageTaskFactory(redhat.NewArchiveCataloger, pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, pkgcataloging.OSTag, "linux", "rpm", "redhat"),
|
newSimplePackageTaskFactory(redhat.NewArchiveCataloger, pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, pkgcataloging.OSTag, "linux", "rpm", "redhat"),
|
||||||
|
newSimplePackageTaskFactory(debian.NewArchiveCataloger, pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, pkgcataloging.OSTag, "linux", "deb", "debian"),
|
||||||
|
|
||||||
// language-specific package installed catalogers ///////////////////////////////////////////////////////////////////////////
|
// language-specific package installed catalogers ///////////////////////////////////////////////////////////////////////////
|
||||||
newSimplePackageTaskFactory(cpp.NewConanInfoCataloger, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, pkgcataloging.LanguageTag, "cpp", "conan"),
|
newSimplePackageTaskFactory(cpp.NewConanInfoCataloger, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, pkgcataloging.LanguageTag, "cpp", "conan"),
|
||||||
|
|||||||
2889
schema/json/schema-16.0.23.json
Normal file
2889
schema/json/schema-16.0.23.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"$id": "anchore.io/schema/syft/json/16.0.22/document",
|
"$id": "anchore.io/schema/syft/json/16.0.23/document",
|
||||||
"$ref": "#/$defs/Document",
|
"$ref": "#/$defs/Document",
|
||||||
"$defs": {
|
"$defs": {
|
||||||
"AlpmDbEntry": {
|
"AlpmDbEntry": {
|
||||||
@ -586,6 +586,66 @@
|
|||||||
"productVersion"
|
"productVersion"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"DpkgArchiveEntry": {
|
||||||
|
"properties": {
|
||||||
|
"package": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"source": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"sourceVersion": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"architecture": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"maintainer": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"installedSize": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"provides": {
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": "array"
|
||||||
|
},
|
||||||
|
"depends": {
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": "array"
|
||||||
|
},
|
||||||
|
"preDepends": {
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": "array"
|
||||||
|
},
|
||||||
|
"files": {
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/$defs/DpkgFileRecord"
|
||||||
|
},
|
||||||
|
"type": "array"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"package",
|
||||||
|
"source",
|
||||||
|
"version",
|
||||||
|
"sourceVersion",
|
||||||
|
"architecture",
|
||||||
|
"maintainer",
|
||||||
|
"installedSize",
|
||||||
|
"files"
|
||||||
|
]
|
||||||
|
},
|
||||||
"DpkgDbEntry": {
|
"DpkgDbEntry": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"package": {
|
"package": {
|
||||||
@ -1721,6 +1781,9 @@
|
|||||||
{
|
{
|
||||||
"$ref": "#/$defs/DotnetPortableExecutableEntry"
|
"$ref": "#/$defs/DotnetPortableExecutableEntry"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/$defs/DpkgArchiveEntry"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"$ref": "#/$defs/DpkgDbEntry"
|
"$ref": "#/$defs/DpkgDbEntry"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -54,6 +54,9 @@ func Originator(p pkg.Package) (typ string, author string) { //nolint: funlen
|
|||||||
case pkg.DpkgDBEntry:
|
case pkg.DpkgDBEntry:
|
||||||
author = metadata.Maintainer
|
author = metadata.Maintainer
|
||||||
|
|
||||||
|
case pkg.DpkgArchiveEntry:
|
||||||
|
author = metadata.Maintainer
|
||||||
|
|
||||||
case pkg.JavaArchive:
|
case pkg.JavaArchive:
|
||||||
if metadata.Manifest != nil {
|
if metadata.Manifest != nil {
|
||||||
author = metadata.Manifest.Main.MustGet("Specification-Vendor")
|
author = metadata.Manifest.Main.MustGet("Specification-Vendor")
|
||||||
|
|||||||
@ -109,7 +109,7 @@ func Test_OriginatorSupplier(t *testing.T) {
|
|||||||
supplier: "Organization: Microsoft Corporation",
|
supplier: "Organization: Microsoft Corporation",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "from dpkg",
|
name: "from dpkg DB",
|
||||||
input: pkg.Package{
|
input: pkg.Package{
|
||||||
Metadata: pkg.DpkgDBEntry{
|
Metadata: pkg.DpkgDBEntry{
|
||||||
Maintainer: "auth",
|
Maintainer: "auth",
|
||||||
@ -118,6 +118,16 @@ func Test_OriginatorSupplier(t *testing.T) {
|
|||||||
originator: "Person: auth",
|
originator: "Person: auth",
|
||||||
supplier: "Person: auth",
|
supplier: "Person: auth",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "from dpkg archive",
|
||||||
|
input: pkg.Package{
|
||||||
|
Metadata: pkg.DpkgArchiveEntry{
|
||||||
|
Maintainer: "auth",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
originator: "Person: auth",
|
||||||
|
supplier: "Person: auth",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "from gem",
|
name: "from gem",
|
||||||
input: pkg.Package{
|
input: pkg.Package{
|
||||||
|
|||||||
@ -20,6 +20,7 @@ func AllTypes() []any {
|
|||||||
pkg.DotnetDepsEntry{},
|
pkg.DotnetDepsEntry{},
|
||||||
pkg.DotnetPackagesLockEntry{},
|
pkg.DotnetPackagesLockEntry{},
|
||||||
pkg.DotnetPortableExecutableEntry{},
|
pkg.DotnetPortableExecutableEntry{},
|
||||||
|
pkg.DpkgArchiveEntry{},
|
||||||
pkg.DpkgDBEntry{},
|
pkg.DpkgDBEntry{},
|
||||||
pkg.ELFBinaryPackageNoteJSONPayload{},
|
pkg.ELFBinaryPackageNoteJSONPayload{},
|
||||||
pkg.ElixirMixLockEntry{},
|
pkg.ElixirMixLockEntry{},
|
||||||
|
|||||||
@ -74,6 +74,7 @@ var jsonTypes = makeJSONTypes(
|
|||||||
jsonNames(pkg.DartPubspecLockEntry{}, "dart-pubspec-lock-entry", "DartPubMetadata"),
|
jsonNames(pkg.DartPubspecLockEntry{}, "dart-pubspec-lock-entry", "DartPubMetadata"),
|
||||||
jsonNames(pkg.DotnetDepsEntry{}, "dotnet-deps-entry", "DotnetDepsMetadata"),
|
jsonNames(pkg.DotnetDepsEntry{}, "dotnet-deps-entry", "DotnetDepsMetadata"),
|
||||||
jsonNames(pkg.DotnetPortableExecutableEntry{}, "dotnet-portable-executable-entry"),
|
jsonNames(pkg.DotnetPortableExecutableEntry{}, "dotnet-portable-executable-entry"),
|
||||||
|
jsonNames(pkg.DpkgArchiveEntry{}, "dpkg-archive-entry"),
|
||||||
jsonNames(pkg.DpkgDBEntry{}, "dpkg-db-entry", "DpkgMetadata"),
|
jsonNames(pkg.DpkgDBEntry{}, "dpkg-db-entry", "DpkgMetadata"),
|
||||||
jsonNames(pkg.ELFBinaryPackageNoteJSONPayload{}, "elf-binary-package-note-json-payload"),
|
jsonNames(pkg.ELFBinaryPackageNoteJSONPayload{}, "elf-binary-package-note-json-payload"),
|
||||||
jsonNames(pkg.RubyGemspec{}, "ruby-gemspec", "GemMetadata"),
|
jsonNames(pkg.RubyGemspec{}, "ruby-gemspec", "GemMetadata"),
|
||||||
|
|||||||
@ -17,3 +17,9 @@ func NewDBCataloger() pkg.Cataloger {
|
|||||||
WithParserByGlobs(parseDpkgDB, "**/lib/dpkg/status", "**/lib/dpkg/status.d/*", "**/lib/opkg/info/*.control", "**/lib/opkg/status").
|
WithParserByGlobs(parseDpkgDB, "**/lib/dpkg/status", "**/lib/dpkg/status.d/*", "**/lib/opkg/info/*.control", "**/lib/opkg/status").
|
||||||
WithProcessors(dependency.Processor(dbEntryDependencySpecifier))
|
WithProcessors(dependency.Processor(dbEntryDependencySpecifier))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewArchiveCataloger returns a new Debian package cataloger object capable of parsing .deb archive files
|
||||||
|
func NewArchiveCataloger() pkg.Cataloger {
|
||||||
|
return generic.NewCataloger("deb-archive-cataloger").
|
||||||
|
WithParserByGlobs(parseDebArchive, "**/*.deb")
|
||||||
|
}
|
||||||
|
|||||||
@ -36,6 +36,7 @@ func TestDpkgCataloger(t *testing.T) {
|
|||||||
file.NewLocation("/var/lib/dpkg/info/libpam-runtime.conffiles").WithAnnotation(pkg.EvidenceAnnotationKey, pkg.SupportingEvidenceAnnotation),
|
file.NewLocation("/var/lib/dpkg/info/libpam-runtime.conffiles").WithAnnotation(pkg.EvidenceAnnotationKey, pkg.SupportingEvidenceAnnotation),
|
||||||
file.NewLocation("/usr/share/doc/libpam-runtime/copyright").WithAnnotation(pkg.EvidenceAnnotationKey, pkg.SupportingEvidenceAnnotation),
|
file.NewLocation("/usr/share/doc/libpam-runtime/copyright").WithAnnotation(pkg.EvidenceAnnotationKey, pkg.SupportingEvidenceAnnotation),
|
||||||
),
|
),
|
||||||
|
PURL: "pkg:deb/debian/libpam-runtime@1.1.8-3.6?arch=all&distro=debian-12&upstream=pam",
|
||||||
Type: pkg.DebPkg,
|
Type: pkg.DebPkg,
|
||||||
Metadata: pkg.DpkgDBEntry{
|
Metadata: pkg.DpkgDBEntry{
|
||||||
Package: "libpam-runtime",
|
Package: "libpam-runtime",
|
||||||
@ -224,6 +225,70 @@ func Test_CatalogerRelationships(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDpkgArchiveCataloger(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
expected []pkg.Package
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "image-single-dpkg",
|
||||||
|
expected: []pkg.Package{
|
||||||
|
{
|
||||||
|
Name: "zlib1g",
|
||||||
|
Version: "1:1.3.dfsg-3.1ubuntu2.1",
|
||||||
|
FoundBy: "deb-archive-cataloger",
|
||||||
|
Locations: file.NewLocationSet(
|
||||||
|
file.NewLocation("/zlib1g.deb"),
|
||||||
|
),
|
||||||
|
Licenses: pkg.NewLicenseSet(
|
||||||
|
pkg.NewLicenseFromLocations("Zlib"),
|
||||||
|
),
|
||||||
|
PURL: "pkg:deb/zlib1g@1%3A1.3.dfsg-3.1ubuntu2.1?arch=amd64&upstream=zlib",
|
||||||
|
Type: pkg.DebPkg,
|
||||||
|
Metadata: pkg.DpkgArchiveEntry{
|
||||||
|
Package: "zlib1g",
|
||||||
|
Source: "zlib",
|
||||||
|
Version: "1:1.3.dfsg-3.1ubuntu2.1",
|
||||||
|
Architecture: "amd64",
|
||||||
|
Maintainer: "Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>",
|
||||||
|
InstalledSize: 163,
|
||||||
|
Description: `compression library - runtime
|
||||||
|
zlib is a library implementing the deflate compression method found
|
||||||
|
in gzip and PKZIP. This package includes the shared library.`,
|
||||||
|
Provides: []string{"libz1"},
|
||||||
|
Depends: []string{"libc6 (>= 2.14)"},
|
||||||
|
Files: []pkg.DpkgFileRecord{
|
||||||
|
{
|
||||||
|
Path: "/usr/lib/x86_64-linux-gnu/libz.so.1.3",
|
||||||
|
Digest: &file.Digest{Algorithm: "md5", Value: "4447b36fc5cd1b044f089553b4166f09"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Path: "/usr/share/doc/zlib1g/changelog.Debian.gz",
|
||||||
|
Digest: &file.Digest{Algorithm: "md5", Value: "8b870c2e94c0cf780e2a65329cf11fdc"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Path: "/usr/share/doc/zlib1g/copyright",
|
||||||
|
Digest: &file.Digest{Algorithm: "md5", Value: "d348307d5bf18267bcbada155a715a3e"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
c := NewArchiveCataloger()
|
||||||
|
pkgtest.NewCatalogTester().
|
||||||
|
WithImageResolver(t, tt.name).
|
||||||
|
IgnoreLocationLayer(). // this fixture can be rebuilt, thus the layer ID will change
|
||||||
|
Expects(tt.expected, nil).
|
||||||
|
TestCataloger(t, c)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestCataloger_Globs(t *testing.T) {
|
func TestCataloger_Globs(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
|
|||||||
@ -24,7 +24,7 @@ const (
|
|||||||
|
|
||||||
func newDpkgPackage(d pkg.DpkgDBEntry, dbLocation file.Location, resolver file.Resolver, release *linux.Release, evidence ...file.Location) pkg.Package {
|
func newDpkgPackage(d pkg.DpkgDBEntry, dbLocation file.Location, resolver file.Resolver, release *linux.Release, evidence ...file.Location) pkg.Package {
|
||||||
// TODO: separate pr to license refactor, but explore extracting dpkg-specific license parsing into a separate function
|
// TODO: separate pr to license refactor, but explore extracting dpkg-specific license parsing into a separate function
|
||||||
licenses := make([]pkg.License, 0)
|
var licenses []pkg.License
|
||||||
|
|
||||||
locations := file.NewLocationSet(dbLocation.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation))
|
locations := file.NewLocationSet(dbLocation.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation))
|
||||||
locations.Add(evidence...)
|
locations.Add(evidence...)
|
||||||
@ -54,6 +54,25 @@ func newDpkgPackage(d pkg.DpkgDBEntry, dbLocation file.Location, resolver file.R
|
|||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newDebArchivePackage(location file.Location, metadata pkg.DpkgArchiveEntry, licenseStrings []string) pkg.Package {
|
||||||
|
p := pkg.Package{
|
||||||
|
Name: metadata.Package,
|
||||||
|
Version: metadata.Version,
|
||||||
|
Licenses: pkg.NewLicenseSet(pkg.NewLicensesFromValues(licenseStrings...)...),
|
||||||
|
Type: pkg.DebPkg,
|
||||||
|
PURL: packageURL(
|
||||||
|
pkg.DpkgDBEntry(metadata),
|
||||||
|
// we don't know the distro information, but since this is a deb file then we can reasonably assume it is a debian-based distro
|
||||||
|
&linux.Release{IDLike: []string{"debian"}},
|
||||||
|
),
|
||||||
|
Metadata: metadata,
|
||||||
|
Locations: file.NewLocationSet(location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)),
|
||||||
|
}
|
||||||
|
|
||||||
|
p.SetID()
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
// PackageURL returns the PURL for the specific Debian package (see https://github.com/package-url/purl-spec)
|
// PackageURL returns the PURL for the specific Debian package (see https://github.com/package-url/purl-spec)
|
||||||
func packageURL(m pkg.DpkgDBEntry, distro *linux.Release) string {
|
func packageURL(m pkg.DpkgDBEntry, distro *linux.Release) string {
|
||||||
if distro == nil {
|
if distro == nil {
|
||||||
|
|||||||
238
syft/pkg/cataloger/debian/parse_deb_archive.go
Normal file
238
syft/pkg/cataloger/debian/parse_deb_archive.go
Normal file
@ -0,0 +1,238 @@
|
|||||||
|
package debian
|
||||||
|
|
||||||
|
import (
|
||||||
|
"archive/tar"
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/blakesmith/ar"
|
||||||
|
"github.com/mholt/archives"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/internal"
|
||||||
|
"github.com/anchore/syft/internal/unknown"
|
||||||
|
"github.com/anchore/syft/syft/artifact"
|
||||||
|
"github.com/anchore/syft/syft/file"
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
||||||
|
)
|
||||||
|
|
||||||
|
// parseDebArchive parses a Debian package archive (.deb) file and returns the packages it contains.
|
||||||
|
// A .deb file is an ar archive containing three main files:
|
||||||
|
// - debian-binary: Version of the .deb format (usually "2.0")
|
||||||
|
// - control.tar.gz/xz/zst: Contains package metadata (control file, md5sums, conffiles)
|
||||||
|
// - data.tar.gz/xz/zst: Contains the actual files to be installed (not processed by this cataloger)
|
||||||
|
//
|
||||||
|
// This function extracts and processes the control information to create package metadata.
|
||||||
|
func parseDebArchive(ctx context.Context, _ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||||
|
arReader := ar.NewReader(reader)
|
||||||
|
|
||||||
|
var metadata *pkg.DpkgArchiveEntry
|
||||||
|
var licenses []string
|
||||||
|
var unknownErr error
|
||||||
|
for {
|
||||||
|
header, err := arReader.Next()
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("failed to read ar header: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case strings.HasPrefix(header.Name, "control.tar"):
|
||||||
|
// Decompress the control.tar.* file
|
||||||
|
dcReader, err := decompressionStream(ctx, arReader, header.Name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, unknown.New(reader.Location, fmt.Errorf("failed to decompress control.tar.* file: %w", err))
|
||||||
|
}
|
||||||
|
metadata, err = processControlTar(dcReader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, unknown.New(reader.Location, fmt.Errorf("failed to process control.tar.* file: %w", err))
|
||||||
|
}
|
||||||
|
case strings.HasPrefix(header.Name, "data.tar"):
|
||||||
|
// Decompress the data.tar.* file
|
||||||
|
dcReader, err := decompressionStream(ctx, arReader, header.Name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, unknown.New(reader.Location, fmt.Errorf("failed to decompress data.tar.* file: %w", err))
|
||||||
|
}
|
||||||
|
licenses, err = processDataTar(dcReader)
|
||||||
|
if err != nil {
|
||||||
|
unknownErr = unknown.Append(unknownErr, reader.Location, fmt.Errorf("failed to process data.tar.* file: %w", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if metadata == nil {
|
||||||
|
return nil, nil, unknown.New(reader.Location, fmt.Errorf("no application found described in .dpkg archive"))
|
||||||
|
}
|
||||||
|
|
||||||
|
return []pkg.Package{
|
||||||
|
newDebArchivePackage(reader.Location, *metadata, licenses),
|
||||||
|
}, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is the pattern you'd expect to see in a tar header for a debian package license file ()
|
||||||
|
var archiveHeaderLicensePathPattern = regexp.MustCompile(`^\.?/usr/share/doc/[^/]+/copyright$`)
|
||||||
|
|
||||||
|
func processDataTar(dcReader io.ReadCloser) ([]string, error) {
|
||||||
|
defer internal.CloseAndLogError(dcReader, "")
|
||||||
|
var licenses []string
|
||||||
|
|
||||||
|
tarReader := tar.NewReader(dcReader)
|
||||||
|
for {
|
||||||
|
header, err := tarReader.Next()
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return licenses, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// look for /usr/share/docs/*/copyright files, parse each one for license claims
|
||||||
|
// TODO: in the future we can add archive sub indexes to the locations to see where within
|
||||||
|
// the dpkg archive the license was found
|
||||||
|
if archiveHeaderLicensePathPattern.MatchString(header.Name) {
|
||||||
|
licenses = append(licenses, parseLicensesFromCopyright(tarReader)...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return licenses, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func processControlTar(dcReader io.ReadCloser) (*pkg.DpkgArchiveEntry, error) {
|
||||||
|
defer internal.CloseAndLogError(dcReader, "")
|
||||||
|
|
||||||
|
// Extract control, md5sums, and conffiles files from control.tar
|
||||||
|
tarReader := tar.NewReader(dcReader)
|
||||||
|
controlFileContent, md5Content, confContent, err := readControlFiles(tarReader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to read control files: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if controlFileContent == nil {
|
||||||
|
return nil, fmt.Errorf("control file not found in archive")
|
||||||
|
}
|
||||||
|
|
||||||
|
metadata, err := newDpkgArchiveMetadata(controlFileContent, md5Content, confContent)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create package metadata: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &metadata, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newDpkgArchiveMetadata(controlFile, md5sums, confFiles []byte) (pkg.DpkgArchiveEntry, error) {
|
||||||
|
// parse the control file to get package metadata
|
||||||
|
metadata, err := parseControlFile(string(controlFile))
|
||||||
|
if err != nil {
|
||||||
|
return pkg.DpkgArchiveEntry{}, fmt.Errorf("failed to parse control file: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse MD5 sums to get file records
|
||||||
|
var files []pkg.DpkgFileRecord
|
||||||
|
if len(md5sums) > 0 {
|
||||||
|
files = parseDpkgMD5Info(bytes.NewReader(md5sums))
|
||||||
|
}
|
||||||
|
|
||||||
|
// mark config files
|
||||||
|
if len(confFiles) > 0 {
|
||||||
|
markConfigFiles(confFiles, files)
|
||||||
|
}
|
||||||
|
|
||||||
|
metadata.Files = files
|
||||||
|
return metadata, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func decompressionStream(ctx context.Context, r io.Reader, filePath string) (io.ReadCloser, error) {
|
||||||
|
format, stream, err := archives.Identify(ctx, filePath, r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to identify compression format: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
decompressor, ok := format.(archives.Decompressor)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("file format does not support decompression: %s", filePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
rc, err := decompressor.OpenReader(stream)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create decompression reader: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// readControlFiles extracts important files from the control.tar archive
|
||||||
|
func readControlFiles(tarReader *tar.Reader) (controlFile, md5sums, conffiles []byte, err error) {
|
||||||
|
for {
|
||||||
|
header, err := tarReader.Next()
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch filepath.Base(header.Name) {
|
||||||
|
case "control":
|
||||||
|
controlFile, err = io.ReadAll(tarReader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, nil, err
|
||||||
|
}
|
||||||
|
case "md5sums":
|
||||||
|
md5sums, err = io.ReadAll(tarReader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, nil, err
|
||||||
|
}
|
||||||
|
case "conffiles":
|
||||||
|
conffiles, err = io.ReadAll(tarReader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return controlFile, md5sums, conffiles, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseControlFile parses the content of a debian control file into package metadata
|
||||||
|
func parseControlFile(controlFileContent string) (pkg.DpkgArchiveEntry, error) {
|
||||||
|
// Reuse the existing dpkg status file parsing logic
|
||||||
|
reader := strings.NewReader(controlFileContent)
|
||||||
|
|
||||||
|
entries, err := parseDpkgStatus(reader)
|
||||||
|
if err != nil {
|
||||||
|
return pkg.DpkgArchiveEntry{}, fmt.Errorf("failed to parse control file: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(entries) == 0 {
|
||||||
|
return pkg.DpkgArchiveEntry{}, fmt.Errorf("no package entries found in control file")
|
||||||
|
}
|
||||||
|
|
||||||
|
// We expect only one entry from a .deb control file
|
||||||
|
return pkg.DpkgArchiveEntry(entries[0]), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// markConfigFiles marks files that are listed in conffiles as configuration files
|
||||||
|
func markConfigFiles(conffilesContent []byte, files []pkg.DpkgFileRecord) {
|
||||||
|
// Parse the conffiles content into DpkgFileRecord entries
|
||||||
|
confFiles := parseDpkgConffileInfo(bytes.NewReader(conffilesContent))
|
||||||
|
|
||||||
|
// Create a map for quick lookup of config files by path
|
||||||
|
configPathMap := make(map[string]struct{})
|
||||||
|
for _, confFile := range confFiles {
|
||||||
|
configPathMap[confFile.Path] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark files as config files if they're in the conffiles list
|
||||||
|
for i := range files {
|
||||||
|
if _, exists := configPathMap[files[i].Path]; exists {
|
||||||
|
files[i].IsConfigFile = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
142
syft/pkg/cataloger/debian/parse_deb_archive_test.go
Normal file
142
syft/pkg/cataloger/debian/parse_deb_archive_test.go
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
package debian
|
||||||
|
|
||||||
|
import (
|
||||||
|
"archive/tar"
|
||||||
|
"bytes"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft/file"
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestReadControlFiles(t *testing.T) {
|
||||||
|
tarBytes := createTestTarWithControlFiles(t)
|
||||||
|
|
||||||
|
tarReader := bytes.NewReader(tarBytes)
|
||||||
|
reader := tar.NewReader(tarReader)
|
||||||
|
|
||||||
|
controlFile, md5sums, conffiles, err := readControlFiles(reader)
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.NotNil(t, controlFile, "expected control file to be found")
|
||||||
|
assert.NotNil(t, md5sums, "expected md5sums file to be found")
|
||||||
|
assert.NotNil(t, conffiles, "expected conffiles file to be found")
|
||||||
|
|
||||||
|
assert.Contains(t, string(controlFile), "Package: test-package")
|
||||||
|
assert.Contains(t, string(md5sums), "d41d8cd98f00b204e9800998ecf8427e")
|
||||||
|
assert.Contains(t, string(conffiles), "/etc/test")
|
||||||
|
}
|
||||||
|
|
||||||
|
// createTestTarWithControlFiles creates a simple in-memory tar file with test control files
|
||||||
|
func createTestTarWithControlFiles(t *testing.T) []byte {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
tw := tar.NewWriter(&buf)
|
||||||
|
|
||||||
|
// Add control file
|
||||||
|
controlContent := `Package: test-package
|
||||||
|
Version: 1.0.0
|
||||||
|
Architecture: all
|
||||||
|
Maintainer: Test <test@example.com>
|
||||||
|
Description: Test package
|
||||||
|
`
|
||||||
|
err := tw.WriteHeader(&tar.Header{
|
||||||
|
Name: "control",
|
||||||
|
Mode: 0644,
|
||||||
|
Size: int64(len(controlContent)),
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
_, err = tw.Write([]byte(controlContent))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Add md5sums file
|
||||||
|
md5Content := "d41d8cd98f00b204e9800998ecf8427e usr/bin/test-command\n"
|
||||||
|
err = tw.WriteHeader(&tar.Header{
|
||||||
|
Name: "md5sums",
|
||||||
|
Mode: 0644,
|
||||||
|
Size: int64(len(md5Content)),
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
_, err = tw.Write([]byte(md5Content))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Add conffiles file
|
||||||
|
conffilesContent := "/etc/test/config.conf\n"
|
||||||
|
err = tw.WriteHeader(&tar.Header{
|
||||||
|
Name: "conffiles",
|
||||||
|
Mode: 0644,
|
||||||
|
Size: int64(len(conffilesContent)),
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
_, err = tw.Write([]byte(conffilesContent))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Close the tar writer
|
||||||
|
err = tw.Close()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
return buf.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMarkConfigFiles(t *testing.T) {
|
||||||
|
// Create test data
|
||||||
|
conffilesContent := []byte("/usr/bin/test-command\n/etc/test/config.conf\n")
|
||||||
|
|
||||||
|
files := []pkg.DpkgFileRecord{
|
||||||
|
{
|
||||||
|
Path: "/usr/bin/test-command",
|
||||||
|
Digest: &file.Digest{
|
||||||
|
Algorithm: "md5",
|
||||||
|
Value: "d41d8cd98f00b204e9800998ecf8427e",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Path: "/etc/test/config.conf",
|
||||||
|
Digest: &file.Digest{
|
||||||
|
Algorithm: "md5",
|
||||||
|
Value: "d41d8cd98f00b204e9800998ecf8427e",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Path: "/usr/bin/other-command",
|
||||||
|
Digest: &file.Digest{
|
||||||
|
Algorithm: "md5",
|
||||||
|
Value: "d41d8cd98f00b204e9800998ecf8427e",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
markConfigFiles(conffilesContent, files)
|
||||||
|
|
||||||
|
assert.True(t, files[0].IsConfigFile, "first file should be marked as config file")
|
||||||
|
assert.True(t, files[1].IsConfigFile, "second file should be marked as config file")
|
||||||
|
assert.False(t, files[2].IsConfigFile, "third file should not be marked as config file")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseControlFile(t *testing.T) {
|
||||||
|
controlContent := `Package: test-package
|
||||||
|
Version: 1.2.3-4
|
||||||
|
Architecture: amd64
|
||||||
|
Maintainer: Test User <test@example.com>
|
||||||
|
Installed-Size: 1234
|
||||||
|
Depends: libc6, libtest
|
||||||
|
Description: This is a test package
|
||||||
|
More description text
|
||||||
|
And even more details
|
||||||
|
`
|
||||||
|
|
||||||
|
metadata, err := parseControlFile(controlContent)
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, "test-package", metadata.Package)
|
||||||
|
assert.Equal(t, "1.2.3-4", metadata.Version)
|
||||||
|
assert.Equal(t, "amd64", metadata.Architecture)
|
||||||
|
assert.Equal(t, "Test User <test@example.com>", metadata.Maintainer)
|
||||||
|
assert.Equal(t, 1234, metadata.InstalledSize)
|
||||||
|
assert.Contains(t, metadata.Description, "This is a test package")
|
||||||
|
assert.Len(t, metadata.Depends, 2)
|
||||||
|
assert.Contains(t, metadata.Depends, "libc6")
|
||||||
|
assert.Contains(t, metadata.Depends, "libtest")
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"
|
||||||
|
NAME="Debian GNU/Linux"
|
||||||
|
VERSION_ID="12"
|
||||||
|
VERSION="12 (bookworm)"
|
||||||
|
VERSION_CODENAME=bookworm
|
||||||
|
ID=debian
|
||||||
|
HOME_URL="https://www.debian.org/"
|
||||||
|
SUPPORT_URL="https://www.debian.org/support"
|
||||||
|
BUG_REPORT_URL="https://bugs.debian.org/"
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
FROM ubuntu:22.04 AS downloader
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get install -y curl
|
||||||
|
|
||||||
|
RUN curl -o zlib1g.deb http://archive.ubuntu.com/ubuntu/pool/main/z/zlib/zlib1g_1.3.dfsg-3.1ubuntu2.1_amd64.deb
|
||||||
|
|
||||||
|
FROM scratch
|
||||||
|
|
||||||
|
COPY --from=downloader /zlib1g.deb /zlib1g.deb
|
||||||
@ -12,6 +12,8 @@ const DpkgDBGlob = "**/var/lib/dpkg/{status,status.d/**}"
|
|||||||
|
|
||||||
var _ FileOwner = (*DpkgDBEntry)(nil)
|
var _ FileOwner = (*DpkgDBEntry)(nil)
|
||||||
|
|
||||||
|
type DpkgArchiveEntry DpkgDBEntry
|
||||||
|
|
||||||
// DpkgDBEntry represents all captured data for a Debian package DB entry; available fields are described
|
// DpkgDBEntry represents all captured data for a Debian package DB entry; available fields are described
|
||||||
// at http://manpages.ubuntu.com/manpages/xenial/man1/dpkg-query.1.html in the --showformat section.
|
// at http://manpages.ubuntu.com/manpages/xenial/man1/dpkg-query.1.html in the --showformat section.
|
||||||
// Additional information about how these fields are used can be found at
|
// Additional information about how these fields are used can be found at
|
||||||
|
|||||||
@ -39,7 +39,7 @@ func PURLQualifiers(vars map[string]string, release *linux.Release) (q packageur
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
distroQualifiers := []string{}
|
var distroQualifiers []string
|
||||||
|
|
||||||
if release == nil {
|
if release == nil {
|
||||||
return q
|
return q
|
||||||
@ -55,10 +55,12 @@ func PURLQualifiers(vars map[string]string, release *linux.Release) (q packageur
|
|||||||
distroQualifiers = append(distroQualifiers, release.BuildID)
|
distroQualifiers = append(distroQualifiers, release.BuildID)
|
||||||
}
|
}
|
||||||
|
|
||||||
q = append(q, packageurl.Qualifier{
|
if len(distroQualifiers) > 0 {
|
||||||
Key: PURLQualifierDistro,
|
q = append(q, packageurl.Qualifier{
|
||||||
Value: strings.Join(distroQualifiers, "-"),
|
Key: PURLQualifierDistro,
|
||||||
})
|
Value: strings.Join(distroQualifiers, "-"),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return q
|
return q
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user