Beispiel #1
0
def test_parse_line():
    t = threatmodel.ThreatModel()
    p = parser.SourceFileParser(t)

    lines = [{
        "line":
        "somecode.action(parameter) // @mitigates Path:To:Component against Threat with Control",
        "next_line":
        "other.action(parameter) // @mitigates Path:To:Component2 against Threat2 with Control2",
        "action": "mitigates",
        "threat": "Threat",
        "component": "Path:To:Component",
        "control": "Control",
        "annotation":
        "@mitigates Path:To:Component against Threat with Control",
        "code": "somecode.action(parameter)",
        "filename": "afile.js",
        "line_no": 66
    }]

    for line in lines:
        (data, source) = p.parse_line(line["line"], line["next_line"],
                                      line["filename"], line["line_no"])
        assert data == {
            "action": "mitigates",
            "threat": "Threat",
            "component": "Path:To:Component",
            "control": "Control"
        }
        assert source == {
            "annotation": line["annotation"],
            "code": line["code"],
            "filename": line["filename"],
            "line": line["line_no"]
        }
Beispiel #2
0
def test_parse_comment_line():
    t = threatmodel.ThreatModel()
    p = parser.SourceFileParser(t)

    lines = [{
        "line": "// A normal comment",
        "annotation": "A normal comment",
        "code": ""
    }, {
        "line": "somecode.action(parameter) // An inline comment",
        "annotation": "An inline comment",
        "code": "somecode.action(parameter)"
    }, {
        "line": "# A normal comment",
        "annotation": "A normal comment",
        "code": ""
    }, {
        "line": "somecode.action(parameter) # An inline comment",
        "annotation": "An inline comment",
        "code": "somecode.action(parameter)"
    }]

    for line in lines:
        (annotation, code) = p.parse_comment_line(line["line"])
        assert line["code"] == code
        assert line["annotation"] == annotation
Beispiel #3
0
def test_parse_control_extended_comment():
    t = threatmodel.ThreatModel()
    p = parser.SourceFileParser(t)

    comment_text = """
@control A Control (#controlid):
  description: |
    A multiline
    description
  cost: high
"""
    annotations = p.parse_comment(comment_text)
    assert len(annotations) == 1
    assert annotations[0]["control"] == "A Control (#controlid)"
    assert annotations[0]["description"] == "A multiline\ndescription\n"
    assert annotations[0]["cost"] == "high"
Beispiel #4
0
def test_parse_threat_extended_comment():
    t = threatmodel.ThreatModel()
    p = parser.SourceFileParser(t)

    comment_text = """
@threat A Threat (#threatid):
  description: |
    A multiline
    description
  impact: high
"""
    annotations = p.parse_comment(comment_text)
    assert len(annotations) == 1
    assert annotations[0]["threat"] == "A Threat (#threatid)"
    assert annotations[0]["description"] == "A multiline\ndescription\n"
    assert annotations[0]["impact"] == "high"
Beispiel #5
0
def test_parse_component_extended_comment_with_leading_stars():
    t = threatmodel.ThreatModel()
    p = parser.SourceFileParser(t)

    comment_text = """
         * @component Path:To:Component (#componentid):
         * description: |
         *   A multiline
         *   description
         * value: high
"""
    annotations = p.parse_comment(comment_text)
    assert len(annotations) == 1
    assert annotations[0]["component"] == "Path:To:Component (#componentid)"
    assert annotations[0]["description"] == "A multiline\ndescription\n"
    assert annotations[0]["value"] == "high"
Beispiel #6
0
def test_parse_review_extended_comment_with_leading_stars():
    t = threatmodel.ThreatModel()
    p = parser.SourceFileParser(t)

    comment_text = """
         * @review Path:To:Component Check something:
         *   description: |
         *     A multiline
         *     description
         *   urgent: yes
"""
    annotations = p.parse_comment(comment_text)
    assert len(annotations) == 1
    assert annotations[0]["component"] == "Path:To:Component"
    assert annotations[0]["details"] == "Check something"
    assert annotations[0]["description"] == "A multiline\ndescription\n"
    assert annotations[0]["urgent"] == True
