update api, update testcases
Signed-off-by: liang chenye <liangchenye@huawei.com>
This commit is contained in:
parent
0a997145ed
commit
3c3a96e71d
@ -129,18 +129,18 @@ Server: clair
|
||||
{
|
||||
"Layer": {
|
||||
"Name": "17675ec01494d651e1ccf81dc9cf63959ebfeed4f978fddb1666b6ead008ed52",
|
||||
"NamespaceName": "debian:8",
|
||||
"Namespaces": [{"Name": "debian", "Version": "8"}],
|
||||
"ParentName": "140f9bdfeb9784cf8730e9dab5dd12fbd704151cf555ac8cae650451794e5ac2",
|
||||
"IndexedByVersion": 1,
|
||||
"Features": [
|
||||
{
|
||||
"Name": "coreutils",
|
||||
"NamespaceName": "debian:8",
|
||||
"Namespace": {"Name": "debian", "Version": "8"},
|
||||
"Version": "8.23-4",
|
||||
"Vulnerabilities": [
|
||||
{
|
||||
"Name": "CVE-2014-9471",
|
||||
"NamespaceName": "debian:8",
|
||||
"Namespace": {"Name": "debian", "Version": "8"},
|
||||
"Description": "The parse_datetime function in GNU coreutils allows remote attackers to cause a denial of service (crash) or possibly execute arbitrary code via a crafted date string, as demonstrated by the \"--date=TZ=\"123\"345\" @1\" string to the touch or date command.",
|
||||
"Link": "https://security-tracker.debian.org/tracker/CVE-2014-9471",
|
||||
"Severity": "Low",
|
||||
@ -196,15 +196,15 @@ Server: clair
|
||||
|
||||
{
|
||||
"Namespaces": [
|
||||
{ "Name": "debian:8" },
|
||||
{ "Name": "debian:9" }
|
||||
{ "ID": "gAAAAABXTQKgma_TLKq0wr1D6wVB507N3fi9wsWMUypYOSXTDVxQ8OR5L5S6PqZ9Wh0IzWojnVmlspyTL4cyjytyra7U9vAHMA==", "Name": "debian", "Version": "8" },
|
||||
{ "ID": "gAAAAABXTQPZmOFlOR8zzuhv8Y2fD7HbUY8O6z_Py2vibB9uveWZoycSY1HDIkcf7lN_UDynom4kWubFS4h9KBCbWwjNIqacsw==", "Name": "debian", "Version": "9" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Vulnerabilities
|
||||
|
||||
#### GET /namespaces/`:nsName`/vulnerabilities
|
||||
#### GET /namespaces/`:nsID`/vulnerabilities
|
||||
|
||||
###### Description
|
||||
|
||||
@ -220,7 +220,7 @@ The GET route for the Vulnerabilities resource displays the vulnerabilities data
|
||||
###### Example Request
|
||||
|
||||
```json
|
||||
GET http://localhost:6060/v1/namespaces/debian%3A8/vulnerabilities?limit=2 HTTP/1.1
|
||||
GET http://localhost:6060/v1/namespaces/gAAAAABXTQKgma_TLKq0wr1D6wVB507N3fi9wsWMUypYOSXTDVxQ8OR5L5S6PqZ9Wh0IzWojnVmlspyTL4cyjytyra7U9vAHMA==/vulnerabilities?limit=2 HTTP/1.1
|
||||
```
|
||||
|
||||
###### Example Response
|
||||
@ -234,14 +234,14 @@ Server: clair
|
||||
"Vulnerabilities": [
|
||||
{
|
||||
"Name": "CVE-1999-1332",
|
||||
"NamespaceName": "debian:8",
|
||||
"Namespace": {"Name": "debian", "Version": "8"},
|
||||
"Description": "gzexe in the gzip package on Red Hat Linux 5.0 and earlier allows local users to overwrite files of other users via a symlink attack on a temporary file.",
|
||||
"Link": "https://security-tracker.debian.org/tracker/CVE-1999-1332",
|
||||
"Severity": "Low"
|
||||
},
|
||||
{
|
||||
"Name": "CVE-1999-1572",
|
||||
"NamespaceName": "debian:8",
|
||||
"Namespace": {"Name": "debian", "Version": "8"},
|
||||
"Description": "cpio on FreeBSD 2.1.0, Debian GNU/Linux 3.0, and possibly other operating systems, uses a 0 umask when creating files using the -O (archive) or -F options, which creates the files with mode 0666 and allows local users to read or overwrite those files.",
|
||||
"Link": "https://security-tracker.debian.org/tracker/CVE-1999-1572",
|
||||
"Severity": "Low",
|
||||
@ -259,7 +259,7 @@ Server: clair
|
||||
}
|
||||
```
|
||||
|
||||
#### POST /namespaces/`:name`/vulnerabilities
|
||||
#### POST /namespaces/`:nsID`/vulnerabilities
|
||||
|
||||
###### Description
|
||||
|
||||
@ -268,12 +268,12 @@ The POST route for the Vulnerabilities resource creates a new Vulnerability.
|
||||
###### Example Request
|
||||
|
||||
```json
|
||||
POST http://localhost:6060/v1/namespaces/debian%3A8/vulnerabilities HTTP/1.1
|
||||
POST http://localhost:6060/v1/namespaces/gAAAAABXTQKgma_TLKq0wr1D6wVB507N3fi9wsWMUypYOSXTDVxQ8OR5L5S6PqZ9Wh0IzWojnVmlspyTL4cyjytyra7U9vAHMA==/vulnerabilities HTTP/1.1
|
||||
|
||||
{
|
||||
"Vulnerability": {
|
||||
"Name": "CVE-2014-9471",
|
||||
"NamespaceName": "debian:8",
|
||||
"Namespace": {"Name": "debian", "Version": "8"},
|
||||
"Link": "https://security-tracker.debian.org/tracker/CVE-2014-9471",
|
||||
"Description": "The parse_datetime function in GNU coreutils allows remote attackers to cause a denial of service (crash) or possibly execute arbitrary code via a crafted date string, as demonstrated by the \"--date=TZ=\"123\"345\" @1\" string to the touch or date command.",
|
||||
"Severity": "Low",
|
||||
@ -288,7 +288,7 @@ POST http://localhost:6060/v1/namespaces/debian%3A8/vulnerabilities HTTP/1.1
|
||||
"FixedIn": [
|
||||
{
|
||||
"Name": "coreutils",
|
||||
"NamespaceName": "debian:8",
|
||||
"Namespace": {"Name": "debian", "Version": "8"},
|
||||
"Version": "8.23-1"
|
||||
}
|
||||
]
|
||||
@ -306,7 +306,7 @@ Server: clair
|
||||
{
|
||||
"Vulnerability": {
|
||||
"Name": "CVE-2014-9471",
|
||||
"NamespaceName": "debian:8",
|
||||
"Namespace": {"Name": "debian", "Version": "8"},
|
||||
"Link": "https://security-tracker.debian.org/tracker/CVE-2014-9471",
|
||||
"Description": "The parse_datetime function in GNU coreutils allows remote attackers to cause a denial of service (crash) or possibly execute arbitrary code via a crafted date string, as demonstrated by the \"--date=TZ=\"123\"345\" @1\" string to the touch or date command.",
|
||||
"Severity": "Low",
|
||||
@ -321,7 +321,7 @@ Server: clair
|
||||
"FixedIn": [
|
||||
{
|
||||
"Name": "coreutils",
|
||||
"NamespaceName": "debian:8",
|
||||
"Namespace": {"Name": "debian", "Version": "8"},
|
||||
"Version": "8.23-1"
|
||||
}
|
||||
]
|
||||
@ -329,7 +329,7 @@ Server: clair
|
||||
}
|
||||
```
|
||||
|
||||
#### GET /namespaces/`:nsName`/vulnerabilities/`:vulnName`
|
||||
#### GET /namespaces/`:nsID`/vulnerabilities/`:vulnName`
|
||||
|
||||
###### Description
|
||||
|
||||
@ -344,7 +344,7 @@ The GET route for the Vulnerabilities resource displays the current data for a g
|
||||
###### Example Request
|
||||
|
||||
```json
|
||||
GET http://localhost:6060/v1/namespaces/debian%3A8/vulnerabilities/CVE-2014-9471?fixedIn HTTP/1.1
|
||||
GET http://localhost:6060/v1/namespaces/gAAAAABXTQKgma_TLKq0wr1D6wVB507N3fi9wsWMUypYOSXTDVxQ8OR5L5S6PqZ9Wh0IzWojnVmlspyTL4cyjytyra7U9vAHMA==/vulnerabilities/CVE-2014-9471?fixedIn HTTP/1.1
|
||||
```
|
||||
|
||||
###### Example Response
|
||||
@ -357,7 +357,7 @@ Server: clair
|
||||
{
|
||||
"Vulnerability": {
|
||||
"Name": "CVE-2014-9471",
|
||||
"NamespaceName": "debian:8",
|
||||
"Namespace": {"Name": "debian", "Version": "8"},
|
||||
"Link": "https://security-tracker.debian.org/tracker/CVE-2014-9471",
|
||||
"Description": "The parse_datetime function in GNU coreutils allows remote attackers to cause a denial of service (crash) or possibly execute arbitrary code via a crafted date string, as demonstrated by the \"--date=TZ=\"123\"345\" @1\" string to the touch or date command.",
|
||||
"Severity": "Low",
|
||||
@ -372,7 +372,7 @@ Server: clair
|
||||
"FixedIn": [
|
||||
{
|
||||
"Name": "coreutils",
|
||||
"NamespaceName": "debian:8",
|
||||
"Namespace": {"Name": "debian", "Version": "8"},
|
||||
"Version": "8.23-1"
|
||||
}
|
||||
]
|
||||
@ -380,7 +380,7 @@ Server: clair
|
||||
}
|
||||
```
|
||||
|
||||
#### PUT /namespaces/`:nsName`/vulnerabilities/`:vulnName`
|
||||
#### PUT /namespaces/`:nsID`/vulnerabilities/`:vulnName`
|
||||
|
||||
###### Description
|
||||
|
||||
@ -392,12 +392,12 @@ If this vulnerability was inserted by a Fetcher, changes may be lost when the Fe
|
||||
###### Example Request
|
||||
|
||||
```json
|
||||
PUT http://localhost:6060/v1/namespaces/debian%3A8/vulnerabilities/CVE-2014-9471
|
||||
PUT http://localhost:6060/v1/namespaces/gAAAAABXTQKgma_TLKq0wr1D6wVB507N3fi9wsWMUypYOSXTDVxQ8OR5L5S6PqZ9Wh0IzWojnVmlspyTL4cyjytyra7U9vAHMA==/vulnerabilities/CVE-2014-9471
|
||||
|
||||
{
|
||||
"Vulnerability": {
|
||||
"Name": "CVE-2014-9471",
|
||||
"NamespaceName": "debian:8",
|
||||
"Namespace": {"Name": "debian", "Version": "8"},
|
||||
"Link": "https://security-tracker.debian.org/tracker/CVE-2014-9471",
|
||||
"Description": "The parse_datetime function in GNU coreutils allows remote attackers to cause a denial of service (crash) or possibly execute arbitrary code via a crafted date string, as demonstrated by the \"--date=TZ=\"123\"345\" @1\" string to the touch or date command.",
|
||||
"Severity": "Low",
|
||||
@ -422,7 +422,7 @@ Server: clair
|
||||
{
|
||||
"Vulnerability": {
|
||||
"Name": "CVE-2014-9471",
|
||||
"NamespaceName": "debian:8",
|
||||
"Namespace": {"Name": "debian", "Version": "8"},
|
||||
"Link": "https://security-tracker.debian.org/tracker/CVE-2014-9471",
|
||||
"Description": "The parse_datetime function in GNU coreutils allows remote attackers to cause a denial of service (crash) or possibly execute arbitrary code via a crafted date string, as demonstrated by the \"--date=TZ=\"123\"345\" @1\" string to the touch or date command.",
|
||||
"Severity": "Low",
|
||||
@ -439,7 +439,7 @@ Server: clair
|
||||
```
|
||||
|
||||
|
||||
#### DELETE /namespaces/`:nsName`/vulnerabilities/`:vulnName`
|
||||
#### DELETE /namespaces/`:nsID`/vulnerabilities/`:vulnName`
|
||||
|
||||
###### Description
|
||||
|
||||
@ -449,7 +449,7 @@ If this vulnerability was inserted by a Fetcher, it may be re-inserted when the
|
||||
###### Example Request
|
||||
|
||||
```json
|
||||
GET http://localhost:6060/v1/namespaces/debian%3A8/vulnerabilities/CVE-2014-9471 HTTP/1.1
|
||||
GET http://localhost:6060/v1/namespaces/gAAAAABXTQKgma_TLKq0wr1D6wVB507N3fi9wsWMUypYOSXTDVxQ8OR5L5S6PqZ9Wh0IzWojnVmlspyTL4cyjytyra7U9vAHMA==/vulnerabilities/CVE-2014-9471 HTTP/1.1
|
||||
```
|
||||
|
||||
###### Example Response
|
||||
@ -461,7 +461,7 @@ Server: clair
|
||||
|
||||
## Fixes
|
||||
|
||||
#### GET /namespaces/`:nsName`/vulnerabilities/`:vulnName`/fixes
|
||||
#### GET /namespaces/`:nsID`/vulnerabilities/`:vulnName`/fixes
|
||||
|
||||
###### Description
|
||||
|
||||
@ -470,7 +470,7 @@ The GET route for the Fixes resource displays the list of Features that fix the
|
||||
###### Example Request
|
||||
|
||||
```json
|
||||
GET http://localhost:6060/v1/namespaces/debian%3A8/vulnerabilities/CVE-2014-9471/fixes HTTP/1.1
|
||||
GET http://localhost:6060/v1/namespaces/gAAAAABXTQKgma_TLKq0wr1D6wVB507N3fi9wsWMUypYOSXTDVxQ8OR5L5S6PqZ9Wh0IzWojnVmlspyTL4cyjytyra7U9vAHMA==/vulnerabilities/CVE-2014-9471/fixes HTTP/1.1
|
||||
```
|
||||
|
||||
###### Example Response
|
||||
@ -484,14 +484,14 @@ Server: clair
|
||||
"Features": [
|
||||
{
|
||||
"Name": "coreutils",
|
||||
"NamespaceName": "debian:8",
|
||||
"Namespace": {"Name": "debian", "Version": "8"},
|
||||
"Version": "8.23-1"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### PUT /namespaces/`:nsName`/vulnerabilities/`:vulnName`/fixes/`:featureName`
|
||||
#### PUT /namespaces/`:nsID`/vulnerabilities/`:vulnName`/fixes/`:featureName`
|
||||
|
||||
###### Description
|
||||
|
||||
@ -500,12 +500,12 @@ The PUT route for the Fixes resource updates a Feature that is the fix for a giv
|
||||
###### Example Request
|
||||
|
||||
```json
|
||||
PUT http://localhost:6060/v1/namespaces/debian%3A8/vulnerabilities/CVE-2014-9471/fixes/coreutils HTTP/1.1
|
||||
PUT http://localhost:6060/v1/namespaces/gAAAAABXTQKgma_TLKq0wr1D6wVB507N3fi9wsWMUypYOSXTDVxQ8OR5L5S6PqZ9Wh0IzWojnVmlspyTL4cyjytyra7U9vAHMA==/vulnerabilities/CVE-2014-9471/fixes/coreutils HTTP/1.1
|
||||
|
||||
{
|
||||
"Feature": {
|
||||
"Name": "coreutils",
|
||||
"NamespaceName": "debian:8",
|
||||
"Namespace": {"Name": "debian", "Version": "8"},
|
||||
"Version": "4.24-9"
|
||||
}
|
||||
}
|
||||
@ -520,13 +520,13 @@ Server: clair
|
||||
{
|
||||
"Feature": {
|
||||
"Name": "coreutils",
|
||||
"NamespaceName": "debian:8",
|
||||
"Namespace": {"Name": "debian", "Version": "8"},
|
||||
"Version": "4.24-9"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### DELETE /namespaces/`:nsName`/vulnerabilities/`:vulnName`/fixes/`:featureName`
|
||||
#### DELETE /namespaces/`:nsID`/vulnerabilities/`:vulnName`/fixes/`:featureName`
|
||||
|
||||
###### Description
|
||||
|
||||
@ -535,7 +535,7 @@ The DELETE route for the Fixes resource removes a Feature as fix for the given V
|
||||
###### Example Request
|
||||
|
||||
```json
|
||||
DELETE http://localhost:6060/v1/namespaces/debian%3A8/vulnerabilities/CVE-2014-9471/fixes/coreutils
|
||||
DELETE http://localhost:6060/v1/namespaces/gAAAAABXTQKgma_TLKq0wr1D6wVB507N3fi9wsWMUypYOSXTDVxQ8OR5L5S6PqZ9Wh0IzWojnVmlspyTL4cyjytyra7U9vAHMA==/vulnerabilities/CVE-2014-9471/fixes/coreutils
|
||||
```
|
||||
|
||||
###### Example Response
|
||||
@ -585,13 +585,13 @@ Server: clair
|
||||
"New": {
|
||||
"Vulnerability": {
|
||||
"Name": "CVE-TEST",
|
||||
"NamespaceName": "debian:8",
|
||||
"Namespace": {"Name": "debian", "Version": "8"},
|
||||
"Description": "New CVE",
|
||||
"Severity": "Low",
|
||||
"FixedIn": [
|
||||
{
|
||||
"Name": "grep",
|
||||
"NamespaceName": "debian:8",
|
||||
"Namespace": {"Name": "debian", "Version": "8"},
|
||||
"Version": "2.25"
|
||||
}
|
||||
]
|
||||
@ -604,7 +604,7 @@ Server: clair
|
||||
"Old": {
|
||||
"Vulnerability": {
|
||||
"Name": "CVE-TEST",
|
||||
"NamespaceName": "debian:8",
|
||||
"Namespace": {"Name": "debian", "Version": "8"},
|
||||
"Description": "New CVE",
|
||||
"Severity": "Low",
|
||||
"FixedIn": []
|
||||
|
@ -35,7 +35,7 @@ type Error struct {
|
||||
|
||||
type Layer struct {
|
||||
Name string `json:"Name,omitempty"`
|
||||
NamespaceName string `json:"NamespaceName,omitempty"`
|
||||
Namespaces []Namespace `json:"Namespaces,omitempty"`
|
||||
Path string `json:"Path,omitempty"`
|
||||
Headers map[string]string `json:"Headers,omitempty"`
|
||||
ParentName string `json:"ParentName,omitempty"`
|
||||
@ -54,27 +54,27 @@ func LayerFromDatabaseModel(dbLayer database.Layer, withFeatures, withVulnerabil
|
||||
layer.ParentName = dbLayer.Parent.Name
|
||||
}
|
||||
|
||||
if dbLayer.Namespace != nil {
|
||||
layer.NamespaceName = dbLayer.Namespace.Name
|
||||
for _, namespace := range dbLayer.Namespaces {
|
||||
layer.Namespaces = append(layer.Namespaces, Namespace{Name: namespace.Name, Version: namespace.Version.String()})
|
||||
}
|
||||
|
||||
if withFeatures || withVulnerabilities && dbLayer.Features != nil {
|
||||
for _, dbFeatureVersion := range dbLayer.Features {
|
||||
feature := Feature{
|
||||
Name: dbFeatureVersion.Feature.Name,
|
||||
NamespaceName: dbFeatureVersion.Feature.Namespace.Name,
|
||||
Version: dbFeatureVersion.Version.String(),
|
||||
AddedBy: dbFeatureVersion.AddedBy.Name,
|
||||
Name: dbFeatureVersion.Feature.Name,
|
||||
Namespace: Namespace{Name: dbFeatureVersion.Feature.Namespace.Name, Version: dbFeatureVersion.Feature.Namespace.Version.String()},
|
||||
Version: dbFeatureVersion.Version.String(),
|
||||
AddedBy: dbFeatureVersion.AddedBy.Name,
|
||||
}
|
||||
|
||||
for _, dbVuln := range dbFeatureVersion.AffectedBy {
|
||||
vuln := Vulnerability{
|
||||
Name: dbVuln.Name,
|
||||
NamespaceName: dbVuln.Namespace.Name,
|
||||
Description: dbVuln.Description,
|
||||
Link: dbVuln.Link,
|
||||
Severity: string(dbVuln.Severity),
|
||||
Metadata: dbVuln.Metadata,
|
||||
Name: dbVuln.Name,
|
||||
Namespace: Namespace{Name: dbVuln.Namespace.Name, Version: dbVuln.Namespace.Version.String()},
|
||||
Description: dbVuln.Description,
|
||||
Link: dbVuln.Link,
|
||||
Severity: string(dbVuln.Severity),
|
||||
Metadata: dbVuln.Metadata,
|
||||
}
|
||||
|
||||
if dbVuln.FixedBy != types.MaxVersion {
|
||||
@ -90,18 +90,20 @@ func LayerFromDatabaseModel(dbLayer database.Layer, withFeatures, withVulnerabil
|
||||
}
|
||||
|
||||
type Namespace struct {
|
||||
Name string `json:"Name,omitempty"`
|
||||
ID string `json:"ID,omitempty"`
|
||||
Name string `json:"Name,omitempty"`
|
||||
Version string `json:"Version,omitempty"`
|
||||
}
|
||||
|
||||
type Vulnerability struct {
|
||||
Name string `json:"Name,omitempty"`
|
||||
NamespaceName string `json:"NamespaceName,omitempty"`
|
||||
Description string `json:"Description,omitempty"`
|
||||
Link string `json:"Link,omitempty"`
|
||||
Severity string `json:"Severity,omitempty"`
|
||||
Metadata map[string]interface{} `json:"Metadata,omitempty"`
|
||||
FixedBy string `json:"FixedBy,omitempty"`
|
||||
FixedIn []Feature `json:"FixedIn,omitempty"`
|
||||
Name string `json:"Name,omitempty"`
|
||||
Namespace Namespace `json:"Namespace,omitempty"`
|
||||
Description string `json:"Description,omitempty"`
|
||||
Link string `json:"Link,omitempty"`
|
||||
Severity string `json:"Severity,omitempty"`
|
||||
Metadata map[string]interface{} `json:"Metadata,omitempty"`
|
||||
FixedBy string `json:"FixedBy,omitempty"`
|
||||
FixedIn []Feature `json:"FixedIn,omitempty"`
|
||||
}
|
||||
|
||||
func (v Vulnerability) DatabaseModel() (database.Vulnerability, error) {
|
||||
@ -110,6 +112,11 @@ func (v Vulnerability) DatabaseModel() (database.Vulnerability, error) {
|
||||
return database.Vulnerability{}, errors.New("Invalid severity")
|
||||
}
|
||||
|
||||
version, err := types.NewVersion(v.Namespace.Version)
|
||||
if err != nil {
|
||||
return database.Vulnerability{}, errors.New("Invalid namespace version")
|
||||
}
|
||||
|
||||
var dbFeatures []database.FeatureVersion
|
||||
for _, feature := range v.FixedIn {
|
||||
dbFeature, err := feature.DatabaseModel()
|
||||
@ -122,7 +129,7 @@ func (v Vulnerability) DatabaseModel() (database.Vulnerability, error) {
|
||||
|
||||
return database.Vulnerability{
|
||||
Name: v.Name,
|
||||
Namespace: database.Namespace{Name: v.NamespaceName},
|
||||
Namespace: database.Namespace{Name: v.Namespace.Name, Version: version},
|
||||
Description: v.Description,
|
||||
Link: v.Link,
|
||||
Severity: severity,
|
||||
@ -133,12 +140,12 @@ func (v Vulnerability) DatabaseModel() (database.Vulnerability, error) {
|
||||
|
||||
func VulnerabilityFromDatabaseModel(dbVuln database.Vulnerability, withFixedIn bool) Vulnerability {
|
||||
vuln := Vulnerability{
|
||||
Name: dbVuln.Name,
|
||||
NamespaceName: dbVuln.Namespace.Name,
|
||||
Description: dbVuln.Description,
|
||||
Link: dbVuln.Link,
|
||||
Severity: string(dbVuln.Severity),
|
||||
Metadata: dbVuln.Metadata,
|
||||
Name: dbVuln.Name,
|
||||
Namespace: Namespace{Name: dbVuln.Namespace.Name, Version: dbVuln.Namespace.Version.String()},
|
||||
Description: dbVuln.Description,
|
||||
Link: dbVuln.Link,
|
||||
Severity: string(dbVuln.Severity),
|
||||
Metadata: dbVuln.Metadata,
|
||||
}
|
||||
|
||||
if withFixedIn {
|
||||
@ -152,7 +159,7 @@ func VulnerabilityFromDatabaseModel(dbVuln database.Vulnerability, withFixedIn b
|
||||
|
||||
type Feature struct {
|
||||
Name string `json:"Name,omitempty"`
|
||||
NamespaceName string `json:"NamespaceName,omitempty"`
|
||||
Namespace Namespace `json:"Namespace,omitempty"`
|
||||
Version string `json:"Version,omitempty"`
|
||||
Vulnerabilities []Vulnerability `json:"Vulnerabilities,omitempty"`
|
||||
AddedBy string `json:"AddedBy,omitempty"`
|
||||
@ -165,10 +172,10 @@ func FeatureFromDatabaseModel(dbFeatureVersion database.FeatureVersion) Feature
|
||||
}
|
||||
|
||||
return Feature{
|
||||
Name: dbFeatureVersion.Feature.Name,
|
||||
NamespaceName: dbFeatureVersion.Feature.Namespace.Name,
|
||||
Version: versionStr,
|
||||
AddedBy: dbFeatureVersion.AddedBy.Name,
|
||||
Name: dbFeatureVersion.Feature.Name,
|
||||
Namespace: Namespace{Name: dbFeatureVersion.Feature.Namespace.Name, Version: dbFeatureVersion.Feature.Namespace.Version.String()},
|
||||
Version: versionStr,
|
||||
AddedBy: dbFeatureVersion.AddedBy.Name,
|
||||
}
|
||||
}
|
||||
|
||||
@ -184,10 +191,15 @@ func (f Feature) DatabaseModel() (database.FeatureVersion, error) {
|
||||
}
|
||||
}
|
||||
|
||||
nsVersion, err := types.NewVersion(f.Namespace.Version)
|
||||
if err != nil {
|
||||
return database.FeatureVersion{}, err
|
||||
}
|
||||
|
||||
return database.FeatureVersion{
|
||||
Feature: database.Feature{
|
||||
Name: f.Name,
|
||||
Namespace: database.Namespace{Name: f.NamespaceName},
|
||||
Namespace: database.Namespace{Name: f.Namespace.Name, Version: nsVersion},
|
||||
},
|
||||
Version: version,
|
||||
}, nil
|
||||
|
@ -34,16 +34,16 @@ func NewRouter(ctx *context.RouteContext) *httprouter.Router {
|
||||
router.GET("/namespaces", context.HTTPHandler(getNamespaces, ctx))
|
||||
|
||||
// Vulnerabilities
|
||||
router.GET("/namespaces/:namespaceName/vulnerabilities", context.HTTPHandler(getVulnerabilities, ctx))
|
||||
router.POST("/namespaces/:namespaceName/vulnerabilities", context.HTTPHandler(postVulnerability, ctx))
|
||||
router.GET("/namespaces/:namespaceName/vulnerabilities/:vulnerabilityName", context.HTTPHandler(getVulnerability, ctx))
|
||||
router.PUT("/namespaces/:namespaceName/vulnerabilities/:vulnerabilityName", context.HTTPHandler(putVulnerability, ctx))
|
||||
router.DELETE("/namespaces/:namespaceName/vulnerabilities/:vulnerabilityName", context.HTTPHandler(deleteVulnerability, ctx))
|
||||
router.GET("/namespaces/:namespaceID/vulnerabilities", context.HTTPHandler(getVulnerabilities, ctx))
|
||||
router.POST("/namespaces/:namespaceID/vulnerabilities", context.HTTPHandler(postVulnerability, ctx))
|
||||
router.GET("/namespaces/:namespaceID/vulnerabilities/:vulnerabilityName", context.HTTPHandler(getVulnerability, ctx))
|
||||
router.PUT("/namespaces/:namespaceID/vulnerabilities/:vulnerabilityName", context.HTTPHandler(putVulnerability, ctx))
|
||||
router.DELETE("/namespaces/:namespaceID/vulnerabilities/:vulnerabilityName", context.HTTPHandler(deleteVulnerability, ctx))
|
||||
|
||||
// Fixes
|
||||
router.GET("/namespaces/:namespaceName/vulnerabilities/:vulnerabilityName/fixes", context.HTTPHandler(getFixes, ctx))
|
||||
router.PUT("/namespaces/:namespaceName/vulnerabilities/:vulnerabilityName/fixes/:fixName", context.HTTPHandler(putFix, ctx))
|
||||
router.DELETE("/namespaces/:namespaceName/vulnerabilities/:vulnerabilityName/fixes/:fixName", context.HTTPHandler(deleteFix, ctx))
|
||||
router.GET("/namespaces/:namespaceID/vulnerabilities/:vulnerabilityName/fixes", context.HTTPHandler(getFixes, ctx))
|
||||
router.PUT("/namespaces/:namespaceID/vulnerabilities/:vulnerabilityName/fixes/:fixName", context.HTTPHandler(putFix, ctx))
|
||||
router.DELETE("/namespaces/:namespaceID/vulnerabilities/:vulnerabilityName/fixes/:fixName", context.HTTPHandler(deleteFix, ctx))
|
||||
|
||||
// Notifications
|
||||
router.GET("/notifications/:notificationName", context.HTTPHandler(getNotification, ctx))
|
||||
|
@ -179,7 +179,12 @@ func getNamespaces(w http.ResponseWriter, r *http.Request, p httprouter.Params,
|
||||
}
|
||||
var namespaces []Namespace
|
||||
for _, dbNamespace := range dbNamespaces {
|
||||
namespaces = append(namespaces, Namespace{Name: dbNamespace.Name})
|
||||
if namespaceIDBytes, err := tokenMarshal(dbNamespace.ID, ctx.Config.PaginationKey); err != nil {
|
||||
writeResponse(w, r, http.StatusInternalServerError, NamespaceEnvelope{Error: &Error{err.Error()}})
|
||||
return getNamespacesRoute, http.StatusInternalServerError
|
||||
} else {
|
||||
namespaces = append(namespaces, Namespace{ID: string(namespaceIDBytes), Name: dbNamespace.Name, Version: dbNamespace.Version.String()})
|
||||
}
|
||||
}
|
||||
|
||||
writeResponse(w, r, http.StatusOK, NamespaceEnvelope{Namespaces: &namespaces})
|
||||
@ -213,13 +218,13 @@ func getVulnerabilities(w http.ResponseWriter, r *http.Request, p httprouter.Par
|
||||
}
|
||||
}
|
||||
|
||||
namespace := p.ByName("namespaceName")
|
||||
if namespace == "" {
|
||||
writeResponse(w, r, http.StatusBadRequest, VulnerabilityEnvelope{Error: &Error{"namespace should not be empty"}})
|
||||
namespaceID := 0
|
||||
if err = tokenUnmarshal(p.ByName("namespaceID"), ctx.Config.PaginationKey, &namespaceID); err != nil {
|
||||
writeResponse(w, r, http.StatusBadRequest, VulnerabilityEnvelope{Error: &Error{"invalid namespace id format: " + err.Error()}})
|
||||
return getNotificationRoute, http.StatusBadRequest
|
||||
}
|
||||
|
||||
dbVulns, nextPage, err := ctx.Store.ListVulnerabilities(namespace, limit, page)
|
||||
dbVulns, nextPage, err := ctx.Store.ListVulnerabilities(namespaceID, limit, page)
|
||||
if err == cerrors.ErrNotFound {
|
||||
writeResponse(w, r, http.StatusNotFound, VulnerabilityEnvelope{Error: &Error{err.Error()}})
|
||||
return getVulnerabilityRoute, http.StatusNotFound
|
||||
@ -286,7 +291,13 @@ func postVulnerability(w http.ResponseWriter, r *http.Request, p httprouter.Para
|
||||
func getVulnerability(w http.ResponseWriter, r *http.Request, p httprouter.Params, ctx *context.RouteContext) (string, int) {
|
||||
_, withFixedIn := r.URL.Query()["fixedIn"]
|
||||
|
||||
dbVuln, err := ctx.Store.FindVulnerability(p.ByName("namespaceName"), p.ByName("vulnerabilityName"))
|
||||
namespaceID := 0
|
||||
if err := tokenUnmarshal(p.ByName("namespaceID"), ctx.Config.PaginationKey, &namespaceID); err != nil {
|
||||
writeResponse(w, r, http.StatusBadRequest, VulnerabilityEnvelope{Error: &Error{"invalid namespace id format: " + err.Error()}})
|
||||
return getVulnerabilityRoute, http.StatusBadRequest
|
||||
}
|
||||
|
||||
dbVuln, err := ctx.Store.FindVulnerability(namespaceID, p.ByName("vulnerabilityName"))
|
||||
if err == cerrors.ErrNotFound {
|
||||
writeResponse(w, r, http.StatusNotFound, VulnerabilityEnvelope{Error: &Error{err.Error()}})
|
||||
return getVulnerabilityRoute, http.StatusNotFound
|
||||
@ -302,6 +313,12 @@ func getVulnerability(w http.ResponseWriter, r *http.Request, p httprouter.Param
|
||||
}
|
||||
|
||||
func putVulnerability(w http.ResponseWriter, r *http.Request, p httprouter.Params, ctx *context.RouteContext) (string, int) {
|
||||
namespaceID := 0
|
||||
if err := tokenUnmarshal(p.ByName("namespaceID"), ctx.Config.PaginationKey, &namespaceID); err != nil {
|
||||
writeResponse(w, r, http.StatusBadRequest, VulnerabilityEnvelope{Error: &Error{"invalid namespace id format: " + err.Error()}})
|
||||
return putVulnerabilityRoute, http.StatusBadRequest
|
||||
}
|
||||
|
||||
request := VulnerabilityEnvelope{}
|
||||
err := decodeJSON(r, &request)
|
||||
if err != nil {
|
||||
@ -325,7 +342,7 @@ func putVulnerability(w http.ResponseWriter, r *http.Request, p httprouter.Param
|
||||
return putVulnerabilityRoute, http.StatusBadRequest
|
||||
}
|
||||
|
||||
vuln.Namespace.Name = p.ByName("namespaceName")
|
||||
vuln.Namespace.ID = namespaceID
|
||||
vuln.Name = p.ByName("vulnerabilityName")
|
||||
|
||||
err = ctx.Store.InsertVulnerabilities([]database.Vulnerability{vuln}, true)
|
||||
@ -345,7 +362,13 @@ func putVulnerability(w http.ResponseWriter, r *http.Request, p httprouter.Param
|
||||
}
|
||||
|
||||
func deleteVulnerability(w http.ResponseWriter, r *http.Request, p httprouter.Params, ctx *context.RouteContext) (string, int) {
|
||||
err := ctx.Store.DeleteVulnerability(p.ByName("namespaceName"), p.ByName("vulnerabilityName"))
|
||||
namespaceID := 0
|
||||
if err := tokenUnmarshal(p.ByName("namespaceID"), ctx.Config.PaginationKey, &namespaceID); err != nil {
|
||||
writeResponse(w, r, http.StatusBadRequest, VulnerabilityEnvelope{Error: &Error{"invalid namespace id format: " + err.Error()}})
|
||||
return deleteVulnerabilityRoute, http.StatusBadRequest
|
||||
}
|
||||
|
||||
err := ctx.Store.DeleteVulnerability(namespaceID, p.ByName("vulnerabilityName"))
|
||||
if err == cerrors.ErrNotFound {
|
||||
writeResponse(w, r, http.StatusNotFound, VulnerabilityEnvelope{Error: &Error{err.Error()}})
|
||||
return deleteVulnerabilityRoute, http.StatusNotFound
|
||||
@ -359,7 +382,13 @@ func deleteVulnerability(w http.ResponseWriter, r *http.Request, p httprouter.Pa
|
||||
}
|
||||
|
||||
func getFixes(w http.ResponseWriter, r *http.Request, p httprouter.Params, ctx *context.RouteContext) (string, int) {
|
||||
dbVuln, err := ctx.Store.FindVulnerability(p.ByName("namespaceName"), p.ByName("vulnerabilityName"))
|
||||
namespaceID := 0
|
||||
if err := tokenUnmarshal(p.ByName("namespaceID"), ctx.Config.PaginationKey, &namespaceID); err != nil {
|
||||
writeResponse(w, r, http.StatusBadRequest, VulnerabilityEnvelope{Error: &Error{"invalid namespace id format: " + err.Error()}})
|
||||
return getFixesRoute, http.StatusBadRequest
|
||||
}
|
||||
|
||||
dbVuln, err := ctx.Store.FindVulnerability(namespaceID, p.ByName("vulnerabilityName"))
|
||||
if err == cerrors.ErrNotFound {
|
||||
writeResponse(w, r, http.StatusNotFound, FeatureEnvelope{Error: &Error{err.Error()}})
|
||||
return getFixesRoute, http.StatusNotFound
|
||||
@ -374,6 +403,12 @@ func getFixes(w http.ResponseWriter, r *http.Request, p httprouter.Params, ctx *
|
||||
}
|
||||
|
||||
func putFix(w http.ResponseWriter, r *http.Request, p httprouter.Params, ctx *context.RouteContext) (string, int) {
|
||||
namespaceID := 0
|
||||
if err := tokenUnmarshal(p.ByName("namespaceID"), ctx.Config.PaginationKey, &namespaceID); err != nil {
|
||||
writeResponse(w, r, http.StatusBadRequest, FeatureEnvelope{Error: &Error{"invalid namespace id format: " + err.Error()}})
|
||||
return putFixRoute, http.StatusBadRequest
|
||||
}
|
||||
|
||||
request := FeatureEnvelope{}
|
||||
err := decodeJSON(r, &request)
|
||||
if err != nil {
|
||||
@ -397,7 +432,7 @@ func putFix(w http.ResponseWriter, r *http.Request, p httprouter.Params, ctx *co
|
||||
return putFixRoute, http.StatusBadRequest
|
||||
}
|
||||
|
||||
err = ctx.Store.InsertVulnerabilityFixes(p.ByName("vulnerabilityNamespace"), p.ByName("vulnerabilityName"), []database.FeatureVersion{dbFix})
|
||||
err = ctx.Store.InsertVulnerabilityFixes(namespaceID, p.ByName("vulnerabilityName"), []database.FeatureVersion{dbFix})
|
||||
if err != nil {
|
||||
switch err.(type) {
|
||||
case *cerrors.ErrBadRequest:
|
||||
@ -418,7 +453,13 @@ func putFix(w http.ResponseWriter, r *http.Request, p httprouter.Params, ctx *co
|
||||
}
|
||||
|
||||
func deleteFix(w http.ResponseWriter, r *http.Request, p httprouter.Params, ctx *context.RouteContext) (string, int) {
|
||||
err := ctx.Store.DeleteVulnerabilityFix(p.ByName("vulnerabilityNamespace"), p.ByName("vulnerabilityName"), p.ByName("fixName"))
|
||||
namespaceID := 0
|
||||
if err := tokenUnmarshal(p.ByName("namespaceID"), ctx.Config.PaginationKey, &namespaceID); err != nil {
|
||||
writeResponse(w, r, http.StatusBadRequest, FeatureEnvelope{Error: &Error{"invalid namespace id format: " + err.Error()}})
|
||||
return deleteFixRoute, http.StatusBadRequest
|
||||
}
|
||||
|
||||
err := ctx.Store.DeleteVulnerabilityFix(namespaceID, p.ByName("vulnerabilityName"), p.ByName("fixName"))
|
||||
if err == cerrors.ErrNotFound {
|
||||
writeResponse(w, r, http.StatusNotFound, FeatureEnvelope{Error: &Error{err.Error()}})
|
||||
return deleteFixRoute, http.StatusNotFound
|
||||
|
@ -67,6 +67,8 @@ type Datastore interface {
|
||||
// # Namespace
|
||||
// ListNamespaces returns the entire list of known Namespaces.
|
||||
ListNamespaces() ([]Namespace, error)
|
||||
// GetNamespaceID returns the id by name and version.
|
||||
GetNamespaceID(Namespace) (int, error)
|
||||
|
||||
// # Layer
|
||||
// InsertLayer stores a Layer in the database.
|
||||
@ -93,7 +95,7 @@ type Datastore interface {
|
||||
// The Limit and page parameters are used to paginate the return list.
|
||||
// The first given page should be 0. The function will then return the next available page.
|
||||
// If there is no more page, -1 has to be returned.
|
||||
ListVulnerabilities(namespace Namespace, limit int, page int) ([]Vulnerability, int, error)
|
||||
ListVulnerabilities(namespaceID int, limit int, page int) ([]Vulnerability, int, error)
|
||||
|
||||
// InsertVulnerabilities stores the given Vulnerabilities in the database, updating them if
|
||||
// necessary. A vulnerability is uniquely identified by its Namespace and its Name.
|
||||
@ -110,22 +112,22 @@ type Datastore interface {
|
||||
InsertVulnerabilities(vulnerabilities []Vulnerability, createNotification bool) error
|
||||
|
||||
// FindVulnerability retrieves a Vulnerability from the database, including the FixedIn list.
|
||||
FindVulnerability(namespace Namespace, name string) (Vulnerability, error)
|
||||
FindVulnerability(namespaceID int, name string) (Vulnerability, error)
|
||||
|
||||
// DeleteVulnerability removes a Vulnerability from the database.
|
||||
// It has to create a Notification that will contain the old Vulnerability.
|
||||
DeleteVulnerability(namespace Namespace, name string) error
|
||||
DeleteVulnerability(namespaceID int, name string) error
|
||||
|
||||
// InsertVulnerabilityFixes adds new FixedIn Feature or update the Versions of existing ones to
|
||||
// the specified Vulnerability in the database.
|
||||
// It has has to create a Notification that will contain the old and the updated Vulnerability.
|
||||
InsertVulnerabilityFixes(vulnerabilityNamespace Namespace, vulnerabilityName string, fixes []FeatureVersion) error
|
||||
InsertVulnerabilityFixes(vulnerabilityNamespaceID int, vulnerabilityName string, fixes []FeatureVersion) error
|
||||
|
||||
// DeleteVulnerabilityFix removes a FixedIn Feature from the specified Vulnerability in the
|
||||
// database. It can be used to store the fact that a Vulnerability no longer affects the given
|
||||
// Feature in any Version.
|
||||
// It has has to create a Notification that will contain the old and the updated Vulnerability.
|
||||
DeleteVulnerabilityFix(vulnerabilityNamespace Namespace, vulnerabilityName, featureName string) error
|
||||
DeleteVulnerabilityFix(vulnerabilityNamespaceID int, vulnerabilityName, featureName string) error
|
||||
|
||||
// # Notification
|
||||
// GetAvailableNotification returns the Name, Created, Notified and Deleted fields of a
|
||||
|
@ -20,15 +20,16 @@ import "time"
|
||||
// The default behavior of each method is to simply panic.
|
||||
type MockDatastore struct {
|
||||
FctListNamespaces func() ([]Namespace, error)
|
||||
FctGetNamespaceID func(namespace Namespace) (int, error)
|
||||
FctInsertLayer func(Layer) error
|
||||
FctFindLayer func(name string, withFeatures, withVulnerabilities bool) (Layer, error)
|
||||
FctDeleteLayer func(name string) error
|
||||
FctListVulnerabilities func(namespace Namespace, limit int, page int) ([]Vulnerability, int, error)
|
||||
FctListVulnerabilities func(namespaceID int, limit int, page int) ([]Vulnerability, int, error)
|
||||
FctInsertVulnerabilities func(vulnerabilities []Vulnerability, createNotification bool) error
|
||||
FctFindVulnerability func(namespace Namespace, name string) (Vulnerability, error)
|
||||
FctDeleteVulnerability func(namespace Namespace, name string) error
|
||||
FctInsertVulnerabilityFixes func(vulnerabilityNamespace Namespace, vulnerabilityName string, fixes []FeatureVersion) error
|
||||
FctDeleteVulnerabilityFix func(vulnerabilityNamespace Namespace, vulnerabilityName, featureName string) error
|
||||
FctFindVulnerability func(namespaceID int, name string) (Vulnerability, error)
|
||||
FctDeleteVulnerability func(namespaceID int, name string) error
|
||||
FctInsertVulnerabilityFixes func(vulnerabilityNamespaceID int, vulnerabilityName string, fixes []FeatureVersion) error
|
||||
FctDeleteVulnerabilityFix func(vulnerabilityNamespaceID int, vulnerabilityName, featureName string) error
|
||||
FctGetAvailableNotification func(renotifyInterval time.Duration) (VulnerabilityNotification, error)
|
||||
FctGetNotification func(name string, limit int, page VulnerabilityNotificationPageNumber) (VulnerabilityNotification, VulnerabilityNotificationPageNumber, error)
|
||||
FctSetNotificationNotified func(name string) error
|
||||
@ -49,6 +50,13 @@ func (mds *MockDatastore) ListNamespaces() ([]Namespace, error) {
|
||||
panic("required mock function not implemented")
|
||||
}
|
||||
|
||||
func (mds *MockDatastore) GetNamespaceID(namespace Namespace) (int, error) {
|
||||
if mds.FctGetNamespaceID != nil {
|
||||
return mds.FctGetNamespaceID(namespace)
|
||||
}
|
||||
panic("required mock function not implemented")
|
||||
}
|
||||
|
||||
func (mds *MockDatastore) InsertLayer(layer Layer) error {
|
||||
if mds.FctInsertLayer != nil {
|
||||
return mds.FctInsertLayer(layer)
|
||||
@ -70,9 +78,9 @@ func (mds *MockDatastore) DeleteLayer(name string) error {
|
||||
panic("required mock function not implemented")
|
||||
}
|
||||
|
||||
func (mds *MockDatastore) ListVulnerabilities(namespace Namespace, limit int, page int) ([]Vulnerability, int, error) {
|
||||
func (mds *MockDatastore) ListVulnerabilities(namespaceID int, limit int, page int) ([]Vulnerability, int, error) {
|
||||
if mds.FctListVulnerabilities != nil {
|
||||
return mds.FctListVulnerabilities(namespace, limit, page)
|
||||
return mds.FctListVulnerabilities(namespaceID, limit, page)
|
||||
}
|
||||
panic("required mock function not implemented")
|
||||
}
|
||||
@ -84,30 +92,30 @@ func (mds *MockDatastore) InsertVulnerabilities(vulnerabilities []Vulnerability,
|
||||
panic("required mock function not implemented")
|
||||
}
|
||||
|
||||
func (mds *MockDatastore) FindVulnerability(namespace Namespace, name string) (Vulnerability, error) {
|
||||
func (mds *MockDatastore) FindVulnerability(namespaceID int, name string) (Vulnerability, error) {
|
||||
if mds.FctFindVulnerability != nil {
|
||||
return mds.FctFindVulnerability(namespace, name)
|
||||
return mds.FctFindVulnerability(namespaceID, name)
|
||||
}
|
||||
panic("required mock function not implemented")
|
||||
}
|
||||
|
||||
func (mds *MockDatastore) DeleteVulnerability(namespace Namespace, name string) error {
|
||||
func (mds *MockDatastore) DeleteVulnerability(namespaceID int, name string) error {
|
||||
if mds.FctDeleteVulnerability != nil {
|
||||
return mds.FctDeleteVulnerability(namespace, name)
|
||||
return mds.FctDeleteVulnerability(namespaceID, name)
|
||||
}
|
||||
panic("required mock function not implemented")
|
||||
}
|
||||
|
||||
func (mds *MockDatastore) InsertVulnerabilityFixes(vulnerabilityNamespace Namespace, vulnerabilityName string, fixes []FeatureVersion) error {
|
||||
func (mds *MockDatastore) InsertVulnerabilityFixes(vulnerabilityNamespaceID int, vulnerabilityName string, fixes []FeatureVersion) error {
|
||||
if mds.FctInsertVulnerabilityFixes != nil {
|
||||
return mds.FctInsertVulnerabilityFixes(vulnerabilityNamespace, vulnerabilityName, fixes)
|
||||
return mds.FctInsertVulnerabilityFixes(vulnerabilityNamespaceID, vulnerabilityName, fixes)
|
||||
}
|
||||
panic("required mock function not implemented")
|
||||
}
|
||||
|
||||
func (mds *MockDatastore) DeleteVulnerabilityFix(vulnerabilityNamespace Namespace, vulnerabilityName, featureName string) error {
|
||||
func (mds *MockDatastore) DeleteVulnerabilityFix(vulnerabilityNamespaceID int, vulnerabilityName, featureName string) error {
|
||||
if mds.FctDeleteVulnerabilityFix != nil {
|
||||
return mds.FctDeleteVulnerabilityFix(vulnerabilityNamespace, vulnerabilityName, featureName)
|
||||
return mds.FctDeleteVulnerabilityFix(vulnerabilityNamespaceID, vulnerabilityName, featureName)
|
||||
}
|
||||
panic("required mock function not implemented")
|
||||
}
|
||||
|
@ -21,13 +21,13 @@ var DebianReleasesMapping = map[string]string{
|
||||
"wheezy": "7",
|
||||
"jessie": "8",
|
||||
"stretch": "9",
|
||||
"sid": "unstable",
|
||||
"sid": "10",
|
||||
|
||||
// Class names
|
||||
"oldstable": "7",
|
||||
"stable": "8",
|
||||
"testing": "9",
|
||||
"unstable": "unstable",
|
||||
"unstable": "10",
|
||||
}
|
||||
|
||||
// UbuntuReleasesMapping translates Ubuntu code names to version numbers
|
||||
|
@ -52,28 +52,6 @@ func (pgSQL *pgSQL) FindLayer(name string, withFeatures, withVulnerabilities boo
|
||||
Model: database.Model{ID: int(parentID.Int64)},
|
||||
Name: parentName.String,
|
||||
}
|
||||
|
||||
// Find its parent's namespaces
|
||||
t = time.Now()
|
||||
rows, err := pgSQL.Query(searchLayerNamespace, parentID)
|
||||
observeQueryTime("FindLayer", "searchParentLayerNamespace", t)
|
||||
if err != nil {
|
||||
return layer, handleError("searchLayerNamespace", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
var pn database.Namespace
|
||||
|
||||
err = rows.Scan(&pn.ID, &pn.Name, &pn.Version)
|
||||
if err != nil {
|
||||
return layer, handleError("searchLayerNamespace.Scan()", err)
|
||||
}
|
||||
layer.Parent.Namespaces = append(layer.Parent.Namespaces, pn)
|
||||
}
|
||||
if err = rows.Err(); err != nil {
|
||||
return layer, handleError("searchLayerNamespace.Rows()", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Find its namespaces
|
||||
|
@ -208,23 +208,29 @@ func testInsertLayerTree(t *testing.T, datastore database.Datastore) {
|
||||
},
|
||||
// This layer changes the namespace and adds Features.
|
||||
{
|
||||
Name: "TestInsertLayer3",
|
||||
Parent: &database.Layer{Name: "TestInsertLayer2"},
|
||||
Name: "TestInsertLayer3",
|
||||
Parent: &database.Layer{Name: "TestInsertLayer2",
|
||||
Namespaces: []database.Namespace{testInsertLayerNamespace1},
|
||||
},
|
||||
Namespaces: []database.Namespace{testInsertLayerNamespace2},
|
||||
Features: []database.FeatureVersion{f1, f2, f3},
|
||||
},
|
||||
// This layer covers the case where the last layer doesn't provide any new Feature.
|
||||
{
|
||||
Name: "TestInsertLayer4a",
|
||||
Parent: &database.Layer{Name: "TestInsertLayer3"},
|
||||
Name: "TestInsertLayer4a",
|
||||
Parent: &database.Layer{Name: "TestInsertLayer3",
|
||||
Namespaces: []database.Namespace{testInsertLayerNamespace1, testInsertLayerNamespace2},
|
||||
},
|
||||
Features: []database.FeatureVersion{f1, f2, f3},
|
||||
},
|
||||
// This layer covers the case where the last layer provides Features.
|
||||
// It also modifies the Namespace ("upgrade") but keeps some Features not upgraded, their
|
||||
// Namespaces should then remain unchanged.
|
||||
{
|
||||
Name: "TestInsertLayer4b",
|
||||
Parent: &database.Layer{Name: "TestInsertLayer3"},
|
||||
Name: "TestInsertLayer4b",
|
||||
Parent: &database.Layer{Name: "TestInsertLayer3",
|
||||
Namespaces: []database.Namespace{testInsertLayerNamespace1, testInsertLayerNamespace2},
|
||||
},
|
||||
Namespaces: []database.Namespace{testInsertLayerNamespace3},
|
||||
Features: []database.FeatureVersion{
|
||||
// Deletes TestInsertLayerFeature1.
|
||||
@ -295,6 +301,8 @@ func testInsertLayerUpdate(t *testing.T, datastore database.Datastore) {
|
||||
}
|
||||
|
||||
l3, _ := datastore.FindLayer("TestInsertLayer3", true, false)
|
||||
l3Parent, _ := datastore.FindLayer(l3.Parent.Name, false, false)
|
||||
l3.Parent = &l3Parent
|
||||
l3u := database.Layer{
|
||||
Name: l3.Name,
|
||||
Parent: l3.Parent,
|
||||
@ -304,7 +312,7 @@ func testInsertLayerUpdate(t *testing.T, datastore database.Datastore) {
|
||||
|
||||
l4u := database.Layer{
|
||||
Name: "TestInsertLayer4",
|
||||
Parent: &database.Layer{Name: "TestInsertLayer3"},
|
||||
Parent: &database.Layer{Name: "TestInsertLayer3", Namespaces: l3.Namespaces},
|
||||
Features: []database.FeatureVersion{f7},
|
||||
EngineVersion: 2,
|
||||
}
|
||||
|
@ -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.
|
||||
@ -33,7 +33,7 @@ CREATE INDEX ON LayerNamespace (layer_id, namespace_id);
|
||||
|
||||
INSERT INTO LayerNamespace(layer_id, namespace_id)
|
||||
SELECT id, namespace_id
|
||||
from Layer;
|
||||
from Layer WHERE namespace_id IS NOT NULL;
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Layer table
|
||||
|
@ -50,6 +50,30 @@ func (pgSQL *pgSQL) insertNamespace(namespace database.Namespace) (int, error) {
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func (pgSQL *pgSQL) GetNamespaceID(namespace database.Namespace) (int, error) {
|
||||
if pgSQL.cache != nil {
|
||||
promCacheQueriesTotal.WithLabelValues("namespace").Inc()
|
||||
if id, found := pgSQL.cache.Get("namespace:" + namespace.Name + ":" + namespace.Version.String()); found {
|
||||
promCacheHitsTotal.WithLabelValues("namespace").Inc()
|
||||
return id.(int), nil
|
||||
}
|
||||
}
|
||||
|
||||
defer observeQueryTime("getNamespaceID", "all", time.Now())
|
||||
|
||||
var id int
|
||||
err := pgSQL.QueryRow(getNamespaceID, namespace.Name, namespace.Version.String()).Scan(&id)
|
||||
if err != nil {
|
||||
return 0, handleError("getNamespaceID", err)
|
||||
}
|
||||
|
||||
if pgSQL.cache != nil {
|
||||
pgSQL.cache.Add("namespace:"+namespace.Name+":"+namespace.Version.String(), id)
|
||||
}
|
||||
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func (pgSQL *pgSQL) ListNamespaces() (namespaces []database.Namespace, err error) {
|
||||
rows, err := pgSQL.Query(listNamespace)
|
||||
if err != nil {
|
||||
|
@ -118,7 +118,8 @@ func TestNotification(t *testing.T) {
|
||||
assert.Nil(t, datastore.insertVulnerability(v1, false, true))
|
||||
|
||||
// Get the notification associated to the previously inserted vulnerability.
|
||||
notification, err := datastore.GetAvailableNotification(time.Second)
|
||||
var notification database.VulnerabilityNotification
|
||||
notification, err = datastore.GetAvailableNotification(time.Second)
|
||||
|
||||
if assert.Nil(t, err) && assert.NotEmpty(t, notification.Name) {
|
||||
// Verify the renotify behaviour.
|
||||
@ -206,8 +207,12 @@ func TestNotification(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
namespaceID, err := datastore.GetNamespaceID(database.Namespace{
|
||||
Name: "TestNotificationNamespace",
|
||||
Version: types.NewVersionUnsafe("1.0"),
|
||||
})
|
||||
// Delete a vulnerability and verify the notification.
|
||||
if assert.Nil(t, datastore.DeleteVulnerability(v1b.Namespace, v1b.Name)) {
|
||||
if assert.Nil(t, err) && assert.Nil(t, datastore.DeleteVulnerability(namespaceID, v1b.Name)) {
|
||||
notification, err = datastore.GetAvailableNotification(time.Second)
|
||||
assert.Nil(t, err)
|
||||
assert.NotEmpty(t, notification.Name)
|
||||
|
@ -37,9 +37,9 @@ const (
|
||||
SELECT id FROM Namespace WHERE name = $1 AND version = $2
|
||||
UNION
|
||||
SELECT id FROM new_namespace`
|
||||
|
||||
searchNamespace = `SELECT id FROM Namespace WHERE name = $1 AND version = $2`
|
||||
listNamespace = `SELECT id, name, version FROM Namespace`
|
||||
getNamespaceID = `SELECT id FROM Namespace WHERE name = $1 AND version = $2`
|
||||
listNamespace = `SELECT id, name, version FROM Namespace where version IS NOT NULL`
|
||||
getNamespaceByID = `SELECT name, version FROM Namespace WHERE id = $1`
|
||||
|
||||
// feature.go
|
||||
soiFeature = `
|
||||
@ -161,10 +161,10 @@ const (
|
||||
searchVulnerabilityBase = `
|
||||
SELECT v.id, v.name, n.id, n.name, n.version, v.description, v.link, v.severity, v.metadata
|
||||
FROM Vulnerability v JOIN Namespace n ON v.namespace_id = n.id`
|
||||
searchVulnerabilityForUpdate = ` FOR UPDATE OF v`
|
||||
searchVulnerabilityByNamespaceAndName = ` WHERE n.name = $1 AND n.version = $2 AND v.name = $3 AND v.deleted_at IS NULL`
|
||||
searchVulnerabilityByID = ` WHERE v.id = $1`
|
||||
searchVulnerabilityByNamespaceID = ` WHERE n.id = $1 AND v.deleted_at IS NULL
|
||||
searchVulnerabilityForUpdate = ` FOR UPDATE OF v`
|
||||
searchVulnerabilityByNamespaceIDAndName = ` WHERE n.id = $1 AND v.name = $2 AND v.deleted_at IS NULL`
|
||||
searchVulnerabilityByID = ` WHERE v.id = $1`
|
||||
searchVulnerabilityByNamespaceID = ` WHERE n.id = $1 AND v.deleted_at IS NULL
|
||||
AND v.id >= $2
|
||||
ORDER BY v.id
|
||||
LIMIT $3`
|
||||
@ -189,8 +189,8 @@ const (
|
||||
removeVulnerability = `
|
||||
UPDATE Vulnerability
|
||||
SET deleted_at = CURRENT_TIMESTAMP
|
||||
WHERE namespace_id = (SELECT id FROM Namespace WHERE name = $1 AND version = $2)
|
||||
AND name = $3
|
||||
WHERE namespace_id = $1
|
||||
AND name = $2
|
||||
AND deleted_at IS NULL
|
||||
RETURNING id`
|
||||
|
||||
|
@ -28,21 +28,12 @@ import (
|
||||
"github.com/guregu/null/zero"
|
||||
)
|
||||
|
||||
func (pgSQL *pgSQL) ListVulnerabilities(namespace database.Namespace, limit int, startID int) ([]database.Vulnerability, int, error) {
|
||||
func (pgSQL *pgSQL) ListVulnerabilities(namespaceID int, limit int, startID int) ([]database.Vulnerability, int, error) {
|
||||
defer observeQueryTime("listVulnerabilities", "all", time.Now())
|
||||
|
||||
// Query Namespace.
|
||||
var id int
|
||||
err := pgSQL.QueryRow(searchNamespace, namespace.Name, &namespace.Version).Scan(&id)
|
||||
if err != nil {
|
||||
return nil, -1, handleError("searchNamespace", err)
|
||||
} else if id == 0 {
|
||||
return nil, -1, cerrors.ErrNotFound
|
||||
}
|
||||
|
||||
// Query.
|
||||
query := searchVulnerabilityBase + searchVulnerabilityByNamespaceID
|
||||
rows, err := pgSQL.Query(query, id, startID, limit+1)
|
||||
rows, err := pgSQL.Query(query, namespaceID, startID, limit+1)
|
||||
if err != nil {
|
||||
return nil, -1, handleError("searchVulnerabilityByNamespaceID", err)
|
||||
}
|
||||
@ -84,21 +75,21 @@ func (pgSQL *pgSQL) ListVulnerabilities(namespace database.Namespace, limit int,
|
||||
return vulns, nextID, nil
|
||||
}
|
||||
|
||||
func (pgSQL *pgSQL) FindVulnerability(namespace database.Namespace, name string) (database.Vulnerability, error) {
|
||||
return findVulnerability(pgSQL, namespace, name, false)
|
||||
func (pgSQL *pgSQL) FindVulnerability(namespaceID int, name string) (database.Vulnerability, error) {
|
||||
return findVulnerability(pgSQL, namespaceID, name, false)
|
||||
}
|
||||
|
||||
func findVulnerability(queryer Queryer, namespace database.Namespace, name string, forUpdate bool) (database.Vulnerability, error) {
|
||||
func findVulnerability(queryer Queryer, namespaceID int, name string, forUpdate bool) (database.Vulnerability, error) {
|
||||
defer observeQueryTime("findVulnerability", "all", time.Now())
|
||||
|
||||
queryName := "searchVulnerabilityBase+searchVulnerabilityByNamespaceAndName"
|
||||
query := searchVulnerabilityBase + searchVulnerabilityByNamespaceAndName
|
||||
queryName := "searchVulnerabilityBase+searchVulnerabilityByNamespaceIDAndName"
|
||||
query := searchVulnerabilityBase + searchVulnerabilityByNamespaceIDAndName
|
||||
if forUpdate {
|
||||
queryName = queryName + "+searchVulnerabilityForUpdate"
|
||||
query = query + searchVulnerabilityForUpdate
|
||||
}
|
||||
|
||||
return scanVulnerability(queryer, queryName, queryer.QueryRow(query, namespace.Name, &namespace.Version, name))
|
||||
return scanVulnerability(queryer, queryName, queryer.QueryRow(query, namespaceID, name))
|
||||
}
|
||||
|
||||
func (pgSQL *pgSQL) findVulnerabilityByIDWithDeleted(id int) (database.Vulnerability, error) {
|
||||
@ -195,9 +186,24 @@ func (pgSQL *pgSQL) insertVulnerability(vulnerability database.Vulnerability, on
|
||||
tf := time.Now()
|
||||
|
||||
// Verify parameters
|
||||
if vulnerability.Name == "" || vulnerability.Namespace.IsEmpty() {
|
||||
return cerrors.NewBadRequestError("insertVulnerability needs at least the Name and the Namespace")
|
||||
if vulnerability.Name == "" {
|
||||
return cerrors.NewBadRequestError("insertVulnerability needs at least the Name")
|
||||
}
|
||||
|
||||
if vulnerability.Namespace.ID <= 0 {
|
||||
// Find or insert Vulnerability's Namespace.
|
||||
namespaceID, err := pgSQL.insertNamespace(vulnerability.Namespace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
vulnerability.Namespace.ID = namespaceID
|
||||
} else if vulnerability.Namespace.IsEmpty() {
|
||||
err := pgSQL.QueryRow(getNamespaceByID, vulnerability.Namespace.ID).Scan(&vulnerability.Namespace.Name, &vulnerability.Namespace.Version)
|
||||
if err != nil {
|
||||
return cerrors.NewBadRequestError("could not get the related namespace")
|
||||
}
|
||||
}
|
||||
|
||||
if !onlyFixedIn && !vulnerability.Severity.IsValid() {
|
||||
msg := fmt.Sprintf("could not insert a vulnerability that has an invalid Severity: %s", vulnerability.Severity)
|
||||
log.Warning(msg)
|
||||
@ -209,8 +215,7 @@ func (pgSQL *pgSQL) insertVulnerability(vulnerability database.Vulnerability, on
|
||||
if fifv.Feature.Namespace.IsEmpty() {
|
||||
// As there is no Namespace on that FixedIn FeatureVersion, set it to the Vulnerability's
|
||||
// Namespace.
|
||||
fifv.Feature.Namespace.Name = vulnerability.Namespace.Name
|
||||
fifv.Feature.Namespace.Version = vulnerability.Namespace.Version
|
||||
fifv.Feature.Namespace = vulnerability.Namespace
|
||||
} else if !fifv.Feature.Namespace.Equal(vulnerability.Namespace) {
|
||||
msg := "could not insert an invalid vulnerability that contains FixedIn FeatureVersion that are not in the same namespace as the Vulnerability"
|
||||
log.Warning(msg)
|
||||
@ -229,7 +234,7 @@ func (pgSQL *pgSQL) insertVulnerability(vulnerability database.Vulnerability, on
|
||||
}
|
||||
|
||||
// Find existing vulnerability and its Vulnerability_FixedIn_Features (for update).
|
||||
existingVulnerability, err := findVulnerability(tx, vulnerability.Namespace, vulnerability.Name, true)
|
||||
existingVulnerability, err := findVulnerability(tx, vulnerability.Namespace.ID, vulnerability.Name, true)
|
||||
if err != nil && err != cerrors.ErrNotFound {
|
||||
tx.Rollback()
|
||||
return err
|
||||
@ -267,7 +272,7 @@ func (pgSQL *pgSQL) insertVulnerability(vulnerability database.Vulnerability, on
|
||||
}
|
||||
|
||||
// Mark the old vulnerability as non latest.
|
||||
_, err = tx.Exec(removeVulnerability, vulnerability.Namespace.Name, &vulnerability.Namespace.Version, vulnerability.Name)
|
||||
_, err = tx.Exec(removeVulnerability, vulnerability.Namespace.ID, vulnerability.Name)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return handleError("removeVulnerability", err)
|
||||
@ -284,16 +289,10 @@ func (pgSQL *pgSQL) insertVulnerability(vulnerability database.Vulnerability, on
|
||||
vulnerability.FixedIn = fixedIn
|
||||
}
|
||||
|
||||
// Find or insert Vulnerability's Namespace.
|
||||
namespaceID, err := pgSQL.insertNamespace(vulnerability.Namespace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Insert vulnerability.
|
||||
err = tx.QueryRow(
|
||||
insertVulnerability,
|
||||
namespaceID,
|
||||
vulnerability.Namespace.ID,
|
||||
vulnerability.Name,
|
||||
vulnerability.Description,
|
||||
vulnerability.Link,
|
||||
@ -500,38 +499,41 @@ func linkVulnerabilityToFeatureVersions(tx *sql.Tx, fixedInID, vulnerabilityID,
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pgSQL *pgSQL) InsertVulnerabilityFixes(vulnerabilityNamespace database.Namespace, vulnerabilityName string, fixes []database.FeatureVersion) error {
|
||||
func (pgSQL *pgSQL) InsertVulnerabilityFixes(vulnerabilityNamespaceID int, vulnerabilityName string, fixes []database.FeatureVersion) error {
|
||||
defer observeQueryTime("InsertVulnerabilityFixes", "all", time.Now())
|
||||
|
||||
var vns database.Namespace
|
||||
if err := pgSQL.QueryRow(getNamespaceByID, vulnerabilityNamespaceID).Scan(&vns.Name, &vns.Version); err != nil {
|
||||
return handleError("getNamespaceByID", err)
|
||||
}
|
||||
vns.ID = vulnerabilityNamespaceID
|
||||
|
||||
v := database.Vulnerability{
|
||||
Name: vulnerabilityName,
|
||||
Namespace: database.Namespace{
|
||||
Name: vulnerabilityNamespace.Name,
|
||||
Version: vulnerabilityNamespace.Version,
|
||||
},
|
||||
FixedIn: fixes,
|
||||
Name: vulnerabilityName,
|
||||
Namespace: vns,
|
||||
FixedIn: fixes,
|
||||
}
|
||||
|
||||
return pgSQL.insertVulnerability(v, true, true)
|
||||
}
|
||||
|
||||
func (pgSQL *pgSQL) DeleteVulnerabilityFix(vulnerabilityNamespace database.Namespace, vulnerabilityName, featureName string) error {
|
||||
func (pgSQL *pgSQL) DeleteVulnerabilityFix(vulnerabilityNamespaceID int, vulnerabilityName, featureName string) error {
|
||||
defer observeQueryTime("DeleteVulnerabilityFix", "all", time.Now())
|
||||
|
||||
var vns database.Namespace
|
||||
if err := pgSQL.QueryRow(getNamespaceByID, vulnerabilityNamespaceID).Scan(&vns.Name, &vns.Version); err != nil {
|
||||
return handleError("getNamespaceByID", err)
|
||||
}
|
||||
vns.ID = vulnerabilityNamespaceID
|
||||
|
||||
v := database.Vulnerability{
|
||||
Name: vulnerabilityName,
|
||||
Namespace: database.Namespace{
|
||||
Name: vulnerabilityNamespace.Name,
|
||||
Version: vulnerabilityNamespace.Version,
|
||||
},
|
||||
Name: vulnerabilityName,
|
||||
Namespace: vns,
|
||||
FixedIn: []database.FeatureVersion{
|
||||
{
|
||||
Feature: database.Feature{
|
||||
Name: featureName,
|
||||
Namespace: database.Namespace{
|
||||
Name: vulnerabilityNamespace.Name,
|
||||
Version: vulnerabilityNamespace.Version,
|
||||
},
|
||||
Name: featureName,
|
||||
Namespace: vns,
|
||||
},
|
||||
Version: types.MinVersion,
|
||||
},
|
||||
@ -541,7 +543,7 @@ func (pgSQL *pgSQL) DeleteVulnerabilityFix(vulnerabilityNamespace database.Names
|
||||
return pgSQL.insertVulnerability(v, true, true)
|
||||
}
|
||||
|
||||
func (pgSQL *pgSQL) DeleteVulnerability(namespace database.Namespace, name string) error {
|
||||
func (pgSQL *pgSQL) DeleteVulnerability(namespaceID int, name string) error {
|
||||
defer observeQueryTime("DeleteVulnerability", "all", time.Now())
|
||||
|
||||
// Begin transaction.
|
||||
@ -552,7 +554,7 @@ func (pgSQL *pgSQL) DeleteVulnerability(namespace database.Namespace, name strin
|
||||
}
|
||||
|
||||
var vulnerabilityID int
|
||||
err = tx.QueryRow(removeVulnerability, namespace.Name, &namespace.Version, name).Scan(&vulnerabilityID)
|
||||
err = tx.QueryRow(removeVulnerability, namespaceID, name).Scan(&vulnerabilityID)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return handleError("removeVulnerability", err)
|
||||
|
@ -37,8 +37,12 @@ func TestFindVulnerability(t *testing.T) {
|
||||
Name: "debian",
|
||||
Version: types.NewVersionUnsafe("7"),
|
||||
}
|
||||
var testExistNamespaceID int
|
||||
testExistNamespaceID, err = datastore.GetNamespaceID(testExistNamespace)
|
||||
assert.Nil(t, err)
|
||||
|
||||
// Find a vulnerability that does not exist.
|
||||
_, err = datastore.FindVulnerability(database.Namespace{}, "")
|
||||
_, err = datastore.FindVulnerability(-1, "")
|
||||
assert.Equal(t, cerrors.ErrNotFound, err)
|
||||
|
||||
// Find a normal vulnerability.
|
||||
@ -60,7 +64,7 @@ func TestFindVulnerability(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
v1f, err := datastore.FindVulnerability(testExistNamespace, "CVE-OPENSSL-1-DEB7")
|
||||
v1f, err := datastore.FindVulnerability(testExistNamespaceID, "CVE-OPENSSL-1-DEB7")
|
||||
if assert.Nil(t, err) {
|
||||
equalsVuln(t, &v1, &v1f)
|
||||
}
|
||||
@ -73,7 +77,7 @@ func TestFindVulnerability(t *testing.T) {
|
||||
Severity: types.Unknown,
|
||||
}
|
||||
|
||||
v2f, err := datastore.FindVulnerability(testExistNamespace, "CVE-NOPE")
|
||||
v2f, err := datastore.FindVulnerability(testExistNamespaceID, "CVE-NOPE")
|
||||
if assert.Nil(t, err) {
|
||||
equalsVuln(t, &v2, &v2f)
|
||||
}
|
||||
@ -91,20 +95,28 @@ func TestDeleteVulnerability(t *testing.T) {
|
||||
Name: "debian",
|
||||
Version: types.NewVersionUnsafe("7"),
|
||||
}
|
||||
var testExistNamespaceID int
|
||||
testExistNamespaceID, err = datastore.GetNamespaceID(testExistNamespace)
|
||||
assert.Nil(t, err)
|
||||
|
||||
testNonExistNamespace := database.Namespace{
|
||||
Name: "TestDeleteVulnerabilityNamespace",
|
||||
Version: types.NewVersionUnsafe("1.0"),
|
||||
}
|
||||
// Delete non-existing Vulnerability.
|
||||
err = datastore.DeleteVulnerability(testNonExistNamespace, "CVE-OPENSSL-1-DEB7")
|
||||
var testNonExistNamespaceID int
|
||||
testNonExistNamespaceID, err = datastore.GetNamespaceID(testNonExistNamespace)
|
||||
assert.Equal(t, cerrors.ErrNotFound, err)
|
||||
err = datastore.DeleteVulnerability(testExistNamespace, "TestDeleteVulnerabilityVulnerability1")
|
||||
|
||||
// Delete non-existing Vulnerability.
|
||||
err = datastore.DeleteVulnerability(testNonExistNamespaceID, "CVE-OPENSSL-1-DEB7")
|
||||
assert.Equal(t, cerrors.ErrNotFound, err)
|
||||
err = datastore.DeleteVulnerability(testExistNamespaceID, "TestDeleteVulnerabilityVulnerability1")
|
||||
assert.Equal(t, cerrors.ErrNotFound, err)
|
||||
|
||||
// Delete Vulnerability.
|
||||
err = datastore.DeleteVulnerability(testExistNamespace, "CVE-OPENSSL-1-DEB7")
|
||||
err = datastore.DeleteVulnerability(testExistNamespaceID, "CVE-OPENSSL-1-DEB7")
|
||||
if assert.Nil(t, err) {
|
||||
_, err := datastore.FindVulnerability(testExistNamespace, "CVE-OPENSSL-1-DEB7")
|
||||
_, err := datastore.FindVulnerability(testExistNamespaceID, "CVE-OPENSSL-1-DEB7")
|
||||
assert.Equal(t, cerrors.ErrNotFound, err)
|
||||
}
|
||||
}
|
||||
@ -228,7 +240,11 @@ func TestInsertVulnerability(t *testing.T) {
|
||||
}
|
||||
err = datastore.InsertVulnerabilities([]database.Vulnerability{v1}, true)
|
||||
if assert.Nil(t, err) {
|
||||
v1f, err := datastore.FindVulnerability(n1, v1.Name)
|
||||
var n1ID int
|
||||
var v1f database.Vulnerability
|
||||
n1ID, err := datastore.GetNamespaceID(n1)
|
||||
assert.Nil(t, err)
|
||||
v1f, err = datastore.FindVulnerability(n1ID, v1.Name)
|
||||
if assert.Nil(t, err) {
|
||||
equalsVuln(t, &v1, &v1f)
|
||||
}
|
||||
@ -244,7 +260,11 @@ func TestInsertVulnerability(t *testing.T) {
|
||||
|
||||
err = datastore.InsertVulnerabilities([]database.Vulnerability{v1}, true)
|
||||
if assert.Nil(t, err) {
|
||||
v1f, err := datastore.FindVulnerability(n1, v1.Name)
|
||||
var n1ID int
|
||||
var v1f database.Vulnerability
|
||||
n1ID, err := datastore.GetNamespaceID(n1)
|
||||
assert.Nil(t, err)
|
||||
v1f, err = datastore.FindVulnerability(n1ID, v1.Name)
|
||||
if assert.Nil(t, err) {
|
||||
// We already had f1 before the update.
|
||||
// Add it to the struct for comparison.
|
||||
|
@ -169,6 +169,7 @@ func parseDebianJSON(data *jsonData) (vulnerabilities []database.Vulnerability,
|
||||
|
||||
// Determine the version of the package the vulnerability affects.
|
||||
var version types.Version
|
||||
var nsVersion types.Version
|
||||
var err error
|
||||
if releaseNode.FixedVersion == "0" {
|
||||
// This means that the package is not affected by this vulnerability.
|
||||
@ -187,13 +188,19 @@ func parseDebianJSON(data *jsonData) (vulnerabilities []database.Vulnerability,
|
||||
}
|
||||
}
|
||||
|
||||
nsVersion, err = types.NewVersion(database.DebianReleasesMapping[releaseName])
|
||||
if err != nil {
|
||||
log.Warningf("could not parse namespace version '%s': %s. skipping", database.DebianReleasesMapping[releaseName], err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
// Create and add the feature version.
|
||||
pkg := database.FeatureVersion{
|
||||
Feature: database.Feature{
|
||||
Name: pkgName,
|
||||
Namespace: database.Namespace{
|
||||
Name: "debian",
|
||||
Version: types.NewVersionUnsafe(database.DebianReleasesMapping[releaseName]),
|
||||
Version: nsVersion,
|
||||
},
|
||||
},
|
||||
Version: version,
|
||||
|
@ -48,7 +48,7 @@ func TestDebianParser(t *testing.T) {
|
||||
},
|
||||
{
|
||||
Feature: database.Feature{
|
||||
Namespace: database.Namespace{Name: "debian", Version: types.NewVersionUnsafe("unstable")},
|
||||
Namespace: database.Namespace{Name: "debian", Version: types.NewVersionUnsafe("10")},
|
||||
|
||||
Name: "aptdaemon",
|
||||
},
|
||||
@ -74,7 +74,7 @@ func TestDebianParser(t *testing.T) {
|
||||
},
|
||||
{
|
||||
Feature: database.Feature{
|
||||
Namespace: database.Namespace{Name: "debian", Version: types.NewVersionUnsafe("unstable")},
|
||||
Namespace: database.Namespace{Name: "debian", Version: types.NewVersionUnsafe("10")},
|
||||
Name: "aptdaemon",
|
||||
},
|
||||
Version: types.NewVersionUnsafe("0.7.0"),
|
||||
|
@ -291,8 +291,13 @@ func toFeatureVersions(criteria criteria) []database.FeatureVersion {
|
||||
}
|
||||
|
||||
if osVersion > firstConsideredRHEL {
|
||||
nsVersion, err := types.NewVersion(strconv.Itoa(osVersion))
|
||||
if err != nil {
|
||||
log.Warningf("could not parse namespace version '%s': %s. skipping", strconv.Itoa(osVersion), err.Error())
|
||||
continue
|
||||
}
|
||||
featureVersion.Feature.Namespace.Name = "centos"
|
||||
featureVersion.Feature.Namespace.Version = types.NewVersionUnsafe(strconv.Itoa(osVersion))
|
||||
featureVersion.Feature.Namespace.Version = nsVersion
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
|
@ -373,10 +373,15 @@ func parseUbuntuCVE(fileContent io.Reader) (vulnerability database.Vulnerability
|
||||
continue
|
||||
}
|
||||
|
||||
nsVersion, err := types.NewVersion(database.UbuntuReleasesMapping[md["release"]])
|
||||
if err != nil {
|
||||
log.Warningf("could not parse namespace version '%s': %s. skipping", database.UbuntuReleasesMapping[md["release"]], err)
|
||||
}
|
||||
|
||||
// Create and add the new package.
|
||||
featureVersion := database.FeatureVersion{
|
||||
Feature: database.Feature{
|
||||
Namespace: database.Namespace{Name: "ubuntu", Version: types.NewVersionUnsafe(database.UbuntuReleasesMapping[md["release"]])},
|
||||
Namespace: database.Namespace{Name: "ubuntu", Version: nsVersion},
|
||||
Name: md["package"],
|
||||
},
|
||||
Version: version,
|
||||
|
@ -68,8 +68,7 @@ func DetectFeatures(data map[string][]byte, namespaces []database.Namespace) ([]
|
||||
}
|
||||
// Ensure that every feature has a Namespace associated
|
||||
for i := 0; i < len(pkgs); i++ {
|
||||
pkgs[i].Feature.Namespace.Name = namespace.Name
|
||||
pkgs[i].Feature.Namespace.Version = namespace.Version
|
||||
pkgs[i].Feature.Namespace = namespace
|
||||
}
|
||||
packages = append(packages, pkgs...)
|
||||
break
|
||||
|
@ -76,7 +76,11 @@ func (detector *AptSourcesNamespaceDetector) Detect(data map[string][]byte) *dat
|
||||
}
|
||||
|
||||
if OS != "" && version != "" {
|
||||
return &database.Namespace{Name: OS, Version: types.NewVersionUnsafe(version)}
|
||||
if nsVersion, err := types.NewVersion(version); err != nil {
|
||||
return nil
|
||||
} else {
|
||||
return &database.Namespace{Name: OS, Version: nsVersion}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ import (
|
||||
|
||||
var aptSourcesOSTests = []namespace.NamespaceTest{
|
||||
{
|
||||
ExpectedNamespace: database.Namespace{Name: "debian", Version: types.NewVersionUnsafe("unstable")},
|
||||
ExpectedNamespace: database.Namespace{Name: "debian", Version: types.NewVersionUnsafe("10")},
|
||||
Data: map[string][]byte{
|
||||
"etc/os-release": []byte(
|
||||
`PRETTY_NAME="Debian GNU/Linux stretch/sid"
|
||||
|
@ -71,7 +71,11 @@ func (detector *LsbReleaseNamespaceDetector) Detect(data map[string][]byte) *dat
|
||||
}
|
||||
|
||||
if OS != "" && version != "" {
|
||||
return &database.Namespace{Name: OS, Version: types.NewVersionUnsafe(version)}
|
||||
if nsVersion, err := types.NewVersion(version); err != nil {
|
||||
return nil
|
||||
} else {
|
||||
return &database.Namespace{Name: OS, Version: nsVersion}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -66,7 +66,11 @@ func (detector *OsReleaseNamespaceDetector) Detect(data map[string][]byte) *data
|
||||
}
|
||||
|
||||
if OS != "" && version != "" {
|
||||
return &database.Namespace{Name: OS, Version: types.NewVersionUnsafe(version)}
|
||||
if nsVersion, err := types.NewVersion(version); err != nil {
|
||||
return nil
|
||||
} else {
|
||||
return &database.Namespace{Name: OS, Version: nsVersion}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -47,7 +47,11 @@ func (detector *RedhatReleaseNamespaceDetector) Detect(data map[string][]byte) *
|
||||
|
||||
r := redhatReleaseRegexp.FindStringSubmatch(string(f))
|
||||
if len(r) == 4 {
|
||||
return &database.Namespace{Name: strings.ToLower(r[1]), Version: types.NewVersionUnsafe(r[3])}
|
||||
if nsVersion, err := types.NewVersion(r[3]); err != nil {
|
||||
return nil
|
||||
} else {
|
||||
return &database.Namespace{Name: strings.ToLower(r[1]), Version: nsVersion}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user