Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
Run 'python3-libraries' fuzzer in CI using CIFuzz
  • Loading branch information
sethmlarson committed Jan 12, 2026
commit 2623d6047a21089896b6662d611bb4e1b83c54b1
40 changes: 40 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -676,6 +676,45 @@ jobs:
sarif_file: cifuzz-sarif/results.sarif
checkout_path: cifuzz-sarif

cifuzz-libraries:
Comment thread
sethmlarson marked this conversation as resolved.
Outdated
name: CIFuzz-libraries
runs-on: ubuntu-latest
timeout-minutes: 60
Comment thread
sethmlarson marked this conversation as resolved.
Outdated
needs: build-context
if: needs.build-context.outputs.run-ci-fuzz-libraries == 'true'
permissions:
security-events: write
strategy:
fail-fast: false
matrix:
sanitizer: [address, undefined, memory]
steps:
- name: Build fuzzers (${{ matrix.sanitizer }})
id: build
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
with:
oss-fuzz-project-name: python3-libraries
sanitizer: ${{ matrix.sanitizer }}
- name: Run fuzzers (${{ matrix.sanitizer }})
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
with:
fuzz-seconds: 600
oss-fuzz-project-name: python3-libraries
output-sarif: true
sanitizer: ${{ matrix.sanitizer }}
- name: Upload crash
if: failure() && steps.build.outcome == 'success'
uses: actions/upload-artifact@v4
Comment thread
sethmlarson marked this conversation as resolved.
Outdated
with:
name: ${{ matrix.sanitizer }}-artifacts
path: ./out/artifacts
- name: Upload SARIF
if: always() && steps.build.outcome == 'success'
uses: github/codeql-action/upload-sarif@v3
Comment thread
sethmlarson marked this conversation as resolved.
Outdated
with:
sarif_file: cifuzz-sarif/results.sarif
checkout_path: cifuzz-sarif

all-required-green: # This job does nothing and is only used for the branch protection
name: All required checks pass
runs-on: ubuntu-latest
Expand All @@ -698,6 +737,7 @@ jobs:
- build-san
- cross-build-linux
- cifuzz
- cifuzz-libraries
if: always()

steps:
Expand Down
Comment thread
sethmlarson marked this conversation as resolved.
Outdated
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Run the 'python3-libraries' fuzzer using CIFuzz. Automatically detect when
modules are changed.
66 changes: 65 additions & 1 deletion Tools/build/compute-changes.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,57 @@
MACOS_DIRS = frozenset({"Mac"})
WASI_DIRS = frozenset({Path("Tools", "wasm")})

LIBRARY_FUZZER_PATHS = frozenset({
# All C/CPP fuzzers.
Path("configure"),
# ast
Path("Lib/ast.py"),
Path("Python/ast.c"),
# configparser
Path("Lib/configparser.py"),
# csv
Path("Lib/csv.py"),
Path("Modules/_csv.c"),
# decode
Path("Lib/encodings/"),
Path("Modules/_codecsmodule.c"),
Path("Modules/cjkcodecs/"),
Path("Modules/unicodedata*"),
# difflib
Path("Lib/difflib.py"),
# email
Path("Lib/email/"),
# html
Path("Lib/html/"),
Path("Lib/_markupbase.py"),
# http.client
Path("Lib/http/client.py"),
# json
Path("Lib/json/"),
Path("Modules/_json.c"),
# plist
Path("Lib/plistlib.py"),
# re
Path("Lib/re/"),
Path("Modules/_sre/"),
# tarfile
Path("Lib/tarfile.py"),
# tomllib
Path("Modules/tomllib/"),
# xml
Path("Lib/xml/"),
Comment thread
sethmlarson marked this conversation as resolved.
Path("Lib/_markupbase.py"),
Path("Modules/expat/"),
# zipfile
Path("Lib/zipfile/"),
})


@dataclass(kw_only=True, slots=True)
class Outputs:
run_android: bool = False
run_ci_fuzz: bool = False
run_ci_fuzz_libraries: bool = False
run_docs: bool = False
run_ios: bool = False
run_macos: bool = False
Expand Down Expand Up @@ -94,6 +140,11 @@ def compute_changes() -> None:
else:
print("Branch too old for CIFuzz tests; or no C files were changed")

if outputs.run_ci_fuzz_libraries:
print("Run CIFuzz tests for libraries")
else:
print("Branch too old for CIFuzz tests; or no library files were changed")
Comment thread
sethmlarson marked this conversation as resolved.
Outdated

if outputs.run_docs:
print("Build documentation")

Expand Down Expand Up @@ -144,9 +195,18 @@ def get_file_platform(file: Path) -> str | None:
return None


def is_fuzzable_library_file(file: Path) -> bool:
return any(
(file.is_relative_to(needs_fuzz) and needs_fuzz.is_dir())
or (file == needs_fuzz and file.is_file())
for needs_fuzz in LIBRARY_FUZZER_PATHS
)


def process_changed_files(changed_files: Set[Path]) -> Outputs:
run_tests = False
run_ci_fuzz = False
run_ci_fuzz_libraries = False
run_docs = False
run_windows_tests = False
run_windows_msi = False
Expand All @@ -161,7 +221,7 @@ def process_changed_files(changed_files: Set[Path]) -> Outputs:

if file.parent == GITHUB_WORKFLOWS_PATH:
if file.name == "build.yml":
run_tests = run_ci_fuzz = True
run_tests = run_ci_fuzz = run_ci_fuzz_libraries = True
has_platform_specific_change = False
if file.name == "reusable-docs.yml":
run_docs = True
Expand Down Expand Up @@ -196,6 +256,8 @@ def process_changed_files(changed_files: Set[Path]) -> Outputs:
("Modules", "_xxtestfuzz"),
}:
run_ci_fuzz = True
if not run_ci_fuzz_libraries and is_fuzzable_library_file(file):
run_ci_fuzz_libraries = True

# Check for changed documentation-related files
if doc_file:
Expand Down Expand Up @@ -229,6 +291,7 @@ def process_changed_files(changed_files: Set[Path]) -> Outputs:
return Outputs(
run_android=run_android,
run_ci_fuzz=run_ci_fuzz,
run_ci_fuzz_libraries=run_ci_fuzz_libraries,
run_docs=run_docs,
run_ios=run_ios,
run_macos=run_macos,
Expand Down Expand Up @@ -265,6 +328,7 @@ def write_github_output(outputs: Outputs) -> None:
with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as f:
f.write(f"run-android={bool_lower(outputs.run_android)}\n")
f.write(f"run-ci-fuzz={bool_lower(outputs.run_ci_fuzz)}\n")
f.write(f"run-ci-fuzz-libraries={bool_lower(outputs.run_ci_fuzz_libraries)}\n")
f.write(f"run-docs={bool_lower(outputs.run_docs)}\n")
f.write(f"run-ios={bool_lower(outputs.run_ios)}\n")
f.write(f"run-macos={bool_lower(outputs.run_macos)}\n")
Expand Down
Loading