safeuploads 1.1.1__tar.gz → 1.1.2__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.
- {safeuploads-1.1.1 → safeuploads-1.1.2}/.github/workflows/audit-safeuploads.yml +1 -1
- {safeuploads-1.1.1 → safeuploads-1.1.2}/.github/workflows/conventional-commits.yml +7 -2
- {safeuploads-1.1.1 → safeuploads-1.1.2}/.github/workflows/docs.yml +2 -2
- {safeuploads-1.1.1 → safeuploads-1.1.2}/.github/workflows/fuzz.yml +1 -1
- {safeuploads-1.1.1 → safeuploads-1.1.2}/.github/workflows/lint-and-test.yml +3 -3
- {safeuploads-1.1.1 → safeuploads-1.1.2}/.github/workflows/publish-safeuploads.yml +7 -7
- safeuploads-1.1.2/.github/workflows/test-matrix-safeuploads.yml +104 -0
- safeuploads-1.1.2/CHANGELOG.md +114 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/PKG-INFO +2 -2
- {safeuploads-1.1.1 → safeuploads-1.1.2}/pyproject.toml +2 -2
- safeuploads-1.1.2/uv.lock +1308 -0
- safeuploads-1.1.1/CHANGELOG.md +0 -161
- safeuploads-1.1.1/uv.lock +0 -1120
- {safeuploads-1.1.1 → safeuploads-1.1.2}/.github/CODEOWNERS +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/.github/FUNDING.yml +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/.github/agents/se-gitops-ci-specialist.agent.md +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/.github/agents/se-security-reviewer.agent.md +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/.github/agents/test-implementor.agent.md +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/.github/agents/test-reviewer.agent.md +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/.github/copilot-instructions.md +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/.github/dependabot.yml +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/.github/instructions/agents.instructions.md +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/.github/instructions/github-actions-ci-cd-best-practices.instructions.md +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/.github/instructions/instructions.instructions.md +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/.github/instructions/prompt.instructions.md +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/.github/instructions/python.instructions.md +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/.github/instructions/security-and-owasp.instructions.md +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/.github/scripts/check_conventional_commits.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/.github/scripts/smoke_import.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/.github/workflows/mirror.yml +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/.gitignore +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/CODE_OF_CONDUCT.md +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/CONTRIBUTING.md +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/LICENSE.md +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/README.md +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/SECURITY.md +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/docs/api.md +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/docs/index.md +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/docs/rate-limiting.md +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/docs/security/architecture.md +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/docs/security/integration-checklist.md +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/docs/security/threat-model.md +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/examples/README.md +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/examples/fastapi_example.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/mkdocs.yml +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/safeuploads/__init__.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/safeuploads/audit.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/safeuploads/config.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/safeuploads/enums.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/safeuploads/exceptions.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/safeuploads/file_validator.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/safeuploads/inspectors/__init__.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/safeuploads/inspectors/base.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/safeuploads/inspectors/content_inspector.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/safeuploads/inspectors/gzip_inspector.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/safeuploads/inspectors/zip_inspector.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/safeuploads/protocols.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/safeuploads/py.typed +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/safeuploads/utils.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/safeuploads/validators/__init__.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/safeuploads/validators/base.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/safeuploads/validators/compression_validator.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/safeuploads/validators/extension_validator.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/safeuploads/validators/unicode_validator.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/safeuploads/validators/windows_validator.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/safeuploads/validators/xml_validator.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/tests/__init__.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/tests/conftest.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/tests/fuzz/__init__.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/tests/fuzz/test_fuzz_config.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/tests/fuzz/test_fuzz_filenames.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/tests/fuzz/test_fuzz_images.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/tests/fuzz/test_fuzz_zip.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/tests/inspectors/__init__.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/tests/inspectors/test_content_inspector.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/tests/inspectors/test_gzip_inspector.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/tests/inspectors/test_zip_inspector.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/tests/test_audit.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/tests/test_config.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/tests/test_config_validation.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/tests/test_enums.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/tests/test_exceptions.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/tests/test_fastapi_integration.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/tests/test_file_validator.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/tests/test_performance.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/tests/test_utils.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/tests/test_validate_activity_file.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/tests/test_validate_gzip_file.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/tests/validators/__init__.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/tests/validators/test_compression_validator.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/tests/validators/test_extension_validator.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/tests/validators/test_unicode_validator.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/tests/validators/test_windows_validator.py +0 -0
- {safeuploads-1.1.1 → safeuploads-1.1.2}/tests/validators/test_xml_validator.py +0 -0
|
@@ -39,7 +39,7 @@ jobs:
|
|
|
39
39
|
fetch-depth: 1
|
|
40
40
|
|
|
41
41
|
- name: Install uv
|
|
42
|
-
uses: astral-sh/setup-uv@
|
|
42
|
+
uses: astral-sh/setup-uv@18d369b23da25a81e9458561248e1aafff6a70fa # v10.3.1
|
|
43
43
|
with:
|
|
44
44
|
# Resolve uv from `[tool.uv] required-version` in pyproject.toml, so CI
|
|
45
45
|
# and local development are held to the same floor and ceiling.
|
|
@@ -22,8 +22,13 @@ jobs:
|
|
|
22
22
|
fetch-depth: 0
|
|
23
23
|
|
|
24
24
|
- name: Validate PR title
|
|
25
|
-
# The
|
|
26
|
-
#
|
|
25
|
+
# The title only changes on opened/edited/reopened. Skipping it on
|
|
26
|
+
# `synchronize` keeps a push to a branch shared with another open PR
|
|
27
|
+
# (for example a WIP umbrella PR) from failing on that PR's title
|
|
28
|
+
# before the commit-range check below can run.
|
|
29
|
+
if: github.event.action != 'synchronize'
|
|
30
|
+
# The PR title is untrusted data: passed through an environment variable
|
|
31
|
+
# (never interpolated into the shell) to the trusted base-ref checker.
|
|
27
32
|
env:
|
|
28
33
|
PR_TITLE: ${{ github.event.pull_request.title }}
|
|
29
34
|
run: |
|
|
@@ -40,7 +40,7 @@ jobs:
|
|
|
40
40
|
fetch-depth: 1
|
|
41
41
|
|
|
42
42
|
- name: Install uv
|
|
43
|
-
uses: astral-sh/setup-uv@
|
|
43
|
+
uses: astral-sh/setup-uv@18d369b23da25a81e9458561248e1aafff6a70fa # v10.3.1
|
|
44
44
|
with:
|
|
45
45
|
# Resolve uv from `[tool.uv] required-version` in pyproject.toml, so CI
|
|
46
46
|
# and local development are held to the same floor and ceiling.
|
|
@@ -78,4 +78,4 @@ jobs:
|
|
|
78
78
|
steps:
|
|
79
79
|
- name: Deploy to GitHub Pages
|
|
80
80
|
id: deployment
|
|
81
|
-
uses: actions/deploy-pages@
|
|
81
|
+
uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5.0.1
|
|
@@ -28,7 +28,7 @@ jobs:
|
|
|
28
28
|
run: sudo apt-get update && sudo apt-get install -y libmagic1
|
|
29
29
|
|
|
30
30
|
- name: Install uv
|
|
31
|
-
uses: astral-sh/setup-uv@
|
|
31
|
+
uses: astral-sh/setup-uv@18d369b23da25a81e9458561248e1aafff6a70fa # v10.3.1
|
|
32
32
|
with:
|
|
33
33
|
version-file: pyproject.toml
|
|
34
34
|
|
|
@@ -32,7 +32,7 @@ jobs:
|
|
|
32
32
|
fetch-depth: 1
|
|
33
33
|
|
|
34
34
|
- name: Install uv
|
|
35
|
-
uses: astral-sh/setup-uv@
|
|
35
|
+
uses: astral-sh/setup-uv@18d369b23da25a81e9458561248e1aafff6a70fa # v10.3.1
|
|
36
36
|
with:
|
|
37
37
|
# Resolve uv from `[tool.uv] required-version` in pyproject.toml, so CI
|
|
38
38
|
# and local development are held to the same floor and ceiling.
|
|
@@ -68,7 +68,7 @@ jobs:
|
|
|
68
68
|
run: sudo apt-get update && sudo apt-get install -y libmagic1
|
|
69
69
|
|
|
70
70
|
- name: Install uv
|
|
71
|
-
uses: astral-sh/setup-uv@
|
|
71
|
+
uses: astral-sh/setup-uv@18d369b23da25a81e9458561248e1aafff6a70fa # v10.3.1
|
|
72
72
|
with:
|
|
73
73
|
version-file: pyproject.toml
|
|
74
74
|
|
|
@@ -82,7 +82,7 @@ jobs:
|
|
|
82
82
|
run: uv run pytest --cov-fail-under=90
|
|
83
83
|
|
|
84
84
|
- name: Upload coverage report
|
|
85
|
-
uses: actions/upload-artifact@
|
|
85
|
+
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
|
86
86
|
if: always()
|
|
87
87
|
with:
|
|
88
88
|
name: safeuploads-coverage
|
|
@@ -36,7 +36,7 @@ jobs:
|
|
|
36
36
|
persist-credentials: false
|
|
37
37
|
|
|
38
38
|
- name: Install uv
|
|
39
|
-
uses: astral-sh/setup-uv@
|
|
39
|
+
uses: astral-sh/setup-uv@18d369b23da25a81e9458561248e1aafff6a70fa # v10.3.1
|
|
40
40
|
with:
|
|
41
41
|
# Resolve uv from `[tool.uv] required-version` in pyproject.toml, so CI
|
|
42
42
|
# and local development are held to the same floor and ceiling.
|
|
@@ -122,7 +122,7 @@ jobs:
|
|
|
122
122
|
# attests everything it downloads, so a stray checksum or SBOM file there
|
|
123
123
|
# would end up in the attestation.
|
|
124
124
|
- name: Upload build artifacts
|
|
125
|
-
uses: actions/upload-artifact@
|
|
125
|
+
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
|
126
126
|
with:
|
|
127
127
|
name: safeuploads-dist
|
|
128
128
|
path: dist/
|
|
@@ -130,7 +130,7 @@ jobs:
|
|
|
130
130
|
retention-days: 90
|
|
131
131
|
|
|
132
132
|
- name: Upload release metadata
|
|
133
|
-
uses: actions/upload-artifact@
|
|
133
|
+
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
|
134
134
|
with:
|
|
135
135
|
name: safeuploads-release-metadata
|
|
136
136
|
path: release-metadata/
|
|
@@ -149,22 +149,22 @@ jobs:
|
|
|
149
149
|
id-token: write
|
|
150
150
|
steps:
|
|
151
151
|
- name: Install uv
|
|
152
|
-
uses: astral-sh/setup-uv@
|
|
152
|
+
uses: astral-sh/setup-uv@18d369b23da25a81e9458561248e1aafff6a70fa # v10.3.1
|
|
153
153
|
with:
|
|
154
154
|
# This job never checks the repository out, so there is no
|
|
155
155
|
# pyproject.toml to read `required-version` from; keep this in step
|
|
156
156
|
# with the floor declared there.
|
|
157
|
-
version: "0.
|
|
157
|
+
version: "0.13.5"
|
|
158
158
|
enable-cache: false
|
|
159
159
|
|
|
160
160
|
- name: Download build artifacts
|
|
161
|
-
uses: actions/download-artifact@
|
|
161
|
+
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
|
162
162
|
with:
|
|
163
163
|
name: safeuploads-dist
|
|
164
164
|
path: dist/
|
|
165
165
|
|
|
166
166
|
- name: Generate PEP 740 attestations
|
|
167
|
-
uses: astral-sh/attest-action@
|
|
167
|
+
uses: astral-sh/attest-action@39b6ce43875c196a579e31635b11aa2a2036384a # v0.0.7
|
|
168
168
|
|
|
169
169
|
- name: Publish to PyPI
|
|
170
170
|
run: uv publish --trusted-publishing always dist/*.whl dist/*.tar.gz
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
name: Test matrix safeuploads
|
|
2
|
+
|
|
3
|
+
# Portability matrix on top of the fast default `Lint & Test` workflow:
|
|
4
|
+
# * every supported Python version (3.13, 3.14, 3.15) with the full
|
|
5
|
+
# dependency set (dev group + fastapi extra), proving the suite
|
|
6
|
+
# passes on every Python the package declares support for; and
|
|
7
|
+
# * a bare `import safeuploads` with only the base dependencies
|
|
8
|
+
# installed (no optional extras, no dev group), proving
|
|
9
|
+
# python-magic and defusedxml are truly sufficient on their own
|
|
10
|
+
# and the `fastapi` extra stays optional.
|
|
11
|
+
|
|
12
|
+
on:
|
|
13
|
+
push:
|
|
14
|
+
branches:
|
|
15
|
+
- main
|
|
16
|
+
paths: &paths
|
|
17
|
+
- safeuploads/**
|
|
18
|
+
- tests/**
|
|
19
|
+
- pyproject.toml
|
|
20
|
+
- uv.lock
|
|
21
|
+
- .github/workflows/test-matrix-safeuploads.yml
|
|
22
|
+
- .github/scripts/smoke_import.py
|
|
23
|
+
pull_request:
|
|
24
|
+
branches:
|
|
25
|
+
- main
|
|
26
|
+
paths: *paths
|
|
27
|
+
|
|
28
|
+
permissions:
|
|
29
|
+
contents: read
|
|
30
|
+
|
|
31
|
+
concurrency:
|
|
32
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
33
|
+
cancel-in-progress: true
|
|
34
|
+
|
|
35
|
+
jobs:
|
|
36
|
+
# 1. Every supported Python version, with the full dependency set.
|
|
37
|
+
test-python-matrix:
|
|
38
|
+
name: safeuploads (py${{ matrix.python }})
|
|
39
|
+
runs-on: ubuntu-latest
|
|
40
|
+
strategy:
|
|
41
|
+
fail-fast: false
|
|
42
|
+
matrix:
|
|
43
|
+
python: ["3.13", "3.14", "3.15"]
|
|
44
|
+
steps:
|
|
45
|
+
- name: Checkout code
|
|
46
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
47
|
+
with:
|
|
48
|
+
fetch-depth: 1
|
|
49
|
+
|
|
50
|
+
- name: Install system dependencies
|
|
51
|
+
run: sudo apt-get update && sudo apt-get install -y libmagic1
|
|
52
|
+
|
|
53
|
+
- name: Install uv
|
|
54
|
+
uses: astral-sh/setup-uv@18d369b23da25a81e9458561248e1aafff6a70fa # v10.3.1
|
|
55
|
+
with:
|
|
56
|
+
# Resolve uv from `[tool.uv] required-version` in pyproject.toml, so CI
|
|
57
|
+
# and local development are held to the same floor and ceiling.
|
|
58
|
+
version-file: pyproject.toml
|
|
59
|
+
|
|
60
|
+
- name: Sync dependencies
|
|
61
|
+
run: uv sync --frozen --dev --extra fastapi --python ${{ matrix.python }}
|
|
62
|
+
|
|
63
|
+
- name: Run tests
|
|
64
|
+
run: uv run --no-sync --python ${{ matrix.python }} pytest
|
|
65
|
+
|
|
66
|
+
# 2. Bare import with only the base dependencies (no extras, no dev group):
|
|
67
|
+
# proves `import safeuploads` works with zero extras installed.
|
|
68
|
+
import-base-deps:
|
|
69
|
+
name: safeuploads (bare import, no extras)
|
|
70
|
+
runs-on: ubuntu-latest
|
|
71
|
+
steps:
|
|
72
|
+
- name: Checkout code
|
|
73
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
74
|
+
with:
|
|
75
|
+
fetch-depth: 1
|
|
76
|
+
|
|
77
|
+
- name: Install system dependencies
|
|
78
|
+
run: sudo apt-get update && sudo apt-get install -y libmagic1
|
|
79
|
+
|
|
80
|
+
- name: Install uv
|
|
81
|
+
uses: astral-sh/setup-uv@18d369b23da25a81e9458561248e1aafff6a70fa # v10.3.1
|
|
82
|
+
with:
|
|
83
|
+
# Resolve uv from `[tool.uv] required-version` in pyproject.toml, so CI
|
|
84
|
+
# and local development are held to the same floor and ceiling.
|
|
85
|
+
version-file: pyproject.toml
|
|
86
|
+
|
|
87
|
+
- name: Install base dependencies only (no optional extras, no dev group)
|
|
88
|
+
# --no-dev installs the base runtime dependencies + the project only;
|
|
89
|
+
# the fastapi extra and the dev dependency group stay out.
|
|
90
|
+
# --no-editable installs safeuploads as a real distribution (not a
|
|
91
|
+
# path into the checkout), so the smoke test actually validates an
|
|
92
|
+
# install.
|
|
93
|
+
run: uv sync --frozen --no-dev --no-editable
|
|
94
|
+
|
|
95
|
+
# Run from outside the repository root so the local `safeuploads/`
|
|
96
|
+
# package directory cannot shadow the installed distribution:
|
|
97
|
+
# otherwise this would validate the working tree rather than what a
|
|
98
|
+
# user actually gets.
|
|
99
|
+
- name: Import safeuploads without optional extras
|
|
100
|
+
run: |
|
|
101
|
+
set -euo pipefail
|
|
102
|
+
cp -r .venv "$RUNNER_TEMP/base-venv"
|
|
103
|
+
cd "$RUNNER_TEMP"
|
|
104
|
+
VIRTUAL_ENV="$RUNNER_TEMP/base-venv" uv run --no-project python "$GITHUB_WORKSPACE/.github/scripts/smoke_import.py"
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## [1.1.2] - 2026-10-22
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- Updated all dependency groups to their latest versions.
|
|
12
|
+
- Updated uv to 0.13.5.
|
|
13
|
+
- Updated GitHub Actions to their latest releases, pinned by commit hash.
|
|
14
|
+
|
|
15
|
+
## [1.1.1] - 2026-08-19
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- Migrated CI/CD from Forgejo/Codeberg to GitHub Actions: lint & test, scheduled fuzz, docs deploy, PyPI publish, and Conventional Commits checks.
|
|
20
|
+
- Added Dependabot configuration, a `CODEOWNERS` file, and a scheduled dependency-vulnerability audit workflow (`pip-audit`).
|
|
21
|
+
- Updated all repository, documentation, and badge links from Codeberg to GitHub.
|
|
22
|
+
|
|
23
|
+
## [1.1.0] - 2026-07-20
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
### Added
|
|
27
|
+
|
|
28
|
+
- `verify_zip_decompression` option that decompresses every ZIP entry to reject archives with forged central-directory metadata.
|
|
29
|
+
- Custom `executor` parameter on `FileValidator` to offload blocking inspection to a bounded thread pool instead of the default `asyncio` pool.
|
|
30
|
+
- Instance-level configuration validation and isolation so a per-instance `limits` object never mutates the shared class defaults.
|
|
31
|
+
- New `SecurityLimits` size limits plus additional recursable-archive types and script patterns for deeper threat detection.
|
|
32
|
+
- `BaseInspector` base class sharing configuration and audit state across inspectors.
|
|
33
|
+
- PEP 561 `py.typed` marker so downstream projects consume the shipped type hints.
|
|
34
|
+
- Integration tests exercising a real Starlette `UploadFile` and an end-to-end FastAPI multipart request.
|
|
35
|
+
|
|
36
|
+
### Changed
|
|
37
|
+
|
|
38
|
+
- `ErrorCode` is now a `StrEnum`. This is backward compatible: members still compare and hash equal to their string values, so existing comparisons and JSON serialization are unaffected.
|
|
39
|
+
- Validation flow refactored around a single generic runner for consistent audit logging and error mapping.
|
|
40
|
+
- Thread safety hardened: access to the shared `python-magic` instance is locked, and blocking inspection is offloaded off the event loop.
|
|
41
|
+
- File-size validation now rejects uploads whose declared size already exceeds the limit and verifies the real byte count by streaming.
|
|
42
|
+
- **Potentially breaking:** the public allow-list constants (`ALLOWED_IMAGE_MIMES`, `ALLOWED_ZIP_MIMES`, `ALLOWED_IMAGE_EXTENSIONS`, `ALLOWED_ZIP_EXTENSIONS`) are now immutable `frozenset`s. Read-only use is unaffected; in-place mutation (e.g. `.add(...)`) is no longer supported, assign a new set instead.
|
|
43
|
+
|
|
44
|
+
### Fixed
|
|
45
|
+
|
|
46
|
+
- Corrected the filename-sanitization debug log so it reports the true original filename rather than the already-sanitized value.
|
|
47
|
+
- Documentation URLs updated to the new site.
|
|
48
|
+
|
|
49
|
+
## [1.0.1] - 2026-06-03
|
|
50
|
+
|
|
51
|
+
### Fixed
|
|
52
|
+
|
|
53
|
+
- `_stream_to_temp_file` now seeks the original `UploadFile` back to position 0 (#3).
|
|
54
|
+
|
|
55
|
+
### Changed
|
|
56
|
+
|
|
57
|
+
- Dependency version bumps.
|
|
58
|
+
|
|
59
|
+
## [1.0.0] - 2026-03-26
|
|
60
|
+
|
|
61
|
+
First stable, production-ready release. Every layer of the validation
|
|
62
|
+
pipeline was expanded, hardened, and documented since v0.1.2.
|
|
63
|
+
|
|
64
|
+
### Added
|
|
65
|
+
|
|
66
|
+
- **Activity & gzip validation:** `validate_activity_file` (GPX/TCX/FIT) and `validate_gzip_file` with decompression-bomb detection, plus `XmlSecurityValidator` using `defusedxml` to block XXE, DTD, and entity-expansion attacks in XML-based activity files.
|
|
67
|
+
- **Audit logging:** `SecurityAuditLogger`, `AuditEvent`, and `AuditEventType` with per-request correlation IDs, toggled by `enable_audit_logging`.
|
|
68
|
+
- **Content security inspector:** `ContentSecurityInspector` for malware-signature scanning, script/webshell marker detection, and polyglot detection, controlled by `enable_content_analysis` and `content_scan_max_size`.
|
|
69
|
+
- **Nested ZIP complexity checks:** recursive inspection with cumulative entry, depth, hash, and timing checks, archive-quine and ZIP-of-ZIPs detection, and a new `max_total_entries_recursive` limit.
|
|
70
|
+
|
|
71
|
+
### Changed
|
|
72
|
+
|
|
73
|
+
- **Security hardening:** streaming file-size enforcement via `chunk_size`, tightened ZIP inspection (null-byte filename detection, monotonic timers, 512-byte content scans, sanitized error messages), and a hardened MIME cache (256 → 64 entries, extension-only derivation).
|
|
74
|
+
- `defusedxml` added as a runtime dependency.
|
|
75
|
+
- FastAPI example now binds to `127.0.0.1` instead of `0.0.0.0`.
|
|
76
|
+
- **Performance:** pre-computed `frozenset` collections, cached lookup sets at initialization, and LRU-cached MIME guessing.
|
|
77
|
+
|
|
78
|
+
### Other
|
|
79
|
+
|
|
80
|
+
- Hypothesis fuzz tests and integration suites; GitHub Actions for lint/test, fuzzing, docs, and PyPI publish; Dependabot and `CODEOWNERS`; new security docs (threat model, architecture, integration checklist).
|
|
81
|
+
|
|
82
|
+
## [0.1.2] - 2025-10-31
|
|
83
|
+
|
|
84
|
+
### Fixed
|
|
85
|
+
|
|
86
|
+
- Added `BinaryFileCategory` to the exported enums in `safeuploads/__init__.py` so it is available for external use.
|
|
87
|
+
|
|
88
|
+
## [0.1.1] - 2025-10-31
|
|
89
|
+
|
|
90
|
+
### Added
|
|
91
|
+
|
|
92
|
+
- `max_number_files_same_type` in `SecurityLimits`; `ZipContentInspector` now uses this configurable limit instead of a hardcoded value when checking for excessive files of the same type in a ZIP archive.
|
|
93
|
+
- `BinaryFileCategory` enum categorizing binary file extensions (starting with fitness files such as `.fit`); `ZipContentInspector` skips script-content checks for these binary files.
|
|
94
|
+
|
|
95
|
+
## [0.1.0] - 2025-10-30
|
|
96
|
+
|
|
97
|
+
Initial release.
|
|
98
|
+
|
|
99
|
+
### Added
|
|
100
|
+
|
|
101
|
+
- **Filename security:** Unicode normalization, directory-traversal protection, Windows reserved-name blocking.
|
|
102
|
+
- **Extension validation:** configurable allow/block lists with dangerous-extension detection.
|
|
103
|
+
- **ZIP bomb protection:** compression-ratio limits, nested-archive inspection, size constraints.
|
|
104
|
+
- **MIME type verification:** magic-number validation for common file types.
|
|
105
|
+
- Framework-agnostic async validation, a rich exception hierarchy with machine-readable error codes, secure defaults, and full type hints.
|
|
106
|
+
|
|
107
|
+
[1.1.2]: https://github.com/endurain-project/safeuploads/compare/v1.1.1...v1.1.2
|
|
108
|
+
[1.1.1]: https://github.com/endurain-project/safeuploads/compare/v1.1.0...v1.1.1
|
|
109
|
+
[1.1.0]: https://github.com/endurain-project/safeuploads/compare/v1.0.1...v1.1.0
|
|
110
|
+
[1.0.1]: https://github.com/endurain-project/safeuploads/releases/tag/v1.0.1
|
|
111
|
+
[1.0.0]: https://github.com/endurain-project/safeuploads/releases/tag/v1.0.0
|
|
112
|
+
[0.1.2]: https://github.com/endurain-project/safeuploads/releases/tag/v0.1.2
|
|
113
|
+
[0.1.1]: https://github.com/endurain-project/safeuploads/releases/tag/v0.1.1
|
|
114
|
+
[0.1.0]: https://github.com/endurain-project/safeuploads/releases/tag/v0.1.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "safeuploads"
|
|
3
|
-
version = "1.1.
|
|
3
|
+
version = "1.1.2"
|
|
4
4
|
description = "A comprehensive file security system for validating uploads and preventing attacks"
|
|
5
5
|
authors = [
|
|
6
6
|
{name = "João Vitória Silva",email = "joao@endurain.com"}
|
|
@@ -40,7 +40,7 @@ requires = ["hatchling"]
|
|
|
40
40
|
build-backend = "hatchling.build"
|
|
41
41
|
|
|
42
42
|
[tool.uv]
|
|
43
|
-
required-version = "0.
|
|
43
|
+
required-version = "0.13.5"
|
|
44
44
|
exclude-newer = "30 days"
|
|
45
45
|
|
|
46
46
|
[tool.ruff]
|