Skip to content
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
bfa5bc7
Add serializers based on models #8
kartiksibal Aug 14, 2017
89f2bb1
Add DRF to requirements.txt
kartiksibal Aug 14, 2017
c75ae67
Remove un-used imports #8
kartiksibal Aug 14, 2017
4d1c6c1
Merge branch 'json_api' of https://github.com/nexB/vulnerablecode int…
kartiksibal Aug 14, 2017
585327a
Change data output format #8
kartiksibal Aug 20, 2017
37d16b2
Change API data format to as discussed #8
kartiksibal Aug 21, 2017
96d6bfd
Add test cases and change data output format #8
kartiksibal Aug 22, 2017
0705c24
Updated serialization logic
kartiksibal Aug 23, 2017
f08d614
Add many to many field on Package #8
kartiksibal Aug 23, 2017
692d72d
Remove un-used imports #8
kartiksibal Aug 23, 2017
fcadb17
Add test cases #8
kartiksibal Aug 24, 2017
d41215d
New migrations #8
kartiksibal Aug 24, 2017
9015a68
Update models #8
kartiksibal Aug 24, 2017
bdcb807
Minor formatting changes #8
kartiksibal Aug 24, 2017
42c7be2
Add test cases #8
kartiksibal Aug 25, 2017
d1821c4
Update unique together #8
kartiksibal Aug 25, 2017
8158a84
Add missing migration file along some code cleanup #8
tdruez Sep 7, 2017
0317f8a
Move tests to vulncode_app/tests #8
kartiksibal Sep 12, 2017
d533162
Re-order serializers according to models #8
kartiksibal Sep 12, 2017
5469f99
change API url to api/ from data/ #8
kartiksibal Sep 12, 2017
0bf6354
Update travis according to new dir structure
kartiksibal Sep 12, 2017
9b277d6
Update tests according to changed api url #8
kartiksibal Sep 12, 2017
5d5f089
Merge branch 'json_api' of https://github.com/nexB/vulnerablecode int…
kartiksibal Sep 12, 2017
16ea31a
Update readme for API instructions #8
kartiksibal Sep 12, 2017
86c359a
Refactor the codebase structure
tdruez Sep 20, 2017
b016877
Fix failing tests following codebase structure changes
tdruez Sep 21, 2017
23fc544
Add back Gitter webhooks removed by mistake
tdruez Sep 21, 2017
a860bef
Update URL regex #8
kartiksibal Sep 22, 2017
c42a775
Included platform in package serializer #8
kartiksibal Sep 22, 2017
2d6d5eb
Update tests according to changes #8
kartiksibal Sep 22, 2017
2c5f78d
Add a `vulnerabilities` m2m field on the Package model
tdruez Sep 22, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ before_script:

script:
- python3.6 -m pytest -v tests/
- python3.6 manage.py test
- python3.6 manage.py test vulncode_app/tests

notifications:
email: false
Expand Down
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ python3.6 -m pytest -v tests/
For Django based tests
```
cd app/
./manage.py test
./manage.py test vulncode_app/tests
```

