#!/usr/bin/env python """Gitlab bridge for PenText: imports and updates gitlab issues into PenText. This script is part of the PenText framework https://pentext.org Copyright (C) 2016-2017 Radically Open Security https://www.radicallyopensecurity.com Author(s): Peter Mosmans This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. """ from __future__ import absolute_import from __future__ import print_function from __future__ import unicode_literals import argparse import io import os import sys import textwrap try: import gitlab import pypandoc # Path of this script. The validate_report module is on the same path. sys.path.append(os.path.dirname(__file__)) import validate_report except (NameError, ImportError) as exception: print('[-] This script needs python-gitlab, pypandoc and validate_report library', file=sys.stderr) print("validate_report is part of the PenText framework", file=sys.stderr) print("Install python-gitlab with: sudo pip install python-gitlab", file=sys.stderr) print("Install pypandoc with: sudo pip install pypandoc\n", file=sys.stderr) print("Currently missing: " + exception.message, file=sys.stderr) sys.exit(-1) class BaseItem(object): """Base class for PenText items.""" DECLARATION = '\n' def __init__(self, item_type): if item_type not in ('finding', 'non-finding'): raise ValueError('Only finding and non-finding are currently supported') self.item_type = item_type self.__path = '{0}s'.format(self.item_type) self.root_open = '<{0}>\n'.format(self.item_type) self.root_close = '\n'.format(self.item_type) self.title = '' self.content = '' @property def filename(self): """Filename.""" return '{0}/{1}.xml'.format(self.__path, valid_filename(self.identifier)) def __str__(self): """Return an XML representation of the class.""" return self.DECLARATION + self.root_open + self.element('title') + \ self.content + self.root_close def element(self, attribute): """Return opening and closing attribute tags, including attribute value.""" return '<{0}>{1}\n'.format(attribute, getattr(self, attribute)) def write_file(self): """Serialize item to file as XML.""" try: with io.open(self.filename, 'w') as xmlfile: xmlfile.write(unicode(self)) print_line('[+] Wrote {0}'.format(self.filename)) except IOError: print('Could not write to %s', self.filename, file=sys.stderr) sys.exit(-1) class Finding(BaseItem): """Encapsulates finding.""" def __init__(self): BaseItem.__init__(self, 'finding') self.threat_level = 'Moderate' self.finding_type = 'TODO' self.status = 'new' self.description = '

TODO

' self.technicaldescription = '

TODO

' self.impact = '

TODO

' self.recommendation = '' def __str__(self): """Return an XML representation of the class.""" self.root_open = '\n'.format(self.identifier, self.threat_level, self.finding_type, self.status) self.content = self.element('description') + \ self.element('technicaldescription') + \ self.element('impact') + \ self.element('recommendation') return BaseItem.__str__(self) class NonFinding(BaseItem): """Encapsulates non-finding.""" def __init__(self): BaseItem.__init__(self, 'non-finding') def __str__(self): """Return an XML representation of the class.""" self.root_open = '