mirror of
https://github.com/anchore/syft
synced 2024-11-10 14:24:12 +00:00
enhance dpkg support by parsing md5sum and copyright file sources
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
This commit is contained in:
parent
b6eb589b78
commit
2a329002b8
23 changed files with 1136 additions and 95 deletions
|
@ -10,6 +10,19 @@
|
|||
},
|
||||
"type": "array"
|
||||
},
|
||||
"licenses": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "null"
|
||||
},
|
||||
{
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
]
|
||||
},
|
||||
"locations": {
|
||||
"items": {
|
||||
"anyOf": [
|
||||
|
@ -53,55 +66,62 @@
|
|||
"type": "integer"
|
||||
},
|
||||
"files": {
|
||||
"items": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"checksum": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "null"
|
||||
},
|
||||
{
|
||||
"items": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
"digest": {
|
||||
{
|
||||
"properties": {
|
||||
"algorithm": {
|
||||
"checksum": {
|
||||
"type": "string"
|
||||
},
|
||||
"value": {
|
||||
"digest": {
|
||||
"properties": {
|
||||
"algorithm": {
|
||||
"type": "string"
|
||||
},
|
||||
"value": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"algorithm",
|
||||
"value"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"ownerGid": {
|
||||
"type": "string"
|
||||
},
|
||||
"ownerUid": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
},
|
||||
"permissions": {
|
||||
"type": "string"
|
||||
},
|
||||
"size": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"algorithm",
|
||||
"value"
|
||||
"path"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"ownerGid": {
|
||||
"type": "string"
|
||||
},
|
||||
"ownerUid": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
},
|
||||
"permissions": {
|
||||
"type": "string"
|
||||
},
|
||||
"size": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"path"
|
||||
],
|
||||
"type": "object"
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "array"
|
||||
]
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
]
|
||||
},
|
||||
"gitCommitOfApkPort": {
|
||||
"type": "string"
|
||||
|
@ -307,6 +327,7 @@
|
|||
},
|
||||
"required": [
|
||||
"foundBy",
|
||||
"licenses",
|
||||
"locations",
|
||||
"name",
|
||||
"type",
|
||||
|
|
|
@ -4,14 +4,193 @@ Package dpkg provides a concrete Cataloger implementation for Debian package DB
|
|||
package deb
|
||||
|
||||
import (
|
||||
"github.com/anchore/syft/syft/cataloger/common"
|
||||
"fmt"
|
||||
"io"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/anchore/stereoscope/pkg/file"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/scope"
|
||||
)
|
||||
|
||||
const (
|
||||
dpkgStatusGlob = "**/var/lib/dpkg/status"
|
||||
md5sumsExt = ".md5sums"
|
||||
docsPath = "/usr/share/doc"
|
||||
)
|
||||
|
||||
type Cataloger struct{}
|
||||
|
||||
// NewDpkgdbCataloger returns a new Deb package cataloger object.
|
||||
func NewDpkgdbCataloger() *common.GenericCataloger {
|
||||
globParsers := map[string]common.ParserFn{
|
||||
"**/var/lib/dpkg/status": parseDpkgStatus,
|
||||
func NewDpkgdbCataloger() *Cataloger {
|
||||
return &Cataloger{}
|
||||
}
|
||||
|
||||
// Name returns a string that uniquely describes a cataloger
|
||||
func (c *Cataloger) Name() string {
|
||||
return "dpkgdb-cataloger"
|
||||
}
|
||||
|
||||
// Catalog is given an object to resolve file references and content, this function returns any discovered Packages after analyzing dpkg support files.
|
||||
func (c *Cataloger) Catalog(resolver scope.Resolver) ([]pkg.Package, error) {
|
||||
dbFileMatches, err := resolver.FilesByGlob(dpkgStatusGlob)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find dpkg status files's by glob: %w", err)
|
||||
}
|
||||
|
||||
return common.NewGenericCataloger(nil, globParsers, "dpkgdb-cataloger")
|
||||
var pkgs []pkg.Package
|
||||
for _, dbRef := range dbFileMatches {
|
||||
dbContents, err := resolver.FileContentsByRef(dbRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pkgs, err = parseDpkgStatus(strings.NewReader(dbContents))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to catalog dpkg package=%+v: %w", dbRef.Path, err)
|
||||
}
|
||||
|
||||
md5ContentsByName, md5RefsByName, err := fetchMd5Contents(resolver, dbRef, pkgs)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to find dpkg md5 contents: %w", err)
|
||||
}
|
||||
|
||||
copyrightContentsByName, copyrightRefsByName, err := fetchCopyrightContents(resolver, dbRef, pkgs)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to find dpkg copyright contents: %w", err)
|
||||
}
|
||||
|
||||
for i := range pkgs {
|
||||
p := &pkgs[i]
|
||||
p.FoundBy = c.Name()
|
||||
p.Source = []file.Reference{dbRef}
|
||||
|
||||
if md5Reader, ok := md5ContentsByName[md5Key(*p)]; ok {
|
||||
// attach the file list
|
||||
metadata := p.Metadata.(pkg.DpkgMetadata)
|
||||
metadata.Files = parseDpkgMD5Info(md5Reader)
|
||||
p.Metadata = metadata
|
||||
|
||||
// keep a record of the file where this was discovered
|
||||
if ref, ok := md5RefsByName[md5Key(*p)]; ok {
|
||||
p.Source = append(p.Source, ref)
|
||||
}
|
||||
}
|
||||
|
||||
copyrightReader, ok := copyrightContentsByName[p.Name]
|
||||
if ok {
|
||||
// attach the licenses
|
||||
p.Licenses = parseLicensesFromCopyright(copyrightReader)
|
||||
|
||||
// keep a record of the file where this was discovered
|
||||
if ref, ok := copyrightRefsByName[p.Name]; ok {
|
||||
p.Source = append(p.Source, ref)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return pkgs, nil
|
||||
}
|
||||
|
||||
func fetchMd5Contents(resolver scope.Resolver, dbRef file.Reference, pkgs []pkg.Package) (map[string]io.Reader, map[string]file.Reference, error) {
|
||||
// fetch all MD5 file contents. This approach is more efficient than fetching each MD5 file one at a time
|
||||
|
||||
var md5FileMatches []file.Reference
|
||||
var nameByRef = make(map[file.Reference]string)
|
||||
parentPath, err := dbRef.Path.ParentPath()
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("unable to find parent of path=%+v: %w", dbRef.Path, err)
|
||||
}
|
||||
for _, p := range pkgs {
|
||||
// look for /var/lib/dpkg/info/NAME:ARCH.md5sums
|
||||
name := md5Key(p)
|
||||
md5sumPath := path.Join(string(parentPath), "info", name+md5sumsExt)
|
||||
md5SumRef, err := resolver.RelativeFileByPath(dbRef, md5sumPath)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("unable to find relative md5sum from path=%+v: %w", dbRef.Path, err)
|
||||
}
|
||||
|
||||
if md5SumRef == nil {
|
||||
// the most specific key did not work, fallback to just the name
|
||||
// look for /var/lib/dpkg/info/NAME.md5sums
|
||||
name := p.Name
|
||||
md5sumPath := path.Join(string(parentPath), "info", name+md5sumsExt)
|
||||
md5SumRef, err = resolver.RelativeFileByPath(dbRef, md5sumPath)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("unable to find relative md5sum from path=%+v: %w", dbRef.Path, err)
|
||||
}
|
||||
}
|
||||
// we should have at least one reference
|
||||
if md5SumRef != nil {
|
||||
md5FileMatches = append(md5FileMatches, *md5SumRef)
|
||||
nameByRef[*md5SumRef] = name
|
||||
}
|
||||
}
|
||||
|
||||
// fetch the md5 contents
|
||||
md5ContentsByRef, err := resolver.MultipleFileContentsByRef(md5FileMatches...)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// organize content results and refs by a combination of name and architecture
|
||||
var contentsByName = make(map[string]io.Reader)
|
||||
var refsByName = make(map[string]file.Reference)
|
||||
for ref, contents := range md5ContentsByRef {
|
||||
name := nameByRef[ref]
|
||||
contentsByName[name] = strings.NewReader(contents)
|
||||
refsByName[name] = ref
|
||||
}
|
||||
|
||||
return contentsByName, refsByName, nil
|
||||
}
|
||||
|
||||
func fetchCopyrightContents(resolver scope.Resolver, dbRef file.Reference, pkgs []pkg.Package) (map[string]io.Reader, map[string]file.Reference, error) {
|
||||
// fetch all copyright file contents. This approach is more efficient than fetching each copyright file one at a time
|
||||
|
||||
var copyrightFileMatches []file.Reference
|
||||
var nameByRef = make(map[file.Reference]string)
|
||||
for _, p := range pkgs {
|
||||
// look for /usr/share/docs/NAME/copyright files
|
||||
name := p.Name
|
||||
copyrightPath := path.Join(docsPath, name, "copyright")
|
||||
copyrightRef, err := resolver.RelativeFileByPath(dbRef, copyrightPath)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("unable to find relative copyright from path=%+v: %w", dbRef.Path, err)
|
||||
}
|
||||
|
||||
// we may not have a copyright file for each package, ignore missing files
|
||||
if copyrightRef != nil {
|
||||
copyrightFileMatches = append(copyrightFileMatches, *copyrightRef)
|
||||
nameByRef[*copyrightRef] = name
|
||||
}
|
||||
}
|
||||
|
||||
// fetch the copyright contents
|
||||
copyrightContentsByRef, err := resolver.MultipleFileContentsByRef(copyrightFileMatches...)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// organize content results and refs by package name
|
||||
var contentsByName = make(map[string]io.Reader)
|
||||
var refsByName = make(map[string]file.Reference)
|
||||
for ref, contents := range copyrightContentsByRef {
|
||||
name := nameByRef[ref]
|
||||
contentsByName[name] = strings.NewReader(contents)
|
||||
refsByName[name] = ref
|
||||
}
|
||||
|
||||
return contentsByName, refsByName, nil
|
||||
}
|
||||
|
||||
func md5Key(p pkg.Package) string {
|
||||
metadata := p.Metadata.(pkg.DpkgMetadata)
|
||||
|
||||
contentKey := p.Name
|
||||
if metadata.Architecture != "" && metadata.Architecture != "all" {
|
||||
contentKey = contentKey + ":" + metadata.Architecture
|
||||
}
|
||||
return contentKey
|
||||
}
|
||||
|
|
99
syft/cataloger/deb/cataloger_test.go
Normal file
99
syft/cataloger/deb/cataloger_test.go
Normal file
|
@ -0,0 +1,99 @@
|
|||
package deb
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/anchore/stereoscope/pkg/imagetest"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/scope"
|
||||
"github.com/go-test/deep"
|
||||
)
|
||||
|
||||
func TestDpkgCataloger(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
sources map[string][]string
|
||||
expected []pkg.Package
|
||||
}{
|
||||
{
|
||||
name: "go-case",
|
||||
sources: map[string][]string{
|
||||
"libpam-runtime": {"/var/lib/dpkg/status", "/var/lib/dpkg/info/libpam-runtime.md5sums", "/usr/share/doc/libpam-runtime/copyright"},
|
||||
},
|
||||
expected: []pkg.Package{
|
||||
{
|
||||
Name: "libpam-runtime",
|
||||
Version: "1.1.8-3.6",
|
||||
FoundBy: "dpkgdb-cataloger",
|
||||
Licenses: []string{"GPL-2", "LGPL-2.1"},
|
||||
Type: pkg.DebPkg,
|
||||
MetadataType: pkg.DpkgMetadataType,
|
||||
Metadata: pkg.DpkgMetadata{
|
||||
Package: "libpam-runtime",
|
||||
Source: "pam",
|
||||
Version: "1.1.8-3.6",
|
||||
Architecture: "all",
|
||||
Maintainer: "Steve Langasek <vorlon@debian.org>",
|
||||
InstalledSize: 1016,
|
||||
Files: []pkg.DpkgFileRecord{
|
||||
{Path: "/lib/x86_64-linux-gnu/libz.so.1.2.11", MD5: "55f905631797551d4d936a34c7e73474"},
|
||||
{Path: "/usr/share/doc/zlib1g/changelog.Debian.gz", MD5: "cede84bda30d2380217f97753c8ccf3a"},
|
||||
{Path: "/usr/share/doc/zlib1g/changelog.gz", MD5: "f3c9dafa6da7992c47328b4464f6d122"},
|
||||
{Path: "/usr/share/doc/zlib1g/copyright", MD5: "a4fae96070439a5209a62ae5b8017ab2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
|
||||
img, cleanup := imagetest.GetFixtureImage(t, "docker-archive", "image-dpkg")
|
||||
defer cleanup()
|
||||
|
||||
s, err := scope.NewScopeFromImage(img, scope.AllLayersScope)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
c := NewDpkgdbCataloger()
|
||||
|
||||
actual, err := c.Catalog(s.Resolver)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to catalog: %+v", err)
|
||||
}
|
||||
|
||||
if len(actual) != len(test.expected) {
|
||||
for _, a := range actual {
|
||||
t.Logf(" %+v", a)
|
||||
}
|
||||
t.Fatalf("unexpected package count: %d!=%d", len(actual), len(test.expected))
|
||||
}
|
||||
|
||||
// test sources...
|
||||
for idx := range actual {
|
||||
a := &actual[idx]
|
||||
// we will test the sources separately
|
||||
var sourcesList = make([]string, len(a.Source))
|
||||
for i, s := range a.Source {
|
||||
sourcesList[i] = string(s.Path)
|
||||
}
|
||||
a.Source = nil
|
||||
|
||||
for _, d := range deep.Equal(sourcesList, test.sources[a.Name]) {
|
||||
t.Errorf("diff: %+v", d)
|
||||
}
|
||||
}
|
||||
|
||||
// test remaining fields...
|
||||
for _, d := range deep.Equal(actual, test.expected) {
|
||||
t.Errorf("diff: %+v", d)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
}
|
38
syft/cataloger/deb/parse_copyright.go
Normal file
38
syft/cataloger/deb/parse_copyright.go
Normal file
|
@ -0,0 +1,38 @@
|
|||
package deb
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/anchore/syft/internal"
|
||||
)
|
||||
|
||||
// For more information see: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/#license-syntax
|
||||
|
||||
func parseLicensesFromCopyright(reader io.Reader) []string {
|
||||
findings := internal.NewStringSet()
|
||||
scanner := bufio.NewScanner(reader)
|
||||
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if strings.HasPrefix(line, "License:") {
|
||||
candidate := strings.Replace(line, "License:", "", 1)
|
||||
candidate = strings.TrimSpace(candidate)
|
||||
if strings.Contains(candidate, " or ") || strings.Contains(candidate, " and ") {
|
||||
// this is a multi-license summary, ignore this as other recurrent license lines should cover this
|
||||
continue
|
||||
}
|
||||
if candidate != "" && strings.ToLower(candidate) != "none" {
|
||||
findings.Add(candidate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
results := findings.ToSlice()
|
||||
|
||||
sort.Strings(results)
|
||||
|
||||
return results
|
||||
}
|
58
syft/cataloger/deb/parse_copyright_test.go
Normal file
58
syft/cataloger/deb/parse_copyright_test.go
Normal file
|
@ -0,0 +1,58 @@
|
|||
package deb
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/go-test/deep"
|
||||
)
|
||||
|
||||
func TestParseLicensesFromCopyright(t *testing.T) {
|
||||
tests := []struct {
|
||||
fixture string
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
fixture: "test-fixtures/copyright/trilicense",
|
||||
expected: []string{"GPL-2", "LGPL-2.1", "MPL-1.1"},
|
||||
},
|
||||
{
|
||||
fixture: "test-fixtures/copyright/liblzma5",
|
||||
expected: []string{"Autoconf", "GPL-2", "GPL-2+", "LGPL-2.1+", "PD", "PD-debian", "config-h", "noderivs", "permissive-fsf", "permissive-nowarranty", "probably-PD"},
|
||||
},
|
||||
{
|
||||
fixture: "test-fixtures/copyright/libaudit-common",
|
||||
expected: []string{"GPL-2", "LGPL-2.1"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.fixture, func(t *testing.T) {
|
||||
file, err := os.Open(test.fixture)
|
||||
if err != nil {
|
||||
t.Fatal("Unable to read: ", err)
|
||||
}
|
||||
defer func() {
|
||||
err := file.Close()
|
||||
if err != nil {
|
||||
t.Fatal("closing file failed:", err)
|
||||
}
|
||||
}()
|
||||
|
||||
actual := parseLicensesFromCopyright(file)
|
||||
|
||||
if len(actual) != len(test.expected) {
|
||||
for _, a := range actual {
|
||||
t.Logf(" %+v", a)
|
||||
}
|
||||
t.Fatalf("unexpected package count: %d!=%d", len(actual), len(test.expected))
|
||||
}
|
||||
|
||||
diffs := deep.Equal(actual, test.expected)
|
||||
for _, d := range diffs {
|
||||
t.Errorf("diff: %+v", d)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
30
syft/cataloger/deb/parse_dpkg_info_files.go
Normal file
30
syft/cataloger/deb/parse_dpkg_info_files.go
Normal file
|
@ -0,0 +1,30 @@
|
|||
package deb
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
)
|
||||
|
||||
func parseDpkgMD5Info(reader io.Reader) []pkg.DpkgFileRecord {
|
||||
var findings []pkg.DpkgFileRecord
|
||||
scanner := bufio.NewScanner(reader)
|
||||
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
fields := strings.SplitN(line, " ", 2)
|
||||
if len(fields) == 2 {
|
||||
path := strings.TrimSpace(fields[1])
|
||||
if !strings.HasPrefix(path, "/") {
|
||||
path = "/" + path
|
||||
}
|
||||
findings = append(findings, pkg.DpkgFileRecord{
|
||||
Path: path,
|
||||
MD5: strings.TrimSpace(fields[0]),
|
||||
})
|
||||
}
|
||||
}
|
||||
return findings
|
||||
}
|
57
syft/cataloger/deb/parse_dpkg_info_files_test.go
Normal file
57
syft/cataloger/deb/parse_dpkg_info_files_test.go
Normal file
|
@ -0,0 +1,57 @@
|
|||
package deb
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/go-test/deep"
|
||||
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
)
|
||||
|
||||
func TestMD5SumInfoParsing(t *testing.T) {
|
||||
tests := []struct {
|
||||
fixture string
|
||||
expected []pkg.DpkgFileRecord
|
||||
}{
|
||||
{
|
||||
fixture: "test-fixtures/info/zlib1g.md5sums",
|
||||
expected: []pkg.DpkgFileRecord{
|
||||
{Path: "/lib/x86_64-linux-gnu/libz.so.1.2.11", MD5: "55f905631797551d4d936a34c7e73474"},
|
||||
{Path: "/usr/share/doc/zlib1g/changelog.Debian.gz", MD5: "cede84bda30d2380217f97753c8ccf3a"},
|
||||
{Path: "/usr/share/doc/zlib1g/changelog.gz", MD5: "f3c9dafa6da7992c47328b4464f6d122"},
|
||||
{Path: "/usr/share/doc/zlib1g/copyright", MD5: "a4fae96070439a5209a62ae5b8017ab2"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.fixture, func(t *testing.T) {
|
||||
file, err := os.Open(test.fixture)
|
||||
if err != nil {
|
||||
t.Fatal("Unable to read: ", err)
|
||||
}
|
||||
defer func() {
|
||||
err := file.Close()
|
||||
if err != nil {
|
||||
t.Fatal("closing file failed:", err)
|
||||
}
|
||||
}()
|
||||
|
||||
actual := parseDpkgMD5Info(file)
|
||||
|
||||
if len(actual) != len(test.expected) {
|
||||
for _, a := range actual {
|
||||
t.Logf(" %+v", a)
|
||||
}
|
||||
t.Fatalf("unexpected package count: %d!=%d", len(actual), len(test.expected))
|
||||
}
|
||||
|
||||
diffs := deep.Equal(actual, test.expected)
|
||||
for _, d := range diffs {
|
||||
t.Errorf("diff: %+v", d)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
|
@ -2,40 +2,43 @@ package deb
|
|||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/anchore/syft/syft/cataloger/common"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
)
|
||||
|
||||
// integrity check
|
||||
var _ common.ParserFn = parseDpkgStatus
|
||||
|
||||
var errEndOfPackages = fmt.Errorf("no more packages to read")
|
||||
|
||||
// parseDpkgStatus is a parser function for Debian DB status contents, returning all Debian packages listed.
|
||||
func parseDpkgStatus(_ string, reader io.Reader) ([]pkg.Package, error) {
|
||||
func parseDpkgStatus(reader io.Reader) ([]pkg.Package, error) {
|
||||
buffedReader := bufio.NewReader(reader)
|
||||
var packages = make([]pkg.Package, 0)
|
||||
|
||||
for {
|
||||
continueProcessing := true
|
||||
for continueProcessing {
|
||||
entry, err := parseDpkgStatusEntry(buffedReader)
|
||||
if err != nil {
|
||||
if err == errEndOfPackages {
|
||||
break
|
||||
if errors.Is(err, errEndOfPackages) {
|
||||
continueProcessing = false
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
packages = append(packages, pkg.Package{
|
||||
Name: entry.Package,
|
||||
Version: entry.Version,
|
||||
Type: pkg.DebPkg,
|
||||
MetadataType: pkg.DpkgMetadataType,
|
||||
Metadata: entry,
|
||||
})
|
||||
|
||||
if entry.Package != "" {
|
||||
packages = append(packages, pkg.Package{
|
||||
Name: entry.Package,
|
||||
Version: entry.Version,
|
||||
Type: pkg.DebPkg,
|
||||
MetadataType: pkg.DpkgMetadataType,
|
||||
Metadata: entry,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return packages, nil
|
||||
|
@ -43,14 +46,16 @@ func parseDpkgStatus(_ string, reader io.Reader) ([]pkg.Package, error) {
|
|||
|
||||
// parseDpkgStatusEntry returns an individual Dpkg entry, or returns errEndOfPackages if there are no more packages to parse from the reader.
|
||||
func parseDpkgStatusEntry(reader *bufio.Reader) (entry pkg.DpkgMetadata, err error) {
|
||||
dpkgFields := make(map[string]string)
|
||||
dpkgFields := make(map[string]interface{})
|
||||
var retErr error
|
||||
var key string
|
||||
|
||||
for {
|
||||
line, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
return pkg.DpkgMetadata{}, errEndOfPackages
|
||||
retErr = errEndOfPackages
|
||||
break
|
||||
}
|
||||
return pkg.DpkgMetadata{}, err
|
||||
}
|
||||
|
@ -82,18 +87,16 @@ func parseDpkgStatusEntry(reader *bufio.Reader) (entry pkg.DpkgMetadata, err err
|
|||
dpkgFields[key] = val
|
||||
default:
|
||||
// parse a new key
|
||||
if i := strings.Index(line, ":"); i > 0 {
|
||||
key = strings.TrimSpace(line[0:i])
|
||||
val := strings.TrimSpace(line[i+1:])
|
||||
|
||||
if _, ok := dpkgFields[key]; ok {
|
||||
return pkg.DpkgMetadata{}, fmt.Errorf("duplicate key discovered: %s", key)
|
||||
}
|
||||
|
||||
dpkgFields[key] = val
|
||||
} else {
|
||||
return pkg.DpkgMetadata{}, fmt.Errorf("cannot parse field from line: '%s'", line)
|
||||
var val interface{}
|
||||
key, val, err = handleNewKeyValue(line)
|
||||
if err != nil {
|
||||
return pkg.DpkgMetadata{}, err
|
||||
}
|
||||
|
||||
if _, ok := dpkgFields[key]; ok {
|
||||
return pkg.DpkgMetadata{}, fmt.Errorf("duplicate key discovered: %s", key)
|
||||
}
|
||||
dpkgFields[key] = val
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,5 +105,29 @@ func parseDpkgStatusEntry(reader *bufio.Reader) (entry pkg.DpkgMetadata, err err
|
|||
return pkg.DpkgMetadata{}, err
|
||||
}
|
||||
|
||||
return entry, nil
|
||||
return entry, retErr
|
||||
}
|
||||
|
||||
// handleNewKeyValue parse a new key-value pair from the given unprocessed line
|
||||
func handleNewKeyValue(line string) (string, interface{}, error) {
|
||||
if i := strings.Index(line, ":"); i > 0 {
|
||||
var key = strings.TrimSpace(line[0:i])
|
||||
// mapstruct cant handle "-"
|
||||
key = strings.ReplaceAll(key, "-", "")
|
||||
val := strings.TrimSpace(line[i+1:])
|
||||
|
||||
// further processing of values based on the key that was discovered
|
||||
switch key {
|
||||
case "InstalledSize":
|
||||
numVal, err := strconv.Atoi(val)
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("bad installed-size value=%q: %w", val, err)
|
||||
}
|
||||
return key, numVal, nil
|
||||
default:
|
||||
return key, val, nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", nil, fmt.Errorf("cannot parse field from line: '%s'", line)
|
||||
}
|
||||
|
|
|
@ -24,17 +24,19 @@ func TestSinglePackage(t *testing.T) {
|
|||
{
|
||||
name: "Test Single Package",
|
||||
expected: pkg.DpkgMetadata{
|
||||
Package: "apt",
|
||||
Source: "apt-dev",
|
||||
Version: "1.8.2",
|
||||
Architecture: "amd64",
|
||||
Package: "apt",
|
||||
Source: "apt-dev",
|
||||
Version: "1.8.2",
|
||||
Architecture: "amd64",
|
||||
InstalledSize: 4064,
|
||||
Maintainer: "APT Development Team <deity@lists.debian.org>",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
file, err := os.Open("test-fixtures/single")
|
||||
file, err := os.Open("test-fixtures/status/single")
|
||||
if err != nil {
|
||||
t.Fatal("Unable to read test_fixtures/single: ", err)
|
||||
}
|
||||
|
@ -66,15 +68,19 @@ func TestMultiplePackages(t *testing.T) {
|
|||
name: "Test Multiple Package",
|
||||
expected: []pkg.DpkgMetadata{
|
||||
{
|
||||
Package: "tzdata",
|
||||
Version: "2020a-0+deb10u1",
|
||||
Source: "tzdata-dev",
|
||||
Architecture: "all",
|
||||
Package: "tzdata",
|
||||
Version: "2020a-0+deb10u1",
|
||||
Source: "tzdata-dev",
|
||||
Architecture: "all",
|
||||
InstalledSize: 3036,
|
||||
Maintainer: "GNU Libc Maintainers <debian-glibc@lists.debian.org>",
|
||||
},
|
||||
{
|
||||
Package: "util-linux",
|
||||
Version: "2.33.1-0.1",
|
||||
Architecture: "amd64",
|
||||
Package: "util-linux",
|
||||
Version: "2.33.1-0.1",
|
||||
Architecture: "amd64",
|
||||
InstalledSize: 4327,
|
||||
Maintainer: "LaMont Jones <lamont@debian.org>",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -82,7 +88,7 @@ func TestMultiplePackages(t *testing.T) {
|
|||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
file, err := os.Open("test-fixtures/multiple")
|
||||
file, err := os.Open("test-fixtures/status/multiple")
|
||||
if err != nil {
|
||||
t.Fatal("Unable to read: ", err)
|
||||
}
|
||||
|
@ -93,7 +99,7 @@ func TestMultiplePackages(t *testing.T) {
|
|||
}
|
||||
}()
|
||||
|
||||
pkgs, err := parseDpkgStatus(file.Name(), file)
|
||||
pkgs, err := parseDpkgStatus(file)
|
||||
if err != nil {
|
||||
t.Fatal("Unable to read file contents: ", err)
|
||||
}
|
||||
|
|
43
syft/cataloger/deb/test-fixtures/copyright/libaudit-common
Normal file
43
syft/cataloger/deb/test-fixtures/copyright/libaudit-common
Normal file
|
@ -0,0 +1,43 @@
|
|||
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: auditd
|
||||
Source: https://people.redhat.com/sgrubb/audit/
|
||||
|
||||
Files: *
|
||||
Copyright: 2012-2016 Steve Grubb <sgrubb@redhat.com>
|
||||
2006-2012 Rik Faith
|
||||
License: GPL-2
|
||||
|
||||
Files: src/libev/*
|
||||
Copyright: 2007-2009 Marc Alexamder Lehmann
|
||||
License: GPL-2
|
||||
|
||||
Files: lib/*
|
||||
Copyright: 2005-2008 Steve Grubb <sgrubb@redhat.com>
|
||||
License: LGPL-2.1
|
||||
The audit daemon's library libaudit.* is released under LGPL
|
||||
so that it may be linked with 3rd party software.
|
||||
.
|
||||
On Debian systems, refer to /usr/share/common-licenses/LGPL-2.1
|
||||
for the complete text of the GNU Lesser General Public License.
|
||||
|
||||
Files: debian/*
|
||||
Copyright: 2007-2011 Philipp Matthias Hahn <pmhahn@debian.org>
|
||||
2012-2016 Laurent Bigonville <bigon@debian.org>
|
||||
License: GPL-2
|
||||
|
||||
License: GPL-2
|
||||
This package is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2,
|
||||
as published by the Free Software Foundation.
|
||||
.
|
||||
This package is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this package; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
.
|
||||
On Debian systems, the complete text of the GNU General
|
||||
Public License can be found in `/usr/share/common-licenses/GPL-1'.
|
383
syft/cataloger/deb/test-fixtures/copyright/liblzma5
Normal file
383
syft/cataloger/deb/test-fixtures/copyright/liblzma5
Normal file
|
@ -0,0 +1,383 @@
|
|||
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: XZ Utils
|
||||
Upstream-Contact:
|
||||
Lasse Collin <lasse.collin@tukaani.org>
|
||||
http://tukaani.org/xz/lists.html
|
||||
Source:
|
||||
http://tukaani.org/xz
|
||||
http://git.tukaani.org/xz.git
|
||||
Comment:
|
||||
XZ Utils is developed and maintained upstream by Lasse Collin. Major
|
||||
portions are based on code by other authors; see AUTHORS for details.
|
||||
Most of the source has been put into the public domain, but some files
|
||||
have not (details below).
|
||||
.
|
||||
This file describes the source package. The binary packages contain
|
||||
some files derived from other works: for example, images in the API
|
||||
documentation come from Doxygen.
|
||||
License:
|
||||
Different licenses apply to different files in this package. Here
|
||||
is a rough summary of which licenses apply to which parts of this
|
||||
package (but check the individual files to be sure!):
|
||||
.
|
||||
- liblzma is in the public domain.
|
||||
.
|
||||
- xz, xzdec, and lzmadec command line tools are in the public
|
||||
domain unless GNU getopt_long had to be compiled and linked
|
||||
in from the lib directory. The getopt_long code is under
|
||||
GNU LGPLv2.1+.
|
||||
.
|
||||
- The scripts to grep, diff, and view compressed files have been
|
||||
adapted from gzip. These scripts and their documentation are
|
||||
under GNU GPLv2+.
|
||||
.
|
||||
- All the documentation in the doc directory and most of the
|
||||
XZ Utils specific documentation files in other directories
|
||||
are in the public domain.
|
||||
.
|
||||
- Translated messages are in the public domain.
|
||||
.
|
||||
- The build system contains public domain files, and files that
|
||||
are under GNU GPLv2+ or GNU GPLv3+. None of these files end up
|
||||
in the binaries being built.
|
||||
.
|
||||
- Test files and test code in the tests directory, and debugging
|
||||
utilities in the debug directory are in the public domain.
|
||||
.
|
||||
- The extra directory may contain public domain files, and files
|
||||
that are under various free software licenses.
|
||||
.
|
||||
You can do whatever you want with the files that have been put into
|
||||
the public domain. If you find public domain legally problematic,
|
||||
take the previous sentence as a license grant. If you still find
|
||||
the lack of copyright legally problematic, you have too many
|
||||
lawyers.
|
||||
.
|
||||
As usual, this software is provided "as is", without any warranty.
|
||||
.
|
||||
If you copy significant amounts of public domain code from XZ Utils
|
||||
into your project, acknowledging this somewhere in your software is
|
||||
polite (especially if it is proprietary, non-free software), but
|
||||
naturally it is not legally required. Here is an example of a good
|
||||
notice to put into "about box" or into documentation:
|
||||
.
|
||||
This software includes code from XZ Utils <http://tukaani.org/xz/>.
|
||||
.
|
||||
The following license texts are included in the following files:
|
||||
- COPYING.LGPLv2.1: GNU Lesser General Public License version 2.1
|
||||
- COPYING.GPLv2: GNU General Public License version 2
|
||||
- COPYING.GPLv3: GNU General Public License version 3
|
||||
.
|
||||
Note that the toolchain (compiler, linker etc.) may add some code
|
||||
pieces that are copyrighted. Thus, it is possible that e.g. liblzma
|
||||
binary wouldn't actually be in the public domain in its entirety
|
||||
even though it contains no copyrighted code from the XZ Utils source
|
||||
package.
|
||||
.
|
||||
If you have questions, don't hesitate to ask the author(s) for more
|
||||
information.
|
||||
|
||||
Files: *
|
||||
Copyright: 2006-2012, Lasse Collin
|
||||
1999-2008, Igor Pavlov
|
||||
2006, Ville Koskinen
|
||||
1998, Steve Reid
|
||||
2000, Wei Dai
|
||||
2003, Kevin Springle
|
||||
2009, Jonathan Nieder
|
||||
2010, Anders F Björklund
|
||||
License: PD
|
||||
This file has been put in the public domain.
|
||||
You can do whatever you want with this file.
|
||||
Comment:
|
||||
From: Lasse Collin <lasse.collin@tukaani.org>
|
||||
To: Jonathan Nieder <jrnieder@gmail.com>
|
||||
Subject: Re: XZ utils for Debian
|
||||
Date: Sun, 19 Jul 2009 13:28:23 +0300
|
||||
Message-Id: <200907191328.23816.lasse.collin@tukaani.org>
|
||||
.
|
||||
[...]
|
||||
.
|
||||
> AUTHORS, ChangeLog, COPYING, README, THANKS, TODO,
|
||||
> dos/README, windows/README
|
||||
.
|
||||
COPYING says that most docs are in the public domain. Maybe that's not
|
||||
clear enough, but on the other hand it looks a bit stupid to put
|
||||
copyright information in tiny and relatively small docs like README.
|
||||
.
|
||||
I don't dare to say that _all_ XZ Utils specific docs are in the public
|
||||
domain unless otherwise mentioned in the file. I'm including PDF files
|
||||
generated by groff + ps2pdf, and some day I might include Doxygen-
|
||||
generated HTML docs too. Those don't include any copyright notices, but
|
||||
it seems likely that groff + ps2pdf or at least Doxygen put some
|
||||
copyrighted content into the generated files.
|
||||
|
||||
Files: INSTALL NEWS PACKAGERS
|
||||
windows/README-Windows.txt
|
||||
windows/INSTALL-Windows.txt
|
||||
Copyright: 2009-2010, Lasse Collin
|
||||
License: probably-PD
|
||||
See the note on AUTHORS, README, and so on above.
|
||||
|
||||
Files: src/scripts/* lib/* extra/scanlzma/scanlzma.c
|
||||
Copyright: © 1993, Jean-loup Gailly
|
||||
© 1989-1994, 1996-1999, 2001-2007, Free Software Foundation, Inc.
|
||||
© 2006 Timo Lindfors
|
||||
2005, Charles Levert
|
||||
2005, 2009, Lasse Collin
|
||||
2009, Andrew Dudman
|
||||
Other-Authors: Paul Eggert, Ulrich Drepper
|
||||
License: GPL-2+
|
||||
|
||||
Files: src/scripts/Makefile.am src/scripts/xzless.1
|
||||
Copyright: 2009, Andrew Dudman
|
||||
2009, Lasse Collin
|
||||
License: PD
|
||||
This file has been put in the public domain.
|
||||
You can do whatever you want with this file.
|
||||
|
||||
Files: doc/examples/xz_pipe_comp.c doc/examples/xz_pipe_decomp.c
|
||||
Copyright: 2010, Daniel Mealha Cabrita
|
||||
License: PD
|
||||
Not copyrighted -- provided to the public domain.
|
||||
|
||||
Files: lib/getopt.c lib/getopt1.c lib/getopt.in.h
|
||||
Copyright: © 1987-2007 Free Software Foundation, Inc.
|
||||
Other-Authors: Ulrich Drepper
|
||||
License: LGPL-2.1+
|
||||
|
||||
Files: m4/getopt.m4 m4/posix-shell.m4
|
||||
Copyright: © 2002-2006, 2008 Free Software Foundation, Inc.
|
||||
© 2007-2008 Free Software Foundation, Inc.
|
||||
Other-Authors: Bruno Haible, Paul Eggert
|
||||
License: permissive-fsf
|
||||
|
||||
Files: m4/acx_pthread.m4
|
||||
Copyright: © 2008, Steven G. Johnson <stevenj@alum.mit.edu>
|
||||
License: Autoconf
|
||||
|
||||
Files: Doxyfile.in
|
||||
Copyright: © 1997-2007 by Dimitri van Heesch
|
||||
Origin: Doxygen 1.4.7
|
||||
License: GPL-2
|
||||
|
||||
Files: src/liblzma/check/crc32_table_?e.h
|
||||
src/liblzma/check/crc64_table_?e.h
|
||||
src/liblzma/lzma/fastpos_table.c
|
||||
src/liblzma/rangecoder/price_table.c
|
||||
Copyright: none, automatically generated data
|
||||
Generated-With:
|
||||
src/liblzma/check/crc32_tablegen.c
|
||||
src/liblzma/check/crc64_tablegen.c
|
||||
src/liblzma/lzma/fastpos_tablegen.c
|
||||
src/liblzma/rangecoder/price_tablegen.c
|
||||
License: none
|
||||
No copyright to license.
|
||||
|
||||
Files: .gitignore m4/.gitignore po/.gitignore po/LINGUAS po/POTFILES.in
|
||||
Copyright: none; these are just short lists.
|
||||
License: none
|
||||
No copyright to license.
|
||||
|
||||
Files: tests/compress_prepared_bcj_*
|
||||
Copyright: 2008-2009, Lasse Collin
|
||||
Source-Code: tests/bcj_test.c
|
||||
License: PD
|
||||
This file has been put into the public domain.
|
||||
You can do whatever you want with this file.
|
||||
Comment:
|
||||
changelog.gz (commit 975d8fd) explains:
|
||||
.
|
||||
Recreated the BCJ test files for x86 and SPARC. The old files
|
||||
were linked with crt*.o, which are copyrighted, and thus the
|
||||
old test files were not in the public domain as a whole. They
|
||||
are freely distributable though, but it is better to be careful
|
||||
and avoid including any copyrighted pieces in the test files.
|
||||
The new files are just compiled and assembled object files,
|
||||
and thus don't contain any copyrighted code.
|
||||
|
||||
Files: po/cs.po po/de.po po/fr.po
|
||||
Copyright: 2010, Marek Černocký
|
||||
2010, Andre Noll
|
||||
2011, Adrien Nader
|
||||
License: PD
|
||||
This file is put in the public domain.
|
||||
|
||||
Files: po/it.po po/pl.po
|
||||
Copyright: 2009, 2010, Gruppo traduzione italiano di Ubuntu-it
|
||||
2010, Lorenzo De Liso
|
||||
2009, 2010, 2011, Milo Casagrande
|
||||
2011, Jakub Bogusz
|
||||
License: PD
|
||||
This file is in the public domain
|
||||
|
||||
Files: INSTALL.generic
|
||||
Copyright: © 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
|
||||
2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
|
||||
License: permissive-nowarranty
|
||||
|
||||
Files: dos/config.h
|
||||
Copyright: © 1992, 1993, 1994, 1999, 2000, 2001, 2002, 2005
|
||||
Free Software Foundation, Inc.
|
||||
2007-2010, Lasse Collin
|
||||
Other-Authors: Roland McGrath, Akim Demaille, Paul Eggert,
|
||||
David Mackenzie, Bruno Haible, and many others.
|
||||
Origin: configure.ac from XZ Utils,
|
||||
visibility.m4 serial 1 (gettext-0.15),
|
||||
Autoconf 2.52g
|
||||
License: config-h
|
||||
configure.ac:
|
||||
.
|
||||
# Author: Lasse Collin
|
||||
#
|
||||
# This file has been put into the public domain.
|
||||
# You can do whatever you want with this file.
|
||||
.
|
||||
visibility.m4:
|
||||
.
|
||||
dnl Copyright (C) 2005 Free Software Foundation, Inc.
|
||||
dnl This file is free software; the Free Software Foundation
|
||||
dnl gives unlimited permission to copy and/or distribute it,
|
||||
dnl with or without modifications, as long as this notice is preserved.
|
||||
.
|
||||
dnl From Bruno Haible.
|
||||
.
|
||||
comments from Autoconf 2.52g:
|
||||
.
|
||||
# Copyright 1992, 1993, 1994, 1999, 2000, 2001, 2002
|
||||
# Free Software Foundation, Inc.
|
||||
.
|
||||
[...]
|
||||
.
|
||||
# As a special exception, the Free Software Foundation gives unlimited
|
||||
# permission to copy, distribute and modify the configure scripts that
|
||||
# are the output of Autoconf. You need not follow the terms of the GNU
|
||||
# General Public License when using or distributing such scripts, even
|
||||
# though portions of the text of Autoconf appear in them. The GNU
|
||||
# General Public License (GPL) does govern all other use of the material
|
||||
# that constitutes the Autoconf program.
|
||||
.
|
||||
On Debian systems, the complete text of the GNU General Public
|
||||
License version 2 can be found in ‘/usr/share/common-licenses/GPL-2’.
|
||||
dos/config.h was generated with autoheader, which tells Autoconf to
|
||||
output a script to generate a config.h file and then runs it.
|
||||
|
||||
Files: po/Makevars
|
||||
Origin: gettext-runtime/po/Makevars (gettext-0.12)
|
||||
Copyright: © 2003 Free Software Foundation, Inc.
|
||||
Authors: Bruno Haible
|
||||
License: LGPL-2.1+
|
||||
The gettext-runtime package is under the LGPL, see files intl/COPYING.LIB-2.0
|
||||
and intl/COPYING.LIB-2.1.
|
||||
.
|
||||
On Debian systems, the complete text of intl/COPYING.LIB-2.0 from
|
||||
gettext-runtime 0.12 can be found in ‘/usr/share/common-licenses/LGPL-2’
|
||||
and the text of intl/COPYING.LIB-2.1 can be found in
|
||||
‘/usr/share/common-licenses/LGPL-2.1’.
|
||||
.
|
||||
po/Makevars consists mostly of helpful comments and does not contain a
|
||||
copyright and license notice.
|
||||
|
||||
Files: COPYING.GPLv2 COPYING.GPLv3 COPYING.LGPLv2.1
|
||||
Copyright: © 1989, 1991, 1999, 2007 Free Software Foundation, Inc.
|
||||
License: noderivs
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Files: debian/*
|
||||
Copyright: 2009-2012, Jonathan Nieder
|
||||
License: PD-debian
|
||||
The Debian packaging files are in the public domain.
|
||||
You may freely use, modify, distribute, and relicense them.
|
||||
|
||||
License: LGPL-2.1+
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1, or (at your option)
|
||||
any later version.
|
||||
.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
.
|
||||
You should have received a copy of the GNU Lesser General Public License along
|
||||
with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
.
|
||||
On Debian systems, the complete text of the GNU Lesser General Public
|
||||
License version 2.1 can be found in ‘/usr/share/common-licenses/LGPL-2.1’.
|
||||
|
||||
License: GPL-2
|
||||
Permission to use, copy, modify, and distribute this software and its
|
||||
documentation under the terms of the GNU General Public License is
|
||||
hereby granted. No representations are made about the suitability of
|
||||
this software for any purpose. It is provided "as is" without express
|
||||
or implied warranty. See the GNU General Public License for more
|
||||
details.
|
||||
.
|
||||
Documents produced by doxygen are derivative works derived from the
|
||||
input used in their production; they are not affected by this license.
|
||||
.
|
||||
On Debian systems, the complete text of the version of the GNU General
|
||||
Public License distributed with Doxygen can be found in
|
||||
‘/usr/share/common-licenses/GPL-2’.
|
||||
|
||||
License: GPL-2+
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
.
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
.
|
||||
On Debian systems, the complete text of the GNU General Public License
|
||||
version 2 can be found in ‘/usr/share/common-licenses/GPL-2’.
|
||||
|
||||
License: Autoconf
|
||||
This program is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation, either version 3 of the License, or (at your
|
||||
option) any later version.
|
||||
.
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
Public License for more details.
|
||||
.
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
.
|
||||
As a special exception, the respective Autoconf Macro's copyright owner
|
||||
gives unlimited permission to copy, distribute and modify the configure
|
||||
scripts that are the output of Autoconf when processing the Macro. You
|
||||
need not follow the terms of the GNU General Public License when using
|
||||
or distributing such scripts, even though portions of the text of the
|
||||
Macro appear in them. The GNU General Public License (GPL) does govern
|
||||
all other use of the material that constitutes the Autoconf Macro.
|
||||
.
|
||||
This special exception to the GPL applies to versions of the Autoconf
|
||||
Macro released by the Autoconf Archive. When you make and distribute a
|
||||
modified version of the Autoconf Macro, you may extend this special
|
||||
exception to the GPL to apply to your modified version as well.
|
||||
.
|
||||
On Debian systems, the complete text of the GNU General Public
|
||||
License version 3 can be found in ‘/usr/share/common-licenses/GPL-3’.
|
||||
|
||||
License: permissive-fsf
|
||||
This file is free software; the Free Software Foundation
|
||||
gives unlimited permission to copy and/or distribute it,
|
||||
with or without modifications, as long as this notice is preserved.
|
||||
|
||||
License: permissive-nowarranty
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved. This file is offered as-is,
|
||||
without warranty of any kind.
|
13
syft/cataloger/deb/test-fixtures/copyright/trilicense
Normal file
13
syft/cataloger/deb/test-fixtures/copyright/trilicense
Normal file
|
@ -0,0 +1,13 @@
|
|||
Files: src/js/editline/*
|
||||
Copyright: 1993, John Doe
|
||||
1993, Joe Average
|
||||
License: MPL-1.1 or GPL-2 or LGPL-2.1
|
||||
|
||||
License: MPL-1.1
|
||||
[LICENSE TEXT]
|
||||
|
||||
License: GPL-2
|
||||
[LICENSE TEXT]
|
||||
|
||||
License: LGPL-2.1
|
||||
[LICENSE TEXT]
|
2
syft/cataloger/deb/test-fixtures/image-dpkg/Dockerfile
Normal file
2
syft/cataloger/deb/test-fixtures/image-dpkg/Dockerfile
Normal file
|
@ -0,0 +1,2 @@
|
|||
FROM scratch
|
||||
COPY . .
|
|
@ -0,0 +1,43 @@
|
|||
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: auditd
|
||||
Source: https://people.redhat.com/sgrubb/audit/
|
||||
|
||||
Files: *
|
||||
Copyright: 2012-2016 Steve Grubb <sgrubb@redhat.com>
|
||||
2006-2012 Rik Faith
|
||||
License: GPL-2
|
||||
|
||||
Files: src/libev/*
|
||||
Copyright: 2007-2009 Marc Alexamder Lehmann
|
||||
License: GPL-2
|
||||
|
||||
Files: lib/*
|
||||
Copyright: 2005-2008 Steve Grubb <sgrubb@redhat.com>
|
||||
License: LGPL-2.1
|
||||
The audit daemon's library libaudit.* is released under LGPL
|
||||
so that it may be linked with 3rd party software.
|
||||
.
|
||||
On Debian systems, refer to /usr/share/common-licenses/LGPL-2.1
|
||||
for the complete text of the GNU Lesser General Public License.
|
||||
|
||||
Files: debian/*
|
||||
Copyright: 2007-2011 Philipp Matthias Hahn <pmhahn@debian.org>
|
||||
2012-2016 Laurent Bigonville <bigon@debian.org>
|
||||
License: GPL-2
|
||||
|
||||
License: GPL-2
|
||||
This package is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2,
|
||||
as published by the Free Software Foundation.
|
||||
.
|
||||
This package is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this package; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
.
|
||||
On Debian systems, the complete text of the GNU General
|
||||
Public License can be found in `/usr/share/common-licenses/GPL-1'.
|
|
@ -0,0 +1,4 @@
|
|||
55f905631797551d4d936a34c7e73474 lib/x86_64-linux-gnu/libz.so.1.2.11
|
||||
cede84bda30d2380217f97753c8ccf3a usr/share/doc/zlib1g/changelog.Debian.gz
|
||||
f3c9dafa6da7992c47328b4464f6d122 usr/share/doc/zlib1g/changelog.gz
|
||||
a4fae96070439a5209a62ae5b8017ab2 usr/share/doc/zlib1g/copyright
|
|
@ -0,0 +1,21 @@
|
|||
Package: libpam-runtime
|
||||
Status: install ok installed
|
||||
Priority: required
|
||||
Section: admin
|
||||
Installed-Size: 1016
|
||||
Maintainer: Steve Langasek <vorlon@debian.org>
|
||||
Architecture: all
|
||||
Multi-Arch: foreign
|
||||
Source: pam
|
||||
Version: 1.1.8-3.6
|
||||
Replaces: libpam0g-dev, libpam0g-util
|
||||
Depends: debconf (>= 0.5) | debconf-2.0, debconf (>= 1.5.19) | cdebconf, libpam-modules (>= 1.0.1-6)
|
||||
Conflicts: libpam0g-util
|
||||
Conffiles:
|
||||
/etc/pam.conf 87fc76f18e98ee7d3848f6b81b3391e5
|
||||
/etc/pam.d/other 31aa7f2181889ffb00b87df4126d1701
|
||||
Description: Runtime support for the PAM library
|
||||
Contains configuration files and directories required for
|
||||
authentication to work on Debian systems. This package is required
|
||||
on almost all installations.
|
||||
Homepage: http://www.linux-pam.org/
|
4
syft/cataloger/deb/test-fixtures/info/zlib1g.md5sums
Normal file
4
syft/cataloger/deb/test-fixtures/info/zlib1g.md5sums
Normal file
|
@ -0,0 +1,4 @@
|
|||
55f905631797551d4d936a34c7e73474 lib/x86_64-linux-gnu/libz.so.1.2.11
|
||||
cede84bda30d2380217f97753c8ccf3a usr/share/doc/zlib1g/changelog.Debian.gz
|
||||
f3c9dafa6da7992c47328b4464f6d122 usr/share/doc/zlib1g/changelog.gz
|
||||
a4fae96070439a5209a62ae5b8017ab2 usr/share/doc/zlib1g/copyright
|
|
@ -8,11 +8,18 @@ import (
|
|||
// DpkgMetadata 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.
|
||||
type DpkgMetadata struct {
|
||||
Package string `mapstructure:"Package" json:"package"`
|
||||
Source string `mapstructure:"Source" json:"source"`
|
||||
Version string `mapstructure:"Version" json:"version"`
|
||||
Architecture string `mapstructure:"Architecture" json:"architecture"`
|
||||
// TODO: consider keeping the remaining values as an embedded map
|
||||
Package string `mapstructure:"Package" json:"package"`
|
||||
Source string `mapstructure:"Source" json:"source"`
|
||||
Version string `mapstructure:"Version" json:"version"`
|
||||
Architecture string `mapstructure:"Architecture" json:"architecture"`
|
||||
Maintainer string `mapstructure:"Maintainer" json:"maintainer"`
|
||||
InstalledSize int `mapstructure:"InstalledSize" json:"installedSize"`
|
||||
Files []DpkgFileRecord `json:"files"`
|
||||
}
|
||||
|
||||
type DpkgFileRecord struct {
|
||||
Path string `json:"path"`
|
||||
MD5 string `json:"md5"`
|
||||
}
|
||||
|
||||
func (m DpkgMetadata) PackageURL(d distro.Distro) string {
|
||||
|
|
|
@ -11,6 +11,7 @@ type Artifact struct {
|
|||
Type string `json:"type"`
|
||||
FoundBy []string `json:"foundBy"`
|
||||
Locations Locations `json:"locations,omitempty"`
|
||||
Licenses []string `json:"licenses"`
|
||||
Metadata interface{} `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
|
@ -26,6 +27,7 @@ func NewArtifact(p *pkg.Package, s scope.Scope) (Artifact, error) {
|
|||
Type: string(p.Type),
|
||||
FoundBy: []string{p.FoundBy},
|
||||
Locations: locations,
|
||||
Licenses: p.Licenses,
|
||||
Metadata: p.Metadata,
|
||||
}, nil
|
||||
}
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
],
|
||||
"locations": [
|
||||
"/some/path/pkg1"
|
||||
]
|
||||
],
|
||||
"licenses": null
|
||||
},
|
||||
{
|
||||
"name": "package-2",
|
||||
|
@ -20,7 +21,8 @@
|
|||
],
|
||||
"locations": [
|
||||
"/some/path/pkg1"
|
||||
]
|
||||
],
|
||||
"licenses": null
|
||||
}
|
||||
],
|
||||
"source": {
|
||||
|
|
|
@ -12,7 +12,8 @@
|
|||
"path": "/somefile-1.txt",
|
||||
"layerIndex": 0
|
||||
}
|
||||
]
|
||||
],
|
||||
"licenses": null
|
||||
},
|
||||
{
|
||||
"name": "package-2",
|
||||
|
@ -26,7 +27,8 @@
|
|||
"path": "/somefile-2.txt",
|
||||
"layerIndex": 1
|
||||
}
|
||||
]
|
||||
],
|
||||
"licenses": null
|
||||
}
|
||||
],
|
||||
"source": {
|
||||
|
|
Loading…
Reference in a new issue