Merge pull request #849 from coreos-inc/vulnerability-tool-priority
Only send vulnerability events if the minimum priority is gte to that…
This commit is contained in:
commit
744ad9e79b
13 changed files with 175 additions and 156 deletions
|
@ -22,12 +22,19 @@ def notification_view(note):
|
||||||
except:
|
except:
|
||||||
config = {}
|
config = {}
|
||||||
|
|
||||||
|
event_config = {}
|
||||||
|
try:
|
||||||
|
event_config = json.loads(note.event_config_json)
|
||||||
|
except:
|
||||||
|
event_config = {}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'uuid': note.uuid,
|
'uuid': note.uuid,
|
||||||
'event': note.event.name,
|
'event': note.event.name,
|
||||||
'method': note.method.name,
|
'method': note.method.name,
|
||||||
'config': config,
|
'config': config,
|
||||||
'title': note.title,
|
'title': note.title,
|
||||||
|
'event_config': event_config,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -160,7 +167,7 @@ class TestRepositoryNotification(RepositoryParamResource):
|
||||||
raise NotFound()
|
raise NotFound()
|
||||||
|
|
||||||
event_info = NotificationEvent.get_event(test_note.event.name)
|
event_info = NotificationEvent.get_event(test_note.event.name)
|
||||||
sample_data = event_info.get_sample_data(repository=test_note.repository)
|
sample_data = event_info.get_sample_data(test_note)
|
||||||
notification_data = build_notification_data(test_note, sample_data)
|
notification_data = build_notification_data(test_note, sample_data)
|
||||||
notification_queue.put([test_note.repository.namespace_user.username, repository,
|
notification_queue.put([test_note.repository.namespace_user.username, repository,
|
||||||
test_note.event.name], json.dumps(notification_data))
|
test_note.event.name], json.dumps(notification_data))
|
||||||
|
|
|
@ -22,6 +22,7 @@ from werkzeug.routing import BaseConverter
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from config import frontend_visible_config
|
from config import frontend_visible_config
|
||||||
from external_libraries import get_external_javascript, get_external_css
|
from external_libraries import get_external_javascript, get_external_css
|
||||||
|
from util.secscan.api import PRIORITY_LEVELS
|
||||||
|
|
||||||
import features
|
import features
|
||||||
|
|
||||||
|
@ -183,6 +184,7 @@ def render_page_template(name, **kwargs):
|
||||||
config_set=json.dumps(frontend_visible_config(app.config)),
|
config_set=json.dumps(frontend_visible_config(app.config)),
|
||||||
oauth_set=json.dumps(get_oauth_config()),
|
oauth_set=json.dumps(get_oauth_config()),
|
||||||
scope_set=json.dumps(scopes.app_scopes(app.config)),
|
scope_set=json.dumps(scopes.app_scopes(app.config)),
|
||||||
|
vuln_priority_set=json.dumps(PRIORITY_LEVELS),
|
||||||
mixpanel_key=app.config.get('MIXPANEL_KEY', ''),
|
mixpanel_key=app.config.get('MIXPANEL_KEY', ''),
|
||||||
google_analytics_key=app.config.get('GOOGLE_ANALYTICS_KEY', ''),
|
google_analytics_key=app.config.get('GOOGLE_ANALYTICS_KEY', ''),
|
||||||
sentry_public_dsn=app.config.get('SENTRY_PUBLIC_DSN', ''),
|
sentry_public_dsn=app.config.get('SENTRY_PUBLIC_DSN', ''),
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
|
import json
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from notificationhelper import build_event_data
|
from notificationhelper import build_event_data
|
||||||
from util.jinjautil import get_template_env
|
from util.jinjautil import get_template_env
|
||||||
|
from util.secscan.api import PRIORITY_LEVELS, get_priority_for_index
|
||||||
|
|
||||||
template_env = get_template_env("events")
|
template_env = get_template_env("events")
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
@ -37,13 +39,18 @@ class NotificationEvent(object):
|
||||||
'notification_data': notification_data
|
'notification_data': notification_data
|
||||||
})
|
})
|
||||||
|
|
||||||
def get_sample_data(self, repository=None):
|
def get_sample_data(self, notification):
|
||||||
"""
|
"""
|
||||||
Returns sample data for testing the raising of this notification, with an optional
|
Returns sample data for testing the raising of this notification, with an example notification.
|
||||||
repository.
|
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def should_perform(self, event_data, notification_data):
|
||||||
|
"""
|
||||||
|
Whether a notification for this event should be performed. By default returns True.
|
||||||
|
"""
|
||||||
|
return True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def event_name(cls):
|
def event_name(cls):
|
||||||
"""
|
"""
|
||||||
|
@ -71,8 +78,8 @@ class RepoPushEvent(NotificationEvent):
|
||||||
def get_summary(self, event_data, notification_data):
|
def get_summary(self, event_data, notification_data):
|
||||||
return 'Repository %s updated' % (event_data['repository'])
|
return 'Repository %s updated' % (event_data['repository'])
|
||||||
|
|
||||||
def get_sample_data(self, repository):
|
def get_sample_data(self, notification):
|
||||||
return build_event_data(repository, {
|
return build_event_data(notification.repository, {
|
||||||
'updated_tags': {'latest': 'someimageid', 'foo': 'anotherimage'},
|
'updated_tags': {'latest': 'someimageid', 'foo': 'anotherimage'},
|
||||||
'pruned_image_count': 3
|
'pruned_image_count': 3
|
||||||
})
|
})
|
||||||
|
@ -99,18 +106,27 @@ class VulnerabilityFoundEvent(NotificationEvent):
|
||||||
|
|
||||||
return 'info'
|
return 'info'
|
||||||
|
|
||||||
def get_sample_data(self, repository):
|
def get_sample_data(self, notification):
|
||||||
return build_event_data(repository, {
|
event_config = json.loads(notification.event_config_json)
|
||||||
|
|
||||||
|
return build_event_data(notification.repository, {
|
||||||
'tags': ['latest', 'prod'],
|
'tags': ['latest', 'prod'],
|
||||||
'image': 'some-image-id',
|
'image': 'some-image-id',
|
||||||
'vulnerability': {
|
'vulnerability': {
|
||||||
'id': 'CVE-FAKE-CVE',
|
'id': 'CVE-FAKE-CVE',
|
||||||
'description': 'A futurist vulnerability',
|
'description': 'A futurist vulnerability',
|
||||||
'link': 'https://security-tracker.debian.org/tracker/CVE-FAKE-CVE',
|
'link': 'https://security-tracker.debian.org/tracker/CVE-FAKE-CVE',
|
||||||
'priority': 'Critical',
|
'priority': get_priority_for_index(event_config['level'])
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
def should_perform(self, event_data, notification_data):
|
||||||
|
event_config = json.loads(notification_data.event_config_json)
|
||||||
|
expected_level_index = event_config['level']
|
||||||
|
priority = PRIORITY_LEVELS[event_data['vulnerability']['priority']]
|
||||||
|
actual_level_index = priority['index']
|
||||||
|
return expected_level_index <= actual_level_index
|
||||||
|
|
||||||
def get_summary(self, event_data, notification_data):
|
def get_summary(self, event_data, notification_data):
|
||||||
msg = '%s vulnerability detected in repository %s in tags %s'
|
msg = '%s vulnerability detected in repository %s in tags %s'
|
||||||
return msg % (event_data['vulnerability']['priority'],
|
return msg % (event_data['vulnerability']['priority'],
|
||||||
|
@ -126,10 +142,10 @@ class BuildQueueEvent(NotificationEvent):
|
||||||
def get_level(self, event_data, notification_data):
|
def get_level(self, event_data, notification_data):
|
||||||
return 'info'
|
return 'info'
|
||||||
|
|
||||||
def get_sample_data(self, repository):
|
def get_sample_data(self, notification):
|
||||||
build_uuid = 'fake-build-id'
|
build_uuid = 'fake-build-id'
|
||||||
|
|
||||||
return build_event_data(repository, {
|
return build_event_data(notification.repository, {
|
||||||
'is_manual': False,
|
'is_manual': False,
|
||||||
'build_id': build_uuid,
|
'build_id': build_uuid,
|
||||||
'build_name': 'some-fake-build',
|
'build_name': 'some-fake-build',
|
||||||
|
@ -165,10 +181,10 @@ class BuildStartEvent(NotificationEvent):
|
||||||
def get_level(self, event_data, notification_data):
|
def get_level(self, event_data, notification_data):
|
||||||
return 'info'
|
return 'info'
|
||||||
|
|
||||||
def get_sample_data(self, repository):
|
def get_sample_data(self, notification):
|
||||||
build_uuid = 'fake-build-id'
|
build_uuid = 'fake-build-id'
|
||||||
|
|
||||||
return build_event_data(repository, {
|
return build_event_data(notification.repository, {
|
||||||
'build_id': build_uuid,
|
'build_id': build_uuid,
|
||||||
'build_name': 'some-fake-build',
|
'build_name': 'some-fake-build',
|
||||||
'docker_tags': ['latest', 'foo', 'bar'],
|
'docker_tags': ['latest', 'foo', 'bar'],
|
||||||
|
@ -193,10 +209,10 @@ class BuildSuccessEvent(NotificationEvent):
|
||||||
def get_level(self, event_data, notification_data):
|
def get_level(self, event_data, notification_data):
|
||||||
return 'success'
|
return 'success'
|
||||||
|
|
||||||
def get_sample_data(self, repository):
|
def get_sample_data(self, notification):
|
||||||
build_uuid = 'fake-build-id'
|
build_uuid = 'fake-build-id'
|
||||||
|
|
||||||
return build_event_data(repository, {
|
return build_event_data(notification.repository, {
|
||||||
'build_id': build_uuid,
|
'build_id': build_uuid,
|
||||||
'build_name': 'some-fake-build',
|
'build_name': 'some-fake-build',
|
||||||
'docker_tags': ['latest', 'foo', 'bar'],
|
'docker_tags': ['latest', 'foo', 'bar'],
|
||||||
|
@ -222,10 +238,10 @@ class BuildFailureEvent(NotificationEvent):
|
||||||
def get_level(self, event_data, notification_data):
|
def get_level(self, event_data, notification_data):
|
||||||
return 'error'
|
return 'error'
|
||||||
|
|
||||||
def get_sample_data(self, repository):
|
def get_sample_data(self, notification):
|
||||||
build_uuid = 'fake-build-id'
|
build_uuid = 'fake-build-id'
|
||||||
|
|
||||||
return build_event_data(repository, {
|
return build_event_data(notification.repository, {
|
||||||
'build_id': build_uuid,
|
'build_id': build_uuid,
|
||||||
'build_name': 'some-fake-build',
|
'build_name': 'some-fake-build',
|
||||||
'docker_tags': ['latest', 'foo', 'bar'],
|
'docker_tags': ['latest', 'foo', 'bar'],
|
||||||
|
|
|
@ -1,3 +1,13 @@
|
||||||
.repository-events-table-element .notification-row i.fa {
|
.repository-events-table-element .notification-row i.fa {
|
||||||
margin-right: 6px;
|
margin-right: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.repository-events-table-element .notification-event-fields {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0px;
|
||||||
|
margin-left: 28px;
|
||||||
|
margin-top: 3px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #888;
|
||||||
|
margin-bottom: 0px;
|
||||||
|
}
|
|
@ -44,6 +44,17 @@
|
||||||
<i class="fa fa-lg" ng-class="getEventInfo(notification).icon"></i>
|
<i class="fa fa-lg" ng-class="getEventInfo(notification).icon"></i>
|
||||||
{{ getEventInfo(notification).title }}
|
{{ getEventInfo(notification).title }}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
|
<ul class="notification-event-fields" ng-if="getEventInfo(notification).fields.length">
|
||||||
|
<li ng-repeat="field in getEventInfo(notification).fields">
|
||||||
|
{{ field.title }}:
|
||||||
|
<span ng-switch on="field.type">
|
||||||
|
<span ng-switch-when="enum">
|
||||||
|
{{ findEnumValue(field.values, notification.event_config[field.name]).title }}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
|
|
|
@ -43,6 +43,18 @@ angular.module('quay').directive('repositoryEventsTable', function () {
|
||||||
$scope.showNewNotificationCounter++;
|
$scope.showNewNotificationCounter++;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.findEnumValue = function(values, index) {
|
||||||
|
var found = null;
|
||||||
|
Object.keys(values).forEach(function(key) {
|
||||||
|
if (values[key]['index'] == index) {
|
||||||
|
found = values[key];
|
||||||
|
return
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return found
|
||||||
|
};
|
||||||
|
|
||||||
$scope.getEventInfo = function(notification) {
|
$scope.getEventInfo = function(notification) {
|
||||||
return ExternalNotificationData.getEventInfo(notification.event);
|
return ExternalNotificationData.getEventInfo(notification.event);
|
||||||
};
|
};
|
||||||
|
|
|
@ -129,7 +129,8 @@ function($rootScope, $interval, UserService, ApiService, StringBuilderService, P
|
||||||
'message': 'A {vulnerability.priority} vulnerability was detected in repository {repository}',
|
'message': 'A {vulnerability.priority} vulnerability was detected in repository {repository}',
|
||||||
'page': function(metadata) {
|
'page': function(metadata) {
|
||||||
return '/repository/' + metadata.repository + '?tab=tags';
|
return '/repository/' + metadata.repository + '?tab=tags';
|
||||||
}
|
},
|
||||||
|
'dismissable': true
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -3,89 +3,7 @@
|
||||||
*/
|
*/
|
||||||
angular.module('quay').factory('VulnerabilityService', ['Config', function(Config) {
|
angular.module('quay').factory('VulnerabilityService', ['Config', function(Config) {
|
||||||
var vulnService = {};
|
var vulnService = {};
|
||||||
|
vulnService.LEVELS = window.__vuln_priority;
|
||||||
// NOTE: This objects are used directly in the external-notification-data service, so make sure
|
|
||||||
// to update that code if the format here is changed.
|
|
||||||
vulnService.LEVELS = {
|
|
||||||
'Unknown': {
|
|
||||||
'title': 'Unknown',
|
|
||||||
'index': '6',
|
|
||||||
'level': 'info',
|
|
||||||
|
|
||||||
'description': 'Unknown is either a security problem that has not been assigned ' +
|
|
||||||
'to a priority yet or a priority that our system did not recognize',
|
|
||||||
'banner_required': false
|
|
||||||
},
|
|
||||||
|
|
||||||
'Negligible': {
|
|
||||||
'title': 'Negligible',
|
|
||||||
'index': '5',
|
|
||||||
'level': 'info',
|
|
||||||
|
|
||||||
'description': 'Negligible is technically a security problem, but is only theoretical ' +
|
|
||||||
'in nature, requires a very special situation, has almost no install base, ' +
|
|
||||||
'or does no real damage.',
|
|
||||||
'banner_required': false
|
|
||||||
},
|
|
||||||
|
|
||||||
'Low': {
|
|
||||||
'title': 'Low',
|
|
||||||
'index': '4',
|
|
||||||
'level': 'warning',
|
|
||||||
|
|
||||||
'description': 'Low is a security problem, but is hard to exploit due to environment, ' +
|
|
||||||
'requires a user-assisted attack, a small install base, or does very ' +
|
|
||||||
'little damage.',
|
|
||||||
'banner_required': false
|
|
||||||
},
|
|
||||||
|
|
||||||
'Medium': {
|
|
||||||
'title': 'Medium',
|
|
||||||
'value': 'Medium',
|
|
||||||
'index': '3',
|
|
||||||
'level': 'warning',
|
|
||||||
|
|
||||||
'description': 'Medium is a real security problem, and is exploitable for many people. ' +
|
|
||||||
'Includes network daemon denial of service attacks, cross-site scripting, ' +
|
|
||||||
'and gaining user privileges.',
|
|
||||||
'banner_required': false
|
|
||||||
},
|
|
||||||
|
|
||||||
'High': {
|
|
||||||
'title': 'High',
|
|
||||||
'value': 'High',
|
|
||||||
'index': '2',
|
|
||||||
'level': 'warning',
|
|
||||||
|
|
||||||
'description': 'High is a real problem, exploitable for many people in a default installation. ' +
|
|
||||||
'Includes serious remote denial of services, local root privilege escalations, ' +
|
|
||||||
'or data loss.',
|
|
||||||
'banner_required': false
|
|
||||||
},
|
|
||||||
|
|
||||||
'Critical': {
|
|
||||||
'title': 'Critical',
|
|
||||||
'value': 'Critical',
|
|
||||||
'index': '1',
|
|
||||||
'level': 'error',
|
|
||||||
|
|
||||||
'description': 'Critical is a world-burning problem, exploitable for nearly all people in ' +
|
|
||||||
'a installation of the package. Includes remote root privilege escalations, ' +
|
|
||||||
'or massive data loss.',
|
|
||||||
'banner_required': true
|
|
||||||
},
|
|
||||||
|
|
||||||
'Defcon1': {
|
|
||||||
'title': 'Defcon 1',
|
|
||||||
'value': 'Defcon1',
|
|
||||||
'index': '0',
|
|
||||||
'level': 'error',
|
|
||||||
|
|
||||||
'description': 'Defcon1 is a Critical problem which has been manually highlighted ' +
|
|
||||||
'by the Quay team. It requires immediate attention.',
|
|
||||||
'banner_required': true
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
vulnService.getLevels = function() {
|
vulnService.getLevels = function() {
|
||||||
return Object.keys(vulnService.LEVELS).map(function(key) {
|
return Object.keys(vulnService.LEVELS).map(function(key) {
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
window.__config = {{ config_set|safe }};
|
window.__config = {{ config_set|safe }};
|
||||||
window.__oauth = {{ oauth_set|safe }};
|
window.__oauth = {{ oauth_set|safe }};
|
||||||
window.__auth_scopes = {{ scope_set|safe }};
|
window.__auth_scopes = {{ scope_set|safe }};
|
||||||
|
window.__vuln_priority = {{ vuln_priority_set|safe }}
|
||||||
window.__token = '{{ csrf_token() }}';
|
window.__token = '{{ csrf_token() }}';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -1,51 +0,0 @@
|
||||||
import features
|
|
||||||
import logging
|
|
||||||
import requests
|
|
||||||
import json
|
|
||||||
|
|
||||||
from urlparse import urljoin
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
class SecEndpoint(object):
|
|
||||||
""" Helper class for talking to the Sec API. """
|
|
||||||
def __init__(self, app, config_provider):
|
|
||||||
self.app = app
|
|
||||||
self.config_provider = config_provider
|
|
||||||
|
|
||||||
if not features.SECURITY_SCANNER:
|
|
||||||
return
|
|
||||||
|
|
||||||
self.security_config = app.config['SECURITY_SCANNER']
|
|
||||||
|
|
||||||
self.certificate = self._getfilepath('CA_CERTIFICATE_FILENAME') or False
|
|
||||||
self.public_key = self._getfilepath('PUBLIC_KEY_FILENAME')
|
|
||||||
self.private_key = self._getfilepath('PRIVATE_KEY_FILENAME')
|
|
||||||
|
|
||||||
if self.public_key and self.private_key:
|
|
||||||
self.keys = (self.public_key, self.private_key)
|
|
||||||
else:
|
|
||||||
self.keys = None
|
|
||||||
|
|
||||||
def _getfilepath(self, config_key):
|
|
||||||
security_config = self.security_config
|
|
||||||
|
|
||||||
if config_key in security_config:
|
|
||||||
with self.config_provider.get_volume_file(security_config[config_key]) as f:
|
|
||||||
return f.name
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
def call_api(self, relative_url, *args, **kwargs):
|
|
||||||
""" Issues an HTTP call to the sec API at the given relative URL. """
|
|
||||||
security_config = self.security_config
|
|
||||||
api_url = urljoin(security_config['ENDPOINT'], '/' + security_config['API_VERSION']) + '/'
|
|
||||||
url = urljoin(api_url, relative_url % args)
|
|
||||||
|
|
||||||
client = self.app.config['HTTPCLIENT']
|
|
||||||
timeout = security_config.get('API_CALL_TIMEOUT', 1)
|
|
||||||
logger.debug('Looking up sec information: %s', url)
|
|
||||||
|
|
||||||
return client.get(url, params=kwargs, timeout=timeout, cert=self.keys,
|
|
||||||
verify=self.certificate)
|
|
||||||
|
|
|
@ -2,12 +2,103 @@ import features
|
||||||
import logging
|
import logging
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
from app import app
|
from data.database import CloseForLongOperation
|
||||||
from database import CloseForLongOperation
|
|
||||||
from urlparse import urljoin
|
from urlparse import urljoin
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# NOTE: This objects are used directly in the external-notification-data and vulnerability-service
|
||||||
|
# on the frontend, so be careful with changing their existing keys.
|
||||||
|
PRIORITY_LEVELS = {
|
||||||
|
'Unknown': {
|
||||||
|
'title': 'Unknown',
|
||||||
|
'index': '6',
|
||||||
|
'level': 'info',
|
||||||
|
|
||||||
|
'description': 'Unknown is either a security problem that has not been assigned ' +
|
||||||
|
'to a priority yet or a priority that our system did not recognize',
|
||||||
|
'banner_required': False
|
||||||
|
},
|
||||||
|
|
||||||
|
'Negligible': {
|
||||||
|
'title': 'Negligible',
|
||||||
|
'index': '5',
|
||||||
|
'level': 'info',
|
||||||
|
|
||||||
|
'description': 'Negligible is technically a security problem, but is only theoretical ' +
|
||||||
|
'in nature, requires a very special situation, has almost no install base, ' +
|
||||||
|
'or does no real damage.',
|
||||||
|
'banner_required': False
|
||||||
|
},
|
||||||
|
|
||||||
|
'Low': {
|
||||||
|
'title': 'Low',
|
||||||
|
'index': '4',
|
||||||
|
'level': 'warning',
|
||||||
|
|
||||||
|
'description': 'Low is a security problem, but is hard to exploit due to environment, ' +
|
||||||
|
'requires a user-assisted attack, a small install base, or does very ' +
|
||||||
|
'little damage.',
|
||||||
|
'banner_required': False
|
||||||
|
},
|
||||||
|
|
||||||
|
'Medium': {
|
||||||
|
'title': 'Medium',
|
||||||
|
'value': 'Medium',
|
||||||
|
'index': '3',
|
||||||
|
'level': 'warning',
|
||||||
|
|
||||||
|
'description': 'Medium is a real security problem, and is exploitable for many people. ' +
|
||||||
|
'Includes network daemon denial of service attacks, cross-site scripting, ' +
|
||||||
|
'and gaining user privileges.',
|
||||||
|
'banner_required': False
|
||||||
|
},
|
||||||
|
|
||||||
|
'High': {
|
||||||
|
'title': 'High',
|
||||||
|
'value': 'High',
|
||||||
|
'index': '2',
|
||||||
|
'level': 'warning',
|
||||||
|
|
||||||
|
'description': 'High is a real problem, exploitable for many people in a default installation. ' +
|
||||||
|
'Includes serious remote denial of services, local root privilege escalations, ' +
|
||||||
|
'or data loss.',
|
||||||
|
'banner_required': False
|
||||||
|
},
|
||||||
|
|
||||||
|
'Critical': {
|
||||||
|
'title': 'Critical',
|
||||||
|
'value': 'Critical',
|
||||||
|
'index': '1',
|
||||||
|
'level': 'error',
|
||||||
|
|
||||||
|
'description': 'Critical is a world-burning problem, exploitable for nearly all people in ' +
|
||||||
|
'a installation of the package. Includes remote root privilege escalations, ' +
|
||||||
|
'or massive data loss.',
|
||||||
|
'banner_required': True
|
||||||
|
},
|
||||||
|
|
||||||
|
'Defcon1': {
|
||||||
|
'title': 'Defcon 1',
|
||||||
|
'value': 'Defcon1',
|
||||||
|
'index': '0',
|
||||||
|
'level': 'error',
|
||||||
|
|
||||||
|
'description': 'Defcon1 is a Critical problem which has been manually highlighted ' +
|
||||||
|
'by the Quay team. It requires immediate attention.',
|
||||||
|
'banner_required': True
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def get_priority_for_index(index):
|
||||||
|
for priority in PRIORITY_LEVELS:
|
||||||
|
if PRIORITY_LEVELS[priority]['index'] == index:
|
||||||
|
return priority
|
||||||
|
|
||||||
|
return 'Unknown'
|
||||||
|
|
||||||
|
|
||||||
class SecurityScannerAPI(object):
|
class SecurityScannerAPI(object):
|
||||||
""" Helper class for talking to the Security Scan service (Clair). """
|
""" Helper class for talking to the Security Scan service (Clair). """
|
||||||
def __init__(self, app, config_provider):
|
def __init__(self, app, config_provider):
|
||||||
|
@ -76,7 +167,7 @@ class SecurityScannerAPI(object):
|
||||||
timeout = security_config.get('API_TIMEOUT_SECONDS', 1)
|
timeout = security_config.get('API_TIMEOUT_SECONDS', 1)
|
||||||
logger.debug('Looking up sec information: %s', url)
|
logger.debug('Looking up sec information: %s', url)
|
||||||
|
|
||||||
with CloseForLongOperation(app.config):
|
with CloseForLongOperation(self.app.config):
|
||||||
if body is not None:
|
if body is not None:
|
||||||
return client.post(url, json=body, params=kwargs, timeout=timeout, cert=self.keys,
|
return client.post(url, json=body, params=kwargs, timeout=timeout, cert=self.keys,
|
||||||
verify=self.certificate)
|
verify=self.certificate)
|
||||||
|
|
|
@ -34,6 +34,7 @@ class NotificationWorker(QueueWorker):
|
||||||
logger.exception('Cannot find notification event: %s', ex.message)
|
logger.exception('Cannot find notification event: %s', ex.message)
|
||||||
raise JobException('Cannot find notification event: %s' % ex.message)
|
raise JobException('Cannot find notification event: %s' % ex.message)
|
||||||
|
|
||||||
|
if event_handler.should_perform(job_details['event_data'], notification):
|
||||||
method_handler.perform(notification, event_handler, job_details)
|
method_handler.perform(notification, event_handler, job_details)
|
||||||
|
|
||||||
|
|
||||||
|
|
Reference in a new issue