Merge pull request #272 from jzelinskie/alpine
[WIP] Alpine support via Alpine-SecDB
This commit is contained in:
commit
d62bddd6e3
@ -17,10 +17,10 @@ FROM golang:1.6
|
||||
MAINTAINER Quentin Machu <quentin.machu@coreos.com>
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y bzr rpm xz-utils && \
|
||||
apt-get install -y git bzr rpm xz-utils && \
|
||||
apt-get autoremove -y && \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* # 18MAR2016
|
||||
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* # 29NOV2016
|
||||
|
||||
VOLUME /config
|
||||
|
||||
|
@ -161,6 +161,7 @@ By indexing the features of an image into the database, images only need to be r
|
||||
| [Debian Security Bug Tracker] | Debian 6, 7, 8, unstable namespaces | [dpkg] | [Debian] |
|
||||
| [Ubuntu CVE Tracker] | Ubuntu 12.04, 12.10, 13.04, 14.04, 14.10, 15.04, 15.10, 16.04 namespaces | [dpkg] | [GPLv2] |
|
||||
| [Red Hat Security Data] | CentOS 5, 6, 7 namespaces | [rpm] | [CVRF] |
|
||||
| [Alpine SecDB] | Alpine 3.3, Alpine 3.4 namespaces | [apk] | [MIT] |
|
||||
| [NVD] | Generic Vulnerability Metadata | N/A | [Public Domain] |
|
||||
|
||||
[Debian Security Bug Tracker]: https://security-tracker.debian.org/tracker
|
||||
@ -173,6 +174,9 @@ By indexing the features of an image into the database, images only need to be r
|
||||
[GPLv2]: https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html
|
||||
[CVRF]: http://www.icasi.org/cvrf-licensing/
|
||||
[Public Domain]: https://nvd.nist.gov/faq
|
||||
[Alpine SecDB]: http://git.alpinelinux.org/cgit/alpine-secdb/
|
||||
[apk]: http://git.alpinelinux.org/cgit/apk-tools/
|
||||
[MIT]: https://gist.github.com/jzelinskie/6da1e2da728424d88518be2adbd76979
|
||||
|
||||
|
||||
### Customization
|
||||
|
@ -28,6 +28,7 @@ import (
|
||||
// Register components
|
||||
_ "github.com/coreos/clair/notifier/notifiers"
|
||||
|
||||
_ "github.com/coreos/clair/updater/fetchers/alpine"
|
||||
_ "github.com/coreos/clair/updater/fetchers/debian"
|
||||
_ "github.com/coreos/clair/updater/fetchers/opensuse"
|
||||
_ "github.com/coreos/clair/updater/fetchers/rhel"
|
||||
@ -38,9 +39,11 @@ import (
|
||||
_ "github.com/coreos/clair/worker/detectors/data/aci"
|
||||
_ "github.com/coreos/clair/worker/detectors/data/docker"
|
||||
|
||||
_ "github.com/coreos/clair/worker/detectors/feature/apk"
|
||||
_ "github.com/coreos/clair/worker/detectors/feature/dpkg"
|
||||
_ "github.com/coreos/clair/worker/detectors/feature/rpm"
|
||||
|
||||
_ "github.com/coreos/clair/worker/detectors/namespace/alpinerelease"
|
||||
_ "github.com/coreos/clair/worker/detectors/namespace/aptsources"
|
||||
_ "github.com/coreos/clair/worker/detectors/namespace/lsbrelease"
|
||||
_ "github.com/coreos/clair/worker/detectors/namespace/osrelease"
|
||||
|
299
updater/fetchers/alpine/alpine.go
Normal file
299
updater/fetchers/alpine/alpine.go
Normal file
@ -0,0 +1,299 @@
|
||||
// Copyright 2016 clair authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package alpine implements a vulnerability Fetcher using the alpine-secdb
|
||||
// git repository.
|
||||
package alpine
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/coreos/pkg/capnslog"
|
||||
|
||||
"github.com/coreos/clair/database"
|
||||
"github.com/coreos/clair/updater"
|
||||
"github.com/coreos/clair/utils"
|
||||
cerrors "github.com/coreos/clair/utils/errors"
|
||||
"github.com/coreos/clair/utils/types"
|
||||
)
|
||||
|
||||
const (
|
||||
// When available, this should be updated to use HTTPS.
|
||||
secdbGitURL = "http://git.alpinelinux.org/cgit/alpine-secdb"
|
||||
updaterFlag = "alpine-secdbUpdater"
|
||||
nvdURLPrefix = "https://cve.mitre.org/cgi-bin/cvename.cgi?name="
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrFilesystem is returned when a fetcher fails to interact with the local filesystem.
|
||||
ErrFilesystem = errors.New("updater/fetchers: something went wrong when interacting with the fs")
|
||||
|
||||
// ErrGitFailure is returned when a fetcher fails to interact with git.
|
||||
ErrGitFailure = errors.New("updater/fetchers: something went wrong when interacting with git")
|
||||
|
||||
log = capnslog.NewPackageLogger("github.com/coreos/clair", "updater/fetchers/alpine")
|
||||
)
|
||||
|
||||
func init() {
|
||||
updater.RegisterFetcher("alpine", &fetcher{})
|
||||
}
|
||||
|
||||
type fetcher struct {
|
||||
repositoryLocalPath string
|
||||
}
|
||||
|
||||
func (f *fetcher) FetchUpdate(db database.Datastore) (resp updater.FetcherResponse, err error) {
|
||||
log.Info("fetching Alpine vulnerabilities")
|
||||
|
||||
// Pull the master branch.
|
||||
var commit string
|
||||
commit, err = f.pullRepository()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Ask the database for the latest commit we successfully applied.
|
||||
var dbCommit string
|
||||
dbCommit, err = db.GetKeyValue(updaterFlag)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Set the updaterFlag to equal the commit processed.
|
||||
resp.FlagName = updaterFlag
|
||||
resp.FlagValue = commit
|
||||
|
||||
// Short-circuit if there have been no updates.
|
||||
if commit == dbCommit {
|
||||
log.Debug("no alpine update")
|
||||
return
|
||||
}
|
||||
|
||||
var namespaces []string
|
||||
namespaces, err = detectNamespaces(f.repositoryLocalPath)
|
||||
// Append any changed vulnerabilities to the response.
|
||||
for _, namespace := range namespaces {
|
||||
var vulns []database.Vulnerability
|
||||
var note string
|
||||
vulns, note, err = parseVulnsFromNamespace(f.repositoryLocalPath, namespace)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if note != "" {
|
||||
resp.Notes = append(resp.Notes, note)
|
||||
}
|
||||
resp.Vulnerabilities = append(resp.Vulnerabilities, vulns...)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func detectNamespaces(path string) ([]string, error) {
|
||||
// Open the root directory.
|
||||
dir, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer dir.Close()
|
||||
|
||||
// Get a list of the namspaces from the directory names.
|
||||
names, err := dir.Readdirnames(0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var namespaces []string
|
||||
for _, name := range names {
|
||||
// Filter out hidden directories like `.git`.
|
||||
if strings.HasPrefix(name, ".") {
|
||||
continue
|
||||
}
|
||||
|
||||
namespaces = append(namespaces, name)
|
||||
}
|
||||
|
||||
return namespaces, nil
|
||||
}
|
||||
|
||||
type parserFunc func(io.Reader) ([]database.Vulnerability, error)
|
||||
|
||||
var parsers = map[string]parserFunc{
|
||||
"v3.3": parse33YAML,
|
||||
"v3.4": parse34YAML,
|
||||
}
|
||||
|
||||
func parseVulnsFromNamespace(repositoryPath, namespace string) (vulns []database.Vulnerability, note string, err error) {
|
||||
var file io.ReadCloser
|
||||
file, err = os.Open(repositoryPath + "/" + namespace + "/main.yaml")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
parseFunc, exists := parsers[namespace]
|
||||
if !exists {
|
||||
note = fmt.Sprintf("The file %s is not mapped to any Alpine version number", namespace)
|
||||
return
|
||||
}
|
||||
|
||||
vulns, err = parseFunc(file)
|
||||
return
|
||||
}
|
||||
|
||||
func (f *fetcher) pullRepository() (commit string, err error) {
|
||||
// If the repository doesn't exist, clone it.
|
||||
if _, pathExists := os.Stat(f.repositoryLocalPath); f.repositoryLocalPath == "" || os.IsNotExist(pathExists) {
|
||||
if f.repositoryLocalPath, err = ioutil.TempDir(os.TempDir(), "alpine-secdb"); err != nil {
|
||||
return "", ErrFilesystem
|
||||
}
|
||||
|
||||
if out, err := utils.Exec(f.repositoryLocalPath, "git", "clone", secdbGitURL, "."); err != nil {
|
||||
f.Clean()
|
||||
log.Errorf("could not pull alpine-secdb repository: %s. output: %s", err, out)
|
||||
return "", cerrors.ErrCouldNotDownload
|
||||
}
|
||||
} else {
|
||||
// The repository exists and it needs to be refreshed via a pull.
|
||||
_, err := utils.Exec(f.repositoryLocalPath, "git", "pull")
|
||||
if err != nil {
|
||||
return "", ErrGitFailure
|
||||
}
|
||||
}
|
||||
|
||||
out, err := utils.Exec(f.repositoryLocalPath, "git", "rev-parse", "HEAD")
|
||||
if err != nil {
|
||||
return "", ErrGitFailure
|
||||
}
|
||||
|
||||
commit = strings.TrimSpace(string(out))
|
||||
return
|
||||
}
|
||||
|
||||
func (f *fetcher) Clean() {
|
||||
if f.repositoryLocalPath != "" {
|
||||
os.RemoveAll(f.repositoryLocalPath)
|
||||
}
|
||||
}
|
||||
|
||||
type secdb33File struct {
|
||||
Distro string `yaml:"distroversion"`
|
||||
Packages []struct {
|
||||
Pkg struct {
|
||||
Name string `yaml:"name"`
|
||||
Version string `yaml:"ver"`
|
||||
Fixes []string `yaml:"fixes"`
|
||||
} `yaml:"pkg"`
|
||||
} `yaml:"packages"`
|
||||
}
|
||||
|
||||
func parse33YAML(r io.Reader) (vulns []database.Vulnerability, err error) {
|
||||
var rBytes []byte
|
||||
rBytes, err = ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var file secdb33File
|
||||
err = yaml.Unmarshal(rBytes, &file)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, pack := range file.Packages {
|
||||
pkg := pack.Pkg
|
||||
for _, fix := range pkg.Fixes {
|
||||
version, err := types.NewVersion(pkg.Version)
|
||||
if err != nil {
|
||||
log.Warningf("could not parse package version '%s': %s. skipping", pkg.Version, err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
vulns = append(vulns, database.Vulnerability{
|
||||
Name: fix,
|
||||
Severity: types.Unknown,
|
||||
Link: nvdURLPrefix + fix,
|
||||
FixedIn: []database.FeatureVersion{
|
||||
{
|
||||
Feature: database.Feature{
|
||||
Namespace: database.Namespace{Name: "alpine:" + file.Distro},
|
||||
Name: pkg.Name,
|
||||
},
|
||||
Version: version,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type secdb34File struct {
|
||||
Distro string `yaml:"distroversion"`
|
||||
Packages []struct {
|
||||
Pkg struct {
|
||||
Name string `yaml:"name"`
|
||||
Fixes map[string][]string `yaml:"secfixes"`
|
||||
} `yaml:"pkg"`
|
||||
} `yaml:"packages"`
|
||||
}
|
||||
|
||||
func parse34YAML(r io.Reader) (vulns []database.Vulnerability, err error) {
|
||||
var rBytes []byte
|
||||
rBytes, err = ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var file secdb34File
|
||||
err = yaml.Unmarshal(rBytes, &file)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, pack := range file.Packages {
|
||||
pkg := pack.Pkg
|
||||
for versionStr, vulnStrs := range pkg.Fixes {
|
||||
version, err := types.NewVersion(versionStr)
|
||||
if err != nil {
|
||||
log.Warningf("could not parse package version '%s': %s. skipping", versionStr, err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
for _, vulnStr := range vulnStrs {
|
||||
var vuln database.Vulnerability
|
||||
vuln.Severity = types.Unknown
|
||||
vuln.Name = vulnStr
|
||||
vuln.Link = nvdURLPrefix + vulnStr
|
||||
vuln.FixedIn = []database.FeatureVersion{
|
||||
{
|
||||
Feature: database.Feature{
|
||||
Namespace: database.Namespace{Name: "alpine:" + file.Distro},
|
||||
Name: pkg.Name,
|
||||
},
|
||||
Version: version,
|
||||
},
|
||||
}
|
||||
vulns = append(vulns, vuln)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
60
updater/fetchers/alpine/alpine_test.go
Normal file
60
updater/fetchers/alpine/alpine_test.go
Normal file
@ -0,0 +1,60 @@
|
||||
// Copyright 2016 clair authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package alpine
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAlpine33YAMLParsing(t *testing.T) {
|
||||
_, filename, _, _ := runtime.Caller(0)
|
||||
path := filepath.Join(filepath.Dir(filename))
|
||||
|
||||
testData, _ := os.Open(path + "/testdata/v33_main.yaml")
|
||||
defer testData.Close()
|
||||
|
||||
vulns, err := parse33YAML(testData)
|
||||
if err != nil {
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
assert.Equal(t, 15, len(vulns))
|
||||
assert.Equal(t, "CVE-2016-2147", vulns[0].Name)
|
||||
assert.Equal(t, "alpine:v3.3", vulns[0].FixedIn[0].Feature.Namespace.Name)
|
||||
assert.Equal(t, "busybox", vulns[0].FixedIn[0].Feature.Name)
|
||||
assert.Equal(t, "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-2147", vulns[0].Link)
|
||||
}
|
||||
|
||||
func TestAlpine34YAMLParsing(t *testing.T) {
|
||||
_, filename, _, _ := runtime.Caller(0)
|
||||
path := filepath.Join(filepath.Dir(filename))
|
||||
|
||||
testData, _ := os.Open(path + "/testdata/v34_main.yaml")
|
||||
defer testData.Close()
|
||||
|
||||
vulns, err := parse34YAML(testData)
|
||||
if err != nil {
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
assert.Equal(t, 105, len(vulns))
|
||||
assert.Equal(t, "CVE-2016-5387", vulns[0].Name)
|
||||
assert.Equal(t, "alpine:v3.4", vulns[0].FixedIn[0].Feature.Namespace.Name)
|
||||
assert.Equal(t, "apache2", vulns[0].FixedIn[0].Feature.Name)
|
||||
assert.Equal(t, "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-5387", vulns[0].Link)
|
||||
}
|
69
updater/fetchers/alpine/testdata/v33_main.yaml
vendored
Normal file
69
updater/fetchers/alpine/testdata/v33_main.yaml
vendored
Normal file
@ -0,0 +1,69 @@
|
||||
---
|
||||
distroversion: v3.3
|
||||
reponame: main
|
||||
archs:
|
||||
- x86_64
|
||||
- x86
|
||||
- armhf
|
||||
urlprefix: http://dl-cdn.alpinelinux.org/alpine
|
||||
apkurl: "{{urlprefix}}/{{distroversion}}/{{reponame}}/{{arch}}/{{pkg.name}}-${{pkg.ver}}.apk"
|
||||
packages:
|
||||
- pkg:
|
||||
name: busybox
|
||||
ver: 1.24.2-r0
|
||||
fixes:
|
||||
- CVE-2016-2147
|
||||
- CVE-2016-2148
|
||||
- pkg:
|
||||
name: expat
|
||||
ver: 2.1.1-r1
|
||||
fixes:
|
||||
- CVE-2016-0718
|
||||
- pkg:
|
||||
name: gd
|
||||
ver: 2.1.1-r1
|
||||
fixes:
|
||||
- CVE-2016-3074
|
||||
- pkg:
|
||||
name: giflib
|
||||
ver: 5.1.1-r1
|
||||
fixes:
|
||||
- CVE-2016-3977
|
||||
- pkg:
|
||||
name: jq
|
||||
ver: 1.5-r1
|
||||
fixes:
|
||||
- CVE-2015-8863
|
||||
- pkg:
|
||||
name: libarchive
|
||||
ver: 3.1.2-r3
|
||||
fixes:
|
||||
- CVE-2016-1541
|
||||
- pkg:
|
||||
name: libssh2
|
||||
ver: 1.6.0-r1
|
||||
fixes:
|
||||
- CVE-2016-0787
|
||||
- pkg:
|
||||
name: mercurial
|
||||
ver: 3.7.3-r1
|
||||
fixes:
|
||||
- CVE-2016-3105
|
||||
- pkg:
|
||||
name: openssl
|
||||
ver: 1.0.2h-r1
|
||||
fixes:
|
||||
- CVE-2016-2177
|
||||
- CVE-2016-2178
|
||||
- pkg:
|
||||
name: pcre
|
||||
ver: 8.38-r1
|
||||
fixes:
|
||||
- CVE-2016-1283
|
||||
- CVE-2016-3191
|
||||
- pkg:
|
||||
name: wpa_supplicant
|
||||
ver: 2.5-r2
|
||||
fixes:
|
||||
- CVE-2016-4476
|
||||
- CVE-2016-4477
|
251
updater/fetchers/alpine/testdata/v34_main.yaml
vendored
Normal file
251
updater/fetchers/alpine/testdata/v34_main.yaml
vendored
Normal file
@ -0,0 +1,251 @@
|
||||
---
|
||||
distroversion: v3.4
|
||||
reponame: main
|
||||
archs:
|
||||
- x86_64
|
||||
- x86
|
||||
- armhf
|
||||
urlprefix: http://dl-cdn.alpinelinux.org/alpine
|
||||
apkurl: "{{urlprefix}}/{{distroversion}}/{{reponame}}/{{arch}}/{{pkg.name}}-{{pkg.ver}}.apk"
|
||||
packages:
|
||||
- pkg:
|
||||
name: apache2
|
||||
secfixes:
|
||||
2.4.23-r1:
|
||||
- CVE-2016-5387
|
||||
- pkg:
|
||||
name: busybox
|
||||
secfixes:
|
||||
1.24.2-r0:
|
||||
- CVE-2016-2147
|
||||
- CVE-2016-2148
|
||||
- pkg:
|
||||
name: bzip2
|
||||
secfixes:
|
||||
1.0.6-r5:
|
||||
- CVE-2016-3189
|
||||
- pkg:
|
||||
name: c-ares
|
||||
secfixes:
|
||||
1.12.0-r0:
|
||||
- CVE-2016-5180
|
||||
- pkg:
|
||||
name: collectd
|
||||
secfixes:
|
||||
5.5.2-r0:
|
||||
- CVE-2016-6254
|
||||
- pkg:
|
||||
name: curl
|
||||
secfixes:
|
||||
7.51.0:
|
||||
- CVE-2016-8615
|
||||
- CVE-2016-8616
|
||||
- CVE-2016-8617
|
||||
- CVE-2016-8618
|
||||
- CVE-2016-8619
|
||||
- CVE-2016-8620
|
||||
- CVE-2016-8621
|
||||
- CVE-2016-8622
|
||||
- CVE-2016-8623
|
||||
- CVE-2016-8624
|
||||
- CVE-2016-8625
|
||||
7.50.3-r0:
|
||||
- CVE-2016-7167
|
||||
7.50.2-r0:
|
||||
- CVE-2016-7141
|
||||
7.50.1-r0:
|
||||
- CVE-2016-5419
|
||||
- CVE-2016-5420
|
||||
- CVE-2016-5421
|
||||
7.36.0-r0:
|
||||
- CVE-2014-0138
|
||||
- CVE-2014-0139
|
||||
- pkg:
|
||||
name: expat
|
||||
secfixes:
|
||||
2.1.1-r1:
|
||||
- CVE-2016-0718
|
||||
2.1.1-r2:
|
||||
- CVE-2016-4472
|
||||
- pkg:
|
||||
name: flex
|
||||
secfixes:
|
||||
2.6.1-r0:
|
||||
- CVE-2016-6354
|
||||
- pkg:
|
||||
name: gd
|
||||
secfixes:
|
||||
2.2.1-r0:
|
||||
- CVE-2016-3074
|
||||
2.2.2-r0:
|
||||
- CVE-2015-8874
|
||||
- CVE-2016-5767
|
||||
2.2.3-r0:
|
||||
- CVE-2016-5766
|
||||
- CVE-2016-6128
|
||||
- CVE-2016-6132
|
||||
- CVE-2016-6207
|
||||
- CVE-2016-6214
|
||||
2.2.3-r1:
|
||||
- CVE-2016-7568
|
||||
- pkg:
|
||||
name: giflib
|
||||
secfixes:
|
||||
5.1.4-r0:
|
||||
- CVE-2016-3977
|
||||
- pkg:
|
||||
name: guile
|
||||
secfixes:
|
||||
2.0.11-r3:
|
||||
- CVE-2016-8605
|
||||
- CVE-2016-8606
|
||||
- pkg:
|
||||
name: icu
|
||||
secfixes:
|
||||
57.1-r1:
|
||||
- CVE-2016-6293
|
||||
- pkg:
|
||||
name: imagemagick
|
||||
secfixes:
|
||||
6.9.5.3:
|
||||
- CVE-2016-5010
|
||||
- CVE-2016-5687
|
||||
- CVE-2016-5688
|
||||
- CVE-2016-5689
|
||||
- CVE-2016-5690
|
||||
- CVE-2016-5691
|
||||
- CVE-2016-5841
|
||||
- CVE-2016-5842
|
||||
- CVE-2016-6491
|
||||
6.9.5.9-r1:
|
||||
- CVE-2016-7799
|
||||
- CVE-2016-7906
|
||||
- pkg:
|
||||
name: jq
|
||||
secfixes:
|
||||
1.5-r1:
|
||||
- CVE-2015-8863
|
||||
- pkg:
|
||||
name: krb5
|
||||
secfixes:
|
||||
1.14-r1:
|
||||
- CVE-2015-8629
|
||||
- CVE-2015-8630
|
||||
- CVE-2015-8631
|
||||
1.14-r2:
|
||||
- CVE-2016-3119
|
||||
1.14.3-r0:
|
||||
- CVE-2016-3120
|
||||
- pkg:
|
||||
name: libarchive
|
||||
secfixes:
|
||||
3.2.0-r0:
|
||||
- CVE-2016-1541
|
||||
3.2.1-r0:
|
||||
- CVE-2015-8934
|
||||
- CVE-2016-4300
|
||||
- CVE-2016-4302
|
||||
- CVE-2016-4809
|
||||
- CVE-2016-5844
|
||||
- CVE-2016-6250
|
||||
- pkg:
|
||||
name: libbsd
|
||||
secfixes:
|
||||
0.8.2:
|
||||
- CVE-2016-2090
|
||||
- pkg:
|
||||
name: libidn
|
||||
secfixes:
|
||||
1.33-r0:
|
||||
- CVE-2015-8948
|
||||
- CVE-2016-6261
|
||||
- CVE-2016-6262
|
||||
- CVE-2016-6263
|
||||
- pkg:
|
||||
name: libssh2
|
||||
secfixes:
|
||||
1.7.0-r0:
|
||||
- CVE-2016-0787
|
||||
- pkg:
|
||||
name: openjpeg
|
||||
secfixes:
|
||||
2.1.2-r0:
|
||||
- CVE-2016-7445
|
||||
- pkg:
|
||||
name: openssh
|
||||
secfixes:
|
||||
7.2_p2-r1:
|
||||
- CVE-2016-6210
|
||||
7.2_p2-r2:
|
||||
- CVE-2016-6515
|
||||
- pkg:
|
||||
name: openssl
|
||||
secfixes:
|
||||
1.0.2h-r0:
|
||||
- CVE-2016-2107
|
||||
- CVE-2016-2105
|
||||
- CVE-2016-2106
|
||||
- CVE-2016-2109
|
||||
- CVE-2016-2176
|
||||
1.0.2h-r1:
|
||||
- CVE-2016-2177
|
||||
- CVE-2016-2178
|
||||
1.0.2h-r2:
|
||||
- CVE-2016-2180
|
||||
1.0.2h-r3:
|
||||
- CVE-2016-2179
|
||||
- CVE-2016-2182
|
||||
- CVE-2016-6302
|
||||
- CVE-2016-6303
|
||||
1.0.2h-r4:
|
||||
- CVE-2016-2181
|
||||
1.0.2i-r0:
|
||||
- CVE-2016-2183
|
||||
- CVE-2016-6304
|
||||
- CVE-2016-6306
|
||||
- pkg:
|
||||
name: pcre
|
||||
secfixes:
|
||||
8.38-r1:
|
||||
- CVE-2016-1283
|
||||
- CVE-2016-3191
|
||||
- pkg:
|
||||
name: py-django
|
||||
secfixes:
|
||||
1.8.16-r0:
|
||||
- CVE-2016-9013
|
||||
- CVE-2016-9014
|
||||
- pkg:
|
||||
name: tar
|
||||
secfixes:
|
||||
1.29-r1:
|
||||
- CVE-2016-6321
|
||||
- pkg:
|
||||
name: wget
|
||||
secfixes:
|
||||
1.17.1-r1:
|
||||
- CVE-2016-4971
|
||||
- pkg:
|
||||
name: wpa_supplicant
|
||||
secfixes:
|
||||
2.5-r3:
|
||||
- CVE-2016-4476
|
||||
- CVE-2016-4477
|
||||
- pkg:
|
||||
name: xen
|
||||
secfixes:
|
||||
4.6.3-r1:
|
||||
- CVE-2016-6258 XSA-182
|
||||
- CVE-2016-6259 XSA-183
|
||||
- CVE-2016-5403 XSA-184
|
||||
4.6.3-r2:
|
||||
- CVE-2016-7092 XSA-185
|
||||
- CVE-2016-7093 XSA-186
|
||||
- CVE-2016-7094 XSA-187
|
||||
4.6.3-r3:
|
||||
- CVE-2016-7777 XSA-190
|
||||
- pkg:
|
||||
name: zabbix
|
||||
secfixes:
|
||||
3.0.4-r0:
|
||||
- ZBX-11023
|
84
worker/detectors/feature/apk/apk.go
Normal file
84
worker/detectors/feature/apk/apk.go
Normal file
@ -0,0 +1,84 @@
|
||||
// Copyright 2016 clair authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package apk
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
|
||||
"github.com/coreos/clair/database"
|
||||
"github.com/coreos/clair/utils/types"
|
||||
"github.com/coreos/clair/worker/detectors"
|
||||
"github.com/coreos/pkg/capnslog"
|
||||
)
|
||||
|
||||
var log = capnslog.NewPackageLogger("github.com/coreos/clair", "worker/detectors/packages")
|
||||
|
||||
func init() {
|
||||
detectors.RegisterFeaturesDetector("apk", &detector{})
|
||||
}
|
||||
|
||||
type detector struct{}
|
||||
|
||||
func (d *detector) Detect(data map[string][]byte) ([]database.FeatureVersion, error) {
|
||||
file, exists := data["lib/apk/db/installed"]
|
||||
if !exists {
|
||||
return []database.FeatureVersion{}, nil
|
||||
}
|
||||
|
||||
// Iterate over each line in the "installed" file attempting to parse each
|
||||
// package into a feature that will be stored in a set to guarantee
|
||||
// uniqueness.
|
||||
pkgSet := make(map[string]database.FeatureVersion)
|
||||
ipkg := database.FeatureVersion{}
|
||||
scanner := bufio.NewScanner(bytes.NewBuffer(file))
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if len(line) < 2 {
|
||||
continue
|
||||
}
|
||||
|
||||
// Parse the package name or version.
|
||||
switch {
|
||||
case line[:2] == "P:":
|
||||
ipkg.Feature.Name = line[2:]
|
||||
case line[:2] == "V:":
|
||||
var err error
|
||||
ipkg.Version, err = types.NewVersion(line[2:])
|
||||
if err != nil {
|
||||
log.Warningf("could not parse package version '%s': %s. skipping", line[2:], err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// If we have a whole feature, store it in the set and try to parse a new
|
||||
// one.
|
||||
if ipkg.Feature.Name != "" && ipkg.Version.String() != "" {
|
||||
pkgSet[ipkg.Feature.Name+"#"+ipkg.Version.String()] = ipkg
|
||||
ipkg = database.FeatureVersion{}
|
||||
}
|
||||
}
|
||||
|
||||
// Convert the map into a slice.
|
||||
pkgs := make([]database.FeatureVersion, 0, len(pkgSet))
|
||||
for _, pkg := range pkgSet {
|
||||
pkgs = append(pkgs, pkg)
|
||||
}
|
||||
|
||||
return pkgs, nil
|
||||
}
|
||||
|
||||
func (d *detector) GetRequiredFiles() []string {
|
||||
return []string{"lib/apk/db/installed"}
|
||||
}
|
80
worker/detectors/feature/apk/apk_test.go
Normal file
80
worker/detectors/feature/apk/apk_test.go
Normal file
@ -0,0 +1,80 @@
|
||||
// Copyright 2016 clair authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package apk
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/coreos/clair/database"
|
||||
"github.com/coreos/clair/utils/types"
|
||||
"github.com/coreos/clair/worker/detectors/feature"
|
||||
)
|
||||
|
||||
func TestAPKFeatureDetection(t *testing.T) {
|
||||
testData := []feature.TestData{
|
||||
{
|
||||
FeatureVersions: []database.FeatureVersion{
|
||||
{
|
||||
Feature: database.Feature{Name: "musl"},
|
||||
Version: types.NewVersionUnsafe("1.1.14-r10"),
|
||||
},
|
||||
{
|
||||
Feature: database.Feature{Name: "busybox"},
|
||||
Version: types.NewVersionUnsafe("1.24.2-r9"),
|
||||
},
|
||||
{
|
||||
Feature: database.Feature{Name: "alpine-baselayout"},
|
||||
Version: types.NewVersionUnsafe("3.0.3-r0"),
|
||||
},
|
||||
{
|
||||
Feature: database.Feature{Name: "alpine-keys"},
|
||||
Version: types.NewVersionUnsafe("1.1-r0"),
|
||||
},
|
||||
{
|
||||
Feature: database.Feature{Name: "zlib"},
|
||||
Version: types.NewVersionUnsafe("1.2.8-r2"),
|
||||
},
|
||||
{
|
||||
Feature: database.Feature{Name: "libcrypto1.0"},
|
||||
Version: types.NewVersionUnsafe("1.0.2h-r1"),
|
||||
},
|
||||
{
|
||||
Feature: database.Feature{Name: "libssl1.0"},
|
||||
Version: types.NewVersionUnsafe("1.0.2h-r1"),
|
||||
},
|
||||
{
|
||||
Feature: database.Feature{Name: "apk-tools"},
|
||||
Version: types.NewVersionUnsafe("2.6.7-r0"),
|
||||
},
|
||||
{
|
||||
Feature: database.Feature{Name: "scanelf"},
|
||||
Version: types.NewVersionUnsafe("1.1.6-r0"),
|
||||
},
|
||||
{
|
||||
Feature: database.Feature{Name: "musl-utils"},
|
||||
Version: types.NewVersionUnsafe("1.1.14-r10"),
|
||||
},
|
||||
{
|
||||
Feature: database.Feature{Name: "libc-utils"},
|
||||
Version: types.NewVersionUnsafe("0.7-r0"),
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"lib/apk/db/installed": feature.LoadFileForTest("apk/testdata/installed"),
|
||||
},
|
||||
},
|
||||
}
|
||||
feature.TestDetector(t, &detector{}, testData)
|
||||
}
|
448
worker/detectors/feature/apk/testdata/installed
vendored
Normal file
448
worker/detectors/feature/apk/testdata/installed
vendored
Normal file
@ -0,0 +1,448 @@
|
||||
C:Q11otALzX1d1D0kVawy06IairTXS0=
|
||||
P:musl
|
||||
V:1.1.14-r10
|
||||
A:x86_64
|
||||
S:445080
|
||||
I:569344
|
||||
T:the musl c library (libc) implementation
|
||||
U:http://www.musl-libc.org/
|
||||
L:MIT
|
||||
o:musl
|
||||
m:Timo Teräs <timo.teras@iki.fi>
|
||||
t:1466181580
|
||||
c:e6c226fbe17bb8f856dce5f0d9bc088b333e6225
|
||||
p:so:libc.musl-x86_64.so.1=1
|
||||
F:lib
|
||||
R:libc.musl-x86_64.so.1
|
||||
a:0:0:777
|
||||
Z:Q17yJ3JFNypA4mxhJJr0ou6CzsJVI=
|
||||
R:ld-musl-x86_64.so.1
|
||||
a:0:0:755
|
||||
Z:Q1KUwsFGLHn/enpN9+QIpK/FmixtQ=
|
||||
|
||||
C:Q1yhJHGSZ80L7cL0y4UKKGrBPwrUQ=
|
||||
P:busybox
|
||||
V:1.24.2-r9
|
||||
A:x86_64
|
||||
S:642121
|
||||
I:909312
|
||||
T:Size optimized toolbox of many common UNIX utilities
|
||||
U:http://busybox.net
|
||||
L:GPL2
|
||||
o:busybox
|
||||
m:Natanael Copa <ncopa@alpinelinux.org>
|
||||
t:1466671780
|
||||
c:386b639b3917a9d1b8588dd87f09ed446501cddf
|
||||
D:so:libc.musl-x86_64.so.1
|
||||
F:bin
|
||||
R:busybox
|
||||
a:0:0:755
|
||||
Z:Q1xOlCsdvx4O0gnKWoFCNKjz2quRE=
|
||||
R:sh
|
||||
a:0:0:777
|
||||
Z:Q1pcfTfDNEbNKQc2s1tia7da05M8Q=
|
||||
F:etc
|
||||
R:securetty
|
||||
Z:Q14VDshgWFleuDbp4jqXk+UNES65Q=
|
||||
R:udhcpd.conf
|
||||
Z:Q1PWhOJ+TaEzAXw+XC6kkz/FXI/KA=
|
||||
F:etc/logrotate.d
|
||||
R:acpid
|
||||
Z:Q1bPM2hPZy1LntZ/YdI4ZFJzVl1Y8=
|
||||
F:etc/network
|
||||
F:etc/network/if-up.d
|
||||
F:etc/network/if-post-up.d
|
||||
F:etc/network/if-pre-up.d
|
||||
F:etc/network/if-post-down.d
|
||||
F:etc/network/if-pre-down.d
|
||||
F:etc/network/if-down.d
|
||||
F:sbin
|
||||
F:tmp
|
||||
M:0:0:1777
|
||||
F:usr
|
||||
F:usr/sbin
|
||||
F:usr/bin
|
||||
F:var
|
||||
F:var/lib
|
||||
F:var/lib/udhcpd
|
||||
F:var/cache
|
||||
F:var/cache/misc
|
||||
|
||||
C:Q1ohSJYVBBHXLdH6/bMtHGxIVczPo=
|
||||
P:alpine-baselayout
|
||||
V:3.0.3-r0
|
||||
A:x86_64
|
||||
S:74697
|
||||
I:401408
|
||||
T:Alpine base dir structure and init scripts
|
||||
U:http://git.alpinelinux.org/cgit/aports/tree/main/alpine-baselayout
|
||||
L:GPL2
|
||||
o:alpine-baselayout
|
||||
m:Natanael Copa <ncopa@alpinelinux.org>
|
||||
t:1466181584
|
||||
c:d0bef446b94220475c60e78f2e081f38390b89ca
|
||||
D:busybox so:libc.musl-x86_64.so.1
|
||||
F:dev
|
||||
F:dev/shm
|
||||
F:dev/pts
|
||||
F:etc
|
||||
R:hosts
|
||||
Z:Q1S93L8EsQ/7zGSnfGDfj5I7bjCS4=
|
||||
R:sysctl.conf
|
||||
Z:Q14upz3tfnNxZkIEsUhWn7Xoiw96g=
|
||||
R:group
|
||||
Z:Q1zNuxdqs1x+nJO8WucpZfQrdiapA=
|
||||
R:protocols
|
||||
Z:Q13FqXUnvuOpMDrH/6rehxuYAEE34=
|
||||
R:fstab
|
||||
Z:Q11Q7hNe8QpDS531guqCdrXBzoA/o=
|
||||
R:mtab
|
||||
a:0:0:777
|
||||
Z:Q1kiljhXXH1LlQroHsEJIkPZg2eiw=
|
||||
R:profile
|
||||
Z:Q1FrM1yy3WJbQTc9LgnKTn5tRovlE=
|
||||
R:TZ
|
||||
Z:Q1uHH18uOLEzp56qFUP843WSoKM9E=
|
||||
R:shells
|
||||
Z:Q1ojm2YdpCJ6B/apGDaZ/Sdb2xJkA=
|
||||
R:motd
|
||||
Z:Q1MaUHN/Rf32Lf67Owrq1BXQU7usE=
|
||||
R:inittab
|
||||
Z:Q1TsthbhW7QzWRe1E/NKwTOuD4pHc=
|
||||
R:hostname
|
||||
Z:Q16nVwYVXP/tChvUPdukVD2ifXOmc=
|
||||
R:modules
|
||||
Z:Q1C7P4uPQo8B6P6V+O78ybHl0AHhA=
|
||||
R:services
|
||||
Z:Q1NBe0rrC8HMzNmVf4ybSENcsdey0=
|
||||
R:shadow
|
||||
a:0:42:640
|
||||
Z:Q1LG0ii8vP4gQgDmSnK0WBtjtovlg=
|
||||
R:passwd
|
||||
Z:Q11HpI0rBp2zsun4+LIIBENg8JQUE=
|
||||
F:etc/profile.d
|
||||
R:color_prompt
|
||||
Z:Q10wL23GuSCVfumMRgakabUI6EsSk=
|
||||
F:etc/init.d
|
||||
F:etc/apk
|
||||
F:etc/sysctl.d
|
||||
R:00-alpine.conf
|
||||
Z:Q1kZy9KEvjykp1vCw1kWgdvBuEXvg=
|
||||
F:etc/modprobe.d
|
||||
R:i386.conf
|
||||
Z:Q1pnay/njn6ol9cCssL7KiZZ8etlc=
|
||||
R:blacklist.conf
|
||||
Z:Q1+TdC1pulajuYy0ebcos8V/aMeqk=
|
||||
R:aliases.conf
|
||||
Z:Q1udaZLaeaalyuCcnBgCKPIybDO08=
|
||||
R:kms.conf
|
||||
Z:Q1yH/c6fBvCWn0Huny5Rf/GET2Jbs=
|
||||
F:etc/modules-load.d
|
||||
F:etc/opt
|
||||
F:etc/conf.d
|
||||
F:etc/crontabs
|
||||
R:root
|
||||
a:0:0:600
|
||||
Z:Q1vfk1apUWI4yLJGhhNRd0kJixfvY=
|
||||
F:etc/periodic
|
||||
F:etc/periodic/hourly
|
||||
F:etc/periodic/weekly
|
||||
F:etc/periodic/monthly
|
||||
F:etc/periodic/15min
|
||||
F:etc/periodic/daily
|
||||
F:etc/network
|
||||
F:etc/network/if-up.d
|
||||
F:etc/network/if-pre-up.d
|
||||
F:etc/network/if-post-down.d
|
||||
F:etc/network/if-down.d
|
||||
F:home
|
||||
F:lib
|
||||
F:lib/mdev
|
||||
F:lib/firmware
|
||||
F:media
|
||||
F:media/floppy
|
||||
F:media/cdrom
|
||||
F:media/usb
|
||||
F:mnt
|
||||
F:proc
|
||||
F:root
|
||||
M:0:0:700
|
||||
F:run
|
||||
F:sbin
|
||||
R:mkmntdirs
|
||||
a:0:0:755
|
||||
Z:Q1lGBnGMsnB3SEZL/oHeN99F1/ie8=
|
||||
F:srv
|
||||
F:sys
|
||||
F:tmp
|
||||
M:0:0:1777
|
||||
F:usr
|
||||
F:usr/sbin
|
||||
F:usr/bin
|
||||
F:usr/local
|
||||
F:usr/local/bin
|
||||
F:usr/local/lib
|
||||
F:usr/local/share
|
||||
F:usr/share
|
||||
F:usr/share/man
|
||||
F:usr/share/misc
|
||||
F:var
|
||||
F:var/lock
|
||||
F:var/lock/subsys
|
||||
F:var/tmp
|
||||
M:0:0:1777
|
||||
F:var/log
|
||||
F:var/lib
|
||||
F:var/lib/misc
|
||||
F:var/local
|
||||
F:var/opt
|
||||
F:var/cache
|
||||
F:var/cache/misc
|
||||
F:var/spool
|
||||
F:var/spool/cron
|
||||
R:crontabs
|
||||
a:0:0:777
|
||||
Z:Q1OFZt+ZMp7j0Gny0rqSKuWJyqYmA=
|
||||
F:var/empty
|
||||
F:var/run
|
||||
|
||||
C:Q1Te9/+u5q66cAwdYlcDJvdcu4+iU=
|
||||
P:alpine-keys
|
||||
V:1.1-r0
|
||||
A:x86_64
|
||||
S:7787
|
||||
I:36864
|
||||
T:Public keys for Alpine Linux packages
|
||||
U:http://alpinelinux.org
|
||||
L:GPL
|
||||
o:alpine-keys
|
||||
m:Natanael Copa <ncopa@alpinelinux.org>
|
||||
t:1461964035
|
||||
c:d0b08b1e17d40d21196df7709fdb95f37165615d
|
||||
r:alpine-base
|
||||
F:etc
|
||||
F:etc/apk
|
||||
F:etc/apk/keys
|
||||
R:alpine-devel@lists.alpinelinux.org-4d07755e.rsa.pub
|
||||
Z:Q1XfH9IG0ZFgbOIssIhpiWqDlSspY=
|
||||
R:alpine-devel@lists.alpinelinux.org-524d27bb.rsa.pub
|
||||
Z:Q1BTqS+H/UUyhQuzHwiBl47+BTKuU=
|
||||
R:alpine-devel@lists.alpinelinux.org-5243ef4b.rsa.pub
|
||||
Z:Q1v7YWZYzAWoclaLDI45jEguI7YN0=
|
||||
R:alpine-devel@lists.alpinelinux.org-5261cecb.rsa.pub
|
||||
Z:Q1NnGuDsdQOx4ZNYfB3N97eLyGPkI=
|
||||
R:alpine-devel@lists.alpinelinux.org-4a6a0840.rsa.pub
|
||||
Z:Q1OvCFSO94z97c80mIDCxqGkh2Og4=
|
||||
|
||||
C:Q179BNNNQKqOszFIASc2TCeounYO8=
|
||||
P:zlib
|
||||
V:1.2.8-r2
|
||||
A:x86_64
|
||||
S:71733
|
||||
I:98304
|
||||
T:A compression/decompression Library
|
||||
U:http://zlib.net
|
||||
L:zlib
|
||||
o:zlib
|
||||
m:Natanael Copa <ncopa@alpinelinux.org>
|
||||
t:1461931151
|
||||
c:a7329a4de4d10d99206c78c229dc3742880cd042
|
||||
D:so:libc.musl-x86_64.so.1
|
||||
p:so:libz.so.1=1.2.8
|
||||
F:lib
|
||||
R:libz.so.1.2.8
|
||||
a:0:0:755
|
||||
Z:Q1bh8VMdNZcPKyIQTtLMtz/0VL2H0=
|
||||
R:libz.so.1
|
||||
a:0:0:777
|
||||
Z:Q1x1VqGi0rW5lxmvPQOjnqNapz/OU=
|
||||
|
||||
C:Q1Zchg/48QO2ZPQLqEmj9aUcaci+s=
|
||||
P:libcrypto1.0
|
||||
V:1.0.2h-r1
|
||||
A:x86_64
|
||||
S:1714530
|
||||
I:2527232
|
||||
T:Crypto library from openssl
|
||||
U:http://openssl.org
|
||||
L:openssl
|
||||
o:openssl
|
||||
m:Timo Teras <timo.teras@iki.fi>
|
||||
t:1466620012
|
||||
c:38c6e1fd86f4d9cba4c146b8bdcd71f84e1a4ee7
|
||||
D:so:libc.musl-x86_64.so.1 so:libz.so.1
|
||||
p:so:libcrypto.so.1.0.0=1.0.0
|
||||
F:lib
|
||||
R:libcrypto.so.1.0.0
|
||||
a:0:0:555
|
||||
Z:Q1DgSoxP0AWq64XJSPXT0yRTjSSBk=
|
||||
F:usr
|
||||
F:usr/bin
|
||||
R:c_rehash
|
||||
a:0:0:755
|
||||
Z:Q1XZt0LbTr44grnBtK+Yihjynh2EE=
|
||||
F:usr/lib
|
||||
R:libcrypto.so.1.0.0
|
||||
a:0:0:777
|
||||
Z:Q1jLDKGBtunzKi5FKmK/QTAqfh6uI=
|
||||
F:usr/lib/engines
|
||||
R:libubsec.so
|
||||
a:0:0:555
|
||||
Z:Q1SaoP91RpISCN8KO3AxuB8Tzyc/A=
|
||||
R:libatalla.so
|
||||
a:0:0:555
|
||||
Z:Q1W31yRhAZE9X5Z5zy9l6mkn1tbcQ=
|
||||
R:libcapi.so
|
||||
a:0:0:555
|
||||
Z:Q1iriyqA2XunZb8pxmsOeRML2ZsRg=
|
||||
R:libgost.so
|
||||
a:0:0:555
|
||||
Z:Q1zwS6yHAzzdnrHb9BV8pIsE2yIgg=
|
||||
R:libcswift.so
|
||||
a:0:0:555
|
||||
Z:Q16/TBTN+WkIFQeFlCPTDc5Xs33bU=
|
||||
R:libchil.so
|
||||
a:0:0:555
|
||||
Z:Q1fMssNRSfAgg4nZVYm0IzYG2gTLk=
|
||||
R:libgmp.so
|
||||
a:0:0:555
|
||||
Z:Q1onZiPB/LsF3Xqn8rwH5FcYLkuf4=
|
||||
R:libnuron.so
|
||||
a:0:0:555
|
||||
Z:Q189GVmg2NFt2nTCqfcSl7Wtoym1o=
|
||||
R:lib4758cca.so
|
||||
a:0:0:555
|
||||
Z:Q1aNXgEbvxfvZdZpa4frZ9p6eq2Y4=
|
||||
R:libsureware.so
|
||||
a:0:0:555
|
||||
Z:Q14Z9HkfG+WqvGRIb42iugBuBKOag=
|
||||
R:libpadlock.so
|
||||
a:0:0:555
|
||||
Z:Q1OAwUUirl7Q1OiqTjB96lKBQYbMc=
|
||||
R:libaep.so
|
||||
a:0:0:555
|
||||
Z:Q1nrvE4qxl4AXEC/psF1Eh9n6E7Pg=
|
||||
|
||||
C:Q1cSDzN+k7K0xE4PXzGhW2DcZ4yhQ=
|
||||
P:libssl1.0
|
||||
V:1.0.2h-r1
|
||||
A:x86_64
|
||||
S:274743
|
||||
I:442368
|
||||
T:SSL shared libraries
|
||||
U:http://openssl.org
|
||||
L:openssl
|
||||
o:openssl
|
||||
m:Timo Teras <timo.teras@iki.fi>
|
||||
t:1466620012
|
||||
c:38c6e1fd86f4d9cba4c146b8bdcd71f84e1a4ee7
|
||||
D:so:libc.musl-x86_64.so.1 so:libcrypto.so.1.0.0
|
||||
p:so:libssl.so.1.0.0=1.0.0
|
||||
F:lib
|
||||
R:libssl.so.1.0.0
|
||||
a:0:0:555
|
||||
Z:Q1wdqn4897nQP5l/f3SV4DWf9QOkQ=
|
||||
F:usr
|
||||
F:usr/lib
|
||||
R:libssl.so.1.0.0
|
||||
a:0:0:777
|
||||
Z:Q1ke5dnHGVWcEyRpOe0/lKEqizHHQ=
|
||||
|
||||
C:Q1CZDArNYrQXWBjDpMxg7RHxTiO9g=
|
||||
P:apk-tools
|
||||
V:2.6.7-r0
|
||||
A:x86_64
|
||||
S:146592
|
||||
I:253952
|
||||
T:Alpine Package Keeper - package manager for alpine
|
||||
U:http://git.alpinelinux.org/cgit/apk-tools/
|
||||
L:GPL2
|
||||
o:apk-tools
|
||||
m:Natanael Copa <ncopa@alpinelinux.org>
|
||||
t:1464341138
|
||||
c:08b6e2ae43356fbb24ef5c262fb08bfe09d675b0
|
||||
D:so:libc.musl-x86_64.so.1 so:libcrypto.so.1.0.0 so:libssl.so.1.0.0 so:libz.so.1
|
||||
F:etc
|
||||
F:etc/apk
|
||||
F:etc/apk/keys
|
||||
F:etc/apk/protected_paths.d
|
||||
F:sbin
|
||||
R:apk
|
||||
a:0:0:755
|
||||
Z:Q1ozOGvVOspzXfX1bUFjrjZ6ygEB0=
|
||||
F:usr
|
||||
F:var
|
||||
F:var/lib
|
||||
F:var/lib/apk
|
||||
F:var/cache
|
||||
F:var/cache/misc
|
||||
|
||||
C:Q1+bq4F8Wtk+kqYhi8D3WWtlfALZA=
|
||||
P:scanelf
|
||||
V:1.1.6-r0
|
||||
A:x86_64
|
||||
S:53666
|
||||
I:90112
|
||||
T:Scan ELF binaries for stuff
|
||||
U:https://wiki.gentoo.org/wiki/Hardened/PaX_Utilities
|
||||
L:GPL2
|
||||
o:pax-utils
|
||||
m:Natanael Copa <ncopa@alpinelinux.org>
|
||||
t:1461934341
|
||||
c:891f6254fb6e1f11f62ee2c9fd35784fd313b9d1
|
||||
D:so:libc.musl-x86_64.so.1
|
||||
r:pax-utils
|
||||
F:usr
|
||||
F:usr/bin
|
||||
R:scanelf
|
||||
a:0:0:755
|
||||
Z:Q12S+aDBkRA63GvTmx45HqqbOKBz0=
|
||||
|
||||
C:Q1YIqh3Tnv97xmFdPl4zODdQ+PXsw=
|
||||
P:musl-utils
|
||||
V:1.1.14-r10
|
||||
A:x86_64
|
||||
S:50427
|
||||
I:110592
|
||||
T:the musl c library (libc) implementation
|
||||
U:http://www.musl-libc.org/
|
||||
L:MIT BSD GPL2+
|
||||
o:musl
|
||||
m:Timo Teräs <timo.teras@iki.fi>
|
||||
t:1466181579
|
||||
c:e6c226fbe17bb8f856dce5f0d9bc088b333e6225
|
||||
D:!uclibc-utils scanelf musl=1.1.14-r10 so:libc.musl-x86_64.so.1
|
||||
r:libiconv uclibc-utils
|
||||
F:sbin
|
||||
R:ldconfig
|
||||
a:0:0:755
|
||||
Z:Q1Kja2+POZKxEkUOZqwSjC6kmaED4=
|
||||
F:usr
|
||||
F:usr/bin
|
||||
R:iconv
|
||||
a:0:0:755
|
||||
Z:Q1DmLsMEsBDtwb8S0z1pl0MYH29+o=
|
||||
R:ldd
|
||||
a:0:0:777
|
||||
Z:Q1a/NMxsyXbxLcmrTyGQtovas5gJk=
|
||||
R:getconf
|
||||
a:0:0:755
|
||||
Z:Q1iub9vwJRjlaCnu21SWjb504fUqk=
|
||||
R:getent
|
||||
a:0:0:755
|
||||
Z:Q1Z5dnRfQ7nvRbRRSpM1k0J7UMdng=
|
||||
|
||||
C:Q1kFW8ev12zyZyGYBC9y/Epe1PqWE=
|
||||
P:libc-utils
|
||||
V:0.7-r0
|
||||
A:x86_64
|
||||
S:2804
|
||||
I:4096
|
||||
T:Meta package to pull in correct libc
|
||||
U:http://alpinelinux.org
|
||||
L:GPL
|
||||
o:libc-dev
|
||||
m:Natanael Copa <ncopa@alpinelinux.org>
|
||||
t:1461934274
|
||||
c:e3725c0af137717d6883265a92db3838900b5cee
|
||||
D:musl-utils
|
@ -22,7 +22,8 @@ import (
|
||||
"github.com/coreos/clair/worker/detectors/feature"
|
||||
)
|
||||
|
||||
var dpkgPackagesTests = []feature.FeatureVersionTest{
|
||||
func TestDpkgFeatureDetection(t *testing.T) {
|
||||
testData := []feature.TestData{
|
||||
// Test an Ubuntu dpkg status file
|
||||
{
|
||||
FeatureVersions: []database.FeatureVersion{
|
||||
@ -44,8 +45,7 @@ var dpkgPackagesTests = []feature.FeatureVersionTest{
|
||||
"var/lib/dpkg/status": feature.LoadFileForTest("dpkg/testdata/status"),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestDpkgFeaturesDetector(t *testing.T) {
|
||||
feature.TestFeaturesDetector(t, &DpkgFeaturesDetector{}, dpkgPackagesTests)
|
||||
feature.TestDetector(t, &DpkgFeaturesDetector{}, testData)
|
||||
}
|
||||
|
@ -22,7 +22,8 @@ import (
|
||||
"github.com/coreos/clair/worker/detectors/feature"
|
||||
)
|
||||
|
||||
var rpmPackagesTests = []feature.FeatureVersionTest{
|
||||
func TestRpmFeatureDetection(t *testing.T) {
|
||||
testData := []feature.TestData{
|
||||
// Test a CentOS 7 RPM database
|
||||
// Memo: Use the following command on a RPM-based system to shrink a database: rpm -qa --qf "%{NAME}\n" |tail -n +3| xargs rpm -e --justdb
|
||||
{
|
||||
@ -42,8 +43,7 @@ var rpmPackagesTests = []feature.FeatureVersionTest{
|
||||
"var/lib/rpm/Packages": feature.LoadFileForTest("rpm/testdata/Packages"),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestRpmFeaturesDetector(t *testing.T) {
|
||||
feature.TestFeaturesDetector(t, &RpmFeaturesDetector{}, rpmPackagesTests)
|
||||
feature.TestDetector(t, &RpmFeaturesDetector{}, testData)
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2015 clair authors
|
||||
// Copyright 2016 clair authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@ -12,6 +12,8 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package feature implements utilities common to implementations of
|
||||
// FeatureDetector.
|
||||
package feature
|
||||
|
||||
import (
|
||||
@ -25,22 +27,28 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type FeatureVersionTest struct {
|
||||
FeatureVersions []database.FeatureVersion
|
||||
// TestData represents the data used to test an implementation of
|
||||
// FeatureDetector.
|
||||
type TestData struct {
|
||||
Data map[string][]byte
|
||||
FeatureVersions []database.FeatureVersion
|
||||
}
|
||||
|
||||
// LoadFileForTest can be used in order to obtain the []byte contents of a file
|
||||
// that is meant to be used for test data.
|
||||
func LoadFileForTest(name string) []byte {
|
||||
_, filename, _, _ := runtime.Caller(0)
|
||||
d, _ := ioutil.ReadFile(filepath.Join(filepath.Dir(filename)) + "/" + name)
|
||||
return d
|
||||
}
|
||||
|
||||
func TestFeaturesDetector(t *testing.T, detector detectors.FeaturesDetector, tests []FeatureVersionTest) {
|
||||
for _, test := range tests {
|
||||
featureVersions, err := detector.Detect(test.Data)
|
||||
if assert.Nil(t, err) && assert.Len(t, featureVersions, len(test.FeatureVersions)) {
|
||||
for _, expectedFeatureVersion := range test.FeatureVersions {
|
||||
// TestDetector runs a detector on each provided instance of TestData and
|
||||
// asserts the ouput to be equal to the expected output.
|
||||
func TestDetector(t *testing.T, detector detectors.FeaturesDetector, testData []TestData) {
|
||||
for _, td := range testData {
|
||||
featureVersions, err := detector.Detect(td.Data)
|
||||
if assert.Nil(t, err) && assert.Len(t, featureVersions, len(td.FeatureVersions)) {
|
||||
for _, expectedFeatureVersion := range td.FeatureVersions {
|
||||
assert.Contains(t, featureVersions, expectedFeatureVersion)
|
||||
}
|
||||
}
|
||||
|
61
worker/detectors/namespace/alpinerelease/alpinerelease.go
Normal file
61
worker/detectors/namespace/alpinerelease/alpinerelease.go
Normal file
@ -0,0 +1,61 @@
|
||||
// Copyright 2016 clair authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package alpinerelease
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/coreos/clair/database"
|
||||
"github.com/coreos/clair/worker/detectors"
|
||||
)
|
||||
|
||||
const (
|
||||
osName = "alpine"
|
||||
alpineReleasePath = "etc/alpine-release"
|
||||
)
|
||||
|
||||
var versionRegexp = regexp.MustCompile(`^(\d)+\.(\d)+\.(\d)+$`)
|
||||
|
||||
func init() {
|
||||
detectors.RegisterNamespaceDetector("alpine-release", &detector{})
|
||||
}
|
||||
|
||||
// detector implements NamespaceDetector by reading the current version of
|
||||
// Alpine Linux from /etc/alpine-release.
|
||||
type detector struct{}
|
||||
|
||||
func (d *detector) Detect(data map[string][]byte) *database.Namespace {
|
||||
file, exists := data[alpineReleasePath]
|
||||
if exists {
|
||||
scanner := bufio.NewScanner(bytes.NewBuffer(file))
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
match := versionRegexp.FindStringSubmatch(line)
|
||||
if len(match) > 0 {
|
||||
versionNumbers := strings.Split(match[0], ".")
|
||||
return &database.Namespace{Name: osName + ":" + "v" + versionNumbers[0] + "." + versionNumbers[1]}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *detector) GetRequiredFiles() []string {
|
||||
return []string{alpineReleasePath}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
// Copyright 2016 clair authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package alpinerelease
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/coreos/clair/database"
|
||||
"github.com/coreos/clair/worker/detectors/namespace"
|
||||
)
|
||||
|
||||
func TestAlpineReleaseNamespaceDetection(t *testing.T) {
|
||||
testData := []namespace.TestData{
|
||||
{
|
||||
ExpectedNamespace: &database.Namespace{Name: "alpine:v3.3"},
|
||||
Data: map[string][]byte{"etc/alpine-release": []byte(`3.3.4`)},
|
||||
},
|
||||
{
|
||||
ExpectedNamespace: &database.Namespace{Name: "alpine:v3.4"},
|
||||
Data: map[string][]byte{"etc/alpine-release": []byte(`3.4.0`)},
|
||||
},
|
||||
{
|
||||
ExpectedNamespace: &database.Namespace{Name: "alpine:v0.3"},
|
||||
Data: map[string][]byte{"etc/alpine-release": []byte(`0.3.4`)},
|
||||
},
|
||||
{
|
||||
ExpectedNamespace: &database.Namespace{Name: "alpine:v0.3"},
|
||||
Data: map[string][]byte{"etc/alpine-release": []byte(`
|
||||
0.3.4
|
||||
`)},
|
||||
},
|
||||
{
|
||||
ExpectedNamespace: nil,
|
||||
Data: map[string][]byte{},
|
||||
},
|
||||
}
|
||||
|
||||
namespace.TestDetector(t, &detector{}, testData)
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2015 clair authors
|
||||
// Copyright 2016 clair authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@ -21,9 +21,10 @@ import (
|
||||
"github.com/coreos/clair/worker/detectors/namespace"
|
||||
)
|
||||
|
||||
var aptSourcesOSTests = []namespace.NamespaceTest{
|
||||
func TestAptSourcesNamespaceDetector(t *testing.T) {
|
||||
testData := []namespace.TestData{
|
||||
{
|
||||
ExpectedNamespace: database.Namespace{Name: "debian:unstable"},
|
||||
ExpectedNamespace: &database.Namespace{Name: "debian:unstable"},
|
||||
Data: map[string][]byte{
|
||||
"etc/os-release": []byte(
|
||||
`PRETTY_NAME="Debian GNU/Linux stretch/sid"
|
||||
@ -35,8 +36,7 @@ BUG_REPORT_URL="https://bugs.debian.org/"`),
|
||||
"etc/apt/sources.list": []byte(`deb http://httpredir.debian.org/debian unstable main`),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestAptSourcesNamespaceDetector(t *testing.T) {
|
||||
namespace.TestNamespaceDetector(t, &AptSourcesNamespaceDetector{}, aptSourcesOSTests)
|
||||
namespace.TestDetector(t, &AptSourcesNamespaceDetector{}, testData)
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2015 clair authors
|
||||
// Copyright 2016 clair authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@ -21,9 +21,10 @@ import (
|
||||
"github.com/coreos/clair/worker/detectors/namespace"
|
||||
)
|
||||
|
||||
var lsbReleaseOSTests = []namespace.NamespaceTest{
|
||||
func TestLsbReleaseNamespaceDetector(t *testing.T) {
|
||||
testData := []namespace.TestData{
|
||||
{
|
||||
ExpectedNamespace: database.Namespace{Name: "ubuntu:12.04"},
|
||||
ExpectedNamespace: &database.Namespace{Name: "ubuntu:12.04"},
|
||||
Data: map[string][]byte{
|
||||
"etc/lsb-release": []byte(
|
||||
`DISTRIB_ID=Ubuntu
|
||||
@ -33,7 +34,7 @@ DISTRIB_DESCRIPTION="Ubuntu 12.04 LTS"`),
|
||||
},
|
||||
},
|
||||
{ // We don't care about the minor version of Debian
|
||||
ExpectedNamespace: database.Namespace{Name: "debian:7"},
|
||||
ExpectedNamespace: &database.Namespace{Name: "debian:7"},
|
||||
Data: map[string][]byte{
|
||||
"etc/lsb-release": []byte(
|
||||
`DISTRIB_ID=Debian
|
||||
@ -42,8 +43,7 @@ DISTRIB_CODENAME=wheezy
|
||||
DISTRIB_DESCRIPTION="Debian 7.1"`),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestLsbReleaseNamespaceDetector(t *testing.T) {
|
||||
namespace.TestNamespaceDetector(t, &LsbReleaseNamespaceDetector{}, lsbReleaseOSTests)
|
||||
namespace.TestDetector(t, &LsbReleaseNamespaceDetector{}, testData)
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2015 clair authors
|
||||
// Copyright 2016 clair authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@ -21,9 +21,10 @@ import (
|
||||
"github.com/coreos/clair/worker/detectors/namespace"
|
||||
)
|
||||
|
||||
var osReleaseOSTests = []namespace.NamespaceTest{
|
||||
func TestOsReleaseNamespaceDetector(t *testing.T) {
|
||||
testData := []namespace.TestData{
|
||||
{
|
||||
ExpectedNamespace: database.Namespace{Name: "debian:8"},
|
||||
ExpectedNamespace: &database.Namespace{Name: "debian:8"},
|
||||
Data: map[string][]byte{
|
||||
"etc/os-release": []byte(
|
||||
`PRETTY_NAME="Debian GNU/Linux 8 (jessie)"
|
||||
@ -37,7 +38,7 @@ BUG_REPORT_URL="https://bugs.debian.org/"`),
|
||||
},
|
||||
},
|
||||
{
|
||||
ExpectedNamespace: database.Namespace{Name: "ubuntu:15.10"},
|
||||
ExpectedNamespace: &database.Namespace{Name: "ubuntu:15.10"},
|
||||
Data: map[string][]byte{
|
||||
"etc/os-release": []byte(
|
||||
`NAME="Ubuntu"
|
||||
@ -52,7 +53,7 @@ BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"`),
|
||||
},
|
||||
},
|
||||
{ // Doesn't have quotes around VERSION_ID
|
||||
ExpectedNamespace: database.Namespace{Name: "fedora:20"},
|
||||
ExpectedNamespace: &database.Namespace{Name: "fedora:20"},
|
||||
Data: map[string][]byte{
|
||||
"etc/os-release": []byte(
|
||||
`NAME=Fedora
|
||||
@ -70,8 +71,7 @@ REDHAT_SUPPORT_PRODUCT="Fedora"
|
||||
REDHAT_SUPPORT_PRODUCT_VERSION=20`),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestOsReleaseNamespaceDetector(t *testing.T) {
|
||||
namespace.TestNamespaceDetector(t, &OsReleaseNamespaceDetector{}, osReleaseOSTests)
|
||||
namespace.TestDetector(t, &OsReleaseNamespaceDetector{}, testData)
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2015 clair authors
|
||||
// Copyright 2016 clair authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@ -21,21 +21,21 @@ import (
|
||||
"github.com/coreos/clair/worker/detectors/namespace"
|
||||
)
|
||||
|
||||
var redhatReleaseTests = []namespace.NamespaceTest{
|
||||
func TestRedhatReleaseNamespaceDetector(t *testing.T) {
|
||||
testData := []namespace.TestData{
|
||||
{
|
||||
ExpectedNamespace: database.Namespace{Name: "centos:6"},
|
||||
ExpectedNamespace: &database.Namespace{Name: "centos:6"},
|
||||
Data: map[string][]byte{
|
||||
"etc/centos-release": []byte(`CentOS release 6.6 (Final)`),
|
||||
},
|
||||
},
|
||||
{
|
||||
ExpectedNamespace: database.Namespace{Name: "centos:7"},
|
||||
ExpectedNamespace: &database.Namespace{Name: "centos:7"},
|
||||
Data: map[string][]byte{
|
||||
"etc/system-release": []byte(`CentOS Linux release 7.1.1503 (Core)`),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestRedhatReleaseNamespaceDetector(t *testing.T) {
|
||||
namespace.TestNamespaceDetector(t, &RedhatReleaseNamespaceDetector{}, redhatReleaseTests)
|
||||
namespace.TestDetector(t, &RedhatReleaseNamespaceDetector{}, testData)
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2015 clair authors
|
||||
// Copyright 2016 clair authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@ -12,6 +12,8 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package namespace implements utilities common to implementations of
|
||||
// NamespaceDetector.
|
||||
package namespace
|
||||
|
||||
import (
|
||||
@ -22,13 +24,22 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type NamespaceTest struct {
|
||||
// TestData represents the data used to test an implementation of
|
||||
// NameSpaceDetector.
|
||||
type TestData struct {
|
||||
Data map[string][]byte
|
||||
ExpectedNamespace database.Namespace
|
||||
ExpectedNamespace *database.Namespace
|
||||
}
|
||||
|
||||
func TestNamespaceDetector(t *testing.T, detector detectors.NamespaceDetector, tests []NamespaceTest) {
|
||||
for _, test := range tests {
|
||||
assert.Equal(t, test.ExpectedNamespace, *detector.Detect(test.Data))
|
||||
// TestDetector runs a detector on each provided instance of TestData and
|
||||
// asserts the output to be equal to the expected output.
|
||||
func TestDetector(t *testing.T, detector detectors.NamespaceDetector, testData []TestData) {
|
||||
for _, td := range testData {
|
||||
detectedNamespace := detector.Detect(td.Data)
|
||||
if detectedNamespace == nil {
|
||||
assert.Equal(t, td.ExpectedNamespace, detectedNamespace)
|
||||
} else {
|
||||
assert.Equal(t, td.ExpectedNamespace.Name, detectedNamespace.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user