changeset 0:e18b61a73a68

Initial Release
author Benoît Allard <benoit.allard@greenbone.net>
date Tue, 23 Sep 2014 15:19:14 +0200
parents
children d47e1164740f
files CHANGES LICENSE MANIFEST.in README.txt farolluz/__init__.py farolluz/cvrf.py farolluz/parsers/__init__.py farolluz/parsers/cvrf.py farolluz/py2.py farolluz/renderer.py farolluz/templates/cvrf.j2 farolluz/templates/nasl.j2 farolluz/templates/nasl_core.j2 farolluz/templates/oval.j2 farolluz/templates/oval_core.j2 farolluz/utils.py parse_cvrf render setup.py
diffstat 19 files changed, 2761 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CHANGES	Tue Sep 23 15:19:14 2014 +0200
@@ -0,0 +1,14 @@
+FarolLuz 0.1 (2014-09-23)
+=========================
+
+This is the first release of FarolLuz. FarolLuz is a set of library /
+utilities to manipulate Security Advisories. It is part of Farol, a Security
+Advisory Management Platform.
+
+It has the following features:
+
+- Parsing of CVRF Documents
+- Generation of CVRF Documents
+- Generation of RedHat LSC as NASL scripts
+- Various utility methods on the CVRF objects
+- Experimental Generation of RedHat LSC as OVAL scripts
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LICENSE	Tue Sep 23 15:19:14 2014 +0200
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MANIFEST.in	Tue Sep 23 15:19:14 2014 +0200
@@ -0,0 +1,1 @@
+include farolluz/templates/*.j2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/README.txt	Tue Sep 23 15:19:14 2014 +0200
@@ -0,0 +1,33 @@
+==========
+ FarolLuz
+==========
+
+-------------------------------------------
+A Utility to manipulate Security Advisories
+-------------------------------------------
+
+:version: 0.1
+:license: GPLv2+
+
+Introduction
+------------
+
+FarolLuz is a set of library / utilities to manipulate security advisories. It
+is part of Farol, a Security Advisory Management Platform.
+
+Main features
+-------------
+
+* Read CVRF advisories
+* Write CVRF Advisories
+* Write NASL scripts
+* Write OVAL Advisories (experimental)
+
+Installation
+------------
+
+To install ``farolluz``, use the pip package manager (preferably inside a
+virtualenv)::
+
+    pip install farolluz
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/farolluz/__init__.py	Tue Sep 23 15:19:14 2014 +0200
@@ -0,0 +1,31 @@
+# -*- encoding: utf-8 -*-
+# Description:
+# A utility to manipulate Security Advisories
+#
+# Authors:
+# Benoît Allard <benoit.allard@greenbone.net>
+#
+# Copyright:
+# Copyright (C) 2014 Greenbone Networks GmbH
+#
+# 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 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+
+"""\
+Farol Luz: A utility to manipulate security advisories
+
+This is part of Farol: A Security Advisory Management Platform.
+"""
+
+__version__ = '0.1'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/farolluz/cvrf.py	Tue Sep 23 15:19:14 2014 +0200
@@ -0,0 +1,1016 @@
+# -*- coding: utf-8 -*-
+#
+# Authors:
+# Benoît Allard <benoit.allard@greenbone.net>
+#
+# Copyright:
+# Copyright (C) 2014 Greenbone Networks GmbH
+#
+# 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 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+
+"""\
+Objects related to CVRF Documents
+"""
+
+class ValidationError(Exception): pass
+
+class CVRFPublisher(object):
+    TYPES = ('Vendor', 'Discoverer', 'Coordinator', 'User', 'Other')
+    def __init__(self, _type, vendorid=None):
+        self._type = _type
+        self._vendorid = vendorid
+        self._contact = None
+        self._authority = None
+
+    def setContact(self, contact):
+        self._contact = contact
+
+    def setAuthority(self, authority):
+        self._authority = authority
+
+    def validate(self):
+        if not self._type:
+            raise ValidationError('Document Publisher needs to have a type')
+        if self._type not in self.TYPES:
+            raise ValidationError('Document Publisher Type needs to be one of %s' % ', '.join(self.TYPES))
+
+    def __str__(self):
+        s = 'CVRFPublisher: %s' % self._type
+        if self._vendorid is not None:
+            s += ' ID: %s' % self._vendorid
+        if self._contact is not None:
+            s += ' Contact: "%s"' % self._contact
+        if self._authority is not None:
+            s += ' Authority: "%s"' % self._authority
+        return s
+
+
+class CVRFTrackingID(object):
+    def __init__(self, _id):
+        self._id = _id
+        self._aliases = []
+
+    def addAlias(self, alias):
+        self._aliases.append(alias)
+
+    def validate(self):
+        if not self._id:
+            raise ValidationError('Document ID cannot be left empty')
+
+    def __str__(self):
+        if self._aliases:
+            return "%s (%s)" % (self._id, ', '.join(self._aliases))
+        return self._id
+
+
+class CVRFTracking(object):
+    STATUSES = ('Draft', 'Interim', 'Final')
+    def __init__(self, _id, status, version, initial, current):
+        self._identification = _id
+        self._status = status
+        self._version = version
+        self._history = []
+        self._initialDate = initial
+        self._currentDate = current
+        self._generator = None
+
+    def addRevision(self, revision):
+        self._history.append(revision)
+
+    def setGenerator(self, generator):
+        self._generator = generator
+
+    def validate(self):
+        if self._identification is None:
+            raise ValidationError('Document Tracking needs to have an Identification')
+        self._identification.validate()
+        if not self._status:
+            raise ValidationError('Document status must be set')
+        if self._status not in self.STATUSES:
+            raise ValidationError('Document Status must be one of %s' % ', '.join(self.STATUSES))
+        if not self._version:
+            raise ValidationError('Document Version must be set')
+        if len(self._version) > 4:
+            raise ValidationError('Document Version must be comprised between `nn` and `nn.nn.nn.nn`')
+        if not self._history:
+            raise ValidationError('Document must have at least a revision')
+        if not self._initialDate:
+            raise ValidationError('Document must have an initial Release date set')
+        prev_date = self._initialDate
+        if self._history[0]._date < self._initialDate:
+            # Documents could have revisions before being released
+            prev_date = self._history[0]._date
+        prev = ()
+        for revision in self._history:
+            revision.validate()
+            if revision._number <= prev:
+                raise ValidationError('Revision numbers must always be increasing')
+            if revision._date < prev_date:
+                raise ValidationError('Revision dates must always be increasing')
+            prev = revision._number
+            prev_date = revision._date
+        if not self._currentDate:
+            raise ValidationError('Document must have a Current Release Date set')
+        if self._currentDate != self._history[-1]._date:
+            raise ValidationError('Current Release Date must be the same as the Date from the last Revision')
+        if self._initialDate > self._currentDate:
+            raise ValidationError('Initial date must not be after current Date')
+        if self._version != self._history[-1]._number:
+            raise ValidationError('Document version must be the same as the number of the last Revision')
+
+    def __str__(self):
+        s = "ID: %s" % self._identification
+        s += " Status: %s" % self._status
+        s += " v%s" % '.'.join('%d' % i for i in self._version)
+        s += " %d revisions" % len(self._history)
+        s += " Initial release: %s" % self._initialDate.isoformat()
+        return s
+
+
+class CVRFRevision(object):
+    def __init__(self, number, date, description):
+        self._number = number
+        self._date = date
+        self._description = description
+
+    def validate(self):
+        if not self._number:
+            raise ValidationError('A Revision must have a Number')
+        if not self._date:
+            raise ValidationError('A Revision must have a Date')
+        if not self._description:
+            raise ValidationError('A Revision must have a Description')
+
+class CVRFGenerator(object):
+    def __init__(self):
+        self._engine = None
+        self._date = None
+
+    def setEngine(self, engine):
+        self._engine = engine
+
+    def setDate(self, date):
+        self._date = date
+
+    def validate(self):
+        if (not self._engine) and (not self._date):
+            raise ValidationError('The Generator must have at least an Engine or a Date')
+
+
+class CVRFNote(object):
+    TYPES = ('General', 'Details', 'Description', 'Summary', 'FAQ',
+             'Legal Disclaimer', 'Other')
+    def __init__(self, _type, ordinal, note, title=None, audience=None):
+        self._type = _type
+        self._ordinal = ordinal
+        self._note = note
+        self._title = title
+        self._audience = audience
+
+    def getTitle(self):
+        """ returns something that can be used as a title """
+        if self._title is None:
+            return "%s (#%d)" % (self._type, self._ordinal)
+        return "%s (%s)" % (self._title, self._type)
+
+    def validate(self):
+        if not self._type:
+            raise ValidationError('A Note needs to have a Type set')
+        if self._type not in self.TYPES:
+            raise ValidationError('A Note Type needs to be one of %s' % ', '.join(self.TYPES))
+        if self._ordinal < 0:
+            raise ValidationError('A Note ordinal must be a positive integer')
+        if not self._note:
+            raise ValidationError('A Note must contain some text')
+
+
+    def __str__(self):
+        return self._note
+
+
+class CVRFReference(object):
+    TYPES = ('Self', 'External')
+    def __init__(self, url, description, _type=None):
+        self._url = url
+        self._description = description
+        self._type = _type
+
+    def validate(self):
+        if (self._type is not None) and (self._type not in self.TYPES):
+            raise ValidationError('If a Reference type is set, it mist be one of %s' % ', '.join(self.TYPES))
+        if not self._url:
+            raise ValidationError('A Reference must contain an URL')
+        if not self._description:
+            raise ValidationError('A Reference must contain a description')
+
+
+class CVRFAcknowledgment(object):
+    def __init__(self, name=None, organization=None, description=None,
+                 url=None):
+        self._name = name
+        self._organization = organization
+        self._description = description
+        self._url = url
+
+    def getTitle(self):
+        return "%s - %s" % (self._name, self._organization)
+
+    def validate(self):
+        if (not self._name) and (not self._organization) and (not self._description):
+            raise ValidationError('An Acknowledgment must have at least a Name, an Organization or a Description')
+
+
+class CVRFProductTree(object):
+    def __init__(self):
+        # All the branches, they can be order with their `parent` attribute
+        self._branches = []
+        self._groups = []
+        self._relationships = []
+        self._products = []
+        self._groups = []
+
+    def addBranch(self, branch):
+        parent = self.getBranch(branch.getParent().getPath())
+        if parent is self:
+            self._branches.append(branch)
+        else:
+            parent._childs.append(branch)
+
+    def addProduct(self, product):
+        if product not in self._products:
+            self._products.append(product)
+        if product._parent is not self:
+            product._parent._product = product
+
+    def addRelationship(self, rel):
+        self._relationships.append(rel)
+
+    def addGroup(self, group):
+        self._groups.append(group)
+
+    def getProductForID(self, productid):
+        for product in self._products:
+            if product._productid == productid:
+                return product
+        raise KeyError(productid)
+
+    def getGroupForID(self, groupid):
+        for group in self._groups:
+            if group._groupid == groupid:
+                return group
+        raise KeyError(groupid)
+
+    def decomposeProduct(self, productid):
+        """ In case of product defined as a relationship (product X installed
+        on OS Y), this gives us the following tuple: (OS, product). """
+        product = self.getProductForID(productid)
+        parent = product._parent
+        if parent is None:
+            return (None, None)
+        if not isinstance(parent, CVRFRelationship):
+            return (None, None)
+        relationtype = parent._relationtype.replace(' ', '').lower()
+        if relationtype not in ('defaultcomponentof', 'installedon'):
+            return (None, None)
+        return (
+            self.getProductForID(parent._relatestoproductreference),
+            self.getProductForID(parent._productreference)
+        )
+
+    def getBranch(self, path):
+        if len(path) == 0:
+            return self
+        branches = self._branches
+        node = None
+        for idx in path:
+            node = branches[idx]
+            branches = node._childs
+        return node
+
+    def getBranches(self):
+        for branch in self._branches:
+            yield branch
+            for sub_branch in branch.getBranches():
+                yield sub_branch
+
+    def getPath(self):
+        return ()
+
+    def getNameOfRelationship(self, relationship):
+        if relationship is None:
+            return ''
+        return ' '.join((self.getProductForID(relationship._productreference)._name, 'as',
+                relationship._relationtype.lower(),
+                self.getProductForID(relationship._relatestoproductreference)._name))
+
+    def getOrphanedBranches(self, product=None):
+        """ The branches that could accept `product` as Product Definition """
+        white_list = []
+        if product is not None:
+            white_list = [product._parent]
+        for branch in self.getBranches():
+            if (branch in white_list) or branch.isOrphaned():
+                yield branch
+
+    def getNotTerminalBranches(self, b2=None):
+        """\
+        The branches that could accept `b2` as new sub-branches
+        Note that b2 and all its sub-branches cannot be listed
+        """
+        black_list = []
+        if b2 is not None:
+            black_list = [b2] + list(b2.getBranches())
+        for branch in self.getBranches():
+            if branch in black_list:
+                continue
+            if branch._product is None:
+                yield branch
+
+    def getOrphanedRelationships(self, product=None):
+        """ The relationships that need a product defninition """
+        white_list = []
+        if product is not None:
+            white_list = [product.getCurrentRelationship()]
+        for i, relationship in enumerate(self._relationships):
+            if (relationship in white_list) or relationship.isOrphaned():
+                yield (i, relationship)
+
+    def nbProducts(self):
+        """ Amount of 'raw' Products """
+        return len([p for p in self._products if p._parent is self])
+
+    def validate(self):
+        for branch in self._branches:
+            branch.validate()
+        productids = set()
+        for product in self._products:
+            product.validate()
+            if product._productid in productids:
+                raise ValidationError('Each ProductID must be unique (%s)' % product._productid)
+            productids.add(product._productid)
+        for relationship in self._relationships:
+            relationship.validate()
+            for productid in (relationship._productreference,
+                              relationship._relatestoproductreference):
+                if productid not in productids:
+                    raise ValidationError('ProductID %s is unknown' % productid)
+        groupids = set()
+        for group in self._groups:
+            group.validate()
+            if group._groupid in groupids:
+                raise ValidationError('Duplicated GroupID: %s' % group._groupid)
+            groupids.add(group._groupid)
+            for productid in group._productids:
+                if productid not in productids:
+                    raise ValidationError('ProductID %s is unknown' % productid)
+        return productids, groupids
+
+    def __str__(self):
+        return 'Products: %s' % '\n'.join(str(p) for p in self._products)
+
+
+class CVRFProductBranch(object):
+    TYPES = ('Vendor', 'Product Family', 'Product Name', 'Product Version',
+             'Patch Level', 'Service Pack', 'Architecture', 'Language',
+             'Legacy', 'Specification')
+    def __init__(self, _type, name, parentbranch):
+        self._type = _type
+        self._name = name
+        self._parentbranch = parentbranch
+        self._childs = []
+        self._product = None
+
+    def getParent(self):
+        return self._parentbranch
+
+    def getPath(self, string=False):
+        """ return the path to that branch element as a tuple """
+        if self.isRoot():
+            for i, b in enumerate(self._parentbranch._branches):
+                if b is self:
+                    if string:
+                        return '%d' % i
+                    return (i, )
+        else:
+            for i, b in enumerate(self._parentbranch._childs):
+                if b is self:
+                    if string:
+                        return '/'.join([self._parentbranch.getPath(string), '%d' % i])
+                    return self._parentbranch.getPath(string) + (i,)
+        if string:
+            return ''
+        return ()
+
+    def getTree(self):
+        """ this returns a list of tuples (type, name) leading to here"""
+        if self.isRoot():
+            return [(self._type, self._name)]
+        return self._parentbranch.getTree() + [(self._type, self._name)]
+
+    def getName(self):
+        return ' / '.join("%s: %s" % (type_, name) for type_, name in self.getTree())
+
+    def getParentPath(self):
+        """ return as string the path to the parent """
+        return '/'.join('%s' % p for p in self.getPath()[:-1])
+
+    def isRoot(self):
+        return isinstance(self._parentbranch, CVRFProductTree)
+
+    def isOrphaned(self):
+        """ Has no childs and no product """
+        return len(self._childs) == 0 and (self._product is None)
+
+    def getBranches(self):
+        for branch in self._childs:
+            yield branch
+            for sub_branch in branch.getBranches():
+                yield sub_branch
+
+    def unlink(self):
+        """ Unset our _parent, and remove us from the _parent._childs """
+        if self.isRoot():
+            self.getParent()._branches.remove(self)
+        else:
+            self.getParent()._childs.remove(self)
+        self._parentbranch = None
+
+    def validate(self):
+        if not self._type:
+            raise ValidationError('A Branch must have a Type')
+        if self._type not in self.TYPES:
+            raise ValidationError('A Branch Type must be one of %s' % ', '.join(self.TYPES))
+        if not self._name:
+            raise ValidationError('A Branch must have a Name')
+        for branch in self._childs:
+            branch.validate()
+        if self.isOrphaned():
+            raise ValidationError('A Branch must have at least a sub-product or sub-branches')
+
+    def __str__(self):
+        return "%s: %s" % (self._type, self._name)
+
+
+class CVRFFullProductName(object):
+    def __init__(self, productid, name, parent, cpe=None):
+        self._productid = productid
+        self._name = name
+        # Can be None (directly under the tree), a ProductBranch, or a
+        # Relationship
+        self._parent = parent
+        self._cpe = cpe
+
+    def isRoot(self):
+        return isinstance(self._parent, CVRFProductTree)
+
+    def isRelationship(self):
+        return isinstance(self._parent, CVRFRelationship)
+
+    def getTree(self):
+        if not isinstance(self._parent, CVRFProductBranch):
+            return []
+        return self._parent.getTree()
+
+    def getParentPath(self):
+        if self.isRoot() or self.isRelationship():
+            return ''
+        return self._parent.getPath(True)
+
+    def getCurrentRelationship(self):
+        if self.isRelationship():
+            return self._parent
+        return None
+
+    def unlink(self):
+        """ Unset our _parent, and remove us from the _parent._childs """
+        if self.isRoot():
+            self._parent._products.remove(self)
+        else:
+            self._parent._product = None
+        self._parent = None
+
+    def validate(self):
+        if not self._productid:
+            raise ValidationError('A Product must have a ProductID')
+        if not self._name:
+            raise ValidationError('A Product must have a Name')
+
+    def __str__(self):
+        return "%s (%s)" % (self._productid, self._name)
+
+
+class CVRFRelationship(object):
+    TYPES = ('Default Component Of', 'Optional Component Of',
+             'External Component Of', 'Installed On', 'Installed With')
+    def __init__(self, productref, reltype, relatestoproductref):
+        self._productreference = productref
+        self._relationtype = reltype
+        self._relatestoproductreference = relatestoproductref
+        self._product = None
+
+    def getParent(self):
+        """ All parent element of a FullProductName should implement that
+        method """
+        return None
+
+    def isOrphaned(self):
+        return self._product is None
+
+    def validate(self):
+        if not self._productreference:
+            raise ValidationError('A Relationship must have a Product Reference')
+        if not self._relationtype:
+            raise ValidationError('A Relationship must have a Relation Type')
+        if self._relationtype not in self.TYPES:
+            raise ValidationError('Relation Type must be one of %s' % ', '.join(self.TYPES))
+        if not self._relatestoproductreference:
+            raise ValidationError('A Relationship must have a "Relates To product Reference"')
+        if self._productreference == self._relatestoproductreference:
+            raise ValidationError('A Relationship cannot reference twice the same Product')
+
+
+class CVRFGroup(object):
+    def __init__(self, groupid):
+        self._groupid = groupid
+        self._description = None
+        self._productids = []
+
+    def setDescription(self, description):
+        self._description = description
+
+    def addProductID(self, productid):
+        self._productids.append(productid)
+
+    def getTitle(self):
+        if self._description:
+            return "%s (%d products)" % (self._description, len(self._productids))
+        return "#%s (%d products)" % (self._groupid, len(self._productids))
+
+    def validate(self):
+        if not self._groupid:
+            raise ValidationError('A Group must have a GroupID')
+        if not self._productids or len(self._productids) < 2:
+            raise ValidationError('A Group must contain at least two products')
+
+
+class CVRFVulnerabilityID(object):
+    def __init__(self, systemname, value):
+        self._systemname = systemname
+        self._value = value
+
+    def validate(self):
+        if not self._systemname:
+            raise ValidationError('A Vulnerability ID must have a System Name')
+        if not self._value:
+            raise ValidationError('A Vulnerability ID must have a value')
+
+
+class CVRFVulnerability(object):
+    def __init__(self, ordinal):
+        self._ordinal = ordinal
+        self._title = None
+        self._id = None
+        self._notes = []
+        self._discoverydate = None
+        self._releasedate = None
+        self._involvements = []
+        self._cve = None
+        self._cwes = []
+        self._productstatuses = []
+        self._threats = []
+        self._cvsss = []
+        self._remediations = []
+        self._references = []
+        self._acknowledgments = []
+
+    def setTitle(self, title):
+        self._title = title
+
+    def setID(self, _id):
+        self._id = _id
+
+    def addNote(self, note):
+        self._notes.append(note)
+
+    def setDiscoveryDate(self, date):
+        self._discoverydate = date
+
+    def setReleaseDate(self, date):
+        self._releasedate = date
+
+    def addInvolvement(self, involvement):
+        self._involvements.append(involvement)
+
+    def setCVE(self, cve):
+        self._cve = cve
+
+    def addCWE(self, cwe):
+        self._cwes.append(cwe)
+
+    def addProductStatus(self, productstatus):
+        self._productstatuses.append(productstatus)
+
+    def addThreat(self, threat):
+        self._threats.append(threat)
+
+    def addCVSSSet(self, cvss_set):
+        self._cvsss.append(cvss_set)
+
+    def addRemediation(self, remediation):
+        self._remediations.append(remediation)
+
+    def addReference(self, ref):
+        self._references.append(ref)
+
+    def addAcknowledgment(self, ack):
+        self._acknowledgments.append(ack)
+
+    def getTitle(self):
+        """ return something that can be used as a title """
+        if self._title:
+            if self._id:
+                return "%s (%s)" % (self._title, self._id._value)
+            return self._title
+        if self._id:
+            return self._id._value
+        return "#%d" % self._ordinal
+
+    def validate(self, productids, groupids):
+        if not self._ordinal:
+            raise ValidationError('A Vulnerability must have an ordinal')
+        if self._id is not None:
+            self._id.validate()
+        ordinals = set()
+        for note in self._notes:
+            note.validate()
+            if note._ordinal in ordinals:
+                raise ValidationError('Vulnerability Note Ordinal %d duplicated' % note._ordinal)
+            ordinals.add(note._ordinal)
+        for involvement in self._involvements:
+            involvement.validate()
+        for cwe in self._cwes:
+            cwe.validate()
+        for status in self._productstatuses:
+            status.validate(productids)
+        for threat in self._threats:
+            threat.validate(productids, groupids)
+        for cvss in self._cvsss:
+            cvss.validate(productids)
+        for remediation in self._remediations:
+            remediation.validate(productids, groupids)
+        for reference in self._references:
+            reference.validate()
+        for acknowledgment in self._acknowledgments:
+            acknowledgment.validate()
+
+
+
+class CVRFInvolvement(object):
+    PARTIES = CVRFPublisher.TYPES
+    STATUSES = ('Open', 'Disputed', 'In Progress', 'Completed',
+                'Contact Attempted', 'Not Contacted')
+    def __init__(self, party, status):
+        self._party = party
+        self._status = status
+        self._description = None
+
+    def setDescription(self, description):
+        self._description = description
+
+    def getTitle(self):
+        return "From %s: %s" % (self._party, self._status)
+
+    def validate(self):
+        if not self._party:
+            raise ValidationError('An Involvement must have a Party')
+        if self._party not in self.PARTIES:
+            raise ValidationError("An Involvement's Party must be one of %s" % ', '.join(self.PARTIES))
+        if not self._status:
+            raise ValidationError('An Involvement must have a Status')
+        if self._status not in self.STATUSES:
+            raise ValidationError("An Involvement's Status must be one of %s" % ', '.join(self.STATUSES))
+
+
+class CVRFCWE(object):
+    def __init__(self, _id, value):
+        self._id = _id
+        self._value = value
+
+    def validate(self):
+        if not self._id:
+            raise ValidationError('A CWE must have an ID')
+        if not self._value:
+            raise ValidationError('A CWE must have a description')
+
+
+class CVRFProductStatus(object):
+    TYPES = ('First Affected', 'Known Affected', 'Known Not Affected',
+             'First Fixed', 'Fixed', 'Recommended', 'Last Affected')
+    def __init__(self, _type):
+        self._type = _type
+        self._productids = []
+
+    def addProductID(self, productid):
+        self._productids.append(productid)
+
+    def getTitle(self):
+        return "%s: %d products" % (self._type, len(self._productids))
+
+    def validate(self, productids):
+        if not self._type:
+            raise ValidationError('A Product Status must have a Type')
+        if self._type not in self.TYPES:
+            raise ValidationError("A Product Status' Type must be one of %s" % ', '.join(self.TYPES))
+        if len(self._productids) < 1:
+            raise ValidationError('A Product Status must mention at least one Product')
+        for productid in self._productids:
+            if productid not in productids:
+                raise ValidationError('Unknown ProductID: %s' % productid)
+
+
+class CVRFThreat(object):
+    TYPES = ('Impact', 'Exploit Status', 'Target Set')
+    def __init__(self, _type, description):
+        self._type = _type
+        self._description = description
+        self._date = None
+        self._productids = []
+        self._groupids = []
+
+    def setDate(self, date):
+        self._date = date
+
+    def addProductID(self, productid):
+        self._productids.append(productid)
+
+    def addGroupID(self, groupid):
+        self._groupids.append(groupid)
+
+    def getTitle(self):
+        return self._type
+
+    def validate(self, productids, groupids):
+        if not self._type:
+            raise ValidationError('A Threat must have a Type')
+        if self._type not in self.TYPES:
+            raise ValidationError("A Threat's Type must be one of %s" % ', '.join(self.TYPES))
+        if not self._description:
+            raise ValidationError('A Threat must have a Description')
+        for productid in self._productids:
+            if productid not in productids:
+                raise ValidationError('Unknown ProductID: %s' % productid)
+        for groupid in self._groupids:
+            if groupid not in groupids:
+                raise ValidationError('Unknown GroupID: %s' % groupid)
+
+
+class CVRFCVSSSet(object):
+    # To determine the base Score
+    VALUES = {'AV': {'L':0.395, 'A':0.646, 'N':1.0},
+              'AC': {'H':0.35, 'M':0.61 ,'L':0.71},
+              'Au': {'M':0.45, 'S':0.56, 'N':0.704},
+              'C': {'N':0.0, 'P':0.275, 'C':0.66},
+              'I': {'N':0.0, 'P':0.275, 'C':0.66},
+              'A': {'N':0.0, 'P':0.275, 'C':0.66}}
+    def __init__(self, basescore):
+        self._basescore = basescore
+        self._temporalscore = None
+        self._environmentalscore = None
+        self._vector = None
+        self.vector = None
+        self._productids = []
+
+    def setTemporalScore(self, tempscore):
+        self._temporalscore = tempscore
+
+    def setEnvironmentalScore(self, envscore):
+        self._environmentalscore = envscore
+
+    def setVector(self, vector):
+        self._vector = vector
+        if vector is None:
+            self.vector = vector
+            return
+        try:
+            self.vector = {}
+            for component in vector[:26].split('/'):
+                name, value = component.split(':')
+                self.vector[name] = self.VALUES[name][value]
+        except (KeyError, ValueError):
+            self.vector = None
+
+    def addProductID(self, productid):
+        self._productids.append(productid)
+
+    def baseScore(self):
+        v = self.vector # make an alias for shorter lines
+        exploitability = 20 * v['AV'] * v['AC'] * v['Au']
+        impact = 10.41 * (1 - (1 - v['C']) * (1 - v['I']) * (1 - v['A']))
+        def f(i): return 0 if i == 0 else 1.176
+        return ((0.6 * impact) + (0.4 * exploitability) - 1.5) * f(impact)
+
+    def validate(self, productids):
+        if not self._basescore:
+            raise ValidationError('A CVSS Score Set must have a Base Score')
+        if self._vector and not self.vector:
+            raise ValidationError('Syntax Error in CVSS Vector')
+        if abs(self._basescore - self.baseScore()) >= 0.05:
+            raise ValidationError('Inconsistency in CVSS Score Set between Vector (%f) and Base Score (%f)' % (self.baseScore(), self._basescore))
+        for productid in self._productids:
+            if productid not in productids:
+                raise ValidationError('Unknown ProductID: %s' % productid)
+
+
+class CVRFRemediation(object):
+    TYPES = ('Workaround', 'Mitigation', 'Vendor Fix', 'None Available',
+             'Will Not Fix')
+    def __init__(self, _type, description):
+        self._type = _type
+        self._description = description
+        self._date = None
+        self._entitlement = None
+        self._url = None
+        self._productids = []
+        self._groupids = []
+
+    def setDate(self, date):
+        self._date = date
+
+    def setEntitlement(self, entitlement):
+        self._entitlement = entitlement
+
+    def setURL(self, url):
+        self._url = url
+
+    def addProductID(self, productid):
+        self._productids.append(productid)
+
+    def addGroupID(self, groupid):
+        self._groupids.append(groupid)
+
+    def getTitle(self):
+        return self._type
+
+    def validate(self, productids, groupids):
+        if not self._type:
+            raise ValidationError('A Remediation must have a Type')
+        if self._type not in self.TYPES:
+            raise ValidationError("A Remediation's Type must be one of %s" % ', '.join(self.TYPES))
+        if not self._description:
+            raise ValidationError('A Remediation must have a Description')
+        for productid in self._productids:
+            if productid not in productids:
+                raise ValidationError('Unknown ProductID: %s' % productid)
+        for groupid in self._groupids:
+            if groupid not in groupids:
+                raise ValidationError('Unknown GroupID: %s' % groupid)
+
+class CVRF(object):
+    def __init__(self, title, _type):
+        self._title = title
+        self._type = _type
+        self._publisher = None
+        self._tracking = None
+        self._notes = []
+        self._distribution = None
+        self._references = []
+        self._acknowledgments = []
+        self._producttree = None
+        self._vulnerabilities = []
+
+    def setPublisher(self, publisher):
+        self._publisher = publisher
+
+    def setTracking(self, tracking):
+        self._tracking = tracking
+
+    def addNote(self, note):
+        self._notes.append(note)
+
+    def setDistribution(self, distribution):
+        self._distribution = distribution
+
+    def addReference(self, ref):
+        self._references.append(ref)
+
+    def addAcknowledgment(self, ack):
+        self._acknowledgments.append(ack)
+
+    def createProductTree(self):
+        """ only done if the element is there """
+        self._producttree = CVRFProductTree()
+        return self._producttree
+
+    def addVulnerability(self, vuln):
+        self._vulnerabilities.append(vuln)
+
+    def getProductForID(self, productid):
+        if self._producttree is None:
+            raise ValueError('No ProductTree')
+        return self._producttree.getProductForID(productid)
+
+    def getGroupForID(self, groupid):
+        if self._producttree is None:
+            raise ValueError('No ProductTree')
+        return self._producttree.getGroupForID(groupid)
+
+    def getHighestCVSS(self):
+        highestBaseScore = 0
+        highest = None
+        for vulnerability in self._vulnerabilities:
+            for cvss in vulnerability._cvsss:
+                if cvss._basescore <= highestBaseScore:
+                    continue
+                highestBaseScore = cvss._basescore
+                highest = cvss
+        return highest
+
+    def getProductList(self, type_='Fixed'):
+        products = set()
+        if type_ == 'Fixed':
+            # First try through the Remediation
+            for vulnerability in self._vulnerabilities:
+                for remediation in vulnerability._remediations:
+                    if remediation._type != 'Vendor Fix':
+                        continue
+                    for productid in remediation._productids:
+                        products.add(productid)
+                    for groupid in remediation._groupids:
+                        for productid in self.getGroupForID(groupid)._productids:
+                            products.add(productid)
+        if not products:
+            # If nothing there, try through the productstatuses
+            for vulnerability in self._vulnerabilities:
+                for status in vulnerability._productstatuses:
+                    if status._type != type_:
+                        continue
+                    for productid in status._productids:
+                        products.add(productid)
+        return set(self.getProductForID(p) for p in products)
+
+    def getNote(self, ordinal):
+        for note in self._notes:
+            if note._ordinal == ordinal:
+                return note
+        return None
+
+    def validate(self):
+        if not self._title:
+            raise ValidationError('Document Title cannot be empty')
+        if not self._type:
+            raise ValidationError('Document Type cannot be empty')
+        if self._publisher is None:
+            raise ValidationError('Document Publisher needs to be set')
+        self._publisher.validate()
+        if self._tracking is None:
+            raise ValidationError('Document Tracking needs to be set')
+        self._tracking.validate()
+        ordinals = set()
+        for note in self._notes:
+            note.validate()
+            if note._ordinal in ordinals:
+                raise ValidationError('Document Note ordinal %d is issued twice' % note._ordinal)
+            ordinals.add(note._ordinal)
+        for reference in self._references:
+            reference.validate()
+        for acknowledgment in self._acknowledgments:
+            acknowledgment.validate()
+        productids = set()
+        groupids = set()
+        if self._producttree:
+            productids, groupids = self._producttree.validate()
+        ordinals = set()
+        for vulnerability in self._vulnerabilities:
+            vulnerability.validate(productids, groupids)
+            if vulnerability._ordinal in ordinals:
+                raise ValidationError('Vulnerability ordinal %d is issued twice' % vulnerability._ordinal)
+            ordinals.add(vulnerability._ordinal)
+
+    def __str__(self):
+        s = [
+            'Title: %s' % self._title,
+            'Type: %s' % self._type,
+            'Publisher: %s' % self._publisher,
+            'tracking: %s' % self._tracking,
+            '%d Notes: %s' % (len(self._notes), ', '.join(
+                str(n) for n in self._notes))
+        ]
+        if self._distribution is not None:
+            s.append('Distribution: %s' % self._distribution)
+        s.extend([
+            '%d Acknowledgments' % len(self._acknowledgments),
+            'Products: %s' % self._producttree,
+        ])
+        return '\n'.join(s)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/farolluz/parsers/__init__.py	Tue Sep 23 15:19:14 2014 +0200
@@ -0,0 +1,23 @@
+# -*- encoding: utf-8 -*-
+# Description:
+# A utility to manipulate Security Advisories
+#
+# Authors:
+# Benoît Allard <benoit.allard@greenbone.net>
+#
+# Copyright:
+# Copyright (C) 2014 Greenbone Networks GmbH
+#
+# 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 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/farolluz/parsers/cvrf.py	Tue Sep 23 15:19:14 2014 +0200
@@ -0,0 +1,354 @@
+# -*- coding: utf-8 -*-
+# Description:
+# Methods for parsing CVRF documents
+#
+# Authors:
+# Benoît Allard <benoit.allard@greenbone.net>
+#
+# Copyright:
+# Copyright (C) 2014 Greenbone Networks GmbH
+#
+# 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 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+
+"""\
+Methods for parsing of CVRF Documents
+"""
+
+from __future__ import print_function
+
+import re
+import textwrap
+import xml.etree.ElementTree as ET
+from datetime import datetime, timedelta
+
+try:
+    from datetime import timezone
+except ImportError:
+    from ..py2 import FixedTimeZone as timezone
+
+from ..cvrf import (CVRF, CVRFPublisher, CVRFTracking, CVRFRevision, CVRFNote,
+    CVRFAcknowledgment, CVRFProductBranch, CVRFFullProductName, CVRFGenerator,
+    CVRFRelationship, CVRFVulnerability, CVRFVulnerabilityID, CVRFThreat,
+    CVRFProductStatus, CVRFCVSSSet, CVRFReference, CVRFRemediation, CVRFGroup,
+    CVRFInvolvement, CVRFCWE, CVRFTrackingID)
+
+NAMESPACES = {
+    'cvrf': "http://www.icasi.org/CVRF/schema/cvrf/1.1",
+    'prod': "http://www.icasi.org/CVRF/schema/prod/1.1",
+    'vuln': "http://www.icasi.org/CVRF/schema/vuln/1.1",
+    'xml':  "http://www.w3.org/XML/1998/namespace",
+}
+
+
+def UN(ns, name):
+    """ UN for Universal Name """
+    return "{%s}%s" % (NAMESPACES[ns], name)
+
+
+def parseVersion(string):
+    return tuple(int(i) for i in string.split('.'))
+
+
+def parseDate(string):
+    m = re.match('(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:([+-])(\d{2}):(\d{2})|(Z))?', string)
+    if (m.group(7) is None) or (m.group(7) == 'Z'):
+        tzhours = 0
+        tzmin = 0
+    else:
+        tzhours = int(m.group(8))
+        if m.group(7) == '-':
+            tzhours = - tzhours
+        tzmin = int(m.group(9))
+    return datetime(int(m.group(1)), int(m.group(2)), int(m.group(3)), int(m.group(4)), int(m.group(5)), int(m.group(6)), tzinfo=timezone(timedelta(hours=tzhours, minutes=tzmin)))
+
+
+def parseNote(elem):
+    return CVRFNote(
+        elem.attrib['Type'],
+        int(elem.attrib['Ordinal']),
+        textwrap.dedent(elem.text).strip(),
+        elem.attrib.get('Title'),
+        elem.attrib.get('Audience')
+    )
+
+
+def parseReference(elem, ns='cvrf'):
+    """ ns is the current namespace """
+    return CVRFReference(
+        elem.findtext(UN(ns, 'URL')).strip(),
+        textwrap.dedent(elem.findtext(UN(ns, 'Description'))).strip(),
+        elem.attrib.get('Type')
+    )
+
+
+def parseAcknowledgment(elem, ns='cvrf'):
+    return CVRFAcknowledgment(
+        elem.findtext(UN(ns, 'Name')),
+        elem.findtext(UN(ns, 'Organization')),
+        elem.findtext(UN(ns, 'Description')),
+        elem.findtext(UN(ns, 'URL')),
+    )
+
+
+def parseFullProductName(elem, parent):
+    return CVRFFullProductName(
+        elem.attrib['ProductID'],
+        elem.text.strip(),
+        parent,
+        cpe=elem.attrib.get('CPE')
+    )
+
+
+def parseProdBranch(elem, ptree, parentbranch=None):
+    """ Recursively parses the branches and the terminal productnames """
+    fpncvrf = elem.find(UN('prod', 'FullProductName'))
+    if (parentbranch is not None) and (fpncvrf is not None):
+        # Don't process the products at the root of the tree
+        prod = parseFullProductName(fpncvrf, parentbranch)
+        ptree.addProduct(prod)
+
+    if parentbranch is None:
+        parentbranch = ptree
+    for brcvrf in elem.findall(UN('prod', 'Branch')):
+        br = CVRFProductBranch(brcvrf.attrib['Type'], brcvrf.attrib['Name'], parentbranch)
+        # And go into recursion ...
+        br._childs = list(parseProdBranch(brcvrf, ptree, br))
+        yield br
+
+
+def parseVulnerability(elem):
+    vuln = CVRFVulnerability(int(elem.attrib['Ordinal']))
+
+    xmltitle = elem.findtext(UN('vuln', 'Title'))
+    if xmltitle is not None:
+        vuln.setTitle(xmltitle.strip())
+
+    xmlID = elem.find(UN('vuln', 'ID'))
+    if xmlID is not None:
+        vuln.setID(CVRFVulnerabilityID(xmlID.attrib['SystemName'], xmlID.text.strip()))
+
+    for xmlnote in elem.findall('/'.join([UN('vuln', 'Notes'), UN('vuln', 'Note')])):
+        vuln.addNote(parseNote(xmlnote))
+
+    xmldiscoverydate = elem.findtext(UN('vuln', 'DiscoveryDate'))
+    if xmldiscoverydate is not None:
+        vuln.setDiscoveryDate(parseDate(xmldiscoverydate))
+    xmlreleasedate = elem.findtext(UN('vuln', 'ReleaseDate'))
+    if xmlreleasedate is not None:
+        vuln.setReleaseDate(parseDate(xmlreleasedate))
+
+    for xmlinv in elem.findall('/'.join([UN('vuln', 'Involvements'), UN('vuln', 'Involvement')])):
+        involvement = CVRFInvolvement(
+            xmlinv.attrib['Party'],
+            xmlinv.attrib['Status']
+        )
+        xmldescr = xmlinv.findtext(UN('vuln', 'Description'))
+        if xmldescr is not None:
+            involvement.setDescription(textwrap.dedent(xmldescr).strip())
+        vuln.addInvolvement(involvement)
+
+    xmlcve = elem.findtext(UN('vuln', 'CVE'))
+    if xmlcve is not None:
+        vuln.setCVE(xmlcve.strip())
+
+    for xmlcwe in elem.findall(UN('vuln', 'CWE')):
+        vuln.addCWE(CVRFCWE(
+            xmlcwe.attrib['ID'],
+            xmlcwe.text.strip()
+        ))
+
+    for xmlstatus in elem.findall('/'.join([UN('vuln', 'ProductStatuses'), UN('vuln', 'Status')])):
+        status = CVRFProductStatus(xmlstatus.attrib['Type'])
+        for xmlproductid in xmlstatus.findall(UN('vuln', 'ProductID')):
+            status.addProductID(xmlproductid.text.strip())
+
+        vuln.addProductStatus(status)
+
+    for xmlthreat in elem.findall('/'.join([UN('vuln', 'Threats'), UN('vuln', 'Threat')])):
+        threat = CVRFThreat(
+            xmlthreat.attrib['Type'],
+            textwrap.dedent(xmlthreat.findtext(UN('vuln', 'Description'))).strip()
+        )
+        xmldate = xmlthreat.findtext(UN('vuln', 'Date'))
+        if xmldate is not None:
+            threat.setDate(parseDate(xmldate))
+        for xmlpid in xmlthreat.findall(UN('vuln', 'ProductID')):
+            threat.addProductID(xmlpid.text.strip())
+        for xmlgid in xmlthreat.findall(UN('vuln', 'GroupID')):
+            threat.addGroupID(xmlgid.text.strip())
+
+        vuln.addThreat(threat)
+
+    for xmlcvss in elem.findall('/'.join([UN('vuln', 'CVSSScoreSets'), UN('vuln', 'ScoreSet')])):
+        cvss_set = CVRFCVSSSet(float(xmlcvss.findtext(UN('vuln', 'BaseScore')).strip()))
+        xmltempscore = xmlcvss.findtext(UN('vuln', 'TemporalScore'))
+        if xmltempscore is not None:
+            cvss_set.setTemporalScore(float(xmltempscore.strip()))
+        xmlenvscore = xmlcvss.findtext(UN('vuln', 'EnvironmentalScore'))
+        if xmlenvscore is not None:
+            cvss_set.setEnvironmentalScore(float(xmlenvscore.strip()))
+        xmlvector = xmlcvss.findtext(UN('vuln', 'Vector'))
+        if xmlvector is not None:
+            cvss_set.setVector(xmlvector.strip())
+        for xmlprodid in xmlcvss.findall(UN('vuln', 'ProductID')):
+            cvss_set.addProductID(xmlprodid.text.strip())
+
+        vuln.addCVSSSet(cvss_set)
+
+    for xmlremediation in elem.findall('/'.join([UN('vuln', 'Remediations'), UN('vuln', 'Remediation')])):
+        remediation = CVRFRemediation(
+            xmlremediation.attrib['Type'],
+            textwrap.dedent(xmlremediation.findtext(UN('vuln', 'Description'))).strip()
+        )
+        xmldate = xmlremediation.findtext(UN('vuln', 'Date'))
+        if xmldate is not None:
+            remediation.setDate(parseDate(xmldate))
+        xmlentitlement = xmlremediation.findtext(UN('vuln', 'Entitlement'))
+        if xmlentitlement is not None:
+            remediation.setEntitlement(textwrap.dedent(xmlentitlement).strip())
+        xmlurl = xmlremediation.findtext(UN('vuln', 'URL'))
+        if xmlurl is not None:
+            remediation.setURL(xmlurl.strip())
+        for xmlpid in xmlremediation.findall(UN('vuln', 'ProductID')):
+            remediation.addProductID(xmlpid.text.strip())
+        for xmlgid in xmlremediation.findall(UN('vuln', 'GroupID')):
+            remediation.addGroupID(xmlgid.text.strip())
+
+        vuln.addRemediation(remediation)
+
+    for xmlref in elem.findall('/'.join([UN('vuln', 'References'), UN('vuln', 'Reference')])):
+        vuln.addReference(parseReference(xmlref, 'vuln'))
+
+    for xmlack in elem.findall('/'.join([UN('vuln', 'Acknowledgments'), UN('vuln', 'Acknowledgment')])):
+        vuln.addAcknowledgment(parseAcknowledgment(xmlack, 'vuln'))
+
+    return vuln
+
+
+def parse(xml):
+    if hasattr(xml, 'read'):
+        xml = xml.read()
+    cvrfdoc = ET.fromstring(xml)
+    if cvrfdoc.tag != UN('cvrf', 'cvrfdoc'):
+        raise ValueError('Not a CVRF document !')
+    doc = CVRF(
+        cvrfdoc.findtext(UN('cvrf', 'DocumentTitle')).strip(),
+        cvrfdoc.findtext(UN('cvrf', 'DocumentType')).strip()
+    )
+    cvrfpub = cvrfdoc.find(UN('cvrf', 'DocumentPublisher'))
+    pub = CVRFPublisher(cvrfpub.attrib['Type'], cvrfpub.attrib.get('VendorID'))
+    doc.setPublisher(pub)
+    contact = cvrfpub.find(UN('cvrf', 'ContactDetails'))
+    if contact is not None:
+        pub.setContact(contact.text.strip())
+    authority = cvrfpub.find(UN('cvrf', 'IssuingAuthority'))
+    if authority is not None:
+        pub.setAuthority(authority.text.strip())
+    cvrftracking = cvrfdoc.find(UN('cvrf', 'DocumentTracking'))
+    identification = CVRFTrackingID(
+        cvrftracking.findtext('/'.join([UN('cvrf', 'Identification'), UN('cvrf', 'ID')])).strip()
+    )
+    for cvrfalias in cvrftracking.findall('/'.join([UN('cvrf', 'Identification'), UN('cvrf', 'Alias')])):
+        identification.addAlias(cvrfalias.text.strip())
+    tracking = CVRFTracking(
+        identification,
+        cvrftracking.findtext(UN('cvrf', 'Status')).strip(),
+        parseVersion(cvrftracking.findtext(UN('cvrf', 'Version')).strip()),
+        parseDate(cvrftracking.findtext(UN('cvrf', 'InitialReleaseDate')).strip()),
+        parseDate(cvrftracking.findtext(UN('cvrf', 'CurrentReleaseDate')).strip())
+    )
+    doc.setTracking(tracking)
+    for cvrfrev in cvrftracking.findall('/'.join([UN('cvrf', 'RevisionHistory'), UN('cvrf', 'Revision')])):
+        rev = CVRFRevision(
+            parseVersion(cvrfrev.findtext(UN('cvrf', 'Number')).strip()),
+            parseDate(cvrfrev.findtext(UN('cvrf', 'Date')).strip()),
+            cvrfrev.findtext(UN('cvrf', 'Description')).strip(),
+        )
+        tracking.addRevision(rev)
+
+    xmlgenerator = cvrftracking.find(UN('cvrf', 'Generator'))
+    if xmlgenerator is not None:
+        generator = CVRFGenerator()
+        xmlengine = xmlgenerator.findtext(UN('cvrf', 'Engine'))
+        if xmlengine is not None:
+            generator.setEngine(xmlengine.strip())
+        xmldate = xmlgenerator.findtext(UN('cvrf', 'Date'))
+        if xmldate is not None:
+            generator.setDate(parseDate(xmldate.strip()))
+        tracking.setGenerator(generator)
+
+    for cvrfnote in cvrfdoc.findall('/'.join([UN('cvrf', 'DocumentNotes'), UN('cvrf', 'Note')])):
+        doc.addNote(parseNote(cvrfnote))
+
+    distr = cvrfdoc.findtext(UN('cvrf', 'DocumentDistribution'))
+    if distr is not None:
+        doc.setDistribution(textwrap.dedent(distr).strip())
+
+    # This is in a quite free format, not sure how to do something with it ...
+    xmlaggsev = cvrfdoc.find(UN('cvrf', 'AggregateSeverity'))
+
+    for xmlref in cvrfdoc.findall('/'.join([UN('cvrf', 'DocumentReferences'), UN('cvrf', 'Reference')])):
+        doc.addReference(parseReference(xmlref))
+
+    for cvrfack in cvrfdoc.findall('/'.join([UN('cvrf', 'Acknowledgments'), UN('cvrf', 'Acknowledgment')])):
+        doc.addAcknowledgment(parseAcknowledgment(cvrfack))
+
+    # --- The ProductTree
+
+    cvrfptree = cvrfdoc.find(UN('prod', 'ProductTree'))
+    if cvrfptree is not None:
+        producttree = doc.createProductTree()
+        for branch in parseProdBranch(cvrfptree, producttree):
+            producttree.addBranch(branch)
+
+        for product in cvrfptree.findall(UN('prod', 'FullProductName')):
+            producttree.addProduct(parseFullProductName(product, producttree))
+
+        for cvrfrel in cvrfptree.findall(UN('prod', 'Relationship')):
+            rel = CVRFRelationship(
+                cvrfrel.attrib['ProductReference'],
+                cvrfrel.attrib['RelationType'],
+                cvrfrel.attrib['RelatesToProductReference']
+            )
+            producttree.addRelationship(rel)
+            producttree.addProduct(parseFullProductName(cvrfrel.find(UN('prod', 'FullProductName')), rel))
+
+        for xmlgroup in cvrfptree.findall('/'.join([UN('prod', 'ProductGroups'), UN('prod', 'Group')])):
+            group = CVRFGroup(xmlgroup.attrib['GroupID'])
+            xmldescr = xmlgroup.findtext(UN('prod', 'Description'))
+            if xmldescr is not None:
+                group.setDescription(textwrap.dedent(xmldescr).strip())
+            for xmlpid in xmlgroup.findall(UN('prod', 'ProductID')):
+                group.addProductID(xmlpid.text.strip())
+            producttree.addGroup(group)
+
+    # --- The Vulnerabilities
+
+    for cvrfvuln in cvrfdoc.findall(UN('vuln', 'Vulnerability')):
+        doc.addVulnerability(parseVulnerability(cvrfvuln))
+
+    return doc
+
+
+if __name__ == "__main__":
+    import sys
+    with open(sys.argv[1], 'rt') as f:
+        cvrf = parse(f)
+    cvrf.validate()
+    print(cvrf)
+    print(cvrf.getHighestCVSS()._vector)
+    print(cvrf.getProductList())
+    print(cvrf._producttree._branches)
+#    print(cvrf._producttree._branches[0]._childs)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/farolluz/py2.py	Tue Sep 23 15:19:14 2014 +0200
@@ -0,0 +1,44 @@
+# -*- coding: utf-8 -*-
+# Description:
+# Python2 Compatibility module
+#
+# Authors:
+# Benoît Allard <benoit.allard@greenbone.net>
+#
+# Copyright:
+# Copyright (C) 2014 Greenbone Networks GmbH
+#
+# 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 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+
+"""\
+Glue for missing features of python3 in python2
+"""
+
+from datetime import tzinfo, timedelta
+
+class FixedTimeZone(tzinfo):
+    def __init__(self, offset):
+        self.__offset = offset
+
+    def utcoffset(self, dt):
+        return self.__offset
+
+    def dst(self, dt):
+        return timedelta(0)
+
+try:
+  from urllib.request import urlopen
+except ImportError:
+  from urllib2 import urlopen
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/farolluz/renderer.py	Tue Sep 23 15:19:14 2014 +0200
@@ -0,0 +1,153 @@
+# -*- encoding: utf-8 -*-
+# Description:
+# Module related to the rendering of a Security Advisory.
+#
+# Authors:
+# Benoît Allard <benoit.allard@greenbone.net>
+#
+# Copyright:
+# Copyright (C) 2014 Greenbone Networks GmbH
+#
+# 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 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+
+from __future__ import print_function
+
+import os
+import sys
+from datetime import datetime
+import jinja2
+
+from .parsers import cvrf
+from .utils import utcnow
+
+# Supported Red Hat OSes for parsing. The value is as used in
+# gather-package-list.nasl to set "ssh/login/release"
+# Refer to that file, or the lsc_generator for a complete list.
+OS_MAP = {
+    'Red Hat Enterprise Linux Server (v. 7)' : 'RHENT_7',
+    'Red Hat Enterprise Linux Server (v. 6)' : 'RHENT_6',
+    'Red Hat Enterprise Linux Workstation (v. 6)' : 'RHENT_6',
+    'Red Hat Enterprise Linux Desktop (v. 6)' : 'RHENT_6',
+    'Red Hat Enterprise Linux Desktop 6' : 'RHENT_6',
+    'Red Hat Enterprise Linux (v. 5 server)' : 'RHENT_5',
+    'Red Hat Enterprise Linux ES version 2.1' : 'RHENT_2.1',
+    'Red Hat Enterprise Linux WS version 2.1' : 'RHENT_2.1',
+    'Red Hat Enterprise Linux AS version 3' : 'RHENT_3',
+    'Red Hat Enterprise Linux ES version 3' : 'RHENT_3',
+    'Red Hat Enterprise Linux WS version 3' : 'RHENT_3',
+    'Red Hat Enterprise Linux AS version 4' : 'RHENT_4',
+    'Red Hat Enterprise Linux ES version 4' : 'RHENT_4',
+    'Red Hat Enterprise Linux WS version 4' : 'RHENT_4',
+    'Red Hat Enterprise Linux AS (Advanced Server) version 2.1' : 'RHENT_2.1',
+}
+
+def calculateRiskFactor(cvss_score, debug=0):
+    """
+    Calculates and Return Risk Factor given CVSS Base Score
+    """
+    cvss_score = float(cvss_score)
+
+    for high, name in [
+            (2, 'Low'),
+            (5, 'Medium'),
+            (8, 'High'),
+            (10, 'Critical')]:
+        if cvss_score <= high:
+            return name
+
+
+def getReleaseName(os_name):
+    return OS_MAP.get(os_name, 'UNKNOWN')
+
+def getPackageName(rpm_name):
+    return rpm_name.split('-')[0]
+
+def PackageNameForrpmvuln(package_name):
+    package_name = package_name.rstrip('.src.rpm|.x86_64.rpm')
+    return (package_name.replace('-', '~'))
+
+def render(cvrf, templatepath, **kwargs):
+
+    red_hat = False
+    script_family = ""
+    os_cpe = ""
+    ## check the platform
+    if "Red Hat Security Advisory" in cvrf._title:
+        red_hat = True
+        script_family = "Red Hat Local Security Checks"
+        os_cpe = "cpe:/o:redhat:enterprise_linux"
+
+#    product_id = cvrf._vulnerabilities[0]._productstatuses[0]._productids
+#    print (product_id)
+#    for eachid in cvrf._vulnerabilities[0]._productstatuses[0]._productids: 
+#        print(cvrf.getProductForID(eachid)._name)
+# 
+#    print("productnames")
+#    print(', '.join(p._name for p in cvrf.getProductList()))
+       
+
+
+    templatedir = os.path.join(os.path.dirname(__file__), 'templates')
+    templateLoader = jinja2.FileSystemLoader(searchpath=templatedir)
+    templateEnv = jinja2.Environment(
+        loader=templateLoader,
+        extensions=['jinja2.ext.with_']
+    )
+
+    templateEnv.filters['risk_factor'] = calculateRiskFactor
+    templateEnv.filters['release_map'] = getReleaseName
+    templateEnv.filters['package_name'] = getPackageName
+    templateEnv.filters['for_rpmvuln'] = PackageNameForrpmvuln
+
+    template = templateEnv.get_template(templatepath)
+
+
+
+    templateVars = {
+        "cvrf": cvrf,
+        "script_id": 0,
+        "now" : utcnow(),
+        "red_hat": red_hat,
+        "script_family" :  script_family,
+        "os_cpe" : os_cpe,
+
+    }
+
+    templateVars.update(kwargs)
+
+    return template.render(templateVars)
+
+def main(cvrfpath, templatepath):
+
+    with open(cvrfpath, 'rt') as f:
+        cvrfdoc = cvrf.parse(f)
+
+    outputText = render(cvrfdoc, templatepath)
+
+    adv_id = cvrfdoc._tracking._identification._id
+    if adv_id :
+        file_name = adv_id.replace(":", "_");
+        file_name = "gb_"  + file_name + "." + os.path.basename(templatepath).split('.')[0]
+
+    with open(file_name, 'w') as file_handle:
+        file_handle.write(outputText)
+    print("file written to:", file_name)
+
+if __name__ == "__main__":
+    import sys
+    template = "nasl.j2"
+    if len(sys.argv) >= 3:
+        template = sys.argv[2]
+    main(sys.argv[1], template)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/farolluz/templates/cvrf.j2	Tue Sep 23 15:19:14 2014 +0200
@@ -0,0 +1,258 @@
+{#
+# Description:
+# Template for generation of CVRF documents
+#
+# Authors:
+# Benoît Allard <benoit.allard@greenbone.net>
+#
+# Copyright:
+# Copyright (C) 2014 Greenbone Networks GmbH
+#
+# 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 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+-#}
+
+<?xml version="1.0" encoding="utf-8"?>
+
+{#- Some macros for producttree generation #}
+{%- macro FullProductNames(producttree, parent) %}
+  {%- for product in producttree._products %}
+    {%- if product._parent is sameas parent %}
+      <FullProductName{{ {'ProductID': product._productid, 'CPE': product._cpe} | xmlattr }}>
+        {{- product._name -}}
+      </FullProductName>
+    {%- endif %}
+  {%- endfor %}
+{%- endmacro %}
+
+{%- macro Note(note) -%}
+  <Note{{ {'Type': note._type, 'Ordinal': note._ordinal, 'Title': note._title, 'Audience': note._audience} | xmlattr }}>
+    {{- note._note | escape -}}
+  </Note>
+{%- endmacro %}
+<cvrfdoc xmlns="http://www.icasi.org/CVRF/schema/cvrf/1.1">
+  <DocumentTitle>{{ cvrf._title }}</DocumentTitle>
+  <DocumentType>{{ cvrf._type }}</DocumentType>
+  {%- with publisher = cvrf._publisher %}
+  <DocumentPublisher{{ {'Type': publisher._type, 'VendorID': publisher._vendorid} | xmlattr }}>
+    {%- if publisher._contact %}
+    <ContactDetails>{{ publisher._contact }}</ContactDetails>
+    {%- endif %}
+    {%- if publisher._authority %}
+    <IssuingAuthority>{{ publisher._authority }}</IssuingAuthority>
+    {%- endif %}
+  </DocumentPublisher>
+  {%- endwith %}
+  {%- with tracking = cvrf._tracking %}
+  <DocumentTracking>
+    <Identification>
+      <ID>{{ tracking._identification._id }}</ID>
+      {%- for alias in tracking._identification._aliases %}
+      <Alias>{{ alias }}</Alias>
+      {%- endfor %}
+    </Identification>
+    <Status>{{ tracking._status }}</Status>
+    <Version>{{ tracking._version | join('.') }}</Version>
+    <RevisionHistory>
+      {%- for revision in tracking._history %}
+      <Revision>
+        <Number>{{ revision._number | join('.') }}</Number>
+        <Date>{{ revision._date.isoformat() }}</Date>
+        <Description>{{ revision._description }}</Description>
+      </Revision>
+      {%- endfor %}
+    </RevisionHistory>
+    <InitialReleaseDate>{{ tracking._initialDate.isoformat() }}</InitialReleaseDate>
+    <CurrentReleaseDate>{{ tracking._currentDate.isoformat() }}</CurrentReleaseDate>
+    {%- if tracking._generator %}
+    <Generator>
+    {%- with generator = tracking._generator %}
+      {%- if generator._engine %}
+      <Engine>{{ generator._engine }}</Engine>
+      {%- endif %}
+      {%- if generator._date %}
+      <Date>{{ generator._date.isoformat() }}</Date>
+      {%- endif %}
+    {%- endwith %}
+    </Generator>
+    {%- endif %}
+  </DocumentTracking>
+  {%- endwith %}
+  {%- if cvrf._notes %}
+  <DocumentNotes>
+    {%- for note in cvrf._notes %}
+    {{ Note(note) }}
+    {%- endfor %}
+  </DocumentNotes>
+  {%- endif %}
+  {%- if cvrf._distribution %}
+  <DocumentDistribution>{{ cvrf._distribution }}</DocumentDistribution>
+  {%- endif %}
+  {#- AggregateSeverity is missing #}
+  {%- if cvrf._references %}
+  <DocumentReferences>
+    {%- for reference in cvrf._references %}
+    <Reference{{ {'Type': reference._type} | xmlattr }}>
+      <URL>{{ reference._url }}</URL>
+      <Description>{{ reference._description }}</Description>
+    </Reference>
+    {%- endfor %}
+  </DocumentReferences>
+  {%- endif %}
+  {%- if cvrf._acknowledgments %}
+  <Acknowledgments>
+    {%- for acknowledgment in cvrf._acknowledgments %}
+    <Acknowledgment>
+      {%- if acknowledgment._name %}
+      <Name>{{ acknowledgment._name }}</Name>
+      {%- endif %}
+      {%- if acknowledgment._organization %}
+      <Organization>{{ acknowledgment._organization }}</Organization>
+      {%- endif %}
+      {%- if acknowledgment._description %}
+      <Description>{{ acknowledgment._description }}</Description>
+      {%- endif %}
+      {%- if acknowledgment._url %}
+      <URL>{{ acknowledgment._url }}</URL>
+      {%- endif %}
+    </Acknowledgment>
+    {%- endfor %}
+  </Acknowledgments>
+  {%- endif %}
+  {%- if cvrf._producttree %}
+  <ProductTree xmlns="http://www.icasi.org/CVRF/schema/prod/1.1">
+  {%- with producttree = cvrf._producttree %}
+    {%- for branch in producttree._branches recursive %}
+    <Branch{{ {'Type': branch._type, 'Name': branch._name} | xmlattr }}>
+      {{- loop(branch._childs) }}
+      {{- FullProductNames(producttree, branch) }}
+    </Branch>
+    {%- endfor %}
+    {{ FullProductNames(producttree, producttree) }}
+    {%- for relationship in producttree._relationships -%}
+    <Relationship{{ {'ProductReference': relationship._productreference, 'RelationType': relationship._relationtype, 'RelatesToProductReference': relationship._relatestoproductreference} | xmlattr }}>
+      {{- FullProductNames(producttree, relationship) }}
+    </Relationship>
+    {%- endfor %}
+    {%- if producttree._groups %}
+    <ProductGroups>
+      {%- for group in producttree._groups %}
+      <Group{{ {'GroupID': group._id} | xmlattr }}>
+        {%- if group._description %}
+        <Description>{{ group._description }}</Description>
+        {%- endif %}
+        {%- for productid in group._productids %}
+        <ProductID>{{ productid }}</ProductID>
+        {%- endfor %}
+      </Group>
+      {%- endfor %}
+    </ProductGroups>
+    {%- endif %}
+  {%- endwith %}
+  </ProductTree>
+  {%- endif %}
+  {%- for vulnerability in cvrf._vulnerabilities %}
+  <Vulnerability xmlns="http://www.icasi.org/CVRF/schema/vuln/1.1" Ordinal="{{ vulnerability._ordinal}}">
+    {%- if vulnerability._title %}
+    <Title>{{ vulnerability._title }}</Title>
+    {%- endif %}
+    {%- if vulnerability._id %}
+    <ID SystemName="{{ vulnerability._id._systemname }}">{{ vulnerability._id._value }}</ID>
+    {%- endif %}
+    {%- if vulnerability._notes %}
+    <Notes>
+      {%- for note in vulnerability._notes %}
+      {{ Note(note) }}
+      {%- endfor %}
+    </Notes>
+    {%- endif %}
+    {%- if vulnerability._discoverydate %}
+    <DiscoveryDate>{{ vulnerability._discoverydate.isoformat() }}</DiscoveryDate>
+    {%- endif %}
+    {%- if vulnerability._releasedate %}
+    <ReleaseDate>{{ vulnerability._releasedate.isoformat() }}</ReleaseDate>
+    {%- endif %}
+    {%- if vulnerability._involvements %}
+    <Involvements>
+      {%- for involvement in vulnerability._involvements %}
+      <Involvement{{ {'Party': involvement._party, 'Status': involvement._status} | xmlattr }}>
+        {%- if involvement._description %}
+        <Description>{{ involvement._description }}</Description>
+        {%- endif %}
+      </Involvement>
+      {%- endfor %}
+    </Involvements>
+    {%- endif %}
+    {%- if vulnerability._cve %}
+    <CVE>{{ vulnerability._cve }}</CVE>
+    {%- endif %}
+    {%- for cwe in vulnerability._cwes %}
+    <CWE ID="{{ cwe._id }}">{{ cwe._value }}</CWE>
+    {%- endfor %}
+    {%- if vulnerability._productstatuses %}
+    <ProductStatuses>
+      {%- for status in vulnerability._productstatuses %}
+      <Status Type="{{ status._type }}">
+        {%- for productid in status._productids %}
+        <ProductID>{{ productid }}</ProductID>
+        {%- endfor %}
+      </Status>
+      {%- endfor %}
+    </ProductStatuses>
+    {%- endif %}
+    {%- if vulnerability._cvsss %}
+    <CVSSScoreSets>
+      {%- for cvss in vulnerability._cvsss %}
+      <ScoreSet>
+        <BaseScore>{{ cvss._basescore }}</BaseScore>
+        {%- if cvss._temporalscore %}
+        <TemporalScore>{{ cvss._temporalscore }}</TemporalScore>
+        {%- endif %}
+        {%- if cvss._environmentalscore %}
+        <EnvironmentalScore>{{ cvss._environmentalscore }}</EnvironmentalScore>
+        {%- endif %}
+        {%- if cvss._vector %}
+        <Vector>{{ cvss._vector }}</Vector>
+        {%- endif %}
+        {%- for productid in cvss._productids %}
+        <ProductID>{{productid}}</ProductID>
+        {%- endfor %}
+      </ScoreSet>
+      {%- endfor %}
+    </CVSSScoreSets>
+    {%- endif %}
+    {%- if vulnerability._remediations %}
+    <Remediations>
+      {%- for remediation in vulnerability._remediations %}
+      <Remediation Type="{{ remediation._type }}"{% if remediation._date %} Date="{{ remediation._date.isoformat() }}"{% endif %}>
+        <Description>{{ remediation._description }}</Description>
+        {%- if remediation._entitlement %}
+        <Entitlement>{{ remediation._entitlement }}</Entitlement>
+        {%- endif %}
+        {%- if remediation._url %}
+        <URL>{{ remediation._url }}</URL>
+        {%- endif %}
+        {%- for productid in remediation._productids %}
+        <ProductID>{{ productid }}</ProductID>
+        {%- endfor %}
+        {%- for groupid in remediation._groupids %}
+        <GroupID>{{ groupid }}</GroupID>
+        {%- endfor %}
+      </Remediation>
+      {%- endfor %}
+    </Remediations>
+    {%- endif %}
+  </Vulnerability>
+  {%- endfor %}
+</cvrfdoc>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/farolluz/templates/nasl.j2	Tue Sep 23 15:19:14 2014 +0200
@@ -0,0 +1,102 @@
+{#
+# Description:
+# Template for generation of NASL documents
+#
+# Authors:
+# Benoît Allard <benoit.allard@greenbone.net>
+#
+# Copyright:
+# Copyright (C) 2014 Greenbone Networks GmbH
+#
+# 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 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+-#}
+
+{% import "nasl_core.j2" as nasl_core -%}
+###############################################################################
+# OpenVAS Vulnerability Test
+#
+# {{ cvrf._title }} ({{ cvrf._tracking._identification._id }})
+#
+# Authors:
+# System Generated Check
+#
+# Copyright:
+# Copyright (C) {{ now.strftime('%Y') }} Greenbone Networks GmbH, http://www.greenbone.net
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2
+# (or any later version), as published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+###############################################################################
+
+if(description)
+{
+  script_oid("1.3.6.1.4.1.25623.1.0.{{ script_id }}");
+  script_version("$Revision$");
+  script_tag(name:"check_type", value:"authenticated package test");
+  script_tag(name:"last_modification", value:"$Date$");
+  script_tag(name:"creation_date", value:"{{ now.strftime('%F %T %z (%a, %d %b %Y)') }}");
+  script_cve_id({% for vuln in cvrf._vulnerabilities %}"{{ vuln._cve }}"{% if not loop.last %}, {% endif %}{% endfor %});
+  script_tag(name:"cvss_base", value:"{{ cvrf.getHighestCVSS()._basescore }}");
+  script_tag(name:"cvss_base_vector", value:"{{ cvrf.getHighestCVSS()._vector }}");
+  script_name("{{ cvrf._title }} ({{ cvrf._tracking._identification._id }})");
+  script_tag(name: "summary", value: "{{ nasl_core.notes(cvrf, 'Summary') }}");
+  script_tag(name: "insight", value: "{{ nasl_core.notes(cvrf, 'Details') }}");
+  script_tag(name: "affected" , value: "
+{%- for product in cvrf.getProductList() %}
+  {{ product._name }} {% if not loop.last %}, {% endif %}
+
+{%- endfor %}");
+  script_tag(name: "solution" , value:"Please Install the Updated Packages.");
+
+  script_xref(name: "{{ cvrf._tracking._id }}", value: "{{ cvrf._tracking._id }}");
+{%- for ref in cvrf._references %}
+  script_xref(name: "URL" , value: "{{ ref._url  }}");
+{%- endfor %}
+  script_summary("Check for the {{ cvrf._title }}");
+  script_category(ACT_GATHER_INFO);
+  script_copyright("Copyright (C) {{ now.strftime('%Y') }} Greenbone Networks GmbH");
+  script_family("{{ script_family }}");
+  script_dependencies("gather-package-list.nasl");
+  script_mandatory_keys({% if os_cpe %}"HostDetails/OS/{{ os_cpe }}", {% endif %}"login/SSH/success", "ssh/login/release");
+  exit(0);
+}
+
+
+{% if red_hat %}include("pkg-lib-rpm.inc");{% endif %}
+
+release = get_kb_item("ssh/login/release");
+
+res = "";
+if(release == NULL){
+  exit(0);
+}
+
+{%- if red_hat %}
+{{ nasl_core.isrpmvuln(cvrf.getProductList(), cvrf._producttree) }}
+{%- else %}
+# Not red_hat
+{%- endif %}
+
+if (__pkg_match) exit(99); # Not vulnerable.
+exit(0);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/farolluz/templates/nasl_core.j2	Tue Sep 23 15:19:14 2014 +0200
@@ -0,0 +1,59 @@
+{#
+# Description:
+# Template macros for generation of NASL documents
+#
+# Authors:
+# Benoît Allard <benoit.allard@greenbone.net>
+#
+# Copyright:
+# Copyright (C) 2014 Greenbone Networks GmbH
+#
+# 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 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+-#}
+
+{% macro isrpmvuln(plist, ptree) %}
+{%- set done = [] %}
+{% for prod in plist %}
+  {%- set os, package = ptree.decomposeProduct(prod._productid) %}
+  {%- if os is not none %}
+    {%- set rls = os._name | release_map %}
+    {%- set rpm = package._name | for_rpmvuln %}
+    {%- if rls != 'UNKNOWN' %}
+      {%- if (rls, rpm) not in done %}
+# {{ package._name }} on {{ os._name }}
+if ((res = isrpmvuln(pkg:"{{ package._name | package_name }}", rpm:"{{ rpm }}", rls:"{{ rls }}")) != NULL)
+  {
+    security_message(data:res);
+    exit(0);
+  }
+        {{- done.append((rls, rpm)) or '' }}
+      {%- endif %}
+    {%- else %}
+# Unknown release: {{ os._name }}
+    {%- endif %}
+  {%- endif %}
+{%- endfor %}
+{% endmacro %}
+
+{% macro notes(cvrf, name) %}
+{%- for note in cvrf._notes %}
+  {%- if note._type == name or note._title == name %}{{ note._note.replace('"', "'") }}{% endif %}
+{%- endfor %}
+{%- for vulnerability in cvrf._vulnerabilities %}
+  {%- for note in vulnerability._notes %}
+    {%- if note._type == name or note._title == name %}{{ note._note.replace('"', "'") }}{% endif %}
+  {%- endfor %}
+{%- endfor %}
+{% endmacro %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/farolluz/templates/oval.j2	Tue Sep 23 15:19:14 2014 +0200
@@ -0,0 +1,154 @@
+{#
+# Description:
+# Template for generation of OVAL documents
+#
+# Authors:
+# Antu Sanadi <santu@secpod.com>
+#
+# Copyright:
+# Copyright (C) 2014 Greenbone Networks GmbH
+#
+# 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 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+-#}
+
+<?xml version="1.0" encoding="UTF-8"?>
+{% import "oval_core.j2" as oval_core -%}
+<oval_definitions xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5" xmlns:oval-def="http://oval.mitre.org/XMLSchema/oval-definitions-5" 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#esx esx-definitions-schema.xsd http://oval.mitre.org/XMLSchema/oval-definitions-5#unix unix-definitions-schema.xsd http://oval.mitre.org/XMLSchema/oval-definitions-5#linux linux-definitions-schema.xsd http://oval.mitre.org/XMLSchema/oval-definitions-5#windows windows-definitions-schema.xsd http://oval.mitre.org/XMLSchema/oval-definitions-5#independent independent-definitions-schema.xsd http://oval.mitre.org/XMLSchema/oval-definitions-5 oval-definitions-schema.xsd http://oval.mitre.org/XMLSchema/oval-definitions-5#solaris solaris-definitions-schema.xsd http://oval.mitre.org/XMLSchema/oval-common-5 oval-common-schema.xsd http://oval.mitre.org/XMLSchema/oval-definitions-5#hpux hpux-definitions-schema.xsd http://oval.mitre.org/XMLSchema/oval-definitions-5#aix aix-definitions-schema.xsd">
+  <generator>
+    <oval:product_name>SecPod SCAP Repository</oval:product_name>
+    <oval:schema_version>5.10</oval:schema_version>
+    <oval:timestamp>{{ now.isoformat() }}</oval:timestamp>
+  </generator>
+  <definitions>
+{%- set done = [] %}
+{% for prod in cvrf.getProductList()   %}
+  {%- set os, package = cvrf._producttree.decomposeProduct(prod._productid) %}
+   {%- if os is not none %}
+    {%- set rls = os._name | release_map %}
+    {%- set rpm = package._name | for_rpmvuln %}
+    {%- if rls != 'UNKNOWN' %}
+      {%- if (rls, rpm) not in done %}
+  <definition version="1" class="inventory" id="oval:org.secpod.oval:def:501309">
+      <metadata>
+        <title> {{ os._name }} is installed</title>
+        <affected family="unix">
+          <platform>{{ os._name }}</platform>
+        </affected>
+        <reference source="CPE" ref_id="{{ os_cpe }}"/>
+        <description>{{ os._name }} is installed</description>
+        <oval_repository>
+          <dates>
+            <submitted date="{{ now.isoformat() }}">
+              <contributor organization="SecPod Technologies">SecPod Team</contributor>
+            </submitted>
+          </dates>
+          <status>ACCEPTED</status>
+        </oval_repository>
+      </metadata>
+      <criteria>
+        <criterion comment="{{ os._name }} is installed" test_ref="oval:org.secpod.oval:tst:511359"/>
+      </criteria>
+   </definition>
+    <definition version="1" class="inventory" id="oval:org.secpod.oval:def:501309">
+      <metadata>
+        <title> {{ package._name }} is installed</title>
+        <affected family="unix">
+          <platform>{{ package._name }}</platform>
+        </affected>
+        <reference source="CPE" ref_id="{{ os_cpe }}"/>
+        <description>{{ package._name }} is installed</description>
+        <oval_repository>
+          <dates>
+            <submitted date="{{ now.isoformat() }}">
+              <contributor organization="SecPod Technologies">SecPod Team</contributor>
+            </submitted>
+          </dates>
+          <status>ACCEPTED</status>
+        </oval_repository>
+      </metadata>
+      <criteria>
+        <criterion comment="{{ package._name }} is installed" test_ref="oval:org.secpod.oval:tst:511359"/>
+      </criteria>
+    </definition>
+    <definition version="0" class="patch" id="oval:org.secpod.oval:def:501352">
+      <metadata>
+        <title>{{ cvrf._title }} ({{ cvrf._tracking._id }})</title>
+        <affected family="unix">
+          <platform>{{ os._name }}</platform>
+          <product> {{ package._name }}</product>
+        </affected>
+        <reference source="VENDOR" ref_url="{% for ref in cvrf._references %} {%-if 'RHSA-' in ref._url %}{{ref._url}}{%- endif %} {%- endfor %}" ref_id="{{ cvrf._tracking._id }}"/>
+
+        {%- for vuln in cvrf._vulnerabilities %}
+        <reference source="CVE" ref_url="http://www.scaprepo.com/view.jsp?id={{ vuln._cve }}" ref_id="{{ vuln._cve }}"/>
+        {%- endfor %})
+        <description>{{ oval_core.notes(cvrf, 'Details') }}</description>
+        <oval_repository>
+          <dates>
+            <submitted date="{{ now.isoformat() }}">
+              <contributor organization="SecPod Technologies">SecPod Team</contributor>
+            </submitted>
+          </dates>
+          <status>INITIAL SUBMISSION</status>
+        </oval_repository>
+      </metadata>
+      <criteria operator="AND">
+        <extend_definition comment="{{ os._name }} is installed" definition_ref="oval:org.secpod.oval:def:501309"/>
+        <extend_definition comment=" {{ package._name }} is installed" definition_ref="oval:org.secpod.oval:def:203387"/>
+        <criteria comment="All dependent packages of {{ package._name }} " operator="OR">
+          <criterion comment=" {{ package._name }} is earlier than 0:2.3.5-3.el7_0" test_ref="oval:org.secpod.oval:tst:215690"/>
+        </criteria>
+      </criteria>
+    </definition>
+  </definitions>
+  <tests>
+    <textfilecontent54_test xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent" comment="Red Hat Enterprise Linux 7 is installed" id="oval:org.secpod.oval:tst:511359" version="1" check="all" check_existence="at_least_one_exists">
+      <object object_ref="oval:org.secpod.oval:obj:500000"/>
+      <state state_ref="oval:org.secpod.oval:ste:502133"/>
+    </textfilecontent54_test>
+    <rpminfo_test xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#linux" comment="{{ package._name }} is installed" version="0" check="all" check_existence="at_least_one_exists">
+      <object object_ref="oval:org.secpod.oval:obj:200887"/>
+    </rpminfo_test>
+    <rpminfo_test xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#linux" comment=" {{ package._name }} is earlier than 0:2.3.5-3.el7_0" id="oval:org.secpod.oval:tst:215690" version="0" check="all" check_existence="at_least_one_exists">
+      <object object_ref="oval:org.secpod.oval:obj:200887"/>
+      <state state_ref="oval:org.secpod.oval:ste:203835"/>
+    </rpminfo_test>
+  </tests>
+  <objects>
+    <textfilecontent54_object xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent" comment="Object holds RHEL version" id="oval:org.secpod.oval:obj:500000" version="1">
+      <path>/etc</path>
+      <filename>redhat-release</filename>
+      <pattern operation="pattern match">^Red Hat Enterprise.*release.*$</pattern>
+      <instance datatype="int">1</instance>
+    </textfilecontent54_object>
+    <rpminfo_object xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#linux" comment="resteasy-base package information" id="oval:org.secpod.oval:obj:200887" version="0">
+      <name>{{ package._name }}</name>
+    </rpminfo_object>
+  </objects>
+  <states>
+    <textfilecontent54_state xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent" comment="State matches RHEL 7" id="oval:org.secpod.oval:ste:502133" version="1">
+      <text operation="pattern match">^Red Hat Enterprise.*release 7.*$</text>
+    </textfilecontent54_state>
+    <rpminfo_state xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#linux" comment="version is earlier than 0:2.3.5-3.el7_0" id="oval:org.secpod.oval:ste:203835" version="0">
+      <evr datatype="evr_string" operation="less than">0:2.3.5-3.el7_0</evr>
+    </rpminfo_state>
+  </states>
+</oval_definitions>
+
+  {{- done.append((rls, rpm)) or '' }}
+      {%- endif %}
+    {%- endif %}
+  {%- endif %}
+{%- endfor %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/farolluz/templates/oval_core.j2	Tue Sep 23 15:19:14 2014 +0200
@@ -0,0 +1,35 @@
+{#
+# Description:
+# Template macros for generation of OVAL documents
+#
+# Authors:
+# Benoît Allard <benoit.allard@greenbone.net>
+#
+# Copyright:
+# Copyright (C) 2014 Greenbone Networks GmbH
+#
+# 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 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+-#}
+
+{% macro notes(cvrf, name) %}
+{%- for note in cvrf._notes %}
+  {%- if note._type == name or note._title == name %}{{ note._note.replace('"', "'") }}{% endif %}
+{%- endfor %}
+{%- for vulnerability in cvrf._vulnerabilities %}
+  {%- for note in vulnerability._notes %}
+    {%- if note._type == name or note._title == name %}{{ note._note.replace('"', "'") }}{% endif %}
+  {%- endfor %}
+{%- endfor %}
+{% endmacro %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/farolluz/utils.py	Tue Sep 23 15:19:14 2014 +0200
@@ -0,0 +1,32 @@
+# -*- coding: utf-8 -*-
+# Description:
+# Utilities used at multiple places.
+#
+# Authors:
+# Benoît Allard <benoit.allard@greenbone.net>
+#
+# Copyright:
+# Copyright (C) 2014 Greenbone Networks GmbH
+#
+# 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 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+
+from datetime import datetime
+
+from .parsers import cvrf
+
+def utcnow():
+    """ This function returns the current date in a timezone aware fashion """
+    return cvrf.parseDate(datetime.utcnow().isoformat()+'Z')
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/parse_cvrf	Tue Sep 23 15:19:14 2014 +0200
@@ -0,0 +1,36 @@
+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Authors:
+# Benoît Allard <benoit.allard@greenbone.net>
+#
+# Copyright:
+# Copyright (C) 2014 Greenbone Networks GmbH
+#
+# 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 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+
+import sys
+
+from farolluz.parsers.cvrf import parse
+
+if __name__ == "__main__":
+    with open(sys.argv[1], 'rt') as f:
+        cvrf = parse(f)
+    cvrf.validate()
+    print(cvrf)
+    print(cvrf.getHighestCVSS()._vector)
+    print(cvrf.getProductList())
+    print(cvrf._producttree._branches)
+#    print(cvrf._producttree._branches[0]._childs)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/render	Tue Sep 23 15:19:14 2014 +0200
@@ -0,0 +1,32 @@
+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Authors:
+# Benoît Allard <benoit.allard@greenbone.net>
+#
+# Copyright:
+# Copyright (C) 2014 Greenbone Networks GmbH
+#
+# 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 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+
+import sys
+
+from farolluz.renderer import main
+
+if __name__ == "__main__":
+    template = "nasl.j2"
+    if len(sys.argv) >= 3:
+        template = sys.argv[2]
+    main(sys.argv[1], template)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/setup.py	Tue Sep 23 15:19:14 2014 +0200
@@ -0,0 +1,45 @@
+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Authors:
+# Benoît Allard <benoit.allard@greenbone.net>
+#
+# Copyright:
+# Copyright (C) 2014 Greenbone Networks GmbH
+#
+# 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 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+
+from setuptools import setup
+
+from farolluz import __version__
+
+with open('README.txt', 'rt') as f:
+    long_description = f.read()
+
+setup(
+    name='farolluz',
+    version=__version__,
+    description="Utilities to manipulate security advisories",
+    long_description=long_description,
+    author="Benoît Allard",
+    author_email='benoit.allard@greenbone.net',
+    license='GPLv2+',
+    packages=['farolluz', 'farolluz.parsers'],
+#    package_dir={'farolluz': 'farolluz'},
+#    include_package_data=True,
+#    package_data={'farolluz': ['templates/*.j2']},
+    scripts=['parse_cvrf', 'render'],
+    install_requires=['Jinja2'],
+)
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)