safe-unzip 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.
- safe_unzip-0.1.0/.github/workflows/ci.yml +114 -0
- safe_unzip-0.1.0/.github/workflows/release.yml +146 -0
- safe_unzip-0.1.0/.gitignore +19 -0
- safe_unzip-0.1.0/CHANGELOG.md +44 -0
- safe_unzip-0.1.0/Cargo.lock +901 -0
- safe_unzip-0.1.0/Cargo.toml +21 -0
- safe_unzip-0.1.0/PKG-INFO +22 -0
- safe_unzip-0.1.0/README.md +351 -0
- safe_unzip-0.1.0/pyproject.toml +40 -0
- safe_unzip-0.1.0/python/Cargo.toml +16 -0
- safe_unzip-0.1.0/python/python/safe_unzip/__init__.py +53 -0
- safe_unzip-0.1.0/python/python/safe_unzip/__init__.pyi +101 -0
- safe_unzip-0.1.0/python/python/safe_unzip/py.typed +0 -0
- safe_unzip-0.1.0/python/safe_unzip/__init__.py +53 -0
- safe_unzip-0.1.0/python/safe_unzip/__init__.pyi +101 -0
- safe_unzip-0.1.0/python/safe_unzip/py.typed +0 -0
- safe_unzip-0.1.0/python/src/lib.rs +293 -0
- safe_unzip-0.1.0/python/tests/__init__.py +2 -0
- safe_unzip-0.1.0/python/tests/test_safe_unzip.py +310 -0
- safe_unzip-0.1.0/safe_unzip_spec.md +685 -0
- safe_unzip-0.1.0/src/error.rs +177 -0
- safe_unzip-0.1.0/src/extractor.rs +631 -0
- safe_unzip-0.1.0/src/lib.rs +73 -0
- safe_unzip-0.1.0/src/limits.rs +25 -0
- safe_unzip-0.1.0/tests/security_test.rs +792 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [master, main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [master, main]
|
|
8
|
+
|
|
9
|
+
env:
|
|
10
|
+
CARGO_TERM_COLOR: always
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
test:
|
|
14
|
+
name: Test (${{ matrix.os }})
|
|
15
|
+
runs-on: ${{ matrix.os }}
|
|
16
|
+
strategy:
|
|
17
|
+
fail-fast: false
|
|
18
|
+
matrix:
|
|
19
|
+
os:
|
|
20
|
+
- ubuntu-latest # Linux x86_64
|
|
21
|
+
- macos-latest # macOS arm64 (Apple Silicon)
|
|
22
|
+
- windows-latest # Windows x86_64
|
|
23
|
+
|
|
24
|
+
steps:
|
|
25
|
+
- uses: actions/checkout@v4
|
|
26
|
+
|
|
27
|
+
- name: Install Rust
|
|
28
|
+
uses: dtolnay/rust-toolchain@stable
|
|
29
|
+
|
|
30
|
+
- name: Run tests
|
|
31
|
+
run: cargo test --verbose
|
|
32
|
+
|
|
33
|
+
clippy:
|
|
34
|
+
name: Clippy
|
|
35
|
+
runs-on: ubuntu-latest
|
|
36
|
+
steps:
|
|
37
|
+
- uses: actions/checkout@v4
|
|
38
|
+
|
|
39
|
+
- name: Install Rust
|
|
40
|
+
uses: dtolnay/rust-toolchain@stable
|
|
41
|
+
with:
|
|
42
|
+
components: clippy
|
|
43
|
+
|
|
44
|
+
- name: Run Clippy
|
|
45
|
+
run: cargo clippy --all-targets -- -D warnings
|
|
46
|
+
|
|
47
|
+
fmt:
|
|
48
|
+
name: Format
|
|
49
|
+
runs-on: ubuntu-latest
|
|
50
|
+
steps:
|
|
51
|
+
- uses: actions/checkout@v4
|
|
52
|
+
|
|
53
|
+
- name: Install Rust
|
|
54
|
+
uses: dtolnay/rust-toolchain@stable
|
|
55
|
+
with:
|
|
56
|
+
components: rustfmt
|
|
57
|
+
|
|
58
|
+
- name: Check formatting
|
|
59
|
+
run: cargo fmt --all -- --check
|
|
60
|
+
|
|
61
|
+
audit:
|
|
62
|
+
name: Security Audit
|
|
63
|
+
runs-on: ubuntu-latest
|
|
64
|
+
steps:
|
|
65
|
+
- uses: actions/checkout@v4
|
|
66
|
+
|
|
67
|
+
- name: Install cargo-audit
|
|
68
|
+
run: cargo install cargo-audit
|
|
69
|
+
|
|
70
|
+
- name: Run audit
|
|
71
|
+
run: cargo audit
|
|
72
|
+
|
|
73
|
+
# Python bindings build and test
|
|
74
|
+
python:
|
|
75
|
+
name: Python Bindings (${{ matrix.os }}, py${{ matrix.python-version }})
|
|
76
|
+
runs-on: ${{ matrix.os }}
|
|
77
|
+
strategy:
|
|
78
|
+
fail-fast: false
|
|
79
|
+
matrix:
|
|
80
|
+
os:
|
|
81
|
+
- ubuntu-latest # Linux x86_64
|
|
82
|
+
- macos-latest # macOS arm64 (Apple Silicon)
|
|
83
|
+
- windows-latest # Windows x86_64
|
|
84
|
+
python-version: ['3.9', '3.x'] # min supported + latest (3.14)
|
|
85
|
+
|
|
86
|
+
steps:
|
|
87
|
+
- uses: actions/checkout@v4
|
|
88
|
+
|
|
89
|
+
- name: Install Rust
|
|
90
|
+
uses: dtolnay/rust-toolchain@stable
|
|
91
|
+
|
|
92
|
+
- name: Set up Python
|
|
93
|
+
uses: actions/setup-python@v5
|
|
94
|
+
with:
|
|
95
|
+
python-version: ${{ matrix.python-version }}
|
|
96
|
+
|
|
97
|
+
- name: Install dependencies
|
|
98
|
+
run: pip install maturin pytest
|
|
99
|
+
|
|
100
|
+
- name: Build Python wheel
|
|
101
|
+
env:
|
|
102
|
+
PYO3_USE_ABI3_FORWARD_COMPATIBILITY: 1
|
|
103
|
+
shell: bash
|
|
104
|
+
run: |
|
|
105
|
+
cp README.md python/README.md
|
|
106
|
+
cd python && maturin build --release
|
|
107
|
+
|
|
108
|
+
- name: Install Python bindings
|
|
109
|
+
shell: bash
|
|
110
|
+
run: pip install target/wheels/*.whl
|
|
111
|
+
|
|
112
|
+
- name: Run Python tests
|
|
113
|
+
run: cd python && pytest tests/ -v
|
|
114
|
+
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- 'v*'
|
|
7
|
+
|
|
8
|
+
env:
|
|
9
|
+
CARGO_TERM_COLOR: always
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
# Publish to crates.io
|
|
13
|
+
crates-io:
|
|
14
|
+
name: Publish to crates.io
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
continue-on-error: true # Don't fail if already published
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
|
|
20
|
+
- name: Install Rust
|
|
21
|
+
uses: dtolnay/rust-toolchain@stable
|
|
22
|
+
|
|
23
|
+
- name: Publish to crates.io
|
|
24
|
+
env:
|
|
25
|
+
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
|
|
26
|
+
run: cargo publish --no-verify
|
|
27
|
+
|
|
28
|
+
# Build Python wheels for all platforms
|
|
29
|
+
build-wheels:
|
|
30
|
+
name: Build wheels (${{ matrix.os }})
|
|
31
|
+
runs-on: ${{ matrix.os }}
|
|
32
|
+
strategy:
|
|
33
|
+
fail-fast: false
|
|
34
|
+
matrix:
|
|
35
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
36
|
+
|
|
37
|
+
steps:
|
|
38
|
+
- uses: actions/checkout@v4
|
|
39
|
+
|
|
40
|
+
- name: Install Rust
|
|
41
|
+
uses: dtolnay/rust-toolchain@stable
|
|
42
|
+
|
|
43
|
+
- name: Set up Python
|
|
44
|
+
uses: actions/setup-python@v5
|
|
45
|
+
with:
|
|
46
|
+
python-version: '3.11'
|
|
47
|
+
|
|
48
|
+
- name: Install maturin
|
|
49
|
+
run: pip install maturin
|
|
50
|
+
|
|
51
|
+
- name: Build wheels
|
|
52
|
+
env:
|
|
53
|
+
PYO3_USE_ABI3_FORWARD_COMPATIBILITY: 1
|
|
54
|
+
shell: bash
|
|
55
|
+
run: |
|
|
56
|
+
cp README.md python/README.md
|
|
57
|
+
cd python && maturin build --release --strip
|
|
58
|
+
|
|
59
|
+
- name: Upload wheels
|
|
60
|
+
uses: actions/upload-artifact@v4
|
|
61
|
+
with:
|
|
62
|
+
name: wheels-${{ matrix.os }}
|
|
63
|
+
path: target/wheels/*.whl
|
|
64
|
+
|
|
65
|
+
# Build source distribution
|
|
66
|
+
build-sdist:
|
|
67
|
+
name: Build source distribution
|
|
68
|
+
runs-on: ubuntu-latest
|
|
69
|
+
steps:
|
|
70
|
+
- uses: actions/checkout@v4
|
|
71
|
+
|
|
72
|
+
- name: Set up Python
|
|
73
|
+
uses: actions/setup-python@v5
|
|
74
|
+
with:
|
|
75
|
+
python-version: '3.11'
|
|
76
|
+
|
|
77
|
+
- name: Install maturin
|
|
78
|
+
run: pip install maturin
|
|
79
|
+
|
|
80
|
+
- name: Build sdist
|
|
81
|
+
run: cd python && maturin sdist
|
|
82
|
+
|
|
83
|
+
- name: Upload sdist
|
|
84
|
+
uses: actions/upload-artifact@v4
|
|
85
|
+
with:
|
|
86
|
+
name: sdist
|
|
87
|
+
path: target/wheels/*.tar.gz
|
|
88
|
+
|
|
89
|
+
# Publish to PyPI
|
|
90
|
+
pypi:
|
|
91
|
+
name: Publish to PyPI
|
|
92
|
+
needs: [build-wheels, build-sdist]
|
|
93
|
+
runs-on: ubuntu-latest
|
|
94
|
+
|
|
95
|
+
steps:
|
|
96
|
+
- name: Download wheels
|
|
97
|
+
uses: actions/download-artifact@v4
|
|
98
|
+
with:
|
|
99
|
+
pattern: wheels-*
|
|
100
|
+
path: dist
|
|
101
|
+
merge-multiple: true
|
|
102
|
+
|
|
103
|
+
- name: Download sdist
|
|
104
|
+
uses: actions/download-artifact@v4
|
|
105
|
+
with:
|
|
106
|
+
name: sdist
|
|
107
|
+
path: dist
|
|
108
|
+
|
|
109
|
+
- name: Publish to PyPI
|
|
110
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
111
|
+
with:
|
|
112
|
+
password: ${{ secrets.PYPI_TOKEN }}
|
|
113
|
+
|
|
114
|
+
# Create GitHub Release
|
|
115
|
+
github-release:
|
|
116
|
+
name: Create GitHub Release
|
|
117
|
+
needs: [crates-io, pypi]
|
|
118
|
+
runs-on: ubuntu-latest
|
|
119
|
+
permissions:
|
|
120
|
+
contents: write
|
|
121
|
+
|
|
122
|
+
steps:
|
|
123
|
+
- uses: actions/checkout@v4
|
|
124
|
+
|
|
125
|
+
- name: Download wheels
|
|
126
|
+
uses: actions/download-artifact@v4
|
|
127
|
+
with:
|
|
128
|
+
pattern: wheels-*
|
|
129
|
+
path: dist
|
|
130
|
+
merge-multiple: true
|
|
131
|
+
|
|
132
|
+
- name: Extract changelog for this version
|
|
133
|
+
id: changelog
|
|
134
|
+
run: |
|
|
135
|
+
VERSION=${GITHUB_REF#refs/tags/v}
|
|
136
|
+
# Extract section for this version from CHANGELOG.md
|
|
137
|
+
awk "/## \[${VERSION}\]/,/## \[/" CHANGELOG.md | head -n -1 > release_notes.md
|
|
138
|
+
echo "Release notes:"
|
|
139
|
+
cat release_notes.md
|
|
140
|
+
|
|
141
|
+
- name: Create Release
|
|
142
|
+
uses: softprops/action-gh-release@v2
|
|
143
|
+
with:
|
|
144
|
+
files: dist/*.whl
|
|
145
|
+
body_path: release_notes.md
|
|
146
|
+
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## [0.1.0] - 2025-12-31
|
|
6
|
+
|
|
7
|
+
### Initial Release 🎉
|
|
8
|
+
|
|
9
|
+
**safe_unzip** is a secure zip extraction library that prevents common archive-based attacks.
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
- **Zip Slip Prevention**: Blocks path traversal attacks (`../../etc/passwd`)
|
|
14
|
+
- **Zip Bomb Protection**: Limits on total size, file count, single file size, and path depth
|
|
15
|
+
- **Symlink Safety**: Configurable policies (skip or error)
|
|
16
|
+
- **Secure Overwrite**: Removes symlinks before overwriting to prevent TOCTOU attacks
|
|
17
|
+
- **Filename Sanitization**: Rejects control characters, backslashes, Windows reserved names
|
|
18
|
+
- **Strict Size Enforcement**: Catches zip bombs that lie about declared size
|
|
19
|
+
- **Two Extraction Modes**:
|
|
20
|
+
- `Streaming` (default): Fast, may leave partial state on error
|
|
21
|
+
- `ValidateFirst`: Two-pass, atomic (all-or-nothing)
|
|
22
|
+
|
|
23
|
+
### Python Bindings
|
|
24
|
+
|
|
25
|
+
Full Python bindings with identical security guarantees:
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
from safe_unzip import Extractor
|
|
29
|
+
|
|
30
|
+
Extractor("/path/to/dest").extract_file("archive.zip")
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Platforms
|
|
34
|
+
|
|
35
|
+
- Linux (x86_64)
|
|
36
|
+
- macOS (arm64, x86_64)
|
|
37
|
+
- Windows (x86_64)
|
|
38
|
+
|
|
39
|
+
### Links
|
|
40
|
+
|
|
41
|
+
- [crates.io](https://crates.io/crates/safe_unzip)
|
|
42
|
+
- [PyPI](https://pypi.org/project/safe-unzip/)
|
|
43
|
+
- [Documentation](https://github.com/tenuo-ai/safe_unzip)
|
|
44
|
+
|