Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support running the analysis with SBOM and the main software component with no repository #165

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
2 changes: 2 additions & 0 deletions docs/source/pages/cli_usage/action_verify-policy.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
.. Copyright (c) 2023 - 2023, Oracle and/or its affiliates. All rights reserved.
.. Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.

.. _verify-policy-action-cli:

=============
Verify Policy
=============
Expand Down
17 changes: 17 additions & 0 deletions docs/source/pages/using.rst
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,23 @@ With the example above, the generated output reports can be seen here:
- `micronaut-core.html <../_static/examples/micronaut-projects/micronaut-core/analyze_with_sbom/micronaut-core.html>`__
- `micronaut-core.json <../_static/examples/micronaut-projects/micronaut-core/analyze_with_sbom/micronaut-core.json>`__

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Analyzing dependencies in the SBOM without the main software component
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

In the case where the repository URL of the main software component is not available (e.g. the repository is in a private domain where Macaron cannot access),
Macaron can still run the analysis on the dependencies listed in the SBOM.
To do that, you must first create a PURL to present the main software component. This is so that this software component could be referenced later in the :ref:`verify-policy <verify-policy-action-cli>` command.
For example: ``pkg:private_domain.com/org/name``.

Then the analysis can be run with:

.. code-block:: shell

./run_macaron.sh analyze -purl pkg:private_domain.com/org/name -sbom <path_to_sbom>

With ``path_to_sbom`` is the path to the SBOM you want to use.

.. _more-deps:

'''''''''''''''''''''''''''
Expand Down
14 changes: 13 additions & 1 deletion scripts/dev_scripts/integration_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ python $COMPARE_DEPS $DEP_RESULT $DEP_EXPECTED || log_fail
python $COMPARE_JSON_OUT $JSON_RESULT $JSON_EXPECTED || log_fail

echo -e "\n----------------------------------------------------------------------------------"
echo "apache/maven: Analyzing the repo path, the branch name and the commit digest with dependency resolution using a CycloneDx SBOM."
echo "apache/maven: Analyzing using a CycloneDx SBOM with target repo path"
echo -e "----------------------------------------------------------------------------------\n"
SBOM_FILE=$WORKSPACE/tests/dependency_analyzer/cyclonedx/resources/apache_maven_root_sbom.json
DEP_EXPECTED=$WORKSPACE/tests/dependency_analyzer/expected_results/apache_maven_with_sbom_provided.json
Expand All @@ -133,6 +133,18 @@ $RUN_MACARON analyze -rp https://github.com/apache/maven -b master -d 6767f2500f

python $COMPARE_DEPS $DEP_RESULT $DEP_EXPECTED || log_fail


echo -e "\n----------------------------------------------------------------------------------"
echo "apache/maven: Analyzing using a CycloneDx SBOM file of a software component whose repository is not available."
echo -e "----------------------------------------------------------------------------------\n"
SBOM_FILE=$WORKSPACE/tests/dependency_analyzer/cyclonedx/resources/private_mirror_apache_maven.json
DEP_EXPECTED=$WORKSPACE/tests/dependency_analyzer/expected_results/private_mirror_apache_maven.json
DEP_RESULT=$WORKSPACE/output/reports/private_domain_com/apache/maven/dependencies.json

$RUN_MACARON analyze -purl pkg:private_domain.com/apache/maven -sbom "$SBOM_FILE" || log_fail

python $COMPARE_DEPS $DEP_RESULT $DEP_EXPECTED || log_fail

# Analyze micronaut-projects/micronaut-core.
echo -e "\n=================================================================================="
echo "Run integration tests with configurations for micronaut-projects/micronaut-core..."
Expand Down
12 changes: 8 additions & 4 deletions src/macaron/output_reporter/results.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,17 @@ def get_dict(self) -> dict:
dict
The dictionary representation of this record.
"""
has_passing_check = False
if self.context:
for res in self.context.check_results.values():
if res["result_type"] == CheckResultType.PASSED:
has_passing_check = True
break

result = {
"metadata": {
"timestamps": datetime.now().isoformat(sep=" ", timespec="seconds"),
"has_passing_check": has_passing_check,
},
"target": self.context.get_dict() if self.context else {},
"dependencies": self.get_dep_summary(),
Expand Down Expand Up @@ -303,8 +311,4 @@ def __str__(self) -> str:
for mesg in mesg_list:
output = "".join([output, f"- {mesg}\n"])

for record in self.get_records():
if not record.context:
continue

return output
47 changes: 17 additions & 30 deletions src/macaron/output_reporter/templates/base_template.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!-- Copyright (c) 2022 - 2022, Oracle and/or its affiliates. All rights reserved. -->
<!-- Copyright (c) 2022 - 2023, Oracle and/or its affiliates. All rights reserved. -->
<!-- Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/. -->

<!DOCTYPE html>
Expand Down Expand Up @@ -255,26 +255,30 @@
padding-left: 2em
}

.caret {
/*
The reason why we need to create a separate .toggler class is because all .caret class are set binded
to the listener for extending/collapsing the provenance fields.
*/
.caret, .toggler {
cursor: pointer;
user-select: none;
}

/* Create the caret using a unicode symbol, and style it. */
.caret::before {
.caret::before, .toggler::before {
content: "\25B8";
color: black;
display: inline-block;
margin-right: 6px;
}

/* Rotate the caret icon when clicked on. */
.caret-down::before {
.caret-down::before, .toggler-extend::before {
transform: rotate(90deg);
}

/* Hide the nested list. */
.nested-ul {
.nested-ul, .hidden {
display: none;
}

Expand Down Expand Up @@ -609,31 +613,7 @@
</div>
</header>

<div class="table_caption">Target information</div>
{% block target_info%}
{% endblock %}

<div class='space_divider'></div>

<div class="table_caption">Provenance summary</div>
{% block prov_justification %}
{% endblock %}

<button class="fancy-button" onclick="expandAll()">Expand All</button>
<button class="fancy-button" onclick="collapseAll()">Collapse All</button>

{% block prov_summary %}
{% endblock %}

<div class='space_divider'></div>

<div class="table_caption">Reports for Macaron checks</div>
{% block checks_report %}
{% endblock%}

<div class='space_divider'></div>

{% block deps_result_section %}
{% block content %}
{% endblock %}

<footer class='footer'>
Expand Down Expand Up @@ -696,6 +676,13 @@
});
}

// Add a listener to the caret for extending/collapsing the check status table.
let check_status_toggler = document.getElementById("check_report_title");
check_status_toggler.addEventListener("click", function() {
this.classList.toggle("toggler-extend");
document.getElementById("check_report_content").classList.toggle("hidden");
});

// When loaded, expand all CI services.<n> elements
setExpandState(document.querySelectorAll(".tree-view-nested-list > * > .caret"), true);
setExpandState(document.querySelectorAll(".tree-view-nested-list > * > * > * > .caret"), true);
Expand Down
81 changes: 62 additions & 19 deletions src/macaron/output_reporter/templates/macaron.html
Original file line number Diff line number Diff line change
Expand Up @@ -168,49 +168,92 @@

{#
This section is where we fill in the blocks defined in base_template.html.
Note that the input context dictionary will have the format:
{data = <data_from_html_reporter}
The data for this template is passed in as a Python dictionary by the HTMLReporter. We can access those data by
specifying the keys to the required value field.
For example, if the data from HTMLReporter is:
{
"metadata": {
"boo": 1,
"foo": 2
}
}
Within the Jinja2 template, ``{{ metadata.boo }}`` will be rendered as ``1``
#}

{% block timestamps %}
{{ metadata.timestamps | indent(12, first=true) }}
{% endblock%}
{% endblock %}

{% block content %}
<div class="table_caption">Target information</div>
{% if not target.info.remote_path %}
{#
Display the related section only the remote path is available. The remote path for a target software component
is not available when Macaron cannot resolve it from the user provided PURL.
#}
<div id= "prov_justification">
Manual configuration required. Could not find SCM URL.
</div>
{% endif %}

{% block target_info %}
{{ render_target_info_table(target.info) | indent(4, first=true) }}
{% endblock %}
{{ render_target_info_table(target.info) | indent(4) }}

<div class='space_divider'></div>

{% block prov_justification %}
<div class="table_caption">Provenance summary</div>
<div id= "prov_justification">
{% if target.provenances.is_inferred == true %}
Could not find a provenance for this repository. Below is what Macaron has inferred.
{% else %}
This is the provenance found for this repository.
{% endif %}
</div>
{% endblock %}

<button class="fancy-button" onclick="expandAll()">Expand All</button>
<button class="fancy-button" onclick="collapseAll()">Collapse All</button>
{{ render_tree_view_nested_list(target.provenances.content) | indent(4) }}

{% block prov_summary %}
{{ render_tree_view_nested_list(target.provenances.content) | indent(4, first=true) }}
{% endblock %}

<div class='space_divider'></div>

{% block checks_report %}
{{ render_checks_report(target.checks.results) | indent(4, first=true) }}
{% endblock %}
{#
When there is no passing check for this software component, we hide the check report table when the viewer
first open the HTML file. However, the viewer could click the `toggler` to expand the table if they want to see it. To achieve this, there are two component we need to handle:
- The toggler, which is the symbol that indicate the Extended or Collapsed state of the check report table:
The class ``toggler-extend`` will apply the CSS rule to rotate the toggler symbol indicating the "Extend" state.
If ``toggler-extend`` is not set, the toggler will be in the Collapsed state.
- The ``check_report_content`` div, which contains the check report table: The HTML class ``hidden`` will set ``display: none`` to this div and hide the check report table.
#}
{% if metadata.has_passing_check %}
{#
Set the default state to Extend if there is a passing check.
#}
<div class="table_caption toggler toggler-extend" id="check_report_title">Reports for Macaron checks</div>
<div id="check_report_content">
{% else %}
{#
Set the default state to Collapsed if there is no passing check.
#}
<div class="table_caption toggler" id="check_report_title">Reports for Macaron checks</div>
<div id="check_report_content" class="hidden">
{% endif %}
{{ render_checks_report(target.checks.results) | indent(8) }}
</div>

<div class='space_divider'></div>

{% block deps_result_section %}
{% if dependencies.analyzed_deps != 0 %}
{#
Display the dependencies data if it's available:
- The total number of dependencies and unique repositories include in the analysis
- Dependency results (The number of dependencies pass each check)
- The status for each dependency
#}
{% if dependencies.analyzed_deps != 0 %}
<div class="table_caption" id="deps_result_title">Dependency results</div>
<div class="table_sub_caption">
{{ dependencies.analyzed_deps }} dependencies that map to {{ dependencies.unique_dep_repos }} unique repositories have been successfully analyzed.
{{ dependencies.analyzed_deps }} dependencies have been found.
</div>
{{ render_dep_summary(dependencies.checks_summary) | indent(4) }}
<div class="space_divider"></div>
{{ render_dep_status(dependencies.dep_status) | indent(4) }}
{% endif %}
{% endif %}
{% endblock %}
6 changes: 2 additions & 4 deletions src/macaron/slsa_analyzer/analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,17 +170,15 @@ def run(self, user_config: dict, sbom_path: str = "", skip_deps: bool = False) -
logger.info("Start analyzing the dependencies.")
for config in deps_config:
dep_status: SCMStatus = config.get_value("available")
if dep_status != SCMStatus.AVAILABLE:
if dep_status == SCMStatus.DUPLICATED_SCM:
behnazh-w marked this conversation as resolved.
Show resolved Hide resolved
dep_record: Record = Record(
record_id=config.get_value("id"),
description=config.get_value("note"),
pre_config=config,
status=config.get_value("available"),
)
report.add_dep_record(dep_record)
if dep_status == SCMStatus.DUPLICATED_SCM:
duplicated_scm_records.append(dep_record)

duplicated_scm_records.append(dep_record)
continue
dep_record = self.run_single(config, analysis, report.record_mapping)
report.add_dep_record(dep_record)
Expand Down
Loading
Loading