zipcheck 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. zipcheck-0.1.0/.dockerignore +25 -0
  2. zipcheck-0.1.0/CHANGELOG.md +75 -0
  3. zipcheck-0.1.0/CONTRIBUTING.md +107 -0
  4. zipcheck-0.1.0/Dockerfile +26 -0
  5. zipcheck-0.1.0/LICENSE +21 -0
  6. zipcheck-0.1.0/MANIFEST.in +10 -0
  7. zipcheck-0.1.0/PKG-INFO +676 -0
  8. zipcheck-0.1.0/README.md +635 -0
  9. zipcheck-0.1.0/SECURITY.md +55 -0
  10. zipcheck-0.1.0/docs/metadata-map.md +299 -0
  11. zipcheck-0.1.0/docs/production.md +237 -0
  12. zipcheck-0.1.0/fuzz/fuzz_scan.py +51 -0
  13. zipcheck-0.1.0/fuzz/generate_seeds.py +172 -0
  14. zipcheck-0.1.0/packaging/aur/.SRCINFO +18 -0
  15. zipcheck-0.1.0/packaging/aur/PKGBUILD +29 -0
  16. zipcheck-0.1.0/packaging/aur/refresh.sh +6 -0
  17. zipcheck-0.1.0/pyproject.toml +103 -0
  18. zipcheck-0.1.0/setup.cfg +4 -0
  19. zipcheck-0.1.0/src/zipcheck/__init__.py +21 -0
  20. zipcheck-0.1.0/src/zipcheck/__main__.py +4 -0
  21. zipcheck-0.1.0/src/zipcheck/cli.py +333 -0
  22. zipcheck-0.1.0/src/zipcheck/detect.py +138 -0
  23. zipcheck-0.1.0/src/zipcheck/engine.py +968 -0
  24. zipcheck-0.1.0/src/zipcheck/formats/__init__.py +1 -0
  25. zipcheck-0.1.0/src/zipcheck/formats/bzip2fmt.py +95 -0
  26. zipcheck-0.1.0/src/zipcheck/formats/gzipfmt.py +143 -0
  27. zipcheck-0.1.0/src/zipcheck/formats/probe.py +62 -0
  28. zipcheck-0.1.0/src/zipcheck/formats/rarfmt.py +280 -0
  29. zipcheck-0.1.0/src/zipcheck/formats/sevenzipfmt.py +382 -0
  30. zipcheck-0.1.0/src/zipcheck/formats/tarfmt.py +271 -0
  31. zipcheck-0.1.0/src/zipcheck/formats/xzfmt.py +170 -0
  32. zipcheck-0.1.0/src/zipcheck/formats/zipfmt.py +1034 -0
  33. zipcheck-0.1.0/src/zipcheck/formats/zstdfmt.py +80 -0
  34. zipcheck-0.1.0/src/zipcheck/limits.py +62 -0
  35. zipcheck-0.1.0/src/zipcheck/model.py +216 -0
  36. zipcheck-0.1.0/src/zipcheck/py.typed +0 -0
  37. zipcheck-0.1.0/src/zipcheck/reader.py +169 -0
  38. zipcheck-0.1.0/src/zipcheck/verify.py +816 -0
  39. zipcheck-0.1.0/src/zipcheck.egg-info/PKG-INFO +676 -0
  40. zipcheck-0.1.0/src/zipcheck.egg-info/SOURCES.txt +54 -0
  41. zipcheck-0.1.0/src/zipcheck.egg-info/dependency_links.txt +1 -0
  42. zipcheck-0.1.0/src/zipcheck.egg-info/entry_points.txt +2 -0
  43. zipcheck-0.1.0/src/zipcheck.egg-info/requires.txt +12 -0
  44. zipcheck-0.1.0/src/zipcheck.egg-info/top_level.txt +1 -0
  45. zipcheck-0.1.0/tests/__init__.py +0 -0
  46. zipcheck-0.1.0/tests/conftest.py +8 -0
  47. zipcheck-0.1.0/tests/helpers.py +463 -0
  48. zipcheck-0.1.0/tests/test_cli.py +199 -0
  49. zipcheck-0.1.0/tests/test_other_formats.py +86 -0
  50. zipcheck-0.1.0/tests/test_property.py +84 -0
  51. zipcheck-0.1.0/tests/test_robustness.py +53 -0
  52. zipcheck-0.1.0/tests/test_tar.py +64 -0
  53. zipcheck-0.1.0/tests/test_verify.py +219 -0
  54. zipcheck-0.1.0/tests/test_zip.py +194 -0
  55. zipcheck-0.1.0/tools/benchmark.py +46 -0
  56. zipcheck-0.1.0/tools/generate_samples.py +235 -0
