deployproof 0.2.0__tar.gz → 0.2.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.
Files changed (37) hide show
  1. {deployproof-0.2.0/src/deployproof.egg-info → deployproof-0.2.1}/PKG-INFO +6 -5
  2. {deployproof-0.2.0 → deployproof-0.2.1}/README.md +5 -4
  3. {deployproof-0.2.0 → deployproof-0.2.1}/pyproject.toml +1 -1
  4. {deployproof-0.2.0 → deployproof-0.2.1}/src/deployproof/__init__.py +1 -1
  5. {deployproof-0.2.0 → deployproof-0.2.1}/src/deployproof/dependencies.py +1 -1
  6. {deployproof-0.2.0 → deployproof-0.2.1}/src/deployproof/mutator.py +13 -1
  7. {deployproof-0.2.0 → deployproof-0.2.1}/src/deployproof/reporter.py +1 -1
  8. {deployproof-0.2.0 → deployproof-0.2.1/src/deployproof.egg-info}/PKG-INFO +6 -5
  9. {deployproof-0.2.0 → deployproof-0.2.1}/tests/test_cli.py +3 -3
  10. {deployproof-0.2.0 → deployproof-0.2.1}/tests/test_mutator.py +37 -0
  11. {deployproof-0.2.0 → deployproof-0.2.1}/LICENSE +0 -0
  12. {deployproof-0.2.0 → deployproof-0.2.1}/setup.cfg +0 -0
  13. {deployproof-0.2.0 → deployproof-0.2.1}/src/deployproof/cli.py +0 -0
  14. {deployproof-0.2.0 → deployproof-0.2.1}/src/deployproof/control_flow.py +0 -0
  15. {deployproof-0.2.0 → deployproof-0.2.1}/src/deployproof/diff.py +0 -0
  16. {deployproof-0.2.0 → deployproof-0.2.1}/src/deployproof/mocks.py +0 -0
  17. {deployproof-0.2.0 → deployproof-0.2.1}/src/deployproof/secrets.py +0 -0
  18. {deployproof-0.2.0 → deployproof-0.2.1}/src/deployproof/symlinks.py +0 -0
  19. {deployproof-0.2.0 → deployproof-0.2.1}/src/deployproof/wsl.py +0 -0
  20. {deployproof-0.2.0 → deployproof-0.2.1}/src/deployproof.egg-info/SOURCES.txt +0 -0
  21. {deployproof-0.2.0 → deployproof-0.2.1}/src/deployproof.egg-info/dependency_links.txt +0 -0
  22. {deployproof-0.2.0 → deployproof-0.2.1}/src/deployproof.egg-info/entry_points.txt +0 -0
  23. {deployproof-0.2.0 → deployproof-0.2.1}/src/deployproof.egg-info/requires.txt +0 -0
  24. {deployproof-0.2.0 → deployproof-0.2.1}/src/deployproof.egg-info/top_level.txt +0 -0
  25. {deployproof-0.2.0 → deployproof-0.2.1}/tests/test_baseline_collection_error.py +0 -0
  26. {deployproof-0.2.0 → deployproof-0.2.1}/tests/test_cli_dependency_scan.py +0 -0
  27. {deployproof-0.2.0 → deployproof-0.2.1}/tests/test_control_flow.py +0 -0
  28. {deployproof-0.2.0 → deployproof-0.2.1}/tests/test_dependencies_extractor.py +0 -0
  29. {deployproof-0.2.0 → deployproof-0.2.1}/tests/test_dependencies_pypi.py +0 -0
  30. {deployproof-0.2.0 → deployproof-0.2.1}/tests/test_diff.py +0 -0
  31. {deployproof-0.2.0 → deployproof-0.2.1}/tests/test_edge_cases_validation.py +0 -0
  32. {deployproof-0.2.0 → deployproof-0.2.1}/tests/test_mocks.py +0 -0
  33. {deployproof-0.2.0 → deployproof-0.2.1}/tests/test_mutation_suites.py +0 -0
  34. {deployproof-0.2.0 → deployproof-0.2.1}/tests/test_secrets.py +0 -0
  35. {deployproof-0.2.0 → deployproof-0.2.1}/tests/test_stress_regressions.py +0 -0
  36. {deployproof-0.2.0 → deployproof-0.2.1}/tests/test_symlinks.py +0 -0
  37. {deployproof-0.2.0 → deployproof-0.2.1}/tests/test_wsl.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: deployproof
