Added capability to scan extracted egg and wheel metadata in the local Python

environment.


Former-commit-id: b0259d38134bf18b1eb72db9951dbe2d04ba8fb9
This commit is contained in:
Dale Visser
2015-03-30 15:59:54 -04:00
parent a5dee0cb27
commit e328ec990c
21 changed files with 648 additions and 279 deletions

View File

@@ -20,11 +20,12 @@ package org.owasp.dependencycheck.analyzer;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.Collections;
import java.util.Set;
import java.util.Arrays;
import java.util.HashSet;
import org.junit.Test;
import org.owasp.dependencycheck.BaseTest;
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
import org.owasp.dependencycheck.dependency.Dependency;
import org.owasp.dependencycheck.dependency.Evidence;
@@ -41,9 +42,28 @@ public class PythonDistributionAnalyzerTest extends BaseTest {
* is thrown when an exception occurs.
*/
@Test
public void testAnalyze() throws Exception {
public void testAnalyzeWheel() throws AnalysisException {
djangoAssertions(new Dependency(BaseTest.getResourceAsFile(this,
"Django-1.7.2-py2.py3-none-any.whl")));
}
/**
* Test of inspect method, of class JarAnalyzer.
*
* @throws Exception
* is thrown when an exception occurs.
*/
@Test
public void testAnalyzeSitePackage() throws AnalysisException {
final Dependency result = new Dependency(BaseTest.getResourceAsFile(
this, "Django-1.7.2-py2.py3-none-any.whl"));
this, "site-packages/Django-1.7.2.dist-info/METADATA"));
djangoAssertions(result);
assertEquals("Django-1.7.2.dist-info/METADATA",
result.getDisplayFileName());
}
private void djangoAssertions(final Dependency result)
throws AnalysisException {
new PythonDistributionAnalyzer().analyze(result, null);
assertTrue("Expected vendor evidence to contain \"djangoproject\".",
result.getVendorEvidence().toString().contains("djangoproject"));
@@ -54,9 +74,24 @@ public class PythonDistributionAnalyzerTest extends BaseTest {
break;
}
}
assertTrue(
"implementation-version of 1.7.2 not found in Django wheel.",
found);
assertTrue("Version 1.7.2 not found in Django dependency.", found);
}
@Test
public void testAnalyzeEggInfo() throws AnalysisException {
final Dependency result = new Dependency(BaseTest.getResourceAsFile(
this, "site-packages/eggutils-0.0.2-py2.7.egg-info/PKG-INFO"));
new PythonDistributionAnalyzer().analyze(result, null);
assertTrue("Expected vendor evidence to contain \"python\".", result
.getVendorEvidence().toString().contains("python"));
boolean found = false;
for (final Evidence e : result.getVersionEvidence()) {
if ("Version".equals(e.getName()) && "0.0.2".equals(e.getValue())) {
found = true;
break;
}
}
assertTrue("Version 0.0.2 not found in eggutils dependency.", found);
}
/**
@@ -64,8 +99,10 @@ public class PythonDistributionAnalyzerTest extends BaseTest {
*/
@Test
public void testGetSupportedExtensions() {
assertEquals("Supported extensions should just be \"whl\".",
(Set<String>) Collections.singleton("whl"),
assertEquals(
"Supported extensions should just be \"whl\", \"METADATA\" and \"PKG-INFO\".",
new HashSet<String>(Arrays
.asList("whl", "METADATA", "PKG-INFO")),
new PythonDistributionAnalyzer().getSupportedExtensions());
}
@@ -83,7 +120,12 @@ public class PythonDistributionAnalyzerTest extends BaseTest {
*/
@Test
public void testSupportsExtension() {
final PythonDistributionAnalyzer analyzer = new PythonDistributionAnalyzer();
assertTrue("Should support \"whl\" extension.",
new PythonDistributionAnalyzer().supportsExtension("whl"));
analyzer.supportsExtension("whl"));
assertTrue("Should support \"METADATA\" extension.",
analyzer.supportsExtension("METADATA"));
assertTrue("Should support \"METADATA\" extension.",
analyzer.supportsExtension("PKG-INFO"));
}
}

View File

@@ -0,0 +1,5 @@
#!python
from django.core import management
if __name__ == "__main__":
management.execute_from_command_line()

View File

