pysentry-rs 0.2.0__tar.gz → 0.2.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.

Potentially problematic release.


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

Files changed (51) hide show
  1. pysentry_rs-0.2.2/.github/FUNDING.yml +1 -0
  2. {pysentry_rs-0.2.0 → pysentry_rs-0.2.2}/.github/workflows/ci.yml +12 -10
  3. {pysentry_rs-0.2.0 → pysentry_rs-0.2.2}/Cargo.lock +74 -1
  4. {pysentry_rs-0.2.0 → pysentry_rs-0.2.2}/Cargo.toml +3 -1
  5. {pysentry_rs-0.2.0 → pysentry_rs-0.2.2}/PKG-INFO +190 -43
  6. {pysentry_rs-0.2.0 → pysentry_rs-0.2.2}/README.md +189 -42
  7. pysentry_rs-0.2.2/python/pysentry/__init__.py +24 -0
  8. pysentry_rs-0.2.2/src/cache/audit.rs +502 -0
  9. {pysentry_rs-0.2.0 → pysentry_rs-0.2.2}/src/cache/storage.rs +2 -0
  10. pysentry_rs-0.2.0/src/main.rs → pysentry_rs-0.2.2/src/cli.rs +231 -185
  11. {pysentry_rs-0.2.0 → pysentry_rs-0.2.2}/src/dependency/resolvers/mod.rs +126 -29
  12. {pysentry_rs-0.2.0 → pysentry_rs-0.2.2}/src/dependency/resolvers/pip_tools.rs +187 -1
  13. {pysentry_rs-0.2.0 → pysentry_rs-0.2.2}/src/dependency/resolvers/uv.rs +178 -1
  14. {pysentry_rs-0.2.0 → pysentry_rs-0.2.2}/src/dependency/scanner.rs +1 -1
  15. {pysentry_rs-0.2.0 → pysentry_rs-0.2.2}/src/lib.rs +5 -1
  16. pysentry_rs-0.2.2/src/main.rs +67 -0
  17. {pysentry_rs-0.2.0 → pysentry_rs-0.2.2}/src/output/report.rs +292 -0
  18. {pysentry_rs-0.2.0 → pysentry_rs-0.2.2}/src/parsers/mod.rs +1 -1
  19. {pysentry_rs-0.2.0 → pysentry_rs-0.2.2}/src/parsers/poetry_lock.rs +67 -2
  20. {pysentry_rs-0.2.0 → pysentry_rs-0.2.2}/src/parsers/pyproject.rs +2 -2
  21. {pysentry_rs-0.2.0 → pysentry_rs-0.2.2}/src/parsers/requirements.rs +3 -3
  22. {pysentry_rs-0.2.0 → pysentry_rs-0.2.2}/src/providers/osv.rs +286 -21
  23. pysentry_rs-0.2.2/src/python.rs +87 -0
  24. pysentry_rs-0.2.2/src/types.rs +156 -0
  25. pysentry_rs-0.2.2/src/vulnerability/database.rs +439 -0
  26. pysentry_rs-0.2.0/python/pysentry/__init__.py +0 -187
  27. pysentry_rs-0.2.0/python/pysentry/__main__.py +0 -6
  28. pysentry_rs-0.2.0/src/cache/audit.rs +0 -76
  29. pysentry_rs-0.2.0/src/python.rs +0 -442
  30. pysentry_rs-0.2.0/src/types.rs +0 -88
  31. pysentry_rs-0.2.0/src/vulnerability/database.rs +0 -163
  32. {pysentry_rs-0.2.0 → pysentry_rs-0.2.2}/.github/dependabot.yml +0 -0
  33. {pysentry_rs-0.2.0 → pysentry_rs-0.2.2}/.github/workflows/release.yml +0 -0
  34. {pysentry_rs-0.2.0 → pysentry_rs-0.2.2}/.gitignore +0 -0
  35. {pysentry_rs-0.2.0 → pysentry_rs-0.2.2}/.pre-commit-config.yaml +0 -0
  36. {pysentry_rs-0.2.0 → pysentry_rs-0.2.2}/LICENSE +0 -0
  37. {pysentry_rs-0.2.0 → pysentry_rs-0.2.2}/fixtures/requirements-tests/requirements-dev.txt +0 -0
  38. {pysentry_rs-0.2.0 → pysentry_rs-0.2.2}/fixtures/requirements-tests/requirements.txt +0 -0
  39. {pysentry_rs-0.2.0 → pysentry_rs-0.2.2}/fixtures/requirements-tests-vulnerable/requirements.txt +0 -0
  40. {pysentry_rs-0.2.0 → pysentry_rs-0.2.2}/pyproject.toml +0 -0
  41. {pysentry_rs-0.2.0 → pysentry_rs-0.2.2}/src/cache/mod.rs +0 -0
  42. {pysentry_rs-0.2.0 → pysentry_rs-0.2.2}/src/dependency/mod.rs +0 -0
  43. {pysentry_rs-0.2.0 → pysentry_rs-0.2.2}/src/error.rs +0 -0
  44. {pysentry_rs-0.2.0 → pysentry_rs-0.2.2}/src/output/mod.rs +0 -0
  45. {pysentry_rs-0.2.0 → pysentry_rs-0.2.2}/src/output/sarif.rs +0 -0
  46. {pysentry_rs-0.2.0 → pysentry_rs-0.2.2}/src/parsers/lock.rs +0 -0
  47. {pysentry_rs-0.2.0 → pysentry_rs-0.2.2}/src/providers/mod.rs +0 -0
  48. {pysentry_rs-0.2.0 → pysentry_rs-0.2.2}/src/providers/pypa.rs +0 -0
  49. {pysentry_rs-0.2.0 → pysentry_rs-0.2.2}/src/providers/pypi.rs +0 -0
  50. {pysentry_rs-0.2.0 → pysentry_rs-0.2.2}/src/vulnerability/matcher.rs +0 -0
  51. {pysentry_rs-0.2.0 → pysentry_rs-0.2.2}/src/vulnerability/mod.rs +0 -0
