зеркало из https://github.com/mozilla/scribe.git
Replacing database interactions with a much simpler naming scheme and calls through the Clair API
This commit is contained in:
Родитель
69bc11b133
Коммит
e1a49b3e2c
|
@ -13,7 +13,7 @@ import (
|
|||
)
|
||||
|
||||
type centosRelease struct {
|
||||
identifier int
|
||||
name string
|
||||
versionMatch string
|
||||
expression string
|
||||
filematch string
|
||||
|
@ -22,8 +22,8 @@ type centosRelease struct {
|
|||
const centosExpression = ".*CentOS.*(release \\d+)\\..*"
|
||||
|
||||
var centosReleases = []centosRelease{
|
||||
{platformCentos7, "release 7", centosExpression, "^centos-release$"},
|
||||
{platformCentos6, "release 6", centosExpression, "^centos-release$"},
|
||||
{"centos6", "release 6", centosExpression, "^centos-release$"},
|
||||
{"centos7", "release 7", centosExpression, "^centos-release$"},
|
||||
}
|
||||
|
||||
// The list of packages for this platform we will only consider the newest version for in the
|
||||
|
@ -80,7 +80,7 @@ func centosReleaseTest(platform supportedPlatform, doc *scribe.Document) (tid st
|
|||
// Set our match value on the test to the release string
|
||||
found := false
|
||||
for _, x := range centosReleases {
|
||||
if x.identifier == platform.platformID {
|
||||
if x.name == platform.name {
|
||||
found = true
|
||||
release = x
|
||||
break
|
||||
|
|
|
@ -1,60 +0,0 @@
|
|||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
//
|
||||
// Contributor:
|
||||
// - Aaron Meihm ameihm@mozilla.com
|
||||
|
||||
package main
|
||||
|
||||
func dbGetSupportedPlatforms() (ret []supportedPlatform, err error) {
|
||||
rows, err := dbconn.Query("SELECT id, name FROM namespace")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for rows.Next() {
|
||||
var (
|
||||
nsid int
|
||||
nsname string
|
||||
platform supportedPlatform
|
||||
)
|
||||
err = rows.Scan(&nsid, &nsname)
|
||||
if err != nil {
|
||||
rows.Close()
|
||||
return
|
||||
}
|
||||
platform, err = getPlatform(nsname)
|
||||
if err == nil {
|
||||
platform.clairNamespaceID = nsid
|
||||
ret = append(ret, platform)
|
||||
}
|
||||
}
|
||||
err = rows.Err()
|
||||
return
|
||||
}
|
||||
|
||||
func dbVulnsForPlatform(platform supportedPlatform) (ret []vuln, err error) {
|
||||
rows, err := dbconn.Query(`SELECT f.name, vff.version, v.name,
|
||||
v.severity, v.link, v.description
|
||||
FROM feature f
|
||||
JOIN vulnerability_fixedin_feature vff ON (vff.feature_id = f.id)
|
||||
JOIN vulnerability v ON (v.id = vff.vulnerability_id)
|
||||
WHERE f.namespace_id = $1
|
||||
ORDER BY f.name`, platform.clairNamespaceID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for rows.Next() {
|
||||
var newent vuln
|
||||
err = rows.Scan(&newent.pkgName, &newent.fixedInVersion,
|
||||
&newent.name, &newent.severity, &newent.link,
|
||||
&newent.description)
|
||||
if err != nil {
|
||||
rows.Close()
|
||||
return
|
||||
}
|
||||
ret = append(ret, newent)
|
||||
}
|
||||
err = rows.Err()
|
||||
return
|
||||
}
|
|
@ -9,7 +9,6 @@ package main
|
|||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
|
@ -18,25 +17,18 @@ import (
|
|||
"os"
|
||||
)
|
||||
|
||||
const (
|
||||
platformCentos6 = iota
|
||||
platformCentos7
|
||||
)
|
||||
|
||||
// Our list of platforms we will support policy generation for, this maps the
|
||||
// platform constants to clair namespace identifiers
|
||||
type supportedPlatform struct {
|
||||
platformID int
|
||||
name string
|
||||
clairNamespace string
|
||||
clairNamespaceID int // Populated upon query of the database
|
||||
releaseTest func(supportedPlatform, *scribe.Document) (string, error)
|
||||
pkgNewest func(string) bool
|
||||
name string
|
||||
clairNamespace string
|
||||
releaseTest func(supportedPlatform, *scribe.Document) (string, error)
|
||||
pkgNewest func(string) bool
|
||||
}
|
||||
|
||||
var supportedPlatforms = []supportedPlatform{
|
||||
{platformCentos6, "centos6", "centos:6", 0, centosReleaseTest, centosOnlyNewest},
|
||||
{platformCentos7, "centos7", "centos:7", 0, centosReleaseTest, centosOnlyNewest},
|
||||
{"centos6", "centos:6", centosReleaseTest, centosOnlyNewest},
|
||||
{"centos7", "centos:7", centosReleaseTest, centosOnlyNewest},
|
||||
}
|
||||
|
||||
// Given a clair namespace, return the supportedPlatform entry for it if it is
|
||||
|
@ -52,70 +44,23 @@ func getPlatform(clairNamespace string) (ret supportedPlatform, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
type vuln struct {
|
||||
name string
|
||||
fixedInVersion string
|
||||
pkgName string
|
||||
severity string
|
||||
link string
|
||||
description string
|
||||
}
|
||||
|
||||
// Describes global configuration
|
||||
type config struct {
|
||||
Database struct {
|
||||
DBName string
|
||||
DBHost string
|
||||
DBUser string
|
||||
DBPassword string
|
||||
DBPort string
|
||||
}
|
||||
}
|
||||
|
||||
var dbconn *sql.DB
|
||||
var cfg config
|
||||
|
||||
// Set any configuration based on environment variables
|
||||
func configFromEnv() error {
|
||||
envvar := os.Getenv("PGHOST")
|
||||
if envvar != "" {
|
||||
cfg.Database.DBHost = envvar
|
||||
}
|
||||
envvar = os.Getenv("PGUSER")
|
||||
if envvar != "" {
|
||||
cfg.Database.DBUser = envvar
|
||||
}
|
||||
envvar = os.Getenv("PGPASSWORD")
|
||||
if envvar != "" {
|
||||
cfg.Database.DBPassword = envvar
|
||||
}
|
||||
envvar = os.Getenv("PGDATABASE")
|
||||
if envvar != "" {
|
||||
cfg.Database.DBName = envvar
|
||||
}
|
||||
envvar = os.Getenv("PGPORT")
|
||||
if envvar != "" {
|
||||
cfg.Database.DBPort = envvar
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func dbInit() (err error) {
|
||||
connstr := fmt.Sprintf("dbname=%v host=%v user=%v password=%v port=%v sslmode=disable",
|
||||
cfg.Database.DBName, cfg.Database.DBHost, cfg.Database.DBUser,
|
||||
cfg.Database.DBPassword, cfg.Database.DBPort)
|
||||
dbconn, err = sql.Open("postgres", connstr)
|
||||
return
|
||||
type VulnInfo struct {
|
||||
Package string `json:"package"`
|
||||
Vulnerability string `json:"vulnerability"`
|
||||
Severity string `json:"severity"`
|
||||
Description string `json:"description"`
|
||||
FixedInVersion string `json:"fixedInVersion"`
|
||||
InfoLink string `json:"link"`
|
||||
}
|
||||
|
||||
// Generate a test identifier; this needs to be unique in the document. Here we
|
||||
// just use a few elements from the vulnerability and platform and return an MD5
|
||||
// digest.
|
||||
func generateTestID(v vuln, p supportedPlatform) (string, error) {
|
||||
func generateTestID(v VulnInfo, p supportedPlatform) (string, error) {
|
||||
h := md5.New()
|
||||
h.Write([]byte(v.name))
|
||||
h.Write([]byte(v.Vulnerability))
|
||||
h.Write([]byte(p.name))
|
||||
h.Write([]byte(v.pkgName))
|
||||
h.Write([]byte(v.Package))
|
||||
return fmt.Sprintf("%x", h.Sum(nil)), nil
|
||||
}
|
||||
|
||||
|
@ -125,15 +70,11 @@ func generatePolicy(p string) error {
|
|||
doc scribe.Document
|
||||
)
|
||||
// First make sure this is a supported platform, and this will also get us the namespace ID
|
||||
platforms, err := dbGetSupportedPlatforms()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
supported := false
|
||||
for _, x := range platforms {
|
||||
if x.name == p {
|
||||
for _, pform := range supportedPlatforms {
|
||||
if pform.name == p {
|
||||
platform = pform
|
||||
supported = true
|
||||
platform = x
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -148,8 +89,8 @@ func generatePolicy(p string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// Get all vulnerabilities for the platform from the database
|
||||
vulns, err := dbVulnsForPlatform(platform)
|
||||
// Get all vulnerabilities for the platform from the Clair API
|
||||
vulns, err := vulnsInNamespace(platform.clairNamespace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -166,23 +107,23 @@ func generatePolicy(p string) error {
|
|||
// the package we want to lookup, if so we don't need to add a second
|
||||
// one
|
||||
found := false
|
||||
objname = fmt.Sprintf("obj-package-%v", x.pkgName)
|
||||
objname = fmt.Sprintf("obj-package-%v", x.Package)
|
||||
for _, y := range doc.Objects {
|
||||
if y.Package.Name == x.pkgName {
|
||||
if y.Package.Name == x.Package {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
newobj.Object = objname
|
||||
newobj.Package.Name = x.pkgName
|
||||
newobj.Package.OnlyNewest = platform.pkgNewest(x.pkgName)
|
||||
newobj.Package.Name = x.Package
|
||||
newobj.Package.OnlyNewest = platform.pkgNewest(x.Package)
|
||||
doc.Objects = append(doc.Objects, newobj)
|
||||
}
|
||||
|
||||
newtest.TestName = x.name
|
||||
newtest.TestName = x.Vulnerability
|
||||
newtest.Object = objname
|
||||
newtest.EVR.Value = x.fixedInVersion
|
||||
newtest.EVR.Value = x.FixedInVersion
|
||||
newtest.EVR.Operation = "<"
|
||||
newtest.If = append(newtest.If, reltestid)
|
||||
newtest.TestID, err = generateTestID(x, platform)
|
||||
|
@ -190,11 +131,11 @@ func generatePolicy(p string) error {
|
|||
return err
|
||||
}
|
||||
// Add some tags to the test we can use when we parse results
|
||||
pkgtag := scribe.TestTag{Key: "package", Value: x.pkgName}
|
||||
pkgtag := scribe.TestTag{Key: "package", Value: x.Package}
|
||||
newtest.Tags = append(newtest.Tags, pkgtag)
|
||||
sevtag := scribe.TestTag{Key: "severity", Value: x.severity}
|
||||
sevtag := scribe.TestTag{Key: "severity", Value: x.Severity}
|
||||
newtest.Tags = append(newtest.Tags, sevtag)
|
||||
linktag := scribe.TestTag{Key: "link", Value: x.link}
|
||||
linktag := scribe.TestTag{Key: "link", Value: x.InfoLink}
|
||||
newtest.Tags = append(newtest.Tags, linktag)
|
||||
doc.Tests = append(doc.Tests, newtest)
|
||||
}
|
||||
|
@ -221,27 +162,11 @@ func main() {
|
|||
genPlatform = flag.Args()[0]
|
||||
}
|
||||
|
||||
err = configFromEnv()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error reading config from environment: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
err = dbInit()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error initializing database: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if showVersions {
|
||||
platforms, err := dbGetSupportedPlatforms()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error retrieving platforms: %v\n", err)
|
||||
os.Exit(1)
|
||||
for _, platform := range supportedPlatforms {
|
||||
fmt.Println(platform.name)
|
||||
}
|
||||
for _, x := range platforms {
|
||||
fmt.Printf("%v\n", x.name)
|
||||
}
|
||||
os.Exit(0)
|
||||
return
|
||||
}
|
||||
|
||||
if genPlatform == "" {
|
||||
|
|
Загрузка…
Ссылка в новой задаче