@@ -0,0 +1,25 @@
1
+ .git/
2
+ .github/
3
+ .venv/
4
+ .smoke/
5
+ .uv-cache/
6
+ .uv-python/
7
+ .hypothesis/
8
+ .mypy_cache/
9
+ .pytest_cache/
10
+ .ruff_cache/
11
+ .linTools/
12
+ build/
13
+ dist/
14
+ htmlcov/
15
+ **/__pycache__/
16
+ **/*.egg-info/
17
+ .coverage
18
+ *.sarif
19
+ docs/
20
+ fuzz/
21
+ packaging/
22
+ tests/
23
+ tools/
24
+ pytest-of-*
25
+ tmp*/
@@ -0,0 +1,75 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here.
4
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
5
+ and this project uses [Semantic Versioning](https://semver.org/).
6
+
7
+ ## [0.1.0] - 2026-10-24
8
+
9
+ First public release.
10
+
11
+ ### Added
12
+
13
+ - Static metadata scanners for ZIP/ZIP64, TAR (including GNU/PAX sparse),
14
+ gzip, bzip2, xz/LZMA, Zstandard, 7-Zip and RAR 4/5.
15
+ - Expansion-ratio and absolute-size policy with `clean` / `suspicious` /
16
+ `dangerous` / `unknown` verdicts.
17
+ - Detection of impossible DEFLATE ratios, stored-size mismatches, overlapping
18
+ entries, shared local headers and inconsistent totals.
19
+ - Bounded nested-archive inspection (ZIP, TAR, gzip, bzip2, xz) with depth,
20
+ archive-count, byte and time budgets.
21
+ - Bounded in-memory decompression probe for formats without declared sizes.
22
+ - Bounded content verification (`--verify`, `--verify-limit`,
23
+ `--require-verified`) that decompresses supported content into an in-memory
24
+ counting sink, never to disk.
25
+ - `--production` fail-closed preset for user-upload pipelines; it implies
26
+ `--verify --require-verified`.
27
+ - Recursive verification of nested archives: images up to 8 MiB are captured
28
+ and scanned with a shared 256 MiB nested-output budget.
29
+ - New integrity findings: `HEADER_MISMATCH`, `ENTRY_COUNT_MISMATCH`,
30
+ `UNDERSTATED_COMPRESSED_SIZE`, `OVERSTATED_COMPRESSED_SIZE`,
31
+ `VERIFICATION_FAILED` and `UNVERIFIED`.
32
+ - `nested_unverified` in JSON output, propagated from child scans to the parent.
33
+ - CLI with human and JSON output, directory recursion, configurable fail
34
+ thresholds and documented exit codes.
35
+ - PEP 517/621 packaging with a typed-package marker, wheel/sdist smoke tests,
36
+ and PyPI trusted publishing through GitHub OIDC.
37
+ - CI across Linux, macOS and Windows on Python 3.10-3.14, with branch coverage,
38
+ ruff and mypy gates.
39
+ - Hypothesis property tests and a coverage-guided Atheris fuzz harness with a
40
+ seed corpus and a weekly fuzz workflow.
41
+ - Arch Linux AUR packaging under `packaging/aur`.
42
+ - Safe test corpus generators, sandbox benchmark tool, Dockerfile, and
43
+ documentation of where each format stores its uncompressed size and why a
44
+ magic "bomb signature" does not exist.
45
+
46
+ ### Fixed
47
+
48
+ - The ZIP parser now parses the central directory to its declared end instead of
49
+ stopping at the attacker-controlled EOCD entry count, exposing hidden entries.
50
+ - Local headers are cross-checked against central-directory metadata, so tools
51
+ cannot be played against each other with contradictory sizes or methods.
52
+ - Verification detects compressed streams that continue past their declared
53
+ `csize`, catching forged one-byte members.
54
+ - xz content verification drained the decoder's buffered output correctly;
55
+ highly compressible streams were previously under-measured and reported as
56
+ `METADATA_OVERSTATED` instead of being fully verified.
57
+ - Verification failures and unverifiable nested content now fail closed
58
+ (`suspicious`, or `unknown` under `--require-verified`) instead of reporting
59
+ `clean`.
60
+ - Nested gzip inspection now follows concatenated members instead of stopping at
61
+ the first one, so an archive split across members is still inspected.
62
+ - Nested xz and bzip2 prefix capture now drains the decoders' buffered output,
63
+ so a highly compressible inner archive is captured completely.
64
+ - ZIP LZMA members are now decoded for nested-archive sniffing (bounded), not
65
+ skipped silently.
66
+ - Hitting the central-directory parse limit is reported as truncation
67
+ (`MEDIUM`) instead of being misclassified as hidden entries (`HIGH`).
68
+ - A malformed-header unpack in the nested ZIP prefix parser shifted `csize` and
69
+ `usize` by two bytes; fixed.
70
+ - `scan_file` now opens the file before `fstat`ing the same descriptor,
71
+ removing a stat-then-open race.
72
+ - Human-readable output now groups repeated nested siblings correctly instead of
73
+ printing each one at the same indentation.
74
+
75
+ [0.1.0]: https://github.com/spaxe-dev/zipcheck/releases/tag/v0.1.0
@@ -0,0 +1,107 @@
1
+ # Contributing
2
+
3
+ Thanks for helping make archive handling less exciting.
4
+
5
+ ## Setup
6
+
7
+ ```bash
8
+ git clone <this repository>
9
+ cd zipcheck
10
+ python -m pip install -e ".[dev]"
11
+ python -m pytest
12
+ ruff check src tests tools
13
+ mypy src/zipcheck
14
+ ```
15
+
16
+ Python 3.10+ is required. Runtime code must stay dependency-free; if a feature
17
+ ever needs a third-party package, put it in an optional extra and make the
18
+ feature degrade gracefully when that extra is not installed.
19
+
20
+ ## Ground rules
21
+
22
+ 1. **Never extract member data.** Parsers may read metadata, and may decompress
23
+ a *bounded* prefix into memory for nested-archive inspection. They must
24
+ never write extracted content to disk, emit temp files, or call external
25
+ archive tools.
26
+ 2. **Never allocate from a declared size.** A header claiming 10 TiB must not
27
+ cause a 10 TiB allocation. Read in fixed-size chunks and stop at a cap.
28
+ 3. **Fail closed.** If metadata cannot be read reliably, the result must be
29
+ `unknown` — not `clean`.
30
+ 4. **No exceptions escape `scan_file`.** Malformed input is normal input.
31
+ 5. **Add a test for every parser change.** Prefer a metadata-only fixture (a
32
+ few dozen bytes) over a real bomb.
33
+ 6. **Keep the output stable.** JSON field names are part of the public API.
34
+
35
+ ## Adding a format
36
+
37
+ 1. Add magic/extension routing in `detect.py`.
38
+ 2. Add a parser module under `src/zipcheck/formats/` exposing
39
+ `scan(fp, size, limits, deadline) -> Facts`.
40
+ 3. Read sizes from headers or indexes. If the format has no size field, use
41
+ `formats/probe.py` with a bounded output and explain the limitation in the
42
+ module docstring.
43
+ 4. Register it in `engine.PARSERS` and decide whether nested inspection is
44
+ feasible.
45
+ 5. Add tests: a clean sample, a declared-huge sample, and a malformed sample.
46
+ 6. Document where the size lives in `docs/metadata-map.md` and add the format to
47
+ the README table.
48
+
49
+ ## Adding a detection rule
50
+
51
+ - Emit a `Finding` with a stable `code`, a severity, and a human explanation.
52
+ - Policy thresholds belong in `Limits`, not hard-coded in a parser.
53
+ - Keep false positives explainable: "this is a large expansion", not "this is
54
+ malware".
55
+ - Update the rules table in `README.md`.
56
+
57
+ ## Test fixtures
58
+
59
+ Use `tests/helpers.py` to build archives. Tests must not contain or download
60
+ live bombs. If a real archive is essential to reproduce a bug, minimise it to a
61
+ metadata-only file first.
62
+
63
+ For integration testing against real bombs, use `tools/generate_samples.py`
64
+ inside a disposable VM/container. The generated files are small on disk but
65
+ enormous when extracted.
66
+
67
+ ## Fuzzing
68
+
69
+ Hypothesis property tests run with the normal suite. The coverage-guided
70
+ Atheris harness is Linux-only:
71
+
72
+ ```bash
73
+ python -m pip install -e .[fuzz]
74
+ python fuzz/generate_seeds.py fuzz/corpus
75
+ python fuzz/fuzz_scan.py fuzz/corpus -max_total_time=120
76
+ ```
77
+
78
+ The weekly `fuzz` workflow runs the same harness and uploads crashing inputs.
79
+
80
+ ## Releasing
81
+
82
+ 1. Bump `__version__` in `src/zipcheck/__init__.py`; the package version is read
83
+ from that attribute. Add a `CHANGELOG.md` entry.
84
+ 2. Run the full gate: `pytest`, `mypy src/zipcheck`, `ruff check src tests tools`,
85
+ `python -m build` and `twine check dist/*`.
86
+ 3. Commit, then tag and push `vX.Y.Z`. `.github/workflows/release.yml` builds and
87
+ smoke-tests the sdist/wheel, publishes to PyPI through OIDC trusted
88
+ publishing, and creates a GitHub release.
89
+ 4. One-time setup: register a trusted publisher on PyPI for owner `spaxe-dev`,
90
+ repository `zipcheck`, workflow `release.yml`, environment `pypi`; create the
91
+ same `pypi` environment in the GitHub repository.
92
+ 5. For AUR, wait for the GitHub release, update `pkgver` and checksums in
93
+ `packaging/aur/PKGBUILD`, then run `updpkgsums` and
94
+ `makepkg --printsrcinfo > .SRCINFO` before pushing to the AUR repository.
95
+
96
+ ## Style
97
+
98
+ - `ruff check src tests tools` must pass.
99
+ - `mypy src/zipcheck` must pass.
100
+ - Line length 100.
101
+ - Type hints on public functions.
102
+ - Comments explain *why*, not *what*.
103
+
104
+ ## Security
105
+
106
+ See [SECURITY.md](SECURITY.md) for how to report parser vulnerabilities
107
+ privately.
@@ -0,0 +1,26 @@
1
+ # Small, non-root image for scanning untrusted archives.
2
+ #
3
+ # docker build -t zipcheck .
4
+ # docker run --rm -v "$PWD:/data:ro" zipcheck /data/file.zip
5
+ #
6
+ # The container only needs the archive mounted read-only. zipcheck never writes
7
+ # extracted data, so the filesystem can be read-only as well:
8
+ #
9
+ # docker run --rm --read-only -v "$PWD:/data:ro" zipcheck /data/file.zip
10
+
11
+ FROM python:3.12-slim
12
+
13
+ ENV PYTHONDONTWRITEBYTECODE=1 \
14
+ PYTHONUNBUFFERED=1
15
+
16
+ WORKDIR /app
17
+
18
+ COPY pyproject.toml README.md LICENSE /app/
19
+ COPY src /app/src
20
+
21
+ RUN pip install --no-cache-dir .
22
+
23
+ RUN useradd --create-home --shell /usr/sbin/nologin scanner
24
+ USER scanner
25
+
26
+ ENTRYPOINT ["zipcheck"]
zipcheck-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 zipcheck contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,10 @@
1
+ include CHANGELOG.md
2
+ include CONTRIBUTING.md
3
+ include Dockerfile
4
+ include SECURITY.md
5
+ include .dockerignore
6
+ recursive-include docs *.md
7
+ recursive-include fuzz *.py
8
+ recursive-include packaging *
9
+ recursive-include tests *.py
10
+ recursive-include tools *.py