[PATCH 04/25] Added testcheck.py to shared/oval/

Shawn Wells shawn at redhat.com
Sat Dec 14 01:57:57 UTC 2013


-------------- next part --------------
>From fc6a9ce73035e078374cec25666dadb8fb305a1e Mon Sep 17 00:00:00 2001
From: Shawn Wells <shawn at redhat.com>
Date: Sun, 22 Dec 2013 14:48:47 -0500
Subject: [PATCH 04/25] Added testcheck.py to shared/oval/

Signed-off-by: Shawn Wells <shawn at redhat.com>
---
:000000 100644 0000000... ef052c6... A	shared/oval/.gitignore
:000000 100755 0000000... 77f078a... A	shared/oval/idtranslate.py
:000000 100644 0000000... c64edce... A	shared/oval/idtranslate.pyc
:000000 100755 0000000... 72e724e... A	shared/oval/testcheck.py
 shared/oval/.gitignore      |   1 +
 shared/oval/idtranslate.py  | 138 ++++++++++++++++++++++++++++++++++++++++++++
 shared/oval/idtranslate.pyc | Bin 0 -> 5083 bytes
 shared/oval/testcheck.py    | 124 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 263 insertions(+)

diff --git a/shared/oval/.gitignore b/shared/oval/.gitignore
new file mode 100644
index 0000000..ef052c6
--- /dev/null
+++ b/shared/oval/.gitignore
@@ -0,0 +1 @@
+testids.ini
diff --git a/shared/oval/idtranslate.py b/shared/oval/idtranslate.py
new file mode 100755
index 0000000..77f078a
--- /dev/null
+++ b/shared/oval/idtranslate.py
@@ -0,0 +1,138 @@
+import ConfigParser, sys
+import lxml.etree as ET 
+
+# This class is designed to handle the mapping of meaningful, human-readable
+# names to IDs in the formats required by the SCAP checking systems, such as
+# OVAL and OCIL.  
+
+oval_ns = "http://oval.mitre.org/XMLSchema/oval-definitions-5"
+oval_cs = "http://oval.mitre.org/XMLSchema/oval-definitions-5"
+
+ocil_ns = "http://scap.nist.gov/schema/ocil/2.0"
+ocil_cs = "http://scap.nist.gov/schema/ocil/2"
+
+ovaltag_to_abbrev = {
+	'definition' : 'def',
+	'criteria' : 'crit',
+	'test' : 'tst',
+	'object' : 'obj',
+	'state' : 'ste',
+	'variable' : 'var',
+}
+
+ociltag_to_abbrev = {
+	'questionnaire' : 'questionnaire',
+	'action' : 'testaction',
+	'question' : 'question',
+	'artifact' : 'artifact',
+	'variable' : 'variable',
+}
+
+ovalrefattr_to_tag = {
+	"definition_ref" : "definition",
+	"test_ref" : "test",
+	"object_ref" : "object",
+	"state_ref" : "state",
+	"var_ref" : "variable",
+}
+
+ocilrefattr_to_tag = {
+	"question_ref" : "question",
+}
+
+ocilrefchild_to_tag = {
+	"test_action_ref" : "action",
+}
+
+def split_namespace(tag):
+	# returns a tuple of (namespace,name) removing any fragment id from namespace
+	if tag[:1] == "{":
+		namespace, name = tag[1:].split("}", 1)
+		return namespace.split("#")[0], name
+	else:
+		return (None,tag)
+
+def namespace_to_prefix(tag):
+	namespace, name = split_namespace(tag)
+	if namespace == ocil_ns:
+		return "ocil"
+	if namespace == oval_ns:
+		return "oval"
+	sys.exit("Error: unknown checksystem referenced in tag : %s" % tag)
+
+def tagname_to_abbrev(tag):
+	namespace, tag = split_namespace(tag)
+	if tag == "extend_definition":
+		return tag
+	# grab the last part of the tag name to determine its type
+	tag = tag.rsplit("_", 1)[-1]
+	if namespace == ocil_ns:
+		return ociltag_to_abbrev[tag]
+	if namespace == oval_ns:
+		return ovaltag_to_abbrev[tag]
+	sys.exit("Error: unknown checksystem referenced in tag : %s" % tag)
+
+class idtranslator:
+	def __init__(self, fname, content_id):
+		self.fname = fname 
+		self.content_id = content_id
+		self.config = ConfigParser.ConfigParser()
+		f = self.config.read(fname)
+		if len(f) == 0:
+			self.__setup()
+
+	def __get_next_id(self):
+		i = self.config.getint("general", "next_id")
+		n = "%d" % (i + 1)
+		self.config.set("general", "next_id", n)
+		return i
+
+	def save(self):
+		fd = open(self.fname, "wb")
+		self.config.write(fd)
+
+	def __setup(self):
+		self.config.add_section("general")
+		self.config.set("general", "next_id", "100")
+		self.config.add_section("assigned")
+
+	def assign_id(self, tagname, name):
+		i = None
+		try:
+			i = self.config.getint("assigned", name)
+		except:
+			i = self.__get_next_id()
+			self.config.set("assigned", name, str(i))
+
+		str_id = "%s:%s:%s:%d" % (namespace_to_prefix(tagname), self.content_id, tagname_to_abbrev(tagname), i)
+		return str_id
+
+	def translate(self, tree, store_defname=False):
+		for element in tree.getiterator():
+			idname = element.get("id")
+			if idname:
+				# store the old name if requested (for OVAL definitions)
+				if store_defname and element.tag == "{" + oval_ns + "}definition":
+					metadata = element.find("{" + oval_ns + "}metadata")
+					if metadata is None:
+						metadata = ET.SubElement(element, "metadata")
+					defnam = ET.SubElement(metadata, "reference", ref_id=idname, source=self.content_id) 
+				# set the element to the new identifier 
+				element.set("id", self.assign_id(element.tag, idname))
+				#continue
+			if element.tag == "{" + oval_ns + "}filter":
+				element.text = self.assign_id("{" + oval_ns + "}state", element.text)
+				continue
+			for attr in element.keys():
+				if attr in ovalrefattr_to_tag.keys():
+					element.set(attr,self.assign_id( "{" + oval_ns + "}" + ovalrefattr_to_tag[attr], element.get(attr)))
+				if attr in ocilrefattr_to_tag.keys():
+					element.set(attr, self.assign_id("{" + ocil_ns + "}" + ocilrefattr_to_tag[attr], element.get(attr)))
+			if element.tag == "{" + ocil_ns + "}test_action_ref":
+					element.text = self.assign_id("{" + ocil_ns + "}action", element.text)
+
+		self.save()
+		# note: the ini file is not tracked by git, see .gitignore
+		return tree
+
+
diff --git a/shared/oval/idtranslate.pyc b/shared/oval/idtranslate.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..c64edce37a86aa1bfad41860c6002474258d203f
GIT binary patch
literal 5083
zcmb_f-Etg96+S(?TJ7pTRxDY;jyJYNwg72uS49LPAi;4`6pnyVDh`4$jCNYmNUK?S
zy7go5UfEB<9d|qcRXhMM!4vQTTyP2BcY3ueM5v-b(oRqJnbW7w`OZ&wSN=9V at y8GU
z6nA9sSHb%OJZ{>EWcV5Bifj%0Mz+j3J(B&3Y*i(TWNS>@nq;7iOIDSwy5tywUX!&9
zq&i*=$tLiclxzyGX~|~rnw4x$*0vgwgZT~q*0O7o&Exf^;J21t7yQ=1rHm8G2-ypu
zO-Qzg*OX*8 at S2fqDKNeTiIb8;SIGDp22(nim+U46SoxN`hFzHOwsxSzZS7!@ret>{
zdxyhUB0t}PPDVCccL7WO5BzPohv at EkfApx`?wzFF)x+GEcC}aTw!irF>1Joo9;W(X
zC9^wuk^8(?xRv+Zz0ow+Nsm^G-1*hr-bvdHrgZXd`{C++cjv!i^mG<h at Dt%ZSjks0
z?3B6p^+Cs$d8*9bdHw1wI-K3x-uJceww*w7-uf|+oKMjs(@9#YD7^D at yKDV4h|iB9
z19lZ at URu?FLemauDss at J4(Gfo1;X+jeDpK;GQuY*VF;NiMhCPC`av%pHZWA3bTp0;
z^wItl`sYh1VHN}x6LcW0gK!oa!{;#`_cJsvp at ESm0{9 at 3^6_ANdmrQqzr2d%myz_1
z^dos`g!HPsLQsv#(#uG8BH7GT%AmK|BA6QpJ1D^Bx7zl#y_<s|t%%<g;G-^lL}zXE
z3frP$!Aa?^r?EwPXx&lTvC6|y3slj at t)tfl0PWM$)ApV}>>`HJqZMa6$MF1%mEGe!
zvu(GRmNwH+Z0DIT)53M()zzaHo)|f5kPO#plSCItG-qy_#pvHb`vf1oS_~8}LIVp4
zA at T;P0;qg|^dZZ_Cd}GLnWzxo1xz#mZL_78t8G2Redr*W+ykufq%3>oqvmmOQ1niV
zCeovG;9ej!51VkNEp5 at USu-!1KHY6TYA(AL5sjNvkD)<{N#Q~tLfI$4l)-iFS?(3_
z_!dU-+iY&5xk`lRA#aFn;(N&vRL{@84YFg%in(T{OjRF6nvpRK&tnWOBYhsQ0cn7_
ziDw_-7!h0qE249$53V8pPZ?5RT2h}>)knW(_$du}x{u1Nqmf at Ug#8;>-=29}WXUK=
zHI5SvZ>@y?qpuia!B<?X)G&<i(qOKt(U9&Ev2=U8v?uYs;U~Bf9>4Hu8K2^>qtUz?
zdGjhANu{tVeK}hB2Ozp at Xa;VK7U0ObKAzqkrCYD;kd1%z at DK6057AicKk%LCwgcZ8
z?V#>N+R=o04Ib=@Ri)I#s<&Qa6Rt}ficN<R!;q%z$9UZ5Xb=JLaDomB7djdc`w{mu
z4mBpQc_S;qiHz)5G$;^6&?uyGOwRopr<ekTk15MFHbNO=mT4K=AuhTBbWr(i;S-on
z1RnQ_oqYGFY3XdKI|9Cgp!rwYG}DCaV#1qX=A=P+>Xk|2tUo@|3Zd-Ic6VZyr}#dX
zWo6yDN)Iz2lZ5+ck~~F!ke?0HFtf<gYew_)9BD=Qdtf6#Aptc9k$~7LSmw}HWpRPK
zMqp9*!m)72tBM#fY-+{Y&<eF{3tJ+xiD`kP0~n4_FK3!+p-}P6p)l at RpBIC@+77DN
z8b1=2T-)L*!QpP7Bv>^W==K>1VV^M9&5T(H=ulxIr06gsL-k^L(v1|*5DYyuhM)`E
zfW{QI3z5_9k;i*Swg?_qyII{&v9Z~Z=4vjd>||GIDbvWMCl<$DaU3wW)%Apy1U2pv
zIu~7!oH3XD%yLXW4+BJx4Z&dAvJrm=ZA?j;1`qDv4~HY?^4-E_7hFCGo;1sl5_-0Z
z*D-EUpO`3IrTGlMLF)YqUB}`qW{wV~W2rYE#o#ySpd_GfyjW5&a5~Z;XM`gUD)Ovo
zi!llTz))7g0X|eV#6mQxIE1P&@&ytE5gvkryyF5;2E&T%RAr%$f>lNCP at j$XW3-O=
zEW1a8U)JK$DZa^ukrRIxjeiTxr3!N)o)yw?Jn&`wE@!dK#4BjRxkBSjD_+<J^sErG
z1ZYM&Uqbp-x`IZe8VeBI!NAR-5mPf2vxH~LG^6F<mOAKUSGW8ffpPX%))y2efd0{!
ze=+dIOO*PMhbZ+5Vfklzp!~glg5!XEMHUgZi#%Kevfk{JjADi$@8h6=%}C^+E at hvl
z!$S~_0|Z?@CfFthM7{Rm)(2<d;zwWB!4vgs<e at gW35I$wG0*^<5P}~!8*+ at 4Y6PW1
zI^n`M&~-u<$v4SK=p>W!e466V{-E=xg8jdfKGZ-YP0PNL4r)?<X at U-*Q at 4@KNm&FV
z$V)04DvonYyr3B*&0LT){Z*1?fg~l({6|U8rwxA3Ms{+_RIn544|O7W`m5}Osn5tZ
zM=QgAGJ_!4&_bGL at eK?#HTt8|n`4;tv00~Cipw1XXE at -e;mKNq8Y89*i-7ALmmTYv
z0R0^t)orP at p|97mc!?Yg&;F%5SC|m)U at bjFF;}^LK|<<#rRE&Q;n;Q$A9c6Kl{wQ4
zR%4!griY8o<LxJ1dx+ygNX~U|$Df{0 at z^zW?t#S#pT{!Z%V9$5k()S4;`|oKxETB^
zSr4A^N0`zgB3e~d6t48)s_USt<tbQCIz+(+O%$9wBRT#F$T|*uDuIh%byYY&C0Rte
zxNo2lGmleBExKhEQ5UY8d(oX}(KJyj=COUfk7pfU-i;<At&QsUL~ngbqR=MEVJ|!G
z+9ZkJhq(AhYzRpF9vcOjh5ut*&TPDm-pDBJ{ol9Icojl_j7JY%HPfg!YK>}RtT7o@
zqC?{cY?jfe(%rMe?y6NEQ8(?ypOZ!7h+bj{BpnxS7E0i)5QJ}$?VD`2*!%*G=WUHQ
z4+KYNFYji9pwVke*b}%NsG?VGy?SIl_~858+1&?dZkX9x4Q}OAG2_GkiOOhnxzF)L
K1?bfqQ~w12&o?yy

