diff --git a/.coveragerc b/.coveragerc index 0f24d2f04..0d30ffb5c 100644 --- a/.coveragerc +++ b/.coveragerc @@ -2,4 +2,4 @@ [run] branch = True source = jsonschema -omit = */jsonschema/_reflect.py,*/jsonschema/__main__.py,*/jsonschema/benchmarks/* +omit = */jsonschema/_reflect.py,*/jsonschema/__main__.py,*/jsonschema/benchmarks/*,*/jsonschema/tests/fuzz_validate.py diff --git a/.github/workflows/fuzz.yml b/.github/workflows/fuzz.yml new file mode 100644 index 000000000..c2f69b9b2 --- /dev/null +++ b/.github/workflows/fuzz.yml @@ -0,0 +1,31 @@ +name: CIFuzz + +on: + pull_request: + branches: + - main + +jobs: + Fuzzing: + runs-on: ubuntu-latest + steps: + - name: Build Fuzzers + id: build + uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master + with: + oss-fuzz-project-name: 'jsonschema' + language: python + # Needed until google/oss-fuzz#4996 is merged + continue-on-error: true + - name: Run Fuzzers + if: steps.build.outcome == 'success' + uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master + with: + oss-fuzz-project-name: 'jsonschema' + fuzz-seconds: 30 + - name: Upload Crash + uses: actions/upload-artifact@v1 + if: failure() && steps.build.outcome == 'success' + with: + name: artifacts + path: ./out/artifacts diff --git a/jsonschema/tests/fuzz_validate.py b/jsonschema/tests/fuzz_validate.py new file mode 100644 index 000000000..52675d136 --- /dev/null +++ b/jsonschema/tests/fuzz_validate.py @@ -0,0 +1,47 @@ +""" +Fuzzing setup for OSS-Fuzz. + +See https://github.com/google/oss-fuzz/tree/master/projects/jsonschema for the +other half of the setup here. +""" +import sys + +from hypothesis import given, strategies + +import jsonschema + +PRIM = strategies.one_of( + strategies.booleans(), + strategies.integers(), + strategies.floats(allow_nan=False, allow_infinity=False), + strategies.text(), +) +DICT = strategies.recursive( + base=( + strategies.booleans() + | strategies.dictionaries(strategies.text(), PRIM), + ), + extend=lambda inner: strategies.dictionaries(strategies.text(), inner), +) + + +@given(obj1=DICT, obj2=DICT) +def test_schemas(obj1, obj2): + try: + jsonschema.validate(instance=obj1, schema=obj2) + except jsonschema.exceptions.ValidationError: + pass + except jsonschema.exceptions.SchemaError: + pass + + +def main(): + atheris.Setup(sys.argv, + test_schemas.hypothesis.fuzz_one_input, + enable_python_coverage=True) + atheris.Fuzz() + + +if __name__ == "__main__": + import atheris + main()