Skip to content
Open
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
1 change: 1 addition & 0 deletions docs/source/pages/tutorials/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ For the full list of supported technologies, such as CI services, registries, an
detect_vulnerable_github_actions
provenance
detect_malicious_java_dep
verify_with_existing_policy
generate_verification_summary_attestation
use_verification_summary_attestation
exclude_include_checks
Expand Down
53 changes: 53 additions & 0 deletions docs/source/pages/tutorials/verify_with_existing_policy.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
==============================================================
Verify with an existing example policy using --existing-policy
==============================================================

This short tutorial shows how to use the ``--existing-policy`` flag with the ``verify-policy`` subcommand to run one of the example (predefined) policies that ship with Macaron.

--------
Use case
--------

Use ``--existing-policy`` when you want to run one of the built-in example policies by name instead of providing a local policy file with ``--file``. Example policies are useful for quick checks or automated examples/tests.

-------
Example
-------

Run the ``malware-detection`` example policy against a package URL:

.. code-block:: shell

./run_macaron.sh analyze -purl pkg:pypi/[email protected]

.. note:: By default, Macaron clones the repositories and creates output files under the ``output`` directory. To understand the structure of this directory please see :ref:`Output Files Guide <output_files_guide>`.

.. code-block:: shell

./run_macaron.sh verify-policy \
--database output/macaron.db \
--existing-policy malware-detection \
--package-url "pkg:pypi/django"

The result of this command should show that the policy succeeds with a zero exit code (if a policy fails to pass, Macaron returns a none-zero error code):

.. code-block:: shell

Components Satisfy Policy
1 pkg:pypi/[email protected] check-component

Components Violate Policy None

Passed Policies check-component
Failed Policies None
Policy Report output/policy_report.json
Verification Summary Attestation output/vsa.intoto.jsonl
Decode and Inspect the Content cat output/vsa.intoto.jsonl | jq -r '.payload' | base64 -d | jq

-----------------
Related tutorials
-----------------

- :doc:`detect_malicious_package` — shows what the malware-detection policy does in this tutorial.
- :doc:`use_verification_summary_attestation` — how to consume an attestation
produced by Macaron.
29 changes: 29 additions & 0 deletions src/macaron/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,14 +204,41 @@ def verify_policy(verify_policy_args: argparse.Namespace) -> int:
show_prelude(verify_policy_args.database)
return os.EX_OK

policy_content = None
if verify_policy_args.file:
if not os.path.isfile(verify_policy_args.file):
logger.critical('The policy file "%s" does not exist.', verify_policy_args.file)
return os.EX_OSFILE

with open(verify_policy_args.file, encoding="utf-8") as file:
policy_content = file.read()
elif verify_policy_args.existing_policy:
policy_dir = os.path.join(macaron.MACARON_PATH, "resources", "policies", "datalog")
policy_suffix = ".dl"
template_suffix = f"{policy_suffix}.template"
available_policies = [
os.path.splitext(policy)[0].replace(policy_suffix, "")
for policy in os.listdir(policy_dir)
if policy.endswith(template_suffix)
]
if verify_policy_args.existing_policy not in available_policies:
logger.error(
"The policy %s is not available. Available policies are: %s",
verify_policy_args.existing_policy,
available_policies,
)
return os.EX_USAGE
policy_path = os.path.join(policy_dir, f"{verify_policy_args.existing_policy}{template_suffix}")
with open(policy_path, encoding="utf-8") as file:
policy_content = file.read()
try:
PackageURL.from_string(verify_policy_args.package_url)
policy_content = policy_content.replace("<PACKAGE_PURL>", verify_policy_args.package_url)
except ValueError as err:
logger.error("The package url %s is not valid. Error: %s", verify_policy_args.package_url, err)
return os.EX_USAGE

