pysentry-rs 0.2.1__tar.gz → 0.2.3__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.

Potentially problematic release.


This version of pysentry-rs might be problematic. Click here for more details.

Files changed (62) hide show
  1. pysentry_rs-0.2.3/.github/workflows/benchmark.yml +156 -0
  2. {pysentry_rs-0.2.1 → pysentry_rs-0.2.3}/Cargo.lock +75 -1
  3. {pysentry_rs-0.2.1 → pysentry_rs-0.2.3}/Cargo.toml +4 -1
  4. {pysentry_rs-0.2.1 → pysentry_rs-0.2.3}/PKG-INFO +147 -35
  5. {pysentry_rs-0.2.1 → pysentry_rs-0.2.3}/README.md +146 -34
  6. pysentry_rs-0.2.3/benchmarks/.gitignore +2 -0
  7. pysentry_rs-0.2.3/benchmarks/.python-version +1 -0
  8. pysentry_rs-0.2.3/benchmarks/README.md +3 -0
  9. pysentry_rs-0.2.3/benchmarks/main.py +111 -0
  10. pysentry_rs-0.2.3/benchmarks/pyproject.toml +12 -0
  11. pysentry_rs-0.2.3/benchmarks/src/benchmark_runner.py +364 -0
  12. pysentry_rs-0.2.3/benchmarks/src/performance_monitor.py +157 -0
  13. pysentry_rs-0.2.3/benchmarks/src/report_generator.py +222 -0
  14. pysentry_rs-0.2.3/benchmarks/src/tool_wrapper.py +347 -0
  15. pysentry_rs-0.2.3/benchmarks/test_data/large_requirements.txt +55 -0
  16. pysentry_rs-0.2.3/benchmarks/test_data/small_requirements.txt +10 -0
  17. pysentry_rs-0.2.3/benchmarks/uv.lock +1099 -0
  18. pysentry_rs-0.2.3/python/pysentry/__init__.py +24 -0
  19. pysentry_rs-0.2.3/src/cache/audit.rs +485 -0
  20. {pysentry_rs-0.2.1 → pysentry_rs-0.2.3}/src/cache/storage.rs +5 -4
  21. pysentry_rs-0.2.1/src/main.rs → pysentry_rs-0.2.3/src/cli.rs +76 -378
  22. {pysentry_rs-0.2.1 → pysentry_rs-0.2.3}/src/dependency/resolvers/mod.rs +108 -29
  23. {pysentry_rs-0.2.1 → pysentry_rs-0.2.3}/src/dependency/resolvers/pip_tools.rs +187 -1
  24. {pysentry_rs-0.2.1 → pysentry_rs-0.2.3}/src/dependency/resolvers/uv.rs +211 -3
  25. {pysentry_rs-0.2.1 → pysentry_rs-0.2.3}/src/dependency/scanner.rs +1 -1
  26. {pysentry_rs-0.2.1 → pysentry_rs-0.2.3}/src/lib.rs +5 -1
  27. pysentry_rs-0.2.3/src/main.rs +67 -0
  28. {pysentry_rs-0.2.1 → pysentry_rs-0.2.3}/src/parsers/mod.rs +1 -1
  29. {pysentry_rs-0.2.1 → pysentry_rs-0.2.3}/src/parsers/pyproject.rs +2 -2
  30. {pysentry_rs-0.2.1 → pysentry_rs-0.2.3}/src/parsers/requirements.rs +3 -3
  31. pysentry_rs-0.2.3/src/python.rs +87 -0
  32. {pysentry_rs-0.2.1 → pysentry_rs-0.2.3}/src/types.rs +60 -0
  33. pysentry_rs-0.2.1/python/pysentry/__init__.py +0 -292
  34. pysentry_rs-0.2.1/python/pysentry/__main__.py +0 -6
  35. pysentry_rs-0.2.1/src/cache/audit.rs +0 -76
  36. pysentry_rs-0.2.1/src/python.rs +0 -486
  37. {pysentry_rs-0.2.1 → pysentry_rs-0.2.3}/.github/FUNDING.yml +0 -0
  38. {pysentry_rs-0.2.1 → pysentry_rs-0.2.3}/.github/dependabot.yml +0 -0
  39. {pysentry_rs-0.2.1 → pysentry_rs-0.2.3}/.github/workflows/ci.yml +0 -0
  40. {pysentry_rs-0.2.1 → pysentry_rs-0.2.3}/.github/workflows/release.yml +0 -0
  41. {pysentry_rs-0.2.1 → pysentry_rs-0.2.3}/.gitignore +0 -0
  42. {pysentry_rs-0.2.1 → pysentry_rs-0.2.3}/.pre-commit-config.yaml +0 -0
  43. {pysentry_rs-0.2.1 → pysentry_rs-0.2.3}/LICENSE +0 -0
  44. {pysentry_rs-0.2.1 → pysentry_rs-0.2.3}/fixtures/requirements-tests/requirements-dev.txt +0 -0
  45. {pysentry_rs-0.2.1 → pysentry_rs-0.2.3}/fixtures/requirements-tests/requirements.txt +0 -0
  46. {pysentry_rs-0.2.1 → pysentry_rs-0.2.3}/fixtures/requirements-tests-vulnerable/requirements.txt +0 -0
  47. {pysentry_rs-0.2.1 → pysentry_rs-0.2.3}/pyproject.toml +0 -0
  48. {pysentry_rs-0.2.1 → pysentry_rs-0.2.3}/src/cache/mod.rs +0 -0
  49. {pysentry_rs-0.2.1 → pysentry_rs-0.2.3}/src/dependency/mod.rs +0 -0
  50. {pysentry_rs-0.2.1 → pysentry_rs-0.2.3}/src/error.rs +0 -0
  51. {pysentry_rs-0.2.1 → pysentry_rs-0.2.3}/src/output/mod.rs +0 -0
  52. {pysentry_rs-0.2.1 → pysentry_rs-0.2.3}/src/output/report.rs +0 -0
  53. {pysentry_rs-0.2.1 → pysentry_rs-0.2.3}/src/output/sarif.rs +0 -0
  54. {pysentry_rs-0.2.1 → pysentry_rs-0.2.3}/src/parsers/lock.rs +0 -0
  55. {pysentry_rs-0.2.1 → pysentry_rs-0.2.3}/src/parsers/poetry_lock.rs +0 -0
  56. {pysentry_rs-0.2.1 → pysentry_rs-0.2.3}/src/providers/mod.rs +0 -0
  57. {pysentry_rs-0.2.1 → pysentry_rs-0.2.3}/src/providers/osv.rs +0 -0
  58. {pysentry_rs-0.2.1 → pysentry_rs-0.2.3}/src/providers/pypa.rs +0 -0
  59. {pysentry_rs-0.2.1 → pysentry_rs-0.2.3}/src/providers/pypi.rs +0 -0
  60. {pysentry_rs-0.2.1 → pysentry_rs-0.2.3}/src/vulnerability/database.rs +0 -0
  61. {pysentry_rs-0.2.1 → pysentry_rs-0.2.3}/src/vulnerability/matcher.rs +0 -0
  62. {pysentry_rs-0.2.1 → pysentry_rs-0.2.3}/src/vulnerability/mod.rs +0 -0