Beispiel #7
0
    def get_parser_for_path(self, path, config_path):
        if config_path.mime:
            mime = config_path.mime
        else:
            mime = magic.from_file(path, mime=True)
        _, ext = os.path.splitext(path)

        if mime == "text/plain":
            if ext in [".yaml", ".yml"]:
                return parser.YamlFileParser(self.threatmodel)
            elif ext in [".json"]:
                return parser.YamlFileParser(self.threatmodel)
            elif ext in [".txt"]:
                return parser.TextFileParser(self.threatmodel)
            else:
                logger.warn(
                    "Unsupported file extension {} for mime type text/plain for file {}"
                    .format(ext, path))
                return None
        else:
            return parser.SourceFileParser(self.threatmodel, mime)
Beispiel #8
0
    def parse_source(self, paths, parent):
        for config_path in paths:
            abs_path = data.abs_path(parent, config_path.path)
            logger.debug("Processing source path {}".format(abs_path))
            if abs_path in self.loaded_source_paths:
                logger.debug(
                    "Skipping source path {} as it has already been processed".
                    format(abs_path))
                continue
            self.loaded_source_paths[abs_path] = True  # We've seen it now
            if data.is_threatspec_path(abs_path):
                logger.debug(
                    "Found threatspec.yaml, loading source configuration from {}"
                    .format(abs_path))
                new_config = config.Config()

                new_config_file = data.abs_path(abs_path, "threatspec.yaml")
                (valid, error) = data.validate_yaml_file(
                    new_config_file, os.path.join("data",
                                                  "config_schema.json"))
                if not valid:
                    logger.error(
                        "Couldn't validate the configation file {}: {}".format(
                            abs_path, error))
                    sys.exit(0)

                new_config.load(data.read_yaml(new_config_file))
                self.parse_source(new_config.paths, abs_path)

            for path in data.recurse_path(abs_path):
                if data.path_ignored(path, config_path.ignore):
                    logger.debug("Skipping ignored file path: {}".format(path))
                    continue
                logger.debug("Parsing source files in path {}".format(path))
                if os.path.isfile(path):
                    self.parser = parser.SourceFileParser(self.threatmodel)
                    self.parser.parse_file(path)
                    """
Beispiel #9
0
def test_source_file_parser_parse_comments():
    t = threatmodel.ThreatModel()
    p = parser.SourceFileParser(t)

    comments = [{
        "test":
        "@mitigates Path:To:Component against a multi word threat with a multi word control",
        "result": {
            "action": "mitigate",
            "component": "Path:To:Component",
            "threat": "a multi word threat",
            "control": "a multi word control"
        }
    }, {
        "test":
        "@accepts a multi word threat to Path:To:Component with why it has been accepted",
        "result": {
            "action": "accept",
            "threat": "a multi word threat",
            "component": "Path:To:Component",
            "details": "why it has been accepted"
        }
    }, {
        "test":
        "@transfers a multi word threat from Path:To:Source to Path:To:Destination with why it has been transfered",
        "result": {
            "action": "transfer",
            "threat": "a multi word threat",
            "source_component": "Path:To:Source",
            "destination_component": "Path:To:Destination",
            "details": "why it has been transfered"
        }
    }, {
        "test":
        "@exposes Path:To:Component to a multi word threat with how it is exposed",
        "result": {
            "action": "expose",
            "threat": "a multi word threat",
            "component": "Path:To:Component",
            "details": "how it is exposed"
        }
    }, {
        "test":
        "@connects Path:To:Source with Path:To:Destination with details about connection",
        "result": {
            "action": "connect",
            "source_component": "Path:To:Source",
            "destination_component": "Path:To:Destination",
            "direction": "with",
            "details": "details about connection"
        }
    }, {
        "test": "@review Path:To:Component something worth noting",
        "result": {
            "action": "review",
            "component": "Path:To:Component",
            "details": "something worth noting"
        }
    }, {
        "test": "@tests a multi word control for Path:To:Component",
        "result": {
            "action": "test",
            "control": "a multi word control",
            "component": "Path:To:Component"
        }
    }]

    for comment in comments:
        data = p.parse_comment(comment["test"])
        assert len(data) == 1
        data[0].pop("annotation")
        data[0].pop("line")
        assert data[0] == comment["result"]