@@ -0,0 +1 @@
1
+ buy_me_a_coffee: nyudenkov
@@ -4,19 +4,21 @@ on:
4
4
  push:
5
5
  branches: [main]
6
6
  paths-ignore:
7
- - '**.md'
8
- - 'LICENSE'
9
- - '.gitignore'
10
- - '.editorconfig'
11
- - '.github/dependabot.yml'
7
+ - "**.md"
8
+ - "LICENSE"
9
+ - ".gitignore"
10
+ - ".editorconfig"
11
+ - ".github/dependabot.yml"
12
+ - ".github/FUNDING.yml"
12
13
  pull_request:
13
14
  branches: [main]
14
15
  paths-ignore:
15
- - '**.md'
16
- - 'LICENSE'
17
- - '.gitignore'
18
- - '.editorconfig'
19
- - '.github/dependabot.yml'
16
+ - "**.md"
17
+ - "LICENSE"
18
+ - ".gitignore"
19
+ - ".editorconfig"
20
+ - ".github/dependabot.yml"
21
+ - ".github/FUNDING.yml"
20
22
 
21
23
  env:
22
24
  CARGO_TERM_COLOR: always
@@ -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.0"
1118
+ version = "0.2.2"
1071
1119
  dependencies = [
1072
1120
  "anyhow",
1073
1121
  "async-trait",
@@ -1078,10 +1126,12 @@ dependencies = [
1078
1126
  "futures",
1079
1127
  "pep440_rs",
1080
1128
  "pyo3",
1129
+ "regex",
1081
1130
  "reqwest",
1082
1131
  "serde",
1083
1132
  "serde_json",
1084
1133
  "serde_yaml",
1134
+ "sha2",
1085
1135
  "tempfile",
1086
1136
  "thiserror",
1087
1137
  "tokio",
@@ -1438,6 +1488,17 @@ dependencies = [
1438
1488
  "unsafe-libyaml",
1439
1489
  ]
1440
1490
 
1491
+ [[package]]
1492
+ name = "sha2"
1493
+ version = "0.10.9"
1494
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1495
+ checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
1496
+ dependencies = [
1497
+ "cfg-if",
1498
+ "cpufeatures",
1499
+ "digest",
1500
+ ]
1501
+
1441
1502
  [[package]]
1442
1503
  name = "sharded-slab"
1443
1504
  version = "0.1.7"
@@ -1826,6 +1887,12 @@ version = "0.2.5"
1826
1887
  source = "registry+https://github.com/rust-lang/crates.io-index"
1827
1888
  checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
1828
1889
 
1890
+ [[package]]
1891
+ name = "typenum"
1892
+ version = "1.18.0"
1893
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1894
+ checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
1895
+
1829
1896
  [[package]]
1830
1897
  name = "unicode-ident"
1831
1898
  version = "1.0.18"
@@ -1891,6 +1958,12 @@ version = "0.1.1"
1891
1958
  source = "registry+https://github.com/rust-lang/crates.io-index"
1892
1959
  checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
1893
1960
 
1961
+ [[package]]
1962
+ name = "version_check"
1963
+ version = "0.9.5"
1964
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1965
+ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
1966
+
1894
1967
  [[package]]
1895
1968
  name = "want"
1896
1969
  version = "0.3.1"
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "pysentry"
3
- version = "0.2.0"
3
+ version = "0.2.2"
4
4
  edition = "2021"
5
5
  rust-version = "1.79"
6
6
  description = "Security vulnerability auditing for Python packages"
@@ -31,10 +31,12 @@ 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 }
35
36
  serde = { version = "1.0.219", features = ["derive"] }
36
37
  serde_json = "1.0.142"
37
38
  serde_yaml = "0.9.34"
39
+ sha2 = "0.10.9"
38
40
  tempfile = "3.20.0"
39
41
  thiserror = "2.0.12"
40
42
  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.0
3
+ Version: 0.2.2
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)
@@ -26,6 +26,8 @@ Project-URL: Issues, https://github.com/nyudenkov/pysentry/issues
26
26
 
