enhance dpkg support by parsing md5sum and copyright file sources

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
This commit is contained in:
Alex Goodman 2020-11-09 15:33:24 -05:00
parent b6eb589b78
commit 2a329002b8
No known key found for this signature in database
GPG key ID: 5CB45AE22BAB7EA7
23 changed files with 1136 additions and 95 deletions

View file

@ -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",

View file

@ -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
}

View 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)
}
})
}
}

View 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
}

View 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)
}
})
}
}

View 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
}

View 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)
}
})
}
}

View file

@ -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)
}

View file

@ -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)
}

View 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'.

View 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.

View 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]

View file

@ -0,0 +1,2 @@
FROM scratch
COPY . .

View 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'.

View 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

View file

@ -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/

View 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

View file

@ -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 {

View file

@ -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
}

View file

@ -9,7 +9,8 @@
],
"locations": [
"/some/path/pkg1"
]
],
"licenses": null
},
{
"name": "package-2",
@ -20,7 +21,8 @@
],
"locations": [
"/some/path/pkg1"
]
],
"licenses": null
}
],
"source": {

View file

@ -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": {