mirror of
https://github.com/elicpeter/nyx.git
synced 2026-06-09 19:45:13 +02:00
[pitboss] phase 06: M5.5 — Coverage-feedback payload generation + OOB listener finalized
This commit is contained in:
parent
86613f5279
commit
6f8a645077
12 changed files with 1556 additions and 69 deletions
39
.github/workflows/ci.yml
vendored
39
.github/workflows/ci.yml
vendored
|
|
@ -382,3 +382,42 @@ jobs:
|
|||
name: benchmark-results
|
||||
path: tests/benchmark/results/latest.json
|
||||
if-no-files-found: warn
|
||||
|
||||
corpus-marker-audit:
|
||||
name: corpus-marker-audit
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.12"
|
||||
|
||||
- name: Marker collision audit (§16.3)
|
||||
run: python3 scripts/corpus_dashboard.py
|
||||
# Exits non-zero if any oracle marker from one cap appears in another
|
||||
# cap's payload bytes. This catches cross-cap oracle collisions that
|
||||
# would cause false-positive confirmed verdicts.
|
||||
|
||||
- uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
cache: true
|
||||
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 20
|
||||
cache: npm
|
||||
cache-dependency-path: frontend/package-lock.json
|
||||
|
||||
- name: Build frontend
|
||||
working-directory: frontend
|
||||
run: |
|
||||
npm ci
|
||||
npm run build
|
||||
|
||||
- name: Corpus unit tests (no_marker_collisions, all_payloads_have_fixture_paths)
|
||||
run: cargo nextest run --lib -p nyx-scanner --test-threads=4 2>/dev/null || \
|
||||
cargo nextest run --lib -p nyx-scanner
|
||||
env:
|
||||
RUST_LOG: error
|
||||
|
|
|
|||
157
.github/workflows/corpus_promote.yml
vendored
Normal file
157
.github/workflows/corpus_promote.yml
vendored
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
name: Corpus Promote
|
||||
|
||||
# Weekly automated promotion-PR template.
|
||||
#
|
||||
# Scans fuzz-discovered/ for candidates not yet in src/dynamic/corpus.rs
|
||||
# and opens a PR proposing them for human review (§16.4 — no auto-merge).
|
||||
#
|
||||
# Also runs the marker-collision audit as a hard gate: if any collision is
|
||||
# found the workflow fails rather than proposing the promotion.
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# Sundays at 09:00 UTC — offset from the fuzz run (06:00 UTC) so
|
||||
# discovered candidates are ready before the promotion job runs.
|
||||
- cron: "0 9 * * 0"
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
dry_run:
|
||||
description: "Dry run (print PR body but do not open)"
|
||||
required: false
|
||||
default: "false"
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
concurrency:
|
||||
group: corpus-promote
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
promote:
|
||||
name: Propose corpus promotions
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
cache: true
|
||||
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 20
|
||||
cache: npm
|
||||
cache-dependency-path: frontend/package-lock.json
|
||||
|
||||
- name: Build frontend
|
||||
working-directory: frontend
|
||||
run: |
|
||||
npm ci
|
||||
npm run build
|
||||
|
||||
# ── Marker collision audit ──────────────────────────────────────────────
|
||||
- name: Marker collision audit
|
||||
run: |
|
||||
set -euo pipefail
|
||||
cargo build --features dynamic -p nyx-scanner 2>/dev/null || true
|
||||
cd fuzz/dynamic_corpus
|
||||
cargo run -- audit-markers
|
||||
env:
|
||||
RUST_LOG: error
|
||||
|
||||
# ── Discover candidates ─────────────────────────────────────────────────
|
||||
- name: Find promotion candidates
|
||||
id: candidates
|
||||
run: |
|
||||
set -euo pipefail
|
||||
count=0
|
||||
files=""
|
||||
if [ -d fuzz-discovered ]; then
|
||||
while IFS= read -r f; do
|
||||
# Skip .gitkeep, sidecar JSONs, and files already listed in corpus.rs.
|
||||
[[ "$f" == *".gitkeep" ]] && continue
|
||||
[[ "$f" == *".json" ]] && continue
|
||||
bytes=$(xxd -p "$f" | tr -d '\n')
|
||||
if ! grep -q "$bytes" src/dynamic/corpus.rs 2>/dev/null; then
|
||||
count=$((count + 1))
|
||||
files="$files $f"
|
||||
fi
|
||||
done < <(find fuzz-discovered -type f | sort)
|
||||
fi
|
||||
echo "count=$count" >> "$GITHUB_OUTPUT"
|
||||
echo "files=$files" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Skip if no new candidates
|
||||
if: steps.candidates.outputs.count == '0'
|
||||
run: |
|
||||
echo "No new candidates found in fuzz-discovered/. Nothing to promote."
|
||||
|
||||
# ── Open promotion PR ───────────────────────────────────────────────────
|
||||
- name: Open promotion PR
|
||||
if: >
|
||||
steps.candidates.outputs.count != '0' &&
|
||||
github.event.inputs.dry_run != 'true'
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
CANDIDATE_COUNT: ${{ steps.candidates.outputs.count }}
|
||||
CANDIDATE_FILES: ${{ steps.candidates.outputs.files }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
branch="corpus-promote-$(date +%Y%m%d)"
|
||||
git checkout -b "$branch"
|
||||
|
||||
# Stage candidate files into fuzz-discovered (already there).
|
||||
# The PR body provides the reviewer with everything they need.
|
||||
|
||||
# Build PR body.
|
||||
body=$(cat <<'EOF'
|
||||
## Corpus Promotion Proposal
|
||||
|
||||
This PR was generated automatically by the weekly corpus-promote workflow.
|
||||
It does **not** auto-merge — a human reviewer must approve each candidate
|
||||
before it can land in `src/dynamic/corpus.rs` (§16.4).
|
||||
|
||||
### Candidates
|
||||
|
||||
The following payloads were discovered by the internal mutation fuzzer and
|
||||
confirmed via `sink_hit && oracle_fired` against instrumented fixtures:
|
||||
|
||||
EOF
|
||||
)
|
||||
|
||||
for f in $CANDIDATE_FILES; do
|
||||
sidecar="${f}.json"
|
||||
if [ -f "$sidecar" ]; then
|
||||
body="$body\n- \`$f\`\n \`\`\`json\n$(cat "$sidecar")\n \`\`\`\n"
|
||||
else
|
||||
body="$body\n- \`$f\`\n"
|
||||
fi
|
||||
done
|
||||
|
||||
body="$body\n### Review checklist\n"
|
||||
body="$body\n- [ ] Bytes are a genuine attack vector, not a fixture artifact\n"
|
||||
body="$body\n- [ ] Oracle marker is unique (no collision with other caps)\n"
|
||||
body="$body\n- [ ] \`fixture_paths\` updated in \`src/dynamic/corpus.rs\`\n"
|
||||
body="$body\n- [ ] \`since_corpus_version\` set to next version\n"
|
||||
body="$body\n- [ ] \`CORPUS_VERSION\` bumped and bump history updated\n"
|
||||
body="$body\n\n_Generated by corpus_promote.yml — do not auto-merge._\n"
|
||||
|
||||
git add fuzz-discovered/ || true
|
||||
git diff --cached --quiet || git commit -m "chore: add ${CANDIDATE_COUNT} fuzzer-discovered corpus candidates"
|
||||
|
||||
git push origin "$branch"
|
||||
|
||||
gh pr create \
|
||||
--title "chore(corpus): promote ${CANDIDATE_COUNT} fuzzer-discovered payload(s)" \
|
||||
--body "$(printf '%b' "$body")" \
|
||||
--base master \
|
||||
--label "corpus-promotion" || true
|
||||
|
||||
- name: Dry run summary
|
||||
if: github.event.inputs.dry_run == 'true'
|
||||
run: |
|
||||
echo "Dry run: would promote ${{ steps.candidates.outputs.count }} candidate(s)."
|
||||
echo "Files: ${{ steps.candidates.outputs.files }}"
|
||||
Loading…
Add table
Add a link
Reference in a new issue