Skip to content

Commit

Permalink
Add zip file checks (#15)
Browse files Browse the repository at this point in the history
Signed-off-by: romanodanilo <[email protected]>
  • Loading branch information
romanodanilo authored Aug 2, 2024
1 parent 36c689b commit 7b43b47
Show file tree
Hide file tree
Showing 12 changed files with 717 additions and 1 deletion.
4 changes: 4 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from qc_otx import constants
from qc_otx.checks.core_checker import core_checker
from qc_otx.checks.data_type_checker import data_type_checker
from qc_otx.checks.zip_file_checker import zip_file_checker
from qc_otx.checks import utils, models

logging.basicConfig(format="%(asctime)s - %(message)s", level=logging.INFO)
Expand Down Expand Up @@ -61,6 +62,9 @@ def main():
# 2. Run data type checks
data_type_checker.run_checks(checker_data)

# 3. Run zip file checks
zip_file_checker.run_checks(checker_data)

result.write_to_file(
config.get_checker_bundle_param(
checker_bundle_name=constants.BUNDLE_NAME, param_name="resultFile"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ def check_rule(checker_data: models.CheckerData) -> None:
has_issue = current_value not in signature_dict[current_variable_type]

if has_issue:
current_xpath = tree.getpath(step_by_name_node)
current_xpath = tree.getelementpath(step_by_name_node)
issue_id = checker_data.result.register_issue(
checker_bundle_name=constants.BUNDLE_NAME,
checker_id=data_type_constants.CHECKER_ID,
Expand Down
4 changes: 4 additions & 0 deletions qc_otx/checks/zip_file_checker/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from . import zip_file_constants as zip_file_constants
from . import zip_file_checker as zip_file_checker
from . import type_safe_zip_file as type_safe_zip_file
from . import type_safe_unzip_file as type_safe_unzip_file
94 changes: 94 additions & 0 deletions qc_otx/checks/zip_file_checker/type_safe_unzip_file.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import logging

from qc_baselib import IssueSeverity

from qc_otx import constants
from qc_otx.checks import models

from qc_otx.checks.zip_file_checker import zip_file_constants


def check_rule(checker_data: models.CheckerData) -> None:
"""
Rule ID: asam.net:otx:1.0.0:zip_file.chk_001.type_safe_unzip_file
Description: In an UnZipFile action, the list described by ListTerm <extensions> shall
have a data type of <String>.
Severity: ERROR
Version range: [1.0.0, )
Remark:
None
"""
logging.info("Executing type_safe_unzip_file check")

issue_severity = IssueSeverity.ERROR

rule_uid = checker_data.result.register_rule(
checker_bundle_name=constants.BUNDLE_NAME,
checker_id=zip_file_constants.CHECKER_ID,
emanating_entity="asam.net",
standard="otx",
definition_setting="1.0.0",
rule_full_name="zip_file.chk_001.type_safe_unzip_file",
)

tree = checker_data.input_file_xml_root
root = tree.getroot()
nsmap = {k: v for k, v in root.nsmap.items() if k is not None}

if "xsi" not in nsmap or "zip" not in nsmap:
return
unzip_nodes = tree.xpath("//*[@xsi:type='zip:UnZipFile']", namespaces=nsmap)

logging.debug(f"unzip_nodes {unzip_nodes}")

for unzip_node in unzip_nodes:
list_children = unzip_node.xpath(
".//*[@xsi:type='ListLiteral']", namespaces=nsmap
)
logging.debug(f"list_children : {list_children}")
if list_children is None or len(list_children) == 0:
continue

for current_list in list_children:
logging.debug(f"current_list : {current_list}")

type_children = current_list.xpath(".//*[@xsi:type]", namespaces=nsmap)

logging.debug(f"type_children : {type_children}")
if type_children is None:
continue

string_type_num = 0

for type_child in type_children:
xsi_ns = "{" + nsmap["xsi"] + "}"
current_type = type_child.get(f"{xsi_ns}type")
logging.debug(f"type_child : {type_child.attrib}")
if current_type is None:
continue
logging.debug(f"current_type : {current_type}")
if current_type == "String":
string_type_num += 1

has_issue = string_type_num == 0
if has_issue:
current_xpath = tree.getelementpath(current_list)
issue_id = checker_data.result.register_issue(
checker_bundle_name=constants.BUNDLE_NAME,
checker_id=zip_file_constants.CHECKER_ID,
description="Issue flagging when the list in an UnzipFile action does not contain type String",
level=issue_severity,
rule_uid=rule_uid,
)

checker_data.result.add_xml_location(
checker_bundle_name=constants.BUNDLE_NAME,
checker_id=zip_file_constants.CHECKER_ID,
issue_id=issue_id,
xpath=current_xpath,
description=f"Unzip action does not contain any String type",
)
94 changes: 94 additions & 0 deletions qc_otx/checks/zip_file_checker/type_safe_zip_file.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import logging

from qc_baselib import IssueSeverity

from qc_otx import constants
from qc_otx.checks import models

from qc_otx.checks.zip_file_checker import zip_file_constants


def check_rule(checker_data: models.CheckerData) -> None:
"""
Rule ID: asam.net:otx:1.0.0:zip_file.chk_002.type_safe_zip_file
Description: In a ZipFile action, the list described by ListTerm <extensions> shall
have a data type of <String>.
Severity: ERROR
Version range: [1.0.0, )
Remark:
None
"""
logging.info("Executing correct_target_for_structure_element check")

issue_severity = IssueSeverity.ERROR

rule_uid = checker_data.result.register_rule(
checker_bundle_name=constants.BUNDLE_NAME,
checker_id=zip_file_constants.CHECKER_ID,
emanating_entity="asam.net",
standard="otx",
definition_setting="1.0.0",
rule_full_name="zip_file.chk_002.type_safe_zip_file",
)

tree = checker_data.input_file_xml_root
root = tree.getroot()
nsmap = {k: v for k, v in root.nsmap.items() if k is not None}

if "xsi" not in nsmap or "zip" not in nsmap:
return
zip_nodes = tree.xpath("//*[@xsi:type='zip:ZipFile']", namespaces=nsmap)

logging.debug(f"zip_nodes {zip_nodes}")

for zip_node in zip_nodes:
list_children = zip_node.xpath(
".//*[@xsi:type='ListLiteral']", namespaces=nsmap
)
logging.debug(f"list_children : {list_children}")
if list_children is None or len(list_children) == 0:
continue

for current_list in list_children:
logging.debug(f"current_list : {current_list}")

type_children = current_list.xpath(".//*[@xsi:type]", namespaces=nsmap)

logging.debug(f"type_children : {type_children}")
if type_children is None:
continue

string_type_num = 0

for type_child in type_children:
xsi_ns = "{" + nsmap["xsi"] + "}"
current_type = type_child.get(f"{xsi_ns}type")
logging.debug(f"type_child : {type_child.attrib}")
if current_type is None:
continue
logging.debug(f"current_type : {current_type}")
if current_type == "String":
string_type_num += 1

has_issue = string_type_num == 0
if has_issue:
current_xpath = tree.getelementpath(current_list)
issue_id = checker_data.result.register_issue(
checker_bundle_name=constants.BUNDLE_NAME,
checker_id=zip_file_constants.CHECKER_ID,
description="Issue flagging when the list in an ZipFile action does not contain type String",
level=issue_severity,
rule_uid=rule_uid,
)

checker_data.result.add_xml_location(
checker_bundle_name=constants.BUNDLE_NAME,
checker_id=zip_file_constants.CHECKER_ID,
issue_id=issue_id,
xpath=current_xpath,
description=f"Zip action does not contain any String type",
)
43 changes: 43 additions & 0 deletions qc_otx/checks/zip_file_checker/zip_file_checker.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import logging

from lxml import etree

from qc_baselib import Configuration, Result, StatusType

from qc_otx import constants
from qc_otx.checks import utils, models

from qc_otx.checks.zip_file_checker import (
zip_file_constants,
type_safe_zip_file,
type_safe_unzip_file,
)


def run_checks(checker_data: models.CheckerData) -> None:
logging.info("Executing zip_file checks")

checker_data.result.register_checker(
checker_bundle_name=constants.BUNDLE_NAME,
checker_id=zip_file_constants.CHECKER_ID,
description="Check if zip_file properties of input file are properly set",
summary="",
)

rule_list = [
type_safe_zip_file.check_rule, # Chk001
type_safe_unzip_file.check_rule, # Chk002
]

for rule in rule_list:
rule(checker_data=checker_data)

logging.info(
f"Issues found - {checker_data.result.get_checker_issue_count(checker_bundle_name=constants.BUNDLE_NAME, checker_id=zip_file_constants.CHECKER_ID)}"
)

checker_data.result.set_checker_status(
checker_bundle_name=constants.BUNDLE_NAME,
checker_id=zip_file_constants.CHECKER_ID,
status=StatusType.COMPLETED,
)
1 change: 1 addition & 0 deletions qc_otx/checks/zip_file_checker/zip_file_constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
CHECKER_ID = "zip_file_otx"
93 changes: 93 additions & 0 deletions tests/data/ZipFile_Chk001/negative.otx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<otx name="ZipHandlingExample" id="zip_example_otx" version="1.0.0" timestamp="2016-04-19T12:58:48.709+01:00" package="Examples"
xmlns:otx="http://iso.org/OTX/1.0.0"
xmlns="http://iso.org/OTX/1.0.0"
xmlns:zip="http://iso.org/OTX/1.0.0/ZipHandling"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://iso.org/OTX/1.0.0 ../Core/otx.xsd
http://iso.org/OTX/1.0.0/ZipHandling ../ASAMExtensionInterface/otxIFD_ZipHandling.xsd">
<specification>This document contains four example procedures, using the ZipFile / UnZipFile ActionRealisations. The examples are very simple, assuming the presence of files at the given source locations. Additional examples could be added here too.
</specification>
<procedures>
<procedure id="zip_file_example_1" name="zipExample1" visibility="PUBLIC">
<specification>Zip all files in "./source/files" unconditionally and store them in "./files.zip"
</specification>
<realisation>
<flow>
<action id="zip_file" name="zipFile">
<realisation xsi:type="zip:ZipFile">
<zip:source xsi:type="StringLiteral" value="source/files">
</zip:source>
<zip:target xsi:type="StringLiteral" value="files.zip">
</zip:target>
</realisation>
</action>
</flow>
</realisation>
</procedure>
<procedure id="zip_file_example_2" name="zipExample2" visibility="PUBLIC">
<specification>Uncompress all files contained in "files.zip" unconditionally into the folder "source".
</specification>
<realisation>
<flow>
<action id="unzip_file" name="unzipFile">
<realisation xsi:type="zip:UnZipFile">
<zip:source xsi:type="StringLiteral" value="files.zip">
</zip:source>
<zip:target xsi:type="StringLiteral" value="source">
</zip:target>
</realisation>
</action>
</flow>
</realisation>
</procedure>
<procedure id="zip_file_example_3" name="zipExample3" visibility="PUBLIC">
<specification>Zip all log files (ending with '.log' oder similar to '.log_1', '.log_20' and so on) and store them in the "log.zip" file.
</specification>
<realisation>
<flow>
<action id="zip_log_files" name="zipLogFiles">
<realisation xsi:type="zip:ZipFile">
<zip:source xsi:type="StringLiteral" value="source/files">
</zip:source>
<zip:target xsi:type="StringLiteral" value="logs.zip">
</zip:target>
<zip:extensions xsi:type="ListLiteral">
<itemType xsi:type="String"></itemType>
<items>
<item xsi:type="StringLiteral" value="log"></item>
<item xsi:type="StringLiteral" value="log_*"></item>
</items>
</zip:extensions>
<zip:append xsi:type="BooleanLiteral" value="true"></zip:append>
<zip:override xsi:type="BooleanLiteral" value="false"></zip:override>
</realisation>
</action>
</flow>
</realisation>
</procedure>
<procedure id="zip_file_example_4" name="zipExample4" visibility="PUBLIC">
<specification>Uncompresses only a catalog.xml file from the root of the given zip container. Within this container, additional information can be found, describing the contents of the zip file. It is expected in this example, that there is only one .xml file (which is the catalog) contained in the zip.

This example shows, that it might be useful to be able to control whether the (un) compression of zip containers should happen recursively or not.
</specification>
<realisation>
<flow>
<action id="unzip_catalog_file" name="unzipCatalogFile">
<realisation xsi:type="zip:UnZipFile">
<zip:source xsi:type="StringLiteral" value="myContainer.ending">
</zip:source>
<zip:target xsi:type="StringLiteral" value="myContainer">
</zip:target>
<zip:extensions xsi:type="ListLiteral">
<itemType xsi:type="Double"></itemType>
<items>
<item xsi:type="StringLiteral" value="xml"></item>
</items>
</zip:extensions>
</realisation>
</action>
</flow>
</realisation>
</procedure>
</procedures>
</otx>
Loading

0 comments on commit 7b43b47

Please sign in to comment.