27
27
  # 🐍 PySentry
28
28
 
29
+ [![OSV Integration](https://img.shields.io/badge/OSV-Integrated-blue)](https://google.github.io/osv.dev/)
30
+
29
31
  [Help to test and improve](https://github.com/nyudenkov/pysentry/issues/12)
30
32
 
31
33
  A fast, reliable security vulnerability scanner for Python projects, written in Rust.
@@ -42,11 +44,11 @@ PySentry audits Python projects for known security vulnerabilities by analyzing
42
44
  - PyPA Advisory Database (default)
43
45
  - PyPI JSON API
44
46
  - OSV.dev (Open Source Vulnerabilities)
45
- - **Flexible Output**: Human-readable, JSON, and SARIF formats
47
+ - **Flexible Output for different workflows**: Human-readable, JSON, SARIF, and Markdown formats
46
48
  - **Performance Focused**:
47
49
  - Written in Rust for speed
48
50
  - Async/concurrent processing
49
- - Intelligent caching system
51
+ - Multi-tier intelligent caching (vulnerability data + resolved dependencies)
50
52
  - **Comprehensive Filtering**:
51
53
  - Severity levels (low, medium, high, critical)
52
54
  - Dependency scopes (main only vs all [optional, dev, prod, etc] dependencies)
@@ -197,7 +199,7 @@ pysentry --resolver uv /path/to/project
197
199
  pysentry --resolver pip-tools /path/to/project
198
200
 
199
201
  # Include all dependencies (main + dev + optional)
200
- pysentry --all
202
+ pysentry --all-extras
201
203
 
202
204
  # Filter by severity (only show high and critical)
203
205
  pysentry --severity high
@@ -210,14 +212,22 @@ pysentry --format json --output audit-results.json
210
212
 
211
213
  ```bash
212
214
  # Using uvx for comprehensive audit
213
- uvx pysentry-rs --all --format sarif --output security-report.sarif
215
+ uvx pysentry-rs --all-extras --format sarif --output security-report.sarif
216
+
217
+ # Check multiple vulnerability sources concurrently
218
+ uvx pysentry-rs --sources pypa,osv,pypi /path/to/project
219
+ uvx pysentry-rs --sources pypa --sources osv --sources pypi
214
220
 
215
- # Check only direct dependencies using OSV database
216
- uvx pysentry-rs --direct-only --source osv
221
+ # Generate markdown report
222
+ uvx pysentry-rs --format markdown --output security-report.md
223
+
224
+ # Control CI exit codes - only fail on critical vulnerabilities
225
+ uvx pysentry-rs --fail-on critical
217
226
 
218
227
  # Or with installed binary
219
- pysentry --all --format sarif --output security-report.sarif
220
- pysentry --direct-only --source osv
228
+ pysentry --all-extras --format sarif --output security-report.sarif
229
+ pysentry --sources pypa,osv --direct-only
230
+ pysentry --format markdown --output security-report.md
221
231
 
222
232
  # Ignore specific vulnerabilities
223
233
  pysentry --ignore CVE-2023-12345 --ignore GHSA-xxxx-yyyy-zzzz
@@ -244,41 +254,140 @@ pysentry /path/to/project
244
254
 
245
255
  # Debug requirements.txt resolution
246
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
263
+ ```
264
+
265
+ ### CI/CD Integration Examples
266
+
267
+ ```bash
268
+ # Development environment - only fail on critical vulnerabilities
269
+ pysentry --fail-on critical --format json --output security-report.json
270
+
271
+ # Staging environment - fail on high+ vulnerabilities
272
+ pysentry --fail-on high --sources pypa,osv --format sarif --output security.sarif
273
+
274
+ # Production deployment - strict security (fail on medium+, default)
275
+ pysentry --sources pypa,pypi,osv --format json --output prod-security.json
276
+
277
+ # Generate markdown report for GitHub issues/PRs
278
+ pysentry --format markdown --output SECURITY-REPORT.md
279
+
280
+ # Comprehensive audit with all sources and full reporting
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
247
288
  ```
248
289
 
249
290
  ## Configuration
250
291
 
251
292
  ### Command Line Options
252
293
 
253
- | Option | Description | Default |
254
- | ---------------- | ----------------------------------------------------- | ------------------- |
255
- | `--format` | Output format: `human`, `json`, `sarif` | `human` |
256
- | `--severity` | Minimum severity: `low`, `medium`, `high`, `critical` | `low` |
257
- | `--source` | Vulnerability source: `pypa`, `pypi`, `osv` | `pypa` |
258
- | `--all` | Include all dependencies (main + dev + optional) | `false` |
259
- | `--direct-only` | Check only direct dependencies | `false` |
260
- | `--ignore` | Vulnerability IDs to ignore (repeatable) | `[]` |
261
- | `--output` | Output file path | `stdout` |
262
- | `--no-cache` | Disable caching | `false` |
263
- | `--cache-dir` | Custom cache directory | `~/.cache/pysentry` |
264
- | `--verbose` | Enable verbose output | `false` |
265
- | `--quiet` | Suppress non-error output | `false` |
266
- | `--resolver` | Dependency resolver: `auto`, `uv`, `pip-tools` | `auto` |
267
- | `--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) | `[]` |
268
313
 
269
314
  ### Cache Management
270
315
 
271
- 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
272
342
 
273
- - **Default Location**: `~/.cache/pysentry/` (or system temp directory)
274
- - **TTL-based Expiration**: Separate expiration for each vulnerability source
275
343
  - **Atomic Updates**: Prevents cache corruption during concurrent access
276
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
277
347
 
278
- To clear the cache:
348
+ #### Cache Control Examples
279
349
 
280
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
281
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"
282
391
  ```
283
392
 
284
393
  ## Supported Project Formats
@@ -376,6 +485,10 @@ Support for projects without lock files:
376
485
 
377
486
  Most comfortable to read.
378
487
 
488
+ ### Markdown
489
+
490
+ GitHub-friendly format with structured sections and severity indicators. Perfect for documentation, GitHub issues, and security reports.
491
+
379
492
  ### JSON
380
493
 
381
494
  ```json
@@ -403,26 +516,28 @@ Compatible with GitHub Security tab, VS Code, and other security tools.
403
516
 
404
517
  PySentry is designed for speed and efficiency:
405
518
 
406
- - **Concurrent Processing**: Vulnerability data fetched in parallel
407
- - **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
408
521
  - **Efficient Matching**: In-memory indexing for fast vulnerability lookups
409
522
  - **Streaming**: Large databases processed without excessive memory usage
410
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
+
411
533
  ### Requirements.txt Resolution Performance
412
534
 
413
- PySentry leverages external resolvers for optimal performance:
535
+ PySentry leverages external resolvers with intelligent caching:
414
536
 
415
537
  - **uv resolver**: 2-10x faster than pip-tools, handles large dependency trees efficiently
416
538
  - **pip-tools resolver**: Reliable fallback, slower but widely compatible
417
539
  - **Isolated execution**: Prevents project pollution while maintaining security
418
-
419
- ### Benchmarks
420
-
421
- Typical performance on a project with 100+ dependencies:
422
-
423
- - **Cold cache**: 15-30 seconds
424
- - **Warm cache**: 2-5 seconds
425
- - **Memory usage**: ~50MB peak
540
+ - **Resolution caching**: Eliminates repeated resolver calls for unchanged requirements
426
541
 
427
542
  ## Development
428
543
 
@@ -510,8 +625,9 @@ pysentry --verbose /path/to/project
510
625
  # Check network connectivity
511
626
  curl -I https://osv-vulnerabilities.storage.googleapis.com/
512
627
 
513
- # Try with different source
514
- pysentry --source pypi
628
+ # Try with different or multiple sources
629
+ pysentry --sources pypi
630
+ pysentry --sources pypa,osv
515
631
  ```
516
632
 
517
633
  **Slow requirements.txt resolution**
@@ -546,12 +662,43 @@ ls uv.lock poetry.lock pyproject.toml
546
662
  **Performance Issues**
547
663
 
548
664
  ```bash
549
- # Clear cache and retry
550
- 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
551
673
  pysentry
552
674
 
675
+ # Clear resolution cache via CLI
676
+ pysentry --clear-resolution-cache
677
+
553
678
  # Use verbose mode to identify bottlenecks
554
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
555
702
  ```
556
703
 
557
704
  ## Acknowledgments