@@ -0,0 +1,156 @@
1
+ name: Benchmark Release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+ workflow_dispatch:
8
+ inputs:
9
+ version:
10
+ description: "Version to benchmark (e.g., v0.2.3)"
11
+ required: true
12
+ default: "v0.2.3"
13
+
14
+ env:
15
+ CARGO_TERM_COLOR: always
16
+ RUST_BACKTRACE: 1
17
+
18
+ jobs:
19
+ benchmark:
20
+ name: Run Benchmarks
21
+ runs-on: ubuntu-latest
22
+ permissions:
23
+ contents: write
24
+ pull-requests: write
25
+
26
+ steps:
27
+ - name: Checkout code
28
+ uses: actions/checkout@v4
29
+ with:
30
+ fetch-depth: 0
31
+
32
+ - name: Extract version from tag
33
+ id: version
34
+ run: |
35
+ if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
36
+ VERSION="${{ github.event.inputs.version }}"
37
+ else
38
+ VERSION="${{ github.ref_name }}"
39
+ fi
40
+ VERSION_CLEAN=${VERSION#v}
41
+ echo "version=${VERSION_CLEAN}" >> $GITHUB_OUTPUT
42
+ echo "version_with_v=${VERSION}" >> $GITHUB_OUTPUT
43
+ echo "branch_name=benchmark-${VERSION_CLEAN}" >> $GITHUB_OUTPUT
44
+
45
+ - name: Install system dependencies
46
+ run: |
47
+ sudo apt-get update
48
+ sudo apt-get install -y libssl-dev pkg-config
49
+
50
+ - name: Install Rust
51
+ uses: dtolnay/rust-toolchain@stable
52
+
53
+ - name: Cache cargo
54
+ uses: actions/cache@v4
55
+ with:
56
+ path: |
57
+ ~/.cargo/registry/index/
58
+ ~/.cargo/registry/cache/
59
+ ~/.cargo/git/db/
60
+ target
61
+ key: ${{ runner.os }}-cargo-benchmark-${{ hashFiles('**/Cargo.lock') }}
62
+ restore-keys: |
63
+ ${{ runner.os }}-cargo-benchmark-
64
+ ${{ runner.os }}-cargo-build-
65
+
66
+ - name: Build PySentry
67
+ run: cargo build --release
68
+
69
+ - name: Set up Python
70
+ uses: actions/setup-python@v5
71
+ with:
72
+ python-version: "3.11"
73
+
74
+ - name: Install uv
75
+ run: |
76
+ curl -LsSf https://astral.sh/uv/install.sh | sh
77
+ echo "$HOME/.local/bin" >> $GITHUB_PATH
78
+
79
+ - name: Install pip-audit for benchmark comparison
80
+ run: pip install pip-audit
81
+
82
+ - name: Install benchmark dependencies
83
+ run: |
84
+ cd benchmarks
85
+ uv sync
86
+
87
+ - name: Run benchmark suite
88
+ run: |
89
+ cd benchmarks
90
+ uv run python main.py --skip-build
91
+
92
+ ls -la results/
93
+
94
+ LATEST_FILE=$(ls results/*.md 2>/dev/null | sort -r | head -n 1)
95
+ if [ -f "$LATEST_FILE" ]; then
96
+ cp "$LATEST_FILE" results/latest.md
97
+ echo "Created latest.md from: $LATEST_FILE"
98
+ else
99
+ echo "Warning: No benchmark files found to create latest.md"
100
+ fi
101
+
102
+ - name: Configure Git
103
+ run: |
104
+ git config --global user.name "github-actions[bot]"
105
+ git config --global user.email "github-actions[bot]@users.noreply.github.com"
106
+
107
+ - name: Create and switch to benchmark branch
108
+ run: |
109
+ BRANCH_NAME="${{ steps.version.outputs.branch_name }}"
110
+ git checkout -b $BRANCH_NAME
111
+
112
+ - name: Commit benchmark results
113
+ run: |
114
+ VERSION="${{ steps.version.outputs.version }}"
115
+
116
+ git add benchmarks/results/
117
+
118
+ if git diff --staged --quiet; then
119
+ echo "No changes to commit"
120
+ exit 0
121
+ fi
122
+
123
+ git commit -m "Add benchmark results for version ${VERSION}"
124
+
125
+ - name: Push benchmark branch
126
+ run: |
127
+ BRANCH_NAME="${{ steps.version.outputs.branch_name }}"
128
+ git push origin $BRANCH_NAME
129
+
130
+ - name: Create Pull Request
131
+ env:
132
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
133
+ run: |
134
+ VERSION="${{ steps.version.outputs.version }}"
135
+ BRANCH_NAME="${{ steps.version.outputs.branch_name }}"
136
+
137
+ PR_BODY="This PR contains automated benchmark results comparing PySentry v${VERSION} against pip-audit."
138
+
139
+ gh pr create \
140
+ --title "Benchmark results for v${VERSION}" \
141
+ --body "$PR_BODY" \
142
+ --base main \
143
+ --head $BRANCH_NAME \
144
+ --label "benchmark,automated"
145
+
146
+ - name: Summary
147
+ run: |
148
+ VERSION="${{ steps.version.outputs.version }}"
149
+ BRANCH_NAME="${{ steps.version.outputs.branch_name }}"
150
+
151
+ echo "Benchmark workflow completed successfully!"
152
+ echo ""
153
+ echo "Benchmarked version: v${VERSION}"
154
+ echo "Created branch: ${BRANCH_NAME}"
155
+ echo "Results location: benchmarks/results/"
156
+ echo "Pull request created automatically"
@@ -150,6 +150,15 @@ version = "2.9.1"
150
150
  source = "registry+https://github.com/rust-lang/crates.io-index"
151
151
  checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
152
152
 
153
+ [[package]]
154
+ name = "block-buffer"
155
+ version = "0.10.4"
156
+ source = "registry+https://github.com/rust-lang/crates.io-index"
157
+ checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
158
+ dependencies = [
159
+ "generic-array",
160
+ ]
161
+
153
162
  [[package]]
154
163
  name = "bumpalo"
155
164
  version = "3.19.0"
@@ -250,6 +259,15 @@ version = "0.8.7"
250
259
  source = "registry+https://github.com/rust-lang/crates.io-index"
251
260
  checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
252
261
 
262
+ [[package]]
263
+ name = "cpufeatures"
264
+ version = "0.2.17"
265
+ source = "registry+https://github.com/rust-lang/crates.io-index"
266
+ checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
267
+ dependencies = [
268
+ "libc",
269
+ ]
270
+
253
271
  [[package]]
254
272
  name = "crc32fast"
255
273
  version = "1.5.0"
@@ -259,6 +277,16 @@ dependencies = [
259
277
  "cfg-if",
260
278
  ]
261
279
 
280
+ [[package]]
281
+ name = "crypto-common"
282
+ version = "0.1.6"
283
+ source = "registry+https://github.com/rust-lang/crates.io-index"
284
+ checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
285
+ dependencies = [
286
+ "generic-array",
287
+ "typenum",
288
+ ]
289
+
262
290
  [[package]]
263
291
  name = "derive_arbitrary"
264
292
  version = "1.4.1"
@@ -270,6 +298,16 @@ dependencies = [
270
298
  "syn",
271
299
  ]
272
300
 
301
+ [[package]]
302
+ name = "digest"
303
+ version = "0.10.7"
304
+ source = "registry+https://github.com/rust-lang/crates.io-index"
305
+ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
306
+ dependencies = [
307
+ "block-buffer",
308
+ "crypto-common",
309
+ ]
310
+
273
311
  [[package]]
274
312
  name = "dirs"
275
313
  version = "6.0.0"
@@ -448,6 +486,16 @@ dependencies = [
448
486
  "slab",
449
487
  ]
450
488
 
489
+ [[package]]
490
+ name = "generic-array"
491
+ version = "0.14.7"
492
+ source = "registry+https://github.com/rust-lang/crates.io-index"
493
+ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
494
+ dependencies = [
495
+ "typenum",
496
+ "version_check",
497
+ ]
498
+
451
499
  [[package]]
452
500
  name = "getrandom"
453
501
  version = "0.2.16"
@@ -1067,7 +1115,7 @@ dependencies = [
1067
1115
 
1068
1116
  [[package]]
1069
1117
  name = "pysentry"
1070
- version = "0.2.1"
1118
+ version = "0.2.3"
1071
1119
  dependencies = [
1072
1120
  "anyhow",
1073
1121
  "async-trait",
@@ -1078,10 +1126,13 @@ dependencies = [
1078
1126
  "futures",
1079
1127
  "pep440_rs",
1080
1128
  "pyo3",
1129
+ "regex",
1081
1130
  "reqwest",
1131
+ "rustc-hash",
1082
1132
  "serde",
1083
1133
  "serde_json",
1084
1134
  "serde_yaml",
1135
+ "sha2",
1085
1136
  "tempfile",
1086
1137
  "thiserror",
1087
1138
  "tokio",
@@ -1438,6 +1489,17 @@ dependencies = [
1438
1489
  "unsafe-libyaml",
1439
1490
  ]
1440
1491
 
1492
+ [[package]]
1493
+ name = "sha2"
1494
+ version = "0.10.9"
1495
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1496
+ checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
1497
+ dependencies = [
1498
+ "cfg-if",
1499
+ "cpufeatures",
1500
+ "digest",
1501
+ ]
1502
+
1441
1503
  [[package]]
1442
1504
  name = "sharded-slab"
1443
1505
  version = "0.1.7"
@@ -1826,6 +1888,12 @@ version = "0.2.5"
1826
1888
  source = "registry+https://github.com/rust-lang/crates.io-index"
1827
1889
  checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
1828
1890
 
1891
+ [[package]]
1892
+ name = "typenum"
1893
+ version = "1.18.0"
1894
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1895
+ checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
1896
+
1829
1897
  [[package]]
1830
1898
  name = "unicode-ident"
1831
1899
  version = "1.0.18"
@@ -1891,6 +1959,12 @@ version = "0.1.1"
1891
1959
  source = "registry+https://github.com/rust-lang/crates.io-index"
1892
1960
  checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
1893
1961
 
1962
+ [[package]]
1963
+ name = "version_check"
1964
+ version = "0.9.5"
1965
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1966
+ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
1967
+
1894
1968
  [[package]]
1895
1969
  name = "want"
1896
1970
  version = "0.3.1"
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "pysentry"
3
- version = "0.2.1"
3
+ version = "0.2.3"
4
4
  edition = "2021"
5
5
  rust-version = "1.79"
6
6
  description = "Security vulnerability auditing for Python packages"
@@ -31,10 +31,13 @@ fs-err = "3.1.1"
31
31
  futures = "0.3.31"
32
32
  pep440_rs = "0.7.3"
33
33
  pyo3 = { version = "0.25.1", features = ["extension-module"], optional = true }
34
+ regex = "1.11.1"
34
35
  reqwest = { version = "0.12.22", features = ["json", "stream", "rustls-tls"], default-features = false }
36
+ rustc-hash = "2.1.1"
35
37
  serde = { version = "1.0.219", features = ["derive"] }
36
38
  serde_json = "1.0.142"
37
39
  serde_yaml = "0.9.34"
40
+ sha2 = "0.10.9"
38
41
  tempfile = "3.20.0"
39
42
  thiserror = "2.0.12"
40
43
  tokio = { version = "1.47.1", features = ["fs", "io-util", "rt-multi-thread", "macros", "process"] }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pysentry-rs
3
- Version: 0.2.1
3
+ Version: 0.2.3
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
@@ -48,7 +48,7 @@ PySentry audits Python projects for known security vulnerabilities by analyzing
48
48
  - **Performance Focused**:
49
49
  - Written in Rust for speed
50
50
  - Async/concurrent processing
51
- - Intelligent caching system
51
+ - Multi-tier intelligent caching (vulnerability data + resolved dependencies)
52
52
  - **Comprehensive Filtering**:
53
53
  - Severity levels (low, medium, high, critical)
54
54
  - Dependency scopes (main only vs all [optional, dev, prod, etc] dependencies)
@@ -254,6 +254,12 @@ pysentry /path/to/project
254
254
 
255
255
  # Debug requirements.txt resolution
256
256
  pysentry --verbose --resolver uv /path/to/project
257
+
258
+ # Use longer resolution cache TTL (48 hours)
259
+ pysentry --resolution-cache-ttl 48 /path/to/project
260
+
261
+ # Clear resolution cache before scanning
262
+ pysentry --clear-resolution-cache /path/to/project
257
263
  ```
258
264
 
259
265
  ### CI/CD Integration Examples
@@ -273,42 +279,115 @@ pysentry --format markdown --output SECURITY-REPORT.md
273
279
 
274
280
  # Comprehensive audit with all sources and full reporting
275
281
  pysentry --sources pypa,pypi,osv --all-extras --format json --fail-on low
282
+
283
+ # CI environment with fresh resolution cache
284
+ pysentry --clear-resolution-cache --sources pypa,osv --format sarif
285
+
286
+ # CI with resolution cache disabled
287
+ pysentry --no-resolution-cache --format json --output security-report.json
276
288
  ```
277
289
 
278
290
  ## Configuration
279
291
 
280
292
  ### Command Line Options
281
293
 
282
- | Option | Description | Default |
283
- | ---------------- | ------------------------------------------------------- | ------------------- |
284
- | `--format` | Output format: `human`, `json`, `sarif`, `markdown` | `human` |
285
- | `--severity` | Minimum severity: `low`, `medium`, `high`, `critical` | `low` |
286
- | `--fail-on` | Fail (exit non-zero) on vulnerabilities ≥ severity | `medium` |
287
- | `--sources` | Vulnerability sources: `pypa`, `pypi`, `osv` (multiple) | `pypa` |
288
- | `--all-extras` | Include all dependencies (main + dev + optional) | `false` |
289
- | `--direct-only` | Check only direct dependencies | `false` |
290
- | `--ignore` | Vulnerability IDs to ignore (repeatable) | `[]` |
291
- | `--output` | Output file path | `stdout` |
292
- | `--no-cache` | Disable caching | `false` |
293
- | `--cache-dir` | Custom cache directory | `~/.cache/pysentry` |
294
- | `--verbose` | Enable verbose output | `false` |
295
- | `--quiet` | Suppress non-error output | `false` |
296
- | `--resolver` | Dependency resolver: `auto`, `uv`, `pip-tools` | `auto` |
297
- | `--requirements` | Additional requirements files (repeatable) | `[]` |
294
+ | Option | Description | Default |
295
+ | -------------------------- | ------------------------------------------------------- | ----------------- |
296
+ | `--format` | Output format: `human`, `json`, `sarif`, `markdown` | `human` |
297
+ | `--severity` | Minimum severity: `low`, `medium`, `high`, `critical` | `low` |
298
+ | `--fail-on` | Fail (exit non-zero) on vulnerabilities ≥ severity | `medium` |
299
+ | `--sources` | Vulnerability sources: `pypa`, `pypi`, `osv` (multiple) | `pypa` |
300
+ | `--all-extras` | Include all dependencies (main + dev + optional) | `false` |
301
+ | `--direct-only` | Check only direct dependencies | `false` |
302
+ | `--ignore` | Vulnerability IDs to ignore (repeatable) | `[]` |
303
+ | `--output` | Output file path | `stdout` |
304
+ | `--no-cache` | Disable all caching | `false` |
305
+ | `--cache-dir` | Custom cache directory | Platform-specific |
306
+ | `--resolution-cache-ttl` | Resolution cache TTL in hours | `24` |
307
+ | `--no-resolution-cache` | Disable resolution caching only | `false` |
308
+ | `--clear-resolution-cache` | Clear resolution cache on startup | `false` |
309
+ | `--verbose` | Enable verbose output | `false` |
310
+ | `--quiet` | Suppress non-error output | `false` |
311
+ | `--resolver` | Dependency resolver: `auto`, `uv`, `pip-tools` | `auto` |
312
+ | `--requirements` | Additional requirements files (repeatable) | `[]` |
298
313
 
299
314
  ### Cache Management
300
315
 
301
- PySentry uses an intelligent caching system to avoid redundant API calls:
316
+ PySentry uses an intelligent multi-tier caching system for optimal performance:
317
+
318
+ #### Vulnerability Data Cache
319
+
320
+ - **Location**: `{CACHE_DIR}/pysentry/vulnerability-db/`
321
+ - **Purpose**: Caches vulnerability databases from PyPA, PyPI, OSV
322
+ - **TTL**: 24 hours (configurable per source)
323
+ - **Benefits**: Avoids redundant API calls and downloads
324
+
325
+ #### Resolution Cache
326
+
327
+ - **Location**: `{CACHE_DIR}/pysentry/dependency-resolution/`
328
+ - **Purpose**: Caches resolved dependencies from `uv`/`pip-tools`
329
+ - **TTL**: 24 hours (configurable via `--resolution-cache-ttl`)
330
+ - **Benefits**: Dramatically speeds up repeated scans of requirements.txt files
331
+ - **Cache Key**: Based on requirements content, resolver version, Python version, platform
332
+
333
+ #### Platform-Specific Cache Locations
334
+
335
+ - **Linux**: `~/.cache/pysentry/`
336
+ - **macOS**: `~/Library/Caches/pysentry/`
337
+ - **Windows**: `%LOCALAPPDATA%\pysentry\`
338
+
339
+ **Finding Your Cache Location**: Run with `--verbose` to see the actual cache directory path being used.
340
+
341
+ #### Cache Features
302
342
 
303
- - **Default Location**: `~/.cache/pysentry/` (or system temp directory)
304
- - **TTL-based Expiration**: Separate expiration for each vulnerability source
305
343
  - **Atomic Updates**: Prevents cache corruption during concurrent access
306
344
  - **Custom Location**: Use `--cache-dir` to specify alternative location
345
+ - **Selective Clearing**: Control caching behavior per cache type
346
+ - **Content-based Invalidation**: Automatic cache invalidation on content changes
307
347
 
308
- To clear the cache:
348
+ #### Cache Control Examples
309
349
 
310
350
  ```bash
351
+ # Disable all caching
352
+ pysentry --no-cache
353
+
354
+ # Disable only resolution caching (keep vulnerability cache)
355
+ pysentry --no-resolution-cache
356
+
357
+ # Set resolution cache TTL to 48 hours
358
+ pysentry --resolution-cache-ttl 48
359
+
360
+ # Clear resolution cache on startup (useful for CI)
361
+ pysentry --clear-resolution-cache
362
+
363
+ # Custom cache directory
364
+ pysentry --cache-dir /tmp/my-pysentry-cache
365
+ ```
366
+
367
+ To manually clear all caches:
368
+
369
+ ```bash
370
+ # Linux
311
371
  rm -rf ~/.cache/pysentry/
372
+
373
+ # macOS
374
+ rm -rf ~/Library/Caches/pysentry/
375
+
376
+ # Windows (PowerShell)
377
+ Remove-Item -Recurse -Force "$env:LOCALAPPDATA\pysentry"
378
+ ```
379
+
380
+ To clear only resolution cache:
381
+
382
+ ```bash
383
+ # Linux
384
+ rm -rf ~/.cache/pysentry/dependency-resolution/
385
+
386
+ # macOS
387
+ rm -rf ~/Library/Caches/pysentry/dependency-resolution/
388
+
389
+ # Windows (PowerShell)
390
+ Remove-Item -Recurse -Force "$env:LOCALAPPDATA\pysentry\dependency-resolution"
312
391
  ```
313
392
 
314
393
  ## Supported Project Formats
@@ -437,26 +516,28 @@ Compatible with GitHub Security tab, VS Code, and other security tools.
437
516
 
438
517
  PySentry is designed for speed and efficiency:
439
518
 
440
- - **Concurrent Processing**: Vulnerability data fetched in parallel
441
- - **Smart Caching**: Reduces API calls and parsing overhead
519
+ - **Concurrent Processing**: Vulnerability data fetched in parallel from multiple sources
520
+ - **Multi-tier Caching**: Intelligent caching for both vulnerability data and resolved dependencies
442
521
  - **Efficient Matching**: In-memory indexing for fast vulnerability lookups
443
522
  - **Streaming**: Large databases processed without excessive memory usage
444
523
 
524
+ ### Resolution Cache Performance
525
+
526
+ The resolution cache provides dramatic performance improvements for requirements.txt files:
527
+
528
+ - **First scan**: Standard resolution time using `uv` or `pip-tools`
529
+ - **Subsequent scans**: Near-instantaneous when cache is fresh (>90% time savings)
530
+ - **Cache invalidation**: Automatic when requirements content, resolver, or environment changes
531
+ - **Content-aware**: Different cache entries for different Python versions and platforms
532
+
445
533
  ### Requirements.txt Resolution Performance
446
534
 
447
- PySentry leverages external resolvers for optimal performance:
535
+ PySentry leverages external resolvers with intelligent caching:
448
536
 
449
537
  - **uv resolver**: 2-10x faster than pip-tools, handles large dependency trees efficiently
450
538
  - **pip-tools resolver**: Reliable fallback, slower but widely compatible
451
539
  - **Isolated execution**: Prevents project pollution while maintaining security
452
-
453
- ### Benchmarks
454
-
455
- Typical performance on a project with 100+ dependencies:
456
-
457
- - **Cold cache**: 15-30 seconds
458
- - **Warm cache**: 2-5 seconds
459
- - **Memory usage**: ~50MB peak
540
+ - **Resolution caching**: Eliminates repeated resolver calls for unchanged requirements
460
541
 
461
542
  ## Development
462
543
 
@@ -581,12 +662,43 @@ ls uv.lock poetry.lock pyproject.toml
581
662
  **Performance Issues**
582
663
 
583
664
  ```bash
584
- # Clear cache and retry
585
- rm -rf ~/.cache/pysentry
665
+ # Clear all caches and retry
666
+ rm -rf ~/.cache/pysentry # Linux
667
+ rm -rf ~/Library/Caches/pysentry # macOS
668
+ pysentry
669
+
670
+ # Clear only resolution cache (if vulnerability cache is working)
671
+ rm -rf ~/.cache/pysentry/dependency-resolution/ # Linux
672
+ rm -rf ~/Library/Caches/pysentry/dependency-resolution/ # macOS
586
673
  pysentry
587
674
 
675
+ # Clear resolution cache via CLI
676
+ pysentry --clear-resolution-cache
677
+
588
678
  # Use verbose mode to identify bottlenecks
589
679
  pysentry --verbose
680
+
681
+ # Disable caching to isolate issues
682
+ pysentry --no-cache
683
+ ```
684
+
685
+ **Resolution Cache Issues**
686
+
687
+ ```bash
688
+ # Clear stale resolution cache after environment changes
689
+ pysentry --clear-resolution-cache
690
+
691
+ # Disable resolution cache if causing issues
692
+ pysentry --no-resolution-cache
693
+
694
+ # Extend cache TTL for stable environments
695
+ pysentry --resolution-cache-ttl 168 # 1 week
696
+
697
+ # Check cache usage with verbose output
698
+ pysentry --verbose # Shows cache hits/misses
699
+
700
+ # Force fresh resolution (ignores cache)
701
+ pysentry --clear-resolution-cache --no-resolution-cache
590
702
  ```
591
703
 
592
704
  ## Acknowledgments