Skip to content

JSON API #8 - #26

Merged
tdruez merged 31 commits into
developfrom
json_api
Sep 22, 2017
Merged

JSON API #8#26
tdruez merged 31 commits into
developfrom
json_api

Conversation

@kartiksibal

Copy link
Copy Markdown
Contributor

Signed-off-by: Kartik sibal kartiksibal@gmail.com

* updated views
* updated urls.py

Signed-off-by: Kartik sibal <kartiksibal@gmail.com>
Signed-off-by: Kartik sibal <kartiksibal@gmail.com>
Signed-off-by: kartik sibal <kartiksibal@gmail.com>
Comment thread app/vulncode_app/serializers.py Outdated
class VulnerabilitySerializer(serializers.ModelSerializer):
class Meta:
model = Vulnerability
exclude = ('id', 'cvss')

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.

Avoid using exclude, use fields instead, see https://docs.djangoproject.com/en/1.11/topics/forms/modelforms/#selecting-the-fields-to-use

It is strongly recommended that you explicitly set all fields that should be edited in the form using the fields attribute. Failure to do so can easily lead to security problems when a form unexpectedly allows a user to set certain fields, especially when new fields are added to a model.

Comment thread app/vulncode_app/serializers.py Outdated
class VulnerabilityReferenceSerializer(serializers.ModelSerializer):
class Meta:
model = VulnerabilityReference
exclude = ('id', 'source', 'url', 'vulnerability')

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.

Similar comment, use fields.

* use natural impactpackage link
* add impact package link in data_dump

Signed-off-by: Kartik sibal <kartiksibal@gmail.com>
Signed-off-by: Kartik sibal <kartiksibal@gmail.com>

@pombredanne pombredanne left a comment

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.

Looking good! Only a few comments to address and of course some tests

Comment thread app/vulncode_app/data_dump.py Outdated

from vulncode_app.models import Vulnerability
from vulncode_app.models import VulnerabilityReference
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

Comment thread app/vulncode_app/serializers.py Outdated

from rest_framework import serializers

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.

Import should be sorted

Comment thread app/vulncode_app/urls.py
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

Comment thread app/vulncode_app/urls.py
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.

Comment thread app/vulncode_app/views.py Outdated

pk = Package.objects.filter(name=package_name)

for i, v in enumerate(pk):

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.

This is the wrong approach and should be handled by the proper serializers.

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.

@kartiksibal rather than for i, v in enumerate(pk): just iterate on the packages:

packages = Package.objects.filter(name=package_name)
for package in packages:
  ....

* use dict instead of sets in data output

Signed-off-by: Kartik sibal <kartiksibal@gmail.com>
Comment thread app/vulncode_app/views.py Outdated

pk = Package.objects.filter(name=package_name)

for i, v in enumerate(pk):

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.

you are still enumerating pk. Instead loop on packages:
for package in Package.objects.filter(name=package_name): ....

