deployproof 0.2.2__tar.gz → 1.0.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.
- {deployproof-0.2.2/src/deployproof.egg-info → deployproof-1.0.0}/PKG-INFO +68 -13
- {deployproof-0.2.2 → deployproof-1.0.0}/README.md +67 -12
- {deployproof-0.2.2 → deployproof-1.0.0}/pyproject.toml +1 -1
- {deployproof-0.2.2 → deployproof-1.0.0}/src/deployproof/__init__.py +1 -1
- {deployproof-0.2.2 → deployproof-1.0.0}/src/deployproof/cli.py +23 -11
- {deployproof-0.2.2 → deployproof-1.0.0}/src/deployproof/control_flow.py +7 -2
- deployproof-1.0.0/src/deployproof/coverage_plugin.py +14 -0
- {deployproof-0.2.2 → deployproof-1.0.0}/src/deployproof/dependencies.py +73 -6
- {deployproof-0.2.2 → deployproof-1.0.0}/src/deployproof/diff.py +87 -2
- {deployproof-0.2.2 → deployproof-1.0.0}/src/deployproof/mocks.py +6 -4
- deployproof-1.0.0/src/deployproof/mutator.py +1836 -0
- {deployproof-0.2.2 → deployproof-1.0.0}/src/deployproof/reporter.py +7 -3
- {deployproof-0.2.2 → deployproof-1.0.0/src/deployproof.egg-info}/PKG-INFO +68 -13
- {deployproof-0.2.2 → deployproof-1.0.0}/src/deployproof.egg-info/SOURCES.txt +2 -0
- {deployproof-0.2.2 → deployproof-1.0.0}/tests/test_cli.py +68 -3
- {deployproof-0.2.2 → deployproof-1.0.0}/tests/test_dependencies_extractor.py +39 -0
- {deployproof-0.2.2 → deployproof-1.0.0}/tests/test_diff.py +63 -0
- deployproof-1.0.0/tests/test_import_graph_discovery.py +62 -0
- {deployproof-0.2.2 → deployproof-1.0.0}/tests/test_mutator.py +326 -7
- {deployproof-0.2.2 → deployproof-1.0.0}/tests/test_wsl.py +3 -1
- deployproof-0.2.2/src/deployproof/mutator.py +0 -757
- {deployproof-0.2.2 → deployproof-1.0.0}/LICENSE +0 -0
- {deployproof-0.2.2 → deployproof-1.0.0}/setup.cfg +0 -0
- {deployproof-0.2.2 → deployproof-1.0.0}/src/deployproof/secrets.py +0 -0
- {deployproof-0.2.2 → deployproof-1.0.0}/src/deployproof/symlinks.py +0 -0
- {deployproof-0.2.2 → deployproof-1.0.0}/src/deployproof/wsl.py +0 -0
- {deployproof-0.2.2 → deployproof-1.0.0}/src/deployproof.egg-info/dependency_links.txt +0 -0
- {deployproof-0.2.2 → deployproof-1.0.0}/src/deployproof.egg-info/entry_points.txt +0 -0
- {deployproof-0.2.2 → deployproof-1.0.0}/src/deployproof.egg-info/requires.txt +0 -0
- {deployproof-0.2.2 → deployproof-1.0.0}/src/deployproof.egg-info/top_level.txt +0 -0
- {deployproof-0.2.2 → deployproof-1.0.0}/tests/test_baseline_collection_error.py +0 -0
- {deployproof-0.2.2 → deployproof-1.0.0}/tests/test_cli_dependency_scan.py +0 -0
- {deployproof-0.2.2 → deployproof-1.0.0}/tests/test_control_flow.py +0 -0
- {deployproof-0.2.2 → deployproof-1.0.0}/tests/test_dependencies_pypi.py +0 -0
- {deployproof-0.2.2 → deployproof-1.0.0}/tests/test_edge_cases_validation.py +0 -0
- {deployproof-0.2.2 → deployproof-1.0.0}/tests/test_mocks.py +0 -0
- {deployproof-0.2.2 → deployproof-1.0.0}/tests/test_mutation_suites.py +0 -0
- {deployproof-0.2.2 → deployproof-1.0.0}/tests/test_secrets.py +0 -0
- {deployproof-0.2.2 → deployproof-1.0.0}/tests/test_stress_regressions.py +0 -0
- {deployproof-0.2.2 → deployproof-1.0.0}/tests/test_symlinks.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: deployproof
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 1.0.0
|
|
4
4
|
Summary: A deterministic AI-code deployability checker that catches what coverage misses.
|
|
5
5
|
Author-email: SVS Praveen <svspraveens@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -32,10 +32,10 @@ Dynamic: license-file
|
|
|
32
32
|
|
|
33
33
|
> Deterministic pre-push verification for AI-assisted codebases: AST mutation testing, credential scanning, sandbox-escape detection, mock-usage alerts, swallowed-exception checks, and dependency hallucination defense.
|
|
34
34
|
|
|
35
|
-
[](https://pypi.org/project/deployproof/)
|
|
36
36
|
[](https://pypi.org/project/deployproof/)
|
|
37
37
|
[](https://github.com/SVSPraveen/DeployProof/actions/workflows/ci.yml)
|
|
38
|
-
[](https://github.com/SVSPraveen/DeployProof)
|
|
39
39
|
[](stress_fixtures/)
|
|
40
40
|
[](LICENSE)
|
|
41
41
|
|
|
@@ -45,6 +45,8 @@ Dynamic: license-file
|
|
|
45
45
|
|
|
46
46
|
AI-assisted development introduces subtle failure modes that standard linters and coverage tools miss: test suites with high line coverage but near-zero mutation scores, hardcoded credentials generated in passing, symlinks that deceive approval prompts into escaping the repository sandbox, silently swallowed exceptions, and package names hallucinated by LLMs that don't exist on PyPI. DeployProof catches these at the pre-push stage, before they reach CI or production.
|
|
47
47
|
|
|
48
|
+
> **Privacy & Security Guarantee**: DeployProof runs 100% locally on your machine. It makes zero outbound network calls, except for querying the official PyPI registry (JSON API) to verify that newly introduced dependencies exist and are not hallucinated. DeployProof sends no source code, telemetry, test results, or secret findings to any external server.
|
|
49
|
+
|
|
48
50
|
## Install
|
|
49
51
|
|
|
50
52
|
```bash
|
|
@@ -53,20 +55,70 @@ pip install deployproof
|
|
|
53
55
|
|
|
54
56
|
Requires Python 3.10+.
|
|
55
57
|
|
|
56
|
-
##
|
|
58
|
+
## How to Use DeployProof
|
|
59
|
+
|
|
60
|
+
DeployProof provides two distinct modes of operation. We believe in total transparency about execution costs:
|
|
57
61
|
|
|
58
|
-
|
|
62
|
+
### 1. Diff-Scoped Pre-Push Gate (`deployproof check`) — *Primary Fast Workflow*
|
|
63
|
+
Evaluates **only the files modified in your active session or git diff** (1–3 files typically). Because only newly edited AST nodes are mutated, it executes in **2 to 5 seconds** in local developer loops, pre-commit hooks, and pre-push gates.
|
|
59
64
|
|
|
60
65
|
```bash
|
|
61
|
-
|
|
66
|
+
# Fast daily check: verifies modified files in your current working tree / git diff (2-5s)
|
|
67
|
+
deployproof check
|
|
68
|
+
|
|
69
|
+
# Output structured JSON for automation or IDE tooling
|
|
70
|
+
deployproof check --json
|
|
71
|
+
|
|
72
|
+
# Enforce strict gates on newly introduced mocks or swallowed errors
|
|
73
|
+
deployproof check --strict-mocks --strict-error-handling
|
|
62
74
|
```
|
|
63
75
|
|
|
64
|
-
|
|
76
|
+
### 2. Full Repository Audit Mode (`deployproof check --full-repo`) — *Thorough Codebase Audits*
|
|
77
|
+
Evaluates **every tracked Python file across the entire repository**. Because mutation testing generates hundreds or thousands of mutants and runs the test suite against each one in isolated multi-worker sandboxes, full repository scans take real, honest compute time:
|
|
65
78
|
|
|
66
79
|
```bash
|
|
67
|
-
|
|
80
|
+
# Run a full-repository audit across all tracked files
|
|
81
|
+
deployproof check --full-repo
|
|
82
|
+
|
|
83
|
+
# Customize the parallel worker process count (defaults to auto-detected CPU count capped at 8)
|
|
84
|
+
deployproof check --full-repo --workers 8
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
#### Real-World Timing Expectations:
|
|
88
|
+
| Scan Mode | Target Scope | Typical Duration | Intended Use Case |
|
|
89
|
+
| :--- | :--- | :--- | :--- |
|
|
90
|
+
| **`deployproof check`** | Git Diff (1–3 modified files) | **2 – 5 seconds** | Local pre-commit, active AI IDE coding loops, pre-push sanity checks. |
|
|
91
|
+
| **`deployproof check --workers 8`** | Large Multi-File Diff (100+ mutants) | **1 – 3 minutes** | Large feature branch reviews, refactors. |
|
|
92
|
+
| **`deployproof check --full-repo`** | Small Repo (< 100 mutants) | **30s – 2 minutes** | Initial repo onboarding, weekly audits. |
|
|
93
|
+
| **`deployproof check --full-repo`** | Medium Repo (200–500 mutants) | **5 – 15 minutes** | Release validation, scheduled CI jobs. |
|
|
94
|
+
| **`deployproof check --full-repo`** | Heavy / Network Lib (`requests`, 800 mutants) | **60 – 85 minutes** | Deep occasional audit sweeps. |
|
|
95
|
+
|
|
96
|
+
### Parallel Multi-Worker Sandboxing (`--workers N`)
|
|
97
|
+
|
|
98
|
+
DeployProof includes a built-in multi-process execution engine (`ProcessPoolExecutor`) for parallel mutation testing. You can supply `--workers <N>` to both diff-scoped checks and full-repo audits:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
# Parallelize a large uncommitted diff across 8 worker processes
|
|
102
|
+
deployproof check --workers 8
|
|
103
|
+
|
|
104
|
+
# Full repository audit distributed across 8 worker processes
|
|
105
|
+
deployproof check --full-repo --workers 8
|
|
68
106
|
```
|
|
69
107
|
|
|
108
|
+
#### How Parallel Sandboxing Works:
|
|
109
|
+
1. **Snapshot Creation**: DeployProof takes an initial atomic snapshot of your project into a clean temporary directory.
|
|
110
|
+
2. **PID-Keyed Sandboxes**: Each worker process receives its own dedicated filesystem sandbox (`worker_<PID>`), with an independent `pytest` cache (`--override-ini=cache_dir=...`) and separate temporary directory (`--basetemp=...`).
|
|
111
|
+
3. **Zero Mutation Leaks**: Mutants are generated and executed inside individual worker sandboxes in parallel. The working tree is untouched, and signal handlers (`SIGINT`, `SIGTERM`, `SIGBREAK`) ensure sandboxes are cleanly purged upon completion or interruption.
|
|
112
|
+
|
|
113
|
+
#### Advantages & When to Use:
|
|
114
|
+
* **Large Diff / Full Repo Speedup**: Near-linear execution scaling across CPU cores for batches with 50+ mutants, cutting 30-minute sweeps down to 5–8 minutes.
|
|
115
|
+
* **Process & Cache Isolation**: Eliminates cross-test state leakage, shared database locking, and `.pytest_cache` collisions between concurrent workers.
|
|
116
|
+
|
|
117
|
+
#### Trade-offs & When NOT to Use:
|
|
118
|
+
* **Small Daily Diffs (1–3 files)**: Do NOT use `--workers` for small 2-line edits. Spawning isolated sandboxes and copying file trees incurs ~1–2 seconds of snapshot overhead. Sequential in-place mutation executes in **2–5 seconds** with zero snapshot overhead.
|
|
119
|
+
* **Disk Space & I/O Overhead**: Running $N$ workers copies the repository snapshot $N$ times into temporary storage ($N \times \text{repo size}$ in `tempfile.gettempdir()`). On disk-constrained environments, use fewer workers (e.g. `--workers 2` or `--workers 4`).
|
|
120
|
+
* **Subprocess / Port Collisions**: If your test suite binds to fixed network ports (e.g. localhost:8080) without dynamic port selection, parallel workers running tests concurrently may trigger port conflicts. Use isolated ports or run sequentially in such environments.
|
|
121
|
+
|
|
70
122
|
Output includes a section for each check — symlink scan, secrets scan, dependency scan, mock detection, control flow analysis, and mutation score — with a pass/fail line at the bottom.
|
|
71
123
|
|
|
72
124
|
### Exit Codes:
|
|
@@ -173,6 +225,8 @@ Pre-check clean: 100% of tested basic mutations caught.
|
|
|
173
225
|
| `deployproof check --files <paths...>` | Explicitly evaluate specific files (bypasses git diff). |
|
|
174
226
|
| `deployproof check --threshold <float>` | Minimum mutation score percentage required to pass (default: `80.0`). |
|
|
175
227
|
| `deployproof check --base <ref>` | Base git ref (branch/commit/tag) to diff against. |
|
|
228
|
+
| `deployproof check --full-repo` | Audit all tracked files across the entire repository root (respecting `.gitignore`), using isolated parallel workers. |
|
|
229
|
+
| `deployproof check --workers <int>` | Set the number of isolated parallel worker processes for `--full-repo` scans (default: auto-detected CPU count capped at 8). |
|
|
176
230
|
| `deployproof check --wsl` | Delegate mutation testing to `mutmut` inside WSL (Windows only). |
|
|
177
231
|
|
|
178
232
|
> **Note:** `deployproof check --wsl` (Windows only) is newer and less battle-tested than the core checks — [file an issue](https://github.com/SVSPraveen/DeployProof/issues) if you hit something.
|
|
@@ -189,7 +243,7 @@ deployproof check --json
|
|
|
189
243
|
|
|
190
244
|
```json
|
|
191
245
|
{
|
|
192
|
-
"version": "0.
|
|
246
|
+
"version": "1.0.0",
|
|
193
247
|
"status": "passed",
|
|
194
248
|
"summary": {
|
|
195
249
|
"target_files_count": 1,
|
|
@@ -270,9 +324,9 @@ deployproof check --json
|
|
|
270
324
|
- **Control Flow and Error Handling** — AST-based detector for bare `except:` without re-raise, silently swallowed broad exceptions (`except Exception:` that only `pass` or log/print without re-raising or returning error indicators), and dead/unreachable code following unconditional `return`, `raise`, `break`, or `continue`, with an optional `--strict-error-handling` hard gate.
|
|
271
325
|
|
|
272
326
|
## What This Doesn't Do
|
|
273
|
-
|
|
327
|
+
|
|
274
328
|
- **Test-only diffs are not yet caught.** If a diff modifies or weakens assertions in a test file without changing the corresponding source file, DeployProof currently sees zero modified source lines and passes with 0 mutants evaluated. This is a known gap — see [INVESTIGATION_blastradius.md](INVESTIGATION_blastradius.md) for the reverse-mapping approach being evaluated to close it. Until this lands, DeployProof does not protect against test suites being weakened directly.
|
|
275
|
-
- **
|
|
329
|
+
- **Diff-scoping vs Full Audits:** Standard `deployproof check` is intentionally scoped strictly to files modified in the active git diff (for 2–5s speed). To audit every file in the entire repository, explicitly pass the `--full-repo` flag.
|
|
276
330
|
- **Python only.** Mutation testing and import extraction currently support Python files only. Other languages are not scanned.
|
|
277
331
|
- **No auto-fix.** DeployProof reports findings; it does not modify your code, rewrite imports, or suggest patches.
|
|
278
332
|
- **No IDE plugin yet.** There is no VS Code extension or JetBrains plugin. The CLI is the interface. IDE integration is on the roadmap.
|
|
@@ -289,8 +343,8 @@ Fixtures cover weak test suites, zero-test orphan modules, planted OpenAI/AWS cr
|
|
|
289
343
|
|
|
290
344
|
## Status & Roadmap
|
|
291
345
|
|
|
292
|
-
- **Current (
|
|
293
|
-
- **Next:**
|
|
346
|
+
- **Current (v1.0.0):** Diff-scoped AST mutation testing (with recursive discovery and `SIGINT`/`SIGTERM`/`SIGBREAK` signal-safe disk restoration), **Full Repository Audit Mode (`--full-repo`)** with isolated parallel multi-worker sandboxes and AST import-graph test discovery, baseline test-collection failure isolation with distinct exit code `2`, entropy-driven value-based secrets scanner, GhostApproval symlink sandbox-escape detector, PyPI dependency hallucination / slopsquatting scanner (with import-to-distribution translation, recursive `-r` requirements scanning, and dynamic import detection via `importlib` / `__import__`), mock-introduction detector (`--strict-mocks`), control-flow / swallowed-exception scanner (`--strict-error-handling`), 11/11 launch-day stress test suite, **111 unit tests**, live unbuffered progress streaming, and machine-readable `--json` output.
|
|
347
|
+
- **Next:** Reverse test-to-source dependency mapping (see `FUTURE_SCOPE.md`), SARIF 2.1.0 PR annotations, and multi-language mutation rule packs.
|
|
294
348
|
|
|
295
349
|
## Contributing
|
|
296
350
|
|
|
@@ -303,3 +357,4 @@ MIT. See [LICENSE](LICENSE).
|
|
|
303
357
|
---
|
|
304
358
|
|
|
305
359
|
*Created by [SVS Praveen](https://github.com/SVSPraveen) · [Portfolio](https://svspraveen.vercel.app/) · [LinkedIn](https://www.linkedin.com/in/svs-praveen-s/)*
|
|
360
|
+
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
> Deterministic pre-push verification for AI-assisted codebases: AST mutation testing, credential scanning, sandbox-escape detection, mock-usage alerts, swallowed-exception checks, and dependency hallucination defense.
|
|
4
4
|
|
|
5
|
-
[](https://pypi.org/project/deployproof/)
|
|
6
6
|
[](https://pypi.org/project/deployproof/)
|
|
7
7
|
[](https://github.com/SVSPraveen/DeployProof/actions/workflows/ci.yml)
|
|
8
|
-
[](https://github.com/SVSPraveen/DeployProof)
|
|
9
9
|
[](stress_fixtures/)
|
|
10
10
|
[](LICENSE)
|
|
11
11
|
|
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
|
|
16
16
|
AI-assisted development introduces subtle failure modes that standard linters and coverage tools miss: test suites with high line coverage but near-zero mutation scores, hardcoded credentials generated in passing, symlinks that deceive approval prompts into escaping the repository sandbox, silently swallowed exceptions, and package names hallucinated by LLMs that don't exist on PyPI. DeployProof catches these at the pre-push stage, before they reach CI or production.
|
|
17
17
|
|
|
18
|
+
> **Privacy & Security Guarantee**: DeployProof runs 100% locally on your machine. It makes zero outbound network calls, except for querying the official PyPI registry (JSON API) to verify that newly introduced dependencies exist and are not hallucinated. DeployProof sends no source code, telemetry, test results, or secret findings to any external server.
|
|
19
|
+
|
|
18
20
|
## Install
|
|
19
21
|
|
|
20
22
|
```bash
|
|
@@ -23,20 +25,70 @@ pip install deployproof
|
|
|
23
25
|
|
|
24
26
|
Requires Python 3.10+.
|
|
25
27
|
|
|
26
|
-
##
|
|
28
|
+
## How to Use DeployProof
|
|
29
|
+
|
|
30
|
+
DeployProof provides two distinct modes of operation. We believe in total transparency about execution costs:
|
|
27
31
|
|
|
28
|
-
|
|
32
|
+
### 1. Diff-Scoped Pre-Push Gate (`deployproof check`) — *Primary Fast Workflow*
|
|
33
|
+
Evaluates **only the files modified in your active session or git diff** (1–3 files typically). Because only newly edited AST nodes are mutated, it executes in **2 to 5 seconds** in local developer loops, pre-commit hooks, and pre-push gates.
|
|
29
34
|
|
|
30
35
|
```bash
|
|
31
|
-
|
|
36
|
+
# Fast daily check: verifies modified files in your current working tree / git diff (2-5s)
|
|
37
|
+
deployproof check
|
|
38
|
+
|
|
39
|
+
# Output structured JSON for automation or IDE tooling
|
|
40
|
+
deployproof check --json
|
|
41
|
+
|
|
42
|
+
# Enforce strict gates on newly introduced mocks or swallowed errors
|
|
43
|
+
deployproof check --strict-mocks --strict-error-handling
|
|
32
44
|
```
|
|
33
45
|
|
|
34
|
-
|
|
46
|
+
### 2. Full Repository Audit Mode (`deployproof check --full-repo`) — *Thorough Codebase Audits*
|
|
47
|
+
Evaluates **every tracked Python file across the entire repository**. Because mutation testing generates hundreds or thousands of mutants and runs the test suite against each one in isolated multi-worker sandboxes, full repository scans take real, honest compute time:
|
|
35
48
|
|
|
36
49
|
```bash
|
|
37
|
-
|
|
50
|
+
# Run a full-repository audit across all tracked files
|
|
51
|
+
deployproof check --full-repo
|
|
52
|
+
|
|
53
|
+
# Customize the parallel worker process count (defaults to auto-detected CPU count capped at 8)
|
|
54
|
+
deployproof check --full-repo --workers 8
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
#### Real-World Timing Expectations:
|
|
58
|
+
| Scan Mode | Target Scope | Typical Duration | Intended Use Case |
|
|
59
|
+
| :--- | :--- | :--- | :--- |
|
|
60
|
+
| **`deployproof check`** | Git Diff (1–3 modified files) | **2 – 5 seconds** | Local pre-commit, active AI IDE coding loops, pre-push sanity checks. |
|
|
61
|
+
| **`deployproof check --workers 8`** | Large Multi-File Diff (100+ mutants) | **1 – 3 minutes** | Large feature branch reviews, refactors. |
|
|
62
|
+
| **`deployproof check --full-repo`** | Small Repo (< 100 mutants) | **30s – 2 minutes** | Initial repo onboarding, weekly audits. |
|
|
63
|
+
| **`deployproof check --full-repo`** | Medium Repo (200–500 mutants) | **5 – 15 minutes** | Release validation, scheduled CI jobs. |
|
|
64
|
+
| **`deployproof check --full-repo`** | Heavy / Network Lib (`requests`, 800 mutants) | **60 – 85 minutes** | Deep occasional audit sweeps. |
|
|
65
|
+
|
|
66
|
+
### Parallel Multi-Worker Sandboxing (`--workers N`)
|
|
67
|
+
|
|
68
|
+
DeployProof includes a built-in multi-process execution engine (`ProcessPoolExecutor`) for parallel mutation testing. You can supply `--workers <N>` to both diff-scoped checks and full-repo audits:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
# Parallelize a large uncommitted diff across 8 worker processes
|
|
72
|
+
deployproof check --workers 8
|
|
73
|
+
|
|
74
|
+
# Full repository audit distributed across 8 worker processes
|
|
75
|
+
deployproof check --full-repo --workers 8
|
|
38
76
|
```
|
|
39
77
|
|
|
78
|
+
#### How Parallel Sandboxing Works:
|
|
79
|
+
1. **Snapshot Creation**: DeployProof takes an initial atomic snapshot of your project into a clean temporary directory.
|
|
80
|
+
2. **PID-Keyed Sandboxes**: Each worker process receives its own dedicated filesystem sandbox (`worker_<PID>`), with an independent `pytest` cache (`--override-ini=cache_dir=...`) and separate temporary directory (`--basetemp=...`).
|
|
81
|
+
3. **Zero Mutation Leaks**: Mutants are generated and executed inside individual worker sandboxes in parallel. The working tree is untouched, and signal handlers (`SIGINT`, `SIGTERM`, `SIGBREAK`) ensure sandboxes are cleanly purged upon completion or interruption.
|
|
82
|
+
|
|
83
|
+
#### Advantages & When to Use:
|
|
84
|
+
* **Large Diff / Full Repo Speedup**: Near-linear execution scaling across CPU cores for batches with 50+ mutants, cutting 30-minute sweeps down to 5–8 minutes.
|
|
85
|
+
* **Process & Cache Isolation**: Eliminates cross-test state leakage, shared database locking, and `.pytest_cache` collisions between concurrent workers.
|
|
86
|
+
|
|
87
|
+
#### Trade-offs & When NOT to Use:
|
|
88
|
+
* **Small Daily Diffs (1–3 files)**: Do NOT use `--workers` for small 2-line edits. Spawning isolated sandboxes and copying file trees incurs ~1–2 seconds of snapshot overhead. Sequential in-place mutation executes in **2–5 seconds** with zero snapshot overhead.
|
|
89
|
+
* **Disk Space & I/O Overhead**: Running $N$ workers copies the repository snapshot $N$ times into temporary storage ($N \times \text{repo size}$ in `tempfile.gettempdir()`). On disk-constrained environments, use fewer workers (e.g. `--workers 2` or `--workers 4`).
|
|
90
|
+
* **Subprocess / Port Collisions**: If your test suite binds to fixed network ports (e.g. localhost:8080) without dynamic port selection, parallel workers running tests concurrently may trigger port conflicts. Use isolated ports or run sequentially in such environments.
|
|
91
|
+
|
|
40
92
|
Output includes a section for each check — symlink scan, secrets scan, dependency scan, mock detection, control flow analysis, and mutation score — with a pass/fail line at the bottom.
|
|
41
93
|
|
|
42
94
|
### Exit Codes:
|
|
@@ -143,6 +195,8 @@ Pre-check clean: 100% of tested basic mutations caught.
|
|
|
143
195
|
| `deployproof check --files <paths...>` | Explicitly evaluate specific files (bypasses git diff). |
|
|
144
196
|
| `deployproof check --threshold <float>` | Minimum mutation score percentage required to pass (default: `80.0`). |
|
|
145
197
|
| `deployproof check --base <ref>` | Base git ref (branch/commit/tag) to diff against. |
|
|
198
|
+
| `deployproof check --full-repo` | Audit all tracked files across the entire repository root (respecting `.gitignore`), using isolated parallel workers. |
|
|
199
|
+
| `deployproof check --workers <int>` | Set the number of isolated parallel worker processes for `--full-repo` scans (default: auto-detected CPU count capped at 8). |
|
|
146
200
|
| `deployproof check --wsl` | Delegate mutation testing to `mutmut` inside WSL (Windows only). |
|
|
147
201
|
|
|
148
202
|
> **Note:** `deployproof check --wsl` (Windows only) is newer and less battle-tested than the core checks — [file an issue](https://github.com/SVSPraveen/DeployProof/issues) if you hit something.
|
|
@@ -159,7 +213,7 @@ deployproof check --json
|
|
|
159
213
|
|
|
160
214
|
```json
|
|
161
215
|
{
|
|
162
|
-
"version": "0.
|
|
216
|
+
"version": "1.0.0",
|
|
163
217
|
"status": "passed",
|
|
164
218
|
"summary": {
|
|
165
219
|
"target_files_count": 1,
|
|
@@ -240,9 +294,9 @@ deployproof check --json
|
|
|
240
294
|
- **Control Flow and Error Handling** — AST-based detector for bare `except:` without re-raise, silently swallowed broad exceptions (`except Exception:` that only `pass` or log/print without re-raising or returning error indicators), and dead/unreachable code following unconditional `return`, `raise`, `break`, or `continue`, with an optional `--strict-error-handling` hard gate.
|
|
241
295
|
|
|
242
296
|
## What This Doesn't Do
|
|
243
|
-
|
|
297
|
+
|
|
244
298
|
- **Test-only diffs are not yet caught.** If a diff modifies or weakens assertions in a test file without changing the corresponding source file, DeployProof currently sees zero modified source lines and passes with 0 mutants evaluated. This is a known gap — see [INVESTIGATION_blastradius.md](INVESTIGATION_blastradius.md) for the reverse-mapping approach being evaluated to close it. Until this lands, DeployProof does not protect against test suites being weakened directly.
|
|
245
|
-
- **
|
|
299
|
+
- **Diff-scoping vs Full Audits:** Standard `deployproof check` is intentionally scoped strictly to files modified in the active git diff (for 2–5s speed). To audit every file in the entire repository, explicitly pass the `--full-repo` flag.
|
|
246
300
|
- **Python only.** Mutation testing and import extraction currently support Python files only. Other languages are not scanned.
|
|
247
301
|
- **No auto-fix.** DeployProof reports findings; it does not modify your code, rewrite imports, or suggest patches.
|
|
248
302
|
- **No IDE plugin yet.** There is no VS Code extension or JetBrains plugin. The CLI is the interface. IDE integration is on the roadmap.
|
|
@@ -259,8 +313,8 @@ Fixtures cover weak test suites, zero-test orphan modules, planted OpenAI/AWS cr
|
|
|
259
313
|
|
|
260
314
|
## Status & Roadmap
|
|
261
315
|
|
|
262
|
-
- **Current (
|
|
263
|
-
- **Next:**
|
|
316
|
+
- **Current (v1.0.0):** Diff-scoped AST mutation testing (with recursive discovery and `SIGINT`/`SIGTERM`/`SIGBREAK` signal-safe disk restoration), **Full Repository Audit Mode (`--full-repo`)** with isolated parallel multi-worker sandboxes and AST import-graph test discovery, baseline test-collection failure isolation with distinct exit code `2`, entropy-driven value-based secrets scanner, GhostApproval symlink sandbox-escape detector, PyPI dependency hallucination / slopsquatting scanner (with import-to-distribution translation, recursive `-r` requirements scanning, and dynamic import detection via `importlib` / `__import__`), mock-introduction detector (`--strict-mocks`), control-flow / swallowed-exception scanner (`--strict-error-handling`), 11/11 launch-day stress test suite, **111 unit tests**, live unbuffered progress streaming, and machine-readable `--json` output.
|
|
317
|
+
- **Next:** Reverse test-to-source dependency mapping (see `FUTURE_SCOPE.md`), SARIF 2.1.0 PR annotations, and multi-language mutation rule packs.
|
|
264
318
|
|
|
265
319
|
## Contributing
|
|
266
320
|
|
|
@@ -273,3 +327,4 @@ MIT. See [LICENSE](LICENSE).
|
|
|
273
327
|
---
|
|
274
328
|
|
|
275
329
|
*Created by [SVS Praveen](https://github.com/SVSPraveen) · [Portfolio](https://svspraveen.vercel.app/) · [LinkedIn](https://www.linkedin.com/in/svs-praveen-s/)*
|
|
330
|
+
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "deployproof"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "1.0.0"
|
|
8
8
|
description = "A deterministic AI-code deployability checker that catches what coverage misses."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""DeployProof - Deterministic AI-Code Deployability Checker."""
|
|
2
|
-
__version__ = "0.
|
|
2
|
+
__version__ = "1.0.0"
|
|
@@ -6,9 +6,9 @@ from typing import List, Optional
|
|
|
6
6
|
from deployproof import __version__
|
|
7
7
|
from deployproof.dependencies import extract_all_new_dependencies, scan_dependencies
|
|
8
8
|
from deployproof.control_flow import scan_session_files_for_control_flow
|
|
9
|
-
from deployproof.diff import DiffScopeError, InvalidBaseRefError, NotAGitRepositoryError, get_git_root, is_test_file, resolve_changed_python_files, resolve_changed_session_files
|
|
9
|
+
from deployproof.diff import DiffScopeError, InvalidBaseRefError, NotAGitRepositoryError, get_git_root, is_excluded_mutation_target, is_test_file, resolve_changed_python_files, resolve_changed_session_files, resolve_full_repo_session_files
|
|
10
10
|
from deployproof.mocks import scan_session_files_for_mocks
|
|
11
|
-
from deployproof.mutator import run_mutation_tests
|
|
11
|
+
from deployproof.mutator import cleanup_stale_deployproof_temp_dirs, run_mutation_tests
|
|
12
12
|
from deployproof.reporter import LARGE_FILE_LOC_THRESHOLD, format_json_report, format_report
|
|
13
13
|
from deployproof.secrets import scan_session_files_for_secrets
|
|
14
14
|
from deployproof.symlinks import scan_session_files_for_symlinks
|
|
@@ -20,6 +20,8 @@ def create_parser() -> argparse.ArgumentParser:
|
|
|
20
20
|
parser.add_argument('-v', '--version', action='version', version=f'%(prog)s {__version__}', help="Show program's version number and exit.")
|
|
21
21
|
subparsers = parser.add_subparsers(dest='command', help='Available commands')
|
|
22
22
|
check_parser = subparsers.add_parser('check', help='Run deployability verification checks against session changes.')
|
|
23
|
+
check_parser.add_argument('--full-repo', action='store_true', default=False, help='Scan all files in repository respecting .gitignore instead of diff-scoped session files.')
|
|
24
|
+
check_parser.add_argument('--workers', type=int, default=None, help='Number of parallel worker processes for --full-repo scan (default: auto, up to 8).')
|
|
23
25
|
check_parser.add_argument('--base', type=str, default=None, help='Base git ref (branch/commit/tag) to diff against.')
|
|
24
26
|
check_parser.add_argument('--files', nargs='+', type=str, default=None, help='Explicit files to evaluate (bypasses git diff).')
|
|
25
27
|
check_parser.add_argument('--tests', nargs='+', type=str, default=None, help='Specific test file(s) or directories to execute.')
|
|
@@ -34,8 +36,10 @@ def create_parser() -> argparse.ArgumentParser:
|
|
|
34
36
|
|
|
35
37
|
def handle_check(args: argparse.Namespace) -> int:
|
|
36
38
|
"""Handle the 'check' subcommand."""
|
|
39
|
+
cleanup_stale_deployproof_temp_dirs()
|
|
37
40
|
cwd = Path.cwd().resolve()
|
|
38
41
|
repo_root: Optional[Path] = None
|
|
42
|
+
is_full_repo = getattr(args, 'full_repo', False)
|
|
39
43
|
try:
|
|
40
44
|
if args.files:
|
|
41
45
|
session_files = [Path(f).resolve() for f in args.files]
|
|
@@ -46,6 +50,14 @@ def handle_check(args: argparse.Namespace) -> int:
|
|
|
46
50
|
repo_root = session_files[0].parent
|
|
47
51
|
else:
|
|
48
52
|
repo_root = cwd
|
|
53
|
+
elif is_full_repo:
|
|
54
|
+
try:
|
|
55
|
+
repo_root = get_git_root(cwd)
|
|
56
|
+
except DiffScopeError:
|
|
57
|
+
repo_root = cwd
|
|
58
|
+
if not getattr(args, 'json', False):
|
|
59
|
+
print('Notice: Full repo scan active — evaluating all repository files (this may take significantly longer than a diff-scoped check).\n')
|
|
60
|
+
session_files = resolve_full_repo_session_files(cwd=cwd)
|
|
49
61
|
else:
|
|
50
62
|
repo_root = get_git_root(cwd)
|
|
51
63
|
session_files = resolve_changed_session_files(cwd=cwd, base=args.base)
|
|
@@ -69,15 +81,15 @@ def handle_check(args: argparse.Namespace) -> int:
|
|
|
69
81
|
return 0
|
|
70
82
|
symlink_result = scan_session_files_for_symlinks(session_files, repo_root=repo_root or cwd)
|
|
71
83
|
secrets_result = scan_session_files_for_secrets(session_files)
|
|
72
|
-
extracted_deps = extract_all_new_dependencies(session_files, root=repo_root or cwd, base=args.base)
|
|
84
|
+
extracted_deps = extract_all_new_dependencies(session_files, root=repo_root or cwd, base=args.base, full_repo=is_full_repo)
|
|
73
85
|
dependency_result = scan_dependencies(extracted_deps)
|
|
74
|
-
mock_result = scan_session_files_for_mocks(session_files=session_files, root=repo_root or cwd, base=args.base)
|
|
75
|
-
control_flow_result = scan_session_files_for_control_flow(session_files=session_files, root=repo_root or cwd, base=args.base)
|
|
86
|
+
mock_result = scan_session_files_for_mocks(session_files=session_files, root=repo_root or cwd, base=args.base, full_repo=is_full_repo)
|
|
87
|
+
control_flow_result = scan_session_files_for_control_flow(session_files=session_files, root=repo_root or cwd, base=args.base, full_repo=is_full_repo)
|
|
76
88
|
if args.files:
|
|
77
|
-
|
|
78
|
-
target_files =
|
|
89
|
+
non_excluded_files = [f for f in session_files if f.is_file() and f.suffix == '.py' and (not is_excluded_mutation_target(f, repo_root or cwd))]
|
|
90
|
+
target_files = non_excluded_files if non_excluded_files else [f for f in session_files if f.is_file() and f.suffix == '.py']
|
|
79
91
|
else:
|
|
80
|
-
target_files = [f for f in session_files if f.is_file() and f.suffix == '.py' and (not
|
|
92
|
+
target_files = [f for f in session_files if f.is_file() and f.suffix == '.py' and (not is_excluded_mutation_target(f, repo_root or cwd))]
|
|
81
93
|
if not getattr(args, 'json', False):
|
|
82
94
|
for f in target_files:
|
|
83
95
|
try:
|
|
@@ -107,7 +119,7 @@ def handle_check(args: argparse.Namespace) -> int:
|
|
|
107
119
|
elif not getattr(args, 'json', False):
|
|
108
120
|
print(wsl_msg)
|
|
109
121
|
print('-' * 68)
|
|
110
|
-
result = run_mutation_tests(target_files=target_files, repo_root=repo_root or cwd, test_runner_timeout=args.timeout, extra_pytest_args=args.tests)
|
|
122
|
+
result = run_mutation_tests(target_files=target_files, repo_root=repo_root or cwd, test_runner_timeout=args.timeout, extra_pytest_args=args.tests, workers=getattr(args, 'workers', None), is_full_repo=is_full_repo, base=args.base, quiet=getattr(args, 'json', False))
|
|
111
123
|
if getattr(args, 'json', False):
|
|
112
124
|
report_text = format_json_report(result=result, target_files=target_files, secrets_result=secrets_result, symlink_result=symlink_result, dependency_result=dependency_result, mock_result=mock_result, control_flow_result=control_flow_result, strict_mocks=getattr(args, 'strict_mocks', False), strict_error_handling=getattr(args, 'strict_error_handling', False), repo_root=repo_root or cwd, threshold=args.threshold, version=__version__)
|
|
113
125
|
else:
|
|
@@ -157,12 +169,12 @@ def main(argv: Optional[List[str]]=None) -> int:
|
|
|
157
169
|
"""Entry point for the DeployProof CLI."""
|
|
158
170
|
if hasattr(sys.stdout, 'reconfigure'):
|
|
159
171
|
try:
|
|
160
|
-
sys.stdout.reconfigure(errors='replace')
|
|
172
|
+
sys.stdout.reconfigure(line_buffering=True, errors='replace')
|
|
161
173
|
except Exception:
|
|
162
174
|
pass
|
|
163
175
|
if hasattr(sys.stderr, 'reconfigure'):
|
|
164
176
|
try:
|
|
165
|
-
sys.stderr.reconfigure(errors='replace')
|
|
177
|
+
sys.stderr.reconfigure(line_buffering=False, errors='replace')
|
|
166
178
|
except Exception:
|
|
167
179
|
pass
|
|
168
180
|
parser = create_parser()
|
|
@@ -216,6 +216,7 @@ def scan_file_for_control_flow(
|
|
|
216
216
|
file_path: Path,
|
|
217
217
|
root: Path,
|
|
218
218
|
base: Optional[str] = None,
|
|
219
|
+
full_repo: bool = False,
|
|
219
220
|
) -> List[ControlFlowFinding]:
|
|
220
221
|
"""Scan a Python file for bare excepts, swallowed exceptions, and unreachable code."""
|
|
221
222
|
if not file_path.is_file() or file_path.suffix != ".py":
|
|
@@ -227,7 +228,10 @@ def scan_file_for_control_flow(
|
|
|
227
228
|
except Exception:
|
|
228
229
|
return []
|
|
229
230
|
|
|
230
|
-
|
|
231
|
+
if full_repo:
|
|
232
|
+
modified_lines = None
|
|
233
|
+
else:
|
|
234
|
+
modified_lines = get_modified_line_ranges(file_path=file_path, root=root, base=base)
|
|
231
235
|
source_lines = source_code.splitlines()
|
|
232
236
|
|
|
233
237
|
scanner = ControlFlowScanner(
|
|
@@ -243,6 +247,7 @@ def scan_session_files_for_control_flow(
|
|
|
243
247
|
session_files: List[Path],
|
|
244
248
|
root: Path,
|
|
245
249
|
base: Optional[str] = None,
|
|
250
|
+
full_repo: bool = False,
|
|
246
251
|
) -> ControlFlowScanSummary:
|
|
247
252
|
"""Scan all modified session Python files for control flow and error handling issues."""
|
|
248
253
|
all_findings: List[ControlFlowFinding] = []
|
|
@@ -251,7 +256,7 @@ def scan_session_files_for_control_flow(
|
|
|
251
256
|
for f in session_files:
|
|
252
257
|
if f.is_file() and f.suffix == ".py":
|
|
253
258
|
scanned_files.append(f)
|
|
254
|
-
findings = scan_file_for_control_flow(file_path=f, root=root, base=base)
|
|
259
|
+
findings = scan_file_for_control_flow(file_path=f, root=root, base=base, full_repo=full_repo)
|
|
255
260
|
all_findings.extend(findings)
|
|
256
261
|
|
|
257
262
|
return ControlFlowScanSummary(
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""Pytest plugin for DeployProof coverage-guided test selection.
|
|
2
|
+
|
|
3
|
+
Switches coverage context to the current test nodeid during pytest execution,
|
|
4
|
+
allowing DeployProof to map each source line to the exact test cases covering it.
|
|
5
|
+
"""
|
|
6
|
+
try:
|
|
7
|
+
import coverage
|
|
8
|
+
|
|
9
|
+
def pytest_runtest_protocol(item, nextitem):
|
|
10
|
+
cov = coverage.Coverage.current()
|
|
11
|
+
if cov is not None:
|
|
12
|
+
cov.switch_context(item.nodeid)
|
|
13
|
+
except ImportError:
|
|
14
|
+
pass
|
|
@@ -229,6 +229,70 @@ STDLIB_MODULES: Set[str] = set(getattr(sys, "stdlib_module_names", set())) | {
|
|
|
229
229
|
"zoneinfo",
|
|
230
230
|
}
|
|
231
231
|
|
|
232
|
+
# Legacy Python 2 standard library modules (for compatibility shims and backports)
|
|
233
|
+
LEGACY_STDLIB_MODULES: Set[str] = {
|
|
234
|
+
"BaseHTTPServer",
|
|
235
|
+
"Bastion",
|
|
236
|
+
"CGIHTTPServer",
|
|
237
|
+
"ConfigParser",
|
|
238
|
+
"Cookie",
|
|
239
|
+
"DocXMLRPCServer",
|
|
240
|
+
"HTMLParser",
|
|
241
|
+
"MimeWriter",
|
|
242
|
+
"Queue",
|
|
243
|
+
"SimpleHTTPServer",
|
|
244
|
+
"SimpleXMLRPCServer",
|
|
245
|
+
"SocketServer",
|
|
246
|
+
"StringIO",
|
|
247
|
+
"UserDict",
|
|
248
|
+
"UserList",
|
|
249
|
+
"UserString",
|
|
250
|
+
"al",
|
|
251
|
+
"anydbm",
|
|
252
|
+
"cPickle",
|
|
253
|
+
"cStringIO",
|
|
254
|
+
"cd",
|
|
255
|
+
"commands",
|
|
256
|
+
"cookielib",
|
|
257
|
+
"copy_reg",
|
|
258
|
+
"dbhash",
|
|
259
|
+
"dumbdbm",
|
|
260
|
+
"dummy_thread",
|
|
261
|
+
"dummy_threading",
|
|
262
|
+
"fl",
|
|
263
|
+
"fm",
|
|
264
|
+
"fpformat",
|
|
265
|
+
"gdbm",
|
|
266
|
+
"gl",
|
|
267
|
+
"hotshot",
|
|
268
|
+
"htmlentitydefs",
|
|
269
|
+
"htmllib",
|
|
270
|
+
"httplib",
|
|
271
|
+
"imgfile",
|
|
272
|
+
"jpeg",
|
|
273
|
+
"md5",
|
|
274
|
+
"mimetools",
|
|
275
|
+
"mimify",
|
|
276
|
+
"mutex",
|
|
277
|
+
"new",
|
|
278
|
+
"posixfile",
|
|
279
|
+
"repr",
|
|
280
|
+
"rfc822",
|
|
281
|
+
"rotor",
|
|
282
|
+
"sets",
|
|
283
|
+
"sha",
|
|
284
|
+
"statvfs",
|
|
285
|
+
"sunaudio",
|
|
286
|
+
"sv",
|
|
287
|
+
"thread",
|
|
288
|
+
"urllib2",
|
|
289
|
+
"urlparse",
|
|
290
|
+
"whichdb",
|
|
291
|
+
"xmlrpclib",
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
STDLIB_MODULES = STDLIB_MODULES | LEGACY_STDLIB_MODULES
|
|
295
|
+
|
|
232
296
|
# Mapping of common top-level Python import names to their PyPI distribution package names
|
|
233
297
|
IMPORT_TO_PYPI_MAP: Dict[str, str] = {
|
|
234
298
|
"yaml": "PyYAML",
|
|
@@ -500,6 +564,7 @@ def extract_new_imports_from_py_file(
|
|
|
500
564
|
root: Path,
|
|
501
565
|
local_modules: Set[str],
|
|
502
566
|
base: Optional[str] = None,
|
|
567
|
+
full_repo: bool = False,
|
|
503
568
|
) -> List[ExtractedDependency]:
|
|
504
569
|
"""
|
|
505
570
|
Extract newly added external imports from a modified or new Python file.
|
|
@@ -515,7 +580,7 @@ def extract_new_imports_from_py_file(
|
|
|
515
580
|
except Exception:
|
|
516
581
|
return []
|
|
517
582
|
|
|
518
|
-
added_linenos = get_added_linenos_for_file(file_path, root, base=base)
|
|
583
|
+
added_linenos = None if full_repo else get_added_linenos_for_file(file_path, root, base=base)
|
|
519
584
|
extracted: List[ExtractedDependency] = []
|
|
520
585
|
seen: Set[str] = set()
|
|
521
586
|
|
|
@@ -778,6 +843,7 @@ def extract_new_manifest_dependencies(
|
|
|
778
843
|
root: Path,
|
|
779
844
|
local_modules: Optional[Set[str]] = None,
|
|
780
845
|
base: Optional[str] = None,
|
|
846
|
+
full_repo: bool = False,
|
|
781
847
|
) -> List[ExtractedDependency]:
|
|
782
848
|
"""
|
|
783
849
|
Extract external dependencies from modified manifest files (requirements.txt, pyproject.toml, etc.).
|
|
@@ -794,7 +860,7 @@ def extract_new_manifest_dependencies(
|
|
|
794
860
|
if not (is_requirements or is_pyproject or is_setup_py or is_setup_cfg):
|
|
795
861
|
return []
|
|
796
862
|
|
|
797
|
-
added_linenos = get_added_linenos_for_file(file_path, root, base=base)
|
|
863
|
+
added_linenos = None if full_repo else get_added_linenos_for_file(file_path, root, base=base)
|
|
798
864
|
|
|
799
865
|
if is_requirements:
|
|
800
866
|
return _parse_requirements_file(
|
|
@@ -892,9 +958,10 @@ def extract_all_new_dependencies(
|
|
|
892
958
|
session_files: List[Path],
|
|
893
959
|
root: Path,
|
|
894
960
|
base: Optional[str] = None,
|
|
961
|
+
full_repo: bool = False,
|
|
895
962
|
) -> List[ExtractedDependency]:
|
|
896
963
|
"""
|
|
897
|
-
Extract all
|
|
964
|
+
Extract all external dependencies from Python files and manifests.
|
|
898
965
|
"""
|
|
899
966
|
local_modules = get_local_module_names(root)
|
|
900
967
|
all_deps: List[ExtractedDependency] = []
|
|
@@ -902,14 +969,14 @@ def extract_all_new_dependencies(
|
|
|
902
969
|
|
|
903
970
|
for p in session_files:
|
|
904
971
|
if p.suffix == ".py":
|
|
905
|
-
py_deps = extract_new_imports_from_py_file(p, root, local_modules=local_modules, base=base)
|
|
972
|
+
py_deps = extract_new_imports_from_py_file(p, root, local_modules=local_modules, base=base, full_repo=full_repo)
|
|
906
973
|
for d in py_deps:
|
|
907
974
|
key = f"{d.name}:{d.source_file}:{d.lineno}"
|
|
908
975
|
if key not in seen_unique:
|
|
909
976
|
seen_unique.add(key)
|
|
910
977
|
all_deps.append(d)
|
|
911
978
|
else:
|
|
912
|
-
manifest_deps = extract_new_manifest_dependencies(p, root, local_modules=local_modules, base=base)
|
|
979
|
+
manifest_deps = extract_new_manifest_dependencies(p, root, local_modules=local_modules, base=base, full_repo=full_repo)
|
|
913
980
|
for d in manifest_deps:
|
|
914
981
|
key = f"{d.name}:{d.source_file}:{d.lineno}"
|
|
915
982
|
if key not in seen_unique:
|
|
@@ -983,7 +1050,7 @@ def query_pypi_registry(
|
|
|
983
1050
|
url = f"https://pypi.org/pypi/{canonical_pkg}/json"
|
|
984
1051
|
req = urllib.request.Request(
|
|
985
1052
|
url,
|
|
986
|
-
headers={"User-Agent": "DeployProof/0.
|
|
1053
|
+
headers={"User-Agent": "DeployProof/1.0.0 (https://github.com/SVSPraveen/DeployProof)"},
|
|
987
1054
|
)
|
|
988
1055
|
|
|
989
1056
|
try:
|