fuzz_repo.py 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. import os
  2. import sys
  3. import tempfile
  4. import atheris
  5. with atheris.instrument_imports():
  6. # We instrument `test_utils` as well, so it doesn't block coverage analysis in Fuzz Introspector:
  7. from test_utils import EnhancedFuzzedDataProvider, is_expected_exception
  8. from dulwich.repo import (
  9. InvalidUserIdentity,
  10. Repo,
  11. )
  12. def TestOneInput(data):
  13. fdp = EnhancedFuzzedDataProvider(data)
  14. with tempfile.TemporaryDirectory() as temp_dir:
  15. repo = Repo.init(temp_dir)
  16. repo.set_description(fdp.ConsumeRandomBytes())
  17. repo.get_description()
  18. try:
  19. # Generate a minimal set of files based on fuzz data to minimize I/O operations.
  20. file_names = [
  21. f"File{i}{fdp.ConsumeRandomString(without_surrogates=True)}"
  22. for i in range(min(3, fdp.ConsumeIntInRange(1, 3)))
  23. ]
  24. for file in file_names:
  25. with open(os.path.join(temp_dir, file), "wb") as f:
  26. f.write(fdp.ConsumeRandomBytes())
  27. except (ValueError, OSError):
  28. # Exit early if the fuzzer generates an invalid filename.
  29. return -1
  30. try:
  31. repo.stage(file_names)
  32. repo.do_commit(
  33. message=fdp.ConsumeRandomBytes(),
  34. committer=fdp.ConsumeRandomBytes(),
  35. author=fdp.ConsumeRandomBytes(),
  36. commit_timestamp=fdp.ConsumeRandomInt(),
  37. commit_timezone=fdp.ConsumeRandomInt(),
  38. author_timestamp=fdp.ConsumeRandomInt(),
  39. author_timezone=fdp.ConsumeRandomInt(),
  40. )
  41. except InvalidUserIdentity:
  42. return -1
  43. except ValueError as e:
  44. if is_expected_exception(["Unable to handle non-minute offset"], e):
  45. return -1
  46. else:
  47. raise e
  48. def main():
  49. atheris.Setup(sys.argv, TestOneInput)
  50. atheris.Fuzz()
  51. if __name__ == "__main__":
  52. main()