Fuzz Tests #4
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Copyright 2026 Chainguard, Inc. | |
| # SPDX-License-Identifier: Apache-2.0 | |
| name: Fuzz Tests | |
| on: | |
| schedule: | |
| # Run weekly on Sunday at midnight UTC | |
| - cron: "0 0 * * 0" | |
| workflow_dispatch: | |
| inputs: | |
| fuzz_target: | |
| description: "Specific fuzzer to run (leave empty for all)" | |
| required: false | |
| default: "" | |
| type: string | |
| fuzz_time: | |
| description: "Fuzz duration per target (e.g., 30s, 1m, 5m)" | |
| required: false | |
| default: "30s" | |
| type: choice | |
| options: | |
| - "10s" | |
| - "30s" | |
| - "1m" | |
| - "5m" | |
| - "10m" | |
| - "30m" | |
| - "60m" | |
| - "180m" | |
| permissions: {} | |
| jobs: | |
| discover: | |
| if: ${{ github.repository == 'chainguard-dev/malcontent' }} | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| outputs: | |
| targets: ${{ steps.find.outputs.targets }} | |
| steps: | |
| - name: Harden the runner (Audit all outbound calls) | |
| uses: step-security/harden-runner@e3f713f2d8f53843e71c69a996d56f51aa9adfb9 # v2.14.1 | |
| with: | |
| egress-policy: audit | |
| - name: Checkout code | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| persist-credentials: false | |
| - name: Discover fuzz targets | |
| id: find | |
| env: | |
| TARGET_FILTER: ${{ inputs.fuzz_target }} | |
| run: | | |
| # Find all Fuzz* functions in test files and build JSON array | |
| # Format: [{"test": "FuzzName", "package": "./pkg/path/"}] | |
| all_targets=$(grep -r "^func Fuzz" --include="*_test.go" -l pkg/ | while read -r file; do | |
| dir="./$(dirname "${file}")/" | |
| grep -o "^func Fuzz[A-Za-z0-9_]*" "${file}" | sed 's/^func //' | while read -r func; do | |
| echo "{\"test\":\"${func}\",\"package\":\"${dir}\"}" | |
| done | |
| done | jq -s -c '.') | |
| targets="${all_targets}" | |
| # If a specific target is requested, validate and filter | |
| if [ -n "${TARGET_FILTER}" ]; then | |
| # Validate format: must start with "Fuzz" and contain only alphanumeric/underscore | |
| if ! echo "${TARGET_FILTER}" | grep -qE '^Fuzz[A-Za-z0-9_]+$'; then | |
| echo "::error::Invalid fuzz target format: '${TARGET_FILTER}'. Must match pattern 'Fuzz[A-Za-z0-9_]+'" | |
| exit 1 | |
| fi | |
| # Filter to the requested target | |
| targets=$(echo "${all_targets}" | jq -c --arg t "${TARGET_FILTER}" '[.[] | select(.test == $t)]') | |
| # Check if target exists | |
| if [ "${targets}" = "[]" ]; then | |
| echo "::error::Fuzz target '${TARGET_FILTER}' not found." | |
| echo "Available targets:" | |
| echo "${all_targets}" | jq -r '.[].test' | sort | sed 's/^/ - /' | |
| exit 1 | |
| fi | |
| fi | |
| echo "targets=${targets}" >> "${GITHUB_OUTPUT}" | |
| echo "Discovered targets: ${targets}" | |
| fuzz: | |
| if: ${{ github.repository == 'chainguard-dev/malcontent' && needs.discover.outputs.targets != '[]' }} | |
| needs: discover | |
| runs-on: ubuntu-latest-16-core | |
| permissions: | |
| contents: read | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| target: ${{ fromJson(needs.discover.outputs.targets) }} | |
| container: | |
| image: cgr.dev/chainguard/wolfi-base:latest # zizmor: ignore[unpinned-images] | |
| options: >- | |
| --cap-add DAC_OVERRIDE | |
| --cap-add SETGID | |
| --cap-add SETUID | |
| --cap-drop ALL | |
| --cgroupns private | |
| --cpu-shares=16384 | |
| --memory-swappiness=0 | |
| --security-opt no-new-privileges | |
| --ulimit core=0 | |
| --ulimit nofile=65535:65535 | |
| --ulimit nproc=65535:65535 | |
| steps: | |
| - name: Install dependencies | |
| run: | | |
| apk update | |
| apk add curl findutils git go nodejs upx xz yara-x~1.12.0 | |
| - name: Checkout code | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| persist-credentials: false | |
| - name: Trust repository | |
| run: git config --global --add safe.directory "${GITHUB_WORKSPACE}" | |
| - name: Clone malcontent samples (required for compile fuzzers) | |
| if: contains(matrix.target.package, 'programkind') | |
| run: | | |
| make samples | |
| - name: Run fuzzer - ${{ matrix.target.test }} | |
| env: | |
| FUZZ_TIME: ${{ inputs.fuzz_time || '30s' }} | |
| run: | | |
| go test -timeout 0 -fuzz="${{ matrix.target.test }}" -fuzztime="${FUZZ_TIME}" "${{ matrix.target.package }}" |