literal 0
HcmV?d00001

diff --git a/shared/oval/testcheck.py b/shared/oval/testcheck.py
new file mode 100755
index 0000000..72e724e
--- /dev/null
+++ b/shared/oval/testcheck.py
@@ -0,0 +1,124 @@
+#!/usr/bin/python
+
+import sys, os, tempfile, subprocess, platform
+import idtranslate
+import lxml.etree as ET
+
+header = '''<?xml version="1.0" encoding="UTF-8"?>
+<oval_definitions
+	xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5"
+    xmlns:unix="http://oval.mitre.org/XMLSchema/oval-definitions-5#unix"
+    xmlns:ind="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent"
+    xmlns:linux="http://oval.mitre.org/XMLSchema/oval-definitions-5#linux"
+    xmlns:oval="http://oval.mitre.org/XMLSchema/oval-common-5"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://oval.mitre.org/XMLSchema/oval-definitions-5#unix unix-definitions-schema.xsd
+        http://oval.mitre.org/XMLSchema/oval-definitions-5#independent independent-definitions-schema.xsd
+        http://oval.mitre.org/XMLSchema/oval-definitions-5#linux linux-definitions-schema.xsd
+        http://oval.mitre.org/XMLSchema/oval-definitions-5 oval-definitions-schema.xsd
+        http://oval.mitre.org/XMLSchema/oval-common-5 oval-common-schema.xsd">
+       <generator>
+        <oval:product_name>testcheck.py</oval:product_name>
+        <oval:product_version>0.0.1</oval:product_version>
+        <oval:schema_version>5.10</oval:schema_version>
+        <oval:timestamp>2011-09-23T13:44:00</oval:timestamp>
+    </generator>'''
+footer = '</oval_definitions>'
+
+ovalns = "{http://oval.mitre.org/XMLSchema/oval-definitions-5}"
+
+# globals, to make recursion easier in case we encounter extend_definition
+definitions = ET.Element("definitions")
+tests = ET.Element("tests")
+objects = ET.Element("objects")
+states = ET.Element("states")
+variables = ET.Element("variables")
+
+# add oval elements to the global Elements defined above
+def add_oval_elements(body):
+    tree = ET.fromstring(header + body + footer)
+    tree = replace_external_vars(tree)
+    # parse new file(string) as an etree, so we can arrange elements appropriately 
+    for childnode in tree.findall("./" + ovalns + "def-group/*"):
+        # print "childnode.tag is " + childnode.tag
+        if childnode.tag is ET.Comment: continue 
+        if childnode.tag == ( ovalns + "definition"):
+            definitions.append(childnode)
+            defname = childnode.get("id")
+            # extend_definition is a special case: must include a whole other definition
+            for defchild in childnode.findall(".//" + ovalns + "extend_definition"):
+                defid = defchild.get("definition_ref")            
+                includedbody = read_ovaldefgroup_file(defid+".xml")
+                # recursively add the elements in the other file
+                add_oval_elements(includedbody)
+        if childnode.tag.endswith("_test"): tests.append(childnode)
+        if childnode.tag.endswith("_object"): objects.append(childnode)
+        if childnode.tag.endswith("_state"): states.append(childnode)
+        if childnode.tag.endswith("_variable"): variables.append(childnode)
+    return defname
+
+# replace external_variables with local_variables, so the definition can be tested
+# independently of an XCCDF file
+def replace_external_vars(tree):
+    # external_variable is a special case: we turn it into a local_variable so we can test
+    for node in tree.findall(".//"+ovalns+"external_variable"):
+        print "external_variable with id : " + node.get("id") 
+        extvar_id = node.get("id")
+        #for envkey, envval in os.environ.iteritems():
+        #    print envkey + " = " + envval
+        #sys.exit()
+        if extvar_id not in os.environ.keys():
+            sys.exit("external_variable specified, but no value provided via environment variable")
+        node.tag = ovalns + "local_variable"    # replace tag name: external -> local
+        literal = ET.Element("literal_component")
+        literal.text = os.environ[extvar_id]
+        node.append(literal)
+        # TODO: assignment of external_variable via environment vars, for testing
+    return tree
+
+
+def read_ovaldefgroup_file(testfile):
+    with open( testfile, 'r') as f:
+        body = f.read()
+    return body
+
+def main():
+    global definitions
+    global tests
+    global objects
+    global states
+    global variables
+
+    if len(sys.argv) < 2:
+        print "Provide the name of an XML file, which contains the definition to test."
+        sys.exit(1)
+
+    for testfile in sys.argv[1:]:
+        body = read_ovaldefgroup_file(testfile)
+        defname = add_oval_elements(body)
+        ovaltree = ET.fromstring(header + footer)
+        # append each major element type, if it has subelements
+        for element in [definitions, tests, objects, states, variables]:
+            if element.getchildren():
+                ovaltree.append(element)
+        # re-map all the element ids from meaningful names to meaningless numbers
+        testtranslator = idtranslate.idtranslator("testids.ini", "scap-security-guide.testing")
+        ovaltree = testtranslator.translate(ovaltree)
+        (ovalfile, fname) = tempfile.mkstemp(prefix=defname,suffix=".xml")
+        os.write(ovalfile, ET.tostring(ovaltree))
+        os.close(ovalfile)
+        print "Evaluating with OVAL tempfile : " + fname
+        print "Writing results to : " + fname + "-results"
+        subprocess.call("oscap oval eval --results "+ fname + "-results " + fname, shell=True)
+        # perhaps delete tempfile?
+        definitions = ET.Element("definitions")
+        tests = ET.Element("tests")
+        objects = ET.Element("objects")
+        states = ET.Element("states")
+        variables = ET.Element("variables")
+
+    sys.exit(0)
+
+if __name__ == "__main__":
+    main()
+
-- 
1.8.3.1



More information about the scap-security-guide mailing list