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": {
|
"Layer": {
|
||||||
"Name": "17675ec01494d651e1ccf81dc9cf63959ebfeed4f978fddb1666b6ead008ed52",
|
"Name": "17675ec01494d651e1ccf81dc9cf63959ebfeed4f978fddb1666b6ead008ed52",
|
||||||
"NamespaceName": "debian:8",
|
"Namespaces": [{"Name": "debian", "Version": "8"}],
|
||||||
"ParentName": "140f9bdfeb9784cf8730e9dab5dd12fbd704151cf555ac8cae650451794e5ac2",
|
"ParentName": "140f9bdfeb9784cf8730e9dab5dd12fbd704151cf555ac8cae650451794e5ac2",
|
||||||
"IndexedByVersion": 1,
|
"IndexedByVersion": 1,
|
||||||
"Features": [
|
"Features": [
|
||||||
{
|
{
|
||||||
"Name": "coreutils",
|
"Name": "coreutils",
|
||||||
"NamespaceName": "debian:8",
|
"Namespace": {"Name": "debian", "Version": "8"},
|
||||||
"Version": "8.23-4",
|
"Version": "8.23-4",
|
||||||
"Vulnerabilities": [
|
"Vulnerabilities": [
|
||||||
{
|
{
|
||||||
"Name": "CVE-2014-9471",
|
"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.",
|
"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",
|
"Link": "https://security-tracker.debian.org/tracker/CVE-2014-9471",
|
||||||
"Severity": "Low",
|
"Severity": "Low",
|
||||||
@ -196,15 +196,15 @@ Server: clair
|
|||||||
|
|
||||||
{
|
{
|
||||||
"Namespaces": [
|
"Namespaces": [
|
||||||
{ "Name": "debian:8" },
|
{ "ID": "gAAAAABXTQKgma_TLKq0wr1D6wVB507N3fi9wsWMUypYOSXTDVxQ8OR5L5S6PqZ9Wh0IzWojnVmlspyTL4cyjytyra7U9vAHMA==", "Name": "debian", "Version": "8" },
|
||||||
{ "Name": "debian:9" }
|
{ "ID": "gAAAAABXTQPZmOFlOR8zzuhv8Y2fD7HbUY8O6z_Py2vibB9uveWZoycSY1HDIkcf7lN_UDynom4kWubFS4h9KBCbWwjNIqacsw==", "Name": "debian", "Version": "9" }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Vulnerabilities
|
## Vulnerabilities
|
||||||
|
|
||||||
#### GET /namespaces/`:nsName`/vulnerabilities
|
#### GET /namespaces/`:nsID`/vulnerabilities
|
||||||
|
|
||||||
###### Description
|
###### Description
|
||||||
|
|
||||||
@ -220,7 +220,7 @@ The GET route for the Vulnerabilities resource displays the vulnerabilities data
|
|||||||
###### Example Request
|
###### Example Request
|
||||||
|
|
||||||
```json
|
```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
|
###### Example Response
|
||||||
@ -234,14 +234,14 @@ Server: clair
|
|||||||
"Vulnerabilities": [
|
"Vulnerabilities": [
|
||||||
{
|
{
|
||||||
"Name": "CVE-1999-1332",
|
"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.",
|
"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",
|
"Link": "https://security-tracker.debian.org/tracker/CVE-1999-1332",
|
||||||
"Severity": "Low"
|
"Severity": "Low"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Name": "CVE-1999-1572",
|
"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.",
|
"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",
|
"Link": "https://security-tracker.debian.org/tracker/CVE-1999-1572",
|
||||||
"Severity": "Low",
|
"Severity": "Low",
|
||||||
@ -259,7 +259,7 @@ Server: clair
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### POST /namespaces/`:name`/vulnerabilities
|
#### POST /namespaces/`:nsID`/vulnerabilities
|
||||||
|
|
||||||
###### Description
|
###### Description
|
||||||
|
|
||||||
@ -268,12 +268,12 @@ The POST route for the Vulnerabilities resource creates a new Vulnerability.
|
|||||||
###### Example Request
|
###### Example Request
|
||||||
|
|
||||||
```json
|
```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": {
|
"Vulnerability": {
|
||||||
"Name": "CVE-2014-9471",
|
"Name": "CVE-2014-9471",
|
||||||
"NamespaceName": "debian:8",
|
"Namespace": {"Name": "debian", "Version": "8"},
|
||||||
"Link": "https://security-tracker.debian.org/tracker/CVE-2014-9471",
|
"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.",
|
"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",
|
"Severity": "Low",
|
||||||
@ -288,7 +288,7 @@ POST http://localhost:6060/v1/namespaces/debian%3A8/vulnerabilities HTTP/1.1
|
|||||||
"FixedIn": [
|
"FixedIn": [
|
||||||
{
|
{
|
||||||
"Name": "coreutils",
|
"Name": "coreutils",
|
||||||
"NamespaceName": "debian:8",
|
"Namespace": {"Name": "debian", "Version": "8"},
|
||||||
"Version": "8.23-1"
|
"Version": "8.23-1"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -306,7 +306,7 @@ Server: clair
|
|||||||
{
|
{
|
||||||
"Vulnerability": {
|
"Vulnerability": {
|
||||||
"Name": "CVE-2014-9471",
|
"Name": "CVE-2014-9471",
|
||||||
"NamespaceName": "debian:8",
|
"Namespace": {"Name": "debian", "Version": "8"},
|
||||||
"Link": "https://security-tracker.debian.org/tracker/CVE-2014-9471",
|
"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.",
|
"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",
|
"Severity": "Low",
|
||||||
@ -321,7 +321,7 @@ Server: clair
|
|||||||
"FixedIn": [
|
"FixedIn": [
|
||||||
{
|
{
|
||||||
"Name": "coreutils",
|
"Name": "coreutils",
|
||||||
"NamespaceName": "debian:8",
|
"Namespace": {"Name": "debian", "Version": "8"},
|
||||||
"Version": "8.23-1"
|
"Version": "8.23-1"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -329,7 +329,7 @@ Server: clair
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### GET /namespaces/`:nsName`/vulnerabilities/`:vulnName`
|
#### GET /namespaces/`:nsID`/vulnerabilities/`:vulnName`
|
||||||
|
|
||||||
###### Description
|
###### Description
|
||||||
|
|
||||||
@ -344,7 +344,7 @@ The GET route for the Vulnerabilities resource displays the current data for a g
|
|||||||
###### Example Request
|
###### Example Request
|
||||||
|
|
||||||
```json
|
```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
|
###### Example Response
|
||||||
@ -357,7 +357,7 @@ Server: clair
|
|||||||
{
|
{
|
||||||
"Vulnerability": {
|
"Vulnerability": {
|
||||||
"Name": "CVE-2014-9471",
|
"Name": "CVE-2014-9471",
|
||||||
"NamespaceName": "debian:8",
|
"Namespace": {"Name": "debian", "Version": "8"},
|
||||||
"Link": "https://security-tracker.debian.org/tracker/CVE-2014-9471",
|
"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.",
|
"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",
|
"Severity": "Low",
|
||||||
@ -372,7 +372,7 @@ Server: clair
|
|||||||
"FixedIn": [
|
"FixedIn": [
|
||||||
{
|
{
|
||||||
"Name": "coreutils",
|
"Name": "coreutils",
|
||||||
"NamespaceName": "debian:8",
|
"Namespace": {"Name": "debian", "Version": "8"},
|
||||||
"Version": "8.23-1"
|
"Version": "8.23-1"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -380,7 +380,7 @@ Server: clair
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### PUT /namespaces/`:nsName`/vulnerabilities/`:vulnName`
|
#### PUT /namespaces/`:nsID`/vulnerabilities/`:vulnName`
|
||||||
|
|
||||||
###### Description
|
###### Description
|
||||||
|
|
||||||
@ -392,12 +392,12 @@ If this vulnerability was inserted by a Fetcher, changes may be lost when the Fe
|
|||||||
###### Example Request
|
###### Example Request
|
||||||
|
|
||||||
```json
|
```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": {
|
"Vulnerability": {
|
||||||
"Name": "CVE-2014-9471",
|
"Name": "CVE-2014-9471",
|
||||||
"NamespaceName": "debian:8",
|
"Namespace": {"Name": "debian", "Version": "8"},
|
||||||
"Link": "https://security-tracker.debian.org/tracker/CVE-2014-9471",
|
"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.",
|
"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",
|
"Severity": "Low",
|
||||||
@ -422,7 +422,7 @@ Server: clair
|
|||||||
{
|
{
|
||||||
"Vulnerability": {
|
"Vulnerability": {
|
||||||
"Name": "CVE-2014-9471",
|
"Name": "CVE-2014-9471",
|
||||||
"NamespaceName": "debian:8",
|
"Namespace": {"Name": "debian", "Version": "8"},
|
||||||
"Link": "https://security-tracker.debian.org/tracker/CVE-2014-9471",
|
"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.",
|
"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",
|
"Severity": "Low",
|
||||||
@ -439,7 +439,7 @@ Server: clair
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
#### DELETE /namespaces/`:nsName`/vulnerabilities/`:vulnName`
|
#### DELETE /namespaces/`:nsID`/vulnerabilities/`:vulnName`
|
||||||
|
|
||||||
###### Description
|
###### Description
|
||||||
|
|
||||||
@ -449,7 +449,7 @@ If this vulnerability was inserted by a Fetcher, it may be re-inserted when the
|
|||||||
###### Example Request
|
###### Example Request
|
||||||
|
|
||||||
```json
|
```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
|
###### Example Response
|
||||||
@ -461,7 +461,7 @@ Server: clair
|
|||||||
|
|
||||||
## Fixes
|
## Fixes
|
||||||
|
|
||||||
#### GET /namespaces/`:nsName`/vulnerabilities/`:vulnName`/fixes
|
#### GET /namespaces/`:nsID`/vulnerabilities/`:vulnName`/fixes
|
||||||
|
|
||||||
###### Description
|
###### Description
|
||||||
|
|
||||||
@ -470,7 +470,7 @@ The GET route for the Fixes resource displays the list of Features that fix the
|
|||||||
###### Example Request
|
###### Example Request
|
||||||
|
|
||||||
```json
|
```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
|
###### Example Response
|
||||||
@ -484,14 +484,14 @@ Server: clair
|
|||||||
"Features": [
|
"Features": [
|
||||||
{
|
{
|
||||||
"Name": "coreutils",
|
"Name": "coreutils",
|
||||||
"NamespaceName": "debian:8",
|
"Namespace": {"Name": "debian", "Version": "8"},
|
||||||
"Version": "8.23-1"
|
"Version": "8.23-1"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### PUT /namespaces/`:nsName`/vulnerabilities/`:vulnName`/fixes/`:featureName`
|
#### PUT /namespaces/`:nsID`/vulnerabilities/`:vulnName`/fixes/`:featureName`
|
||||||
|
|
||||||
###### Description
|
###### Description
|
||||||
|
|
||||||
@ -500,12 +500,12 @@ The PUT route for the Fixes resource updates a Feature that is the fix for a giv
|
|||||||
###### Example Request
|
###### Example Request
|
||||||
|
|
||||||
```json
|
```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": {
|
"Feature": {
|
||||||
"Name": "coreutils",
|
"Name": "coreutils",
|
||||||
"NamespaceName": "debian:8",
|
"Namespace": {"Name": "debian", "Version": "8"},
|
||||||
"Version": "4.24-9"
|
"Version": "4.24-9"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -520,13 +520,13 @@ Server: clair
|
|||||||
{
|
{
|
||||||
"Feature": {
|
"Feature": {
|
||||||
"Name": "coreutils",
|
"Name": "coreutils",
|
||||||
"NamespaceName": "debian:8",
|
"Namespace": {"Name": "debian", "Version": "8"},
|
||||||
"Version": "4.24-9"
|
"Version": "4.24-9"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### DELETE /namespaces/`:nsName`/vulnerabilities/`:vulnName`/fixes/`:featureName`
|
#### DELETE /namespaces/`:nsID`/vulnerabilities/`:vulnName`/fixes/`:featureName`
|
||||||
|
|
||||||
###### Description
|
###### Description
|
||||||
|
|
||||||
@ -535,7 +535,7 @@ The DELETE route for the Fixes resource removes a Feature as fix for the given V
|
|||||||
###### Example Request
|
###### Example Request
|
||||||
|
|
||||||
```json
|
```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
|
###### Example Response
|
||||||
@ -585,13 +585,13 @@ Server: clair
|
|||||||
"New": {
|
"New": {
|
||||||
"Vulnerability": {
|
"Vulnerability": {
|
||||||
"Name": "CVE-TEST",
|
"Name": "CVE-TEST",
|
||||||
"NamespaceName": "debian:8",
|
"Namespace": {"Name": "debian", "Version": "8"},
|
||||||
"Description": "New CVE",
|
"Description": "New CVE",
|
||||||
"Severity": "Low",
|
"Severity": "Low",
|
||||||
"FixedIn": [
|
"FixedIn": [
|
||||||
{
|
{
|
||||||
"Name": "grep",
|
"Name": "grep",
|
||||||
"NamespaceName": "debian:8",
|
"Namespace": {"Name": "debian", "Version": "8"},
|
||||||
"Version": "2.25"
|
"Version": "2.25"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -604,7 +604,7 @@ Server: clair
|
|||||||
"Old": {
|
"Old": {
|
||||||
"Vulnerability": {
|
"Vulnerability": {
|
||||||
"Name": "CVE-TEST",
|
"Name": "CVE-TEST",
|
||||||
"NamespaceName": "debian:8",
|
"Namespace": {"Name": "debian", "Version": "8"},
|
||||||
"Description": "New CVE",
|
"Description": "New CVE",
|
||||||
"Severity": "Low",
|
"Severity": "Low",
|
||||||
"FixedIn": []
|
"FixedIn": []
|
||||||
|
@ -35,7 +35,7 @@ type Error struct {
|
|||||||
|
|
||||||
type Layer struct {
|
type Layer struct {
|
||||||
Name string `json:"Name,omitempty"`
|
Name string `json:"Name,omitempty"`
|
||||||
NamespaceName string `json:"NamespaceName,omitempty"`
|
Namespaces []Namespace `json:"Namespaces,omitempty"`
|
||||||
Path string `json:"Path,omitempty"`
|
Path string `json:"Path,omitempty"`
|
||||||
Headers map[string]string `json:"Headers,omitempty"`
|
Headers map[string]string `json:"Headers,omitempty"`
|
||||||
ParentName string `json:"ParentName,omitempty"`
|
ParentName string `json:"ParentName,omitempty"`
|
||||||
@ -54,15 +54,15 @@ func LayerFromDatabaseModel(dbLayer database.Layer, withFeatures, withVulnerabil
|
|||||||
layer.ParentName = dbLayer.Parent.Name
|
layer.ParentName = dbLayer.Parent.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
if dbLayer.Namespace != nil {
|
for _, namespace := range dbLayer.Namespaces {
|
||||||
layer.NamespaceName = dbLayer.Namespace.Name
|
layer.Namespaces = append(layer.Namespaces, Namespace{Name: namespace.Name, Version: namespace.Version.String()})
|
||||||
}
|
}
|
||||||
|
|
||||||
if withFeatures || withVulnerabilities && dbLayer.Features != nil {
|
if withFeatures || withVulnerabilities && dbLayer.Features != nil {
|
||||||
for _, dbFeatureVersion := range dbLayer.Features {
|
for _, dbFeatureVersion := range dbLayer.Features {
|
||||||
feature := Feature{
|
feature := Feature{
|
||||||
Name: dbFeatureVersion.Feature.Name,
|
Name: dbFeatureVersion.Feature.Name,
|
||||||
NamespaceName: dbFeatureVersion.Feature.Namespace.Name,
|
Namespace: Namespace{Name: dbFeatureVersion.Feature.Namespace.Name, Version: dbFeatureVersion.Feature.Namespace.Version.String()},
|
||||||
Version: dbFeatureVersion.Version.String(),
|
Version: dbFeatureVersion.Version.String(),
|
||||||
AddedBy: dbFeatureVersion.AddedBy.Name,
|
AddedBy: dbFeatureVersion.AddedBy.Name,
|
||||||
}
|
}
|
||||||
@ -70,7 +70,7 @@ func LayerFromDatabaseModel(dbLayer database.Layer, withFeatures, withVulnerabil
|
|||||||
for _, dbVuln := range dbFeatureVersion.AffectedBy {
|
for _, dbVuln := range dbFeatureVersion.AffectedBy {
|
||||||
vuln := Vulnerability{
|
vuln := Vulnerability{
|
||||||
Name: dbVuln.Name,
|
Name: dbVuln.Name,
|
||||||
NamespaceName: dbVuln.Namespace.Name,
|
Namespace: Namespace{Name: dbVuln.Namespace.Name, Version: dbVuln.Namespace.Version.String()},
|
||||||
Description: dbVuln.Description,
|
Description: dbVuln.Description,
|
||||||
Link: dbVuln.Link,
|
Link: dbVuln.Link,
|
||||||
Severity: string(dbVuln.Severity),
|
Severity: string(dbVuln.Severity),
|
||||||
@ -90,12 +90,14 @@ func LayerFromDatabaseModel(dbLayer database.Layer, withFeatures, withVulnerabil
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Namespace struct {
|
type Namespace struct {
|
||||||
|
ID string `json:"ID,omitempty"`
|
||||||
Name string `json:"Name,omitempty"`
|
Name string `json:"Name,omitempty"`
|
||||||
|
Version string `json:"Version,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Vulnerability struct {
|
type Vulnerability struct {
|
||||||
Name string `json:"Name,omitempty"`
|
Name string `json:"Name,omitempty"`
|
||||||
NamespaceName string `json:"NamespaceName,omitempty"`
|
Namespace Namespace `json:"Namespace,omitempty"`
|
||||||
Description string `json:"Description,omitempty"`
|
Description string `json:"Description,omitempty"`
|
||||||
Link string `json:"Link,omitempty"`
|
Link string `json:"Link,omitempty"`
|
||||||
Severity string `json:"Severity,omitempty"`
|
Severity string `json:"Severity,omitempty"`
|
||||||
@ -110,6 +112,11 @@ func (v Vulnerability) DatabaseModel() (database.Vulnerability, error) {
|
|||||||
return database.Vulnerability{}, errors.New("Invalid severity")
|
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
|
var dbFeatures []database.FeatureVersion
|
||||||
for _, feature := range v.FixedIn {
|
for _, feature := range v.FixedIn {
|
||||||
dbFeature, err := feature.DatabaseModel()
|
dbFeature, err := feature.DatabaseModel()
|
||||||
@ -122,7 +129,7 @@ func (v Vulnerability) DatabaseModel() (database.Vulnerability, error) {
|
|||||||
|
|
||||||
return database.Vulnerability{
|
return database.Vulnerability{
|
||||||
Name: v.Name,
|
Name: v.Name,
|
||||||
Namespace: database.Namespace{Name: v.NamespaceName},
|
Namespace: database.Namespace{Name: v.Namespace.Name, Version: version},
|
||||||
Description: v.Description,
|
Description: v.Description,
|
||||||
Link: v.Link,
|
Link: v.Link,
|
||||||
Severity: severity,
|
Severity: severity,
|
||||||
@ -134,7 +141,7 @@ func (v Vulnerability) DatabaseModel() (database.Vulnerability, error) {
|
|||||||
func VulnerabilityFromDatabaseModel(dbVuln database.Vulnerability, withFixedIn bool) Vulnerability {
|
func VulnerabilityFromDatabaseModel(dbVuln database.Vulnerability, withFixedIn bool) Vulnerability {
|
||||||
vuln := Vulnerability{
|
vuln := Vulnerability{
|
||||||
Name: dbVuln.Name,
|
Name: dbVuln.Name,
|
||||||
NamespaceName: dbVuln.Namespace.Name,
|
Namespace: Namespace{Name: dbVuln.Namespace.Name, Version: dbVuln.Namespace.Version.String()},
|
||||||
Description: dbVuln.Description,
|
Description: dbVuln.Description,
|
||||||
Link: dbVuln.Link,
|
Link: dbVuln.Link,
|
||||||
Severity: string(dbVuln.Severity),
|
Severity: string(dbVuln.Severity),
|
||||||
@ -152,7 +159,7 @@ func VulnerabilityFromDatabaseModel(dbVuln database.Vulnerability, withFixedIn b
|
|||||||
|
|
||||||
type Feature struct {
|
type Feature struct {
|
||||||
Name string `json:"Name,omitempty"`
|
Name string `json:"Name,omitempty"`
|
||||||
NamespaceName string `json:"NamespaceName,omitempty"`
|
Namespace Namespace `json:"Namespace,omitempty"`
|
||||||
Version string `json:"Version,omitempty"`
|
Version string `json:"Version,omitempty"`
|
||||||
Vulnerabilities []Vulnerability `json:"Vulnerabilities,omitempty"`
|
Vulnerabilities []Vulnerability `json:"Vulnerabilities,omitempty"`
|
||||||
AddedBy string `json:"AddedBy,omitempty"`
|
AddedBy string `json:"AddedBy,omitempty"`
|
||||||
@ -166,7 +173,7 @@ func FeatureFromDatabaseModel(dbFeatureVersion database.FeatureVersion) Feature
|
|||||||
|
|
||||||
return Feature{
|
return Feature{
|
||||||
Name: dbFeatureVersion.Feature.Name,
|
Name: dbFeatureVersion.Feature.Name,
|
||||||
NamespaceName: dbFeatureVersion.Feature.Namespace.Name,
|
Namespace: Namespace{Name: dbFeatureVersion.Feature.Namespace.Name, Version: dbFeatureVersion.Feature.Namespace.Version.String()},
|
||||||
Version: versionStr,
|
Version: versionStr,
|
||||||
AddedBy: dbFeatureVersion.AddedBy.Name,
|
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{
|
return database.FeatureVersion{
|
||||||
Feature: database.Feature{
|
Feature: database.Feature{
|
||||||
Name: f.Name,
|
Name: f.Name,
|
||||||
Namespace: database.Namespace{Name: f.NamespaceName},
|
Namespace: database.Namespace{Name: f.Namespace.Name, Version: nsVersion},
|
||||||
},
|
},
|
||||||
Version: version,
|
Version: version,
|
||||||
}, nil
|
}, nil
|
||||||
|
@ -34,16 +34,16 @@ func NewRouter(ctx *context.RouteContext) *httprouter.Router {
|
|||||||
router.GET("/namespaces", context.HTTPHandler(getNamespaces, ctx))
|
router.GET("/namespaces", context.HTTPHandler(getNamespaces, ctx))
|
||||||
|
|
||||||
// Vulnerabilities
|
// Vulnerabilities
|
||||||
router.GET("/namespaces/:namespaceName/vulnerabilities", context.HTTPHandler(getVulnerabilities, ctx))
|
router.GET("/namespaces/:namespaceID/vulnerabilities", context.HTTPHandler(getVulnerabilities, ctx))
|
||||||
router.POST("/namespaces/:namespaceName/vulnerabilities", context.HTTPHandler(postVulnerability, ctx))
|
router.POST("/namespaces/:namespaceID/vulnerabilities", context.HTTPHandler(postVulnerability, ctx))
|
||||||
router.GET("/namespaces/:namespaceName/vulnerabilities/:vulnerabilityName", context.HTTPHandler(getVulnerability, ctx))
|
router.GET("/namespaces/:namespaceID/vulnerabilities/:vulnerabilityName", context.HTTPHandler(getVulnerability, ctx))
|
||||||
router.PUT("/namespaces/:namespaceName/vulnerabilities/:vulnerabilityName", context.HTTPHandler(putVulnerability, ctx))
|
router.PUT("/namespaces/:namespaceID/vulnerabilities/:vulnerabilityName", context.HTTPHandler(putVulnerability, ctx))
|
||||||
router.DELETE("/namespaces/:namespaceName/vulnerabilities/:vulnerabilityName", context.HTTPHandler(deleteVulnerability, ctx))
|
router.DELETE("/namespaces/:namespaceID/vulnerabilities/:vulnerabilityName", context.HTTPHandler(deleteVulnerability, ctx))
|
||||||
|
|
||||||
// Fixes
|
// Fixes
|
||||||
router.GET("/namespaces/:namespaceName/vulnerabilities/:vulnerabilityName/fixes", context.HTTPHandler(getFixes, ctx))
|
router.GET("/namespaces/:namespaceID/vulnerabilities/:vulnerabilityName/fixes", context.HTTPHandler(getFixes, ctx))
|
||||||
router.PUT("/namespaces/:namespaceName/vulnerabilities/:vulnerabilityName/fixes/:fixName", context.HTTPHandler(putFix, ctx))
|
router.PUT("/namespaces/:namespaceID/vulnerabilities/:vulnerabilityName/fixes/:fixName", context.HTTPHandler(putFix, ctx))
|
||||||
router.DELETE("/namespaces/:namespaceName/vulnerabilities/:vulnerabilityName/fixes/:fixName", context.HTTPHandler(deleteFix, ctx))
|
router.DELETE("/namespaces/:namespaceID/vulnerabilities/:vulnerabilityName/fixes/:fixName", context.HTTPHandler(deleteFix, ctx))
|
||||||
|
|
||||||
// Notifications
|
// Notifications
|
||||||
router.GET("/notifications/:notificationName", context.HTTPHandler(getNotification, ctx))
|
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
|
var namespaces []Namespace
|
||||||
for _, dbNamespace := range dbNamespaces {
|
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})
|
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")
|
namespaceID := 0
|
||||||
if namespace == "" {
|
if err = tokenUnmarshal(p.ByName("namespaceID"), ctx.Config.PaginationKey, &namespaceID); err != nil {
|
||||||
writeResponse(w, r, http.StatusBadRequest, VulnerabilityEnvelope{Error: &Error{"namespace should not be empty"}})
|
writeResponse(w, r, http.StatusBadRequest, VulnerabilityEnvelope{Error: &Error{"invalid namespace id format: " + err.Error()}})
|
||||||
return getNotificationRoute, http.StatusBadRequest
|
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 {
|
if err == cerrors.ErrNotFound {
|
||||||
writeResponse(w, r, http.StatusNotFound, VulnerabilityEnvelope{Error: &Error{err.Error()}})
|
writeResponse(w, r, http.StatusNotFound, VulnerabilityEnvelope{Error: &Error{err.Error()}})
|
||||||
return getVulnerabilityRoute, http.StatusNotFound
|
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) {
|
func getVulnerability(w http.ResponseWriter, r *http.Request, p httprouter.Params, ctx *context.RouteContext) (string, int) {
|
||||||
_, withFixedIn := r.URL.Query()["fixedIn"]
|
_, 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 {
|
if err == cerrors.ErrNotFound {
|
||||||
writeResponse(w, r, http.StatusNotFound, VulnerabilityEnvelope{Error: &Error{err.Error()}})
|
writeResponse(w, r, http.StatusNotFound, VulnerabilityEnvelope{Error: &Error{err.Error()}})
|
||||||
return getVulnerabilityRoute, http.StatusNotFound
|
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) {
|
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{}
|
request := VulnerabilityEnvelope{}
|
||||||
err := decodeJSON(r, &request)
|
err := decodeJSON(r, &request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -325,7 +342,7 @@ func putVulnerability(w http.ResponseWriter, r *http.Request, p httprouter.Param
|
|||||||
return putVulnerabilityRoute, http.StatusBadRequest
|
return putVulnerabilityRoute, http.StatusBadRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
vuln.Namespace.Name = p.ByName("namespaceName")
|
vuln.Namespace.ID = namespaceID
|
||||||
vuln.Name = p.ByName("vulnerabilityName")
|
vuln.Name = p.ByName("vulnerabilityName")
|
||||||
|
|
||||||
err = ctx.Store.InsertVulnerabilities([]database.Vulnerability{vuln}, true)
|
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) {
|
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 {
|
if err == cerrors.ErrNotFound {
|
||||||
writeResponse(w, r, http.StatusNotFound, VulnerabilityEnvelope{Error: &Error{err.Error()}})
|
writeResponse(w, r, http.StatusNotFound, VulnerabilityEnvelope{Error: &Error{err.Error()}})
|
||||||
return deleteVulnerabilityRoute, http.StatusNotFound
|
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) {
|
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 {
|
if err == cerrors.ErrNotFound {
|
||||||
writeResponse(w, r, http.StatusNotFound, FeatureEnvelope{Error: &Error{err.Error()}})
|
writeResponse(w, r, http.StatusNotFound, FeatureEnvelope{Error: &Error{err.Error()}})
|
||||||
return getFixesRoute, http.StatusNotFound
|
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) {
|
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{}
|
request := FeatureEnvelope{}
|
||||||
err := decodeJSON(r, &request)
|
err := decodeJSON(r, &request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -397,7 +432,7 @@ func putFix(w http.ResponseWriter, r *http.Request, p httprouter.Params, ctx *co
|
|||||||
return putFixRoute, http.StatusBadRequest
|
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 {
|
if err != nil {
|
||||||
switch err.(type) {
|
switch err.(type) {
|
||||||
case *cerrors.ErrBadRequest:
|
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) {
|
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 {
|
if err == cerrors.ErrNotFound {
|
||||||
writeResponse(w, r, http.StatusNotFound, FeatureEnvelope{Error: &Error{err.Error()}})
|
writeResponse(w, r, http.StatusNotFound, FeatureEnvelope{Error: &Error{err.Error()}})
|
||||||
return deleteFixRoute, http.StatusNotFound
|
return deleteFixRoute, http.StatusNotFound
|
||||||
|
@ -67,6 +67,8 @@ type Datastore interface {
|
|||||||
// # Namespace
|
// # Namespace
|
||||||
// ListNamespaces returns the entire list of known Namespaces.
|
// ListNamespaces returns the entire list of known Namespaces.
|
||||||
ListNamespaces() ([]Namespace, error)
|
ListNamespaces() ([]Namespace, error)
|
||||||
|
// GetNamespaceID returns the id by name and version.
|
||||||
|
GetNamespaceID(Namespace) (int, error)
|
||||||
|
|
||||||
// # Layer
|
// # Layer
|
||||||
// InsertLayer stores a Layer in the database.
|
// 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 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.
|
// 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.
|
// 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
|
// InsertVulnerabilities stores the given Vulnerabilities in the database, updating them if
|
||||||
// necessary. A vulnerability is uniquely identified by its Namespace and its Name.
|
// 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
|
InsertVulnerabilities(vulnerabilities []Vulnerability, createNotification bool) error
|
||||||
|
|
||||||
// FindVulnerability retrieves a Vulnerability from the database, including the FixedIn list.
|
// 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.
|
// DeleteVulnerability removes a Vulnerability from the database.
|
||||||
// It has to create a Notification that will contain the old Vulnerability.
|
// 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
|
// InsertVulnerabilityFixes adds new FixedIn Feature or update the Versions of existing ones to
|
||||||
// the specified Vulnerability in the database.
|
// the specified Vulnerability in the database.
|
||||||
// It has has to create a Notification that will contain the old and the updated Vulnerability.
|
// 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
|
// 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
|
// database. It can be used to store the fact that a Vulnerability no longer affects the given
|
||||||
// Feature in any Version.
|
// Feature in any Version.
|
||||||
// It has has to create a Notification that will contain the old and the updated Vulnerability.
|
// 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
|
// # Notification
|
||||||
// GetAvailableNotification returns the Name, Created, Notified and Deleted fields of a
|
// 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.
|
// The default behavior of each method is to simply panic.
|
||||||
type MockDatastore struct {
|
type MockDatastore struct {
|
||||||
FctListNamespaces func() ([]Namespace, error)
|
FctListNamespaces func() ([]Namespace, error)
|
||||||
|
FctGetNamespaceID func(namespace Namespace) (int, error)
|
||||||
FctInsertLayer func(Layer) error
|
FctInsertLayer func(Layer) error
|
||||||
FctFindLayer func(name string, withFeatures, withVulnerabilities bool) (Layer, error)
|
FctFindLayer func(name string, withFeatures, withVulnerabilities bool) (Layer, error)
|
||||||
FctDeleteLayer func(name string) 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
|
FctInsertVulnerabilities func(vulnerabilities []Vulnerability, createNotification bool) error
|
||||||
FctFindVulnerability func(namespace Namespace, name string) (Vulnerability, error)
|
FctFindVulnerability func(namespaceID int, name string) (Vulnerability, error)
|
||||||
FctDeleteVulnerability func(namespace Namespace, name string) error
|
FctDeleteVulnerability func(namespaceID int, name string) error
|
||||||
FctInsertVulnerabilityFixes func(vulnerabilityNamespace Namespace, vulnerabilityName string, fixes []FeatureVersion) error
|
FctInsertVulnerabilityFixes func(vulnerabilityNamespaceID int, vulnerabilityName string, fixes []FeatureVersion) error
|
||||||
FctDeleteVulnerabilityFix func(vulnerabilityNamespace Namespace, vulnerabilityName, featureName string) error
|
FctDeleteVulnerabilityFix func(vulnerabilityNamespaceID int, vulnerabilityName, featureName string) error
|
||||||
FctGetAvailableNotification func(renotifyInterval time.Duration) (VulnerabilityNotification, error)
|
FctGetAvailableNotification func(renotifyInterval time.Duration) (VulnerabilityNotification, error)
|
||||||
FctGetNotification func(name string, limit int, page VulnerabilityNotificationPageNumber) (VulnerabilityNotification, VulnerabilityNotificationPageNumber, error)
|
FctGetNotification func(name string, limit int, page VulnerabilityNotificationPageNumber) (VulnerabilityNotification, VulnerabilityNotificationPageNumber, error)
|
||||||
FctSetNotificationNotified func(name string) error
|
FctSetNotificationNotified func(name string) error
|
||||||
@ -49,6 +50,13 @@ func (mds *MockDatastore) ListNamespaces() ([]Namespace, error) {
|
|||||||
panic("required mock function not implemented")
|
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 {
|
func (mds *MockDatastore) InsertLayer(layer Layer) error {
|
||||||
if mds.FctInsertLayer != nil {
|
if mds.FctInsertLayer != nil {
|
||||||
return mds.FctInsertLayer(layer)
|
return mds.FctInsertLayer(layer)
|
||||||
@ -70,9 +78,9 @@ func (mds *MockDatastore) DeleteLayer(name string) error {
|
|||||||
panic("required mock function not implemented")
|
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 {
|
if mds.FctListVulnerabilities != nil {
|
||||||
return mds.FctListVulnerabilities(namespace, limit, page)
|
return mds.FctListVulnerabilities(namespaceID, limit, page)
|
||||||
}
|
}
|
||||||
panic("required mock function not implemented")
|
panic("required mock function not implemented")
|
||||||
}
|
}
|
||||||
@ -84,30 +92,30 @@ func (mds *MockDatastore) InsertVulnerabilities(vulnerabilities []Vulnerability,
|
|||||||
panic("required mock function not implemented")
|
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 {
|
if mds.FctFindVulnerability != nil {
|
||||||
return mds.FctFindVulnerability(namespace, name)
|
return mds.FctFindVulnerability(namespaceID, name)
|
||||||
}
|
}
|
||||||
panic("required mock function not implemented")
|
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 {
|
if mds.FctDeleteVulnerability != nil {
|
||||||
return mds.FctDeleteVulnerability(namespace, name)
|
return mds.FctDeleteVulnerability(namespaceID, name)
|
||||||
}
|
}
|
||||||
panic("required mock function not implemented")
|
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 {
|
if mds.FctInsertVulnerabilityFixes != nil {
|
||||||
return mds.FctInsertVulnerabilityFixes(vulnerabilityNamespace, vulnerabilityName, fixes)
|
return mds.FctInsertVulnerabilityFixes(vulnerabilityNamespaceID, vulnerabilityName, fixes)
|
||||||
}
|
}
|
||||||
panic("required mock function not implemented")
|
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 {
|
if mds.FctDeleteVulnerabilityFix != nil {
|
||||||
return mds.FctDeleteVulnerabilityFix(vulnerabilityNamespace, vulnerabilityName, featureName)
|
return mds.FctDeleteVulnerabilityFix(vulnerabilityNamespaceID, vulnerabilityName, featureName)
|
||||||
}
|
}
|
||||||
panic("required mock function not implemented")
|
panic("required mock function not implemented")
|
||||||
}
|
}
|
||||||
|
@ -21,13 +21,13 @@ var DebianReleasesMapping = map[string]string{
|
|||||||
"wheezy": "7",
|
"wheezy": "7",
|
||||||
"jessie": "8",
|
"jessie": "8",
|
||||||
"stretch": "9",
|
"stretch": "9",
|
||||||
"sid": "unstable",
|
"sid": "10",
|
||||||
|
|
||||||
// Class names
|
// Class names
|
||||||
"oldstable": "7",
|
"oldstable": "7",
|
||||||
"stable": "8",
|
"stable": "8",
|
||||||
"testing": "9",
|
"testing": "9",
|
||||||
"unstable": "unstable",
|
"unstable": "10",
|
||||||
}
|
}
|
||||||
|
|
||||||
// UbuntuReleasesMapping translates Ubuntu code names to version numbers
|
// 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)},
|
Model: database.Model{ID: int(parentID.Int64)},
|
||||||
Name: parentName.String,
|
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
|
// Find its namespaces
|
||||||
|
@ -209,14 +209,18 @@ func testInsertLayerTree(t *testing.T, datastore database.Datastore) {
|
|||||||
// This layer changes the namespace and adds Features.
|
// This layer changes the namespace and adds Features.
|
||||||
{
|
{
|
||||||
Name: "TestInsertLayer3",
|
Name: "TestInsertLayer3",
|
||||||
Parent: &database.Layer{Name: "TestInsertLayer2"},
|
Parent: &database.Layer{Name: "TestInsertLayer2",
|
||||||
|
Namespaces: []database.Namespace{testInsertLayerNamespace1},
|
||||||
|
},
|
||||||
Namespaces: []database.Namespace{testInsertLayerNamespace2},
|
Namespaces: []database.Namespace{testInsertLayerNamespace2},
|
||||||
Features: []database.FeatureVersion{f1, f2, f3},
|
Features: []database.FeatureVersion{f1, f2, f3},
|
||||||
},
|
},
|
||||||
// This layer covers the case where the last layer doesn't provide any new Feature.
|
// This layer covers the case where the last layer doesn't provide any new Feature.
|
||||||
{
|
{
|
||||||
Name: "TestInsertLayer4a",
|
Name: "TestInsertLayer4a",
|
||||||
Parent: &database.Layer{Name: "TestInsertLayer3"},
|
Parent: &database.Layer{Name: "TestInsertLayer3",
|
||||||
|
Namespaces: []database.Namespace{testInsertLayerNamespace1, testInsertLayerNamespace2},
|
||||||
|
},
|
||||||
Features: []database.FeatureVersion{f1, f2, f3},
|
Features: []database.FeatureVersion{f1, f2, f3},
|
||||||
},
|
},
|
||||||
// This layer covers the case where the last layer provides Features.
|
// This layer covers the case where the last layer provides Features.
|
||||||
@ -224,7 +228,9 @@ func testInsertLayerTree(t *testing.T, datastore database.Datastore) {
|
|||||||
// Namespaces should then remain unchanged.
|
// Namespaces should then remain unchanged.
|
||||||
{
|
{
|
||||||
Name: "TestInsertLayer4b",
|
Name: "TestInsertLayer4b",
|
||||||
Parent: &database.Layer{Name: "TestInsertLayer3"},
|
Parent: &database.Layer{Name: "TestInsertLayer3",
|
||||||
|
Namespaces: []database.Namespace{testInsertLayerNamespace1, testInsertLayerNamespace2},
|
||||||
|
},
|
||||||
Namespaces: []database.Namespace{testInsertLayerNamespace3},
|
Namespaces: []database.Namespace{testInsertLayerNamespace3},
|
||||||
Features: []database.FeatureVersion{
|
Features: []database.FeatureVersion{
|
||||||
// Deletes TestInsertLayerFeature1.
|
// Deletes TestInsertLayerFeature1.
|
||||||
@ -295,6 +301,8 @@ func testInsertLayerUpdate(t *testing.T, datastore database.Datastore) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
l3, _ := datastore.FindLayer("TestInsertLayer3", true, false)
|
l3, _ := datastore.FindLayer("TestInsertLayer3", true, false)
|
||||||
|
l3Parent, _ := datastore.FindLayer(l3.Parent.Name, false, false)
|
||||||
|
l3.Parent = &l3Parent
|
||||||
l3u := database.Layer{
|
l3u := database.Layer{
|
||||||
Name: l3.Name,
|
Name: l3.Name,
|
||||||
Parent: l3.Parent,
|
Parent: l3.Parent,
|
||||||
@ -304,7 +312,7 @@ func testInsertLayerUpdate(t *testing.T, datastore database.Datastore) {
|
|||||||
|
|
||||||
l4u := database.Layer{
|
l4u := database.Layer{
|
||||||
Name: "TestInsertLayer4",
|
Name: "TestInsertLayer4",
|
||||||
Parent: &database.Layer{Name: "TestInsertLayer3"},
|
Parent: &database.Layer{Name: "TestInsertLayer3", Namespaces: l3.Namespaces},
|
||||||
Features: []database.FeatureVersion{f7},
|
Features: []database.FeatureVersion{f7},
|
||||||
EngineVersion: 2,
|
EngineVersion: 2,
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
-- Copyright 2015 clair authors
|
-- Copyright 2016 clair authors
|
||||||
--
|
--
|
||||||
-- Licensed under the Apache License, Version 2.0 (the "License");
|
-- Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
-- you may not use this file except in compliance with 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)
|
INSERT INTO LayerNamespace(layer_id, namespace_id)
|
||||||
SELECT id, namespace_id
|
SELECT id, namespace_id
|
||||||
from Layer;
|
from Layer WHERE namespace_id IS NOT NULL;
|
||||||
|
|
||||||
-- -----------------------------------------------------
|
-- -----------------------------------------------------
|
||||||
-- Layer table
|
-- Layer table
|
||||||
|
@ -50,6 +50,30 @@ func (pgSQL *pgSQL) insertNamespace(namespace database.Namespace) (int, error) {
|
|||||||
return id, nil
|
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) {
|
func (pgSQL *pgSQL) ListNamespaces() (namespaces []database.Namespace, err error) {
|
||||||
rows, err := pgSQL.Query(listNamespace)
|
rows, err := pgSQL.Query(listNamespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -118,7 +118,8 @@ func TestNotification(t *testing.T) {
|
|||||||
assert.Nil(t, datastore.insertVulnerability(v1, false, true))
|
assert.Nil(t, datastore.insertVulnerability(v1, false, true))
|
||||||
|
|
||||||
// Get the notification associated to the previously inserted vulnerability.
|
// 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) {
|
if assert.Nil(t, err) && assert.NotEmpty(t, notification.Name) {
|
||||||
// Verify the renotify behaviour.
|
// 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.
|
// 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)
|
notification, err = datastore.GetAvailableNotification(time.Second)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.NotEmpty(t, notification.Name)
|
assert.NotEmpty(t, notification.Name)
|
||||||
|
@ -37,9 +37,9 @@ const (
|
|||||||
SELECT id FROM Namespace WHERE name = $1 AND version = $2
|
SELECT id FROM Namespace WHERE name = $1 AND version = $2
|
||||||
UNION
|
UNION
|
||||||
SELECT id FROM new_namespace`
|
SELECT id FROM new_namespace`
|
||||||
|
getNamespaceID = `SELECT id FROM Namespace WHERE name = $1 AND version = $2`
|
||||||
searchNamespace = `SELECT id FROM Namespace WHERE name = $1 AND version = $2`
|
listNamespace = `SELECT id, name, version FROM Namespace where version IS NOT NULL`
|
||||||
listNamespace = `SELECT id, name, version FROM Namespace`
|
getNamespaceByID = `SELECT name, version FROM Namespace WHERE id = $1`
|
||||||
|
|
||||||
// feature.go
|
// feature.go
|
||||||
soiFeature = `
|
soiFeature = `
|
||||||
@ -162,7 +162,7 @@ const (
|
|||||||
SELECT v.id, v.name, n.id, n.name, n.version, v.description, v.link, v.severity, v.metadata
|
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`
|
FROM Vulnerability v JOIN Namespace n ON v.namespace_id = n.id`
|
||||||
searchVulnerabilityForUpdate = ` FOR UPDATE OF v`
|
searchVulnerabilityForUpdate = ` FOR UPDATE OF v`
|
||||||
searchVulnerabilityByNamespaceAndName = ` WHERE n.name = $1 AND n.version = $2 AND v.name = $3 AND v.deleted_at IS NULL`
|
searchVulnerabilityByNamespaceIDAndName = ` WHERE n.id = $1 AND v.name = $2 AND v.deleted_at IS NULL`
|
||||||
searchVulnerabilityByID = ` WHERE v.id = $1`
|
searchVulnerabilityByID = ` WHERE v.id = $1`
|
||||||
searchVulnerabilityByNamespaceID = ` WHERE n.id = $1 AND v.deleted_at IS NULL
|
searchVulnerabilityByNamespaceID = ` WHERE n.id = $1 AND v.deleted_at IS NULL
|
||||||
AND v.id >= $2
|
AND v.id >= $2
|
||||||
@ -189,8 +189,8 @@ const (
|
|||||||
removeVulnerability = `
|
removeVulnerability = `
|
||||||
UPDATE Vulnerability
|
UPDATE Vulnerability
|
||||||
SET deleted_at = CURRENT_TIMESTAMP
|
SET deleted_at = CURRENT_TIMESTAMP
|
||||||
WHERE namespace_id = (SELECT id FROM Namespace WHERE name = $1 AND version = $2)
|
WHERE namespace_id = $1
|
||||||
AND name = $3
|
AND name = $2
|
||||||
AND deleted_at IS NULL
|
AND deleted_at IS NULL
|
||||||
RETURNING id`
|
RETURNING id`
|
||||||
|
|
||||||
|
@ -28,21 +28,12 @@ import (
|
|||||||
"github.com/guregu/null/zero"
|
"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())
|
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.
|
||||||
query := searchVulnerabilityBase + searchVulnerabilityByNamespaceID
|
query := searchVulnerabilityBase + searchVulnerabilityByNamespaceID
|
||||||
rows, err := pgSQL.Query(query, id, startID, limit+1)
|
rows, err := pgSQL.Query(query, namespaceID, startID, limit+1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, -1, handleError("searchVulnerabilityByNamespaceID", err)
|
return nil, -1, handleError("searchVulnerabilityByNamespaceID", err)
|
||||||
}
|
}
|
||||||
@ -84,21 +75,21 @@ func (pgSQL *pgSQL) ListVulnerabilities(namespace database.Namespace, limit int,
|
|||||||
return vulns, nextID, nil
|
return vulns, nextID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pgSQL *pgSQL) FindVulnerability(namespace database.Namespace, name string) (database.Vulnerability, error) {
|
func (pgSQL *pgSQL) FindVulnerability(namespaceID int, name string) (database.Vulnerability, error) {
|
||||||
return findVulnerability(pgSQL, namespace, name, false)
|
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())
|
defer observeQueryTime("findVulnerability", "all", time.Now())
|
||||||
|
|
||||||
queryName := "searchVulnerabilityBase+searchVulnerabilityByNamespaceAndName"
|
queryName := "searchVulnerabilityBase+searchVulnerabilityByNamespaceIDAndName"
|
||||||
query := searchVulnerabilityBase + searchVulnerabilityByNamespaceAndName
|
query := searchVulnerabilityBase + searchVulnerabilityByNamespaceIDAndName
|
||||||
if forUpdate {
|
if forUpdate {
|
||||||
queryName = queryName + "+searchVulnerabilityForUpdate"
|
queryName = queryName + "+searchVulnerabilityForUpdate"
|
||||||
query = query + 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) {
|
func (pgSQL *pgSQL) findVulnerabilityByIDWithDeleted(id int) (database.Vulnerability, error) {
|
||||||
@ -195,9 +186,24 @@ func (pgSQL *pgSQL) insertVulnerability(vulnerability database.Vulnerability, on
|
|||||||
tf := time.Now()
|
tf := time.Now()
|
||||||
|
|
||||||
// Verify parameters
|
// Verify parameters
|
||||||
if vulnerability.Name == "" || vulnerability.Namespace.IsEmpty() {
|
if vulnerability.Name == "" {
|
||||||
return cerrors.NewBadRequestError("insertVulnerability needs at least the Name and the Namespace")
|
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() {
|
if !onlyFixedIn && !vulnerability.Severity.IsValid() {
|
||||||
msg := fmt.Sprintf("could not insert a vulnerability that has an invalid Severity: %s", vulnerability.Severity)
|
msg := fmt.Sprintf("could not insert a vulnerability that has an invalid Severity: %s", vulnerability.Severity)
|
||||||
log.Warning(msg)
|
log.Warning(msg)
|
||||||
@ -209,8 +215,7 @@ func (pgSQL *pgSQL) insertVulnerability(vulnerability database.Vulnerability, on
|
|||||||
if fifv.Feature.Namespace.IsEmpty() {
|
if fifv.Feature.Namespace.IsEmpty() {
|
||||||
// As there is no Namespace on that FixedIn FeatureVersion, set it to the Vulnerability's
|
// As there is no Namespace on that FixedIn FeatureVersion, set it to the Vulnerability's
|
||||||
// Namespace.
|
// Namespace.
|
||||||
fifv.Feature.Namespace.Name = vulnerability.Namespace.Name
|
fifv.Feature.Namespace = vulnerability.Namespace
|
||||||
fifv.Feature.Namespace.Version = vulnerability.Namespace.Version
|
|
||||||
} else if !fifv.Feature.Namespace.Equal(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"
|
msg := "could not insert an invalid vulnerability that contains FixedIn FeatureVersion that are not in the same namespace as the Vulnerability"
|
||||||
log.Warning(msg)
|
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).
|
// 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 {
|
if err != nil && err != cerrors.ErrNotFound {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
return err
|
return err
|
||||||
@ -267,7 +272,7 @@ func (pgSQL *pgSQL) insertVulnerability(vulnerability database.Vulnerability, on
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Mark the old vulnerability as non latest.
|
// 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 {
|
if err != nil {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
return handleError("removeVulnerability", err)
|
return handleError("removeVulnerability", err)
|
||||||
@ -284,16 +289,10 @@ func (pgSQL *pgSQL) insertVulnerability(vulnerability database.Vulnerability, on
|
|||||||
vulnerability.FixedIn = fixedIn
|
vulnerability.FixedIn = fixedIn
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find or insert Vulnerability's Namespace.
|
|
||||||
namespaceID, err := pgSQL.insertNamespace(vulnerability.Namespace)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert vulnerability.
|
// Insert vulnerability.
|
||||||
err = tx.QueryRow(
|
err = tx.QueryRow(
|
||||||
insertVulnerability,
|
insertVulnerability,
|
||||||
namespaceID,
|
vulnerability.Namespace.ID,
|
||||||
vulnerability.Name,
|
vulnerability.Name,
|
||||||
vulnerability.Description,
|
vulnerability.Description,
|
||||||
vulnerability.Link,
|
vulnerability.Link,
|
||||||
@ -500,38 +499,41 @@ func linkVulnerabilityToFeatureVersions(tx *sql.Tx, fixedInID, vulnerabilityID,
|
|||||||
return nil
|
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())
|
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{
|
v := database.Vulnerability{
|
||||||
Name: vulnerabilityName,
|
Name: vulnerabilityName,
|
||||||
Namespace: database.Namespace{
|
Namespace: vns,
|
||||||
Name: vulnerabilityNamespace.Name,
|
|
||||||
Version: vulnerabilityNamespace.Version,
|
|
||||||
},
|
|
||||||
FixedIn: fixes,
|
FixedIn: fixes,
|
||||||
}
|
}
|
||||||
|
|
||||||
return pgSQL.insertVulnerability(v, true, true)
|
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())
|
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{
|
v := database.Vulnerability{
|
||||||
Name: vulnerabilityName,
|
Name: vulnerabilityName,
|
||||||
Namespace: database.Namespace{
|
Namespace: vns,
|
||||||
Name: vulnerabilityNamespace.Name,
|
|
||||||
Version: vulnerabilityNamespace.Version,
|
|
||||||
},
|
|
||||||
FixedIn: []database.FeatureVersion{
|
FixedIn: []database.FeatureVersion{
|
||||||
{
|
{
|
||||||
Feature: database.Feature{
|
Feature: database.Feature{
|
||||||
Name: featureName,
|
Name: featureName,
|
||||||
Namespace: database.Namespace{
|
Namespace: vns,
|
||||||
Name: vulnerabilityNamespace.Name,
|
|
||||||
Version: vulnerabilityNamespace.Version,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Version: types.MinVersion,
|
Version: types.MinVersion,
|
||||||
},
|
},
|
||||||
@ -541,7 +543,7 @@ func (pgSQL *pgSQL) DeleteVulnerabilityFix(vulnerabilityNamespace database.Names
|
|||||||
return pgSQL.insertVulnerability(v, true, true)
|
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())
|
defer observeQueryTime("DeleteVulnerability", "all", time.Now())
|
||||||
|
|
||||||
// Begin transaction.
|
// Begin transaction.
|
||||||
@ -552,7 +554,7 @@ func (pgSQL *pgSQL) DeleteVulnerability(namespace database.Namespace, name strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
var vulnerabilityID int
|
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 {
|
if err != nil {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
return handleError("removeVulnerability", err)
|
return handleError("removeVulnerability", err)
|
||||||
|
@ -37,8 +37,12 @@ func TestFindVulnerability(t *testing.T) {
|
|||||||
Name: "debian",
|
Name: "debian",
|
||||||
Version: types.NewVersionUnsafe("7"),
|
Version: types.NewVersionUnsafe("7"),
|
||||||
}
|
}
|
||||||
|
var testExistNamespaceID int
|
||||||
|
testExistNamespaceID, err = datastore.GetNamespaceID(testExistNamespace)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
// Find a vulnerability that does not exist.
|
// Find a vulnerability that does not exist.
|
||||||
_, err = datastore.FindVulnerability(database.Namespace{}, "")
|
_, err = datastore.FindVulnerability(-1, "")
|
||||||
assert.Equal(t, cerrors.ErrNotFound, err)
|
assert.Equal(t, cerrors.ErrNotFound, err)
|
||||||
|
|
||||||
// Find a normal vulnerability.
|
// 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) {
|
if assert.Nil(t, err) {
|
||||||
equalsVuln(t, &v1, &v1f)
|
equalsVuln(t, &v1, &v1f)
|
||||||
}
|
}
|
||||||
@ -73,7 +77,7 @@ func TestFindVulnerability(t *testing.T) {
|
|||||||
Severity: types.Unknown,
|
Severity: types.Unknown,
|
||||||
}
|
}
|
||||||
|
|
||||||
v2f, err := datastore.FindVulnerability(testExistNamespace, "CVE-NOPE")
|
v2f, err := datastore.FindVulnerability(testExistNamespaceID, "CVE-NOPE")
|
||||||
if assert.Nil(t, err) {
|
if assert.Nil(t, err) {
|
||||||
equalsVuln(t, &v2, &v2f)
|
equalsVuln(t, &v2, &v2f)
|
||||||
}
|
}
|
||||||
@ -91,20 +95,28 @@ func TestDeleteVulnerability(t *testing.T) {
|
|||||||
Name: "debian",
|
Name: "debian",
|
||||||
Version: types.NewVersionUnsafe("7"),
|
Version: types.NewVersionUnsafe("7"),
|
||||||
}
|
}
|
||||||
|
var testExistNamespaceID int
|
||||||
|
testExistNamespaceID, err = datastore.GetNamespaceID(testExistNamespace)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
testNonExistNamespace := database.Namespace{
|
testNonExistNamespace := database.Namespace{
|
||||||
Name: "TestDeleteVulnerabilityNamespace",
|
Name: "TestDeleteVulnerabilityNamespace",
|
||||||
Version: types.NewVersionUnsafe("1.0"),
|
Version: types.NewVersionUnsafe("1.0"),
|
||||||
}
|
}
|
||||||
// Delete non-existing Vulnerability.
|
var testNonExistNamespaceID int
|
||||||
err = datastore.DeleteVulnerability(testNonExistNamespace, "CVE-OPENSSL-1-DEB7")
|
testNonExistNamespaceID, err = datastore.GetNamespaceID(testNonExistNamespace)
|
||||||
assert.Equal(t, cerrors.ErrNotFound, err)
|
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)
|
assert.Equal(t, cerrors.ErrNotFound, err)
|
||||||
|
|
||||||
// Delete Vulnerability.
|
// Delete Vulnerability.
|
||||||
err = datastore.DeleteVulnerability(testExistNamespace, "CVE-OPENSSL-1-DEB7")
|
err = datastore.DeleteVulnerability(testExistNamespaceID, "CVE-OPENSSL-1-DEB7")
|
||||||
if assert.Nil(t, err) {
|
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)
|
assert.Equal(t, cerrors.ErrNotFound, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -228,7 +240,11 @@ func TestInsertVulnerability(t *testing.T) {
|
|||||||
}
|
}
|
||||||
err = datastore.InsertVulnerabilities([]database.Vulnerability{v1}, true)
|
err = datastore.InsertVulnerabilities([]database.Vulnerability{v1}, true)
|
||||||
if assert.Nil(t, err) {
|
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) {
|
if assert.Nil(t, err) {
|
||||||
equalsVuln(t, &v1, &v1f)
|
equalsVuln(t, &v1, &v1f)
|
||||||
}
|
}
|
||||||
@ -244,7 +260,11 @@ func TestInsertVulnerability(t *testing.T) {
|
|||||||
|
|
||||||
err = datastore.InsertVulnerabilities([]database.Vulnerability{v1}, true)
|
err = datastore.InsertVulnerabilities([]database.Vulnerability{v1}, true)
|
||||||
if assert.Nil(t, err) {
|
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) {
|
if assert.Nil(t, err) {
|
||||||
// We already had f1 before the update.
|
// We already had f1 before the update.
|
||||||
// Add it to the struct for comparison.
|
// 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.
|
// Determine the version of the package the vulnerability affects.
|
||||||
var version types.Version
|
var version types.Version
|
||||||
|
var nsVersion types.Version
|
||||||
var err error
|
var err error
|
||||||
if releaseNode.FixedVersion == "0" {
|
if releaseNode.FixedVersion == "0" {
|
||||||
// This means that the package is not affected by this vulnerability.
|
// 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.
|
// Create and add the feature version.
|
||||||
pkg := database.FeatureVersion{
|
pkg := database.FeatureVersion{
|
||||||
Feature: database.Feature{
|
Feature: database.Feature{
|
||||||
Name: pkgName,
|
Name: pkgName,
|
||||||
Namespace: database.Namespace{
|
Namespace: database.Namespace{
|
||||||
Name: "debian",
|
Name: "debian",
|
||||||
Version: types.NewVersionUnsafe(database.DebianReleasesMapping[releaseName]),
|
Version: nsVersion,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Version: version,
|
Version: version,
|
||||||
|
@ -48,7 +48,7 @@ func TestDebianParser(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
Feature: database.Feature{
|
Feature: database.Feature{
|
||||||
Namespace: database.Namespace{Name: "debian", Version: types.NewVersionUnsafe("unstable")},
|
Namespace: database.Namespace{Name: "debian", Version: types.NewVersionUnsafe("10")},
|
||||||
|
|
||||||
Name: "aptdaemon",
|
Name: "aptdaemon",
|
||||||
},
|
},
|
||||||
@ -74,7 +74,7 @@ func TestDebianParser(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
Feature: database.Feature{
|
Feature: database.Feature{
|
||||||
Namespace: database.Namespace{Name: "debian", Version: types.NewVersionUnsafe("unstable")},
|
Namespace: database.Namespace{Name: "debian", Version: types.NewVersionUnsafe("10")},
|
||||||
Name: "aptdaemon",
|
Name: "aptdaemon",
|
||||||
},
|
},
|
||||||
Version: types.NewVersionUnsafe("0.7.0"),
|
Version: types.NewVersionUnsafe("0.7.0"),
|
||||||
|
@ -291,8 +291,13 @@ func toFeatureVersions(criteria criteria) []database.FeatureVersion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if osVersion > firstConsideredRHEL {
|
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.Name = "centos"
|
||||||
featureVersion.Feature.Namespace.Version = types.NewVersionUnsafe(strconv.Itoa(osVersion))
|
featureVersion.Feature.Namespace.Version = nsVersion
|
||||||
} else {
|
} else {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -373,10 +373,15 @@ func parseUbuntuCVE(fileContent io.Reader) (vulnerability database.Vulnerability
|
|||||||
continue
|
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.
|
// Create and add the new package.
|
||||||
featureVersion := database.FeatureVersion{
|
featureVersion := database.FeatureVersion{
|
||||||
Feature: database.Feature{
|
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"],
|
Name: md["package"],
|
||||||
},
|
},
|
||||||
Version: version,
|
Version: version,
|
||||||
|
@ -68,8 +68,7 @@ func DetectFeatures(data map[string][]byte, namespaces []database.Namespace) ([]
|
|||||||
}
|
}
|
||||||
// Ensure that every feature has a Namespace associated
|
// Ensure that every feature has a Namespace associated
|
||||||
for i := 0; i < len(pkgs); i++ {
|
for i := 0; i < len(pkgs); i++ {
|
||||||
pkgs[i].Feature.Namespace.Name = namespace.Name
|
pkgs[i].Feature.Namespace = namespace
|
||||||
pkgs[i].Feature.Namespace.Version = namespace.Version
|
|
||||||
}
|
}
|
||||||
packages = append(packages, pkgs...)
|
packages = append(packages, pkgs...)
|
||||||
break
|
break
|
||||||
|
@ -76,7 +76,11 @@ func (detector *AptSourcesNamespaceDetector) Detect(data map[string][]byte) *dat
|
|||||||
}
|
}
|
||||||
|
|
||||||
if OS != "" && version != "" {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ import (
|
|||||||
|
|
||||||
var aptSourcesOSTests = []namespace.NamespaceTest{
|
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{
|
Data: map[string][]byte{
|
||||||
"etc/os-release": []byte(
|
"etc/os-release": []byte(
|
||||||
`PRETTY_NAME="Debian GNU/Linux stretch/sid"
|
`PRETTY_NAME="Debian GNU/Linux stretch/sid"
|
||||||
|
@ -71,7 +71,11 @@ func (detector *LsbReleaseNamespaceDetector) Detect(data map[string][]byte) *dat
|
|||||||
}
|
}
|
||||||
|
|
||||||
if OS != "" && version != "" {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,11 @@ func (detector *OsReleaseNamespaceDetector) Detect(data map[string][]byte) *data
|
|||||||
}
|
}
|
||||||
|
|
||||||
if OS != "" && version != "" {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,11 @@ func (detector *RedhatReleaseNamespaceDetector) Detect(data map[string][]byte) *
|
|||||||
|
|
||||||
r := redhatReleaseRegexp.FindStringSubmatch(string(f))
|
r := redhatReleaseRegexp.FindStringSubmatch(string(f))
|
||||||
if len(r) == 4 {
|
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