Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions .github/workflows/fuzz.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: Fuzz

on:
pull_request:
branches: [main]
schedule:
- cron: "0 3 * * 1"

permissions: {}

jobs:
fuzz:
name: Fuzzing (Atheris)
runs-on: ubuntu-24.04
timeout-minutes: 10
permissions:
contents: read
steps:
- name: Harden runner
uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
with:
egress-policy: audit
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Setup Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.11"
- name: Install (épinglé par hash)
run: |
pip install --require-hashes -r requirements.txt
pip install --require-hashes -r requirements-fuzz.txt
- name: Run fuzzing (budget limité)
env:
PYTHONPATH: src
# -runs / -max_total_time bornent l'exécution en CI ; un crash (5xx) échoue.
run: python fuzz/fuzz_api.py -runs=20000 -max_total_time=120
3 changes: 3 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ pip-audit -r requirements.txt # vulnérabilités des dépendances
- Les **dépendances Python** passent par `requirements.in` puis
`pip-compile --generate-hashes`. On ne modifie jamais `requirements.txt` à la main.
- Aucun **secret en clair** dans le code ou les workflows.
- **Toute nouvelle fonctionnalité ou correction de bug est accompagnée d'un
test** qui échoue sans le changement et passe avec. Le harnais de fuzzing
(`fuzz/`) est exécuté en CI et complète les tests unitaires.

## Processus

Expand Down
8 changes: 5 additions & 3 deletions fuzz/fuzz_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@

import atheris

with atheris.instrument_imports():
from fastapi.testclient import TestClient
# On n'instrumente PAS les imports : pydantic-core est une extension compilée
# (Rust) avec un custom loader qui fait planter atheris.instrument_imports()
# (segfault). Le fuzzing reste valide sur la logique de routage/validation.
from fastapi.testclient import TestClient # noqa: E402

from app.main import app
from app.main import app # noqa: E402

client = TestClient(app)

Expand Down
2 changes: 2 additions & 0 deletions requirements-fuzz.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
atheris==2.3.0
httpx==0.28.1
43 changes: 43 additions & 0 deletions requirements-fuzz.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# This file was autogenerated by uv via the following command:
# uv pip compile --generate-hashes requirements-fuzz.in -o requirements-fuzz.txt
anyio==4.14.2 \
--hash=sha256:9f505dda5ac9f0c8309b5e8bd445a8c2bf7246f3ce950121e45ea15bc41d1494 \
--hash=sha256:cfa139f3ed1a23ee8f88a145ddb5ac7605b8bbfd8592baacd7ce3d8bb4313c7f
# via httpx
atheris==2.3.0 \
--hash=sha256:005bde4b5a70e998b7fa097e9aa195972dcc2e04092156a0149cff7aa0de970e \
--hash=sha256:6d4e83c8a518e7f7d1c82ee52453255bf6309b7b335657534e83747d4fdfa110 \
--hash=sha256:9877b6c2bd5386f9fbbb2989a939c717383d9639f5476411c06fe50fe2fe09a6 \
--hash=sha256:b91cb296d60915c3efa4f6db48f09c4678b574cddb7ca98035f1cb9d9fb96f64 \
--hash=sha256:c353952ee375bf851527e8b2ea57fdefd7ad16aadfe18143801998075485eccd \
--hash=sha256:cf1fdf5fa220a41a2f262b32363fc566549502b2cb0addf4e1baad5531c0e825 \
--hash=sha256:e4e43d1ee4760916a84ff73c9c6cf9ac6eee80fc030479bbed43fe0b8e994981
# via -r requirements-fuzz.in
certifi==2026.6.17 \
--hash=sha256:024c88eeec92ca068db80f02b8b07c9cef7b9fe261d1d535abfd5abd6f6af432 \
--hash=sha256:2227dcbaafe0d2f59279d1762ddddc37783ed4354594f194ffc31d20f41fc3db
# via
# httpcore
# httpx
h11==0.16.0 \
--hash=sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1 \
--hash=sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86
# via httpcore
httpcore==1.0.9 \
--hash=sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55 \
--hash=sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8
# via httpx
httpx==0.28.1 \
--hash=sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc \
--hash=sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad
# via -r requirements-fuzz.in
idna==3.18 \
--hash=sha256:7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2 \
--hash=sha256:ffb385a7e039654cef1ab9ef32c6fafe283c0c0467bba1d9029738ce4a14a848
# via
# anyio
# httpx
typing-extensions==4.16.0 \
--hash=sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8 \
--hash=sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5
# via anyio