From 13d6282f82d17a5334abe7ea3a103c8e0f0069cb Mon Sep 17 00:00:00 2001
From: Peter Mosmans
Date: Tue, 1 Nov 2016 13:38:32 +0100
Subject: [PATCH 01/14] Extended list of non-capitalized words
---
chatops/python/validate_report.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/chatops/python/validate_report.py b/chatops/python/validate_report.py
index fe9ae61..eb8c856 100644
--- a/chatops/python/validate_report.py
+++ b/chatops/python/validate_report.py
@@ -46,7 +46,8 @@ VOCABULARY = 'project-vocabulary.pws'
# Snippets may contain XML fragments without the proper entities
EXAMPLEDIR = 'examples/'
NOT_CAPITALIZED = ['a', 'an', 'and', 'as', 'at', 'but', 'by', 'for', 'in',
- 'nor', 'of', 'on', 'or', 'the', 'to', 'up']
+ 'jQuery', 'jQuery-UI', 'nor', 'of', 'on', 'or', 'the', 'to',
+ 'up']
SNIPPETDIR = 'snippets/'
TEMPLATEDIR = 'templates/'
OFFERTE = '/offerte.xml'
From 5caa5aaed8ec1c9c95bf78b5ab97cfde21c6d1f5 Mon Sep 17 00:00:00 2001
From: Peter Mosmans
Date: Tue, 1 Nov 2016 13:44:04 +0100
Subject: [PATCH 02/14] Retrieve list of maximum 99 issues
Workaround for some pagination issues.
---
chatops/python/gitlab-to-pentext.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/chatops/python/gitlab-to-pentext.py b/chatops/python/gitlab-to-pentext.py
index 6200c2a..2e31eca 100644
--- a/chatops/python/gitlab-to-pentext.py
+++ b/chatops/python/gitlab-to-pentext.py
@@ -146,7 +146,7 @@ def list_issues(gitserver, options):
Lists all issues for options['issues']
"""
try:
- for issue in gitserver.project_issues.list(project_id=options['issues']):
+ for issue in gitserver.project_issues.list(project_id=options['issues'], per_page=99):
if issue.state == 'closed' and not options['closed']:
continue
if 'finding' in issue.labels:
From 0fd5171ebab96762f69cfa78d8595b3050baea4b Mon Sep 17 00:00:00 2001
From: Peter Mosmans
Date: Thu, 10 Nov 2016 20:39:18 +1000
Subject: [PATCH 03/14] Added template for future work
---
xml/source/futurework.xml | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/xml/source/futurework.xml b/xml/source/futurework.xml
index f7ce843..1240426 100644
--- a/xml/source/futurework.xml
+++ b/xml/source/futurework.xml
@@ -1,4 +1,12 @@
Future Work
+
+
+ -
+ Title
+ Description
+
+
+
From d07b44058eba8b16a3ed7faa9d12a0424b4df18b Mon Sep 17 00:00:00 2001
From: Peter Mosmans
Date: Thu, 10 Nov 2016 20:43:05 +1000
Subject: [PATCH 04/14] Added boilerplate fingerprinting template
From 34adf23dd1dd94d5e6a12a694bca02c78b7a38e6 Mon Sep 17 00:00:00 2001
From: Peter Mosmans
Date: Thu, 10 Nov 2016 20:46:32 +1000
Subject: [PATCH 05/14] Filter another illegal filename character
---
chatops/python/gitlab-to-pentext.py | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/chatops/python/gitlab-to-pentext.py b/chatops/python/gitlab-to-pentext.py
index 2e31eca..9fd6e14 100644
--- a/chatops/python/gitlab-to-pentext.py
+++ b/chatops/python/gitlab-to-pentext.py
@@ -146,7 +146,8 @@ def list_issues(gitserver, options):
Lists all issues for options['issues']
"""
try:
- for issue in gitserver.project_issues.list(project_id=options['issues'], per_page=99):
+ for issue in gitserver.project_issues.list(project_id=options['issues'],
+ per_page=99):
if issue.state == 'closed' and not options['closed']:
continue
if 'finding' in issue.labels:
@@ -251,7 +252,7 @@ def valid_filename(filename):
"""
result = ''
for char in filename.strip():
- if char in [':', '/', '.', '\\', ' ', '[', ']', '(', ')', '\'']:
+ if char in ['*', ':', '/', '.', '\\', ' ', '[', ']', '(', ')', '\'']:
if len(char) and not result.endswith('-'):
result += '-'
else:
From a75c949bc934c002bd2be7c9cd32b30636bf8237 Mon Sep 17 00:00:00 2001
From: Peter Mosmans
Date: Thu, 10 Nov 2016 20:47:43 +1000
Subject: [PATCH 06/14] Remove debug notification
---
scripts/gitlab-to-pentext.py | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/scripts/gitlab-to-pentext.py b/scripts/gitlab-to-pentext.py
index ce71e3d..a02fd6a 100644
--- a/scripts/gitlab-to-pentext.py
+++ b/scripts/gitlab-to-pentext.py
@@ -119,12 +119,11 @@ def convert_markdown(text):
Replace markdown monospace with monospace tags
"""
result = text
- return result
+ return result # currently not implemented
print('EXAMINING ' + text + ' END')
monospace = re.findall("\`\`\`(.*?)\`\`\`", text, re.DOTALL)
print(monospace)
if len(monospace):
- print('YESSS ' + monospace)
result = {}
result['monospace'] = ''.join(monospace)
@@ -158,7 +157,7 @@ def parse_arguments():
parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
description=textwrap.dedent('''\
-gitlab-to-pentext - imports and updates gitlab issues into PetText (XML) format
+gitlab-to-pentext - imports and updates gitlab issues into PenText (XML) format
Copyright (C) 2016 Peter Mosmans [Radically Open Security]]
This program is free software: you can redistribute it and/or modify
@@ -184,7 +183,7 @@ the Free Software Foundation, either version 3 of the License, or
return vars(parser.parse_args())
-def preflight_checks(options):
+def preflight_checks():
"""
Checks if all tools are there.
Exits with 0 if everything went okilydokily.
@@ -248,7 +247,7 @@ def main():
The main program.
"""
options = parse_arguments()
- gitserver = preflight_checks(options)
+ gitserver = preflight_checks()
if options['projects']:
list_projects(gitserver, options)
if options['issues']:
From 181d9d57cf1abff020b9bb45f8c1b92ad40f9867 Mon Sep 17 00:00:00 2001
From: Peter Mosmans
Date: Mon, 21 Nov 2016 11:28:58 +1000
Subject: [PATCH 07/14] Use logging module
---
chatops/python/validate_report.py | 124 ++++++++++++++++++------------
1 file changed, 76 insertions(+), 48 deletions(-)
diff --git a/chatops/python/validate_report.py b/chatops/python/validate_report.py
index eb8c856..0525db5 100644
--- a/chatops/python/validate_report.py
+++ b/chatops/python/validate_report.py
@@ -23,6 +23,7 @@ from __future__ import print_function
from __future__ import unicode_literals
import argparse
+import logging
import mmap
import os
import re
@@ -107,24 +108,41 @@ the Free Software Foundation, either version 3 of the License, or
return vars(parser.parse_args())
-def validate_spelling(tree, filename, options):
+def initialize_speller():
"""
- Checks spelling of text within tags.
- If options['learn'], then unknown words will be added to the dictionary.
+ Initialize and return speller module.
"""
- result = True
+ speller = None
try:
speller = aspell.Speller(('lang', 'en'),
('personal-dir', '.'),
('personal', VOCABULARY))
- except: # some versions of aspell use a different path
- speller = aspell.Speller(('lang', 'en'),
- ('personal-path', './' + VOCABULARY))
- if options['debug']:
- [print(i[0] + ' ' + str(i[2]) + '\n') for i in speller.ConfigKeys()]
+ except aspell.AspellConfigError as exception: # some versions of aspell use a different path
+ logging.debug('Encountered exception when trying to intialize spelling: %s',
+ exception)
+ try:
+ speller = aspell.Speller(('lang', 'en'),
+ ('personal-path', './' + VOCABULARY))
+ except aspell.AspellSpellerError as exception:
+ logging.error('Could not initialize speller: %s', exception)
+ if speller:
+ [logging.debug(i[0] + ' ' + str(i[2]) + '\n') for i in speller.ConfigKeys()]
+ return speller
+
+
+def validate_spelling(tree, filename, options):
+ """
+ Check spelling of text within tags.
+ If options['learn'], then unknown words will be added to the dictionary.
+ """
+ result = True
+ speller = initialize_speller()
+ if not speller:
+ options['spelling'] = False
+ return result
try:
root = tree.getroot()
- for section in root.iter():
+ for section in root.iter():
if section.text and isinstance(section.tag, basestring) and \
section.tag not in ('a', 'code', 'monospace', 'pre'):
for word in re.findall('([a-zA-Z]+\'?[a-zA-Z]+)', section.text):
@@ -133,12 +151,13 @@ def validate_spelling(tree, filename, options):
speller.addtoPersonal(word)
else:
result = False
- print('[-] Misspelled (unknown) word {0} in {1}'.
- format(word.encode('utf-8'), filename))
+ logging.warning('Misspelled (unknown) word %s in %s',
+ word.encode('utf-8'), filename)
if options['learn']:
speller.saveAllwords()
except aspell.AspellSpellerError as exception:
- print('[-] Spelling disabled ({0})'.format(exception))
+ logging.error('Disabled spelling (%s)', exception)
+ options['spelling'] = False
return result
@@ -201,16 +220,6 @@ def validate_files(filenames, options):
return result
-def print_output(options, stdout, stderr=None):
- """
- Prints out standard out and standard err using the verboseprint function.
- """
- if stdout and options['verbose']:
- print('[+] {0}'.format(stdout))
- if stderr and options['verbose']:
- print('[-] {0}'.format(stderr))
-
-
def validate_report():
"""
Validates XML report file by trying to build it.
@@ -231,7 +240,7 @@ def validate_xml(filename, options):
# crude check whether the file is outside the pentext framework
if 'notes' in filename:
return result, xml_type
- print_output(options, 'Validating XML file: {0}'.format(filename))
+ logging.info('Validating XML file: %s', filename)
try:
with open(filename, 'rb') as xml_file:
xml.sax.parse(xml_file, xml.sax.ContentHandler())
@@ -332,11 +341,11 @@ def validate_type(tree, filename, options):
fix = True
for tag in tags:
if root.find(tag) is None:
- print('[-] Missing tag in {0}: {1}'.format(filename, tag))
+ logging.warning('Missing tag in %s: %s', filename, tag)
result = False
continue
if not get_all_text(root.find(tag)):
- print('[-] Empty tag in {0}: {1}'.format(filename, tag))
+ logging.warning('Empty tag in %s: %s', filename, tag)
result = False
continue
if tag == 'title' and (options['capitalization'] and \
@@ -405,14 +414,14 @@ def validate_master(filename, findings, non_findings, scans, options):
result = True
include_findings = []
include_nonfindings = []
- print_output(options, 'Validating master file {0}'.format(filename))
+ logging.info('Validating master file %s', filename)
try:
xmltree = ElementTree.parse(filename,
ElementTree.XMLParser(strip_cdata=False))
if not find_keyword(xmltree, 'TODO', filename):
print('[-] Keyword checks failed for {0}'.format(filename))
result = False
- print_output(options, 'Performing cross check on findings, non-findings and scans...')
+ logging.info('Performing cross check on findings, non-findings and scans...')
for finding in findings:
if not cross_check_file(filename, finding):
print('[A] Cross check failed for finding {0}'.
@@ -421,23 +430,22 @@ def validate_master(filename, findings, non_findings, scans, options):
result = False
for non_finding in non_findings:
if not cross_check_file(filename, non_finding):
- print('[A] Cross check failed for non-finding {0}'.
- format(non_finding))
+ logging.warning('Cross check failed for non-finding %s', non_finding)
include_nonfindings.append(non_finding)
result = False
if result:
- print_output(options, 'Cross checks successful')
+ logging.info('Cross checks successful')
except (ElementTree.ParseError, IOError) as exception:
- print('[-] validating {0} failed ({1})'.format(filename, exception))
+ logging.warning('Validating %s failed: %s', filename, exception)
result = False
if not result:
if options['auto_fix']:
add_include(filename, 'findings', include_findings)
add_include(filename, 'nonFindings', include_nonfindings)
close_file(filename)
- print('[+] Automatically fixed {0}'.format(filename))
+ logging.info('Automatically fixed %s', filename)
else:
- print('[+] NOTE: Items with [A] can be fixed automatically, use --auto-fix')
+ logging.warning('Item can be fixed automatically, use --auto-fix')
return result
@@ -449,7 +457,7 @@ def report_string(report_file):
report = open(report_file)
return mmap.mmap(report.fileno(), 0, access=mmap.ACCESS_READ)
except IOError as exception:
- print('[-] Could not open {0} ({1})'.format(report_file, exception))
+ logging.critical('Could not open %s: %s', report_file, exception)
sys.exit(-1)
@@ -460,7 +468,7 @@ def cross_check_file(filename, external):
result = True
report_text = report_string(filename)
if report_text.find(external) == -1:
- print('[-] could not find a reference in {0} to {1}'.format(filename, external))
+ logging.warning('Could not find a reference in %s to %s', filename, external)
result = False
return result
@@ -508,11 +516,35 @@ def find_keyword(xmltree, keyword, filename):
section = 'in {0}'.format(tag.attrib['id'])
if tag.text:
if keyword in tag.text:
- print('[-] {0} found in {1} {2}'.format(keyword, filename, section))
+ logging.warning('%s found in %s %s', keyword, filename, section)
result = False
return result
+def setup_logging(options):
+ """
+ Set up loghandlers according to options.
+ """
+ # DEBUG = (10) debug status messages
+ # INFO = (20) verbose status messages
+ # WARNING = (30) warning messages (= errors in validation)
+ # ERROR = (40) error messages (= program errors)
+ logger = logging.getLogger()
+ logger.setLevel(0)
+ console = logging.StreamHandler(stream=sys.stdout)
+ console.setFormatter(logging.Formatter('%(levelname)s %(message)s',
+ datefmt='%H:%M:%S'))
+ if options['debug']:
+ console.setLevel(logging.DEBUG)
+ else:
+ if options['verbose']:
+ print('hi')
+ console.setLevel(logging.INFO)
+ else:
+ logger.setLevel(logging.WARNING)
+ logger.addHandler(console)
+
+
def main():
"""
The main program. Cross-checks, validates XML files and report.
@@ -522,27 +554,23 @@ def main():
reload(sys)
sys.setdefaultencoding('utf-8')
options = parse_arguments()
+ setup_logging(options)
if options['all']:
options['capitalization'] = True
options['long'] = True
if options['learn']:
- print_output(options, 'Adding unknown words to {0}'.format(VOCABULARY))
- # if options['spelling']:
- # if not os.path.exists(VOCABULARY):
- # print_output(options, 'Creating project-specific vocabulary file {0}'.
- # format(VOCABULARY))
- # options['learn'] = True
- print_output(options, 'Validating all XML files...')
+ logging.debug('Adding unknown words to %s', VOCABULARY)
+ logging.info('Validating all XML files...')
result = validate_files(all_files(), options)
if result:
- print_output(options, 'Validation checks successful')
+ logging.info('Validation checks successful')
if DOCBUILDER:
- print_output(options, 'Validating report build...')
+ logging.info('Validating report build...')
result = validate_report() and result
if result:
- print('[+] Succesfully validated everything. Good to go')
+ logging.info('Validation successful. Good to go')
else:
- print('[-] Errors occurred')
+ logging.warning('Validation failed')
if options['spelling'] and options['learn']:
print('[*] Don\'t forget to check the vocabulary file {0}'.
format(VOCABULARY))
From a7253519f346b8ca2e55073378d43e8bcf6ba613 Mon Sep 17 00:00:00 2001
From: Peter Mosmans
Date: Mon, 21 Nov 2016 20:39:09 +1000
Subject: [PATCH 08/14] Replace zip with 7zip
---
chatops/bash/releaser.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/chatops/bash/releaser.sh b/chatops/bash/releaser.sh
index e483420..0cdcdf6 100644
--- a/chatops/bash/releaser.sh
+++ b/chatops/bash/releaser.sh
@@ -42,7 +42,7 @@ if [ -f ${source} ]; then
else
cp -v ${source} ${fullname}
PASS=$(head -c 25 /dev/random | base64 | head -c 25)
- zip --password ${PASS} "${fullname}.zip" ${fullname} 2>/dev/null && echo "Zip file encrypted with password '${PASS}'"
+ 7z a -p${PASS} "${fullname}.zip" ${fullname} 2>/dev/null && echo "Zip file encrypted with password '${PASS}'"
fi
else
echo "Could not find source ${source}"
From b9226a1ddbf79747d0d1fe8615eace2ad0c66010 Mon Sep 17 00:00:00 2001
From: Peter Mosmans
Date: Wed, 23 Nov 2016 22:12:02 +1000
Subject: [PATCH 09/14] Added more explanation for notes directory (source
code)
---
xml/notes/README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/xml/notes/README.md b/xml/notes/README.md
index ac04a43..9e4b845 100644
--- a/xml/notes/README.md
+++ b/xml/notes/README.md
@@ -1,2 +1,2 @@
# notes
-This folder holds all email correspondence and other notes
+This folder holds all email correspondence, notes and received source code
From f9eabe34bc9dfb0c66dee30ff3b496efe5d8026f Mon Sep 17 00:00:00 2001
From: Peter Mosmans
Date: Thu, 24 Nov 2016 10:22:24 +1000
Subject: [PATCH 10/14] Use standard image for invoices
---
xml/xslt/styles_inv.xslt | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/xml/xslt/styles_inv.xslt b/xml/xslt/styles_inv.xslt
index 31e4c06..cf66bfc 100644
--- a/xml/xslt/styles_inv.xslt
+++ b/xml/xslt/styles_inv.xslt
@@ -67,7 +67,7 @@
0cm
0cm
- url(../graphics/logo_alt.png)
+ url(../graphics/logo.png)
30mm
scale-to-fit
scale-to-fit
@@ -104,4 +104,4 @@
#EEEEEE
-
\ No newline at end of file
+
From 13a5a095b69b3608ed238e40d50d50a86ed3544a Mon Sep 17 00:00:00 2001
From: Peter Mosmans
Date: Thu, 24 Nov 2016 10:56:13 +1000
Subject: [PATCH 11/14] Beautified logging based on message type
Initialize speller only once per run
---
chatops/python/validate_report.py | 63 ++++++++++++++++++++-----------
1 file changed, 40 insertions(+), 23 deletions(-)
diff --git a/chatops/python/validate_report.py b/chatops/python/validate_report.py
index 0525db5..720acd5 100644
--- a/chatops/python/validate_report.py
+++ b/chatops/python/validate_report.py
@@ -50,6 +50,7 @@ NOT_CAPITALIZED = ['a', 'an', 'and', 'as', 'at', 'but', 'by', 'for', 'in',
'jQuery', 'jQuery-UI', 'nor', 'of', 'on', 'or', 'the', 'to',
'up']
SNIPPETDIR = 'snippets/'
+STATUS = 25 # loglevel for 'generic' status messages
TEMPLATEDIR = 'templates/'
OFFERTE = '/offerte.xml'
REPORT = '/report.xml'
@@ -62,8 +63,29 @@ if DOCBUILDER:
import proxy_vagrant
try:
import aspell
-except:
- print('[-] aspell not installed: spelling not available')
+except ImportError:
+ print('[-] aspell not installed: spelling not available',)
+
+
+class LogFormatter(logging.Formatter):
+ """
+ Format log messages according to their type.
+ """
+ # DEBUG = (10) debug status messages
+ # INFO = (20) verbose status messages
+ # STATUS = (25) generic status messages
+ # WARNING = (30) warning messages (= errors in validation)
+ # ERROR = (40) error messages (= program errors)
+ FORMATS = {logging.DEBUG :"DEBUG: %(module)s: %(lineno)d: %(message)s",
+ logging.INFO : "[*] %(message)s",
+ STATUS : "[+] %(message)s",
+ logging.WARN : "[-] %(message)s",
+ logging.ERROR : "ERROR: %(message)s",
+ 'DEFAULT' : "%(message)s"}
+
+ def format(self, record):
+ self._fmt = self.FORMATS.get(record.levelno, self.FORMATS['DEFAULT'])
+ return logging.Formatter.format(self, record)
def parse_arguments():
@@ -126,23 +148,22 @@ def initialize_speller():
except aspell.AspellSpellerError as exception:
logging.error('Could not initialize speller: %s', exception)
if speller:
- [logging.debug(i[0] + ' ' + str(i[2]) + '\n') for i in speller.ConfigKeys()]
+ [logging.debug('%s %s', i[0], i[2]) for i in speller.ConfigKeys()]
return speller
-def validate_spelling(tree, filename, options):
+def validate_spelling(tree, filename, options, speller):
"""
Check spelling of text within tags.
If options['learn'], then unknown words will be added to the dictionary.
"""
result = True
- speller = initialize_speller()
if not speller:
options['spelling'] = False
return result
try:
root = tree.getroot()
- for section in root.iter():
+ for section in root.iter():
if section.text and isinstance(section.tag, basestring) and \
section.tag not in ('a', 'code', 'monospace', 'pre'):
for word in re.findall('([a-zA-Z]+\'?[a-zA-Z]+)', section.text):
@@ -172,6 +193,9 @@ def all_files():
def open_editor(filename):
+ """
+ Open editor with file to edit.
+ """
if sys.platform in ('linux', 'linux2'):
editor = os.getenv('EDITOR')
if editor:
@@ -196,6 +220,7 @@ def validate_files(filenames, options):
findings = []
non_findings = []
scans = []
+ speller = initialize_speller()
for filename in filenames:
if (filename.lower().endswith('.xml') or
filename.lower().endswith('xml"')):
@@ -204,7 +229,7 @@ def validate_files(filenames, options):
(REPORT in filename and not options['no_report']):
masters.append(filename)
# try:
- type_result, xml_type = validate_xml(filename, options)
+ type_result, xml_type = validate_xml(filename, options, speller)
result = result and type_result
if 'non-finding' in xml_type:
non_findings.append(filename)
@@ -230,7 +255,7 @@ def validate_report():
return proxy_vagrant.execute_command(host, command)
-def validate_xml(filename, options):
+def validate_xml(filename, options, speller):
"""
Validates XML file by trying to parse it.
Returns True if the file validated successfully.
@@ -245,7 +270,7 @@ def validate_xml(filename, options):
with open(filename, 'rb') as xml_file:
xml.sax.parse(xml_file, xml.sax.ContentHandler())
tree = ElementTree.parse(filename, ElementTree.XMLParser(strip_cdata=False))
- type_result, xml_type = validate_type(tree, filename, options)
+ type_result, xml_type = validate_type(tree, filename, options, speller)
result = validate_long_lines(tree, filename, options) and result and type_result
if options['edit'] and not result:
open_editor(filename)
@@ -292,7 +317,7 @@ def capitalize(line):
return capitalized.strip()
-def validate_type(tree, filename, options):
+def validate_type(tree, filename, options, speller):
"""
Performs specific checks based on type.
Currently only finding and non-finding are supported.
@@ -304,7 +329,7 @@ def validate_type(tree, filename, options):
attributes = []
tags = []
if options['spelling']:
- result = validate_spelling(tree, filename, options)
+ result = validate_spelling(tree, filename, options, speller)
if xml_type == 'pentest_report':
attributes = ['findingCode']
if xml_type == 'finding':
@@ -525,23 +550,17 @@ def setup_logging(options):
"""
Set up loghandlers according to options.
"""
- # DEBUG = (10) debug status messages
- # INFO = (20) verbose status messages
- # WARNING = (30) warning messages (= errors in validation)
- # ERROR = (40) error messages (= program errors)
logger = logging.getLogger()
logger.setLevel(0)
console = logging.StreamHandler(stream=sys.stdout)
- console.setFormatter(logging.Formatter('%(levelname)s %(message)s',
- datefmt='%H:%M:%S'))
+ console.setFormatter(LogFormatter())
if options['debug']:
console.setLevel(logging.DEBUG)
else:
if options['verbose']:
- print('hi')
console.setLevel(logging.INFO)
else:
- logger.setLevel(logging.WARNING)
+ logger.setLevel(STATUS)
logger.addHandler(console)
@@ -563,17 +582,15 @@ def main():
logging.info('Validating all XML files...')
result = validate_files(all_files(), options)
if result:
- logging.info('Validation checks successful')
if DOCBUILDER:
logging.info('Validating report build...')
result = validate_report() and result
if result:
- logging.info('Validation successful. Good to go')
+ logging.log(STATUS, 'Validation checks successful. Good to go')
else:
logging.warning('Validation failed')
if options['spelling'] and options['learn']:
- print('[*] Don\'t forget to check the vocabulary file {0}'.
- format(VOCABULARY))
+ logging.log(STATUS('Don\'t forget to check the vocabulary file %s', VOCABULARY))
if __name__ == "__main__":
From 7b84dfaa25d01f7e4effe484a492a76d528a9ce3 Mon Sep 17 00:00:00 2001
From: skyanth
Date: Tue, 29 Nov 2016 16:31:17 +0100
Subject: [PATCH 12/14] Added execsummary option to report builder
---
chatops/python/docbuilder.py | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/chatops/python/docbuilder.py b/chatops/python/docbuilder.py
index 5da7c57..d96bab0 100644
--- a/chatops/python/docbuilder.py
+++ b/chatops/python/docbuilder.py
@@ -55,6 +55,9 @@ the Free Software Foundation, either version 3 of the License, or
help='overwrite output file if it already exists')
parser.add_argument('-date', action='store',
help='the invoice date')
+ parser.add_argument('-execsummary', action='store',
+ help="""create an executive summary as well as a report.
+ Default: no """)
parser.add_argument('--fop-config', action='store',
default='/etc/docbuilder/rosfop.xconf',
help="""fop configuration file (default
@@ -141,6 +144,8 @@ def to_fo(options):
cmd.append('INVOICE_NO=' + options['invoice'])
if options['date']:
cmd.append('DATE=' + options['date'])
+ if options['execsummary']:
+ cmd.append('EXEC_SUMMARY=' + options['execsummary'])
process = subprocess.Popen(cmd, stdout=PIPE, stderr=PIPE)
stdout, stderr = process.communicate()
print_output(stdout, stderr)
From 69a2c827f834e3e0706bde004f13243d5c9ca512 Mon Sep 17 00:00:00 2001
From: skyanth
Date: Tue, 29 Nov 2016 16:33:01 +0100
Subject: [PATCH 13/14] Clarified execsummary documentation
---
chatops/python/docbuilder.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/chatops/python/docbuilder.py b/chatops/python/docbuilder.py
index d96bab0..af4530a 100644
--- a/chatops/python/docbuilder.py
+++ b/chatops/python/docbuilder.py
@@ -56,8 +56,8 @@ the Free Software Foundation, either version 3 of the License, or
parser.add_argument('-date', action='store',
help='the invoice date')
parser.add_argument('-execsummary', action='store',
- help="""create an executive summary as well as a report.
- Default: no """)
+ help="""create an executive summary as well as a report (true/false).
+ Default: false """)
parser.add_argument('--fop-config', action='store',
default='/etc/docbuilder/rosfop.xconf',
help="""fop configuration file (default
From aad0e9be44e612fa1399d38e1971f8aef2996560 Mon Sep 17 00:00:00 2001
From: skyanth
Date: Tue, 29 Nov 2016 16:58:20 +0100
Subject: [PATCH 14/14] execsummary=true now also still builds report instead
of just summary
---
chatops/bash/handler_build | 1 +
chatops/python/docbuilder.py | 18 ++++++++++++++++++
2 files changed, 19 insertions(+)
diff --git a/chatops/bash/handler_build b/chatops/bash/handler_build
index 01cce2a..49452ec 100644
--- a/chatops/bash/handler_build
+++ b/chatops/bash/handler_build
@@ -113,6 +113,7 @@ build() {
add_to_repo() {
git add target/$TARGET-latest.pdf
git add target/waiver_?*.pdf &>/dev/null
+ git add target/execsummary.pdf &>/dev/null
git commit -q -m "$targetpdf proudly manufactured using ChatOps" &>/dev/null
git push -q >/dev/null
}
diff --git a/chatops/python/docbuilder.py b/chatops/python/docbuilder.py
index af4530a..a1c85d6 100644
--- a/chatops/python/docbuilder.py
+++ b/chatops/python/docbuilder.py
@@ -32,6 +32,7 @@ import textwrap
GITREV = 'GITREV' # Magic tag which gets replaced by the git short commit hash
OFFERTE = 'generate_offerte.xsl' # XSL for generating waivers
WAIVER = 'waiver_' # prefix for waivers
+EXECSUMMARY = 'execsummary' # generating an executive summary instead of a report
def parse_arguments():
@@ -227,6 +228,23 @@ def main():
except OSError as exception:
print_exit('[-] ERR: {0}'.format(exception.strerror),
exception.errno)
+ if options['execsummary'] == 'true': # we're generating a summary as well as a report
+ report_output = options['output']
+ verboseprint('generating additional executive summary')
+ output_dir = os.path.dirname(options['output'])
+ fop_dir = os.path.dirname(options['fop'])
+ try:
+ for fop in [os.path.splitext(x)[0] for x in
+ os.listdir(fop_dir) if x.endswith('fo')]:
+ if EXECSUMMARY in fop:
+ options['output'] = output_dir + os.sep + fop + '.pdf'
+ else:
+ options['output'] = report_output
+ options['fop'] = fop_dir + os.sep + fop + '.fo'
+ result = to_pdf(options) and result
+ except OSError as exception:
+ print_exit('[-] ERR: {0}'.format(exception.strerror),
+ exception.errno)
else:
result = to_pdf(options)