Changed file reading logic. Parsers and auditor don't read files by itself, instead of this expect file descriptor or file content.

pull/40/head
Andrew Krasichkov 2017-05-13 14:53:04 +03:00
parent 625a25db46
commit 3c1437c816
9 changed files with 62 additions and 50 deletions

View File

@ -98,7 +98,7 @@ def main():
_init_logger(args.debug)
path = os.path.expanduser(args.nginx_file)
if not os.path.isfile(path):
if path != '-' and not os.path.exists(path):
sys.stderr.write('Please specify path to Nginx configuration.\n\n')
parser.print_help()
sys.exit(1)
@ -150,7 +150,13 @@ def main():
config.set_for(name, options)
with Gixy(config=config) as yoda:
yoda.audit(path)
if path == '-':
with os.fdopen(sys.stdin.fileno(), 'r') as fdata:
yoda.audit('<stdin>', fdata, is_stdin=True)
else:
with open(path, mode='r') as fdata:
yoda.audit(path, fdata, is_stdin=False)
formatted = formatters()[config.output_format]().format(yoda)
if args.output_file:
with open(config.output_file, 'w') as f:

View File

@ -1,25 +1,32 @@
import os
import logging
import gixy
from gixy.core.plugins_manager import PluginsManager
from gixy.core.context import get_context, pop_context, push_context, purge_context
from gixy.parser.nginx_parser import NginxParser
from gixy.core.config import Config
LOG = logging.getLogger(__name__)
class Manager(object):
def __init__(self, config=None):
self.root = None
self.parser = None
self.auditor = None
self.config = config or Config()
self.auditor = PluginsManager(config=self.config)
self.stats = {gixy.severity.UNSPECIFIED: 0,
gixy.severity.LOW: 0,
gixy.severity.MEDIUM: 0,
gixy.severity.HIGH: 0}
def audit(self, file_path):
self.auditor = PluginsManager(config=self.config)
self.parser = NginxParser(file_path, allow_includes=self.config.allow_includes)
self.root = self.parser.parse(file_path)
def audit(self, file_path, file_data, is_stdin=False):
LOG.debug("Audit config file: {fname}".format(fname=file_path))
parser = NginxParser(
cwd=os.path.dirname(file_path) if not is_stdin else '',
allow_includes=self.config.allow_includes)
self.root = parser.parse(content=file_data.read(), path_info=file_path)
push_context(self.root)
self._audit_recursive(self.root.children)

View File

@ -12,26 +12,32 @@ LOG = logging.getLogger(__name__)
class NginxParser(object):
def __init__(self, file_path, allow_includes=True):
self.base_file_path = file_path
self.cwd = os.path.dirname(file_path)
def __init__(self, cwd='', allow_includes=True):
self.cwd = cwd
self.configs = {}
self.is_dump = False
self.allow_includes = allow_includes
self.directives = {}
self.parser = raw_parser.RawParser()
self._init_directives()
def parse(self, file_path, root=None):
LOG.debug("Parse file: {}".format(file_path))
def parse_file(self, path, root=None):
LOG.debug("Parse file: {}".format(path))
content = open(path).read()
return self.parse(content=content, root=root, path_info=path)
def parse(self, content, root=None, path_info=None):
if not root:
root = block.Root()
try:
parser = raw_parser.RawParser()
parsed = parser.parse(file_path)
parsed = self.parser.parse(content)
except ParseException as e:
LOG.error('Failed to parse config "{file}": {error}'.format(file=file_path, error=str(e)))
error_msg = 'char {char} (line:{line}, col:{col})'.format(char=e.loc, line=e.lineno, col=e.col)
if path_info:
LOG.error('Failed to parse config "{file}": {error}'.format(file=path_info, error=error_msg))
else:
LOG.error('Failed to parse config: {error}'.format(error=error_msg))
return root
if len(parsed) and parsed[0].getName() == 'file_delimiter':
@ -108,7 +114,7 @@ class NginxParser(object):
for file_path in glob.iglob(path):
include = block.IncludeBlock('include', [file_path])
parent.append(include)
self.parse(file_path, include)
self.parse_file(file_path, include)
if not file_path:
LOG.warning("File not found: {}".format(path))

