Skip to content

Commit 26d5f6a

Browse files
authored
Merge pull request #15 from nexB/models_db
Database Model #5
2 parents 12f9022 + f0e46ce commit 26d5f6a

11 files changed

Lines changed: 340 additions & 168 deletions

File tree

.travis.yml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
language: python
22
python: 3.6
33

4-
install: pip install pycodestyle
4+
install:
5+
- pip install -r requirements.txt
6+
- pip install pycodestyle
57

68
before_script:
7-
- pycodestyle --exclude=migrations,settings.py --max-line-length=100 .
9+
- pycodestyle --exclude=migrations,settings.py,lib,tests --max-line-length=100 .
10+
11+
script:
12+
- python3.6 -m pytest -v tests/
813

914
notifications:
15+
email: false
1016
webhooks:
1117
urls:
1218
- https://webhooks.gitter.im/e/b119fa557626081e1f36

README.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,16 @@ Tests
2424
-----
2525

2626
```
27-
python3.6 -m pytest -v
27+
pycodestyle --exclude=migrations,settings.py,lib --max-line-length=100 .
28+
python3.6 -m pytest -v tests/
29+
```
30+
31+
Scrape
32+
------
33+
34+
```
35+
from scraper import debian, ubuntu
36+
37+
debian.scrape_cves()
38+
ubuntu.scrape_cves()
2839
```

api_data.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,4 @@ def extract_fields(data, fields_names):
5252
cve-search' api. Takes as input data, fields requested
5353
"""
5454
return [{name: item.get(name) for name in fields_names}
55-
for item in data]
55+
for item in data]

app/app/urls.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
1. Import the include() function: from django.conf.urls import url, include
1414
2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
1515
"""
16-
from django.conf.urls import url,include
16+
from django.conf.urls import url, include
1717
from django.contrib import admin
1818

