f759dd54c0
Feature's source feature string is directly stored in the database instead of having the parent pointer to simplify the database.
324 lines
8.0 KiB
Go
324 lines
8.0 KiB
Go
// Copyright 2017 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 database
|
|
|
|
import (
|
|
"database/sql/driver"
|
|
"encoding/json"
|
|
"time"
|
|
|
|
"github.com/coreos/clair/pkg/pagination"
|
|
)
|
|
|
|
// Ancestry is a manifest that keeps all layers in an image in order.
|
|
type Ancestry struct {
|
|
// Name is a globally unique value for a set of layers. This is often the
|
|
// sha256 digest of an OCI/Docker manifest.
|
|
Name string
|
|
// By contains the processors that are used when computing the
|
|
// content of this ancestry.
|
|
By []Detector
|
|
// Layers should be ordered and i_th layer is the parent of i+1_th layer in
|
|
// the slice.
|
|
Layers []AncestryLayer
|
|
}
|
|
|
|
// Valid checks if the ancestry is compliant to spec.
|
|
func (a *Ancestry) Valid() bool {
|
|
if a == nil {
|
|
return false
|
|
}
|
|
|
|
if a.Name == "" {
|
|
return false
|
|
}
|
|
|
|
for _, d := range a.By {
|
|
if !d.Valid() {
|
|
return false
|
|
}
|
|
}
|
|
|
|
for _, l := range a.Layers {
|
|
if !l.Valid() {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// AncestryLayer is a layer with all detected namespaced features.
|
|
type AncestryLayer struct {
|
|
// Hash is the sha-256 tarsum on the layer's blob content.
|
|
Hash string
|
|
// Features are the features introduced by this layer when it was
|
|
// processed.
|
|
Features []AncestryFeature
|
|
}
|
|
|
|
// Valid checks if the Ancestry Layer is compliant to the spec.
|
|
func (l *AncestryLayer) Valid() bool {
|
|
if l == nil {
|
|
return false
|
|
}
|
|
|
|
if l.Hash == "" {
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// GetFeatures returns the Ancestry's features.
|
|
func (l *AncestryLayer) GetFeatures() []NamespacedFeature {
|
|
nsf := make([]NamespacedFeature, 0, len(l.Features))
|
|
for _, f := range l.Features {
|
|
nsf = append(nsf, f.NamespacedFeature)
|
|
}
|
|
|
|
return nsf
|
|
}
|
|
|
|
// AncestryFeature is a namespaced feature with the detectors used to
|
|
// find this feature.
|
|
type AncestryFeature struct {
|
|
NamespacedFeature
|
|
|
|
// FeatureBy is the detector that detected the feature.
|
|
FeatureBy Detector
|
|
// NamespaceBy is the detector that detected the namespace.
|
|
NamespaceBy Detector
|
|
}
|
|
|
|
// Layer is a layer with all the detected features and namespaces.
|
|
type Layer struct {
|
|
// Hash is the sha-256 tarsum on the layer's blob content.
|
|
Hash string
|
|
// By contains a list of detectors scanned this Layer.
|
|
By []Detector
|
|
Namespaces []LayerNamespace
|
|
Features []LayerFeature
|
|
}
|
|
|
|
func (l *Layer) GetFeatures() []Feature {
|
|
features := make([]Feature, 0, len(l.Features))
|
|
for _, f := range l.Features {
|
|
features = append(features, f.Feature)
|
|
}
|
|
|
|
return features
|
|
}
|
|
|
|
func (l *Layer) GetNamespaces() []Namespace {
|
|
namespaces := make([]Namespace, 0, len(l.Namespaces))
|
|
for _, ns := range l.Namespaces {
|
|
namespaces = append(namespaces, ns.Namespace)
|
|
}
|
|
|
|
return namespaces
|
|
}
|
|
|
|
// LayerNamespace is a namespace with detection information.
|
|
type LayerNamespace struct {
|
|
Namespace
|
|
|
|
// By is the detector found the namespace.
|
|
By Detector
|
|
}
|
|
|
|
// LayerFeature is a feature with detection information.
|
|
type LayerFeature struct {
|
|
Feature
|
|
|
|
// By is the detector found the feature.
|
|
By Detector
|
|
}
|
|
|
|
// Namespace is the contextual information around features.
|
|
//
|
|
// e.g. Debian:7, NodeJS.
|
|
type Namespace struct {
|
|
Name string
|
|
VersionFormat string
|
|
}
|
|
|
|
// Feature represents a package detected in a layer but the namespace is not
|
|
// determined.
|
|
//
|
|
// e.g. Name: Libssl1.0, Version: 1.0, Name: Openssl, Version: 1.0, VersionFormat: dpkg.
|
|
// dpkg is the version format of the installer package manager, which in this
|
|
// case could be dpkg or apk.
|
|
type Feature struct {
|
|
Name string
|
|
Version string
|
|
SourceName string
|
|
SourceVersion string
|
|
VersionFormat string
|
|
}
|
|
|
|
// NamespacedFeature is a feature with determined namespace and can be affected
|
|
// by vulnerabilities.
|
|
//
|
|
// e.g. OpenSSL 1.0 dpkg Debian:7.
|
|
type NamespacedFeature struct {
|
|
Feature
|
|
|
|
Namespace Namespace
|
|
}
|
|
|
|
// AffectedNamespacedFeature is a namespaced feature affected by the
|
|
// vulnerabilities with fixed-in versions for this feature.
|
|
type AffectedNamespacedFeature struct {
|
|
NamespacedFeature
|
|
|
|
AffectedBy []VulnerabilityWithFixedIn
|
|
}
|
|
|
|
// VulnerabilityWithFixedIn is used for AffectedNamespacedFeature to retrieve
|
|
// the affecting vulnerabilities and the fixed-in versions for the feature.
|
|
type VulnerabilityWithFixedIn struct {
|
|
Vulnerability
|
|
|
|
FixedInVersion string
|
|
}
|
|
|
|
// AffectedFeature is used to determine whether a namespaced feature is affected
|
|
// by a Vulnerability. Namespace and Feature Name is unique. Affected Feature is
|
|
// bound to vulnerability.
|
|
type AffectedFeature struct {
|
|
Namespace Namespace
|
|
FeatureName string
|
|
// FixedInVersion is known next feature version that's not affected by the
|
|
// vulnerability. Empty FixedInVersion means the unaffected version is
|
|
// unknown.
|
|
FixedInVersion string
|
|
// AffectedVersion contains the version range to determine whether or not a
|
|
// feature is affected.
|
|
AffectedVersion string
|
|
}
|
|
|
|
// VulnerabilityID is an identifier for every vulnerability. Every vulnerability
|
|
// has unique namespace and name.
|
|
type VulnerabilityID struct {
|
|
Name string
|
|
Namespace string
|
|
}
|
|
|
|
// Vulnerability represents CVE or similar vulnerability reports.
|
|
type Vulnerability struct {
|
|
Name string
|
|
Namespace Namespace
|
|
|
|
Description string
|
|
Link string
|
|
Severity Severity
|
|
|
|
Metadata MetadataMap
|
|
}
|
|
|
|
// VulnerabilityWithAffected is an vulnerability with all known affected
|
|
// features.
|
|
type VulnerabilityWithAffected struct {
|
|
Vulnerability
|
|
|
|
Affected []AffectedFeature
|
|
}
|
|
|
|
// PagedVulnerableAncestries is a vulnerability with a page of affected
|
|
// ancestries each with a special index attached for streaming purpose. The
|
|
// current page number and next page number are for navigate.
|
|
type PagedVulnerableAncestries struct {
|
|
Vulnerability
|
|
|
|
// Affected is a map of special indexes to Ancestries, which the pair
|
|
// should be unique in a stream. Every indexes in the map should be larger
|
|
// than previous page.
|
|
Affected map[int]string
|
|
|
|
Limit int
|
|
Current pagination.Token
|
|
Next pagination.Token
|
|
|
|
// End signals the end of the pages.
|
|
End bool
|
|
}
|
|
|
|
// NotificationHook is a message sent to another service to inform of a change
|
|
// to a Vulnerability or the Ancestries affected by a Vulnerability. It contains
|
|
// the name of a notification that should be read and marked as read via the
|
|
// API.
|
|
type NotificationHook struct {
|
|
Name string
|
|
|
|
Created time.Time
|
|
Notified time.Time
|
|
Deleted time.Time
|
|
}
|
|
|
|
// VulnerabilityNotification is a notification for vulnerability changes.
|
|
type VulnerabilityNotification struct {
|
|
NotificationHook
|
|
|
|
Old *Vulnerability
|
|
New *Vulnerability
|
|
}
|
|
|
|
// VulnerabilityNotificationWithVulnerable is a notification for vulnerability
|
|
// changes with vulnerable ancestries.
|
|
type VulnerabilityNotificationWithVulnerable struct {
|
|
NotificationHook
|
|
|
|
Old *PagedVulnerableAncestries
|
|
New *PagedVulnerableAncestries
|
|
}
|
|
|
|
// MetadataMap is for storing the metadata returned by vulnerability database.
|
|
type MetadataMap map[string]interface{}
|
|
|
|
// NullableAffectedNamespacedFeature is an affectednamespacedfeature with
|
|
// whether it's found in datastore.
|
|
type NullableAffectedNamespacedFeature struct {
|
|
AffectedNamespacedFeature
|
|
|
|
Valid bool
|
|
}
|
|
|
|
// NullableVulnerability is a vulnerability with whether the vulnerability is
|
|
// found in datastore.
|
|
type NullableVulnerability struct {
|
|
VulnerabilityWithAffected
|
|
|
|
Valid bool
|
|
}
|
|
|
|
func (mm *MetadataMap) Scan(value interface{}) error {
|
|
if value == nil {
|
|
return nil
|
|
}
|
|
|
|
// github.com/lib/pq decodes TEXT/VARCHAR fields into strings.
|
|
val, ok := value.(string)
|
|
if !ok {
|
|
panic("got type other than []byte from database")
|
|
}
|
|
return json.Unmarshal([]byte(val), mm)
|
|
}
|
|
|
|
func (mm *MetadataMap) Value() (driver.Value, error) {
|
|
json, err := json.Marshal(*mm)
|
|
return string(json), err
|
|
}
|