Signed-off-by: Kartik sibal <kartiksibal@gmail.com>
Signed-off-by: kartik sibal <kartiksibal@gmail.com>
Signed-off-by: Kartik sibal <kartiksibal@gmail.com>
Comment thread app/vulncode_app/models.py Outdated
"""
vulnerability = models.ForeignKey('Vulnerability')
package = models.ForeignKey('Package')
package_fk = models.ForeignKey('Package')

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.

You should not rename this. This is a package object, not only a package_fk..

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.

Also since you updated the models, you need to run makemigrations to generate the new migrations alright.

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 It was necessary to rename this since the reverse query name for Package.impacted_package clashes with ImpactedPackage.package

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.

What do you mean by clash? can you be more specific? at the db level? in code? where? provide an example with some stack/error trace.
In any case, package_fk is not a good name.
If a name change is really need to avoid some collision, then this would be the ManyToMany field name in Package that would need to be changed instead.

Or maybe what you are really returning in you API as a primary model is not a Package... but an ImpactedPackage instead which would be actually more natural, what do you think?

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.

Error Trace:
screen shot 2017-08-22 at 8 25 41 pm

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.

And I'll take another look into it, before lodging a ticket.

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.

You also likely need a unique together on these two fields to avoid dupe entries

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

Comment thread app/vulncode_app/serializers.py Outdated
class VulnerabilityReferenceSerializer(serializers.ModelSerializer):
class Meta:
model = VulnerabilityReference
fields = ('reference_id',)

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.

You want to add the other reference fields too there.

Comment thread app/vulncode_app/serializers.py Outdated


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

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.

This should be vulnerabilities, plural IMHO

* sort imports

Signed-off-by: Kartik sibal <kartiksibal@gmail.com>
Comment thread app/vulncode_app/data_dump.py Outdated

from vulncode_app.models import Vulnerability
from vulncode_app.models import VulnerabilityReference
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.

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

@pombredanne pombredanne left a comment

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 have added some comments.
Please check all import sort order...
Also the name collision that you experience is because the lack of plural.

Comment thread app/vulncode_app/data_dump.py Outdated
)
impacted_package = ImpactedPackage.objects.create(
vulnerability=vulnerability,
package_fk=package

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.

Do not call this package_fk in the model, but package.

Comment thread app/vulncode_app/data_dump.py Outdated
vulnerability=vulnerability,
package_fk=package
)
package.impacted_package.add(

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 add this? You created it alright in line 46?

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

Comment thread app/vulncode_app/data_dump.py Outdated
)
ImpactedPackage.objects.create(
vulnerability=vulnerability,
package_fk=package

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.

Same as above: use package, not package_fk as an attribute name in the model

Comment thread app/vulncode_app/models.py Outdated
@@ -50,13 +50,16 @@ class VulnerabilityReference(models.Model):
class Meta:
unique_together = ('vulnerability', 'source', 'reference_id')

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.

Would not the URL also be part of the unique together? just a question, not sure. We can quite likely have multiple URLs for a source that refer to the same reference_id.

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.

I think more than one URL can point at a particular reference_id

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.

ok, then you need to update the unique together then?

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.

And you may want to check other models that may need updated unique together too

Comment thread app/vulncode_app/models.py Outdated
"""
vulnerability = models.ForeignKey('Vulnerability')
package = models.ForeignKey('Package')
package_fk = models.ForeignKey('Package')

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.

What do you mean by clash? can you be more specific? at the db level? in code? where? provide an example with some stack/error trace.
In any case, package_fk is not a good name.
If a name change is really need to avoid some collision, then this would be the ManyToMany field name in Package that would need to be changed instead.

Or maybe what you are really returning in you API as a primary model is not a Package... but an ImpactedPackage instead which would be actually more natural, what do you think?

Comment thread app/vulncode_app/views.py Outdated
from rest_framework.response import Response
from rest_framework import status

from vulncode_app.serializers import PackageSerializer

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

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

Comment thread app/vulncode_app/views.py Outdated
def get(self, request, package_name):
pk = Package.objects.filter(name=package_name)
response = PackageSerializer(pk, many=True).data

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 not needed here

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

Comment thread app/vulncode_app/views.py
response = PackageSerializer(pk, many=True).data

return Response(response)

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.

Only one line between class methods

@kartiksibal kartiksibal Aug 24, 2017

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.

Not a class method.

Comment thread app/vulncode_app/serializers.py Outdated
from vulncode_app.models import Package
from vulncode_app.models import PackageReference
from vulncode_app.models import VulnerabilityReference
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

impacted_package = models.ManyToManyField('ImpactedPackage')
platform = models.CharField(max_length=50, help_text='Package platform eg:maven', blank=True)
name = models.CharField(max_length=50, help_text='Package name', blank=True)
version = models.CharField(max_length=50, help_text='Package version', blank=True)

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.

in the line below

def __str__(self):
    return self.name

we likely need more than just name ... , but this is minor

Comment thread app/vulncode_app/test_api.py Outdated

from django.test import TestCase
from rest_framework.response import Response
from collections import OrderedDict

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.

e.g. this is stdlib and should not be in this block

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

@pombredanne

Copy link
Copy Markdown
Member

Also you likely need to run makemigrations and commit the migrations for the model updates

Signed-off-by: kartik sibal <kartiksibal@gmail.com>
* remove M2M on package
* rename package_fk to package

Signed-off-by: Kartik sibal <kartiksibal@gmail.com>
Signed-off-by: Kartik sibal <kartiksibal@gmail.com>
Comment thread app/vulncode_app/models.py Outdated
@@ -50,13 +50,16 @@ class VulnerabilityReference(models.Model):
class Meta:
unique_together = ('vulnerability', 'source', 'reference_id')

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.

ok, then you need to update the unique together then?

Comment thread app/vulncode_app/models.py Outdated
@@ -50,13 +50,16 @@ class VulnerabilityReference(models.Model):
class Meta:
unique_together = ('vulnerability', 'source', 'reference_id')

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.

And you may want to check other models that may need updated unique together too

* test blank response

