pax_global_header00006660000000000000000000000064125144176210014515gustar00rootroot0000000000000052 comment=b7518047863bac705452307e24aeb66bbe6a007c dodgy-0.1.7/000077500000000000000000000000001251441762100126305ustar00rootroot00000000000000dodgy-0.1.7/.coveragerc000066400000000000000000000000241251441762100147450ustar00rootroot00000000000000 [run] source=dodgy dodgy-0.1.7/.gitignore000066400000000000000000000004671251441762100146270ustar00rootroot00000000000000*.py[cod] # C extensions *.so # Packages *.egg *.egg-info dist build eggs parts var sdist develop-eggs .installed.cfg lib lib64 __pycache__ # Installer logs pip-log.txt # Unit test / coverage reports .coverage .tox nosetests.xml # Translations *.mo # Mr Developer .mr.developer.cfg .project .pydevproject dodgy-0.1.7/.landscape.yaml000066400000000000000000000000201251441762100155140ustar00rootroot00000000000000strictness: highdodgy-0.1.7/.travis.yml000066400000000000000000000004251251441762100147420ustar00rootroot00000000000000language: python python: - "2.7" - "3.3" - "3.4" install: - "pip install --use-mirrors nose coverage coveralls" - "pip install --use-mirrors --editable ." script: nosetests dodgy -s --with-coverage --cover-inclusive --cover-package=dodgy after_success: coveralls dodgy-0.1.7/LICENSE000066400000000000000000000020531251441762100136350ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2013 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. dodgy-0.1.7/MANIFEST.in000066400000000000000000000000221251441762100143600ustar00rootroot00000000000000include bin/dodgy dodgy-0.1.7/README.md000066400000000000000000000027311251441762100141120ustar00rootroot00000000000000dodgy ===== Dodgy is a very basic tool to run against your codebase to search for "dodgy" looking values. It is a series of simple regular expressions designed to detect things such as accidental SCM diff checkins, or passwords or secret keys hard coded into files. While this is primarily aimed at open source projects (for whom a publicly available secret key is pretty dangerous), it can also be used in private projects, with the caveat that it will point out things which are not a problem for private projects and is not configurable enough currently to change that. Another note - this tool is probably best run pre-commit, since it will hopefully prevent dodgy things being checked in. Status --- [![Latest Version](https://pypip.in/v/dodgy/badge.png)](https://crate.io/packages/dodgy) [![Build Status](https://travis-ci.org/landscapeio/dodgy.png?branch=master)](https://travis-ci.org/landscapeio/dodgy) [![Code Health](https://landscape.io/github/landscapeio/dodgy/master/landscape.png)](https://landscape.io/github/landscapeio/dodgy/master) [![Coverage Status](https://coveralls.io/repos/landscapeio/dodgy/badge.png)](https://coveralls.io/r/landscapeio/dodgy) This is a very early version with minimal functionality right now, but will be improved over time. It was written as one of several tools for [landscape.io](https://landscape.io), a code metrics and repository analyser for Python. As such, the features will mostly reflect the needs of Landscape in the early stages. dodgy-0.1.7/bin/000077500000000000000000000000001251441762100134005ustar00rootroot00000000000000dodgy-0.1.7/bin/dodgy000066400000000000000000000000701251441762100144260ustar00rootroot00000000000000#!/usr/bin/env python import dodgy.run dodgy.run.run() dodgy-0.1.7/dodgy/000077500000000000000000000000001251441762100137365ustar00rootroot00000000000000dodgy-0.1.7/dodgy/__init__.py000066400000000000000000000000001251441762100160350ustar00rootroot00000000000000dodgy-0.1.7/dodgy/__pkginfo__.py000066400000000000000000000001311251441762100165340ustar00rootroot00000000000000 VERSION = (0, 1, 7) def get_version(): return '.'.join([str(v) for v in VERSION]) dodgy-0.1.7/dodgy/checks.py000066400000000000000000000036311251441762100155530ustar00rootroot00000000000000import re STRING_VALS = ( ( 'aws_secret_key', 'Amazon Web Services secret key', ( re.compile(r'(\'|")[A-Za-z0-9\\\+]{40}(\'|")'), re.compile(r'(\b|_)AWS(\b|_)', re.IGNORECASE) ), all ), ) LINE_VALS = ( ( 'diff', 'Possible SCM diff in code', ( re.compile(r'^<<<<<<< .*$'), re.compile(r'^>>>>>>> .*$') ), ), ( 'ssh_rsa_private_key', 'Possible SSH private key', re.compile(r'^-{5}(BEGIN|END)\s+RSA\s+PRIVATE\s+KEY-{5}$') ), ( 'ssh_rsa_public_key', 'Possible SSH public key', re.compile('^ssh-rsa\s+AAAA[0-9A-Za-z+/]+[=]{0,3}\s*([^@]+@[^@]+)?$') ), ) VAR_NAMES = ( ( 'password', 'Possible hardcoded password', re.compile(r'(\b|[A-Z0-9_]*_)PASSWORD(_[A-Z0-9_]*|\b)\s*=\s(\'|")[^\'"]+(\'|")') ), ( 'secret', 'Possible hardcoded secret key', re.compile(r'(\b|[A-Z0-9_]*_)SECRET(_[A-Z0-9_]*|\b)\s*=\s(\'|")[^\'"]+(\'|")') ), ) def check_line(line, check_list): messages = [] for tup in check_list: if len(tup) == 3: key, msg, regexps = tup cond = any else: key, msg, regexps, cond = tup if not isinstance(regexps, (list, tuple)): regexps = [regexps] if cond([regexp.search(line) for regexp in regexps]): messages.append((key, msg)) return messages def check_file(filepath): with open(filepath) as to_check: return check_file_contents(to_check.read()) def check_file_contents(file_contents): messages = [] for line_number0, line in enumerate(file_contents.split('\n')): for check_list in (STRING_VALS, LINE_VALS, VAR_NAMES): messages += [(line_number0+1, key, msg) for key, msg in check_line(line, check_list)] return messages dodgy-0.1.7/dodgy/run.py000066400000000000000000000031221251441762100151120ustar00rootroot00000000000000import sys import re import os import mimetypes import json from dodgy.checks import check_file IGNORE_PATHS = [re.compile(patt % {'sep': re.escape(os.path.sep)}) for patt in ( r'(^|%(sep)s)\.[^\.]', # ignores any files or directories starting with '.' r'^tests?%(sep)s?', r'%(sep)stests?(%(sep)s|$)', )] def list_files(start_path): filepaths = [] for root, _, files in os.walk(start_path): for file_name in files: filepaths.append(os.path.join(root, file_name)) return filepaths def run_checks(directory, ignore_paths=None): warnings = [] ignore_paths = ignore_paths or [] ignore_paths = [re.compile(patt) for patt in ignore_paths] ignore_paths += IGNORE_PATHS filepaths = list_files(directory) for filepath in filepaths: relpath = os.path.relpath(filepath, directory) if any([ignore.search(relpath) for ignore in ignore_paths]): continue # this is a naive check to skip binary files, it's probably okay for now mimetype = mimetypes.guess_type(filepath) if mimetype[0] is None or not mimetype[0].startswith('text/'): continue for msg_parts in check_file(filepath): warnings.append({ 'path': relpath, 'line': msg_parts[0], 'code': msg_parts[1], 'message': msg_parts[2] }) return warnings def run(): warnings = run_checks(os.getcwd()) output = json.dumps({'warnings': warnings}, indent=2) sys.stdout.write(output + '\n') if __name__ == '__main__': run() dodgy-0.1.7/setup.py000066400000000000000000000021241251441762100143410ustar00rootroot00000000000000# -*- coding: UTF-8 -*- from distutils.core import setup from setuptools import find_packages from dodgy import __pkginfo__ _packages = find_packages(exclude=["*.tests", "*.tests.*", "tests.*", "tests"]) _short_description = "Dodgy: Searches for dodgy looking lines in Python code" _install_requires = [] _classifiers = ( 'Development Status :: 2 - Pre-Alpha', 'Environment :: Console', 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', 'Operating System :: Unix', 'Topic :: Software Development :: Quality Assurance', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', ) setup( name='dodgy', url='https://github.com/landscapeio/dodgy', author='landscape.io', author_email='code@landscape.io', description=_short_description, install_requires=_install_requires, scripts=['bin/dodgy'], version=__pkginfo__.get_version(), packages=_packages, license='MIT', keywords='check for suspicious code', classifiers=_classifiers ) dodgy-0.1.7/tests/000077500000000000000000000000001251441762100137725ustar00rootroot00000000000000dodgy-0.1.7/tests/__init__.py000066400000000000000000000000001251441762100160710ustar00rootroot00000000000000dodgy-0.1.7/tests/test_checks.py000066400000000000000000000031151251441762100166430ustar00rootroot00000000000000import os from unittest import TestCase from dodgy.checks import check_file class TestChecks(TestCase): def _run_checks(self, file_name): filepath = os.path.join(os.path.dirname(__file__), 'testdata', file_name) return check_file(filepath) def _check_messages(self, messages, expected_keys): if expected_keys == (None,): self.assertTrue(len(messages) == 0) return for key in expected_keys: for message in messages: if key == message[1]: break else: self.fail("Expected key %s but was not found" % key) def _do_test(self, file_name, *expected_keys): messages = self._run_checks(file_name) self._check_messages(messages, expected_keys) def test_amazon_keys(self): self._do_test('amazon.py', 'aws_secret_key') def test_diffs(self): self._do_test('diff.py', 'diff') def test_password_varnames(self): self._do_test('passwords1.py', 'password') self._do_test('passwords2.py', 'password') self._do_test('passwords3.py', 'password') self._do_test('passwords4.py', None) def test_secret_varnames(self): self._do_test('secrets1.py', 'secret') self._do_test('secrets2.py', 'secret') self._do_test('secrets3.py', 'secret') self._do_test('secrets4.py', None) def test_ssh_privatekey(self): self._do_test('ssh_private_key', 'ssh_rsa_private_key') def test_ssh_publickey(self): self._do_test('ssh_public_key.pub', 'ssh_rsa_public_key') dodgy-0.1.7/tests/testdata/000077500000000000000000000000001251441762100156035ustar00rootroot00000000000000dodgy-0.1.7/tests/testdata/amazon.py000066400000000000000000000001041251441762100174350ustar00rootroot00000000000000 AWS_SECRET_ACCESS_KEY = 'A8+6AN5TSUZ3vysJg68Rt\A9E7duMlfKODwb3ZD8' dodgy-0.1.7/tests/testdata/diff.py000066400000000000000000000001521251441762100170630ustar00rootroot00000000000000<<<<<<< HEAD var = 'this is a test doncha know' ======= var = 'this is a test of testyness' >>>>>>> branchdodgy-0.1.7/tests/testdata/passwords1.py000066400000000000000000000000351251441762100202610ustar00rootroot00000000000000FACEBOOK_PASSWORD = '123456' dodgy-0.1.7/tests/testdata/passwords2.py000066400000000000000000000000241251441762100202600ustar00rootroot00000000000000PASSWORD = '111111' dodgy-0.1.7/tests/testdata/passwords3.py000066400000000000000000000000401251441762100202570ustar00rootroot00000000000000PASSWORD_TO_GITHUB = 'password' dodgy-0.1.7/tests/testdata/passwords4.py000066400000000000000000000000161251441762100202630ustar00rootroot00000000000000 PASSWORD = ''dodgy-0.1.7/tests/testdata/secrets1.py000066400000000000000000000000211251441762100176770ustar00rootroot00000000000000SECRET = 'lalala'dodgy-0.1.7/tests/testdata/secrets2.py000066400000000000000000000000311251441762100177010ustar00rootroot00000000000000SECRET_KEY = 'ooo secret'dodgy-0.1.7/tests/testdata/secrets3.py000066400000000000000000000000311251441762100177020ustar00rootroot00000000000000THE_SUPER_SECRET = 'fish'dodgy-0.1.7/tests/testdata/secrets4.py000066400000000000000000000000251251441762100177060ustar00rootroot00000000000000 SOME_SECRET_VAL = ''dodgy-0.1.7/tests/testdata/ssh_private_key000066400000000000000000000032171251441762100207300ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIIEpQIBAAKCAQEAzKmdhTv2MvnItPvct8VHqJ1/+LZn2D4gJI7H1FlpMpB5AmFJ U1Uvdqa2okztuesctvaLGJNcbO1NDqS87Xx2pxwblIWc9KZ/0b8mBnqt4uR9zXv2 dtU5XTGpIWijAeNldQtvjldMZ46BLT2FFRvInIuxM4y8g6LUZGIoEaLiNuj7Jij8 sn6md02FXzLZD9tUXXCOP5Z2undXQZq0N5ctAeoPqRH/Dm2ga4rtBXrLdMmYchfI bILnhroGRV842gLuvIm/fZz9e8NddXG3o/Y1DZ8n7HspJeZ4Kq77D95hisO9/c/q dLyCHIR2Gt45+sVvH4pvzx+ILXFgvJlF5b+l0wIDAQABAoIBAQCTs6Fj4ydGGLB5 tP7QfYa+sJQHqZR+Ii/OUmDy5mgePtemGRHzGxo69gv+S6iRMZWykXFHFipwzj17 YPacKePzrDxXTqo8geDjPaEysdzGT4JfBqSTlERm9o0J+FsT5Ml20/75ahVQ8y5U uP5PgpKgL8x92IbANYY0wAYM3FGHsAgSs+xdgwIKAHLMiXNnpOlT+AMTD1Aq8PkK Mj0ENKfPRCmdQUJITmuiG0TpmJrxgzDl9xYPUYl6oZL2VLLTmHg/DHIBILWrk6+z rq/C5y06AdNIGQnyfZvvLqkpuEhWuOg3cQDp2NM2UPCjtSI9Gf9Idu6f96qv17y8 26CHf8UBAoGBAObT4Uq5hYhAVmeJLDhXo1Br9gHQjFXVQj7FAF+rfkOx/gWac65W z7srPyyDlbXiyuhxcBACV8kUKL/gEbJbv4owX7oaP1nh0BA7X5thcskg+V2FMkCo syN+KYVcAma0KAv/RRpbx8Emk/IWbS+5Y9zBHbVhcUCeFWmL5Cy8WGJTAoGBAOL7 Rb8NbkVZCPaGPMER+tCyhzxIk1Nz/yBtFVorJgPk2DgOe9mvgqNRPkkKhb/GQh2T ElZ16nz0xHVysKal3Z1vxXL6v0BHTEiMYM1GoJWAx47uHzQrsGcnV0hwuAuUWIJK h1NDD+iRwx7TP2P5NUtoNwd/w0FX9BmW7YtUQj6BAoGBAMKzliVht7DmE/vhSNt9 kNQVPLzrHHSKHga0RUxta2POj2ZKkalMsIxAPlld5Lo3QtAuX0ghscp6pqSybDr2 COqXQyfHXAiE4OvQKST3XcspdS3dXDYOFoyprnw+0AexjtYPzEofgK77y284W4EV 75YVjumf99d5gLY2uZDCjgrhAoGAfsujIKDeErsz+JLwaWIj3GV+ijx4oEvSH0kQ fnhQGijCaD4fDXGv5o/B3YeVQ5X65Q59VfM09Gy/OmTBLbbGX+ZKRHqyT7QEdxqE EOf9WMbBs6RtpfUp69XcOklNZpqN/uqnQenafy698wBLDwvtq5wh8Xx7lIsPfyQC uqxs/QECgYEAr8GbvljGxP/rBzTe+tA3FLN0YdOHz3w582GO20tJPkr+c6Kema8w O6t1CVRiWRAINNhR2BXhAMurRfSgZlFKryfzBRvmMNykpZUqZknbt1d2YoVVZ7dT pAAdRNt7oLvFYxBnudF5AqOQ4YjqEvsPjXjayW4pb+1xiKUkEVCCXko= -----END RSA PRIVATE KEY----- dodgy-0.1.7/tests/testdata/ssh_public_key.pub000066400000000000000000000006251251441762100213210ustar00rootroot00000000000000ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDMqZ2FO/Yy+ci0+9y3xUeonX/4tmfYPiAkjsfUWWkykHkCYUlTVS92praiTO256xy29osYk1xs7U0OpLztfHanHBuUhZz0pn/RvyYGeq3i5H3Ne/Z21TldMakhaKMB42V1C2+OV0xnjoEtPYUVG8ici7EzjLyDotRkYigRouI26PsmKPyyfqZ3TYVfMtkP21RdcI4/lna6d1dBmrQ3ly0B6g+pEf8ObaBriu0Fest0yZhyF8hsgueGugZFXzjaAu68ib99nP17w111cbej9jUNnyfseykl5ngqrvsP3mGKw739z+p0vIIchHYa3jn6xW8fim/PH4gtcWC8mUXlv6XT nineseconds@home-laptop dodgy-0.1.7/tox.ini000066400000000000000000000001131251441762100141360ustar00rootroot00000000000000[tox] envlist = py26,py27,py33 [testenv] deps=nose commands=nosetests -s