View File

@ -3,7 +3,7 @@ from cached_property import cached_property
from pyparsing import (
Literal, Suppress, White, Word, alphanums, Forward, Group, Optional, Combine,
Keyword, OneOrMore, ZeroOrMore, Regex, QuotedString, nestedExpr)
Keyword, OneOrMore, ZeroOrMore, Regex, QuotedString, nestedExpr, ParseResults)
LOG = logging.getLogger(__name__)
@ -23,16 +23,15 @@ class RawParser(object):
A class that parses nginx configuration with pyparsing
"""
def __init__(self):
self._script = None
def parse(self, file_path):
def parse(self, data):
"""
Returns the parsed tree.
"""
content = open(file_path).read()
return self.script.parseString(content, parseAll=True)
# return self.script.parseFile(file_path, parseAll=True)
content = data.strip()
if not content:
return ParseResults()
return self.script.parseString(data, parseAll=True)
@cached_property
def script(self):

View File

@ -1,17 +1,13 @@
from nose.tools import assert_equals, assert_is_instance, assert_is_not_none, assert_is_none, assert_true, assert_false
import mock
from six import StringIO
from six.moves import builtins
from gixy.parser.nginx_parser import NginxParser
from gixy.directives.block import *
# TODO(buglloc): what about include block?
def _get_parsed(config):
with mock.patch('%s.open' % builtins.__name__) as mock_open:
mock_open.return_value = StringIO(config)
root = NginxParser('/foo/bar', allow_includes=False).parse('/foo/bar')
return root.children[0]
root = NginxParser(cwd='', allow_includes=False).parse(config)
return root.children[0]
def test_block():

View File

@ -1,15 +1,11 @@
from nose.tools import assert_equals, assert_is_instance, assert_false, assert_true
import mock
from six import StringIO
from six.moves import builtins
from gixy.parser.nginx_parser import NginxParser
from gixy.directives.directive import *
def _get_parsed(config):
with mock.patch('%s.open' % builtins.__name__) as mock_open:
mock_open.return_value = StringIO(config)
return NginxParser('/foo/bar', allow_includes=False).parse('/foo/bar').children[0]
root = NginxParser(cwd='', allow_includes=False).parse(config)
return root.children[0]
def test_directive():

View File

@ -1,16 +1,11 @@
from nose.tools import assert_is_instance, assert_equal
import mock
from six import StringIO
from six.moves import builtins
from gixy.parser.nginx_parser import NginxParser
from gixy.directives.directive import *
from gixy.directives.block import *
def _parse(config):
with mock.patch('%s.open' % builtins.__name__) as mock_open:
mock_open.return_value = StringIO(config)
return NginxParser('/foo/bar', allow_includes=False).parse('/foo/bar')
return NginxParser(cwd='', allow_includes=False).parse(config)
def test_directive():

View File

@ -497,8 +497,15 @@ add_header X-Blank-Comment blank;
assert_config(config, expected)
def test_empty_config():
config = '''
'''
expected = []
assert_config(config, expected)
def assert_config(config, expected):
with mock.patch('%s.open' % builtins.__name__) as mock_open:
mock_open.return_value = StringIO(config)
actual = RawParser().parse('/foo/bar')
assert_equals(actual.asList(), expected)
actual = RawParser().parse(config)
assert_equals(actual.asList(), expected)

View File

@ -81,7 +81,7 @@ def yoda_provider(plugin, plugin_options=None):
def check_configuration(plugin, config_path, test_config):
plugin_options = parse_plugin_options(config_path)
with yoda_provider(plugin, plugin_options) as yoda:
yoda.audit(config_path)
yoda.audit(config_path, open(config_path, mode='r'))
results = RawFormatter().format(yoda)
assert_equals(len(results), 1, 'Should have one report')
@ -102,7 +102,7 @@ def check_configuration(plugin, config_path, test_config):
def check_configuration_fp(plugin, config_path, test_config):
with yoda_provider(plugin) as yoda:
yoda.audit(config_path)
yoda.audit(config_path, open(config_path, mode='r'))
results = RawFormatter().format(yoda)
assert_equals(len(results), 0,