diff --git a/.github/workflows/test_macaron_action.yaml b/.github/workflows/test_macaron_action.yaml index 5f3753a98..2621313c6 100644 --- a/.github/workflows/test_macaron_action.yaml +++ b/.github/workflows/test_macaron_action.yaml @@ -184,7 +184,7 @@ jobs: package_url: pkg:maven/io.github.behnazh-w.demo/example-maven-app@2.0?type=jar repo_path: https://github.com/behnazh-w/example-maven-app output_dir: macaron_output/detect_malicious_java_dep - sbom_path: ./resources/detect_malicious_java_dep/example-sbom.json + sbom_path: ./tests/tutorial_resources/detect_malicious_java_dep/example-sbom.json deps_depth: '1' - name: Run Macaron (verify policy - detect-malicious-upload) diff --git a/README.md b/README.md index d77aca1d5..b4054181f 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,26 @@ ![Macaron](./docs/source/assets/macaron.svg) -[Full Documentation](https://oracle.github.io/macaron/index.html) | [Tutorials](https://oracle.github.io/macaron/pages/tutorials/index.html) | [Videos](https://www.youtube.com/watch?v=ebo0kGKP6bw) | [Papers](#publications) | [Presentations](#presentations) +[Full Documentation](https://oracle.github.io/macaron/index.html) | [Tutorials](https://oracle.github.io/macaron/pages/tutorials/index.html) | [Videos](https://www.youtube.com/watch?v=ebo0kGKP6bw) | [Papers](#publications) | [Presentations](#presentations) | [Macaron GitHub Action](https://oracle.github.io/macaron/pages/macaron_action.html) **Macaron** is a software supply chain security analysis tool from Oracle Labs focused on verifying the **build integrity** of artifacts and their dependencies. It helps developers, security teams, and researchers ensure that packages are built as expected and have not been tampered with. +Use Macaron as a GitHub Action + +To use the Macaron GitHub Action, add the following step to your workflow: +```yaml +- uses: oracle/macaron@v0.21.0 + with: + repo_path: 'https://github.com/example/project' + policy_file: check-github-actions + policy_purl: 'pkg:github.com/example/project' + output_dir: 'macaron-output' + upload_attestation: true +``` + +For detailed instructions and a comprehensive list of available options, please refer to the [Macaron GitHub Action documentation](https://oracle.github.io/macaron/pages/macaron_action.html). + ## Key Capabilities Macaron supports: diff --git a/action.yaml b/action.yaml index 0e77b216d..9cd282cf0 100644 --- a/action.yaml +++ b/action.yaml @@ -58,25 +58,8 @@ outputs: runs: using: composite steps: - - name: Setup Python - uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0 - with: - python-version: 3.11.14 - - - name: Setup Go - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 - with: - go-version: '1.23' - cache: false - - - name: Setup JDK - uses: actions/setup-java@b36c23c0d998641eff861008f374ee103c25ac73 # v4.4.0 - with: - java-version: '17' - distribution: oracle - - name: Setup Macaron - # Create or reuse a Python virtualenv with the macaron CLI and export the `MACARON` binary path via `$GITHUB_ENV` so later steps can use it. + # Create or reuse run_macaron.sh script run: | bash "$GITHUB_ACTION_PATH/scripts/actions/setup_macaron.sh" shell: bash diff --git a/docs/source/index.rst b/docs/source/index.rst index 43fe2af7f..bc9ab5a0d 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -121,6 +121,7 @@ intermediate representations as abstractions. Using such abstractions, Macaron i pages/installation pages/using pages/cli_usage/index + pages/macaron_action pages/tutorials/index pages/output_files pages/checks/slsa_builds diff --git a/docs/source/pages/macaron_action.rst b/docs/source/pages/macaron_action.rst new file mode 100644 index 000000000..450e40870 --- /dev/null +++ b/docs/source/pages/macaron_action.rst @@ -0,0 +1,134 @@ +Macaron GitHub Action +===================== + +Overview +-------- + +This document describes the composite GitHub Action defined in ``action.yaml`` at the repository root. The action uses the Macaron CLI to run supply-chain security analysis and policy verification from a GitHub Actions workflow. + +Quick usage +----------- + +When using this action you can reference the action in your workflow. Example: + +.. code-block:: yaml + + jobs: + analyze: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - name: Run Macaron Security Analysis + uses: oracle/macaron@v0.21.0 + with: + repo_path: 'https://github.com/example/project' + policy_file: check-github-actions + policy_purl: 'pkg:github.com/example/project' + output_dir: 'macaron-output' + upload_attestation: true + +Example: policy verification only +---------------------------------- + +To run only the policy verification step (when you already have an output +database), call the action with ``policy_file`` and set ``output_dir`` to the +directory containing ``macaron.db``: + +.. code-block:: yaml + + - name: Verify policy + uses: oracle/macaron@v0.21.0 + with: + policy_file: policy.dl + output_dir: macaron-output + upload_attestation: true + +Inputs +------ +The action exposes a number of inputs which map directly to Macaron CLI +options. Key inputs are listed below (see ``action.yaml`` for the full list): + +.. list-table:: Action inputs + :header-rows: 1 + :widths: 20 60 20 + + * - Input + - Description + - Default + * - ``repo_path`` + - The path or URL of the repository to analyze. + - + * - ``package_url`` + - A PURL identifying a package to analyze instead of a repository. + - + * - ``sbom_path`` + - Path to an SBOM file to analyze. + - + * - ``python_venv`` + - Path to an existing Python virtualenv (used when analyzing Python + packages). + - + * - ``defaults_path`` + - Path to a Macaron defaults configuration file. + - + * - ``policy_file`` + - Path to a Datalog policy file for policy verification. + - + * - ``policy_purl`` + - PURL for a pre-defined policy to use with verification. + - + * - ``branch`` / ``digest`` + - Checkout options when analyzing a repository (branch name or commit + digest). + - + * - ``deps_depth`` + - Dependency resolution depth (how many levels of transitive dependencies + to resolve). + - ``0`` + * - ``github_token`` + - Token used by Macaron to access GitHub (for cloning, API access, + etc.). + - ``${{ github.token }}`` + * - ``output_dir`` + - Directory where Macaron writes results (database, reports, artifacts). + - ``output`` + * - ``upload_attestation`` + - When ``true``, the action will attempt to upload a generated + verification attestation (VSA) after policy verification. + - ``false`` + +Outputs +------- + +The composite action exposes the following outputs (set by the +``run_macaron_policy_verification.sh`` script when applicable): + +.. list-table:: Action outputs + :header-rows: 1 + :widths: 20 70 + + * - Output + - Description + * - ``policy_report`` + - Path to the generated policy report JSON file produced by + ``macaron verify-policy``. This file contains the policy evaluation + results. + * - ``vsa_report`` + - Path to the generated VSA (Verification Summary Attestation) in + `in-toto `_ JSONL format. If no VSA was produced + during verification, the action emits the string ``"VSA Not Generated."`` + instead of a path. + +How the action works +-------------------- + +1. ``Setup Macaron``: downloads ``run_macaron.sh`` script to install and run macaron in the action. + +2. ``Run Macaron Analysis``: calls ``scripts/actions/run_macaron_analysis.sh`` + which assembles the ``macaron analyze`` command from the inputs and runs + it. Results are written into ``output_dir``. + +3. ``Run Macaron Policy Verification``: if a policy file or PURL is supplied, + the corresponding script runs ``macaron verify-policy`` against the + analysis database and writes ``policy_report`` and ``vsa_report`` to + ``$GITHUB_OUTPUT`` when produced. diff --git a/scripts/actions/run_macaron_analysis.sh b/scripts/actions/run_macaron_analysis.sh index fc97fd916..34305479c 100644 --- a/scripts/actions/run_macaron_analysis.sh +++ b/scripts/actions/run_macaron_analysis.sh @@ -19,7 +19,7 @@ else fi OUTPUT_DIR=${OUTPUT_DIR:-output} -CMD="$CMD --output-dir ${OUTPUT_DIR} -lr . analyze" +CMD="$CMD --output ${OUTPUT_DIR} -lr . analyze" if [ -n "${REPO_PATH:-}" ]; then CMD="$CMD -rp ${REPO_PATH}" diff --git a/scripts/actions/run_macaron_policy_verification.sh b/scripts/actions/run_macaron_policy_verification.sh index fb6218e36..46eb9bee0 100644 --- a/scripts/actions/run_macaron_policy_verification.sh +++ b/scripts/actions/run_macaron_policy_verification.sh @@ -25,7 +25,7 @@ if [ -n "$DEFAULTS_PATH" ]; then else CMD="$MACARON" fi -CMD="$CMD --output-dir ${OUTPUT_DIR} verify-policy --database ${OUTPUT_DIR}/macaron.db" +CMD="$CMD --output ${OUTPUT_DIR} verify-policy --database ${OUTPUT_DIR}/macaron.db" if [ -n "$FILE" ] && [ -f "$FILE" ]; then CMD="$CMD --file $FILE" diff --git a/scripts/actions/setup_macaron.sh b/scripts/actions/setup_macaron.sh index fe2bd9b20..978aab93e 100644 --- a/scripts/actions/setup_macaron.sh +++ b/scripts/actions/setup_macaron.sh @@ -4,25 +4,59 @@ # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/. set -euo pipefail -# Setup Macaron virtualenv and make available via GitHub Actions environment files. -# This script writes `MACARON=` to `$GITHUB_ENV` so later steps can invoke the macaron CLI, and appends the venv `bin` directory to `$GITHUB_PATH`. - MACARON_DIR="${RUNNER_TEMP:-/tmp}/macaron" -VENV_MACARON="$MACARON_DIR/.venv/bin/macaron" - mkdir -p "$MACARON_DIR" -if [ -x "$VENV_MACARON" ]; then - echo "Using macaron from existing venv: $VENV_MACARON" - echo "MACARON=$VENV_MACARON" >> "$GITHUB_ENV" - echo "$MACARON_DIR/.venv/bin" >> "$GITHUB_PATH" - exit 0 +ref="$GITHUB_REF" +MACARON_IMAGE_TAG="" +cd "$GITHUB_ACTION_PATH" +if [[ "$ref" == refs/tags/* ]]; then + MACARON_IMAGE_TAG="${ref#refs/tags/}" + echo "Ref is a tag: $MACARON_IMAGE_TAG" +else + sha="$GITHUB_SHA" + if [[ -z "$sha" ]]; then + sha="$ref" + fi + # Check for tags pointing directly at the SHA. + tags=$(git tag --points-at "$sha") + if [[ -n "$tags" ]]; then + # Get the first tag (main or first one listed) + MACARON_IMAGE_TAG="$(echo "$tags" | head -n1)" + echo "Commit $sha matches tag: $MACARON_IMAGE_TAG" + else + # Search all tags that contain the commit (could be ancestor). + history_tags=$(git tag --contains "$sha") + if [[ -n "$history_tags" ]]; then + MACARON_IMAGE_TAG="$(echo "$history_tags" | head -n1)" + echo "Commit $sha is contained by tag: $MACARON_IMAGE_TAG" + else + echo "No tags found for commit $sha" + fi + fi fi cd "$MACARON_DIR" -git clone https://github.com/oracle/macaron.git . -make venv -export PATH="$MACARON_DIR/.venv/bin:$PATH" -make setup -echo "MACARON=$VENV_MACARON" >> "$GITHUB_ENV" -echo "$MACARON_DIR/.venv/bin" >> "$GITHUB_PATH" + +# Download image using macaron_image_tag else latest release +if [ "${MACARON_IMAGE_TAG}" != "" ]; then + echo "MACARON_IMAGE_TAG detected: ${MACARON_IMAGE_TAG}" + URL="https://raw.githubusercontent.com/oracle/macaron/refs/tags/${MACARON_IMAGE_TAG}/scripts/release_scripts/run_macaron.sh" + SCRIPT_NAME="run_macaron_${MACARON_IMAGE_TAG}.sh" +else + echo "Using default latest release." + URL="https://raw.githubusercontent.com/oracle/macaron/release/scripts/release_scripts/run_macaron.sh" + SCRIPT_NAME="run_macaron.sh" +fi + +# Get the run_macaron.sh script +if [ ! -f "$SCRIPT_NAME" ]; then + echo "Downloading $SCRIPT_NAME from: $URL" + curl -fSL -o "$SCRIPT_NAME" "$URL" +else + echo "$SCRIPT_NAME already exists, skipping download." +fi + +chmod +x "$SCRIPT_NAME" +echo "MACARON=$MACARON_DIR/$SCRIPT_NAME" >> "$GITHUB_ENV" +echo "MACARON_IMAGE_TAG=${MACARON_IMAGE_TAG}" >> "$GITHUB_ENV" diff --git a/src/macaron/resources/policies/datalog/malware-detection.dl.template b/src/macaron/resources/policies/datalog/malware-detection.dl.template index 77eedc5cf..4429cfec6 100644 --- a/src/macaron/resources/policies/datalog/malware-detection.dl.template +++ b/src/macaron/resources/policies/datalog/malware-detection.dl.template @@ -3,7 +3,6 @@ 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("", purl).