@@ -0,0 +1,27 @@
Copyright (c) Django Software Foundation and individual contributors.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of Django nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -0,0 +1,31 @@
Metadata-Version: 2.0
Name: Django
Version: 1.7.2
Summary: A high-level Python Web framework that encourages rapid development and clean, pragmatic design.
Home-page: http://www.djangoproject.com/
Author: Django Software Foundation
Author-email: foundation@djangoproject.com
License: BSD
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Web Environment
Classifier: Framework :: Django
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.2
Classifier: Programming Language :: Python :: 3.3
Classifier: Programming Language :: Python :: 3.4
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
Classifier: Topic :: Internet :: WWW/HTTP :: WSGI
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
Classifier: Topic :: Software Development :: Libraries :: Python Modules
UNKNOWN

View File

@@ -0,0 +1,6 @@
Wheel-Version: 1.0
Generator: bdist_wheel (0.24.0)
Root-Is-Purelib: true
Tag: py2-none-any
Tag: py3-none-any

View File

@@ -0,0 +1,3 @@
[console_scripts]
django-admin = django.core.management:execute_from_command_line

View File

@@ -0,0 +1 @@
{"license": "BSD", "name": "Django", "metadata_version": "2.0", "generator": "bdist_wheel (0.24.0)", "summary": "A high-level Python Web framework that encourages rapid development and clean, pragmatic design.", "version": "1.7.2", "extensions": {"python.details": {"project_urls": {"Home": "http://www.djangoproject.com/"}, "document_names": {"description": "DESCRIPTION.rst", "license": "LICENSE.txt"}, "contacts": [{"role": "author", "email": "foundation@djangoproject.com", "name": "Django Software Foundation"}]}, "python.commands": {"wrap_console": {"django-admin": "django.core.management:execute_from_command_line"}}, "python.exports": {"console_scripts": {"django-admin": "django.core.management:execute_from_command_line"}}}, "classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Framework :: Django", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.2", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Internet :: WWW/HTTP :: WSGI", "Topic :: Software Development :: Libraries :: Application Frameworks", "Topic :: Software Development :: Libraries :: Python Modules"]}

View File

@@ -0,0 +1,21 @@
VERSION = (1, 7, 2, 'final', 0)
def get_version(*args, **kwargs):
# Don't litter django/__init__.py with all the get_version stuff.
# Only import if it's actually called.
from django.utils.version import get_version
return get_version(*args, **kwargs)
def setup():
"""
Configure the settings (this happens as a side effect of accessing the
first setting), configure logging and populate the app registry.
"""
from django.apps import apps
from django.conf import settings
from django.utils.log import configure_logging
configure_logging(settings.LOGGING_CONFIG, settings.LOGGING)
apps.populate(settings.INSTALLED_APPS)

View File