if policy_content:
result = run_policy_engine(verify_policy_args.database, policy_content)
vsa = generate_vsa(policy_content=policy_content, policy_result=result)
# Retrieve the console handler previously configured via the access_handler.
Expand Down Expand Up @@ -573,7 +600,9 @@ def main(argv: list[str] | None = None) -> None:
vp_group = vp_parser.add_mutually_exclusive_group(required=True)

vp_parser.add_argument("-d", "--database", required=True, type=str, help="Path to the database.")
vp_parser.add_argument("-purl", "--package-url", help="PackageURL for policy template.")
vp_group.add_argument("-f", "--file", type=str, help="Path to the Datalog policy.")
vp_group.add_argument("-e", "--existing-policy", help="Name of the existing policy to run.")
vp_group.add_argument("-s", "--show-prelude", action="store_true", help="Show policy prelude.")

# Find the repo and commit of a passed PURL, or the commit of a passed PURL and repo.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#include "prelude.dl"

Policy("github_actions_vulns", component_id, "GitHub Actions Vulnerability Detection") :-
check_passed(component_id, "mcn_githubactions_vulnerabilities_1").

apply_policy_to("github_actions_vulns", component_id) :-
is_component(component_id, purl),
match("<PACKAGE_PURL>*", purl).
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#include "prelude.dl"

Policy("check-dependencies", component_id, "Check the dependencies of component.") :-
transitive_dependency(component_id, dependency),
check_passed(component_id, "mcn_detect_malicious_metadata_1"),
check_passed(dependency, "mcn_detect_malicious_metadata_1").

apply_policy_to("check-dependencies", component_id) :-
is_component(component_id, purl),
match("<PACKAGE_PURL>*", purl).
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#include "prelude.dl"

Policy("check-component", component_id, "Check component artifacts.") :-
check_passed(component_id, "mcn_detect_malicious_metadata_1").


apply_policy_to("check-component", component_id) :-
is_component(component_id, purl),
match("<PACKAGE_PURL>*", purl).
61 changes: 61 additions & 0 deletions tests/policy_engine/test_existing_policy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Copyright (c) 2025 - 2025, 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/.

"""This module tests the existing-policy flag supported by the policy engine."""

import argparse
import os
from pathlib import Path
from unittest.mock import MagicMock, patch

from macaron.__main__ import verify_policy


def test_verify_existing_policy_success(tmp_path: Path) -> None:
"""When an existing policy is provided and package-url is valid, verify_policy returns EX_OK."""
db_file = tmp_path / "macaron.db"
db_file.write_text("")

# Use a MagicMock for the handler.
mock_handler = MagicMock()

# Fake run_policy_engine and generate_vsa that returns a fixed result.
fake_run = MagicMock(return_value={"passed_policies": [["check-component"]], "failed_policies": []})
fake_generate_vsa = MagicMock(return_value=None)

# Fake PolicyReporter class: when called, returns an instance with generate method.
fake_policy_reporter_cls = MagicMock()
fake_policy_reporter_inst = MagicMock()
fake_policy_reporter_inst.generate.return_value = None
fake_policy_reporter_cls.return_value = fake_policy_reporter_inst

with (
patch("macaron.__main__.run_policy_engine", fake_run),
patch("macaron.__main__.generate_vsa", fake_generate_vsa),
patch("macaron.__main__.access_handler.get_handler", return_value=mock_handler),
patch("macaron.__main__.PolicyReporter", fake_policy_reporter_cls),
):
policy_args = argparse.Namespace(
database=str(db_file),
show_prelude=False,
file=None,
existing_policy="malware-detection",
package_url="pkg:pypi/django",
)
result = verify_policy(policy_args)
assert result == os.EX_OK


def test_verify_existing_policy_not_found(tmp_path: Path) -> None:
"""Requesting a non-existent policy returns usage error."""
db_file = tmp_path / "macaron.db"
db_file.write_text("")
policy_args = argparse.Namespace(
database=str(db_file),
show_prelude=False,
file=None,
existing_policy="no-such-policy",
package_url="pkg:pypi/django",
)
result = verify_policy(policy_args)
assert result == os.EX_USAGE
Loading