Signed-off-by: Kartik sibal <kartiksibal@gmail.com>
* add url in vulnerability reference unique together

Signed-off-by: Kartik sibal <kartiksibal@gmail.com>

@pombredanne pombredanne left a comment

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.

So I guess you removed the manytomany. Can you elaborate on this?

Also Would not the root of your seralizers be the impacted package in earnest? (that's not a big deal as the serialization would end up the same)

Finally I think you are missing the all important Resolved packages in your output

If you do not mind, to not force push future commits... it will be easier for review!
Thanks

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

Comment thread app/vulncode_app/serializers.py Outdated
class PackageReferenceSerializer(serializers.ModelSerializer):
class Meta:
model = PackageReference
fields = ('name', 'version', 'repository', 'platform', )

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.

Can you keep the field order from the model?

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

Comment thread app/vulncode_app/serializers.py Outdated
class VulnerabilityReferenceSerializer(serializers.ModelSerializer):
class Meta:
model = VulnerabilityReference
fields = ('reference_id', 'source', 'url')

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.

Here and elsewhere, please keep the model fields order

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

Comment thread app/vulncode_app/test_api.py Outdated
# Visit https://github.com/nexB/vulnerablecode/ for support and download.

import json

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.

no empty lines between a block of imports from the same kind (here stdlib)

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

Comment thread app/vulncode_app/test_api.py Outdated
'summary',
'Multiple stack-based buffer overflows in mimetex.cgi in mimeTeX'
),
('reference',

@pombredanne pombredanne Aug 25, 2017

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 not this be plural "references"?

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.

atm, every reference contains a single reference id. So, I think not.

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.

My point is that there are multiple references, hence the list should be plural

Signed-off-by: Thomas Druez <tdruez@nexb.com>
@tdruez

tdruez commented Sep 7, 2017

Copy link
Copy Markdown
Contributor

@kartiksibal The API code is in much better shape now, thanks to using proper Serializers ;)

I've made some cleanup in 8158a84

Some refinements are still needed from you before the merge:

  1. Add some documentation on how to use the API in the README.md. You can create a new section at the end of the file.
  2. All the test_* files should be located in a tests directory
  3. data is a terrible name for the API URL, please use a proper name. Since this API endpoint returns Packages, I would suggest /api/packages/

Avoid using data for naming things in general.

@pombredanne could you review the shape of the returned package data structure?

Signed-off-by: kartik sibal <kartiksibal@gmail.com>
Signed-off-by: kartik sibal <kartiksibal@gmail.com>
Signed-off-by: kartik sibal <kartiksibal@gmail.com>
Signed-off-by: kartik sibal <kartiksibal@gmail.com>
Signed-off-by: kartik sibal <kartiksibal@gmail.com>
Signed-off-by: Kartik sibal <kartiksibal@gmail.com>

@pombredanne pombredanne left a comment

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.

Thanks! I added a few comments on the overall structure of the returned 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

response = self.client.get('/vulncode_app/api/mimetex', format='json')

expected = [{
"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

Comment thread app/vulncode_app/tests/test_api.py Outdated
"vulnerabilities": [{
"vulnerability": {
"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

Comment thread app/vulncode_app/tests/test_api.py Outdated
"name": "mimetex",
"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?

- Following Django best-practices
- Simplify the layout
- Use proper naming convention

Signed-off-by: Thomas Druez <tdruez@nexb.com>
Signed-off-by: Thomas Druez <tdruez@nexb.com>
Signed-off-by: Thomas Druez <tdruez@nexb.com>
Comment thread vulnerabilities/urls.py Outdated
url(r'^cve-search/(?P<name>[a-z]+)',
views.package,
name='package'),
url(r'^api/(?P<package_name>[a-z]+)',

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.

This pattern [a-z]+ is not good enough to catch real package names, for example: ruby1.9.1 and gcc-4.6. Use (?P<package_name>.+) instead.

kartiksibal and others added 4 commits September 22, 2017 22:54
Signed-off-by: Kartik sibal <kartiksibal@gmail.com>
Signed-off-by: kartik sibal <kartiksibal@gmail.com>
Signed-off-by: kartik sibal <kartiksibal@gmail.com>
Set the new 2m field on the PackageSerializer

Signed-off-by: Thomas Druez <tdruez@nexb.com>
@tdruez
tdruez merged commit 7048c43 into develop Sep 22, 2017
@tdruez
tdruez deleted the json_api branch September 22, 2017 20:31
pombredanne added a commit that referenced this pull request Apr 2, 2025
Create junction from Scripts to bin
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants