Skip to content

Commit

Permalink
Linting Standards (#330)
Browse files Browse the repository at this point in the history
Fix linting issues with flake8 and black.
Add pre-commit congifuration, update documnetation for it.
Apply linting check in Travis CI.
  • Loading branch information
iyehuda committed Apr 5, 2020
1 parent 9ddf321 commit 0f17392
Show file tree
Hide file tree
Showing 59 changed files with 1,075 additions and 879 deletions.
5 changes: 5 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[flake8]
ignore = E203, E266, E501, W503, B903
max-line-length = 120
max-complexity = 18
select = B,C,E,F,W,B9
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@ var/
# Directory Cache Files
.DS_Store
thumbs.db
__pycache__
10 changes: 10 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
repos:
- repo: https://github.com/psf/black
rev: stable
hooks:
- id: black
- repo: https://gitlab.com/pycqa/flake8
rev: 3.7.9
hooks:
- id: flake8
additional_dependencies: [flake8-bugbear]
16 changes: 6 additions & 10 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,19 @@ group: travis_latest
language: python
cache: pip
python:
#- "3.4"
#- "3.5"
- "3.6"
- "3.7"
- "3.8"
install:
- pip install -r requirements.txt
- pip install -r requirements-dev.txt
before_script:
# stop the build if there are Python syntax errors or undefined names
- flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
- flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
- pip install pytest coverage pytest-cov
- make lint-check
script:
- python runtest.py
- make test
after_success:
- bash <(curl -s https://codecov.io/bash)
notifications:
on_success: change
on_failure: change # `always` will be the setting once code changes slow down
email:
on_success: change
on_failure: always
15 changes: 14 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
Thank you for taking interest in contributing to kube-hunter!
## Contribution Guide

## Welcome Aboard

Thank you for taking interest in contributing to kube-hunter!
This guide will walk you through the development process of kube-hunter.

## Setting Up

kube-hunter is written in Python 3 and supports versions 3.6 and above.
You'll probably want to create a virtual environment for your local project.
Once you got your project and IDE set up, you can `make dev-deps` and start contributing!
You may also install a pre-commit hook to take care of linting - `pre-commit install`.

## Issues

- Feel free to open issues for any reason as long as you make it clear if this issue is about a bug/feature/hunter/question/comment.
Expand Down
8 changes: 7 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,13 @@ dev-deps:

.PHONY: lint
lint:
flake8 $(SRC)
black .
flake8

.PHONY: lint-check
lint-check:
flake8
black --check --diff .

.PHONY: test
test:
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

[![Build Status](https://travis-ci.org/aquasecurity/kube-hunter.svg?branch=master)](https://travis-ci.org/aquasecurity/kube-hunter)
[![codecov](https://codecov.io/gh/aquasecurity/kube-hunter/branch/master/graph/badge.svg)](https://codecov.io/gh/aquasecurity/kube-hunter)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
[![License](https://img.shields.io/github/license/aquasecurity/kube-hunter)](https://github.com/aquasecurity/kube-hunter/blob/master/LICENSE)
[![Docker image](https://images.microbadger.com/badges/image/aquasec/kube-hunter.svg)](https://microbadger.com/images/aquasec/kube-hunter "Get your own image badge on microbadger.com")

Expand All @@ -13,7 +14,7 @@ kube-hunter hunts for security weaknesses in Kubernetes clusters. The tool was d

**Explore vulnerabilities**: The kube-hunter knowledge base includes articles about discoverable vulnerabilities and issues. When kube-hunter reports an issue, it will show its VID (Vulnerability ID) so you can look it up in the KB at https://aquasecurity.github.io/kube-hunter/

**Contribute**: We welcome contributions, especially new hunter modules that perform additional tests. If you would like to develop your modules please read [Guidelines For Developing Your First kube-hunter Module](kube_hunter/README.md).
**Contribute**: We welcome contributions, especially new hunter modules that perform additional tests. If you would like to develop your modules please read [Guidelines For Developing Your First kube-hunter Module](kube_hunter/CONTRIBUTING.md).

[![kube-hunter demo video](https://github.com/aquasecurity/kube-hunter/blob/master/kube-hunter-screenshot.png)](https://youtu.be/s2-6rTkH8a8?t=57s)

Expand Down
2 changes: 2 additions & 0 deletions kube_hunter/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
from . import core
from . import modules

__all__ = [core, modules]
40 changes: 17 additions & 23 deletions kube_hunter/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,29 +13,27 @@
config.dispatcher = get_dispatcher(config.dispatch)
logger = logging.getLogger(__name__)

import kube_hunter
import kube_hunter # noqa


def interactive_set_config():
"""Sets config manually, returns True for success"""
options = [("Remote scanning",
"scans one or more specific IPs or DNS names"),
("Interface scanning",
"scans subnets on all local network interfaces"),
("IP range scanning", "scans a given IP range")]
options = [
("Remote scanning", "scans one or more specific IPs or DNS names"),
("Interface scanning", "scans subnets on all local network interfaces"),
("IP range scanning", "scans a given IP range"),
]

print("Choose one of the options below:")
for i, (option, explanation) in enumerate(options):
print("{}. {} ({})".format(i+1, option.ljust(20), explanation))
print("{}. {} ({})".format(i + 1, option.ljust(20), explanation))
choice = input("Your choice: ")
if choice == '1':
config.remote = input("Remotes (separated by a ','): ").\
replace(' ', '').split(',')
elif choice == '2':
if choice == "1":
config.remote = input("Remotes (separated by a ','): ").replace(" ", "").split(",")
elif choice == "2":
config.interface = True
elif choice == '3':
config.cidr = input("CIDR (example - 192.168.1.0/24): ").\
replace(' ', '')
elif choice == "3":
config.cidr = input("CIDR (example - 192.168.1.0/24): ").replace(" ", "")
else:
return False
return True
Expand All @@ -51,7 +49,7 @@ def list_hunters():
print("\n\nActive Hunters:\n---------------")
for hunter, docs in handler.active_hunters.items():
name, doc = hunter.parse_docs(docs)
print("* {}\n {}\n".format( name, doc))
print("* {}\n {}\n".format(name, doc))


global hunt_started_lock
Expand All @@ -61,19 +59,15 @@ def list_hunters():

def main():
global hunt_started
scan_options = [
config.pod,
config.cidr,
config.remote,
config.interface
]
scan_options = [config.pod, config.cidr, config.remote, config.interface]
try:
if config.list:
list_hunters()
return

if not any(scan_options):
if not interactive_set_config(): return
if not interactive_set_config():
return

with hunt_started_lock:
hunt_started = True
Expand Down Expand Up @@ -102,5 +96,5 @@ def main():
hunt_started_lock.release()


if __name__ == '__main__':
if __name__ == "__main__":
main()
12 changes: 5 additions & 7 deletions kube_hunter/conf/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,14 @@
from kube_hunter.conf.parser import parse_args

config = parse_args()
formatter = '%(asctime)s %(levelname)s %(name)s %(message)s'
formatter = "%(asctime)s %(levelname)s %(name)s %(message)s"

loglevel = getattr(logging, config.log.upper(), None)

if not loglevel:
logging.basicConfig(level=logging.INFO,
format=formatter)
logging.warning('Unknown log level selected, using info')
logging.basicConfig(level=logging.INFO, format=formatter)
logging.warning("Unknown log level selected, using info")
elif config.log.lower() != "none":
logging.basicConfig(level=loglevel,
format=formatter)
logging.basicConfig(level=loglevel, format=formatter)

import plugins
import plugins # noqa
83 changes: 26 additions & 57 deletions kube_hunter/conf/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,87 +2,56 @@


def parse_args():
parser = ArgumentParser(
description='Kube-Hunter - hunts for security '
'weaknesses in Kubernetes clusters')
parser = ArgumentParser(description="kube-hunter - hunt for security weaknesses in Kubernetes clusters")

parser.add_argument(
'--list',
action="store_true",
help="Displays all tests in kubehunter "
"(add --active flag to see active tests)")
"--list", action="store_true", help="Displays all tests in kubehunter (add --active flag to see active tests)",
)

parser.add_argument(
'--interface',
action="store_true",
help="Set hunting on all network interfaces")
parser.add_argument("--interface", action="store_true", help="Set hunting on all network interfaces")

parser.add_argument(
'--pod',
action="store_true",
help="Set hunter as an insider pod")
parser.add_argument("--pod", action="store_true", help="Set hunter as an insider pod")

parser.add_argument(
'--quick',
action="store_true",
help="Prefer quick scan (subnet 24)")
parser.add_argument("--quick", action="store_true", help="Prefer quick scan (subnet 24)")

parser.add_argument(
'--include-patched-versions',
action="store_true",
help="Don't skip patched versions when scanning")
"--include-patched-versions", action="store_true", help="Don't skip patched versions when scanning",
)

parser.add_argument("--cidr", type=str, help="Set an ip range to scan, example: 192.168.0.0/16")
parser.add_argument(
'--cidr',
type=str,
help="Set an ip range to scan, example: 192.168.0.0/16")
parser.add_argument(
'--mapping',
action="store_true",
help="Outputs only a mapping of the cluster's nodes")
"--mapping", action="store_true", help="Outputs only a mapping of the cluster's nodes",
)

parser.add_argument(
'--remote',
nargs='+',
metavar="HOST",
default=list(),
help="One or more remote ip/dns to hunt")
"--remote", nargs="+", metavar="HOST", default=list(), help="One or more remote ip/dns to hunt",
)

parser.add_argument(
'--active',
action="store_true",
help="Enables active hunting")
parser.add_argument("--active", action="store_true", help="Enables active hunting")

parser.add_argument(
'--log',
"--log",
type=str,
metavar="LOGLEVEL",
default='INFO',
help="Set log level, options are: debug, info, warn, none")
default="INFO",
help="Set log level, options are: debug, info, warn, none",
)

parser.add_argument(
'--report',
type=str,
default='plain',
help="Set report type, options are: plain, yaml, json")
"--report", type=str, default="plain", help="Set report type, options are: plain, yaml, json",
)

parser.add_argument(
'--dispatch',
"--dispatch",
type=str,
default='stdout',
default="stdout",
help="Where to send the report to, options are: "
"stdout, http (set KUBEHUNTER_HTTP_DISPATCH_URL and "
"KUBEHUNTER_HTTP_DISPATCH_METHOD environment variables to configure)")
"KUBEHUNTER_HTTP_DISPATCH_METHOD environment variables to configure)",
)

parser.add_argument(
'--statistics',
action="store_true",
help="Show hunting statistics")
parser.add_argument("--statistics", action="store_true", help="Show hunting statistics")

parser.add_argument(
'--network-timeout',
type=float,
default=5.0,
help="network operations timeout")
parser.add_argument("--network-timeout", type=float, default=5.0, help="network operations timeout")

return parser.parse_args()
2 changes: 2 additions & 0 deletions kube_hunter/core/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
from . import types
from . import events

__all__ = [types, events]
4 changes: 3 additions & 1 deletion kube_hunter/core/events/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
from .handler import *
from .handler import EventQueue, handler
from . import types

__all__ = [EventQueue, handler, types]
6 changes: 4 additions & 2 deletions kube_hunter/core/events/handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,12 @@ def wrapper(hook):
def __new__unsubscribe_self(self, cls):
handler.hooks[event].remove((hook, predicate))
return object.__new__(self)

hook.__new__ = __new__unsubscribe_self

self.subscribe_event(event, hook=hook, predicate=predicate)
return hook

return wrapper

# getting uninstantiated event object
Expand All @@ -80,7 +82,7 @@ def subscribe_event(self, event, hook=None, predicate=None):
logger.debug(f"{hook} subscribed to {event}")

def apply_filters(self, event):
# if filters are subscribed, apply them on the event
# if filters are subscribed, apply them on the event
for hooked_event in self.filters.keys():
if hooked_event in event.__class__.__mro__:
for filter_hook, predicate in self.filters[hooked_event]:
Expand All @@ -101,7 +103,7 @@ def publish_event(self, event, caller=None):
event.previous = caller.event
event.hunter = caller.__class__

# applying filters on the event, before publishing it to subscribers.
# applying filters on the event, before publishing it to subscribers.
# if filter returned None, not proceeding to publish
event = self.apply_filters(event)
if event:
Expand Down
8 changes: 4 additions & 4 deletions kube_hunter/core/events/types/__init__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from os.path import dirname, basename, isfile
import glob

from .common import *
from .common import * # noqa

# dynamically importing all modules in folder
files = glob.glob(dirname(__file__)+"/*.py")
for module_name in (basename(f)[:-3] for f in files if isfile(f) and not f.endswith('__init__.py')):
files = glob.glob(dirname(__file__) + "/*.py")
for module_name in (basename(f)[:-3] for f in files if isfile(f) and not f.endswith("__init__.py")):
if module_name != "handler":
exec('from .{} import *'.format(module_name))
exec("from .{} import *".format(module_name))
Loading

0 comments on commit 0f17392

Please sign in to comment.