1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
name: Fuzz
# ALICE-SDF v1.7.7 (commit 52d26f9) を base に ALICE-Physics 用に調整
#
# 目的:
# - fuzz/Cargo.toml の [[bin]] を全部 build し (push / PR、build-all job)、push / PR では
# core 4 target、夜間と手動では全 target を time-boxed 実行 (一覧は scripts/fuzz_targets.py)
# - 決定論 lockstep が scene format 経由で保たれることを検証 (roundtrip)
#
# 罠:
# - cargo-fuzz は nightly toolchain 必須 (rust-toolchain 不使用時も明示指定)
on:
push:
branches:
paths:
- 'src/**'
- 'fuzz/**'
- 'scripts/fuzz_targets.py'
- '.github/workflows/fuzz.yml'
- '.github/actions/**'
pull_request:
branches:
paths:
- 'src/**'
- 'fuzz/**'
- 'scripts/fuzz_targets.py'
- '.github/workflows/fuzz.yml'
- '.github/actions/**'
schedule:
# 毎日 03:00 UTC = 12:00 JST (idle 時間帯)
- cron: '0 3 * * *'
workflow_dispatch:
inputs:
duration_seconds:
description: 'Per-target fuzz duration (seconds)'
required: false
default: '60'
type: string
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
CARGO_TERM_COLOR: always
jobs:
# the targets to run, from fuzz/Cargo.toml: the core set on push / PR, every
# [[bin]] on the nightly schedule and on a manual run
targets:
name: Fuzz targets
runs-on: ubuntu-latest
outputs:
list: ${{ steps.list.outputs.list }}
steps:
- uses: actions/checkout@v5
- name: List the fuzz targets
id: list
run: |
python3 scripts/test_fuzz_targets.py
list=$(python3 scripts/fuzz_targets.py --matrix "${{ github.event_name }}")
echo "list=$list" >> "$GITHUB_OUTPUT"
echo "targets: $list"
# every target compiles on every push and PR, including those only run nightly
build-all:
name: Fuzz — build every target
if: github.event_name == 'push' || github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Install nightly toolchain
uses: dtolnay/rust-toolchain@nightly
- uses: Swatinem/rust-cache@v2
with:
workspaces: fuzz
- name: Build every [[bin]] of fuzz/Cargo.toml
run: |
cd fuzz
cargo +nightly build --bins
fuzz:
name: Fuzz — ${{ matrix.target }}
needs: targets
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
target: ${{ fromJSON(needs.targets.outputs.list) }}
steps:
- uses: actions/checkout@v5
# cargo-fuzz は nightly toolchain 必須
- name: Install nightly toolchain
uses: dtolnay/rust-toolchain@nightly
- uses: Swatinem/rust-cache@v2
with:
workspaces: fuzz
- name: Install cargo-fuzz
run: cargo install cargo-fuzz --locked
# build は blocking: compile error を continue-on-error で隠さない
# (2026-09-15 まで job-level continue-on-error だったため
# fuzz_deterministic_roundtrip の E0639 が 2 日間 green 表示で silent だった)
- name: Build fuzz target
run: |
cd fuzz
cargo +nightly fuzz build "${{ matrix.target }}"
- name: Set fuzz duration
id: dur
run: |
DURATION="${{ github.event.inputs.duration_seconds }}"
if [ -z "$DURATION" ]; then
DURATION=60
fi
echo "seconds=$DURATION" >> "$GITHUB_OUTPUT"
# a crash is a reproducible defect: the job fails, and the input that
# crashed is kept as an artifact for triage
- name: Run fuzz target (time-boxed)
id: run
run: |
cd fuzz
cargo +nightly fuzz run "${{ matrix.target }}" -- \
-max_total_time=${{ steps.dur.outputs.seconds }}
- name: Upload crash artifacts (if any)
if: failure() && steps.run.outcome == 'failure'
uses: actions/upload-artifact@v6
with:
name: fuzz-crash-${{ matrix.target }}
path: fuzz/artifacts/${{ matrix.target }}
if-no-files-found: ignore
retention-days: 14
- name: Report crash
if: failure() && steps.run.outcome == 'failure'
run: echo "::error::fuzz target ${{ matrix.target }} found a crash — see the fuzz-crash-${{ matrix.target }} artifact"