1919
urlpatterns = [

app/vulncode_app/models.py

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -26,38 +26,40 @@
2626

2727

2828
class Vulnerability(models.Model):
29-
vulnerability_id = models.AutoField(primary_key=True)
30-
summary = models.TextField(max_length=50)
31-
cvss = models.FloatField(max_length=50)
29+
summary = models.TextField(max_length=50, help_text="Summary of the vulnerability")
30+
cvss = models.FloatField(max_length=50, help_text="CVSS Score")
3231

3332

3433
class VulnerabilityReference(models.Model):
35-
vulnerability_id = models.ForeignKey('Vulnerability')
36-
source = models.CharField(max_length=50)
37-
reference_id = models.CharField(max_length=50)
38-
url = models.URLField(max_length=50)
34+
vulnerability = models.ForeignKey('Vulnerability')
35+
source = models.CharField(max_length=50, help_text="Source's name eg:NVD")
36+
reference_id = models.CharField(max_length=50, help_text="Reference ID, eg:CVE-ID")
37+
url = models.URLField(max_length=1024, help_text="URL of Vulnerability data")
3938

4039

4140
class ImpactedPackage(models.Model):
42-
vulnerability_id = models.ForeignKey('Vulnerability')
43-
package_id = models.ForeignKey('Package')
41+
vulnerability = models.ForeignKey('Vulnerability')
42+
package = models.ForeignKey('Package')
4443

4544

4645
class ResolvedPackage(models.Model):
47-
vulnerability_id = models.ForeignKey('Vulnerability')
48-
package_id = models.ForeignKey('Package')
46+
vulnerability = models.ForeignKey('Vulnerability')
47+
package = models.ForeignKey('Package')
4948

5049

5150
class Package(models.Model):
52-
package_id = models.AutoField(primary_key=True)
53-
platform = models.CharField(max_length=50)
54-
name = models.CharField(max_length=50)
55-
version = models.FloatField(max_length=50)
51+
platform = models.CharField(max_length=50, help_text="Package platform eg:maven")
52+
name = models.CharField(max_length=50, help_text="Package name")
53+
version = models.CharField(max_length=50, help_text="Pacakge version")
5654

5755

5856
class PackageReference(models.Model):
59-
package_id = models.ForeignKey('Package')
60-
repository = models.CharField(max_length=50)
61-
platform = models.CharField(max_length=50)
62-
name = models.CharField(max_length=50)
63-
version = models.FloatField(max_length=50)
57+
package = models.ForeignKey('Package')
58+
repository = models.CharField(max_length=50,
59+
help_text="Repository URL eg:http://central.maven.org")
60+
platform = models.CharField(max_length=50,
61+
help_text="Platform eg:maven")
62+
name = models.CharField(max_length=50,
63+
help_text="Package reference name eg:org.apache.commons.io")
64+
version = models.CharField(max_length=50,
65+
help_text="Reference version")

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
beautifulsoup4==4.6.0
2+
lxml==3.8.0
23

34
# Tests
45
pytest==3.1.3

scraper/debian.py

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
#
2+
# Copyright (c) 2017 nexB Inc. and others. All rights reserved.
3+
# http://nexb.com and https://github.com/nexB/vulnerablecode/
4+
# The VulnerableCode software is licensed under the Apache License version 2.0.
5+
# Data generated with VulnerableCode require an acknowledgment.
6+
#
7+
# You may not use this software except in compliance with the License.
8+
# You may obtain a copy of the License at: http://apache.org/licenses/LICENSE-2.0
9+
# Unless required by applicable law or agreed to in writing, software distributed
10+
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
11+
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
12+
# specific language governing permissions and limitations under the License.
13+
#
14+
# When you publish or redistribute any data created with VulnerableCode or any VulnerableCode
15+
# derivative work, you must accompany this data with the following acknowledgment:
16+
#
17+
# Generated with VulnerableCode and provided on an "AS IS" BASIS, WITHOUT WARRANTIES
18+
# OR CONDITIONS OF ANY KIND, either express or implied. No content created from
19+
# VulnerableCode should be considered or used as legal advice. Consult an Attorney
20+
# for any legal advice.
21+
# VulnerableCode is a free software code scanning tool from nexB Inc. and others.
22+
# Visit https://github.com/nexB/vulnerablecode/ for support and download.
23+
24+
import logging
25+
import re
26+
from urllib.request import urlopen
27+
28+
import bs4
29+
30+
31+
DEBIAN_ROOT_URL = 'https://security-tracker.debian.org'
32+
33+
34+
def extract_tracker_paths(html):
35+
"""
36+
Return a list of tracker URL paths extracted from the given `html` input.
37+
"""
38+
soup = bs4.BeautifulSoup(html, 'lxml')
39+
tracker_links = soup.findAll('a', href=re.compile('^/track+.*'))
40+
return [link.get('href') for link in tracker_links]
41+
42+
43+
def extract_cves_from_tracker(html):
44+
"""
45+
Return all CVEs extracted from the given `html` input.
46+
"""
47+
cve_id = []
48+
package_name = []
49+
vulnerability_status = []
50+
soup = bs4.BeautifulSoup(html, 'lxml')
51+
52+
for tag in soup.find_all('a'):
53+
href = tag.get('href')
54+
55+
if re.search('/tracker/CVE-(.+)', href):
56+
id = re.findall('(?<=/tracker/).*', href)
57+
cve_id.append(id[0])
58+
59+
if re.search('^/tracker/TEMP-+.*', href):
60+
id = re.findall('(?<=/tracker/).*', href)
61+
cve_id.append(id[0])
62+
63+
if re.search('/tracker/source-package/(.+)', href):
64+
pkg = re.findall('(?<=/tracker/source-package/).*', href)
65+
package_name.append(pkg[0])
66+
67+
# if package name is empty, use the previous package name
68+
if href == '/tracker/source-package/':
69+
package_name.append(pkg)
70+
71+
for tag in soup.find_all('td'):
72+
if 'medium' in tag or 'low' in tag or 'not yet assigned' in tag:
73+
vulnerability_status.append(tag.text)
74+
elif tag.find_all('span', {'class': 'red'}) and tag.text == 'high**' or tag.text == 'high':
75+
vulnerability_status.append(tag.text)
76+
77+
return cve_id, package_name, vulnerability_status
78+
79+
80+
def scrape_cves():
81+
"""
82+
Runs the full scraping process of Debian CVEs.
83+
"""
84+
tracker_root_html = urlopen(f'{DEBIAN_ROOT_URL}/tracker/').read()
85+
tracker_paths = extract_tracker_paths(tracker_root_html)
86+
87+
cves = []
88+
for tracker_path in tracker_paths:
89+
tracker_url = f'{DEBIAN_ROOT_URL}{tracker_path}/'
90+
logging.info(f'Visiting: {tracker_url}')
91+
html = urlopen(tracker_url).read()
92+
cves.append(extract_cves_from_tracker(html))
93+
94+
return cves

scraper/scraper_debian.py

Lines changed: 0 additions & 77 deletions
This file was deleted.
Lines changed: 37 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -21,37 +21,44 @@
2121
# VulnerableCode is a free software code scanning tool from nexB Inc. and others.
2222
# Visit https://github.com/nexB/vulnerablecode/ for support and download.
2323

24-
import bs4 as bs
2524
import re
2625
from urllib.request import urlopen
2726

27+
import bs4
2828

29-
def ubuntu_data():
30-
cve_id = []
31-
package_name = []
32-
vulnerability_status = []
33-
34-
url = urlopen("https://people.canonical.com/~ubuntu-security/cve/main.html")
35-
soup = bs.BeautifulSoup (url, "lxml")
36-
37-
"""
38-
Scrape vulnerability status.
39-
Ubuntu provides a general vulnerability
40-
status of a package across all it's releases.
41-
"""
42-
for tag in soup.find_all('tr'):
43-
if re.match('<\w+\s\w+="(\w+)">', str(tag)):
44-
status = re.findall('<\w+\s\w+="(\w+)">', str(tag))
45-
vulnerability_status.append(status[0])
46-
47-
for tag in soup.find_all('a'):
48-
href = tag.get ('href', None)
49-
50-
if re.findall ('^CVE.+', href):
51-
cve_id.append(href)
52-
53-
if re.match('\pkg+.*', href):
54-
pkg = re.findall ('pkg/(.+)\.html', href)
55-
package_name.append(pkg[0])
56-
57-
return cve_id, package_name, vulnerability_status
29+
30+
UBUNTU_ROOT_URL = 'https://people.canonical.com/~ubuntu-security/cve/main.html'
31+
32+
33+
def extract_cves(html):
34+
soup = bs4.BeautifulSoup(html, 'lxml')
35+
36+
cve_id = []
37+
package_name = []
38+
vulnerability_status = []
39+
40+
for tag in soup.find_all('tr'):
41+
if re.match('<\w+\s\w+="(\w+)">', str(tag)):
42+
status = re.findall('<\w+\s\w+="(\w+)">', str(tag))
43+
vulnerability_status.append(status[0])
44+
45+
for tag in soup.find_all('a'):
46+
href = tag.get('href', None)
47+
48+
if re.findall('^CVE.+', href):
49+
cve_id.append(href)
50+
51+
if re.match('pkg+.*', href):
52+
pkg = re.findall('pkg/(.+)\.html', href)
53+
package_name.append(pkg[0])
54+
55+
return cve_id, vulnerability_status, package_name
56+
57+
58+
def scrape_cves():
59+
"""
60+
Runs the full scraping process of Ubuntu CVEs.
61+
"""
62+
html = urlopen(UBUNTU_ROOT_URL).read()
63+
cves = extract_cves(html)
64+
return cves

0 commit comments

Comments
 (0)