Skip to content

Fix/fuzz and security ci #1

Fix/fuzz and security ci

Fix/fuzz and security ci #1

name: Fuzz Python Env Replay
on:
pull_request:
branches: [ main ]
paths:
- .github/workflows/fuzz-python-env-replay.yml
- .github/workflows/fuzz-python-env-comparison.yml
- .github/workflows/fuzz.yml
- fuzz/fuzz_targets/validate_with_python.rs
- fuzz/src/lib.rs
- fuzz/src/python_env.rs
- fuzz/examples/report_python_env.rs
- fuzz/tests/python_env_contract.rs
- fuzz/README.md
workflow_dispatch:
inputs:
source_run_id:
description: Comparison workflow run id to replay artifacts from
required: false
permissions:
actions: read
contents: read
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
jobs:
replay-python-env-artifacts:
name: Replay Python env artifact (${{ matrix.case_name }}, ${{ matrix.policy_name }})
runs-on: ubuntu-latest
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
include:
- case_name: inherit-leak
source_artifact_name: fuzz-python-env-inherit
input_prefix: leak-
policy_name: inherit
env_policy: inherit
- case_name: inherit-leak
source_artifact_name: fuzz-python-env-inherit
input_prefix: leak-
policy_name: strip-setup-python
env_policy: strip_setup_python
- case_name: inherit-leak
source_artifact_name: fuzz-python-env-inherit
input_prefix: leak-
policy_name: strip-setup-python-and-ld-library-path
env_policy: strip_setup_python_and_ld_library_path
- case_name: strip-setup-python-artifact
source_artifact_name: fuzz-python-env-strip-setup-python
input_prefix: crash-
policy_name: inherit
env_policy: inherit
- case_name: strip-setup-python-artifact
source_artifact_name: fuzz-python-env-strip-setup-python
input_prefix: crash-
policy_name: strip-setup-python
env_policy: strip_setup_python
- case_name: strip-setup-python-artifact
source_artifact_name: fuzz-python-env-strip-setup-python
input_prefix: crash-
policy_name: strip-setup-python-and-ld-library-path
env_policy: strip_setup_python_and_ld_library_path
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@0f1b44df7e9cbb178d781a242338dfa5e243ad7f
with:
toolchain: nightly-2026-04-16
- name: Install Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install cargo-fuzz
run: cargo install cargo-fuzz --locked --version 0.13.1
- name: Resolve replay input
id: input
env:
GH_TOKEN: ${{ github.token }}
EVENT_NAME: ${{ github.event_name }}
INPUT_SOURCE_RUN_ID: ${{ github.event.inputs.source_run_id }}
SOURCE_BRANCH: ${{ github.event_name == 'pull_request' && github.head_ref || github.ref_name }}
SOURCE_ARTIFACT_NAME: ${{ matrix.source_artifact_name }}
INPUT_PREFIX: ${{ matrix.input_prefix }}
run: |
source_run_id="$INPUT_SOURCE_RUN_ID"
if [ "$EVENT_NAME" = "pull_request" ]; then
source_run_id=$(gh run list \
--branch "$SOURCE_BRANCH" \
--workflow "Fuzz Python Env Comparison" \
--limit 20 \
--json databaseId,status \
--jq 'map(select(.status=="completed")) | .[0].databaseId // empty')
fi
if [ -z "$source_run_id" ]; then
echo "::error::Could not determine a completed Fuzz Python Env Comparison run id"
exit 1
fi
case "$source_run_id" in
''|*[!0-9]*)
echo "::error::source_run_id must resolve to a GitHub Actions run id"
exit 1
;;
esac
mkdir -p fuzz/replay-input fuzz/artifacts/python-env-replay
gh run download "$source_run_id" -n "$SOURCE_ARTIFACT_NAME" -D fuzz/replay-input
input_file=$(find fuzz/replay-input -maxdepth 1 -type f -name "${INPUT_PREFIX}*" | sort | head -n 1)
if [ -z "$input_file" ]; then
echo "::error::No ${INPUT_PREFIX}* input found in artifact ${SOURCE_ARTIFACT_NAME}"
find fuzz/replay-input -maxdepth 1 -type f -print
exit 1
fi
source_sha=$(gh api "repos/${{ github.repository }}/actions/runs/$source_run_id" --jq .head_sha)
printf 'source_run_id=%s\n' "$source_run_id" >> "$GITHUB_OUTPUT"
printf 'input_file=%s\n' "$input_file" >> "$GITHUB_OUTPUT"
printf 'input_name=%s\n' "$(basename "$input_file")" >> "$GITHUB_OUTPUT"
printf 'input_size=%s\n' "$(wc -c < "$input_file" | tr -d ' ')" >> "$GITHUB_OUTPUT"
printf 'source_sha=%s\n' "$source_sha" >> "$GITHUB_OUTPUT"
- name: Record replay metadata
run: |
prefix="fuzz/artifacts/python-env-replay/${{ matrix.case_name }}-${{ matrix.policy_name }}"
cp "${{ steps.input.outputs.input_file }}" "${prefix}-input.bin"
{
echo "source_run_id=${{ steps.input.outputs.source_run_id }}"
echo "source_sha=${{ steps.input.outputs.source_sha }}"
echo "source_artifact_name=${{ matrix.source_artifact_name }}"
echo "input_name=${{ steps.input.outputs.input_name }}"
echo "input_size=${{ steps.input.outputs.input_size }}"
echo "policy=${{ matrix.env_policy }}"
echo "workflow_sha=${{ github.sha }}"
} > "${prefix}-metadata.txt"
- name: Report effective Python environment
env:
PICKLE_FUZZ_PYTHON_ENV_POLICY: ${{ matrix.env_policy }}
run: |
prefix="fuzz/artifacts/python-env-replay/${{ matrix.case_name }}-${{ matrix.policy_name }}"
cargo run --manifest-path fuzz/Cargo.toml --example report_python_env --quiet \
> "${prefix}-env.txt"
- name: Replay saved fuzz artifact
id: replay
env:
PICKLE_FUZZ_PYTHON_ENV_POLICY: ${{ matrix.env_policy }}
run: |
prefix="fuzz/artifacts/python-env-replay/${{ matrix.case_name }}-${{ matrix.policy_name }}"
rm -rf fuzz/artifacts/validate_with_python
mkdir -p fuzz/artifacts/validate_with_python
set -o pipefail
status=0
cargo fuzz run validate_with_python "${{ steps.input.outputs.input_file }}" -- \
-runs=1 \
-print_final_stats=1 \
-verbosity=1 | tee "${prefix}-replay.log" || status=$?
printf 'cargo_status=%s\n' "$status" >> "$GITHUB_OUTPUT"
- name: Classify replay outcome
id: classify
env:
CARGO_STATUS: ${{ steps.replay.outputs.cargo_status }}
run: |
prefix="fuzz/artifacts/python-env-replay/${{ matrix.case_name }}-${{ matrix.policy_name }}"
input_name='${{ steps.input.outputs.input_name }}'
input_size='${{ steps.input.outputs.input_size }}'
outcome=clean
found_files=''
for kind in crash timeout oom leak; do
found=$(find fuzz/artifacts/validate_with_python -maxdepth 1 -type f -name "${kind}-*" | sort || true)
if [ -n "$found" ]; then
outcome=$kind
found_files=$found
break
fi
done
if [ "$outcome" = clean ] && [ "${CARGO_STATUS:-0}" != "0" ]; then
outcome=nonzero-no-artifact
fi
{
echo "replay_outcome=$outcome"
echo "cargo_status=${CARGO_STATUS:-0}"
echo "matching_files<<EOF"
printf '%s\n' "$found_files"
echo "EOF"
} >> "$GITHUB_OUTPUT"
{
echo "replay_outcome=$outcome"
echo "cargo_status=${CARGO_STATUS:-0}"
if [ -n "$found_files" ]; then
echo "matching_files:"
printf '%s\n' "$found_files"
fi
} >> "${prefix}-metadata.txt"
{
echo "### Replay result"
echo
echo "- Case: \`${{ matrix.case_name }}\`"
echo "- Policy: \`${{ matrix.env_policy }}\`"
echo "- Source run id: \`${{ steps.input.outputs.source_run_id }}\`"
echo "- Source input: \`${input_name}\` (${input_size} bytes)"
echo "- Outcome: \`$outcome\`"
echo "- cargo fuzz exit status: \`${CARGO_STATUS:-0}\`"
if [ -n "$found_files" ]; then
echo "- Matching files:"
printf '%s\n' "$found_files" | while IFS= read -r file; do
echo " - \`$file\`"
done
fi
} >> "$GITHUB_STEP_SUMMARY"
- name: Upload replay artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: fuzz-python-env-replay-${{ matrix.case_name }}-${{ matrix.policy_name }}
path: |
fuzz/artifacts/validate_with_python/
fuzz/artifacts/python-env-replay/${{ matrix.case_name }}-${{ matrix.policy_name }}-input.bin
fuzz/artifacts/python-env-replay/${{ matrix.case_name }}-${{ matrix.policy_name }}-metadata.txt
fuzz/artifacts/python-env-replay/${{ matrix.case_name }}-${{ matrix.policy_name }}-env.txt
fuzz/artifacts/python-env-replay/${{ matrix.case_name }}-${{ matrix.policy_name }}-replay.log
if-no-files-found: error