Add a new API endpoint for ScannerResult(s) (#13335)
This commit is contained in:
Родитель
2897d12735
Коммит
95d694b45f
|
@ -43,4 +43,5 @@ using the API.
|
|||
hero
|
||||
ratings
|
||||
reviewers
|
||||
scanners
|
||||
signing
|
||||
|
|
|
@ -366,6 +366,7 @@ v4 API changelog
|
|||
* 2019-10-17: moved /authenticate endpoint from api/v4/accounts/authenticate to version-less api/auth/authenticate-callback https://github.com/mozilla/addons-server/issues/10487
|
||||
* 2019-11-14: removed ``is_source_public`` property from addons API https://github.com/mozilla/addons-server/issues/12514
|
||||
* 2019-12-05: removed /addons/featured endpoint from v4+ and featured support from other addon api endpoints. https://github.com/mozilla/addons-server/issues/12937
|
||||
* 2020-01-23: added /scanner/results (internal API endpoint).
|
||||
|
||||
.. _`#11380`: https://github.com/mozilla/addons-server/issues/11380/
|
||||
.. _`#11379`: https://github.com/mozilla/addons-server/issues/11379/
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
============
|
||||
Scanners
|
||||
============
|
||||
|
||||
.. note::
|
||||
|
||||
These APIs are subject to change at any time and are for internal use only.
|
||||
|
||||
|
||||
---------------------
|
||||
Scanner Results
|
||||
---------------------
|
||||
|
||||
.. _scanner-results:
|
||||
|
||||
This endpoint returns a list of labelled scanner results.
|
||||
|
||||
.. http:get:: /api/v4/scanner/results/
|
||||
|
||||
:>json int id: The scanner result ID.
|
||||
:>json string scanner: The scanner name.
|
||||
:>json object results: The scanner (raw) results.
|
|
@ -29,6 +29,7 @@ v4_api_urls = [
|
|||
url(r'^', include('olympia.signing.urls')),
|
||||
url(r'^', include(amo_api_patterns)),
|
||||
url(r'^hero/', include('olympia.hero.urls')),
|
||||
url(r'^scanner/', include('olympia.scanners.api_urls')),
|
||||
]
|
||||
|
||||
urlpatterns = [
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
from django.conf.urls import url
|
||||
|
||||
from .views import ScannerResultViewSet
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^results/$', ScannerResultViewSet.as_view(), name='scanner-results'),
|
||||
]
|
|
@ -0,0 +1,21 @@
|
|||
# Generated by Django 2.2.9 on 2020-01-22 16:49
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
def create_waffle_switch(apps, schema_editor):
|
||||
Switch = apps.get_model('waffle', 'Switch')
|
||||
Switch.objects.create(
|
||||
name='enable-scanner-results-api',
|
||||
active=False,
|
||||
note='Enable the API endpoint that exposes the scanner results',
|
||||
)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('scanners', '0022_auto_20200122_1644'),
|
||||
]
|
||||
|
||||
operations = [migrations.RunPython(create_waffle_switch)]
|
|
@ -0,0 +1,15 @@
|
|||
from rest_framework import serializers
|
||||
|
||||
from .models import ScannerResult
|
||||
|
||||
|
||||
class ScannerResultSerializer(serializers.ModelSerializer):
|
||||
scanner = serializers.SerializerMethodField()
|
||||
results = serializers.JSONField()
|
||||
|
||||
class Meta:
|
||||
model = ScannerResult
|
||||
fields = ('id', 'scanner', 'results')
|
||||
|
||||
def get_scanner(self, obj):
|
||||
return obj.get_scanner_name()
|
|
@ -0,0 +1,15 @@
|
|||
from olympia.amo.tests import TestCase
|
||||
from olympia.constants.scanners import CUSTOMS
|
||||
from olympia.scanners.models import ScannerResult
|
||||
from olympia.scanners.serializers import ScannerResultSerializer
|
||||
|
||||
|
||||
class TestScannerResultSerializer(TestCase):
|
||||
def test_serialize(self):
|
||||
result = ScannerResult.objects.create(scanner=CUSTOMS)
|
||||
data = ScannerResultSerializer(instance=result).data
|
||||
assert data == {
|
||||
'id': result.id,
|
||||
'scanner': result.get_scanner_name(),
|
||||
'results': result.results,
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
from olympia.amo.tests import (
|
||||
APITestClient,
|
||||
TestCase,
|
||||
reverse_ns,
|
||||
user_factory,
|
||||
)
|
||||
from olympia.constants.scanners import YARA
|
||||
from olympia.scanners.models import ScannerResult
|
||||
from olympia.scanners.serializers import ScannerResultSerializer
|
||||
|
||||
|
||||
class TestScannerResultViewSet(TestCase):
|
||||
client_class = APITestClient
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
self.user = user_factory()
|
||||
self.grant_permission(self.user, 'Admin:ScannersResultsView')
|
||||
self.client.login_api(self.user)
|
||||
self.url = reverse_ns('scanner-results', api_version='v5')
|
||||
|
||||
def test_endpoint_requires_authentication(self):
|
||||
self.client.logout_api()
|
||||
response = self.client.get(self.url)
|
||||
assert response.status_code == 401
|
||||
|
||||
def test_endpoint_requires_permissions(self):
|
||||
self.user = user_factory()
|
||||
self.client.login_api(self.user)
|
||||
response = self.client.get(self.url)
|
||||
assert response.status_code == 403
|
||||
|
||||
def test_endpoint_can_be_disabled(self):
|
||||
self.create_switch('enable-scanner-results-api', active=False)
|
||||
response = self.client.get(self.url)
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_get(self):
|
||||
yara_result = ScannerResult.objects.create(scanner=YARA)
|
||||
self.create_switch('enable-scanner-results-api', active=True)
|
||||
|
||||
response = self.client.get(self.url)
|
||||
|
||||
assert response.status_code == 200
|
||||
json = response.json()
|
||||
assert 'results' in json
|
||||
results = json['results']
|
||||
assert len(results) == 1
|
||||
assert (results[0] ==
|
||||
ScannerResultSerializer(instance=yara_result).data)
|
|
@ -0,0 +1,32 @@
|
|||
import waffle
|
||||
|
||||
from django.db.transaction import non_atomic_requests
|
||||
from django.http import Http404
|
||||
from rest_framework.generics import ListAPIView
|
||||
|
||||
from olympia import amo
|
||||
from olympia.api.permissions import GroupPermission
|
||||
|
||||
from .models import ScannerResult
|
||||
from .serializers import ScannerResultSerializer
|
||||
|
||||
|
||||
class ScannerResultViewSet(ListAPIView):
|
||||
permission_classes = [
|
||||
GroupPermission(amo.permissions.ADMIN_SCANNERS_RESULTS_VIEW)
|
||||
]
|
||||
|
||||
queryset = ScannerResult.objects.all()
|
||||
serializer_class = ScannerResultSerializer
|
||||
|
||||
def get(self, request, format=None):
|
||||
if not waffle.switch_is_active('enable-scanner-results-api'):
|
||||
raise Http404
|
||||
return super().get(request, format)
|
||||
|
||||
@classmethod
|
||||
def as_view(cls, **initkwargs):
|
||||
"""The API is read-only so we can turn off atomic requests."""
|
||||
return non_atomic_requests(
|
||||
super(ScannerResultViewSet, cls).as_view(**initkwargs)
|
||||
)
|
Загрузка…
Ссылка в новой задаче