Benchmark Release #150
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
| name: Benchmark Release | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| benchmark_uuid: | |
| description: "Benchmark UUID to release (optional; leave empty to auto-discover)." | |
| required: false | |
| default: "" | |
| run_id: | |
| description: "Run ID to release (optional; leave empty to auto-discover)." | |
| required: false | |
| default: "" | |
| report_budget_hours: | |
| description: "Override report budget hours (optional)." | |
| required: false | |
| default: "" | |
| exclude_fuzzers: | |
| description: "Comma-separated fuzzers to exclude (optional)." | |
| required: false | |
| default: "" | |
| force_reanalyze: | |
| description: "Re-run analysis and re-upload artifacts even if release tag exists." | |
| required: false | |
| default: "false" | |
| schedule: | |
| - cron: "0 * * * *" | |
| permissions: | |
| actions: write | |
| contents: write | |
| jobs: | |
| discover: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| has_runs: ${{ steps.discover.outputs.has_runs }} | |
| matrix: ${{ steps.discover.outputs.matrix }} | |
| env: | |
| AWS_REGION: ${{ secrets.AWS_REGION != '' && secrets.AWS_REGION || 'us-east-1' }} | |
| SCFUZZBENCH_BUCKET: ${{ secrets.SCFUZZBENCH_BUCKET }} | |
| steps: | |
| - name: Ensure AWS credentials are configured | |
| run: | | |
| if [ -z "${{ secrets.AWS_ACCESS_KEY_ID }}" ] || [ -z "${{ secrets.AWS_SECRET_ACCESS_KEY }}" ]; then | |
| echo "Set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY secrets." >&2 | |
| exit 1 | |
| fi | |
| if [ -z "${AWS_REGION}" ]; then | |
| echo "Set AWS_REGION secret." >&2 | |
| exit 1 | |
| fi | |
| if [ -z "${SCFUZZBENCH_BUCKET}" ]; then | |
| echo "Set SCFUZZBENCH_BUCKET secret." >&2 | |
| exit 1 | |
| fi | |
| - name: Configure AWS credentials (keys) | |
| uses: aws-actions/configure-aws-credentials@7474bc4690e29a8392af63c5b98e7449536d5c3a # v4 | |
| with: | |
| aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} | |
| aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} | |
| aws-region: ${{ env.AWS_REGION }} | |
| - name: Discover runs | |
| id: discover | |
| env: | |
| BENCHMARK_UUID: ${{ inputs.benchmark_uuid }} | |
| RUN_ID: ${{ inputs.run_id }} | |
| REPORT_BUDGET_HOURS: ${{ inputs.report_budget_hours }} | |
| GRACE_SECONDS: "3600" | |
| run: | | |
| set -euo pipefail | |
| if [[ -n "${BENCHMARK_UUID}" || -n "${RUN_ID}" ]]; then | |
| if [[ -z "${BENCHMARK_UUID}" || -z "${RUN_ID}" ]]; then | |
| echo "Both benchmark_uuid and run_id are required when manually specifying a run." >&2 | |
| exit 1 | |
| fi | |
| matrix=$(python3 - <<'PY' | |
| import json | |
| import os | |
| entry = { | |
| "benchmark_uuid": os.environ["BENCHMARK_UUID"], | |
| "run_id": os.environ["RUN_ID"], | |
| } | |
| report_budget = os.environ.get("REPORT_BUDGET_HOURS", "").strip() | |
| if report_budget: | |
| entry["report_budget_hours"] = report_budget | |
| print(json.dumps({"include": [entry]}, separators=(",", ":"))) | |
| PY | |
| ) | |
| echo "has_runs=true" >> "${GITHUB_OUTPUT}" | |
| echo "matrix=${matrix}" >> "${GITHUB_OUTPUT}" | |
| exit 0 | |
| fi | |
| matrix=$(python3 - <<'PY' | |
| import json | |
| import os | |
| import subprocess | |
| import time | |
| bucket = os.environ["SCFUZZBENCH_BUCKET"] | |
| grace = int(os.environ.get("GRACE_SECONDS", "3600")) | |
| now = int(time.time()) | |
| def aws(*args: str) -> str: | |
| return subprocess.check_output(["aws", *args], text=True) | |
| def list_prefixes(prefix: str) -> list[str]: | |
| data = json.loads( | |
| aws( | |
| "s3api", | |
| "list-objects-v2", | |
| "--bucket", | |
| bucket, | |
| "--prefix", | |
| prefix, | |
| "--delimiter", | |
| "/", | |
| "--output", | |
| "json", | |
| ) | |
| ) | |
| return [entry["Prefix"] for entry in data.get("CommonPrefixes", [])] | |
| runs: list[dict] = [] | |
| for run_prefix in list_prefixes("logs/"): | |
| parts = run_prefix.strip("/").split("/") | |
| if len(parts) < 2: | |
| continue | |
| run_id = parts[1] | |
| for bench_prefix in list_prefixes(f"logs/{run_id}/"): | |
| bench_parts = bench_prefix.strip("/").split("/") | |
| if len(bench_parts) < 3: | |
| continue | |
| benchmark_uuid = bench_parts[2] | |
| manifest_key = f"logs/{run_id}/{benchmark_uuid}/manifest.json" | |
| try: | |
| manifest_raw = aws("s3", "cp", f"s3://{bucket}/{manifest_key}", "-") | |
| manifest = json.loads(manifest_raw) | |
| except Exception: | |
| continue | |
| try: | |
| timeout_hours = float(manifest.get("timeout_hours", 24)) | |
| except Exception: | |
| timeout_hours = 24.0 | |
| try: | |
| run_start = int(run_id) | |
| except ValueError: | |
| continue | |
| if now >= run_start + int(timeout_hours * 3600) + grace: | |
| runs.append( | |
| { | |
| "benchmark_uuid": benchmark_uuid, | |
| "run_id": run_id, | |
| "timeout_hours": timeout_hours, | |
| } | |
| ) | |
| print(json.dumps({"include": runs}, separators=(",", ":"))) | |
| PY | |
| ) | |
| if [[ "${matrix}" == '{"include":[]}' ]]; then | |
| echo "has_runs=false" >> "${GITHUB_OUTPUT}" | |
| else | |
| echo "has_runs=true" >> "${GITHUB_OUTPUT}" | |
| fi | |
| echo "matrix=${matrix}" >> "${GITHUB_OUTPUT}" | |
| release: | |
| needs: discover | |
| if: ${{ needs.discover.outputs.has_runs == 'true' }} | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: ${{ fromJson(needs.discover.outputs.matrix) }} | |
| env: | |
| AWS_REGION: ${{ secrets.AWS_REGION != '' && secrets.AWS_REGION || 'us-east-1' }} | |
| SCFUZZBENCH_BUCKET: ${{ secrets.SCFUZZBENCH_BUCKET }} | |
| steps: | |
| - name: Checkout (tarball) | |
| timeout-minutes: 5 | |
| env: | |
| REPO: ${{ github.repository }} | |
| SHA: ${{ github.sha }} | |
| run: | | |
| set -euo pipefail | |
| url="https://codeload.github.com/${REPO}/tar.gz/${SHA}" | |
| curl -fsSL "${url}" -o repo.tar.gz | |
| topdir="$(tar -tzf repo.tar.gz | sed -n '1p' | cut -d/ -f1)" | |
| tar -xzf repo.tar.gz | |
| shopt -s dotglob | |
| mv "${topdir}"/* . | |
| rm -rf "${topdir}" repo.tar.gz | |
| - name: Configure AWS credentials (keys) | |
| uses: aws-actions/configure-aws-credentials@7474bc4690e29a8392af63c5b98e7449536d5c3a # v4 | |
| with: | |
| aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} | |
| aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} | |
| aws-region: ${{ env.AWS_REGION }} | |
| - name: Check for existing release | |
| id: release_check | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| set -euo pipefail | |
| tag="scfuzzbench-${{ matrix.benchmark_uuid }}-${{ matrix.run_id }}" | |
| if gh release view "${tag}" --repo "${GITHUB_REPOSITORY}" >/dev/null 2>&1; then | |
| echo "exists=true" >> "${GITHUB_OUTPUT}" | |
| else | |
| echo "exists=false" >> "${GITHUB_OUTPUT}" | |
| fi | |
| echo "tag=${tag}" >> "${GITHUB_OUTPUT}" | |
| - name: Setup Python | |
| if: ${{ steps.release_check.outputs.exists != 'true' || inputs.force_reanalyze == 'true' }} | |
| uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 | |
| with: | |
| python-version: "3.11" | |
| - name: Install analysis dependencies | |
| if: ${{ steps.release_check.outputs.exists != 'true' || inputs.force_reanalyze == 'true' }} | |
| run: make analysis-venv | |
| - name: Fetch manifest | |
| if: ${{ steps.release_check.outputs.exists != 'true' || inputs.force_reanalyze == 'true' }} | |
| id: manifest | |
| env: | |
| REPORT_BUDGET_HOURS: ${{ matrix.report_budget_hours }} | |
| run: | | |
| set -euo pipefail | |
| dest_root="${GITHUB_WORKSPACE}/analysis-artifacts/${{ matrix.run_id }}" | |
| analysis_dir="${dest_root}/analysis" | |
| mkdir -p "${analysis_dir}" | |
| logs_manifest_key="logs/${{ matrix.run_id }}/${{ matrix.benchmark_uuid }}/manifest.json" | |
| runs_manifest_key="runs/${{ matrix.run_id }}/${{ matrix.benchmark_uuid }}/manifest.json" | |
| if aws s3 cp "s3://${SCFUZZBENCH_BUCKET}/${logs_manifest_key}" "${analysis_dir}/manifest.json"; then | |
| echo "Fetched manifest from ${logs_manifest_key}" | |
| else | |
| aws s3 cp "s3://${SCFUZZBENCH_BUCKET}/${runs_manifest_key}" "${analysis_dir}/manifest.json" | |
| echo "Fetched manifest from ${runs_manifest_key}" | |
| fi | |
| timeout_hours="${{ matrix.timeout_hours }}" | |
| if [[ -z "${timeout_hours}" || "${timeout_hours}" == "null" ]]; then | |
| timeout_hours=$(ANALYSIS_DIR="${analysis_dir}" python3 - <<'PY' | |
| import json | |
| import os | |
| from pathlib import Path | |
| manifest_path = Path(os.environ["ANALYSIS_DIR"]) / "manifest.json" | |
| manifest = json.loads(manifest_path.read_text()) | |
| value = manifest.get("timeout_hours", 24) | |
| print(value) | |
| PY | |
| ) | |
| fi | |
| report_budget="${REPORT_BUDGET_HOURS}" | |
| if [[ -z "${report_budget}" ]]; then | |
| report_budget="${timeout_hours}" | |
| fi | |
| { | |
| echo "timeout_hours=${timeout_hours}" | |
| echo "report_budget_hours=${report_budget}" | |
| echo "dest_root=${dest_root}" | |
| echo "analysis_dir=${analysis_dir}" | |
| } >> "${GITHUB_OUTPUT}" | |
| - name: Run analysis | |
| if: ${{ steps.release_check.outputs.exists != 'true' || inputs.force_reanalyze == 'true' }} | |
| env: | |
| BUCKET: ${{ env.SCFUZZBENCH_BUCKET }} | |
| RUN_ID: ${{ matrix.run_id }} | |
| BENCHMARK_UUID: ${{ matrix.benchmark_uuid }} | |
| ARTIFACT_CATEGORY: both | |
| DEST: ${{ steps.manifest.outputs.dest_root }} | |
| DURATION_HOURS: ${{ steps.manifest.outputs.report_budget_hours }} | |
| REPORT_BUDGET: ${{ steps.manifest.outputs.report_budget_hours }} | |
| EXCLUDE_FUZZERS: ${{ inputs.exclude_fuzzers }} | |
| run: | | |
| set -euo pipefail | |
| make results-analyze-all | |
| - name: Collect analysis artifacts | |
| if: ${{ steps.release_check.outputs.exists != 'true' || inputs.force_reanalyze == 'true' }} | |
| run: | | |
| set -euo pipefail | |
| dest_root="${{ steps.manifest.outputs.dest_root }}" | |
| analysis_dir="${{ steps.manifest.outputs.analysis_dir }}" | |
| # Website + release notes expect these at the top-level. | |
| cp "${dest_root}/data/REPORT.md" "${analysis_dir}/REPORT.md" | |
| cp "${dest_root}/images/bugs_over_time.png" "${analysis_dir}/bugs_over_time.png" | |
| cp "${dest_root}/images/time_to_k.png" "${analysis_dir}/time_to_k.png" | |
| cp "${dest_root}/images/final_distribution.png" "${analysis_dir}/final_distribution.png" | |
| cp "${dest_root}/images/plateau_and_late_share.png" "${analysis_dir}/plateau_and_late_share.png" | |
| cp "${dest_root}/images/invariant_overlap_upset.png" "${analysis_dir}/invariant_overlap_upset.png" | |
| cp "${dest_root}/images/cpu_usage_over_time.png" "${analysis_dir}/cpu_usage_over_time.png" | |
| cp "${dest_root}/images/memory_usage_over_time.png" "${analysis_dir}/memory_usage_over_time.png" | |
| for optional_chart in \ | |
| tx_per_second_over_time.png \ | |
| gas_per_second_over_time.png \ | |
| seq_per_second_over_time.png \ | |
| coverage_proxy_over_time.png \ | |
| corpus_size_over_time.png \ | |
| favored_items_over_time.png \ | |
| failure_rate_over_time.png \ | |
| progress_metrics_levels.png \ | |
| progress_metrics_availability.png | |
| do | |
| if [[ -f "${dest_root}/images/${optional_chart}" ]]; then | |
| cp "${dest_root}/images/${optional_chart}" "${analysis_dir}/${optional_chart}" | |
| fi | |
| done | |
| cp "${dest_root}/data/broken_invariants.md" "${analysis_dir}/broken_invariants.md" | |
| cp "${dest_root}/data/broken_invariants.csv" "${analysis_dir}/broken_invariants.csv" | |
| cp "${dest_root}/data/runner_resource_usage.md" "${analysis_dir}/runner_resource_usage.md" | |
| cp "${dest_root}/data/runner_resource_summary.csv" "${analysis_dir}/runner_resource_summary.csv" | |
| cp "${dest_root}/data/runner_resource_timeseries.csv" "${analysis_dir}/runner_resource_timeseries.csv" | |
| if [[ -f "${dest_root}/data/throughput_summary.csv" ]]; then | |
| cp "${dest_root}/data/throughput_summary.csv" "${analysis_dir}/throughput_summary.csv" | |
| fi | |
| if [[ -f "${dest_root}/data/progress_metrics_summary.csv" ]]; then | |
| cp "${dest_root}/data/progress_metrics_summary.csv" "${analysis_dir}/progress_metrics_summary.csv" | |
| fi | |
| for differential_csv in \ | |
| differential_coverage_summary.csv \ | |
| differential_coverage_relscores.csv \ | |
| differential_coverage_relcov.csv | |
| do | |
| if [[ -f "${dest_root}/data/${differential_csv}" ]]; then | |
| cp "${dest_root}/data/${differential_csv}" "${analysis_dir}/${differential_csv}" | |
| fi | |
| done | |
| if [[ -f "${dest_root}/data/showmap_campaign_manifest.json" ]]; then | |
| cp "${dest_root}/data/showmap_campaign_manifest.json" "${analysis_dir}/showmap_campaign_manifest.json" | |
| fi | |
| if [[ -d "${dest_root}/data/showmap_campaigns" ]]; then | |
| rm -rf "${analysis_dir}/showmap_campaigns" | |
| cp -R "${dest_root}/data/showmap_campaigns" "${analysis_dir}/showmap_campaigns" | |
| fi | |
| # Optional: include raw CSV outputs in the analysis bundle for debugging. | |
| mkdir -p "${analysis_dir}/data" | |
| cp "${dest_root}/data/"*.csv "${analysis_dir}/data/" || true | |
| - name: Build release bundles | |
| if: ${{ steps.release_check.outputs.exists != 'true' || inputs.force_reanalyze == 'true' }} | |
| id: bundles | |
| run: | | |
| set -euo pipefail | |
| dest_root="${{ steps.manifest.outputs.dest_root }}" | |
| analysis_dir="${{ steps.manifest.outputs.analysis_dir }}" | |
| release_dir="${dest_root}/release" | |
| mkdir -p "${release_dir}" | |
| (cd "${analysis_dir}" && zip -r "${release_dir}/analysis.zip" .) | |
| if compgen -G "${dest_root}/logs/zips/*.zip" > /dev/null; then | |
| (cd "${dest_root}/logs/zips" && zip -r "${release_dir}/logs.zip" .) | |
| echo "has_logs_zip=true" >> "${GITHUB_OUTPUT}" | |
| else | |
| echo "has_logs_zip=false" >> "${GITHUB_OUTPUT}" | |
| fi | |
| if compgen -G "${dest_root}/corpus/zips/*.zip" > /dev/null; then | |
| (cd "${dest_root}/corpus/zips" && zip -r "${release_dir}/corpus.zip" .) | |
| echo "has_corpus_zip=true" >> "${GITHUB_OUTPUT}" | |
| else | |
| echo "has_corpus_zip=false" >> "${GITHUB_OUTPUT}" | |
| fi | |
| echo "release_dir=${release_dir}" >> "${GITHUB_OUTPUT}" | |
| - name: Upload analysis artifacts to S3 | |
| if: ${{ steps.release_check.outputs.exists != 'true' || inputs.force_reanalyze == 'true' }} | |
| run: | | |
| set -euo pipefail | |
| analysis_dir="${{ steps.manifest.outputs.analysis_dir }}" | |
| release_dir="${{ steps.bundles.outputs.release_dir }}" | |
| s3_prefix="analysis/${{ matrix.benchmark_uuid }}/${{ matrix.run_id }}" | |
| aws s3 cp "${analysis_dir}/REPORT.md" "s3://${SCFUZZBENCH_BUCKET}/${s3_prefix}/REPORT.md" --content-type text/markdown | |
| aws s3 cp "${analysis_dir}/bugs_over_time.png" "s3://${SCFUZZBENCH_BUCKET}/${s3_prefix}/bugs_over_time.png" --content-type image/png | |
| aws s3 cp "${analysis_dir}/time_to_k.png" "s3://${SCFUZZBENCH_BUCKET}/${s3_prefix}/time_to_k.png" --content-type image/png | |
| aws s3 cp "${analysis_dir}/final_distribution.png" "s3://${SCFUZZBENCH_BUCKET}/${s3_prefix}/final_distribution.png" --content-type image/png | |
| aws s3 cp "${analysis_dir}/plateau_and_late_share.png" "s3://${SCFUZZBENCH_BUCKET}/${s3_prefix}/plateau_and_late_share.png" --content-type image/png | |
| aws s3 cp "${analysis_dir}/invariant_overlap_upset.png" "s3://${SCFUZZBENCH_BUCKET}/${s3_prefix}/invariant_overlap_upset.png" --content-type image/png | |
| aws s3 cp "${analysis_dir}/cpu_usage_over_time.png" "s3://${SCFUZZBENCH_BUCKET}/${s3_prefix}/cpu_usage_over_time.png" --content-type image/png | |
| aws s3 cp "${analysis_dir}/memory_usage_over_time.png" "s3://${SCFUZZBENCH_BUCKET}/${s3_prefix}/memory_usage_over_time.png" --content-type image/png | |
| for optional_chart in \ | |
| tx_per_second_over_time.png \ | |
| gas_per_second_over_time.png \ | |
| seq_per_second_over_time.png \ | |
| coverage_proxy_over_time.png \ | |
| corpus_size_over_time.png \ | |
| favored_items_over_time.png \ | |
| failure_rate_over_time.png \ | |
| progress_metrics_levels.png \ | |
| progress_metrics_availability.png | |
| do | |
| if [[ -f "${analysis_dir}/${optional_chart}" ]]; then | |
| aws s3 cp "${analysis_dir}/${optional_chart}" "s3://${SCFUZZBENCH_BUCKET}/${s3_prefix}/${optional_chart}" --content-type image/png | |
| fi | |
| done | |
| aws s3 cp "${analysis_dir}/broken_invariants.md" "s3://${SCFUZZBENCH_BUCKET}/${s3_prefix}/broken_invariants.md" --content-type text/markdown | |
| aws s3 cp "${analysis_dir}/broken_invariants.csv" "s3://${SCFUZZBENCH_BUCKET}/${s3_prefix}/broken_invariants.csv" --content-type text/csv | |
| aws s3 cp "${analysis_dir}/runner_resource_usage.md" "s3://${SCFUZZBENCH_BUCKET}/${s3_prefix}/runner_resource_usage.md" --content-type text/markdown | |
| aws s3 cp "${analysis_dir}/runner_resource_summary.csv" "s3://${SCFUZZBENCH_BUCKET}/${s3_prefix}/runner_resource_summary.csv" --content-type text/csv | |
| aws s3 cp "${analysis_dir}/runner_resource_timeseries.csv" "s3://${SCFUZZBENCH_BUCKET}/${s3_prefix}/runner_resource_timeseries.csv" --content-type text/csv | |
| if [[ -f "${analysis_dir}/throughput_summary.csv" ]]; then | |
| aws s3 cp "${analysis_dir}/throughput_summary.csv" "s3://${SCFUZZBENCH_BUCKET}/${s3_prefix}/throughput_summary.csv" --content-type text/csv | |
| fi | |
| if [[ -f "${analysis_dir}/progress_metrics_summary.csv" ]]; then | |
| aws s3 cp "${analysis_dir}/progress_metrics_summary.csv" "s3://${SCFUZZBENCH_BUCKET}/${s3_prefix}/progress_metrics_summary.csv" --content-type text/csv | |
| fi | |
| for differential_csv in \ | |
| differential_coverage_summary.csv \ | |
| differential_coverage_relscores.csv \ | |
| differential_coverage_relcov.csv | |
| do | |
| if [[ -f "${analysis_dir}/${differential_csv}" ]]; then | |
| aws s3 cp "${analysis_dir}/${differential_csv}" "s3://${SCFUZZBENCH_BUCKET}/${s3_prefix}/${differential_csv}" --content-type text/csv | |
| fi | |
| done | |
| if [[ -f "${analysis_dir}/showmap_campaign_manifest.json" ]]; then | |
| aws s3 cp "${analysis_dir}/showmap_campaign_manifest.json" "s3://${SCFUZZBENCH_BUCKET}/${s3_prefix}/showmap_campaign_manifest.json" --content-type application/json | |
| fi | |
| if [[ -d "${analysis_dir}/showmap_campaigns" ]]; then | |
| aws s3 cp "${analysis_dir}/showmap_campaigns" "s3://${SCFUZZBENCH_BUCKET}/${s3_prefix}/showmap_campaigns" --recursive | |
| fi | |
| aws s3 cp "${analysis_dir}/manifest.json" "s3://${SCFUZZBENCH_BUCKET}/${s3_prefix}/manifest.json" --content-type application/json | |
| aws s3 cp "${release_dir}/analysis.zip" "s3://${SCFUZZBENCH_BUCKET}/${s3_prefix}/bundles/analysis.zip" --content-type application/zip | |
| if [[ "${{ steps.bundles.outputs.has_logs_zip }}" == "true" ]]; then | |
| aws s3 cp "${release_dir}/logs.zip" "s3://${SCFUZZBENCH_BUCKET}/${s3_prefix}/bundles/logs.zip" --content-type application/zip | |
| fi | |
| if [[ "${{ steps.bundles.outputs.has_corpus_zip }}" == "true" ]]; then | |
| aws s3 cp "${release_dir}/corpus.zip" "s3://${SCFUZZBENCH_BUCKET}/${s3_prefix}/bundles/corpus.zip" --content-type application/zip | |
| fi | |
| - name: Compose release body | |
| if: ${{ steps.release_check.outputs.exists != 'true' }} | |
| id: body | |
| run: | | |
| set -euo pipefail | |
| analysis_dir="${{ steps.manifest.outputs.analysis_dir }}" | |
| report_path="${analysis_dir}/REPORT.md" | |
| release_body="${analysis_dir}/RELEASE.md" | |
| cp "${report_path}" "${release_body}" | |
| base_url="https://${SCFUZZBENCH_BUCKET}.s3.${AWS_REGION}.amazonaws.com" | |
| analysis_base="${base_url}/analysis/${{ matrix.benchmark_uuid }}/${{ matrix.run_id }}" | |
| logs_base="${base_url}/logs/${{ matrix.run_id }}/${{ matrix.benchmark_uuid }}" | |
| corpus_base="${base_url}/corpus/${{ matrix.run_id }}/${{ matrix.benchmark_uuid }}" | |
| bundles_base="${analysis_base}/bundles" | |
| { | |
| echo "" | |
| echo "## Artifacts" | |
| echo "" | |
| echo "Charts:" | |
| echo "" | |
| echo "" | |
| echo "" | |
| echo "" | |
| for optional_chart in \ | |
| tx_per_second_over_time.png \ | |
| gas_per_second_over_time.png \ | |
| seq_per_second_over_time.png \ | |
| coverage_proxy_over_time.png \ | |
| corpus_size_over_time.png \ | |
| favored_items_over_time.png \ | |
| failure_rate_over_time.png \ | |
| progress_metrics_levels.png \ | |
| progress_metrics_availability.png | |
| do | |
| if [[ -f "${analysis_dir}/${optional_chart}" ]]; then | |
| chart_label="${optional_chart%.png}" | |
| chart_label="${chart_label//_/ }" | |
| echo "" | |
| fi | |
| done | |
| echo "" | |
| echo "" | |
| echo "" | |
| echo "" | |
| echo "Downloads:" | |
| echo "- Analysis bundle: ${bundles_base}/analysis.zip" | |
| echo "- Broken invariants (Markdown): ${analysis_base}/broken_invariants.md" | |
| echo "- Broken invariants (CSV): ${analysis_base}/broken_invariants.csv" | |
| if [[ -f "${analysis_dir}/throughput_summary.csv" ]]; then | |
| echo "- Throughput summary (CSV): ${analysis_base}/throughput_summary.csv" | |
| fi | |
| if [[ -f "${analysis_dir}/progress_metrics_summary.csv" ]]; then | |
| echo "- Progress metrics summary (CSV): ${analysis_base}/progress_metrics_summary.csv" | |
| fi | |
| if [[ -f "${analysis_dir}/differential_coverage_summary.csv" ]]; then | |
| echo "- Differential coverage summary (CSV): ${analysis_base}/differential_coverage_summary.csv" | |
| fi | |
| if [[ -f "${analysis_dir}/differential_coverage_relscores.csv" ]]; then | |
| echo "- Differential coverage relscores (CSV): ${analysis_base}/differential_coverage_relscores.csv" | |
| fi | |
| if [[ -f "${analysis_dir}/differential_coverage_relcov.csv" ]]; then | |
| echo "- Differential coverage relcov (CSV): ${analysis_base}/differential_coverage_relcov.csv" | |
| fi | |
| if [[ -f "${analysis_dir}/showmap_campaign_manifest.json" ]]; then | |
| echo "- Showmap campaign manifest: ${analysis_base}/showmap_campaign_manifest.json" | |
| fi | |
| if [[ -d "${analysis_dir}/showmap_campaigns" ]]; then | |
| echo "- Showmap campaigns prefix: ${analysis_base}/showmap_campaigns/" | |
| fi | |
| echo "- Runner resource usage (Markdown): ${analysis_base}/runner_resource_usage.md" | |
| echo "- Runner resource summary (CSV): ${analysis_base}/runner_resource_summary.csv" | |
| echo "- Runner resource timeseries (CSV): ${analysis_base}/runner_resource_timeseries.csv" | |
| if [[ "${{ steps.bundles.outputs.has_logs_zip }}" == "true" ]]; then | |
| echo "- Logs bundle: ${bundles_base}/logs.zip" | |
| fi | |
| if [[ "${{ steps.bundles.outputs.has_corpus_zip }}" == "true" ]]; then | |
| echo "- Corpus bundle: ${bundles_base}/corpus.zip" | |
| fi | |
| echo "- Raw logs prefix: ${logs_base}/" | |
| if [[ "${{ steps.bundles.outputs.has_corpus_zip }}" == "true" ]]; then | |
| echo "- Raw corpus prefix: ${corpus_base}/" | |
| fi | |
| } >> "${release_body}" | |
| echo "release_body=${release_body}" >> "${GITHUB_OUTPUT}" | |
| - name: Create GitHub release | |
| if: ${{ steps.release_check.outputs.exists != 'true' }} | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| set -euo pipefail | |
| tag="${{ steps.release_check.outputs.tag }}" | |
| gh release create "${tag}" --repo "${GITHUB_REPOSITORY}" --title "${tag}" --notes-file "${{ steps.body.outputs.release_body }}" | |
| refresh_docs: | |
| needs: [discover, release] | |
| if: ${{ needs.discover.outputs.has_runs == 'true' && needs.release.result == 'success' }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Trigger docs refresh | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| set -euo pipefail | |
| gh workflow run "Docs Site" --repo "${GITHUB_REPOSITORY}" --ref main |