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..925f6e127 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,27 @@ ![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 (adjust the version as needed). In this example, we use an example policy. 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). + +```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..f28f9d2e9 100644 --- a/action.yaml +++ b/action.yaml @@ -58,28 +58,13 @@ 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 + env: + ACTION_REF: ${{ github.action_ref }} - name: Run Macaron Analysis id: run-macaron-analysis 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..6c7db9407 --- /dev/null +++ b/docs/source/pages/macaron_action.rst @@ -0,0 +1,175 @@ +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:: + :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). + - + * - ``provenance_expectation`` + - The path to provenance expectation file or directory. + - + * - ``provenance_file`` + - The path to the provenance file in in-toto format. + - + * - ``deps_depth`` + - Dependency resolution depth (how many levels of transitive dependencies + to resolve). + - ``0`` + * - ``show_prelude`` + - Shows the Datalog prelude for the database. + - + * - ``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`` + * - ``subject_path`` + - Path to the artifact serving as the subject of the attestation. + - ``${{ github.workspace }}`` + +Outputs +------- + +The composite action exposes the following outputs (set by the +``run_macaron_policy_verification.sh`` script when applicable): + +.. list-table:: + :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. + +Default Policies +---------------- + +Macaron provides policy templates to run pre-defined policies: + +.. list-table:: + :header-rows: 1 + :widths: 20 60 20 + + * - Policy name + - Description + - Template + * - ``check-github-actions`` + - Detects whether a component was built using GitHub Actions that + are known to be vulnerable or otherwise unsafe. The policy + evaluates a check named `mcn_githubactions_vulnerabilities_1` and + reports a passed/failed result for the component when applied. + - `check-github-actions template `_ + * - ``malware-detection`` + - Checks a component for indicators of malicious or suspicious content. + The policy evaluates a check named mcn_detect_malicious_metadata_1 + and reports a passed/failed result for the component when applied. + - `malware-detection template `_ + * - ``malware-detection-dependencies`` + - Checks the component and its transitive dependencies for indicators + of malicious or suspicious content. The policy ensures the component + and each dependency pass the `mcn_detect_malicious_metadata_1` check. + - `malware-detection-dependencies template `_ + +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..a002bb534 100644 --- a/scripts/actions/setup_macaron.sh +++ b/scripts/actions/setup_macaron.sh @@ -4,25 +4,65 @@ # 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 +ACTION_DIR="${RUNNER_TEMP:-/tmp}/macaron-action" +rm -rf "$ACTION_DIR" +mkdir -p "$ACTION_DIR" + +git clone --filter=blob:none --no-checkout https://github.com/oracle/macaron.git "$ACTION_DIR" + +TARGET_REF="${ACTION_REF:-main}" +MACARON_IMAGE_TAG="" +cd "$ACTION_DIR" +if [[ "$TARGET_REF" =~ ^[0-9a-f]{40}$ ]]; then + # Check for tags pointing directly at the SHA. + tags=$(git tag --points-at "$TARGET_REF") + if [[ -n "$tags" ]]; then + # Get the first tag (main or first one listed) + MACARON_IMAGE_TAG="$(echo "$tags" | head -n1)" + echo "SHA $TARGET_REF maps to exact tag: $MACARON_IMAGE_TAG" + else + # Search all tags that contain the commit (could be ancestor). + history_tags=$(git tag --contains "$TARGET_REF") + if [[ -n "$history_tags" ]]; then + MACARON_IMAGE_TAG="$(echo "$history_tags" | head -n1)" + echo "SHA $TARGET_REF is contained in tag: $MACARON_IMAGE_TAG" + else + echo "No tag found for SHA $TARGET_REF. Defaulting to 'latest'." + MACARON_IMAGE_TAG="latest" + fi + fi +elif [[ "$TARGET_REF" =~ ^v[0-9] ]]; then + MACARON_IMAGE_TAG="$TARGET_REF" + echo "Ref is a direct tag: $MACARON_IMAGE_TAG" +else + echo "Using 'latest' image." + MACARON_IMAGE_TAG="latest" 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}" != "latest" ]; 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).