@@ -0,0 +1,168 @@
"""
This module collects helper functions and classes that "span" multiple levels
of MVC. In other words, these functions/classes introduce controlled coupling
for convenience's sake.
"""
from django.template import loader, RequestContext
from django.http import HttpResponse, Http404
from django.http import HttpResponseRedirect, HttpResponsePermanentRedirect
from django.db.models.base import ModelBase
from django.db.models.manager import Manager
from django.db.models.query import QuerySet
from django.core import urlresolvers
from django.utils import six
def render_to_response(*args, **kwargs):
"""
Returns a HttpResponse whose content is filled with the result of calling
django.template.loader.render_to_string() with the passed arguments.
"""
httpresponse_kwargs = {'content_type': kwargs.pop('content_type', None)}
return HttpResponse(loader.render_to_string(*args, **kwargs), **httpresponse_kwargs)
def render(request, *args, **kwargs):
"""
Returns a HttpResponse whose content is filled with the result of calling
django.template.loader.render_to_string() with the passed arguments.
Uses a RequestContext by default.
"""
httpresponse_kwargs = {
'content_type': kwargs.pop('content_type', None),
'status': kwargs.pop('status', None),
}
if 'context_instance' in kwargs:
context_instance = kwargs.pop('context_instance')
if kwargs.get('current_app', None):
raise ValueError('If you provide a context_instance you must '
'set its current_app before calling render()')
else:
current_app = kwargs.pop('current_app', None)
context_instance = RequestContext(request, current_app=current_app)
kwargs['context_instance'] = context_instance
return HttpResponse(loader.render_to_string(*args, **kwargs),
**httpresponse_kwargs)
def redirect(to, *args, **kwargs):
"""
Returns an HttpResponseRedirect to the appropriate URL for the arguments
passed.
The arguments could be:
* A model: the model's `get_absolute_url()` function will be called.
* A view name, possibly with arguments: `urlresolvers.reverse()` will
be used to reverse-resolve the name.
* A URL, which will be used as-is for the redirect location.
By default issues a temporary redirect; pass permanent=True to issue a
permanent redirect
"""
if kwargs.pop('permanent', False):
redirect_class = HttpResponsePermanentRedirect
else:
redirect_class = HttpResponseRedirect
return redirect_class(resolve_url(to, *args, **kwargs))
def _get_queryset(klass):
"""
Returns a QuerySet from a Model, Manager, or QuerySet. Created to make
get_object_or_404 and get_list_or_404 more DRY.
Raises a ValueError if klass is not a Model, Manager, or QuerySet.
"""
if isinstance(klass, QuerySet):
return klass
elif isinstance(klass, Manager):
manager = klass
elif isinstance(klass, ModelBase):
manager = klass._default_manager
else:
if isinstance(klass, type):
klass__name = klass.__name__
else:
klass__name = klass.__class__.__name__
raise ValueError("Object is of type '%s', but must be a Django Model, "
"Manager, or QuerySet" % klass__name)
return manager.all()
def get_object_or_404(klass, *args, **kwargs):
"""
Uses get() to return an object, or raises a Http404 exception if the object
does not exist.
klass may be a Model, Manager, or QuerySet object. All other passed
arguments and keyword arguments are used in the get() query.
Note: Like with get(), an MultipleObjectsReturned will be raised if more than one
object is found.
"""
queryset = _get_queryset(klass)
try:
return queryset.get(*args, **kwargs)
except queryset.model.DoesNotExist:
raise Http404('No %s matches the given query.' % queryset.model._meta.object_name)
def get_list_or_404(klass, *args, **kwargs):
"""
Uses filter() to return a list of objects, or raise a Http404 exception if
the list is empty.
klass may be a Model, Manager, or QuerySet object. All other passed
arguments and keyword arguments are used in the filter() query.
"""
queryset = _get_queryset(klass)
obj_list = list(queryset.filter(*args, **kwargs))
if not obj_list:
raise Http404('No %s matches the given query.' % queryset.model._meta.object_name)
return obj_list
def resolve_url(to, *args, **kwargs):
"""
Return a URL appropriate for the arguments passed.
The arguments could be:
* A model: the model's `get_absolute_url()` function will be called.
* A view name, possibly with arguments: `urlresolvers.reverse()` will
be used to reverse-resolve the name.
* A URL, which will be returned as-is.
"""
# If it's a model, use get_absolute_url()
if hasattr(to, 'get_absolute_url'):
return to.get_absolute_url()
if isinstance(to, six.string_types):
# Handle relative URLs
if any(to.startswith(path) for path in ('./', '../')):
return to
# Next try a reverse URL resolution.
try:
return urlresolvers.reverse(to, args=args, kwargs=kwargs)
except urlresolvers.NoReverseMatch:
# If this is a callable, re-raise.
if callable(to):
raise
# If this doesn't "feel" like a URL, re-raise.
if '/' not in to and '.' not in to:
raise
# Finally, fall back and assume it's a URL
return to

View File

@@ -0,0 +1,28 @@
Metadata-Version: 1.0
Name: eggutils
Version: 0.0.2
Summary: A set of utilities to create/manipulate eggs
Home-page: http://pypi.python.org/pypi/eggutils
Author: David Cournapeau
Author-email: cournape@gmail.com
License: BSD
Description: Set of utilities to manipulate and create eggs without setuptools, and outside
distutils context (i.e. without running setup).
Making an egg containing DLL
============================
Given Windows model for DLLs, when several python packages depends on the same
dll to be shared between extensions, it may be useful to have a "DLL egg" which
put the dlls within the python installation such as the dll are automatically
found by any extension to the corresponding python interpreter.
Usage:
::
make-dll-egg -m PKG-INFO foo.dll bar.dll
This will create a DLL with metadata taken from the PKG-INFO file, containing
both foo and bar dlls.
Platform: any

View File

@@ -0,0 +1,10 @@
README
setup.cfg
setup.py
eggutils/__init__.py
eggutils/eggutils.py
eggutils.egg-info/PKG-INFO
eggutils.egg-info/SOURCES.txt
eggutils.egg-info/dependency_links.txt
eggutils.egg-info/entry_points.txt
eggutils.egg-info/top_level.txt

View File

@@ -0,0 +1,3 @@
[console_scripts]
make-dll-egg = eggutils.eggutils:wrap_main

View File

@@ -0,0 +1,11 @@
../eggutils/__init__.py
../eggutils/eggutils.py
../eggutils/__init__.pyc
../eggutils/eggutils.pyc
./
SOURCES.txt
dependency_links.txt
top_level.txt
entry_points.txt
PKG-INFO
../../../../bin/make-dll-egg