Scrape and save to the database
Expand All @@ -54,3 +54,17 @@ ubuntu_cves = ubuntu.scrape_cves()
debian_dump(debian_vulnerabilities)
ubuntu_dump(ubuntu_cves)
```

API
----
Start the server

```
cd app/
./manage.py runserver
```

In your browser use
```
localhost:8000/vulncode_app/api/<package name>
```
15 changes: 12 additions & 3 deletions app/vulncode_app/data_dump.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@
# VulnerableCode is a free software code scanning tool from nexB Inc. and others.
# Visit https://github.com/nexB/vulnerablecode/ for support and download.

from vulncode_app.models import ImpactedPackage

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Imports should be sorted

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorts import

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

from vulncode_app.models import Package
from vulncode_app.models import Vulnerability
from vulncode_app.models import VulnerabilityReference
from vulncode_app.models import Package


def debian_dump(extract_data):
Expand All @@ -38,10 +39,14 @@ def debian_dump(extract_data):
vulnerability=vulnerability,
reference_id=data.get('vulnerability_id', ''),
)
Package.objects.create(
package = Package.objects.create(
name=data.get('package_name', ''),
version=data.get('fixed_version', ''),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on our chat, does it ever make sense to create package without name and version or both empty values?
Also what about the platform field? Same for Ubuntu

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refer: #29

)
ImpactedPackage.objects.create(
vulnerability=vulnerability,
package=package
)


def ubuntu_dump(html):
Expand All @@ -56,6 +61,10 @@ def ubuntu_dump(html):
vulnerability=vulnerability,
reference_id=data.get('cve_id'),
)
Package.objects.create(
package = Package.objects.create(
name=data.get('package_name'),
)
ImpactedPackage.objects.create(
vulnerability=vulnerability,
package=package
)
8 changes: 6 additions & 2 deletions app/vulncode_app/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.4 on 2017-08-08 09:11
# Generated by Django 1.11.2 on 2017-08-24 08:31
from __future__ import unicode_literals

from django.db import migrations, models
Expand Down Expand Up @@ -59,7 +59,7 @@ class Migration(migrations.Migration):
name='VulnerabilityReference',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('source', models.CharField(blank=True, help_text="Source's name eg:NVD", max_length=50)),
('source', models.CharField(blank=True, help_text='Source(s) name eg:NVD', max_length=50)),
('reference_id', models.CharField(blank=True, help_text='Reference ID, eg:CVE-ID', max_length=50)),
('url', models.URLField(blank=True, help_text='URL of Vulnerability data', max_length=1024)),
('vulnerability', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='vulncode_app.Vulnerability')),
Expand All @@ -84,4 +84,8 @@ class Migration(migrations.Migration):
name='vulnerabilityreference',
unique_together=set([('vulnerability', 'source', 'reference_id')]),
),
migrations.AlterUniqueTogether(
name='impactedpackage',
unique_together=set([('vulnerability', 'package')]),
),
]
19 changes: 19 additions & 0 deletions app/vulncode_app/migrations/0002_auto_20170907_2111.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.4 on 2017-09-07 21:11
from __future__ import unicode_literals

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('vulncode_app', '0001_initial'),
]

operations = [
migrations.AlterUniqueTogether(
name='vulnerabilityreference',
unique_together=set([('vulnerability', 'source', 'reference_id', 'url')]),
),
]
8 changes: 7 additions & 1 deletion app/vulncode_app/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,10 @@ class VulnerabilityReference(models.Model):
url = models.URLField(max_length=1024, help_text='URL of Vulnerability data', blank=True)

class Meta:
unique_together = ('vulnerability', 'source', 'reference_id')
unique_together = ('vulnerability', 'source', 'reference_id', 'url')

def __str__(self):
return self.source


class ImpactedPackage(models.Model):
Expand All @@ -58,6 +61,9 @@ class ImpactedPackage(models.Model):
vulnerability = models.ForeignKey('Vulnerability')
package = models.ForeignKey('Package')

class Meta:
unique_together = ('vulnerability', 'package')


class ResolvedPackage(models.Model):
"""
Expand Down
66 changes: 66 additions & 0 deletions app/vulncode_app/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#
# Copyright (c) 2017 nexB Inc. and others. All rights reserved.
# http://nexb.com and https://github.com/nexB/vulnerablecode/
# The VulnerableCode software is licensed under the Apache License version 2.0.
# Data generated with VulnerableCode require an acknowledgment.
#
# You may not use this software except in compliance with the License.
# You may obtain a copy of the License at: http://apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software distributed
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
# specific language governing permissions and limitations under the License.
#
# When you publish or redistribute any data created with VulnerableCode or any VulnerableCode
# derivative work, you must accompany this data with the following acknowledgment:
#
# Generated with VulnerableCode and provided on an "AS IS" BASIS, WITHOUT WARRANTIES
# OR CONDITIONS OF ANY KIND, either express or implied. No content created from
# VulnerableCode should be considered or used as legal advice. Consult an Attorney
# for any legal advice.
# VulnerableCode is a free software code scanning tool from nexB Inc. and others.
# Visit https://github.com/nexB/vulnerablecode/ for support and download.

from rest_framework import serializers

from vulncode_app.models import ImpactedPackage
from vulncode_app.models import Package
from vulncode_app.models import PackageReference
from vulncode_app.models import Vulnerability

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sort your imports, this comes before VulnerabilityReference

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

from vulncode_app.models import VulnerabilityReference


class PackageReferenceSerializer(serializers.ModelSerializer):
class Meta:
model = PackageReference
fields = ('repository', 'platform', 'name', 'version')


class VulnerabilityReferenceSerializer(serializers.ModelSerializer):
class Meta:
model = VulnerabilityReference
fields = ('source', 'reference_id', 'url')


class VulnerabilitySerializer(serializers.ModelSerializer):
reference = VulnerabilityReferenceSerializer(source='vulnerabilityreference_set', many=True)

class Meta:
model = Vulnerability
fields = ('summary', 'reference')


class ImpactedPackageSerializer(serializers.ModelSerializer):
vulnerability = VulnerabilitySerializer()

class Meta:
model = ImpactedPackage
fields = ('vulnerability',)


class PackageSerializer(serializers.ModelSerializer):
vulnerabilities = ImpactedPackageSerializer(source='impactedpackage_set', many=True)

class Meta:
model = Package
fields = ('name', 'version', 'vulnerabilities')
158 changes: 158 additions & 0 deletions app/vulncode_app/tests/test_api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
#
# Copyright (c) 2017 nexB Inc. and others. All rights reserved.
# http://nexb.com and https://github.com/nexB/vulnerablecode/
# The VulnerableCode software is licensed under the Apache License version 2.0.
# Data generated with VulnerableCode require an acknowledgment.
#
# You may not use this software except in compliance with the License.
# You may obtain a copy of the License at: http://apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software distributed
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
# specific language governing permissions and limitations under the License.
#
# When you publish or redistribute any data created with VulnerableCode or any VulnerableCode
# derivative work, you must accompany this data with the following acknowledgment:
#
# Generated with VulnerableCode and provided on an "AS IS" BASIS, WITHOUT WARRANTIES
# OR CONDITIONS OF ANY KIND, either express or implied. No content created from
# VulnerableCode should be considered or used as legal advice. Consult an Attorney
# for any legal advice.
# VulnerableCode is a free software code scanning tool from nexB Inc. and others.
# Visit https://github.com/nexB/vulnerablecode/ for support and download.

import json

from django.test import TestCase

from vulncode_app.models import Package
from vulncode_app.serializers import PackageSerializer
from vulncode_app.data_dump import debian_dump
from vulncode_app.data_dump import ubuntu_dump
from scraper import debian
from scraper import ubuntu


class TestResponse(TestCase):
def test_debian_response(self):
with open('tests/test_data/debian.json') as f:
test_data = json.loads(f.read())

extract_data = debian.extract_vulnerabilities(test_data)
debian_dump(extract_data)
response = self.client.get('/vulncode_app/api/mimetex', format='json')

expected = [{

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would expect the returned payload to have some "header" data (e.g. some tool version, what was the query made, number of results returned, ... And to have the list of packages returned under the packages: element

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Create as #30

"name": "mimetex",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May be we are missing other Package fields at the same level as this such as the "platform" ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

"version": "1.50-1.1",
"vulnerabilities": [{
"vulnerability": {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO we do not need vulnerabilities/vulnerability
Only vulnerabilities as a list of mappings, each being a vulnerability since we only list these there. No need for an extra level of nesting and a "vulnerability" nested mapping?

"summary": "Multiple stack-based buffer overflows in mimetex.cgi in mimeTeX",
"reference": [{

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be references (plural) and not reference, since this is also a list of mappings?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

"reference_id": "CVE-2009-2458",
"source": "",
"url": ""
}]
}
}]
}, {
"name": "mimetex",
"version": "1.50-1.1",
"vulnerabilities": [{
"vulnerability": {
"summary": "Multiple unspecified vulnerabilities in mimeTeX.",
"reference": [{
"reference_id": "CVE-2009-2459",
"source": "",
"url": ""
}]
}
}]
}]

self.assertEqual(expected, response.data)

def test_ubuntu_response(self):
with open('tests/test_data/ubuntu_main.html') as f:
test_data = f.read()

extract_data = ubuntu.extract_cves(test_data)
ubuntu_dump(extract_data)
response = self.client.get('/vulncode_app/api/automake', format='json')

expected = [{
"name": "automake",
"version": "",
"vulnerabilities": [{
"vulnerability": {
"summary": "",
"reference": [{
"reference_id": "CVE-2012-3386",
"source": "",
"url": ""
}]
}
}]
}]

self.assertEqual(expected, response.data)

def test_blank_response(self):
response_invalid = self.client.get('/vulncode_app/api/', format='json')
response_blank = self.client.get('/vulncode_app/api/abbpcc', format='json')

self.assertEqual(404, response_invalid.status_code)
self.assertEqual([], response_blank.data)


class TestSerializers(TestCase):
def test_serializers(self):
with open('tests/test_data/debian.json') as f:
test_data = json.loads(f.read())
extract_data = debian.extract_vulnerabilities(test_data)
debian_dump(extract_data)

pk = Package.objects.filter(name="mimetex")
response = PackageSerializer(pk, many=True).data

expected = [
{
"name": "mimetex",
"version": "1.50-1.1",
"vulnerabilities": [
{
"vulnerability": {
"summary": "Multiple stack-based buffer overflows in mimetex.cgi in "
"mimeTeX",
"reference": [
{
"reference_id": "CVE-2009-2458",
"source": "",
"url": ""
}
]
}
}
]
},
{
"name": "mimetex",
"version": "1.50-1.1",
"vulnerabilities": [
{
"vulnerability": {
"summary": "Multiple unspecified vulnerabilities in mimeTeX.",
"reference": [
{
"reference_id": "CVE-2009-2459",
"source": "",
"url": ""
}
]
}
}
]
}
]

self.assertEqual(expected, response)
File renamed without changes.
16 changes: 13 additions & 3 deletions app/vulncode_app/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,20 @@

from django.conf.urls import url

from . import views
from rest_framework.urlpatterns import format_suffix_patterns

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty line needed after this


from vulncode_app import views


urlpatterns = [
url(r'(?P<name>[a-z]+)/(?P<version>[0-9]+)', views.package_version, name='package_version'),
url(r'^(?P<name>[a-z]+)', views.package, name='package'),
url(r'^cve-search/(?P<name>[a-z]+)/(?P<version>[0-9]+)',

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you call this cve-search?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pombredanne because it is getting its's data from CVE-SEARCH API, that we worked out in the beginning.

views.package_version,
name='package_version'),
url(r'^cve-search/(?P<name>[a-z]+)',
views.package,
name='package'),
url(r'^api/(?P<package_name>[a-z]+)',
views.VulnerabilityData.as_view()),
]

urlpatterns = format_suffix_patterns(urlpatterns)
Loading