Skip to content

Commit

Permalink
Changed file reading logic. Parsers and auditor don't read files by i…
Browse files Browse the repository at this point in the history
…tself, instead of this expect file descriptor or file content.
  • Loading branch information
buglloc committed May 13, 2017
1 parent 625a25d commit 3c1437c
Show file tree
Hide file tree
Showing 9 changed files with 62 additions and 50 deletions.
10 changes: 8 additions & 2 deletions gixy/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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:
Expand Down
19 changes: 13 additions & 6 deletions gixy/core/manager.py
Original file line number Diff line number Diff line change
@@ -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)

Expand Down
24 changes: 15 additions & 9 deletions gixy/parser/nginx_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,32 @@


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':
Expand Down Expand Up @@ -108,7 +114,7 @@ def _resolve_file_include(self, pattern, parent):
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))
Expand Down
15 changes: 7 additions & 8 deletions gixy/parser/raw_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

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__)

Expand All @@ -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):
Expand Down
10 changes: 3 additions & 7 deletions tests/directives/test_block.py
Original file line number Diff line number Diff line change
@@ -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():
Expand Down
8 changes: 2 additions & 6 deletions tests/directives/test_directive.py
Original file line number Diff line number Diff line change
@@ -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():
Expand Down
7 changes: 1 addition & 6 deletions tests/parser/test_nginx_parser.py
Original file line number Diff line number Diff line change
@@ -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():
Expand Down
15 changes: 11 additions & 4 deletions tests/parser/test_raw_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -497,8 +497,15 @@ def test_comments():
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)
4 changes: 2 additions & 2 deletions tests/plugins/test_simply.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand All @@ -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,
Expand Down

0 comments on commit 3c1437c

Please sign in to comment.