Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 23 additions & 25 deletions custom_json_diff/lib/bom_diff_template.j2
Original file line number Diff line number Diff line change
Expand Up @@ -589,17 +589,17 @@
<summary>{{ item['short_ref'] }}</summary>
<ul>
<li>ref: {{ item['ref'] }}</li>
{% if item['dependsOn']|length > 0 %}
<li>dependencies:</li>
<ul>
{% for dep in item['dependsOn'] %}
<li>{{ dep }}</li>
{% endfor %}
</ul>
{% endif %}
{% if item['dependsOn']|length == 0 %}
<li>dependencies: N/A</li>
{% for key, value in item|items %}
{% if key == "dependsOn" %}
<li>dependencies:
<ul>
{% for dep in item['dependsOn'] %}
<li>{{ dep }}</li>
{% endfor %}
</ul>
</li>
{% endif %}
{% endfor %}
</ul>
</details>
{% endfor %}</td>
Expand All @@ -608,19 +608,18 @@
<summary>{{ item['short_ref'] }}</summary>
<ul>
<li>ref: {{ item['ref'] }}</li>
{% if item['dependsOn']|length > 0 %}
<li>dependencies:</li>
<ul>
{% for dep in item['dependsOn'] %}
<li>{{ dep }}</li>
{% endfor %}
</ul>
{% endif %}
{% if item['dependsOn']|length == 0 %}
<li>dependencies: N/A</li>
{% for key, value in item|items %}
{% if key == "dependsOn" %}
<li>dependencies:
<ul>
{% for dep in item['dependsOn'] %}
<li>{{ dep }}</li>
{% endfor %}
</ul>
</li>
{% endif %}
{% endfor %}
</ul>

</details>
{% endfor %}</td>
</tr>
Expand Down Expand Up @@ -1160,7 +1159,8 @@
<summary>{{ item['short_ref'] }}</summary>
<ul>
<li>ref: {{ item['ref'] }}</li>
{% if item['dependsOn']|length >0 %}
{% for key, value in item|items %}
{% if key == "dependsOn" %}
<li>dependencies:
<ul>
{% for dep in item['dependsOn'] %}
Expand All @@ -1169,9 +1169,7 @@
</ul>
</li>
{% endif %}
{% if item['dependsOn']|length == 0 %}
<li>dependencies: N/A</li>
{% endif %}
{% endfor %}
</ul>
</details>
{% endfor %}</td>
Expand Down
13 changes: 5 additions & 8 deletions custom_json_diff/lib/custom_diff.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,6 @@ def add_short_ref_for_report(diffs: Dict, options: "Options") -> Dict:
diffs["diff_summary"][options.file_2].get("dependencies", []), purl_regex)
diffs["common_summary"]["dependencies"] = parse_purls(
diffs["common_summary"].get("dependencies", []), purl_regex)
diffs["diff_summary"][options.file_1] = filter_empty(options.include_empty, diffs["diff_summary"][options.file_1])
diffs["diff_summary"][options.file_2] = filter_empty(options.include_empty, diffs["diff_summary"][options.file_2])
diffs["common_summary"] = filter_empty(options.include_empty, diffs["common_summary"])
return diffs


Expand Down Expand Up @@ -108,7 +105,6 @@ def generate_bom_diff(bom: BomDicts, commons: BomDicts, common_refs: Dict) -> Di
case _:
diff_summary["components"]["other_components"].append(i.to_dict()) #type: ignore
diff_summary["misc_data"] = (bom.misc_data - commons.misc_data).to_dict()
diff_summary["components"] = filter_empty(bom.options.include_empty, diff_summary["components"]) #type: ignore
return diff_summary


