summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Dong <michael.dong@rackspace.com>2018-11-15 17:40:14 -0600
committerMichael Dong <michael.dong@rackspace.com>2018-11-28 12:32:24 -0600
commit6cf7bdab872b057f207453920b6a4ceae3eb6efc (patch)
treeeb7cb1de35fbf17101c35598cf0e7e71108741da
parentc1f24e2e4c2db8e70f0d634531cf028e4eee22ec (diff)
Bug fixes and error message updates
Fixes: 1) Crashes in runner and file_utils 2) Binary strings being read in as payloads Updates: 1) Clarified error messages in parser 2) Confusing variable names in test cases vs issues Adds: 1) A `syntribos root` CLI sub command to display the current syntribos root dir Change-Id: I22edf7a1f3d39724522aee88d08b00d299b67248
Notes
Notes (review): Workflow+1: Michael Dong <michael.dong@rackspace.com> Code-Review+2: Charles Neill <charles.neill@rackspace.com> Code-Review+2: Michael Dong <michael.dong@rackspace.com> Verified+2: Zuul Submitted-by: Zuul Submitted-at: Mon, 10 Dec 2018 20:42:05 +0000 Reviewed-on: https://review.openstack.org/618327 Project: openstack/syntribos Branch: refs/heads/master
-rw-r--r--.mailmap6
-rw-r--r--README.rst60
-rw-r--r--doc/source/conf.py12
-rw-r--r--examples/templates/example_get.template2
-rw-r--r--examples/templates/example_post.template13
-rw-r--r--requirements.txt1
-rw-r--r--syntribos/__init__.py6
-rw-r--r--syntribos/checks/http.py3
-rw-r--r--syntribos/clients/http/parser.py9
-rw-r--r--syntribos/config.py21
-rw-r--r--syntribos/extensions/basic_http/client.py5
-rw-r--r--syntribos/extensions/identity/models/base.py2
-rw-r--r--syntribos/result.py26
-rw-r--r--syntribos/runner.py76
-rw-r--r--syntribos/tests/auth/auth.py4
-rw-r--r--syntribos/tests/base.py21
-rw-r--r--syntribos/tests/debug/dry_run.py2
-rw-r--r--syntribos/tests/fuzz/base_fuzz.py13
-rw-r--r--syntribos/tests/fuzz/buffer_overflow.py8
-rw-r--r--syntribos/tests/fuzz/command_injection.py8
-rw-r--r--syntribos/tests/fuzz/integer_overflow.py8
-rw-r--r--syntribos/tests/fuzz/json_depth_overflow.py2
-rw-r--r--syntribos/tests/fuzz/ldap.py8
-rw-r--r--syntribos/tests/fuzz/redos.py8
-rw-r--r--syntribos/tests/fuzz/sql.py8
-rw-r--r--syntribos/tests/fuzz/string_validation.py8
-rw-r--r--syntribos/tests/fuzz/user_defined.py13
-rw-r--r--syntribos/tests/fuzz/xml_external.py8
-rw-r--r--syntribos/tests/fuzz/xss.py2
-rw-r--r--syntribos/tests/headers/cors.py8
-rw-r--r--syntribos/tests/headers/xst.py6
-rw-r--r--syntribos/tests/transport_layer/ssl.py2
-rw-r--r--syntribos/utils/cli.py11
-rw-r--r--syntribos/utils/config_fixture.py2
-rw-r--r--syntribos/utils/env.py14
-rw-r--r--syntribos/utils/file_utils.py16
-rw-r--r--test-requirements.txt6
-rw-r--r--tests/unit/test_ascii_colors.py4
-rw-r--r--tests/unit/test_content_validity.py8
-rw-r--r--tests/unit/test_http_checks.py4
-rw-r--r--tests/unit/test_http_parser.py4
-rw-r--r--tests/unit/test_length.py2
-rw-r--r--tests/unit/test_progress_bar.py2
-rw-r--r--tox.ini2
44 files changed, 269 insertions, 185 deletions
diff --git a/.mailmap b/.mailmap
deleted file mode 100644
index 8fa9de4..0000000
--- a/.mailmap
+++ /dev/null
@@ -1,6 +0,0 @@
1# Format is:
2# <preferred e-mail> <other e-mail 1>
3# <preferred e-mail> <other e-mail 2>
4<michael.xin@rackspace.com> <jqxin2006@gmail.com>
5Nathan Buckner <nathan.buckner@rackspace.com> bucknerns <nathan.buckner@rackspace.com>
6
diff --git a/README.rst b/README.rst
index 04315b0..cdddf53 100644
--- a/README.rst
+++ b/README.rst
@@ -27,29 +27,6 @@ Team and repository tags
27Syntribos, An Automated API Security Testing Tool 27Syntribos, An Automated API Security Testing Tool
28================================================= 28=================================================
29 29
30::
31
32 syntribos
33 xxxxxxx
34 x xxxxxxxxxxxxx x
35 x xxxxxxxxxxx x
36 xxxxxxxxx
37 x xxxxxxx x
38 xxxxx
39 x xxx x
40 x
41 xxxxxxxxxxxxxxx xxxxxxxxxxxxxxx
42 xxxxxxxxxxxxx xxxxxxxxxxxxx
43 xxxxxxxxxxx xxxxxxxxxxx
44 xxxxxxxxx xxxxxxxxx
45 xxxxxx xxxxxx
46 xxx xxx
47 x x
48 x
49 === Automated API Scanning ===
50
51
52
53Syntribos is an open source automated API security testing tool that is 30Syntribos is an open source automated API security testing tool that is
54maintained by members of the `OpenStack Security Project <https://wiki.openstack.org/wiki/Security>`_. 31maintained by members of the `OpenStack Security Project <https://wiki.openstack.org/wiki/Security>`_.
55 32
@@ -182,7 +159,7 @@ User defined Test
182 159
183This test gives users the ability to fuzz using user defined fuzz data and 160This test gives users the ability to fuzz using user defined fuzz data and
184provides an option to look for failure strings provided by the user. The fuzz 161provides an option to look for failure strings provided by the user. The fuzz
185data needs to be provided using the config option :option:`[user_defined]`. 162data needs to be provided using the config option `[user_defined]`.
186 163
187Example:: 164Example::
188 165
@@ -281,6 +258,9 @@ environment, you can specify the ``--force`` flag to overwrite existing files.
281The ``--custom_install_root`` and ``--force`` flags can be combined to 258The ``--custom_install_root`` and ``--force`` flags can be combined to
282overwrite files in a custom install root. 259overwrite files in a custom install root.
283 260
261Note: if you install syntribos to a custom install root, you must supply the
262``--custom_install_root`` flag when running syntribos.
263
284**Example:** 264**Example:**
285 265
286:: 266::
@@ -516,8 +496,14 @@ using syntribos:
516Running syntribos 496Running syntribos
517================= 497=================
518 498
499By default, syntribos looks in the syntribos home directory (the directory
500specified when running the ``syntribos init`` command on install) for config
501files, payloads, and templates. This can all be overridden through command
502line options. For a full list of command line options available, run
503``syntribos --help`` from the command line.
504
519To run syntribos against all the available tests, specify the 505To run syntribos against all the available tests, specify the
520command ``syntribos`` with the configuration file without 506command ``syntribos``, with the configuration file (if needed), without
521specifying any test type. 507specifying any test type.
522 508
523:: 509::
@@ -563,6 +549,9 @@ There are two types of logs generated by syntribos:
563Results Log 549Results Log
564~~~~~~~~~~~ 550~~~~~~~~~~~
565 551
552The results log is displayed at the end of every syntribos run, it can be
553written to a file by using the ``-o`` flag on the command line.
554
566The results log includes failures and errors. The ``"failures"`` key represents 555The results log includes failures and errors. The ``"failures"`` key represents
567tests that have failed, indicating a possible security vulnerability. The 556tests that have failed, indicating a possible security vulnerability. The
568``"errors"`` key gives us information on any unhandled exceptions, such as 557``"errors"`` key gives us information on any unhandled exceptions, such as
@@ -726,6 +715,25 @@ This section describes how to write templates and how to run specific tests.
726Templates are input files which have raw HTTP requests and may be 715Templates are input files which have raw HTTP requests and may be
727supplemented with variable data using extensions. 716supplemented with variable data using extensions.
728 717
718In general, a request template is a marked-up raw HTTP request. It's possible
719for you to test your application by using raw HTTP requests as your request
720templates, but syntribos allows you to mark-up your request templates for
721further functionality.
722
723A request template looks something like this:
724
725::
726
727 POST /users/{user1} HTTP/1.1
728 Content-Type: application/json
729 X-Auth-Token: CALL_EXTERNAL|syntribos.extensions.vAPI.client:get_token:[]|
730
731 {"newpassword": "qwerty123"}
732
733For fuzz tests, syntribos will automatically detect URL parameters, headers,
734and body content as fields to fuzz. It will not automatically detect URL path
735elements as fuzz fields, but they can be specified with curly braces ``{}``.
736
729Note: The name of a template file must end with the extension ``.template`` 737Note: The name of a template file must end with the extension ``.template``
730Otherwise, syntribos will skip the file and will not attempt to parse any files 738Otherwise, syntribos will skip the file and will not attempt to parse any files
731that do not adhere to this naming scheme. 739that do not adhere to this naming scheme.
@@ -963,7 +971,7 @@ XML external entity, reflected cross-site scripting,
963Cross Origin Resource Sharing (CORS), SSL, Regex Denial of Service, 971Cross Origin Resource Sharing (CORS), SSL, Regex Denial of Service,
964JSON Parser Depth Limit, and User defined. 972JSON Parser Depth Limit, and User defined.
965 973
966In order to run a specific test, use the :option:`-t, --test-types` 974In order to run a specific test, use the `-t, --test-types`
967option and provide ``syntribos`` with a keyword, or keywords, to match from 975option and provide ``syntribos`` with a keyword, or keywords, to match from
968the test files located in ``syntribos/tests/``. 976the test files located in ``syntribos/tests/``.
969 977
diff --git a/doc/source/conf.py b/doc/source/conf.py
index 6593c0c..76ce492 100644
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -33,8 +33,8 @@ source_suffix = ".rst"
33master_doc = "index" 33master_doc = "index"
34 34
35# General information about the project. 35# General information about the project.
36project = u"syntribos" 36project = "syntribos"
37copyright = u"2015-present, OpenStack Foundation" 37copyright = "2015-present, OpenStack Foundation"
38 38
39# If true, "()" will be appended to :func: etc. cross-reference text. 39# If true, "()" will be appended to :func: etc. cross-reference text.
40add_function_parentheses = True 40add_function_parentheses = True
@@ -52,8 +52,8 @@ pygments_style = "sphinx"
52# List of tuples "sourcefile", "target", u"title", u"Authors name", "manual" 52# List of tuples "sourcefile", "target", u"title", u"Authors name", "manual"
53 53
54man_pages = [("man/syntribos", "syntribos", 54man_pages = [("man/syntribos", "syntribos",
55 u"Automated API security testing tool", 55 "Automated API security testing tool",
56 [u"OpenStack Security Group"], 1)] 56 ["OpenStack Security Group"], 1)]
57 57
58# -- Options for HTML output -------------------------------------------------- 58# -- Options for HTML output --------------------------------------------------
59 59
@@ -70,8 +70,8 @@ htmlhelp_basename = "%sdoc" % project
70# Grouping the document tree into LaTeX files. List of tuples 70# Grouping the document tree into LaTeX files. List of tuples
71# (source start file, target name, title, author, documentclass 71# (source start file, target name, title, author, documentclass
72# [howto/manual]). 72# [howto/manual]).
73latex_documents = [("index", "%s.tex" % project, u"%s Documentation" % project, 73latex_documents = [("index", "%s.tex" % project, "%s Documentation" % project,
74 u"OpenStack Foundation", "manual"), ] 74 "OpenStack Foundation", "manual"), ]
75 75
76# Example configuration for intersphinx: refer to the Python standard library. 76# Example configuration for intersphinx: refer to the Python standard library.
77# intersphinx_mapping = {"http://docs.python.org/": None} 77# intersphinx_mapping = {"http://docs.python.org/": None}
diff --git a/examples/templates/example_get.template b/examples/templates/example_get.template
new file mode 100644
index 0000000..a211370
--- /dev/null
+++ b/examples/templates/example_get.template
@@ -0,0 +1,2 @@
1GET /examples?query=yes HTTP/1.1
2Accept: application/json
diff --git a/examples/templates/example_post.template b/examples/templates/example_post.template
new file mode 100644
index 0000000..b55ccc0
--- /dev/null
+++ b/examples/templates/example_post.template
@@ -0,0 +1,13 @@
1POST /examples HTTP/1.1
2Accept: application/json
3Content-type: application/json
4
5{
6 "id": 24601,
7 "name": "myname",
8 "password": "letmein",
9 "params": {
10 "string": "aaa",
11 "array": [1,2,3,4,5]
12 }
13}
diff --git a/requirements.txt b/requirements.txt
index b88d9c0..479bfd9 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -10,3 +10,4 @@ python-cinderclient>=3.3.0 # Apache-2.0
10python-glanceclient>=2.8.0 # Apache-2.0 10python-glanceclient>=2.8.0 # Apache-2.0
11python-neutronclient>=6.7.0 # Apache-2.0 11python-neutronclient>=6.7.0 # Apache-2.0
12python-novaclient>=9.1.0 # Apache-2.0 12python-novaclient>=9.1.0 # Apache-2.0
13PyYAML>=3.12 # MIT
diff --git a/syntribos/__init__.py b/syntribos/__init__.py
index bf70c2e..8f8ff08 100644
--- a/syntribos/__init__.py
+++ b/syntribos/__init__.py
@@ -12,6 +12,6 @@
12# See the License for the specific language governing permissions and 12# See the License for the specific language governing permissions and
13# limitations under the License. 13# limitations under the License.
14# pylint: skip-file 14# pylint: skip-file
15from syntribos.issue import Issue # flake8: noqa 15from syntribos.issue import Issue # noqa
16from syntribos.constants import * 16from syntribos.constants import * # noqa
17from syntribos.result import IssueTestResult # flake8: noqa 17from syntribos.result import IssueTestResult # noqa
diff --git a/syntribos/checks/http.py b/syntribos/checks/http.py
index 25caa65..8885b26 100644
--- a/syntribos/checks/http.py
+++ b/syntribos/checks/http.py
@@ -59,7 +59,8 @@ def check_fail(exception):
59 desc="An unknown exception was raised. Please report this.") 59 desc="An unknown exception was raised. Please report this.")
60 60
61 # CONNECTION FAILURES 61 # CONNECTION FAILURES
62 if isinstance(exception, (rex.ProxyError, rex.SSLError)): 62 if isinstance(exception, (rex.ProxyError, rex.SSLError,
63 rex.ChunkedEncodingError, rex.ConnectionError)):
63 tags.update(["CONNECTION_FAIL"]) 64 tags.update(["CONNECTION_FAIL"])
64 # TIMEOUTS 65 # TIMEOUTS
65 elif isinstance(exception, (rex.ConnectTimeout, rex.ReadTimeout)): 66 elif isinstance(exception, (rex.ConnectTimeout, rex.ReadTimeout)):
diff --git a/syntribos/clients/http/parser.py b/syntribos/clients/http/parser.py
index 8c8c220..1c27ef0 100644
--- a/syntribos/clients/http/parser.py
+++ b/syntribos/clients/http/parser.py
@@ -85,9 +85,9 @@ class RequestCreator(object):
85 """ 85 """
86 if not cls.meta_vars: 86 if not cls.meta_vars:
87 msg = ("Template contains reference to meta variable of the form " 87 msg = ("Template contains reference to meta variable of the form "
88 "'|{}|', but no meta.json file is found in the" 88 "'|{}|', but no valid meta.json file was found in the "
89 "templates directory. Check your templates and the " 89 "templates directory. Check that your templates reference "
90 "documentation on how to resolve this".format(var)) 90 "a meta.json file that is correctly formatted.".format(var))
91 raise TemplateParseException(msg) 91 raise TemplateParseException(msg)
92 92
93 if var not in cls.meta_vars: 93 if var not in cls.meta_vars:
@@ -431,7 +431,6 @@ class RequestHelperMixin(object):
431 self.params = "" 431 self.params = ""
432 self.data = "" 432 self.data = ""
433 self.url = "" 433 self.url = ""
434 self.url = ""
435 434
436 @classmethod 435 @classmethod
437 def _run_iters(cls, data, action_field): 436 def _run_iters(cls, data, action_field):
@@ -506,6 +505,8 @@ class RequestHelperMixin(object):
506 if data_type == 'json': 505 if data_type == 'json':
507 return json.dumps(data) 506 return json.dumps(data)
508 elif data_type == 'xml': 507 elif data_type == 'xml':
508 if isinstance(data, str):
509 return data
509 str_data = ElementTree.tostring(data) 510 str_data = ElementTree.tostring(data)
510 # No way to stop tostring from HTML escaping even if we wanted 511 # No way to stop tostring from HTML escaping even if we wanted
511 h = html_parser.HTMLParser() 512 h = html_parser.HTMLParser()
diff --git a/syntribos/config.py b/syntribos/config.py
index bcfb96f..4afdffd 100644
--- a/syntribos/config.py
+++ b/syntribos/config.py
@@ -13,8 +13,6 @@
13# limitations under the License. 13# limitations under the License.
14# pylint: skip-file 14# pylint: skip-file
15import logging 15import logging
16import sys
17
18from oslo_config import cfg 16from oslo_config import cfg
19 17
20import syntribos 18import syntribos
@@ -51,7 +49,6 @@ def handle_config_exception(exc):
51 if msg: 49 if msg:
52 LOG.warning(msg) 50 LOG.warning(msg)
53 print(syntribos.SEP) 51 print(syntribos.SEP)
54 sys.exit(0)
55 else: 52 else:
56 LOG.exception(exc) 53 LOG.exception(exc)
57 54
@@ -108,6 +105,8 @@ def sub_commands(sub_parser):
108 sub_parser.add_parser("dry_run", 105 sub_parser.add_parser("dry_run",
109 help=_("Dry run syntribos with given config" 106 help=_("Dry run syntribos with given config"
110 "options")) 107 "options"))
108 sub_parser.add_parser("root",
109 help=_("Print syntribos root directory"))
111 110
112 111
113def list_opts(): 112def list_opts():
@@ -144,6 +143,13 @@ def register_opts():
144 OPTS_REGISTERED = True 143 OPTS_REGISTERED = True
145 144
146 145
146def list_payment_system_opts():
147 return [
148 cfg.StrOpt('ran', default='', help='Rackspace Account Number'),
149 cfg.StrOpt('alt_ran', default='', help='Alternate RAN')
150 ]
151
152
147def list_cli_opts(): 153def list_cli_opts():
148 return [ 154 return [
149 cfg.SubCommandOpt(name="sub_command", 155 cfg.SubCommandOpt(name="sub_command",
@@ -158,8 +164,8 @@ def list_cli_opts():
158 default=[""], sample_default=["SQL", "XSS"], 164 default=[""], sample_default=["SQL", "XSS"],
159 help=_("Test types to be excluded from " 165 help=_("Test types to be excluded from "
160 "current run against the target API")), 166 "current run against the target API")),
161 cfg.BoolOpt("no_colorize", dest="no_colorize", short="ncl", 167 cfg.BoolOpt("colorize", dest="colorize", short="cl",
162 default=False, 168 default=True,
163 help=_("Enable color in syntribos terminal output")), 169 help=_("Enable color in syntribos terminal output")),
164 cfg.StrOpt("outfile", short="o", 170 cfg.StrOpt("outfile", short="o",
165 sample_default="out.json", help=_("File to print " 171 sample_default="out.json", help=_("File to print "
@@ -174,7 +180,10 @@ def list_cli_opts():
174 cfg.StrOpt("min-confidence", dest="min_confidence", short="C", 180 cfg.StrOpt("min-confidence", dest="min_confidence", short="C",
175 default="LOW", choices=syntribos.RANKING, 181 default="LOW", choices=syntribos.RANKING,
176 help=_("Select a minimum confidence for reported " 182 help=_("Select a minimum confidence for reported "
177 "defects")) 183 "defects")),
184 cfg.BoolOpt("stacktrace", dest="stacktrace", default=True,
185 help=_("Select if Syntribos outputs a stacktrace "
186 " if an exception is raised")),
178 ] 187 ]
179 188
180 189
diff --git a/syntribos/extensions/basic_http/client.py b/syntribos/extensions/basic_http/client.py
index 55997e3..239a94a 100644
--- a/syntribos/extensions/basic_http/client.py
+++ b/syntribos/extensions/basic_http/client.py
@@ -22,5 +22,6 @@ CONF = cfg.CONF
22def basic_auth(user_section='user'): 22def basic_auth(user_section='user'):
23 password = CONF.get(user_section).password or CONF.user.password 23 password = CONF.get(user_section).password or CONF.user.password
24 username = CONF.get(user_section).username or CONF.user.username 24 username = CONF.get(user_section).username or CONF.user.username
25 encoded_creds = base64.b64encode("{}:{}".format(username, password)) 25 encoded_creds = base64.b64encode(
26 return "Basic %s" % encoded_creds 26 "{}:{}".format(username, password).encode())
27 return "Basic %s" % encoded_creds.decode()
diff --git a/syntribos/extensions/identity/models/base.py b/syntribos/extensions/identity/models/base.py
index df7bf30..eb65453 100644
--- a/syntribos/extensions/identity/models/base.py
+++ b/syntribos/extensions/identity/models/base.py
@@ -19,8 +19,6 @@ import xml.etree.ElementTree as ET
19class Namespaces(object): 19class Namespaces(object):
20 XMLNS_XSI = "http://www.w3.org/2001/XMLSchema-instance" 20 XMLNS_XSI = "http://www.w3.org/2001/XMLSchema-instance"
21 XMLNS = "http://docs.openstack.org/identity/api/v2.0" 21 XMLNS = "http://docs.openstack.org/identity/api/v2.0"
22 XMLNS_KSKEY = "http://docs.rackspace.com/identity/api/ext/RAX-KSKEY/v1.0"
23 XMLNS_RAX_AUTH = "http://docs.rackspace.com/identity/api/ext/RAX-AUTH/v1.0"
24 22
25 23
26class BaseIdentityModel(object): 24class BaseIdentityModel(object):
diff --git a/syntribos/result.py b/syntribos/result.py
index 05321fc..6317154 100644
--- a/syntribos/result.py
+++ b/syntribos/result.py
@@ -13,6 +13,7 @@
13# limitations under the License. 13# limitations under the License.
14import threading 14import threading
15import time 15import time
16import traceback
16import unittest 17import unittest
17 18
18from oslo_config import cfg 19from oslo_config import cfg
@@ -20,7 +21,6 @@ from oslo_config import cfg
20import syntribos 21import syntribos
21from syntribos._i18n import _ 22from syntribos._i18n import _
22from syntribos.formatters.json_formatter import JSONFormatter 23from syntribos.formatters.json_formatter import JSONFormatter
23from syntribos.runner import Runner
24import syntribos.utils.remotes 24import syntribos.utils.remotes
25 25
26CONF = cfg.CONF 26CONF = cfg.CONF
@@ -33,6 +33,7 @@ class IssueTestResult(unittest.TextTestResult):
33 This class aggregates :class:`syntribos.issue.Issue` objects from all the 33 This class aggregates :class:`syntribos.issue.Issue` objects from all the
34 tests as they run 34 tests as they run
35 """ 35 """
36 raw_issues = []
36 output = {"failures": {}, "errors": [], "stats": {}} 37 output = {"failures": {}, "errors": [], "stats": {}}
37 output["stats"]["severity"] = { 38 output["stats"]["severity"] = {
38 "UNDEFINED": 0, 39 "UNDEFINED": 0,
@@ -88,6 +89,7 @@ class IssueTestResult(unittest.TextTestResult):
88 """ 89 """
89 lock.acquire() 90 lock.acquire()
90 for issue in test.failures: 91 for issue in test.failures:
92 self.raw_issues.append(issue)
91 defect_type = issue.defect_type 93 defect_type = issue.defect_type
92 if any([ 94 if any([
93 True for x in CONF.syntribos.exclude_results 95 True for x in CONF.syntribos.exclude_results
@@ -212,17 +214,22 @@ class IssueTestResult(unittest.TextTestResult):
212 :type tuple: Tuple of format ``(type, value, traceback)`` 214 :type tuple: Tuple of format ``(type, value, traceback)``
213 """ 215 """
214 with lock: 216 with lock:
217 err_str = "{}: {}".format(err[0].__name__, str(err[1]))
215 for e in self.errors: 218 for e in self.errors:
216 if e['error'] == self._exc_info_to_string(err, test): 219 if e['error'] == err_str:
217 if self.getDescription(test) in e['test']: 220 if self.getDescription(test) in e['test']:
218 return 221 return
219 e['test'].append(self.getDescription(test)) 222 e['test'].append(self.getDescription(test))
220 self.stats["errors"] += 1 223 self.stats["errors"] += 1
221 return 224 return
222 self.errors.append({ 225 stacktrace = traceback.format_exception(*err, limit=0)
226 _e = {
223 "test": [self.getDescription(test)], 227 "test": [self.getDescription(test)],
224 "error": self._exc_info_to_string(err, test) 228 "error": err_str
225 }) 229 }
230 if CONF.stacktrace:
231 _e["stacktrace"] = [x.strip() for x in stacktrace]
232 self.errors.append(_e)
226 self.stats["errors"] += 1 233 self.stats["errors"] += 1
227 234
228 def addSuccess(self, test): 235 def addSuccess(self, test):
@@ -237,7 +244,7 @@ class IssueTestResult(unittest.TextTestResult):
237 def printErrors(self, output_format): 244 def printErrors(self, output_format):
238 """Print out each :class:`syntribos.issue.Issue` that was encountered 245 """Print out each :class:`syntribos.issue.Issue` that was encountered
239 246
240 :param str output_format: Either "json" or "xml" 247 :param str output_format: "json"
241 """ 248 """
242 self.output["errors"] = self.errors 249 self.output["errors"] = self.errors
243 self.output["failures"] = self.failures 250 self.output["failures"] = self.failures
@@ -250,9 +257,8 @@ class IssueTestResult(unittest.TextTestResult):
250 self.printErrors(CONF.output_format) 257 self.printErrors(CONF.output_format)
251 self.print_log_path_and_stats(start_time) 258 self.print_log_path_and_stats(start_time)
252 259
253 def print_log_path_and_stats(self, start_time): 260 def print_log_path_and_stats(self, start_time, log_path):
254 """Print the path to the log folder for this run.""" 261 """Print the path to the log folder for this run."""
255 test_log = Runner.log_path
256 run_time = time.time() - start_time 262 run_time = time.time() - start_time
257 num_fail = self.stats["unique_failures"] 263 num_fail = self.stats["unique_failures"]
258 num_err = self.stats["errors"] 264 num_err = self.stats["errors"]
@@ -267,7 +273,7 @@ class IssueTestResult(unittest.TextTestResult):
267 e=num_err, 273 e=num_err,
268 fsuff="s" * bool(num_fail - 1), 274 fsuff="s" * bool(num_fail - 1),
269 esuff="s" * bool(num_err - 1))) 275 esuff="s" * bool(num_err - 1)))
270 if test_log: 276 if log_path:
271 print(syntribos.SEP) 277 print(syntribos.SEP)
272 print(_("LOG PATH...: %s") % test_log) 278 print(_("LOG PATH...: %s") % log_path)
273 print(syntribos.SEP) 279 print(syntribos.SEP)
diff --git a/syntribos/runner.py b/syntribos/runner.py
index 045711a..4bbfaef 100644
--- a/syntribos/runner.py
+++ b/syntribos/runner.py
@@ -13,7 +13,6 @@
13# limitations under the License. 13# limitations under the License.
14import json 14import json
15import logging 15import logging
16from multiprocessing.dummy import Pool as ThreadPool
17import os 16import os
18import pkgutil 17import pkgutil
19import sys 18import sys
@@ -21,21 +20,22 @@ import threading
21import time 20import time
22import traceback 21import traceback
23import unittest 22import unittest
23from multiprocessing.dummy import Pool as ThreadPool
24 24
25from oslo_config import cfg 25from oslo_config import cfg
26from six.moves import input 26from six.moves import input
27 27
28from syntribos._i18n import _
29import syntribos.config 28import syntribos.config
30from syntribos.formatters.json_formatter import JSONFormatter
31import syntribos.result 29import syntribos.result
32import syntribos.tests as tests 30import syntribos.tests as tests
33import syntribos.tests.base 31import syntribos.tests.base
32from syntribos._i18n import _
33from syntribos.formatters.json_formatter import JSONFormatter
34from syntribos.utils import cleanup 34from syntribos.utils import cleanup
35from syntribos.utils import cli as cli 35from syntribos.utils import cli as cli
36from syntribos.utils import env as ENV 36from syntribos.utils import env as ENV
37from syntribos.utils.file_utils import ContentType
38from syntribos.utils import remotes 37from syntribos.utils import remotes
38from syntribos.utils.file_utils import ContentType
39 39
40result = None 40result = None
41user_base_dir = None 41user_base_dir = None
@@ -144,6 +144,10 @@ class Runner(object):
144 CONF(argv, default_config_files=[]) 144 CONF(argv, default_config_files=[])
145 except Exception as exc: 145 except Exception as exc:
146 syntribos.config.handle_config_exception(exc) 146 syntribos.config.handle_config_exception(exc)
147 if cls.worker:
148 raise exc
149 else:
150 sys.exit(1)
147 151
148 @classmethod 152 @classmethod
149 def setup_runtime_env(cls): 153 def setup_runtime_env(cls):
@@ -191,7 +195,7 @@ class Runner(object):
191 return meta_vars 195 return meta_vars
192 196
193 @classmethod 197 @classmethod
194 def run(cls): 198 def run(cls, argv=sys.argv[1:], worker=False):
195 """Method sets up logger and decides on Syntribos control flow 199 """Method sets up logger and decides on Syntribos control flow
196 200
197 This is the method where control flow of Syntribos is decided 201 This is the method where control flow of Syntribos is decided
@@ -199,26 +203,32 @@ class Runner(object):
199 as ```list_tests``` or ```run``` the respective method is called. 203 as ```list_tests``` or ```run``` the respective method is called.
200 """ 204 """
201 global result 205 global result
202 206 cls.worker = worker
203 cli.print_symbol()
204
205 # If we are initializing, don't look for a default config file 207 # If we are initializing, don't look for a default config file
206 if "init" in sys.argv: 208 if "init" in sys.argv:
207 cls.setup_config() 209 cls.setup_config()
208 else: 210 else:
209 cls.setup_config(use_file=True) 211 cls.setup_config(use_file=True, argv=argv)
210 try: 212 try:
211 if CONF.sub_command.name == "init": 213 if CONF.sub_command.name == "init":
214 cli.print_symbol()
212 ENV.initialize_syntribos_env() 215 ENV.initialize_syntribos_env()
213 exit(0) 216 exit(0)
214 217
215 elif CONF.sub_command.name == "list_tests": 218 elif CONF.sub_command.name == "list_tests":
219 cli.print_symbol()
216 cls.list_tests() 220 cls.list_tests()
217 exit(0) 221 exit(0)
218 222
219 elif CONF.sub_command.name == "download": 223 elif CONF.sub_command.name == "download":
224 cli.print_symbol()
220 ENV.download_wrapper() 225 ENV.download_wrapper()
221 exit(0) 226 exit(0)
227
228 elif CONF.sub_command.name == "root":
229 print(ENV.get_syntribos_root())
230 exit(0)
231
222 except AttributeError: 232 except AttributeError:
223 print( 233 print(
224 _( 234 _(
@@ -248,15 +258,19 @@ class Runner(object):
248 print(_("\nRunning Tests...:")) 258 print(_("\nRunning Tests...:"))
249 templates_dir = CONF.syntribos.templates 259 templates_dir = CONF.syntribos.templates
250 if templates_dir is None: 260 if templates_dir is None:
251 print(_("Attempting to download templates from {}").format( 261 if cls.worker:
252 CONF.remote.templates_uri)) 262 raise Exception("No templates directory was found in the "
253 templates_path = remotes.get(CONF.remote.templates_uri) 263 "config file.")
254 try: 264 else:
255 templates_dir = ContentType("r", 0)(templates_path) 265 print(_("Attempting to download templates from {}").format(
256 except IOError: 266 CONF.remote.templates_uri))
257 print(_("Not able to open `%s`; please verify path, " 267 templates_path = remotes.get(CONF.remote.templates_uri)
258 "exiting...") % templates_path) 268 try:
259 exit(1) 269 templates_dir = ContentType("r")(templates_path)
270 except IOError:
271 print(_("Not able to open `%s`; please verify path, "
272 "exiting...") % templates_path)
273 exit(1)
260 274
261 print(_("\nPress Ctrl-C to pause or exit...\n")) 275 print(_("\nPress Ctrl-C to pause or exit...\n"))
262 meta_vars = None 276 meta_vars = None
@@ -267,8 +281,15 @@ class Runner(object):
267 meta_path = os.path.dirname(file_path) 281 meta_path = os.path.dirname(file_path)
268 try: 282 try:
269 cls.meta_dir_dict[meta_path] = json.loads(file_content) 283 cls.meta_dir_dict[meta_path] = json.loads(file_content)
270 except Exception: 284 except json.decoder.JSONDecodeError:
271 print("Unable to parse %s, skipping..." % file_path) 285 _full_path = os.path.abspath(file_path)
286 print(syntribos.SEP)
287 print(
288 "\n"
289 "*** The JSON parser raised an exception when parsing "
290 "{}. Check that the file contains correctly formatted "
291 "JSON data. *** \n".format(_full_path)
292 )
272 for file_path, req_str in templates_dir: 293 for file_path, req_str in templates_dir:
273 if "meta.json" in file_path: 294 if "meta.json" in file_path:
274 continue 295 continue
@@ -299,7 +320,8 @@ class Runner(object):
299 req_str, dry_run_output, meta_vars) 320 req_str, dry_run_output, meta_vars)
300 321
301 if CONF.sub_command.name == "run": 322 if CONF.sub_command.name == "run":
302 result.print_result(cls.start_time) 323 result.print_result(cls.start_time, cls.log_path)
324 cls.result = result
303 cleanup.delete_temps() 325 cleanup.delete_temps()
304 elif CONF.sub_command.name == "dry_run": 326 elif CONF.sub_command.name == "dry_run":
305 cls.dry_run_report(dry_run_output) 327 cls.dry_run_report(dry_run_output)
@@ -337,7 +359,9 @@ class Runner(object):
337 print(_("\nRequest sucessfully generated!\n")) 359 print(_("\nRequest sucessfully generated!\n"))
338 output["successes"].append(file_path) 360 output["successes"].append(file_path)
339 361
340 test_cases = list(test_class.get_test_cases(file_path, req_str)) 362 test_cases = list(
363 test_class.get_test_cases(file_path, req_str, meta_vars)
364 )
341 if len(test_cases) > 0: 365 if len(test_cases) > 0:
342 for test in test_cases: 366 for test in test_cases:
343 if test: 367 if test:
@@ -346,7 +370,9 @@ class Runner(object):
346 @classmethod 370 @classmethod
347 def dry_run_report(cls, output): 371 def dry_run_report(cls, output):
348 """Reports the dry run through a formatter.""" 372 """Reports the dry run through a formatter."""
349 formatter_types = {"json": JSONFormatter(result)} 373 formatter_types = {
374 "json": JSONFormatter(result),
375 }
350 formatter = formatter_types[CONF.output_format] 376 formatter = formatter_types[CONF.output_format]
351 formatter.report(output) 377 formatter.report(output)
352 378
@@ -383,7 +409,7 @@ class Runner(object):
383 test_id=cli.colorize( 409 test_id=cli.colorize(
384 test_class.test_id, color="green"), 410 test_class.test_id, color="green"),
385 name=test_name.replace("_", " ").capitalize()) 411 name=test_name.replace("_", " ").capitalize())
386 if CONF.no_colorize: 412 if not CONF.colorize:
387 result_string = result_string.ljust(55) 413 result_string = result_string.ljust(55)
388 else: 414 else:
389 result_string = result_string.ljust(60) 415 result_string = result_string.ljust(60)
@@ -397,7 +423,7 @@ class Runner(object):
397 LOG.error("Error in parsing template:") 423 LOG.error("Error in parsing template:")
398 break 424 break
399 test_cases = list( 425 test_cases = list(
400 test_class.get_test_cases(file_path, req_str)) 426 test_class.get_test_cases(file_path, req_str, meta_vars))
401 total_tests = len(test_cases) 427 total_tests = len(test_cases)
402 if total_tests > 0: 428 if total_tests > 0:
403 log_string = "[{test_id}] : {name}".format( 429 log_string = "[{test_id}] : {name}".format(
diff --git a/syntribos/tests/auth/auth.py b/syntribos/tests/auth/auth.py
index 1d40a76..0d2781c 100644
--- a/syntribos/tests/auth/auth.py
+++ b/syntribos/tests/auth/auth.py
@@ -24,7 +24,7 @@ CONF = cfg.CONF
24class AuthTestCase(base.BaseTestCase): 24class AuthTestCase(base.BaseTestCase):
25 """Test for possible token misuse in keystone.""" 25 """Test for possible token misuse in keystone."""
26 test_name = "AUTH" 26 test_name = "AUTH"
27 test_type = "headers" 27 parameter_location = "headers"
28 28
29 @classmethod 29 @classmethod
30 def setUpClass(cls): 30 def setUpClass(cls):
@@ -69,7 +69,7 @@ class AuthTestCase(base.BaseTestCase):
69 ) 69 )
70 70
71 @classmethod 71 @classmethod
72 def get_test_cases(cls, filename, file_content): 72 def get_test_cases(cls, filename, file_content, meta_vars):
73 """Generates the test cases 73 """Generates the test cases
74 74
75 For this particular test, only a single test 75 For this particular test, only a single test
diff --git a/syntribos/tests/base.py b/syntribos/tests/base.py
index cff112b..d7712a3 100644
--- a/syntribos/tests/base.py
+++ b/syntribos/tests/base.py
@@ -117,7 +117,7 @@ class BaseTestCase(unittest.TestCase):
117 pass 117 pass
118 118
119 @classmethod 119 @classmethod
120 def get_test_cases(cls, filename, file_content): 120 def get_test_cases(cls, filename, file_content, meta_vars):
121 """Returns tests for given TestCase class (overwritten by children).""" 121 """Returns tests for given TestCase class (overwritten by children)."""
122 yield cls 122 yield cls
123 123
@@ -136,6 +136,7 @@ class BaseTestCase(unittest.TestCase):
136 cls.init_req = request_obj 136 cls.init_req = request_obj
137 cls.init_resp = None 137 cls.init_resp = None
138 cls.init_signals = None 138 cls.init_signals = None
139 cls.template_path = filename
139 140
140 @classmethod 141 @classmethod
141 def send_init_request(cls, filename, file_content, meta_vars): 142 def send_init_request(cls, filename, file_content, meta_vars):
@@ -189,7 +190,16 @@ class BaseTestCase(unittest.TestCase):
189 if "EXCEPTION_RAISED" in cls.test_signals: 190 if "EXCEPTION_RAISED" in cls.test_signals:
190 sig = cls.test_signals.find( 191 sig = cls.test_signals.find(
191 tags="EXCEPTION_RAISED")[0] 192 tags="EXCEPTION_RAISED")[0]
192 raise sig.data["exception"] 193 exc_name = type(sig.data["exception"]).__name__
194 if ("CONNECTION_FAIL" in sig.tags):
195 six.raise_from(FatalHTTPError(
196 "The remote target has forcibly closed the connection "
197 "with Syntribos and resulted in exception '{}'. This "
198 "could potentially mean that a fatal error was "
199 "encountered within the target application or server"
200 " itself.".format(exc_name)), sig.data["exception"])
201 else:
202 raise sig.data["exception"]
193 203
194 @classmethod 204 @classmethod
195 def tearDown(cls): 205 def tearDown(cls):
@@ -249,7 +259,8 @@ class BaseTestCase(unittest.TestCase):
249 259
250 issue.request = self.test_req 260 issue.request = self.test_req
251 issue.response = self.test_resp 261 issue.response = self.test_resp
252 262 issue.template_path = self.template_path
263 issue.parameter_location = self.parameter_location
253 issue.test_type = self.test_name 264 issue.test_type = self.test_name
254 url_components = urlparse(self.init_resp.url) 265 url_components = urlparse(self.init_resp.url)
255 issue.target = url_components.netloc 266 issue.target = url_components.netloc
@@ -261,3 +272,7 @@ class BaseTestCase(unittest.TestCase):
261 self.failures.append(issue) 272 self.failures.append(issue)
262 273
263 return issue 274 return issue
275
276
277class FatalHTTPError(Exception):
278 pass
diff --git a/syntribos/tests/debug/dry_run.py b/syntribos/tests/debug/dry_run.py
index d93b0d3..03ccb75 100644
--- a/syntribos/tests/debug/dry_run.py
+++ b/syntribos/tests/debug/dry_run.py
@@ -19,7 +19,7 @@ class DryRunTestCase(base.BaseTestCase):
19 """Debug dry run test to run no logic and return no results.""" 19 """Debug dry run test to run no logic and return no results."""
20 20
21 test_name = "DEBUG_DRY_RUN" 21 test_name = "DEBUG_DRY_RUN"
22 test_type = "debug" 22 parameter_location = "debug"
23 23
24 def test_case(self): 24 def test_case(self):
25 pass 25 pass
diff --git a/syntribos/tests/fuzz/base_fuzz.py b/syntribos/tests/fuzz/base_fuzz.py
index 37bc30c..f3f65d6 100644
--- a/syntribos/tests/fuzz/base_fuzz.py
+++ b/syntribos/tests/fuzz/base_fuzz.py
@@ -49,8 +49,8 @@ class BaseFuzzTestCase(base.BaseTestCase):
49 path = cls.data_key 49 path = cls.data_key
50 else: 50 else:
51 path = os.path.join(payloads, file_name or cls.data_key) 51 path = os.path.join(payloads, file_name or cls.data_key)
52 with open(path, "rb") as fp: 52 with open(path, "r") as fp:
53 return str(fp.read()).splitlines() 53 return fp.read().splitlines()
54 except (IOError, AttributeError, TypeError) as e: 54 except (IOError, AttributeError, TypeError) as e:
55 LOG.error("Exception raised: {}".format(e)) 55 LOG.error("Exception raised: {}".format(e))
56 print("\nPayload file for test '{}' not readable, " 56 print("\nPayload file for test '{}' not readable, "
@@ -124,7 +124,7 @@ class BaseFuzzTestCase(base.BaseTestCase):
124 self.run_default_checks() 124 self.run_default_checks()
125 125
126 @classmethod 126 @classmethod
127 def get_test_cases(cls, filename, file_content): 127 def get_test_cases(cls, filename, file_content, meta_vars):
128 """Generates new TestCases for each fuzz string 128 """Generates new TestCases for each fuzz string
129 129
130 For each string returned by cls._get_strings(), yield a TestCase class 130 For each string returned by cls._get_strings(), yield a TestCase class
@@ -143,7 +143,8 @@ class BaseFuzzTestCase(base.BaseTestCase):
143 filename=filename, test_name=cls.test_name) 143 filename=filename, test_name=cls.test_name)
144 144
145 fr = syntribos.tests.fuzz.datagen.fuzz_request( 145 fr = syntribos.tests.fuzz.datagen.fuzz_request(
146 cls.init_req, cls._get_strings(), cls.test_type, prefix_name) 146 cls.init_req, cls._get_strings(), cls.parameter_location,
147 prefix_name)
147 for fuzz_name, request, fuzz_string, param_path in fr: 148 for fuzz_name, request, fuzz_string, param_path in fr:
148 yield cls.extend_class(fuzz_name, fuzz_string, param_path, 149 yield cls.extend_class(fuzz_name, fuzz_string, param_path,
149 {"request": request}) 150 {"request": request})
@@ -195,6 +196,8 @@ class BaseFuzzTestCase(base.BaseTestCase):
195 196
196 issue.request = self.test_req 197 issue.request = self.test_req
197 issue.response = self.test_resp 198 issue.response = self.test_resp
199 issue.template_path = self.template_path
200
198 issue.test_type = self.test_name 201 issue.test_type = self.test_name
199 url_components = urlparse(self.prepared_init_req.url) 202 url_components = urlparse(self.prepared_init_req.url)
200 issue.target = url_components.netloc 203 issue.target = url_components.netloc
@@ -209,7 +212,7 @@ class BaseFuzzTestCase(base.BaseTestCase):
209 212
210 issue.impacted_parameter = ImpactedParameter( 213 issue.impacted_parameter = ImpactedParameter(
211 method=issue.request.method, 214 method=issue.request.method,
212 location=self.test_type, 215 location=self.parameter_location,
213 name=self.param_path, 216 name=self.param_path,
214 value=self.fuzz_string) 217 value=self.fuzz_string)
215 218
diff --git a/syntribos/tests/fuzz/buffer_overflow.py b/syntribos/tests/fuzz/buffer_overflow.py
index d44deb4..2645306 100644
--- a/syntribos/tests/fuzz/buffer_overflow.py
+++ b/syntribos/tests/fuzz/buffer_overflow.py
@@ -22,7 +22,7 @@ class BufferOverflowBody(base_fuzz.BaseFuzzTestCase):
22 """Test for buffer overflow vulnerabilities in HTTP body.""" 22 """Test for buffer overflow vulnerabilities in HTTP body."""
23 23
24 test_name = "BUFFER_OVERFLOW_BODY" 24 test_name = "BUFFER_OVERFLOW_BODY"
25 test_type = "data" 25 parameter_location = "data"
26 failure_keys = [ 26 failure_keys = [
27 '*** stack smashing detected ***:', 27 '*** stack smashing detected ***:',
28 'Backtrace:', 28 'Backtrace:',
@@ -70,19 +70,19 @@ class BufferOverflowParams(BufferOverflowBody):
70 """Test for buffer overflow vulnerabilities in HTTP params.""" 70 """Test for buffer overflow vulnerabilities in HTTP params."""
71 71
72 test_name = "BUFFER_OVERFLOW_PARAMS" 72 test_name = "BUFFER_OVERFLOW_PARAMS"
73 test_type = "params" 73 parameter_location = "params"
74 74
75 75
76class BufferOverflowHeaders(BufferOverflowBody): 76class BufferOverflowHeaders(BufferOverflowBody):
77 """Test for buffer overflow vulnerabilities in HTTP header.""" 77 """Test for buffer overflow vulnerabilities in HTTP header."""
78 78
79 test_name = "BUFFER_OVERFLOW_HEADERS" 79 test_name = "BUFFER_OVERFLOW_HEADERS"
80 test_type = "headers" 80 parameter_location = "headers"
81 81
82 82
83class BufferOverflowURL(BufferOverflowBody): 83class BufferOverflowURL(BufferOverflowBody):
84 """Test for buffer overflow vulnerabilities in HTTP URL.""" 84 """Test for buffer overflow vulnerabilities in HTTP URL."""
85 85
86 test_name = "BUFFER_OVERFLOW_URL" 86 test_name = "BUFFER_OVERFLOW_URL"
87 test_type = "url" 87 parameter_location = "url"
88 url_var = "FUZZ" 88 url_var = "FUZZ"
diff --git a/syntribos/tests/fuzz/command_injection.py b/syntribos/tests/fuzz/command_injection.py
index 1f5253b..fe999a0 100644
--- a/syntribos/tests/fuzz/command_injection.py
+++ b/syntribos/tests/fuzz/command_injection.py
@@ -23,7 +23,7 @@ class CommandInjectionBody(base_fuzz.BaseFuzzTestCase):
23 """Test for command injection vulnerabilities in HTTP body.""" 23 """Test for command injection vulnerabilities in HTTP body."""
24 24
25 test_name = "COMMAND_INJECTION_BODY" 25 test_name = "COMMAND_INJECTION_BODY"
26 test_type = "data" 26 parameter_location = "data"
27 data_key = "command_injection.txt" 27 data_key = "command_injection.txt"
28 failure_keys = [ 28 failure_keys = [
29 'uid=', 29 'uid=',
@@ -63,19 +63,19 @@ class CommandInjectionParams(CommandInjectionBody):
63 """Test for command injection vulnerabilities in HTTP params.""" 63 """Test for command injection vulnerabilities in HTTP params."""
64 64
65 test_name = "COMMAND_INJECTION_PARAMS" 65 test_name = "COMMAND_INJECTION_PARAMS"
66 test_type = "params" 66 parameter_location = "params"
67 67
68 68
69class CommandInjectionHeaders(CommandInjectionBody): 69class CommandInjectionHeaders(CommandInjectionBody):
70 """Test for command injection vulnerabilities in HTTP header.""" 70 """Test for command injection vulnerabilities in HTTP header."""
71 71
72 test_name = "COMMAND_INJECTION_HEADERS" 72 test_name = "COMMAND_INJECTION_HEADERS"
73 test_type = "headers" 73 parameter_location = "headers"
74 74
75 75
76class CommandInjectionURL(CommandInjectionBody): 76class CommandInjectionURL(CommandInjectionBody):
77 """Test for command injection vulnerabilities in HTTP URL.""" 77 """Test for command injection vulnerabilities in HTTP URL."""
78 78
79 test_name = "COMMAND_INJECTION_URL" 79 test_name = "COMMAND_INJECTION_URL"
80 test_type = "url" 80 parameter_location = "url"
81 url_var = "FUZZ" 81 url_var = "FUZZ"
diff --git a/syntribos/tests/fuzz/integer_overflow.py b/syntribos/tests/fuzz/integer_overflow.py
index d3df657..bf74bca 100644
--- a/syntribos/tests/fuzz/integer_overflow.py
+++ b/syntribos/tests/fuzz/integer_overflow.py
@@ -21,7 +21,7 @@ class IntOverflowBody(base_fuzz.BaseFuzzTestCase):
21 """Test for integer overflow vulnerabilities in HTTP body.""" 21 """Test for integer overflow vulnerabilities in HTTP body."""
22 22
23 test_name = "INTEGER_OVERFLOW_BODY" 23 test_name = "INTEGER_OVERFLOW_BODY"
24 test_type = "data" 24 parameter_location = "data"
25 data_key = "integer-overflow.txt" 25 data_key = "integer-overflow.txt"
26 26
27 def test_case(self): 27 def test_case(self):
@@ -41,19 +41,19 @@ class IntOverflowParams(IntOverflowBody):
41 """Test for integer overflow vulnerabilities in HTTP params.""" 41 """Test for integer overflow vulnerabilities in HTTP params."""
42 42
43 test_name = "INTEGER_OVERFLOW_PARAMS" 43 test_name = "INTEGER_OVERFLOW_PARAMS"
44 test_type = "params" 44 parameter_location = "params"
45 45
46 46
47class IntOverflowHeaders(IntOverflowBody): 47class IntOverflowHeaders(IntOverflowBody):
48 """Test for integer overflow vulnerabilities in HTTP header.""" 48 """Test for integer overflow vulnerabilities in HTTP header."""
49 49
50 test_name = "INTEGER_OVERFLOW_HEADERS" 50 test_name = "INTEGER_OVERFLOW_HEADERS"
51 test_type = "headers" 51 parameter_location = "headers"
52 52
53 53
54class IntOverflowURL(IntOverflowBody): 54class IntOverflowURL(IntOverflowBody):
55 """Test for integer overflow vulnerabilities in HTTP URL.""" 55 """Test for integer overflow vulnerabilities in HTTP URL."""
56 56
57 test_name = "INTEGER_OVERFLOW_URL" 57 test_name = "INTEGER_OVERFLOW_URL"
58 test_type = "url" 58 parameter_location = "url"
59 url_var = "FUZZ" 59 url_var = "FUZZ"
diff --git a/syntribos/tests/fuzz/json_depth_overflow.py b/syntribos/tests/fuzz/json_depth_overflow.py
index 2e7f168..ba9b3e7 100644
--- a/syntribos/tests/fuzz/json_depth_overflow.py
+++ b/syntribos/tests/fuzz/json_depth_overflow.py
@@ -22,7 +22,7 @@ class JSONDepthOverflowBody(base_fuzz.BaseFuzzTestCase):
22 """Test for json depth overflow in HTTP body.""" 22 """Test for json depth overflow in HTTP body."""
23 23
24 test_name = "JSON_DEPTH_OVERFLOW_BODY" 24 test_name = "JSON_DEPTH_OVERFLOW_BODY"
25 test_type = "data" 25 parameter_location = "data"
26 failure_keys = [ 26 failure_keys = [
27 "maximum recursion depth exceeded", 27 "maximum recursion depth exceeded",
28 "RuntimeError", 28 "RuntimeError",
diff --git a/syntribos/tests/fuzz/ldap.py b/syntribos/tests/fuzz/ldap.py
index 2d2800c..1c8c045 100644
--- a/syntribos/tests/fuzz/ldap.py
+++ b/syntribos/tests/fuzz/ldap.py
@@ -18,7 +18,7 @@ class LDAPInjectionBody(base_fuzz.BaseFuzzTestCase):
18 """Test for LDAP injection vulnerabilities in HTTP body.""" 18 """Test for LDAP injection vulnerabilities in HTTP body."""
19 19
20 test_name = "LDAP_INJECTION_BODY" 20 test_name = "LDAP_INJECTION_BODY"
21 test_type = "data" 21 parameter_location = "data"
22 data_key = "ldap.txt" 22 data_key = "ldap.txt"
23 23
24 24
@@ -26,19 +26,19 @@ class LDAPInjectionParams(LDAPInjectionBody):
26 """Test for LDAP injection vulnerabilities in HTTP params.""" 26 """Test for LDAP injection vulnerabilities in HTTP params."""
27 27
28 test_name = "LDAP_INJECTION_PARAMS" 28 test_name = "LDAP_INJECTION_PARAMS"
29 test_type = "params" 29 parameter_location = "params"
30 30
31 31
32class LDAPInjectionHeaders(LDAPInjectionBody): 32class LDAPInjectionHeaders(LDAPInjectionBody):
33 """Test for LDAP injection vulnerabilities in HTTP header.""" 33 """Test for LDAP injection vulnerabilities in HTTP header."""
34 34
35 test_name = "LDAP_INJECTION_HEADERS" 35 test_name = "LDAP_INJECTION_HEADERS"
36 test_type = "headers" 36 parameter_location = "headers"
37 37
38 38
39class LDAPInjectionURL(LDAPInjectionBody): 39class LDAPInjectionURL(LDAPInjectionBody):
40 """Test for LDAP injection vulnerabilities in HTTP URL.""" 40 """Test for LDAP injection vulnerabilities in HTTP URL."""
41 41
42 test_name = "LDAP_INJECTION_URL" 42 test_name = "LDAP_INJECTION_URL"
43 test_type = "url" 43 parameter_location = "url"
44 url_var = "FUZZ" 44 url_var = "FUZZ"
diff --git a/syntribos/tests/fuzz/redos.py b/syntribos/tests/fuzz/redos.py
index 9c983c1..26d1626 100644
--- a/syntribos/tests/fuzz/redos.py
+++ b/syntribos/tests/fuzz/redos.py
@@ -20,7 +20,7 @@ class ReDosBody(base_fuzz.BaseFuzzTestCase):
20 """Test for Regex DoS vulnerabilities in HTTP body.""" 20 """Test for Regex DoS vulnerabilities in HTTP body."""
21 21
22 test_name = "REDOS_BODY" 22 test_name = "REDOS_BODY"
23 test_type = "data" 23 parameter_location = "data"
24 data_key = "redos.txt" 24 data_key = "redos.txt"
25 25
26 def test_case(self): 26 def test_case(self):
@@ -41,19 +41,19 @@ class ReDosParams(ReDosBody):
41 """Test for Regex DoS vulnerabilities in HTTP params.""" 41 """Test for Regex DoS vulnerabilities in HTTP params."""
42 42
43 test_name = "REDOS_PARAMS" 43 test_name = "REDOS_PARAMS"
44 test_type = "params" 44 parameter_location = "params"
45 45
46 46
47class ReDosHeaders(ReDosBody): 47class ReDosHeaders(ReDosBody):
48 """Test for Regex DoS vulnerabilities in HTTP header.""" 48 """Test for Regex DoS vulnerabilities in HTTP header."""
49 49
50 test_name = "REDOS_HEADERS" 50 test_name = "REDOS_HEADERS"
51 test_type = "headers" 51 parameter_location = "headers"
52 52
53 53
54class ReDosURL(ReDosBody): 54class ReDosURL(ReDosBody):
55 """Test for Regex DoS vulnerabilities in HTTP URL.""" 55 """Test for Regex DoS vulnerabilities in HTTP URL."""
56 56
57 test_name = "REDOS_URL" 57 test_name = "REDOS_URL"
58 test_type = "url" 58 parameter_location = "url"
59 url_var = "FUZZ" 59 url_var = "FUZZ"
diff --git a/syntribos/tests/fuzz/sql.py b/syntribos/tests/fuzz/sql.py
index 12f475b..c7d2f7e 100644
--- a/syntribos/tests/fuzz/sql.py
+++ b/syntribos/tests/fuzz/sql.py
@@ -22,7 +22,7 @@ class SQLInjectionBody(base_fuzz.BaseFuzzTestCase):
22 """Test for SQL injection vulnerabilities in HTTP body.""" 22 """Test for SQL injection vulnerabilities in HTTP body."""
23 23
24 test_name = "SQL_INJECTION_BODY" 24 test_name = "SQL_INJECTION_BODY"
25 test_type = "data" 25 parameter_location = "data"
26 data_key = "sql-injection.txt" 26 data_key = "sql-injection.txt"
27 failure_keys = [ 27 failure_keys = [
28 "SQL syntax", "mysql", "MySqlException (0x", "valid MySQL result", 28 "SQL syntax", "mysql", "MySqlException (0x", "valid MySQL result",
@@ -65,19 +65,19 @@ class SQLInjectionParams(SQLInjectionBody):
65 """Test for SQL injection vulnerabilities in HTTP params.""" 65 """Test for SQL injection vulnerabilities in HTTP params."""
66 66
67 test_name = "SQL_INJECTION_PARAMS" 67 test_name = "SQL_INJECTION_PARAMS"
68 test_type = "params" 68 parameter_location = "params"
69 69
70 70
71class SQLInjectionHeaders(SQLInjectionBody): 71class SQLInjectionHeaders(SQLInjectionBody):
72 """Test for SQL injection vulnerabilities in HTTP header.""" 72 """Test for SQL injection vulnerabilities in HTTP header."""
73 73
74 test_name = "SQL_INJECTION_HEADERS" 74 test_name = "SQL_INJECTION_HEADERS"
75 test_type = "headers" 75 parameter_location = "headers"
76 76
77 77
78class SQLInjectionURL(SQLInjectionBody): 78class SQLInjectionURL(SQLInjectionBody):
79 """Test for SQL injection vulnerabilities in HTTP URL.""" 79 """Test for SQL injection vulnerabilities in HTTP URL."""
80 80
81 test_name = "SQL_INJECTION_URL" 81 test_name = "SQL_INJECTION_URL"
82 test_type = "url" 82 parameter_location = "url"
83 url_var = "FUZZ" 83 url_var = "FUZZ"
diff --git a/syntribos/tests/fuzz/string_validation.py b/syntribos/tests/fuzz/string_validation.py
index 4c8ddf6..0ad5dc1 100644
--- a/syntribos/tests/fuzz/string_validation.py
+++ b/syntribos/tests/fuzz/string_validation.py
@@ -19,7 +19,7 @@ class StringValidationBody(base_fuzz.BaseFuzzTestCase):
19 """Test for string validation vulnerabilities in HTTP body.""" 19 """Test for string validation vulnerabilities in HTTP body."""
20 20
21 test_name = "STRING_VALIDATION_BODY" 21 test_name = "STRING_VALIDATION_BODY"
22 test_type = "data" 22 parameter_location = "data"
23 data_key = "string_validation.txt" 23 data_key = "string_validation.txt"
24 24
25 25
@@ -27,19 +27,19 @@ class StringValidationParams(StringValidationBody):
27 """Test for string validation vulnerabilities in HTTP params.""" 27 """Test for string validation vulnerabilities in HTTP params."""
28 28
29 test_name = "STRING_VALIDATION_PARAMS" 29 test_name = "STRING_VALIDATION_PARAMS"
30 test_type = "params" 30 parameter_location = "params"
31 31
32 32
33class StringValidationHeaders(StringValidationBody): 33class StringValidationHeaders(StringValidationBody):
34 """Test for string validation vulnerabilities in HTTP header.""" 34 """Test for string validation vulnerabilities in HTTP header."""
35 35
36 test_name = "STRING_VALIDATION_HEADERS" 36 test_name = "STRING_VALIDATION_HEADERS"
37 test_type = "headers" 37 parameter_location = "headers"
38 38
39 39
40class StringValidationURL(StringValidationBody): 40class StringValidationURL(StringValidationBody):
41 """Test for string validation vulnerabilities in HTTP URL.""" 41 """Test for string validation vulnerabilities in HTTP URL."""
42 42
43 test_name = "STRING_VALIDATION_URL" 43 test_name = "STRING_VALIDATION_URL"
44 test_type = "url" 44 parameter_location = "url"
45 url_var = "FUZZ" 45 url_var = "FUZZ"
diff --git a/syntribos/tests/fuzz/user_defined.py b/syntribos/tests/fuzz/user_defined.py
index 1b71fb7..f3ec11f 100644
--- a/syntribos/tests/fuzz/user_defined.py
+++ b/syntribos/tests/fuzz/user_defined.py
@@ -41,7 +41,7 @@ class UserDefinedVulnBody(base_fuzz.BaseFuzzTestCase):
41 """Test for user defined vulnerabilities in HTTP body.""" 41 """Test for user defined vulnerabilities in HTTP body."""
42 42
43 test_name = "USER_DEFINED_VULN_BODY" 43 test_name = "USER_DEFINED_VULN_BODY"
44 test_type = "data" 44 parameter_location = "data"
45 user_defined_config() 45 user_defined_config()
46 data_key = CONF.user_defined.payload 46 data_key = CONF.user_defined.payload
47 failure_keys = CONF.user_defined.failure_keys 47 failure_keys = CONF.user_defined.failure_keys
@@ -74,7 +74,7 @@ class UserDefinedVulnBody(base_fuzz.BaseFuzzTestCase):
74 " provided strings."))) 74 " provided strings.")))
75 75
76 @classmethod 76 @classmethod
77 def get_test_cases(cls, filename, file_content): 77 def get_test_cases(cls, filename, file_content, meta_vars):
78 """Generates test cases if a payload file is provided.""" 78 """Generates test cases if a payload file is provided."""
79 conf_var = CONF.user_defined.payload 79 conf_var = CONF.user_defined.payload
80 if conf_var is None or not os.path.isfile(conf_var): 80 if conf_var is None or not os.path.isfile(conf_var):
@@ -85,7 +85,8 @@ class UserDefinedVulnBody(base_fuzz.BaseFuzzTestCase):
85 test_name=cls.test_name, 85 test_name=cls.test_name,
86 fuzz_file=cls.data_key) 86 fuzz_file=cls.data_key)
87 fr = syntribos.tests.fuzz.datagen.fuzz_request( 87 fr = syntribos.tests.fuzz.datagen.fuzz_request(
88 cls.init_req, cls._get_strings(), cls.test_type, prefix_name) 88 cls.init_req, cls._get_strings(), cls.parameter_location,
89 prefix_name)
89 for fuzz_name, request, fuzz_string, param_path in fr: 90 for fuzz_name, request, fuzz_string, param_path in fr:
90 yield cls.extend_class(fuzz_name, fuzz_string, param_path, 91 yield cls.extend_class(fuzz_name, fuzz_string, param_path,
91 {"request": request}) 92 {"request": request})
@@ -95,19 +96,19 @@ class UserDefinedVulnParams(UserDefinedVulnBody):
95 """Test for user defined vulnerabilities in HTTP params.""" 96 """Test for user defined vulnerabilities in HTTP params."""
96 97
97 test_name = "USER_DEFINED_VULN_PARAMS" 98 test_name = "USER_DEFINED_VULN_PARAMS"
98 test_type = "params" 99 parameter_location = "params"
99 100
100 101
101class UserDefinedVulnHeaders(UserDefinedVulnBody): 102class UserDefinedVulnHeaders(UserDefinedVulnBody):
102 """Test for user defined vulnerabilities in HTTP header.""" 103 """Test for user defined vulnerabilities in HTTP header."""
103 104
104 test_name = "USER_DEFINED_VULN_HEADERS" 105 test_name = "USER_DEFINED_VULN_HEADERS"
105 test_type = "headers" 106 parameter_location = "headers"
106 107
107 108
108class UserDefinedVulnURL(UserDefinedVulnBody): 109class UserDefinedVulnURL(UserDefinedVulnBody):
109 """Test for user defined vulnerabilities in HTTP URL.""" 110 """Test for user defined vulnerabilities in HTTP URL."""
110 111
111 test_name = "USER_DEFINED_VULN_URL" 112 test_name = "USER_DEFINED_VULN_URL"
112 test_type = "url" 113 parameter_location = "url"
113 url_var = "FUZZ" 114 url_var = "FUZZ"
diff --git a/syntribos/tests/fuzz/xml_external.py b/syntribos/tests/fuzz/xml_external.py
index 8786a17..881f8a8 100644
--- a/syntribos/tests/fuzz/xml_external.py
+++ b/syntribos/tests/fuzz/xml_external.py
@@ -27,7 +27,7 @@ class XMLExternalEntityBody(base_fuzz.BaseFuzzTestCase):
27 """Test for XML-external-entity injection vulnerabilities in HTTP body.""" 27 """Test for XML-external-entity injection vulnerabilities in HTTP body."""
28 28
29 test_name = "XML_EXTERNAL_ENTITY_BODY" 29 test_name = "XML_EXTERNAL_ENTITY_BODY"
30 test_type = "data" 30 parameter_location = "data"
31 dtds_data_key = "xml-external.txt" 31 dtds_data_key = "xml-external.txt"
32 failure_keys = [ 32 failure_keys = [
33 'root:', 33 'root:',
@@ -41,7 +41,7 @@ class XMLExternalEntityBody(base_fuzz.BaseFuzzTestCase):
41 'partition'] 41 'partition']
42 42
43 @classmethod 43 @classmethod
44 def get_test_cases(cls, filename, file_content): 44 def get_test_cases(cls, filename, file_content, meta_vars):
45 """Makes sure API call supports XML 45 """Makes sure API call supports XML
46 46
47 Overrides parent fuzz test generation, if API method does not support 47 Overrides parent fuzz test generation, if API method does not support
@@ -49,7 +49,7 @@ class XMLExternalEntityBody(base_fuzz.BaseFuzzTestCase):
49 """ 49 """
50 # Send request for different content-types 50 # Send request for different content-types
51 request_obj = parser.create_request( 51 request_obj = parser.create_request(
52 file_content, CONF.syntribos.endpoint) 52 file_content, CONF.syntribos.endpoint, meta_vars)
53 53
54 prepared_copy = request_obj.get_prepared_copy() 54 prepared_copy = request_obj.get_prepared_copy()
55 prepared_copy.headers['content-type'] = "application/json" 55 prepared_copy.headers['content-type'] = "application/json"
@@ -75,7 +75,7 @@ class XMLExternalEntityBody(base_fuzz.BaseFuzzTestCase):
75 filename=filename, test_name=cls.test_name, 75 filename=filename, test_name=cls.test_name,
76 fuzz_file=cls.dtds_data_key, d_index=d_num) 76 fuzz_file=cls.dtds_data_key, d_index=d_num)
77 fr = syntribos.tests.fuzz.datagen.fuzz_request( 77 fr = syntribos.tests.fuzz.datagen.fuzz_request(
78 request_obj, ["&xxe;"], cls.test_type, prefix_name) 78 request_obj, ["&xxe;"], cls.parameter_location, prefix_name)
79 for fuzz_name, request, fuzz_string, param_path in fr: 79 for fuzz_name, request, fuzz_string, param_path in fr:
80 request.data = "{0}\n{1}".format(dtd, request.data) 80 request.data = "{0}\n{1}".format(dtd, request.data)
81 yield cls.extend_class(fuzz_name, fuzz_string, param_path, 81 yield cls.extend_class(fuzz_name, fuzz_string, param_path,
diff --git a/syntribos/tests/fuzz/xss.py b/syntribos/tests/fuzz/xss.py
index b210d9f..b6673e6 100644
--- a/syntribos/tests/fuzz/xss.py
+++ b/syntribos/tests/fuzz/xss.py
@@ -20,7 +20,7 @@ class XSSBody(base_fuzz.BaseFuzzTestCase):
20 """Test for cross-site-scripting vulnerabilities in HTTP body.""" 20 """Test for cross-site-scripting vulnerabilities in HTTP body."""
21 21
22 test_name = "XSS_BODY" 22 test_name = "XSS_BODY"
23 test_type = "data" 23 parameter_location = "data"
24 data_key = "xss.txt" 24 data_key = "xss.txt"
25 25
26 def test_case(self): 26 def test_case(self):
diff --git a/syntribos/tests/headers/cors.py b/syntribos/tests/headers/cors.py
index 934983f..60edd76 100644
--- a/syntribos/tests/headers/cors.py
+++ b/syntribos/tests/headers/cors.py
@@ -29,19 +29,19 @@ class CorsHeader(base.BaseTestCase):
29 """Test for CORS wild character vulnerabilities in HTTP header.""" 29 """Test for CORS wild character vulnerabilities in HTTP header."""
30 30
31 test_name = "CORS_WILDCARD_HEADERS" 31 test_name = "CORS_WILDCARD_HEADERS"
32 test_type = "headers" 32 parameter_location = "headers"
33 client = client() 33 client = client()
34 failures = [] 34 failures = []
35 35
36 @classmethod 36 @classmethod
37 def get_test_cases(cls, filename, file_content): 37 def get_test_cases(cls, filename, file_content, meta_vars):
38
39 request_obj = parser.create_request( 38 request_obj = parser.create_request(
40 file_content, CONF.syntribos.endpoint 39 file_content, CONF.syntribos.endpoint, meta_vars
41 ) 40 )
42 prepared_copy = request_obj.get_prepared_copy() 41 prepared_copy = request_obj.get_prepared_copy()
43 cls.test_resp, cls.test_signals = cls.client.send_request( 42 cls.test_resp, cls.test_signals = cls.client.send_request(
44 prepared_copy) 43 prepared_copy)
44 cls.test_req = request_obj.get_prepared_copy()
45 yield cls 45 yield cls
46 46
47 def test_case(self): 47 def test_case(self):
diff --git a/syntribos/tests/headers/xst.py b/syntribos/tests/headers/xst.py
index 3017c0e..c57e077 100644
--- a/syntribos/tests/headers/xst.py
+++ b/syntribos/tests/headers/xst.py
@@ -40,15 +40,15 @@ class XstHeader(base.BaseTestCase):
40 """ 40 """
41 41
42 test_name = "XST_HEADERS" 42 test_name = "XST_HEADERS"
43 test_type = "headers" 43 parameter_location = "headers"
44 client = client() 44 client = client()
45 failures = [] 45 failures = []
46 46
47 @classmethod 47 @classmethod
48 def get_test_cases(cls, filename, file_content): 48 def get_test_cases(cls, filename, file_content, meta_vars):
49 xst_header = {"TRACE_THIS": "XST_Vuln"} 49 xst_header = {"TRACE_THIS": "XST_Vuln"}
50 request_obj = parser.create_request( 50 request_obj = parser.create_request(
51 file_content, CONF.syntribos.endpoint, meta_vars=None) 51 file_content, CONF.syntribos.endpoint, meta_vars)
52 prepared_copy = request_obj.get_prepared_copy() 52 prepared_copy = request_obj.get_prepared_copy()
53 prepared_copy.method = "TRACE" 53 prepared_copy.method = "TRACE"
54 prepared_copy.headers.update(xst_header) 54 prepared_copy.headers.update(xst_header)
diff --git a/syntribos/tests/transport_layer/ssl.py b/syntribos/tests/transport_layer/ssl.py
index 354e77d..da20d9b 100644
--- a/syntribos/tests/transport_layer/ssl.py
+++ b/syntribos/tests/transport_layer/ssl.py
@@ -22,7 +22,7 @@ class SSLTestCase(base.BaseTestCase):
22 """Test if response body contains non-https links.""" 22 """Test if response body contains non-https links."""
23 23
24 test_name = "SSL_ENDPOINT_BODY" 24 test_name = "SSL_ENDPOINT_BODY"
25 test_type = "body" 25 parameter_location = "data"
26 26
27 def test_case(self): 27 def test_case(self):
28 self.init_signals.register(https_check(self)) 28 self.init_signals.register(https_check(self))
diff --git a/syntribos/utils/cli.py b/syntribos/utils/cli.py
index 5022bf3..a768ad7 100644
--- a/syntribos/utils/cli.py
+++ b/syntribos/utils/cli.py
@@ -11,8 +11,8 @@
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and 12# See the License for the specific language governing permissions and
13# limitations under the License. 13# limitations under the License.
14from __future__ import division 14
15from __future__ import unicode_literals 15
16from math import ceil 16from math import ceil
17import sys 17import sys
18 18
@@ -39,7 +39,7 @@ def colorize(string, color="nocolor"):
39 colors = dict(list(zip(color_names, list(range(31, 35))))) 39 colors = dict(list(zip(color_names, list(range(31, 35)))))
40 colors["nocolor"] = 0 # No Color 40 colors["nocolor"] = 0 # No Color
41 41
42 if CONF.no_colorize: 42 if not CONF.colorize:
43 return string 43 return string
44 return "\033[0;{color}m{string}\033[0;m".format(string=string, 44 return "\033[0;{color}m{string}\033[0;m".format(string=string,
45 color=colors.setdefault( 45 color=colors.setdefault(
@@ -95,10 +95,11 @@ class ProgressBar(object):
95 95
96 :returns: formatted progress bar string 96 :returns: formatted progress bar string
97 """ 97 """
98 bar_width = int(ceil(self.present_level / self.total_len * self.width)) 98 bar_width = int(
99 ceil(self.present_level / float(self.total_len) * self.width))
99 empty_char = self.empty_char * (self.width - bar_width) 100 empty_char = self.empty_char * (self.width - bar_width)
100 fill_char = self.fill_char * bar_width 101 fill_char = self.fill_char * bar_width
101 percentage = int(self.present_level / self.total_len * 100) 102 percentage = int(self.present_level / float(self.total_len) * 100)
102 return "{message}\t\t|{fill_char}{empty_char}| {percentage} %".format( 103 return "{message}\t\t|{fill_char}{empty_char}| {percentage} %".format(
103 message=self.message, fill_char=fill_char, 104 message=self.message, fill_char=fill_char,
104 empty_char=empty_char, percentage=percentage) 105 empty_char=empty_char, percentage=percentage)
diff --git a/syntribos/utils/config_fixture.py b/syntribos/utils/config_fixture.py
index 8163a2d..8a70d15 100644
--- a/syntribos/utils/config_fixture.py
+++ b/syntribos/utils/config_fixture.py
@@ -64,7 +64,7 @@ class ConfFixture(config_fixture.Config):
64 """config values for CLI options(default group).""" 64 """config values for CLI options(default group)."""
65 # TODO(unrahul): Add mock file path for outfile 65 # TODO(unrahul): Add mock file path for outfile
66 self.conf.set_default("test_types", [""]) 66 self.conf.set_default("test_types", [""])
67 self.conf.set_default("no_colorize", True) 67 self.conf.set_default("colorize", False)
68 self.conf.set_default("output_format", "json") 68 self.conf.set_default("output_format", "json")
69 self.conf.set_default("min_severity", "LOW") 69 self.conf.set_default("min_severity", "LOW")
70 self.conf.set_default("min_confidence", "LOW") 70 self.conf.set_default("min_confidence", "LOW")
diff --git a/syntribos/utils/env.py b/syntribos/utils/env.py
index 44e2c6a..f06540e 100644
--- a/syntribos/utils/env.py
+++ b/syntribos/utils/env.py
@@ -71,10 +71,12 @@ def get_venv_root():
71def get_syntribos_root(): 71def get_syntribos_root():
72 """This determines the proper path to use as syntribos' root directory.""" 72 """This determines the proper path to use as syntribos' root directory."""
73 path = "" 73 path = ""
74 custom_root = CONF.syntribos.custom_root 74 try:
75 75 custom_root = CONF.syntribos.custom_root
76 if custom_root: 76 if custom_root:
77 return expand_path(custom_root) 77 return expand_path(custom_root)
78 except Exception:
79 pass
78 80
79 home_root = get_user_home_root() 81 home_root = get_user_home_root()
80 82
@@ -156,10 +158,10 @@ def create_conf_file(created_folders=None, remote_path=None):
156 "# syntribos barebones configuration file\n" 158 "# syntribos barebones configuration file\n"
157 "# You should update this with your desired options!\n" 159 "# You should update this with your desired options!\n"
158 "[syntribos]\n" 160 "[syntribos]\n"
159 "endpoint=http://127.0.0.1:80\n" 161 "endpoint=http://127.0.0.1:8080\n"
160 "payloads={payloads}\n" 162 "payloads={payloads}\n"
161 "templates={templates}\n" 163 "templates={templates}\n"
162 "{custom_root}\n" 164 "{custom_root}\n\n"
163 "[logging]\n" 165 "[logging]\n"
164 "log_dir={logs}\n" 166 "log_dir={logs}\n"
165 ).format( 167 ).format(
diff --git a/syntribos/utils/file_utils.py b/syntribos/utils/file_utils.py
index da5c22c..2383cea 100644
--- a/syntribos/utils/file_utils.py
+++ b/syntribos/utils/file_utils.py
@@ -54,12 +54,16 @@ class ContentType(ExistingPathType):
54 def _fetch_from_dir(self, string): 54 def _fetch_from_dir(self, string):
55 for path, _, files in os.walk(string): 55 for path, _, files in os.walk(string):
56 for file_ in files: 56 for file_ in files:
57 file_path = os.path.join(path, file_) 57 try:
58 if path is not self._root: 58 file_path = os.path.join(path, file_)
59 subdir = os.path.relpath(path, self._root) 59 if path is not self._root:
60 yield self._fetch_from_file(file_path, subdir) 60 subdir = os.path.relpath(path, self._root)
61 else: 61 yield self._fetch_from_file(file_path, subdir)
62 yield self._fetch_from_file(file_path) 62
63 else:
64 yield self._fetch_from_file(file_path)
65 except Exception:
66 print("Skipped %s" % string)
63 67
64 def _fetch_from_file(self, string, subdir=None): 68 def _fetch_from_file(self, string, subdir=None):
65 # Get the filename here 69 # Get the filename here
diff --git a/test-requirements.txt b/test-requirements.txt
index 88cd8c3..074a7a1 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -1,19 +1,17 @@
1# The order of packages is significant, because pip processes them in the order 1# The order of packages is significant, because pip processes them in the order
2# of appearance. Changing the order has an impact on the overall integration 2# of appearance. Changing the order has an impact on the overall integration
3# process, which may cause wedges in the gate later. 3# process, which may cause wedges in the gate later.
4pylint<=2.1.0 # GPLv2
4unittest2>=1.1.0 # BSD 5unittest2>=1.1.0 # BSD
5coverage!=4.4,>=4.0 # Apache-2.0 6coverage!=4.4,>=4.0 # Apache-2.0
6fixtures>=3.0.0 # Apache-2.0/BSD 7fixtures>=3.0.0 # Apache-2.0/BSD
7hacking>=1.1.0 8flake8 # MIT
8flake8<2.7.0,>=2.6.0 # MIT
9mock>=2.0.0 # BSD 9mock>=2.0.0 # BSD
10python-subunit>=1.0.0 # Apache-2.0/BSD 10python-subunit>=1.0.0 # Apache-2.0/BSD
11testrepository>=0.0.18 # Apache-2.0/BSD 11testrepository>=0.0.18 # Apache-2.0/BSD
12testscenarios>=0.4 # Apache-2.0/BSD 12testscenarios>=0.4 # Apache-2.0/BSD
13testtools>=2.2.0 # MIT 13testtools>=2.2.0 # MIT
14requests-mock>=1.2.0 # Apache-2.0 14requests-mock>=1.2.0 # Apache-2.0
15
16sphinx!=1.6.6,!=1.6.7,>=1.6.2 # BSD 15sphinx!=1.6.6,!=1.6.7,>=1.6.2 # BSD
17oslosphinx>=4.7.0 # Apache-2.0 16oslosphinx>=4.7.0 # Apache-2.0
18beautifulsoup4>=4.6.0 # MIT 17beautifulsoup4>=4.6.0 # MIT
19pylint>=1.5.0 # GPLv2
diff --git a/tests/unit/test_ascii_colors.py b/tests/unit/test_ascii_colors.py
index 83f352b..3b3d8eb 100644
--- a/tests/unit/test_ascii_colors.py
+++ b/tests/unit/test_ascii_colors.py
@@ -20,7 +20,7 @@ from syntribos.utils.cli import CONF
20class TestColorize(testtools.TestCase): 20class TestColorize(testtools.TestCase):
21 21
22 def test_colorize(self): 22 def test_colorize(self):
23 CONF.no_colorize = False 23 CONF.colorize = True
24 string = "color this string" 24 string = "color this string"
25 colors = {"red": 31, 25 colors = {"red": 31,
26 "green": 32, 26 "green": 32,
@@ -34,6 +34,6 @@ class TestColorize(testtools.TestCase):
34 colorize(string, color)) 34 colorize(string, color))
35 35
36 def test_no_colorize(self): 36 def test_no_colorize(self):
37 CONF.no_colorize = True 37 CONF.colorize = False
38 string = "No color" 38 string = "No color"
39 self.assertEqual(string, colorize(string)) 39 self.assertEqual(string, colorize(string))
diff --git a/tests/unit/test_content_validity.py b/tests/unit/test_content_validity.py
index 7f56b2f..df0b77b 100644
--- a/tests/unit/test_content_validity.py
+++ b/tests/unit/test_content_validity.py
@@ -41,7 +41,7 @@ class TestValidContent(testtools.TestCase):
41 """Tests valid_content check for both valid and invalid json/xml.""" 41 """Tests valid_content check for both valid and invalid json/xml."""
42 42
43 def test_valid_json(self, m): 43 def test_valid_json(self, m):
44 text = u'{"text": "Sample json"}' 44 text = '{"text": "Sample json"}'
45 headers = {"Content-type": "application/json"} 45 headers = {"Content-type": "application/json"}
46 m.register_uri("GET", "http://example.com", text=text, headers=headers) 46 m.register_uri("GET", "http://example.com", text=text, headers=headers)
47 resp = requests.get("http://example.com") 47 resp = requests.get("http://example.com")
@@ -50,7 +50,7 @@ class TestValidContent(testtools.TestCase):
50 self.assertEqual("VALID_JSON", signal.slug) 50 self.assertEqual("VALID_JSON", signal.slug)
51 51
52 def test_invalid_json(self, m): 52 def test_invalid_json(self, m):
53 text = u'{"text""" "Sample json"}' 53 text = '{"text""" "Sample json"}'
54 headers = {"Content-type": "application/json"} 54 headers = {"Content-type": "application/json"}
55 m.register_uri("GET", "http://example.com", text=text, headers=headers) 55 m.register_uri("GET", "http://example.com", text=text, headers=headers)
56 resp = requests.get("http://example.com") 56 resp = requests.get("http://example.com")
@@ -60,7 +60,7 @@ class TestValidContent(testtools.TestCase):
60 self.assertIn("APPLICATION_FAIL", signal.tags) 60 self.assertIn("APPLICATION_FAIL", signal.tags)
61 61
62 def test_valid_xml(self, m): 62 def test_valid_xml(self, m):
63 text = u"""<note>\n 63 text = """<note>\n
64 <to>Tove</to>\n 64 <to>Tove</to>\n
65 <from>Jani</from>\n 65 <from>Jani</from>\n
66 <heading>Reminder</heading>\n 66 <heading>Reminder</heading>\n
@@ -78,7 +78,7 @@ class TestValidContent(testtools.TestCase):
78 self.assertEqual("VALID_XML", signal.slug) 78 self.assertEqual("VALID_XML", signal.slug)
79 79
80 def test_invalid_xml(self, m): 80 def test_invalid_xml(self, m):
81 text = u"""<xml version=='1.0' encoding==UTF-8'?> 81 text = """<xml version=='1.0' encoding==UTF-8'?>
82 <!DOCTYPE note SYSTEM 'Note.dtd'> 82 <!DOCTYPE note SYSTEM 'Note.dtd'>
83 <note> 83 <note>
84 <to>Tove</to> 84 <to>Tove</to>
diff --git a/tests/unit/test_http_checks.py b/tests/unit/test_http_checks.py
index 7686d3f..61a8f4e 100644
--- a/tests/unit/test_http_checks.py
+++ b/tests/unit/test_http_checks.py
@@ -46,7 +46,7 @@ class HTTPCheckUnittest(testtools.TestCase):
46 def _assert_has_tags(self, tags, signals): 46 def _assert_has_tags(self, tags, signals):
47 signal = self._get_one_signal(signals, tags=tags) 47 signal = self._get_one_signal(signals, tags=tags)
48 self.assertEqual(len(tags), len(signal.tags)) 48 self.assertEqual(len(tags), len(signal.tags))
49 list(map(lambda t: self.assertIn(t, signal.tags), tags)) 49 list([self.assertIn(t, signal.tags) for t in tags])
50 50
51 51
52class HTTPFailureUnittest(HTTPCheckUnittest): 52class HTTPFailureUnittest(HTTPCheckUnittest):
@@ -66,7 +66,7 @@ class HTTPFailureUnittest(HTTPCheckUnittest):
66 66
67 def test_connect_timeout(self): 67 def test_connect_timeout(self):
68 signal = http_checks.check_fail(rex.ConnectTimeout()) 68 signal = http_checks.check_fail(rex.ConnectTimeout())
69 self._assert_has_tags(self.timeout_tags, signal) 69 self._assert_has_tags(self.conn_fail_tags, signal)
70 self._assert_has_slug("HTTP_FAIL_CONNECT_TIMEOUT", signal) 70 self._assert_has_slug("HTTP_FAIL_CONNECT_TIMEOUT", signal)
71 71
72 def test_invalid_url(self): 72 def test_invalid_url(self):
diff --git a/tests/unit/test_http_parser.py b/tests/unit/test_http_parser.py
index 80b1a9b..329ad4f 100644
--- a/tests/unit/test_http_parser.py
+++ b/tests/unit/test_http_parser.py
@@ -109,13 +109,13 @@ class HTTPParserUnittest(testtools.TestCase):
109 string = 'GET /v1/CALL_EXTERNAL|' 109 string = 'GET /v1/CALL_EXTERNAL|'
110 string += 'syntribos.extensions.random_data.client:get_uuid:[]|' 110 string += 'syntribos.extensions.random_data.client:get_uuid:[]|'
111 parsed_string = parser.call_external_functions(string) 111 parsed_string = parser.call_external_functions(string)
112 self.assertRegex(parsed_string, "GET /v1/[a-f0-9]+$") 112 self.assertRegex(parsed_string, r"GET /v1/[a-f0-9]+$")
113 113
114 def test_call_external_uuid_uuid4(self): 114 def test_call_external_uuid_uuid4(self):
115 """Tests calling 'uuid.uuid4()' in URL string.""" 115 """Tests calling 'uuid.uuid4()' in URL string."""
116 string = 'GET /v1/CALL_EXTERNAL|uuid:uuid4:[]|' 116 string = 'GET /v1/CALL_EXTERNAL|uuid:uuid4:[]|'
117 parsed_string = parser.call_external_functions(string) 117 parsed_string = parser.call_external_functions(string)
118 self.assertRegex(parsed_string, "GET /v1/[a-f0-9\-]+$") 118 self.assertRegex(parsed_string, r"GET /v1/[a-f0-9\-]+$")
119 119
120 def test_call_external_invalid_module(self): 120 def test_call_external_invalid_module(self):
121 """Tests calling invalid module in URL string.""" 121 """Tests calling invalid module in URL string."""
diff --git a/tests/unit/test_length.py b/tests/unit/test_length.py
index 0740f8e..3864849 100644
--- a/tests/unit/test_length.py
+++ b/tests/unit/test_length.py
@@ -39,7 +39,7 @@ class FakeTestObject(object):
39class TestLength(testtools.TestCase): 39class TestLength(testtools.TestCase):
40 @requests_mock.Mocker() 40 @requests_mock.Mocker()
41 def test_percentage_difference(self, m): 41 def test_percentage_difference(self, m):
42 content = u"""'Traceback (most recent call last):\n', 42 content = """'Traceback (most recent call last):\n',
43 File "<doctest...>", line 10, in <module>\n 43 File "<doctest...>", line 10, in <module>\n
44 lumberjack()\n', 44 lumberjack()\n',
45 File "<doctest...>", line 4, in lumberjack\n 45 File "<doctest...>", line 4, in lumberjack\n
diff --git a/tests/unit/test_progress_bar.py b/tests/unit/test_progress_bar.py
index 1fe7850..f9dc2cf 100644
--- a/tests/unit/test_progress_bar.py
+++ b/tests/unit/test_progress_bar.py
@@ -35,7 +35,7 @@ class TestProgressBar(testtools.TestCase):
35 def test_format_bar(self): 35 def test_format_bar(self):
36 pb = ProgressBar(total_len=5, width=5, fill_char="#", message="Test") 36 pb = ProgressBar(total_len=5, width=5, fill_char="#", message="Test")
37 pb.increment() # increments progress bar by 1 37 pb.increment() # increments progress bar by 1
38 self.assertEqual(u"Test\t\t|#----| 20 %", pb.format_bar()) 38 self.assertEqual("Test\t\t|#----| 20 %", pb.format_bar())
39 39
40 def test_print_bar(self): 40 def test_print_bar(self):
41 pb = ProgressBar(total_len=5, width=5, fill_char="#", message="Test") 41 pb = ProgressBar(total_len=5, width=5, fill_char="#", message="Test")
diff --git a/tox.ini b/tox.ini
index b28e230..e554468 100644
--- a/tox.ini
+++ b/tox.ini
@@ -35,7 +35,7 @@ commands = {posargs}
35[flake8] 35[flake8]
36# E123, E125 skipped as they are invalid PEP-8. 36# E123, E125 skipped as they are invalid PEP-8.
37show-source = True 37show-source = True
38ignore = E123,E125,H303,F403,H104,H302 38ignore = E123,E125,H303,F403,H104,H302,W504,H306
39exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build 39exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build
40 40
41[testenv:pylint] 41[testenv:pylint]