deployproof 1.0.1__tar.gz → 1.1.1__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-1.0.1/src/deployproof.egg-info → deployproof-1.1.1}/PKG-INFO +30 -10
- {deployproof-1.0.1 → deployproof-1.1.1}/README.md +27 -7
- {deployproof-1.0.1 → deployproof-1.1.1}/pyproject.toml +7 -5
- deployproof-1.1.1/src/deployproof/__init__.py +2 -0
- {deployproof-1.0.1 → deployproof-1.1.1}/src/deployproof/dependencies.py +6 -1
- {deployproof-1.0.1 → deployproof-1.1.1}/src/deployproof/reporter.py +4 -2
- {deployproof-1.0.1 → deployproof-1.1.1/src/deployproof.egg-info}/PKG-INFO +30 -10
- {deployproof-1.0.1 → deployproof-1.1.1}/tests/test_cli.py +5 -4
- deployproof-1.0.1/src/deployproof/__init__.py +0 -2
- {deployproof-1.0.1 → deployproof-1.1.1}/LICENSE +0 -0
- {deployproof-1.0.1 → deployproof-1.1.1}/setup.cfg +0 -0
- {deployproof-1.0.1 → deployproof-1.1.1}/src/deployproof/cli.py +0 -0
- {deployproof-1.0.1 → deployproof-1.1.1}/src/deployproof/control_flow.py +0 -0
- {deployproof-1.0.1 → deployproof-1.1.1}/src/deployproof/coverage_plugin.py +0 -0
- {deployproof-1.0.1 → deployproof-1.1.1}/src/deployproof/diff.py +0 -0
- {deployproof-1.0.1 → deployproof-1.1.1}/src/deployproof/mocks.py +0 -0
- {deployproof-1.0.1 → deployproof-1.1.1}/src/deployproof/mutator.py +0 -0
- {deployproof-1.0.1 → deployproof-1.1.1}/src/deployproof/secrets.py +0 -0
- {deployproof-1.0.1 → deployproof-1.1.1}/src/deployproof/symlinks.py +0 -0
- {deployproof-1.0.1 → deployproof-1.1.1}/src/deployproof/wsl.py +0 -0
- {deployproof-1.0.1 → deployproof-1.1.1}/src/deployproof.egg-info/SOURCES.txt +0 -0
- {deployproof-1.0.1 → deployproof-1.1.1}/src/deployproof.egg-info/dependency_links.txt +0 -0
- {deployproof-1.0.1 → deployproof-1.1.1}/src/deployproof.egg-info/entry_points.txt +0 -0
- {deployproof-1.0.1 → deployproof-1.1.1}/src/deployproof.egg-info/requires.txt +0 -0
- {deployproof-1.0.1 → deployproof-1.1.1}/src/deployproof.egg-info/top_level.txt +0 -0
- {deployproof-1.0.1 → deployproof-1.1.1}/tests/test_baseline_collection_error.py +0 -0
- {deployproof-1.0.1 → deployproof-1.1.1}/tests/test_cli_dependency_scan.py +0 -0
- {deployproof-1.0.1 → deployproof-1.1.1}/tests/test_control_flow.py +0 -0
- {deployproof-1.0.1 → deployproof-1.1.1}/tests/test_dependencies_extractor.py +0 -0
- {deployproof-1.0.1 → deployproof-1.1.1}/tests/test_dependencies_pypi.py +0 -0
- {deployproof-1.0.1 → deployproof-1.1.1}/tests/test_diff.py +0 -0
- {deployproof-1.0.1 → deployproof-1.1.1}/tests/test_edge_cases_validation.py +0 -0
- {deployproof-1.0.1 → deployproof-1.1.1}/tests/test_import_graph_discovery.py +0 -0
- {deployproof-1.0.1 → deployproof-1.1.1}/tests/test_mocks.py +0 -0
- {deployproof-1.0.1 → deployproof-1.1.1}/tests/test_mutation_suites.py +0 -0
- {deployproof-1.0.1 → deployproof-1.1.1}/tests/test_mutator.py +0 -0
- {deployproof-1.0.1 → deployproof-1.1.1}/tests/test_secrets.py +0 -0
- {deployproof-1.0.1 → deployproof-1.1.1}/tests/test_stress_regressions.py +0 -0
- {deployproof-1.0.1 → deployproof-1.1.1}/tests/test_symlinks.py +0 -0
- {deployproof-1.0.1 → deployproof-1.1.1}/tests/test_wsl.py +0 -0
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: deployproof
|
|
3
|
-
Version: 1.
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 1.1.1
|
|
4
|
+
Summary: Deterministic pre-push quality & security verification gate for Python codebases that catches what coverage misses.
|
|
5
5
|
Author-email: SVS Praveen <svspraveens@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
7
7
|
Project-URL: Homepage, https://github.com/SVSPraveen/DeployProof
|
|
8
8
|
Project-URL: Documentation, https://github.com/SVSPraveen/DeployProof#readme
|
|
9
9
|
Project-URL: Repository, https://github.com/SVSPraveen/DeployProof.git
|
|
10
10
|
Project-URL: Bug Tracker, https://github.com/SVSPraveen/DeployProof/issues
|
|
11
|
-
Keywords:
|
|
11
|
+
Keywords: code-quality,mutation-testing,security-scanner,developer-tools,pre-push-verification,python-testing,ast-analysis,dependency-security,ai-code,slopsquatting
|
|
12
12
|
Classifier: Development Status :: 3 - Alpha
|
|
13
13
|
Classifier: Intended Audience :: Developers
|
|
14
14
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -31,9 +31,13 @@ Dynamic: license-file
|
|
|
31
31
|
|
|
32
32
|
# DeployProof
|
|
33
33
|
|
|
34
|
-
>
|
|
34
|
+
<p align="center">
|
|
35
|
+
<img src="assets/deployproof-hero.png" alt="DeployProof Hero Banner" width="100%" />
|
|
36
|
+
</p>
|
|
35
37
|
|
|
36
|
-
|
|
38
|
+
> Deterministic pre-push quality & security gate for modern Python codebases: AST mutation testing, credential scanning, sandbox-escape detection, mock-usage alerts, swallowed-exception checks, and dependency hallucination defense. Built for human engineering teams and AI-assisted workflows alike.
|
|
39
|
+
|
|
40
|
+
[](https://pypi.org/project/deployproof/)
|
|
37
41
|
[](https://pypi.org/project/deployproof/)
|
|
38
42
|
[](https://github.com/SVSPraveen/DeployProof/actions/workflows/ci.yml)
|
|
39
43
|
[](https://github.com/SVSPraveen/DeployProof)
|
|
@@ -44,17 +48,29 @@ Dynamic: license-file
|
|
|
44
48
|
|
|
45
49
|
## Why This Exists
|
|
46
50
|
|
|
47
|
-
|
|
51
|
+
Modern software development — whether crafted by human engineering teams or generated through AI coding assistants — introduces subtle failure modes that standard linters and line-coverage metrics completely miss:
|
|
52
|
+
|
|
53
|
+
* **Deceptive Test Suites**: Test suites boasting 90%+ line coverage that never assert true correctness, masking near-zero mutation scores.
|
|
54
|
+
* **Accidental Credential Exposure**: Hardcoded API keys, bearer tokens, or service credentials generated in passing or pasted into tests.
|
|
55
|
+
* **Sandbox Escape Risks**: Symlinks that deceive tool approval prompts into breaking outside the repository sandbox.
|
|
56
|
+
* **Silently Swallowed Exceptions**: Blanket `except Exception: pass` anti-patterns that hide critical runtime bugs.
|
|
57
|
+
* **Dependency Hallucinations & Slopsquatting**: Package names invented by LLMs or mistyped dependencies that don't exist on public PyPI.
|
|
58
|
+
|
|
59
|
+
DeployProof serves as an uncompromising, deterministic pre-push gate that validates code quality, test integrity, and security locally before any commit reaches CI or production.
|
|
48
60
|
|
|
49
61
|
> **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.
|
|
50
62
|
|
|
51
63
|
## Install
|
|
52
64
|
|
|
53
65
|
```bash
|
|
66
|
+
# Recommended — installs into an isolated environment, exposes the CLI globally
|
|
67
|
+
pipx install deployproof
|
|
68
|
+
|
|
69
|
+
# Or via pip into your current environment
|
|
54
70
|
pip install deployproof
|
|
55
71
|
```
|
|
56
72
|
|
|
57
|
-
Requires Python 3.10+.
|
|
73
|
+
Requires Python 3.10+. If you don't have `pipx`, install it with `pip install pipx` then run `pipx ensurepath`.
|
|
58
74
|
|
|
59
75
|
## How to Use DeployProof
|
|
60
76
|
|
|
@@ -86,7 +102,11 @@ deployproof check --full-repo --workers 8
|
|
|
86
102
|
```
|
|
87
103
|
|
|
88
104
|
#### Real-World Timing Expectations:
|
|
89
|
-
|
|
105
|
+
|
|
106
|
+
> [!NOTE]
|
|
107
|
+
> **Estimated Timings Disclaimer**: The durations below are empirical estimates based on benchmark runs across various open-source projects (such as `requests`, `click`, and `colorama`). Actual execution time may be **higher or lower** depending on your specific test suite execution speed (e.g., pure unit tests vs. heavy integration/database tests), test runner timeout settings (`--timeout`), hardware profile (CPU core clock speed, available RAM), and codebase complexity.
|
|
108
|
+
|
|
109
|
+
| Scan Mode | Target Scope | Estimated Duration* | Intended Use Case |
|
|
90
110
|
| :--- | :--- | :--- | :--- |
|
|
91
111
|
| **`deployproof check`** | Git Diff (1–3 modified files) | **2 – 5 seconds** | Local pre-commit, active AI IDE coding loops, pre-push sanity checks. |
|
|
92
112
|
| **`deployproof check --workers 8`** | Large Multi-File Diff (100+ mutants) | **1 – 3 minutes** | Large feature branch reviews, refactors. |
|
|
@@ -289,7 +309,7 @@ deployproof check --json
|
|
|
289
309
|
|
|
290
310
|
```json
|
|
291
311
|
{
|
|
292
|
-
"version": "1.
|
|
312
|
+
"version": "1.1.1",
|
|
293
313
|
"status": "passed",
|
|
294
314
|
"summary": {
|
|
295
315
|
"target_files_count": 1,
|
|
@@ -389,7 +409,7 @@ Fixtures cover weak test suites, zero-test orphan modules, planted OpenAI/AWS cr
|
|
|
389
409
|
|
|
390
410
|
## Status & Roadmap
|
|
391
411
|
|
|
392
|
-
- **Current (v1.
|
|
412
|
+
- **Current (v1.1.1):** 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.
|
|
393
413
|
- **Next:** Reverse test-to-source dependency mapping (see `FUTURE_SCOPE.md`), SARIF 2.1.0 PR annotations, and multi-language mutation rule packs.
|
|
394
414
|
|
|
395
415
|
## Contributing
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
# DeployProof
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
<p align="center">
|
|
4
|
+
<img src="assets/deployproof-hero.png" alt="DeployProof Hero Banner" width="100%" />
|
|
5
|
+
</p>
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
> Deterministic pre-push quality & security gate for modern Python codebases: AST mutation testing, credential scanning, sandbox-escape detection, mock-usage alerts, swallowed-exception checks, and dependency hallucination defense. Built for human engineering teams and AI-assisted workflows alike.
|
|
8
|
+
|
|
9
|
+
[](https://pypi.org/project/deployproof/)
|
|
6
10
|
[](https://pypi.org/project/deployproof/)
|
|
7
11
|
[](https://github.com/SVSPraveen/DeployProof/actions/workflows/ci.yml)
|
|
8
12
|
[](https://github.com/SVSPraveen/DeployProof)
|
|
@@ -13,17 +17,29 @@
|
|
|
13
17
|
|
|
14
18
|
## Why This Exists
|
|
15
19
|
|
|
16
|
-
|
|
20
|
+
Modern software development — whether crafted by human engineering teams or generated through AI coding assistants — introduces subtle failure modes that standard linters and line-coverage metrics completely miss:
|
|
21
|
+
|
|
22
|
+
* **Deceptive Test Suites**: Test suites boasting 90%+ line coverage that never assert true correctness, masking near-zero mutation scores.
|
|
23
|
+
* **Accidental Credential Exposure**: Hardcoded API keys, bearer tokens, or service credentials generated in passing or pasted into tests.
|
|
24
|
+
* **Sandbox Escape Risks**: Symlinks that deceive tool approval prompts into breaking outside the repository sandbox.
|
|
25
|
+
* **Silently Swallowed Exceptions**: Blanket `except Exception: pass` anti-patterns that hide critical runtime bugs.
|
|
26
|
+
* **Dependency Hallucinations & Slopsquatting**: Package names invented by LLMs or mistyped dependencies that don't exist on public PyPI.
|
|
27
|
+
|
|
28
|
+
DeployProof serves as an uncompromising, deterministic pre-push gate that validates code quality, test integrity, and security locally before any commit reaches CI or production.
|
|
17
29
|
|
|
18
30
|
> **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
31
|
|
|
20
32
|
## Install
|
|
21
33
|
|
|
22
34
|
```bash
|
|
35
|
+
# Recommended — installs into an isolated environment, exposes the CLI globally
|
|
36
|
+
pipx install deployproof
|
|
37
|
+
|
|
38
|
+
# Or via pip into your current environment
|
|
23
39
|
pip install deployproof
|
|
24
40
|
```
|
|
25
41
|
|
|
26
|
-
Requires Python 3.10+.
|
|
42
|
+
Requires Python 3.10+. If you don't have `pipx`, install it with `pip install pipx` then run `pipx ensurepath`.
|
|
27
43
|
|
|
28
44
|
## How to Use DeployProof
|
|
29
45
|
|
|
@@ -55,7 +71,11 @@ deployproof check --full-repo --workers 8
|
|
|
55
71
|
```
|
|
56
72
|
|
|
57
73
|
#### Real-World Timing Expectations:
|
|
58
|
-
|
|
74
|
+
|
|
75
|
+
> [!NOTE]
|
|
76
|
+
> **Estimated Timings Disclaimer**: The durations below are empirical estimates based on benchmark runs across various open-source projects (such as `requests`, `click`, and `colorama`). Actual execution time may be **higher or lower** depending on your specific test suite execution speed (e.g., pure unit tests vs. heavy integration/database tests), test runner timeout settings (`--timeout`), hardware profile (CPU core clock speed, available RAM), and codebase complexity.
|
|
77
|
+
|
|
78
|
+
| Scan Mode | Target Scope | Estimated Duration* | Intended Use Case |
|
|
59
79
|
| :--- | :--- | :--- | :--- |
|
|
60
80
|
| **`deployproof check`** | Git Diff (1–3 modified files) | **2 – 5 seconds** | Local pre-commit, active AI IDE coding loops, pre-push sanity checks. |
|
|
61
81
|
| **`deployproof check --workers 8`** | Large Multi-File Diff (100+ mutants) | **1 – 3 minutes** | Large feature branch reviews, refactors. |
|
|
@@ -258,7 +278,7 @@ deployproof check --json
|
|
|
258
278
|
|
|
259
279
|
```json
|
|
260
280
|
{
|
|
261
|
-
"version": "1.
|
|
281
|
+
"version": "1.1.1",
|
|
262
282
|
"status": "passed",
|
|
263
283
|
"summary": {
|
|
264
284
|
"target_files_count": 1,
|
|
@@ -358,7 +378,7 @@ Fixtures cover weak test suites, zero-test orphan modules, planted OpenAI/AWS cr
|
|
|
358
378
|
|
|
359
379
|
## Status & Roadmap
|
|
360
380
|
|
|
361
|
-
- **Current (v1.
|
|
381
|
+
- **Current (v1.1.1):** 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.
|
|
362
382
|
- **Next:** Reverse test-to-source dependency mapping (see `FUTURE_SCOPE.md`), SARIF 2.1.0 PR annotations, and multi-language mutation rule packs.
|
|
363
383
|
|
|
364
384
|
## Contributing
|
|
@@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "deployproof"
|
|
7
|
-
version = "1.
|
|
8
|
-
description = "
|
|
7
|
+
version = "1.1.1"
|
|
8
|
+
description = "Deterministic pre-push quality & security verification gate for Python codebases that catches what coverage misses."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
11
11
|
license = "MIT"
|
|
@@ -13,14 +13,16 @@ authors = [
|
|
|
13
13
|
{ name = "SVS Praveen", email = "svspraveens@gmail.com" }
|
|
14
14
|
]
|
|
15
15
|
keywords = [
|
|
16
|
-
"
|
|
16
|
+
"code-quality",
|
|
17
17
|
"mutation-testing",
|
|
18
18
|
"security-scanner",
|
|
19
|
-
"
|
|
20
|
-
"ghostapproval",
|
|
19
|
+
"developer-tools",
|
|
21
20
|
"pre-push-verification",
|
|
21
|
+
"python-testing",
|
|
22
22
|
"ast-analysis",
|
|
23
23
|
"dependency-security",
|
|
24
|
+
"ai-code",
|
|
25
|
+
"slopsquatting",
|
|
24
26
|
]
|
|
25
27
|
classifiers = [
|
|
26
28
|
"Development Status :: 3 - Alpha",
|
|
@@ -1047,10 +1047,15 @@ def query_pypi_registry(
|
|
|
1047
1047
|
# Map import name to PyPI distribution name if known
|
|
1048
1048
|
canonical_pkg = normalize_package_name(norm_name)
|
|
1049
1049
|
|
|
1050
|
+
try:
|
|
1051
|
+
from deployproof import __version__
|
|
1052
|
+
except ImportError:
|
|
1053
|
+
__version__ = "1.1.1"
|
|
1054
|
+
|
|
1050
1055
|
url = f"https://pypi.org/pypi/{canonical_pkg}/json"
|
|
1051
1056
|
req = urllib.request.Request(
|
|
1052
1057
|
url,
|
|
1053
|
-
headers={"User-Agent": "DeployProof/
|
|
1058
|
+
headers={"User-Agent": f"DeployProof/{__version__} (https://github.com/SVSPraveen/DeployProof)"},
|
|
1054
1059
|
)
|
|
1055
1060
|
|
|
1056
1061
|
try:
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import json
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
from typing import Any, Dict, List, Optional
|
|
5
|
+
from deployproof import __version__
|
|
5
6
|
from deployproof.control_flow import ControlFlowScanSummary
|
|
6
7
|
from deployproof.dependencies import DependencyScanSummary
|
|
7
8
|
from deployproof.mocks import MockScanSummary
|
|
@@ -10,8 +11,9 @@ from deployproof.secrets import SecretsScanResult
|
|
|
10
11
|
from deployproof.symlinks import SymlinkScanResult
|
|
11
12
|
LARGE_FILE_LOC_THRESHOLD = 300
|
|
12
13
|
|
|
13
|
-
def format_json_report(result: MutationResult, target_files: List[Path], secrets_result: Optional[SecretsScanResult]=None, symlink_result: Optional[SymlinkScanResult]=None, dependency_result: Optional[DependencyScanSummary]=None, mock_result: Optional[MockScanSummary]=None, control_flow_result: Optional[ControlFlowScanSummary]=None, strict_mocks: bool=False, strict_error_handling: bool=False, repo_root: Optional[Path]=None, threshold: float=80.0, version: str=
|
|
14
|
+
def format_json_report(result: MutationResult, target_files: List[Path], secrets_result: Optional[SecretsScanResult]=None, symlink_result: Optional[SymlinkScanResult]=None, dependency_result: Optional[DependencyScanSummary]=None, mock_result: Optional[MockScanSummary]=None, control_flow_result: Optional[ControlFlowScanSummary]=None, strict_mocks: bool=False, strict_error_handling: bool=False, repo_root: Optional[Path]=None, threshold: float=80.0, version: Optional[str]=None) -> str:
|
|
14
15
|
"""Format all scan findings and mutation results as a structured JSON string."""
|
|
16
|
+
effective_version = version or __version__
|
|
15
17
|
root = (repo_root or Path.cwd()).resolve()
|
|
16
18
|
strict_mocks_triggered = bool(strict_mocks and mock_result and (mock_result.total_findings > 0))
|
|
17
19
|
strict_error_triggered = bool(strict_error_handling and control_flow_result and (control_flow_result.total_findings > 0))
|
|
@@ -94,7 +96,7 @@ def format_json_report(result: MutationResult, target_files: List[Path], secrets
|
|
|
94
96
|
except ValueError:
|
|
95
97
|
rel_f = f.file_path.as_posix()
|
|
96
98
|
control_flow_findings_data.append({'file': rel_f, 'line': f.line_number, 'rule': f.rule_id, 'severity': f.severity, 'snippet': f.snippet, 'message': f.message})
|
|
97
|
-
data: Dict[str, Any] = {'version':
|
|
99
|
+
data: Dict[str, Any] = {'version': effective_version, 'status': status_str, 'summary': {'target_files_count': len(target_files), 'mutation_score': result.mutation_score, 'collection_error': result.collection_error, 'threshold': threshold, 'secrets_found': len(secrets_findings_data), 'symlink_escapes_found': len(symlink_escapes_data), 'dependency_findings': {'high_risk': dependency_result.high_risk_count if dependency_result else 0, 'medium_risk': dependency_result.medium_risk_count if dependency_result else 0, 'ok': dependency_result.ok_count if dependency_result else 0, 'unknown': dependency_result.unknown_count if dependency_result else 0, 'unscanned': len(unscanned_sources_data)}, 'mock_usages_found': len(mock_findings_data), 'control_flow_findings': len(control_flow_findings_data), 'strict_mocks_active': strict_mocks, 'strict_mocks_triggered': strict_mocks_triggered, 'strict_error_handling_active': strict_error_handling, 'strict_error_handling_triggered': strict_error_triggered}, 'scope': {'target_files': scope_files}, 'mutation_testing': {'score': result.mutation_score, 'collection_error': result.collection_error, 'threshold': threshold, 'total_mutants': result.total_mutants, 'killed_mutants': result.killed_mutants, 'survived_mutants_count': len(surviving_mutants_data), 'runner_errors_count': len(result.runner_errors), 'valid_mutants_count': result.killed_mutants + len(surviving_mutants_data), 'duration_seconds': result.duration_seconds, 'surviving_mutants': surviving_mutants_data, 'skipped_constructs': skipped_constructs_data, 'untested_files': untested_files_data}, 'secrets': {'clean': len(secrets_findings_data) == 0, 'files_scanned': secrets_result.files_scanned if secrets_result else len(target_files), 'findings': secrets_findings_data}, 'symlinks': {'clean': len(symlink_escapes_data) == 0, 'files_scanned': symlink_result.files_scanned if symlink_result else len(target_files), 'findings': symlink_escapes_data}, 'dependencies': {'clean': bool(not dep_findings_data), 'total_scanned': dependency_result.total_scanned if dependency_result else 0, 'findings': dep_findings_data, 'unscanned_sources': unscanned_sources_data}, 'mocks': {'clean': len(mock_findings_data) == 0, 'strict_gate_triggered': strict_mocks_triggered, 'findings': mock_findings_data}, 'control_flow': {'clean': len(control_flow_findings_data) == 0, 'strict_gate_triggered': strict_error_triggered, 'findings': control_flow_findings_data}}
|
|
98
100
|
return json.dumps(data, indent=2)
|
|
99
101
|
|
|
100
102
|
def format_report(result: MutationResult, target_files: List[Path], secrets_result: Optional[SecretsScanResult]=None, symlink_result: Optional[SymlinkScanResult]=None, dependency_result: Optional[DependencyScanSummary]=None, mock_result: Optional[MockScanSummary]=None, control_flow_result: Optional[ControlFlowScanSummary]=None, strict_mocks: bool=False, strict_error_handling: bool=False, repo_root: Optional[Path]=None, threshold: float=80.0) -> str:
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: deployproof
|
|
3
|
-
Version: 1.
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 1.1.1
|
|
4
|
+
Summary: Deterministic pre-push quality & security verification gate for Python codebases that catches what coverage misses.
|
|
5
5
|
Author-email: SVS Praveen <svspraveens@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
7
7
|
Project-URL: Homepage, https://github.com/SVSPraveen/DeployProof
|
|
8
8
|
Project-URL: Documentation, https://github.com/SVSPraveen/DeployProof#readme
|
|
9
9
|
Project-URL: Repository, https://github.com/SVSPraveen/DeployProof.git
|
|
10
10
|
Project-URL: Bug Tracker, https://github.com/SVSPraveen/DeployProof/issues
|
|
11
|
-
Keywords:
|
|
11
|
+
Keywords: code-quality,mutation-testing,security-scanner,developer-tools,pre-push-verification,python-testing,ast-analysis,dependency-security,ai-code,slopsquatting
|
|
12
12
|
Classifier: Development Status :: 3 - Alpha
|
|
13
13
|
Classifier: Intended Audience :: Developers
|
|
14
14
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -31,9 +31,13 @@ Dynamic: license-file
|
|
|
31
31
|
|
|
32
32
|
# DeployProof
|
|
33
33
|
|
|
34
|
-
>
|
|
34
|
+
<p align="center">
|
|
35
|
+
<img src="assets/deployproof-hero.png" alt="DeployProof Hero Banner" width="100%" />
|
|
36
|
+
</p>
|
|
35
37
|
|
|
36
|
-
|
|
38
|
+
> Deterministic pre-push quality & security gate for modern Python codebases: AST mutation testing, credential scanning, sandbox-escape detection, mock-usage alerts, swallowed-exception checks, and dependency hallucination defense. Built for human engineering teams and AI-assisted workflows alike.
|
|
39
|
+
|
|
40
|
+
[](https://pypi.org/project/deployproof/)
|
|
37
41
|
[](https://pypi.org/project/deployproof/)
|
|
38
42
|
[](https://github.com/SVSPraveen/DeployProof/actions/workflows/ci.yml)
|
|
39
43
|
[](https://github.com/SVSPraveen/DeployProof)
|
|
@@ -44,17 +48,29 @@ Dynamic: license-file
|
|
|
44
48
|
|
|
45
49
|
## Why This Exists
|
|
46
50
|
|
|
47
|
-
|
|
51
|
+
Modern software development — whether crafted by human engineering teams or generated through AI coding assistants — introduces subtle failure modes that standard linters and line-coverage metrics completely miss:
|
|
52
|
+
|
|
53
|
+
* **Deceptive Test Suites**: Test suites boasting 90%+ line coverage that never assert true correctness, masking near-zero mutation scores.
|
|
54
|
+
* **Accidental Credential Exposure**: Hardcoded API keys, bearer tokens, or service credentials generated in passing or pasted into tests.
|
|
55
|
+
* **Sandbox Escape Risks**: Symlinks that deceive tool approval prompts into breaking outside the repository sandbox.
|
|
56
|
+
* **Silently Swallowed Exceptions**: Blanket `except Exception: pass` anti-patterns that hide critical runtime bugs.
|
|
57
|
+
* **Dependency Hallucinations & Slopsquatting**: Package names invented by LLMs or mistyped dependencies that don't exist on public PyPI.
|
|
58
|
+
|
|
59
|
+
DeployProof serves as an uncompromising, deterministic pre-push gate that validates code quality, test integrity, and security locally before any commit reaches CI or production.
|
|
48
60
|
|
|
49
61
|
> **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.
|
|
50
62
|
|
|
51
63
|
## Install
|
|
52
64
|
|
|
53
65
|
```bash
|
|
66
|
+
# Recommended — installs into an isolated environment, exposes the CLI globally
|
|
67
|
+
pipx install deployproof
|
|
68
|
+
|
|
69
|
+
# Or via pip into your current environment
|
|
54
70
|
pip install deployproof
|
|
55
71
|
```
|
|
56
72
|
|
|
57
|
-
Requires Python 3.10+.
|
|
73
|
+
Requires Python 3.10+. If you don't have `pipx`, install it with `pip install pipx` then run `pipx ensurepath`.
|
|
58
74
|
|
|
59
75
|
## How to Use DeployProof
|
|
60
76
|
|
|
@@ -86,7 +102,11 @@ deployproof check --full-repo --workers 8
|
|
|
86
102
|
```
|
|
87
103
|
|
|
88
104
|
#### Real-World Timing Expectations:
|
|
89
|
-
|
|
105
|
+
|
|
106
|
+
> [!NOTE]
|
|
107
|
+
> **Estimated Timings Disclaimer**: The durations below are empirical estimates based on benchmark runs across various open-source projects (such as `requests`, `click`, and `colorama`). Actual execution time may be **higher or lower** depending on your specific test suite execution speed (e.g., pure unit tests vs. heavy integration/database tests), test runner timeout settings (`--timeout`), hardware profile (CPU core clock speed, available RAM), and codebase complexity.
|
|
108
|
+
|
|
109
|
+
| Scan Mode | Target Scope | Estimated Duration* | Intended Use Case |
|
|
90
110
|
| :--- | :--- | :--- | :--- |
|
|
91
111
|
| **`deployproof check`** | Git Diff (1–3 modified files) | **2 – 5 seconds** | Local pre-commit, active AI IDE coding loops, pre-push sanity checks. |
|
|
92
112
|
| **`deployproof check --workers 8`** | Large Multi-File Diff (100+ mutants) | **1 – 3 minutes** | Large feature branch reviews, refactors. |
|
|
@@ -289,7 +309,7 @@ deployproof check --json
|
|
|
289
309
|
|
|
290
310
|
```json
|
|
291
311
|
{
|
|
292
|
-
"version": "1.
|
|
312
|
+
"version": "1.1.1",
|
|
293
313
|
"status": "passed",
|
|
294
314
|
"summary": {
|
|
295
315
|
"target_files_count": 1,
|
|
@@ -389,7 +409,7 @@ Fixtures cover weak test suites, zero-test orphan modules, planted OpenAI/AWS cr
|
|
|
389
409
|
|
|
390
410
|
## Status & Roadmap
|
|
391
411
|
|
|
392
|
-
- **Current (v1.
|
|
412
|
+
- **Current (v1.1.1):** 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.
|
|
393
413
|
- **Next:** Reverse test-to-source dependency mapping (see `FUTURE_SCOPE.md`), SARIF 2.1.0 PR annotations, and multi-language mutation rule packs.
|
|
394
414
|
|
|
395
415
|
## Contributing
|
|
@@ -9,7 +9,7 @@ from deployproof.cli import create_parser, main
|
|
|
9
9
|
|
|
10
10
|
def test_version():
|
|
11
11
|
"""Verify version string is accessible."""
|
|
12
|
-
assert __version__
|
|
12
|
+
assert isinstance(__version__, str) and len(__version__.split(".")) >= 3
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
def test_parser_version(capsys):
|
|
@@ -19,7 +19,7 @@ def test_parser_version(capsys):
|
|
|
19
19
|
parser.parse_args(["--version"])
|
|
20
20
|
assert exc_info.value.code == 0
|
|
21
21
|
captured = capsys.readouterr()
|
|
22
|
-
assert "deployproof
|
|
22
|
+
assert f"deployproof {__version__}" in captured.out or f"deployproof {__version__}" in captured.err
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
def test_parser_help(capsys):
|
|
@@ -105,7 +105,7 @@ def test_main_check_json_output_passing(capsys):
|
|
|
105
105
|
|
|
106
106
|
data = json.loads(captured.out)
|
|
107
107
|
assert data["status"] == "passed"
|
|
108
|
-
assert data["version"] ==
|
|
108
|
+
assert data["version"] == __version__
|
|
109
109
|
assert data["summary"]["mutation_score"] == 100.0
|
|
110
110
|
assert data["summary"]["secrets_found"] == 0
|
|
111
111
|
assert data["summary"]["symlink_escapes_found"] == 0
|
|
@@ -137,9 +137,10 @@ def test_main_check_json_output_multi_category_findings(tmp_path: Path, capsys,
|
|
|
137
137
|
subprocess.run(["git", "config", "user.email", "test@example.com"], cwd=root, check=True)
|
|
138
138
|
|
|
139
139
|
src = root / "service.py"
|
|
140
|
+
fake_key = "sk-" + "proj-abc123xyz123abc123xyz123abc123xyz123abc123xyz123"
|
|
140
141
|
src.write_text(
|
|
141
142
|
"import importlib\n\n"
|
|
142
|
-
"OPENAI_API_KEY = '
|
|
143
|
+
f"OPENAI_API_KEY = '{fake_key}'\n\n"
|
|
143
144
|
"def load_plugin():\n"
|
|
144
145
|
" return importlib.import_module('hallucinated_fake_package_xyz')\n\n"
|
|
145
146
|
"def calculate(x: int) -> int:\n"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|