aboutsummaryrefslogtreecommitdiffstats
path: root/security/vuxml/files/extra-validation.py
blob: 3252baaec25fd5b8a6c2f0c66037da1f5fdfbc5c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#!/usr/bin/env python
# $FreeBSD$

import datetime
import xml.etree.ElementTree as ET
import sys
import re

if len(sys.argv) != 2:
    print("Usage: %s vuln.xml" % (sys.argv[0]))
    sys.exit(1)

re_date = re.compile(r'^(19|20)[0-9]{2}-[0-9]{2}-[0-9]{2}$')

# warn if description has more than X characters
DESCRIPTION_LENGTH = 5000

tree = ET.parse(sys.argv[1])
root = tree.getroot()

namespace = "{http://www.vuxml.org/apps/vuxml-1}"

ret = 0


def dateof(string):
    return datetime.datetime.strptime(string, "%Y-%m-%d")

all_vids = set()


for vuln in root:
    vid = vuln.get("vid")

    cancelled = False if vuln.find(namespace+"cancelled") is None else True
    if cancelled:
        continue

    # Validate Vids
    if vid in all_vids:
        print("Error: duplicate vid : {0}".format(vid))
    all_vids.add(vid)

    # Validate References
    references = vuln.find(namespace+"references")
    if references is None:
        print("Error: references is None : {0}".format(vid))
        ret = 1
    else:
        prev = references[0]
        for reference in references:
            if reference.tag < prev.tag:
                #print("Warn: tags out of order ({1} and {2}): {0}".format(vid, prev.tag[len(namespace):], reference.tag[len(namespace):]))
                pass
            prev = reference

    # Validate Dates
    dates = vuln.find(namespace+"dates")
    if dates is None:
        print("Error: no date : {0}".format(vid))
        ret = 1
    else:
        discovery = dates.find(namespace+"discovery")
        entry = dates.find(namespace+"entry")
        modified = dates.find(namespace+"modified")
        if discovery is None:
            print("Error: discovery is None : {0}".format(vid))
            ret = 1
        elif entry is None:
            print("Error: entry is None : {0}".format(vid))
            ret = 1
        else:
            if modified is None:
                modified = entry
            if not (dateof(discovery.text) <= dateof(entry.text) <= dateof(modified.text)):
                print("Error: dates are insane : {0}".format(vid))
                ret = 1

        # Make sure the dates are in YYYY-MM-DD format
        datelist = [discovery.text, entry.text] + ([modified.text] if modified is not None else [])
        for d in datelist:
            if not re_date.match(d):
                print("Warning: dates must be in YYYY-MM-DD format: {0}".format(d))

        # Check description lengths
        description = vuln.find(namespace + "description")
        description_len = len(ET.tostring(description))
        if description_len > DESCRIPTION_LENGTH:
            print("Warning: description too long ({0} chars, {1} is warning threshold): {2})" \
                  .format(description_len, DESCRIPTION_LENGTH, vid))

sys.exit(ret)