3
- Version: 0.2.0
3
+ Version: 0.2.1
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
- [![PyPI version](https://img.shields.io/badge/pypi-v0.2.0-007ec6.svg)](https://pypi.org/project/deployproof/)
35
+ [![PyPI version](https://img.shields.io/badge/pypi-v0.2.1-007ec6.svg)](https://pypi.org/project/deployproof/)
36
36
  [![Python versions](https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12%20%7C%203.13-3776ab.svg)](https://pypi.org/project/deployproof/)
37
37
  [![CI](https://github.com/SVSPraveen/DeployProof/actions/workflows/ci.yml/badge.svg)](https://github.com/SVSPraveen/DeployProof/actions/workflows/ci.yml)
38
- [![Tests](https://img.shields.io/badge/tests-93%20passed-2ea44f.svg)](https://github.com/SVSPraveen/DeployProof)
38
+ [![Tests](https://img.shields.io/badge/tests-94%20passed-2ea44f.svg)](https://github.com/SVSPraveen/DeployProof)
39
39
  [![Stress Tests](https://img.shields.io/badge/stress%20tests-11%2F11%20passed-2ea44f.svg)](stress_fixtures/)
40
40
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
41
41
 
@@ -189,7 +189,7 @@ deployproof check --json
189
189
 
190
190
  ```json
191
191
  {
192
- "version": "0.2.0",
192
+ "version": "0.2.1",
193
193
  "status": "passed",
194
194
  "summary": {
195
195
  "target_files_count": 1,
@@ -271,6 +271,7 @@ deployproof check --json
271
271
 
272
272
  ## What This Doesn't Do
273
273
 
274
+ - **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.
274
275
  - **Not a full-repo audit.** Checks are scoped to files changed in the current session (git diff). Files you haven't touched are not re-evaluated.
275
276
  - **Python only.** Mutation testing and import extraction currently support Python files only. Other languages are not scanned.
276
277
  - **No auto-fix.** DeployProof reports findings; it does not modify your code, rewrite imports, or suggest patches.
@@ -288,7 +289,7 @@ Fixtures cover weak test suites, zero-test orphan modules, planted OpenAI/AWS cr
288
289
 
289
290
  ## Status & Roadmap
290
291
 
291
- - **Current (v0.2.0):** Diff-scoped AST mutation testing (with recursive `test/`/`tests/` discovery, AST column-offset snippet reconstruction, and `SIGINT`/`SIGTERM`/`SIGBREAK` signal-safe disk restoration), baseline test-collection failure isolation with distinct exit code `2`, entropy-driven value-based secrets scanner (including unquoted .env values and prefix validation), 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, 93 unit tests, machine-readable `--json` output, and Tier 2 CI verification via GitHub Actions (mutmut).
292
+ - **Current (v0.2.1):** Diff-scoped AST mutation testing (with recursive `test/`/`tests/` discovery, AST column-offset snippet reconstruction, and `SIGINT`/`SIGTERM`/`SIGBREAK` signal-safe disk restoration), baseline test-collection failure isolation with distinct exit code `2`, entropy-driven value-based secrets scanner (including unquoted .env values and prefix validation), 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, 94 unit tests, machine-readable `--json` output, and Tier 2 CI verification via GitHub Actions (mutmut).
292
293
  - **Next:** Multi-language mutation support and expanded ecosystem rule packs.
293
294
 
294
295
  ## Contributing
@@ -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
- [![PyPI version](https://img.shields.io/badge/pypi-v0.2.0-007ec6.svg)](https://pypi.org/project/deployproof/)
5
+ [![PyPI version](https://img.shields.io/badge/pypi-v0.2.1-007ec6.svg)](https://pypi.org/project/deployproof/)
6
6
  [![Python versions](https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12%20%7C%203.13-3776ab.svg)](https://pypi.org/project/deployproof/)
7
7
  [![CI](https://github.com/SVSPraveen/DeployProof/actions/workflows/ci.yml/badge.svg)](https://github.com/SVSPraveen/DeployProof/actions/workflows/ci.yml)
8
- [![Tests](https://img.shields.io/badge/tests-93%20passed-2ea44f.svg)](https://github.com/SVSPraveen/DeployProof)
8
+ [![Tests](https://img.shields.io/badge/tests-94%20passed-2ea44f.svg)](https://github.com/SVSPraveen/DeployProof)
9
9
  [![Stress Tests](https://img.shields.io/badge/stress%20tests-11%2F11%20passed-2ea44f.svg)](stress_fixtures/)
10
10
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
11
11
 
@@ -159,7 +159,7 @@ deployproof check --json
159
159
 
160
160
  ```json
161
161
  {
162
- "version": "0.2.0",
162
+ "version": "0.2.1",
163
163
  "status": "passed",
164
164
  "summary": {
165
165
  "target_files_count": 1,
@@ -241,6 +241,7 @@ deployproof check --json
241
241
 
242
242
  ## What This Doesn't Do
243
243
 
244
+ - **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.
244
245
  - **Not a full-repo audit.** Checks are scoped to files changed in the current session (git diff). Files you haven't touched are not re-evaluated.
245
246
  - **Python only.** Mutation testing and import extraction currently support Python files only. Other languages are not scanned.
246
247
  - **No auto-fix.** DeployProof reports findings; it does not modify your code, rewrite imports, or suggest patches.
@@ -258,7 +259,7 @@ Fixtures cover weak test suites, zero-test orphan modules, planted OpenAI/AWS cr
258
259
 
259
260
  ## Status & Roadmap
260
261
 
261
- - **Current (v0.2.0):** Diff-scoped AST mutation testing (with recursive `test/`/`tests/` discovery, AST column-offset snippet reconstruction, and `SIGINT`/`SIGTERM`/`SIGBREAK` signal-safe disk restoration), baseline test-collection failure isolation with distinct exit code `2`, entropy-driven value-based secrets scanner (including unquoted .env values and prefix validation), 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, 93 unit tests, machine-readable `--json` output, and Tier 2 CI verification via GitHub Actions (mutmut).
262
+ - **Current (v0.2.1):** Diff-scoped AST mutation testing (with recursive `test/`/`tests/` discovery, AST column-offset snippet reconstruction, and `SIGINT`/`SIGTERM`/`SIGBREAK` signal-safe disk restoration), baseline test-collection failure isolation with distinct exit code `2`, entropy-driven value-based secrets scanner (including unquoted .env values and prefix validation), 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, 94 unit tests, machine-readable `--json` output, and Tier 2 CI verification via GitHub Actions (mutmut).
262
263
  - **Next:** Multi-language mutation support and expanded ecosystem rule packs.
263
264
 
264
265
  ## Contributing
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "deployproof"
7
- version = "0.2.0"
7
+ version = "0.2.1"
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.0"
2
+ __version__ = "0.2.1"
@@ -983,7 +983,7 @@ def query_pypi_registry(
983
983
  url = f"https://pypi.org/pypi/{canonical_pkg}/json"
984
984
  req = urllib.request.Request(
985
985
  url,
986
- headers={"User-Agent": "DeployProof/0.2.0 (https://github.com/SVSPraveen/DeployProof)"},
986
+ headers={"User-Agent": "DeployProof/0.2.1 (https://github.com/SVSPraveen/DeployProof)"},
987
987
  )
988
988
 
989
989
  try:
@@ -2,6 +2,7 @@
2
2
  import ast
3
3
  import atexit
4
4
  import copy
5
+ import importlib.util
5
6
  import os
6
7
  import re
7
8
  import shutil
@@ -57,7 +58,7 @@ _PREV_SIGTERM: Any = None
57
58
  _PREV_SIGBREAK: Any = None
58
59
 
59
60
  def _restore_current_mutant_file() -> None:
60
- """Immediately restore the currently mutated file on disk if one is active."""
61
+ """Immediately restore the currently mutated file on disk if one is active and clear its specific bytecode cache."""
61
62
  global _CURRENT_MUTATED_FILE, _CURRENT_ORIGINAL_CONTENT
62
63
  if _CURRENT_MUTATED_FILE is not None and _CURRENT_ORIGINAL_CONTENT is not None:
63
64
  target_path = _CURRENT_MUTATED_FILE
@@ -70,6 +71,17 @@ def _restore_current_mutant_file() -> None:
70
71
  f"Please verify this file's contents before committing or running tests.\n"
71
72
  )
72
73
  sys.stderr.flush()
74
+
75
+ # Remove specific __pycache__ .pyc entry for target_path if it exists
76
+ try:
77
+ pyc_path_str = importlib.util.cache_from_source(str(target_path))
78
+ if pyc_path_str:
79
+ pyc_file = Path(pyc_path_str)
80
+ if pyc_file.is_file():
81
+ pyc_file.unlink(missing_ok=True)
82
+ except (OSError, ValueError):
83
+ pass
84
+
73
85
  _CURRENT_MUTATED_FILE = None
74
86
  _CURRENT_ORIGINAL_CONTENT = None
75
87
  atexit.register(_restore_current_mutant_file)
@@ -10,7 +10,7 @@ from deployproof.secrets import SecretsScanResult
10
10
  from deployproof.symlinks import SymlinkScanResult
11
11
  LARGE_FILE_LOC_THRESHOLD = 300
12
12
 
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='0.2.0') -> str:
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='0.2.1') -> str:
14
14
  """Format all scan findings and mutation results as a structured JSON string."""
15
15
  root = (repo_root or Path.cwd()).resolve()
16
16
  strict_mocks_triggered = bool(strict_mocks and mock_result and (mock_result.total_findings > 0))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: deployproof
3
- Version: 0.2.0
3
+ Version: 0.2.1
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
- [![PyPI version](https://img.shields.io/badge/pypi-v0.2.0-007ec6.svg)](https://pypi.org/project/deployproof/)
35
+ [![PyPI version](https://img.shields.io/badge/pypi-v0.2.1-007ec6.svg)](https://pypi.org/project/deployproof/)
36
36
  [![Python versions](https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12%20%7C%203.13-3776ab.svg)](https://pypi.org/project/deployproof/)
37
37
  [![CI](https://github.com/SVSPraveen/DeployProof/actions/workflows/ci.yml/badge.svg)](https://github.com/SVSPraveen/DeployProof/actions/workflows/ci.yml)
38
- [![Tests](https://img.shields.io/badge/tests-93%20passed-2ea44f.svg)](https://github.com/SVSPraveen/DeployProof)
38
+ [![Tests](https://img.shields.io/badge/tests-94%20passed-2ea44f.svg)](https://github.com/SVSPraveen/DeployProof)
39
39
  [![Stress Tests](https://img.shields.io/badge/stress%20tests-11%2F11%20passed-2ea44f.svg)](stress_fixtures/)
40
40
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
41
41
 
@@ -189,7 +189,7 @@ deployproof check --json
189
189
 
190
190
  ```json
191
191
  {
192
- "version": "0.2.0",
192
+ "version": "0.2.1",
193
193
  "status": "passed",
194
194
  "summary": {
195
195
  "target_files_count": 1,
@@ -271,6 +271,7 @@ deployproof check --json
271
271
 
272
272
  ## What This Doesn't Do
273
273
 
274
+ - **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.
274
275
  - **Not a full-repo audit.** Checks are scoped to files changed in the current session (git diff). Files you haven't touched are not re-evaluated.
275
276
  - **Python only.** Mutation testing and import extraction currently support Python files only. Other languages are not scanned.
276
277
  - **No auto-fix.** DeployProof reports findings; it does not modify your code, rewrite imports, or suggest patches.
@@ -288,7 +289,7 @@ Fixtures cover weak test suites, zero-test orphan modules, planted OpenAI/AWS cr
288
289
 
289
290
  ## Status & Roadmap
290
291
 
291
- - **Current (v0.2.0):** Diff-scoped AST mutation testing (with recursive `test/`/`tests/` discovery, AST column-offset snippet reconstruction, and `SIGINT`/`SIGTERM`/`SIGBREAK` signal-safe disk restoration), baseline test-collection failure isolation with distinct exit code `2`, entropy-driven value-based secrets scanner (including unquoted .env values and prefix validation), 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, 93 unit tests, machine-readable `--json` output, and Tier 2 CI verification via GitHub Actions (mutmut).
292
+ - **Current (v0.2.1):** Diff-scoped AST mutation testing (with recursive `test/`/`tests/` discovery, AST column-offset snippet reconstruction, and `SIGINT`/`SIGTERM`/`SIGBREAK` signal-safe disk restoration), baseline test-collection failure isolation with distinct exit code `2`, entropy-driven value-based secrets scanner (including unquoted .env values and prefix validation), 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, 94 unit tests, machine-readable `--json` output, and Tier 2 CI verification via GitHub Actions (mutmut).
292
293
  - **Next:** Multi-language mutation support and expanded ecosystem rule packs.
293
294
 
294
295
  ## 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__ == "0.2.0"
12
+ assert __version__ == "0.2.1"
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 0.2.0" in captured.out or "deployproof 0.2.0" in captured.err
22
+ assert "deployproof 0.2.1" in captured.out or "deployproof 0.2.1" 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"] == "0.2.0"
108
+ assert data["version"] == "0.2.1"
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
@@ -370,6 +370,43 @@ def test_real_subprocess_os_signal_interrupt_restoration():
370
370
  assert src_file.read_text(encoding="utf-8") == mod_code
371
371
 
372
372
 
373
+ def test_restore_removes_pyc_cache_file():
374
+ """Verify that _restore_current_mutant_file unlinks the exact .pyc cache file without removing other cache files."""
375
+ import importlib.util
376
+ import py_compile
377
+ from deployproof import mutator
378
+
379
+ with tempfile.TemporaryDirectory() as tmpdir:
380
+ tmp_path = Path(tmpdir).resolve()
381
+ src1 = tmp_path / "module1.py"
382
+ src1.write_text("def func1(): return 1\n", encoding="utf-8")
383
+ src2 = tmp_path / "module2.py"
384
+ src2.write_text("def func2(): return 2\n", encoding="utf-8")
385
+
386
+ # Compile both to generate .pyc files in __pycache__
387
+ py_compile.compile(str(src1), doraise=True)
388
+ py_compile.compile(str(src2), doraise=True)
389
+
390
+ pyc1_path = Path(importlib.util.cache_from_source(str(src1)))
391
+ pyc2_path = Path(importlib.util.cache_from_source(str(src2)))
392
+
393
+ assert pyc1_path.is_file(), "pyc1 should exist before restoration"
394
+ assert pyc2_path.is_file(), "pyc2 should exist before restoration"
395
+
396
+ # Simulate active mutant tracking on src1
397
+ mutator._CURRENT_MUTATED_FILE = src1
398
+ mutator._CURRENT_ORIGINAL_CONTENT = "def func1(): return 100\n"
399
+
400
+ # Trigger restoration (as happens on interrupt / atexit)
401
+ mutator._restore_current_mutant_file()
402
+
403
+ # src1 should be restored and its specific .pyc removed
404
+ assert src1.read_text(encoding="utf-8") == "def func1(): return 100\n"
405
+ assert not pyc1_path.exists(), "src1's specific .pyc must be deleted"
406
+ assert pyc2_path.is_file(), "unrelated src2's .pyc must remain intact"
407
+
408
+
409
+
373
410
 
374
411
 
375
412
 
File without changes
File without changes