Expand Down Expand Up @@ -223,7 +219,7 @@ def parse_purls(deps: List[Dict], regex: re.Pattern) -> List[Dict]:
def perform_bom_diff(bom_1: BomDicts, bom_2: BomDicts) -> Tuple[int, Dict]:
b1, b2 = order_documents(bom_1, bom_2)
common_bom = b1.intersection(b2, "common_summary")
output = filter_empty(common_bom.options.include_empty, common_bom.to_summary())
output = common_bom.to_summary()
status, diffs = summarize_bom_diffs(b1, b2, common_bom)
output |= {"diff_summary": diffs}
return status, output
Expand Down Expand Up @@ -253,6 +249,8 @@ def report_results(status: int, diffs: Dict, options: Options, j1: BomDicts, j2:
elif options.preconfig_type == "csaf":
export_html_report(report_file, diffs, options, status)
if options.output:
if not options.include_empty:
diffs = filter_empty(options.include_empty, diffs)
json_dump(options.output, diffs,
error_msg=f"Failed to export diff results to {options.output}.",
success_msg=f"Diff results written to {options.output}.")
Expand Down Expand Up @@ -293,8 +291,7 @@ def summarize_bom_diffs(bom_1: BomDicts, bom_2: BomDicts, commons: BomDicts) ->
summary_1 = generate_bom_diff(bom_1, commons, common_refs)
summary_2 = generate_bom_diff(bom_2, commons_2, common_refs)
status = max(get_bom_status(summary_1), get_bom_status(summary_2))
return status, {bom_1.filename: filter_empty(bom_1.options.include_empty, summary_1),
bom_2.filename: filter_empty(bom_1.options.include_empty, summary_2)}
return status, {bom_1.filename: summary_1, bom_2.filename: summary_2}


def summarize_csaf_diffs(csaf_1: CsafDicts, csaf_2: CsafDicts, commons: CsafDicts) -> Tuple[int, Dict]:
Expand All @@ -304,4 +301,4 @@ def summarize_csaf_diffs(csaf_1: CsafDicts, csaf_2: CsafDicts, commons: CsafDict
diff_summary = generate_csaf_diff(csaf_1, commons, common_refs)
diff_summary |= generate_csaf_diff(csaf_2, commons_2, common_refs)
status = max(get_csaf_status(diff_summary[csaf_1.filename]), get_csaf_status(diff_summary[csaf_2.filename]))
return status, filter_empty(csaf_1.options.include_empty, diff_summary)
return status, diff_summary
12 changes: 8 additions & 4 deletions custom_json_diff/lib/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,14 @@ def export_html_report(outfile: str, diffs: Dict, options: "Options", status: in
template = file_read(template_file)
jinja_env = Environment(autoescape=True)
jinja_tmpl = jinja_env.from_string(str(template))
if options.preconfig_type == "bom":
report_result = render_bom_template(diffs, jinja_tmpl, options, stats_summary, status)
else:
report_result = render_csaf_template(diffs, jinja_tmpl, options, status)
try:
if options.preconfig_type == "bom":
report_result = render_bom_template(diffs, jinja_tmpl, options, stats_summary, status)
else:
report_result = render_csaf_template(diffs, jinja_tmpl, options, status)
except TypeError:
logger.warning(f"Could not render html report for {options.file_1} and {options.file_2} BOM diff. Likely an expected key is missing.")
return
file_write(outfile, report_result, error_msg=f"Unable to generate HTML report at {outfile}.",
success_msg=f"HTML report generated: {outfile}")

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "custom-json-diff"
version = "2.1.1"
version = "2.1.2"
description = "CycloneDx BOM and Oasis CSAF diffing and comparison tool."
authors = [
{ name = "Caroline Russell", email = "[email protected]" },
Expand Down
5 changes: 4 additions & 1 deletion test/test_bom_diff.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from custom_json_diff.lib.custom_diff_classes import (
BomComponent, BomDependency, BomDicts, FlatDicts, Options, BomVdr, BomVdrAffects
)
from custom_json_diff.lib.utils import filter_empty, json_dump


@pytest.fixture
Expand Down Expand Up @@ -347,7 +348,7 @@ def test_bom_diff(results, options_1):
'other_components': 0, 'services': 8, 'vulnerabilities': 0}
assert add_short_ref_for_report(result_summary, j1.options).get("diff_summary", {}).get(
j2.filename, {}).get("dependencies") == [
{'ref': 'pkg:maven/javax.activation/[email protected]?type=jar',
{'dependsOn': [], 'ref': 'pkg:maven/javax.activation/[email protected]?type=jar',
'short_ref': 'javax.activation/[email protected]'}]


Expand All @@ -368,6 +369,8 @@ def test_bom_diff_component_options(results, bom_dicts_1, bom_dicts_2, bom_dicts
_, result_summary = perform_bom_diff(bom_dicts_7, bom_dicts_8)
assert result_summary == results["result_5"]

json_dump("test/test_data.json", results, compact=True)


def test_bom_diff_vdr_options(options_1):
# test don't allow --allow-new-data or --allow-new-versions
Expand Down
7 changes: 6 additions & 1 deletion test/test_csaf_diff.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from custom_json_diff.lib.custom_diff import compare_dicts, perform_csaf_diff
from custom_json_diff.lib.custom_diff_classes import (CsafVulnerability, Options, BomVdr, BomVdrAffects
)
from custom_json_diff.lib.utils import filter_empty, json_dump


@pytest.fixture
Expand All @@ -32,15 +33,19 @@ def results():
def test_csaf_diff(results, options_1, options_2):
result, j1, j2 = compare_dicts(options_1)
_, result_summary = perform_csaf_diff(j1, j2)
results["result_13"] = result_summary
assert result_summary == results["result_13"]

result, j2, j1 = compare_dicts(options_1)
_, result_summary = perform_csaf_diff(j2, j1)
results["result_14"] = result_summary
assert result_summary == results["result_14"]

result, j1, j2 = compare_dicts(options_2)
_, result_summary = perform_csaf_diff(j2, j1)
assert result_summary["diff_summary"] == {"test/csaf_3.json": {}, "test/csaf_4.json": {}}
assert filter_empty(False, result_summary["diff_summary"]) == {"test/csaf_3.json": {}, "test/csaf_4.json": {}}

json_dump("test/results.json", results, compact=True)


def test_csaf_diff_vuln_options(options_1):
Expand Down
2 changes: 1 addition & 1 deletion test/test_data.json

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions test/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,10 @@ def test_json_dump():

def test_json_load():
assert list(json_load("test/test_data.json").keys()) == ['result_1', 'result_10', 'result_11',
'result_12', 'result_2', 'result_3',
'result_4', 'result_5', 'result_6',
'result_7', 'result_8', 'result_9',
'result_13', 'result_14']
'result_12', 'result_13', 'result_14',
'result_2', 'result_3', 'result_4',
'result_5', 'result_6', 'result_7',
'result_8', 'result_9']
assert json_load("notafile.json") == {}


Expand Down