Clair is organized into many different software components all of which are dynamically registered at compile time.
All of these components can be found in the ext/
directory.
Driver Type | Functionality | Example |
---|---|---|
featurefmt | parses features of a particular format out of a layer | apk |
featurens | identifies whether a particular namespaces is applicable to a layer | alpine 3.5 |
imagefmt | determines the location of the root filesystem location for a layer | docker |
notification | implements the transport used to notify of vulnerability changes | webhook |
versionfmt | parses and compares version strings | rpm |
vulnmdsrc | fetches vulnerability metadata and appends them to vulnerabilities being processed | nvd |
vulnsrc | fetches vulnerabilities for a set of namespaces | alpine-sec-db |
Data Source | Data Collected | Format | License |
---|---|---|---|
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 |
Oracle Linux Security Data | Oracle Linux 5, 6, 7 namespaces | rpm | CVRF |
SUSE OVAL Descriptions | openSUSE, SUSE Linux Enterprise namespaces | rpm | CC-BY-NC-4.0 |
Alpine SecDB | Alpine 3.3, Alpine 3.4, Alpine 3.5 namespaces | apk | MIT |
NIST NVD | Generic Vulnerability Metadata | N/A | Public Domain |
In order to allow programmers to add additional behavior, Clair follows a pattern that Go programmers may recognize from the standard database/sql
library.
Each Driver Type defines an interface that must be implemented by drivers.
type DriverInterface interface {
Action() error
}
func RegisterDriver(name, DriverInterface) { ... }
Create a new Go package containing an implementation of the driver interface.
In the source file that implements this custom interface, create an init()
function that registers the driver.
func init() {
drivers.RegisterDriver("mydrivername", myDriverImplementation{})
}
// This line causes the Go compiler to enforce that myDriverImplementation
// implements the the DriverInterface at compile time.
var _ drivers.DriverInterface = myDriverImplementation{}
type myDriverImplementation struct{}
func (d myDriverImplementation) Action() error {
fmt.Println("Hello, Clair!")
return nil
}
The final step is to import the new driver in main.go
as _
in order ensure that the init()
function executes, thus registering your driver.
import (
...
_ "github.com/you/yourclairdriver"
)
If you believe what you've created can benefit others outside of your organization, please consider open sourcing it and creating a pull request to get it included by default.