feat(terraphim): enrich KG with ast-grep code anchors + refresh script #6
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: Fuzz CI | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| schedule: | |
| - cron: "0 2 * * *" | |
| workflow_dispatch: | |
| inputs: | |
| profile: | |
| description: "Fuzz profile to run" | |
| required: false | |
| default: "quick" | |
| type: choice | |
| options: | |
| - quick | |
| - nightly | |
| - all | |
| permissions: | |
| contents: read | |
| env: | |
| CARGO_TERM_COLOR: always | |
| RUST_BACKTRACE: "1" | |
| jobs: | |
| fuzz-quick: | |
| name: "fuzz-quick (${{ matrix.target }})" | |
| if: >- | |
| github.event_name == 'push' || | |
| github.event_name == 'pull_request' || | |
| (github.event_name == 'workflow_dispatch' && | |
| (inputs.profile == 'quick' || inputs.profile == 'all')) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 45 | |
| strategy: | |
| fail-fast: false | |
| max-parallel: 4 | |
| matrix: | |
| target: | |
| - fuzz_sse_parser | |
| - fuzz_sse_stream | |
| - fuzz_session_jsonl | |
| - fuzz_session_entry | |
| - fuzz_provider_event | |
| - fuzz_message_deser | |
| - fuzz_message_roundtrip | |
| - fuzz_config | |
| - fuzz_config_load | |
| - fuzz_tool_paths | |
| - fuzz_grep_pattern | |
| - fuzz_edit_match | |
| - fuzz_extension_payload | |
| defaults: | |
| run: | |
| working-directory: pi_agent_rust | |
| shell: bash | |
| steps: | |
| - name: Checkout pi_agent_rust | |
| uses: actions/checkout@v4 | |
| with: | |
| path: pi_agent_rust | |
| - name: Install Rust toolchain (nightly) | |
| uses: dtolnay/rust-toolchain@nightly | |
| with: | |
| targets: x86_64-unknown-linux-gnu | |
| - name: Install cargo-fuzz | |
| uses: taiki-e/install-action@v2 | |
| with: | |
| tool: cargo-fuzz | |
| - name: Cache cargo artifacts | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.cargo/registry/index/ | |
| ~/.cargo/registry/cache/ | |
| ~/.cargo/git/db/ | |
| pi_agent_rust/fuzz/target/ | |
| key: fuzz-quick-${{ runner.os }}-${{ matrix.target }}-${{ hashFiles('pi_agent_rust/fuzz/Cargo.toml', 'pi_agent_rust/fuzz/Cargo.lock') }} | |
| restore-keys: | | |
| fuzz-quick-${{ runner.os }}-${{ matrix.target }}- | |
| fuzz-quick-${{ runner.os }}- | |
| - name: Run quick fuzz target | |
| env: | |
| FUZZ_PROFILE: quick | |
| FUZZ_TARGET: ${{ matrix.target }} | |
| FUZZ_SECONDS: "60" | |
| run: | | |
| set -euo pipefail | |
| cd fuzz | |
| mkdir -p "corpus/$FUZZ_TARGET" "artifacts/$FUZZ_TARGET" reports | |
| start_ts="$(date -u +%Y-%m-%dT%H:%M:%SZ)" | |
| start_ns="$(date +%s%N)" | |
| set +e | |
| # Force gnu target: cargo-binstall ships cargo-fuzz as a musl binary, | |
| # so its default host triple is x86_64-unknown-linux-musl. ASan is | |
| # incompatible with statically-linked libc, so we must build for the | |
| # dynamically-linked gnu target instead. | |
| cargo fuzz run --target x86_64-unknown-linux-gnu "$FUZZ_TARGET" -- \ | |
| -max_total_time="$FUZZ_SECONDS" \ | |
| -artifact_prefix="artifacts/$FUZZ_TARGET/" \ | |
| "corpus/$FUZZ_TARGET" \ | |
| 2>&1 | tee "reports/${FUZZ_TARGET}_${FUZZ_PROFILE}.log" | |
| exit_code=${PIPESTATUS[0]} | |
| set -e | |
| end_ts="$(date -u +%Y-%m-%dT%H:%M:%SZ)" | |
| end_ns="$(date +%s%N)" | |
| duration_ms=$(( (end_ns - start_ns) / 1000000 )) | |
| corpus_entries="$(find "corpus/$FUZZ_TARGET" -maxdepth 1 -type f 2>/dev/null | wc -l | tr -d ' ')" | |
| artifact_entries="$(find "artifacts/$FUZZ_TARGET" -maxdepth 1 -type f 2>/dev/null | wc -l | tr -d ' ')" | |
| status="pass" | |
| if [ "$exit_code" -ne 0 ]; then | |
| status="fail" | |
| fi | |
| cat > "reports/${FUZZ_TARGET}_${FUZZ_PROFILE}_summary.json" <<EOF | |
| { | |
| "schema": "pi.fuzz.run.v1", | |
| "profile": "$FUZZ_PROFILE", | |
| "target": "$FUZZ_TARGET", | |
| "max_total_time_s": $FUZZ_SECONDS, | |
| "status": "$status", | |
| "exit_code": $exit_code, | |
| "start_ts": "$start_ts", | |
| "end_ts": "$end_ts", | |
| "duration_ms": $duration_ms, | |
| "corpus_entries": $corpus_entries, | |
| "artifact_entries": $artifact_entries | |
| } | |
| EOF | |
| if [ "$exit_code" -ne 0 ]; then | |
| exit "$exit_code" | |
| fi | |
| - name: Upload quick fuzz reports | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: fuzz-quick-${{ matrix.target }}-${{ github.run_id }} | |
| path: | | |
| pi_agent_rust/fuzz/reports/${{ matrix.target }}_quick.log | |
| pi_agent_rust/fuzz/reports/${{ matrix.target }}_quick_summary.json | |
| if-no-files-found: warn | |
| retention-days: 14 | |
| - name: Upload crash artifacts (quick) | |
| if: failure() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: fuzz-crash-quick-${{ matrix.target }}-${{ github.run_id }} | |
| path: pi_agent_rust/fuzz/artifacts/${{ matrix.target }}/ | |
| if-no-files-found: ignore | |
| retention-days: 30 | |
| fuzz-nightly: | |
| name: "fuzz-nightly (${{ matrix.target }})" | |
| if: >- | |
| github.event_name == 'schedule' || | |
| (github.event_name == 'workflow_dispatch' && | |
| (inputs.profile == 'nightly' || inputs.profile == 'all')) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 120 | |
| strategy: | |
| fail-fast: false | |
| max-parallel: 2 | |
| matrix: | |
| target: | |
| - fuzz_sse_parser | |
| - fuzz_provider_event | |
| - fuzz_session_jsonl | |
| - fuzz_message_deser | |
| defaults: | |
| run: | |
| working-directory: pi_agent_rust | |
| shell: bash | |
| steps: | |
| - name: Checkout pi_agent_rust | |
| uses: actions/checkout@v4 | |
| with: | |
| path: pi_agent_rust | |
| - name: Install Rust toolchain (nightly) | |
| uses: dtolnay/rust-toolchain@nightly | |
| with: | |
| targets: x86_64-unknown-linux-gnu | |
| - name: Install cargo-fuzz | |
| uses: taiki-e/install-action@v2 | |
| with: | |
| tool: cargo-fuzz | |
| - name: Cache cargo artifacts | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.cargo/registry/index/ | |
| ~/.cargo/registry/cache/ | |
| ~/.cargo/git/db/ | |
| pi_agent_rust/fuzz/target/ | |
| key: fuzz-nightly-${{ runner.os }}-${{ matrix.target }}-${{ hashFiles('pi_agent_rust/fuzz/Cargo.toml', 'pi_agent_rust/fuzz/Cargo.lock') }} | |
| restore-keys: | | |
| fuzz-nightly-${{ runner.os }}-${{ matrix.target }}- | |
| fuzz-nightly-${{ runner.os }}- | |
| - name: Restore nightly corpus cache | |
| uses: actions/cache@v4 | |
| with: | |
| path: pi_agent_rust/fuzz/corpus/${{ matrix.target }} | |
| key: fuzz-corpus-${{ matrix.target }}-${{ github.run_id }} | |
| restore-keys: | | |
| fuzz-corpus-${{ matrix.target }}- | |
| - name: Run nightly fuzz target | |
| env: | |
| FUZZ_PROFILE: nightly | |
| FUZZ_TARGET: ${{ matrix.target }} | |
| FUZZ_SECONDS: "1800" | |
| run: | | |
| set -euo pipefail | |
| cd fuzz | |
| mkdir -p "corpus/$FUZZ_TARGET" "artifacts/$FUZZ_TARGET" reports | |
| start_ts="$(date -u +%Y-%m-%dT%H:%M:%SZ)" | |
| start_ns="$(date +%s%N)" | |
| set +e | |
| # Force gnu target: cargo-binstall ships cargo-fuzz as a musl binary, | |
| # so its default host triple is x86_64-unknown-linux-musl. ASan is | |
| # incompatible with statically-linked libc, so we must build for the | |
| # dynamically-linked gnu target instead. | |
| cargo fuzz run --target x86_64-unknown-linux-gnu "$FUZZ_TARGET" -- \ | |
| -max_total_time="$FUZZ_SECONDS" \ | |
| -artifact_prefix="artifacts/$FUZZ_TARGET/" \ | |
| "corpus/$FUZZ_TARGET" \ | |
| 2>&1 | tee "reports/${FUZZ_TARGET}_${FUZZ_PROFILE}.log" | |
| exit_code=${PIPESTATUS[0]} | |
| set -e | |
| end_ts="$(date -u +%Y-%m-%dT%H:%M:%SZ)" | |
| end_ns="$(date +%s%N)" | |
| duration_ms=$(( (end_ns - start_ns) / 1000000 )) | |
| corpus_entries="$(find "corpus/$FUZZ_TARGET" -maxdepth 1 -type f 2>/dev/null | wc -l | tr -d ' ')" | |
| artifact_entries="$(find "artifacts/$FUZZ_TARGET" -maxdepth 1 -type f 2>/dev/null | wc -l | tr -d ' ')" | |
| status="pass" | |
| if [ "$exit_code" -ne 0 ]; then | |
| status="fail" | |
| fi | |
| cat > "reports/${FUZZ_TARGET}_${FUZZ_PROFILE}_summary.json" <<EOF | |
| { | |
| "schema": "pi.fuzz.run.v1", | |
| "profile": "$FUZZ_PROFILE", | |
| "target": "$FUZZ_TARGET", | |
| "max_total_time_s": $FUZZ_SECONDS, | |
| "status": "$status", | |
| "exit_code": $exit_code, | |
| "start_ts": "$start_ts", | |
| "end_ts": "$end_ts", | |
| "duration_ms": $duration_ms, | |
| "corpus_entries": $corpus_entries, | |
| "artifact_entries": $artifact_entries | |
| } | |
| EOF | |
| if [ "$exit_code" -ne 0 ]; then | |
| exit "$exit_code" | |
| fi | |
| - name: Upload nightly fuzz reports | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: fuzz-nightly-${{ matrix.target }}-${{ github.run_id }} | |
| path: | | |
| pi_agent_rust/fuzz/reports/${{ matrix.target }}_nightly.log | |
| pi_agent_rust/fuzz/reports/${{ matrix.target }}_nightly_summary.json | |
| if-no-files-found: warn | |
| retention-days: 30 | |
| - name: Upload crash artifacts (nightly) | |
| if: failure() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: fuzz-crash-nightly-${{ matrix.target }}-${{ github.run_id }} | |
| path: pi_agent_rust/fuzz/artifacts/${{ matrix.target }}/ | |
| if-no-files-found: ignore | |
| retention-days: 30 | |
| - name: Upload corpus snapshot (nightly) | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: fuzz-corpus-${{ matrix.target }}-${{ github.run_id }} | |
| path: pi_agent_rust/fuzz/corpus/${{ matrix.target }}/ | |
| if-no-files-found: ignore | |
| retention-days: 14 | |
| fuzz-coverage-dashboard: | |
| name: fuzz-coverage-dashboard | |
| if: >- | |
| github.event_name == 'schedule' || | |
| (github.event_name == 'workflow_dispatch' && | |
| (inputs.profile == 'nightly' || inputs.profile == 'all')) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 60 | |
| defaults: | |
| run: | |
| working-directory: pi_agent_rust | |
| shell: bash | |
| env: | |
| FUZZ_TARGET: fuzz_sse_parser | |
| FUZZ_COVERAGE_SECONDS: "120" | |
| steps: | |
| - name: Checkout pi_agent_rust | |
| uses: actions/checkout@v4 | |
| with: | |
| path: pi_agent_rust | |
| - name: Install Rust toolchain (nightly) | |
| uses: dtolnay/rust-toolchain@nightly | |
| with: | |
| components: llvm-tools-preview | |
| targets: x86_64-unknown-linux-gnu | |
| - name: Install cargo-fuzz | |
| uses: taiki-e/install-action@v2 | |
| with: | |
| tool: cargo-fuzz | |
| - name: Cache cargo artifacts | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.cargo/registry/index/ | |
| ~/.cargo/registry/cache/ | |
| ~/.cargo/git/db/ | |
| pi_agent_rust/fuzz/target/ | |
| key: fuzz-coverage-${{ runner.os }}-${{ hashFiles('pi_agent_rust/fuzz/Cargo.toml', 'pi_agent_rust/fuzz/Cargo.lock') }} | |
| restore-keys: | | |
| fuzz-coverage-${{ runner.os }}- | |
| fuzz-nightly-${{ runner.os }}- | |
| - name: Build fuzz coverage dashboard | |
| run: | | |
| set -euo pipefail | |
| cd fuzz | |
| mkdir -p "corpus/${FUZZ_TARGET}" "coverage/dashboard/html" reports | |
| start_ts="$(date -u +%Y-%m-%dT%H:%M:%SZ)" | |
| start_ns="$(date +%s%N)" | |
| set +e | |
| # Force gnu target — see fuzz-quick job comment. | |
| cargo fuzz coverage --target x86_64-unknown-linux-gnu "${FUZZ_TARGET}" -- \ | |
| -max_total_time="${FUZZ_COVERAGE_SECONDS}" \ | |
| "corpus/${FUZZ_TARGET}" \ | |
| 2>&1 | tee "reports/${FUZZ_TARGET}_coverage.log" | |
| coverage_exit=${PIPESTATUS[0]} | |
| set -e | |
| end_ts="$(date -u +%Y-%m-%dT%H:%M:%SZ)" | |
| end_ns="$(date +%s%N)" | |
| duration_ms=$(( (end_ns - start_ns) / 1000000 )) | |
| if [ "${coverage_exit}" -ne 0 ]; then | |
| echo "coverage run failed for ${FUZZ_TARGET} (exit=${coverage_exit})" >&2 | |
| exit "${coverage_exit}" | |
| fi | |
| host_triple="$(rustc -vV | awk '/host:/ {print $2}')" | |
| llvm_tools_bin="$(rustc --print sysroot)/lib/rustlib/${host_triple}/bin" | |
| llvm_cov="${llvm_tools_bin}/llvm-cov" | |
| llvm_profdata="${llvm_tools_bin}/llvm-profdata" | |
| if [ ! -x "${llvm_cov}" ] || [ ! -x "${llvm_profdata}" ]; then | |
| echo "missing llvm tools in ${llvm_tools_bin}" >&2 | |
| exit 1 | |
| fi | |
| profdata="coverage/${FUZZ_TARGET}/coverage.profdata" | |
| binary_path="$(find target -type f -path '*coverage*' -name "${FUZZ_TARGET}" | head -n 1 || true)" | |
| if [ -z "${binary_path}" ] || [ ! -f "${profdata}" ]; then | |
| echo "coverage artifacts missing (binary='${binary_path}', profdata='${profdata}')" >&2 | |
| exit 1 | |
| fi | |
| raw_summary_json="coverage/dashboard/${FUZZ_TARGET}_raw_summary.json" | |
| dashboard_json="coverage/dashboard/${FUZZ_TARGET}_dashboard.json" | |
| dashboard_md="coverage/dashboard/${FUZZ_TARGET}_dashboard.md" | |
| report_txt="coverage/dashboard/${FUZZ_TARGET}_report.txt" | |
| html_dir="coverage/dashboard/html/${FUZZ_TARGET}" | |
| "${llvm_cov}" export \ | |
| --format=text \ | |
| --summary-only \ | |
| --instr-profile="${profdata}" \ | |
| "${binary_path}" > "${raw_summary_json}" | |
| "${llvm_cov}" report \ | |
| --instr-profile="${profdata}" \ | |
| "${binary_path}" > "${report_txt}" | |
| "${llvm_cov}" show \ | |
| --format=html \ | |
| --output-dir="${html_dir}" \ | |
| --instr-profile="${profdata}" \ | |
| "${binary_path}" | |
| jq \ | |
| --arg schema "pi.fuzz.coverage.dashboard.v1" \ | |
| --arg target "${FUZZ_TARGET}" \ | |
| --arg started "${start_ts}" \ | |
| --arg finished "${end_ts}" \ | |
| --argjson duration_ms "${duration_ms}" \ | |
| --arg run_id "${GITHUB_RUN_ID}" \ | |
| '{ | |
| schema: $schema, | |
| target: $target, | |
| run_id: $run_id, | |
| started_at: $started, | |
| finished_at: $finished, | |
| duration_ms: $duration_ms, | |
| totals: { | |
| lines: (.data[0].totals.lines // {}), | |
| branches: (.data[0].totals.branches // {}), | |
| functions: (.data[0].totals.functions // {}), | |
| regions: (.data[0].totals.regions // {}) | |
| }, | |
| files_lowest_line_coverage: ( | |
| (.data[0].files // []) | |
| | map({ | |
| file: .filename, | |
| lines: (.summary.lines // {}), | |
| branches: (.summary.branches // {}) | |
| }) | |
| | sort_by((.lines.percent // 0)) | |
| | .[:25] | |
| ) | |
| }' "${raw_summary_json}" > "${dashboard_json}" | |
| jq -r ' | |
| "## Fuzz Coverage Dashboard", | |
| "", | |
| "Target: `\(.target)`", | |
| "", | |
| "| Metric | Covered | Count | Percent |", | |
| "|---|---:|---:|---:|", | |
| "| Lines | \(.totals.lines.covered // 0) | \(.totals.lines.count // 0) | \((.totals.lines.percent // 0)|tostring)% |", | |
| "| Branches | \(.totals.branches.covered // 0) | \(.totals.branches.count // 0) | \((.totals.branches.percent // 0)|tostring)% |", | |
| "| Functions | \(.totals.functions.covered // 0) | \(.totals.functions.count // 0) | \((.totals.functions.percent // 0)|tostring)% |", | |
| "| Regions | \(.totals.regions.covered // 0) | \(.totals.regions.count // 0) | \((.totals.regions.percent // 0)|tostring)% |", | |
| "", | |
| "### Lowest line coverage files (top 25)", | |
| "", | |
| "| File | Lines % | Branches % |", | |
| "|---|---:|---:|", | |
| (.files_lowest_line_coverage[] | | |
| "| `\(.file)` | \((.lines.percent // 0)|tostring)% | \((.branches.percent // 0)|tostring)% |") | |
| ' "${dashboard_json}" > "${dashboard_md}" | |
| cat "${dashboard_md}" >> "${GITHUB_STEP_SUMMARY}" | |
| - name: Upload fuzz coverage dashboard artifacts | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: fuzz-coverage-dashboard-${{ env.FUZZ_TARGET }}-${{ github.run_id }} | |
| path: | | |
| pi_agent_rust/fuzz/reports/${{ env.FUZZ_TARGET }}_coverage.log | |
| pi_agent_rust/fuzz/coverage/${{ env.FUZZ_TARGET }}/ | |
| pi_agent_rust/fuzz/coverage/dashboard/${{ env.FUZZ_TARGET }}_raw_summary.json | |
| pi_agent_rust/fuzz/coverage/dashboard/${{ env.FUZZ_TARGET }}_dashboard.json | |
| pi_agent_rust/fuzz/coverage/dashboard/${{ env.FUZZ_TARGET }}_dashboard.md | |
| pi_agent_rust/fuzz/coverage/dashboard/${{ env.FUZZ_TARGET }}_report.txt | |
| pi_agent_rust/fuzz/coverage/dashboard/html/${{ env.FUZZ_TARGET }}/ | |
| if-no-files-found: warn | |
| retention-days: 30 |