proofctl 0.4.1__tar.gz → 0.4.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. {proofctl-0.4.1 → proofctl-0.4.2}/LICENSE +1 -1
  2. proofctl-0.4.2/MANIFEST.in +19 -0
  3. {proofctl-0.4.1 → proofctl-0.4.2}/PKG-INFO +1 -1
  4. {proofctl-0.4.1 → proofctl-0.4.2}/proofctl.egg-info/PKG-INFO +1 -1
  5. {proofctl-0.4.1 → proofctl-0.4.2}/proofctl.egg-info/SOURCES.txt +2 -33
  6. {proofctl-0.4.1 → proofctl-0.4.2}/pyproject.toml +1 -1
  7. proofctl-0.4.1/tests/test_baseline.py +0 -133
  8. proofctl-0.4.1/tests/test_config_proofctl.py +0 -133
  9. proofctl-0.4.1/tests/test_dockerfile.py +0 -473
  10. proofctl-0.4.1/tests/test_engine.py +0 -191
  11. proofctl-0.4.1/tests/test_fixer.py +0 -163
  12. proofctl-0.4.1/tests/test_imports.py +0 -312
  13. proofctl-0.4.1/tests/test_leakage.py +0 -179
  14. proofctl-0.4.1/tests/test_llm.py +0 -279
  15. proofctl-0.4.1/tests/test_local_packages.py +0 -239
  16. proofctl-0.4.1/tests/test_phase1_audit_fixes.py +0 -176
  17. proofctl-0.4.1/tests/test_phase2_audit_fixes.py +0 -311
  18. proofctl-0.4.1/tests/test_phase3_audit_fixes.py +0 -305
  19. proofctl-0.4.1/tests/test_phase4_audit_fixes.py +0 -416
  20. proofctl-0.4.1/tests/test_phase5_llm_imports_fixes.py +0 -306
  21. proofctl-0.4.1/tests/test_phase5_p_l_v_fixes.py +0 -279
  22. proofctl-0.4.1/tests/test_phase5_quality_fixes.py +0 -240
  23. proofctl-0.4.1/tests/test_phase6_audit_fixes.py +0 -359
  24. proofctl-0.4.1/tests/test_phase8_audit_fixes.py +0 -328
  25. proofctl-0.4.1/tests/test_placeholders.py +0 -239
  26. proofctl-0.4.1/tests/test_quality.py +0 -595
  27. proofctl-0.4.1/tests/test_quality_ext.py +0 -286
  28. proofctl-0.4.1/tests/test_secrets.py +0 -512
  29. proofctl-0.4.1/tests/test_security.py +0 -509
  30. proofctl-0.4.1/tests/test_security_ext.py +0 -476
  31. proofctl-0.4.1/tests/test_security_external.py +0 -546
  32. proofctl-0.4.1/tests/test_suppression.py +0 -137
  33. proofctl-0.4.1/tests/test_terraform.py +0 -861
  34. proofctl-0.4.1/tests/test_terraform_ext.py +0 -2806
  35. proofctl-0.4.1/tests/test_terragrunt.py +0 -313
  36. proofctl-0.4.1/tests/test_variants.py +0 -136
  37. proofctl-0.4.1/tests/test_yaml.py +0 -469
  38. proofctl-0.4.1/tests/test_yaml_k8s_gha.py +0 -1387
  39. {proofctl-0.4.1 → proofctl-0.4.2}/README.md +0 -0
  40. {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/__init__.py +0 -0
  41. {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/_globmatch.py +0 -0
  42. {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/baseline.py +0 -0
  43. {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/checkers/__init__.py +0 -0
  44. {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/checkers/base.py +0 -0
  45. {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/checkers/dockerfile.py +0 -0
  46. {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/checkers/hcl_utils.py +0 -0
  47. {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/checkers/imports.py +0 -0
  48. {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/checkers/leakage.py +0 -0
  49. {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/checkers/llm_integration.py +0 -0
  50. {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/checkers/placeholders.py +0 -0
  51. {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/checkers/quality.py +0 -0
  52. {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/checkers/secrets.py +0 -0
  53. {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/checkers/security.py +0 -0
  54. {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/checkers/shell_checker.py +0 -0
  55. {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/checkers/terraform.py +0 -0
  56. {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/checkers/terragrunt.py +0 -0
  57. {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/checkers/variants.py +0 -0
  58. {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/checkers/yaml_checker.py +0 -0
  59. {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/cli.py +0 -0
  60. {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/config.py +0 -0
  61. {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/engine.py +0 -0
  62. {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/fixer.py +0 -0
  63. {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/models.py +0 -0
  64. {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/registry.py +0 -0
  65. {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/reporters/__init__.py +0 -0
  66. {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/reporters/html_reporter.py +0 -0
  67. {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/reporters/json_reporter.py +0 -0
  68. {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/reporters/terminal.py +0 -0
  69. {proofctl-0.4.1 → proofctl-0.4.2}/proofctl.egg-info/dependency_links.txt +0 -0
  70. {proofctl-0.4.1 → proofctl-0.4.2}/proofctl.egg-info/entry_points.txt +0 -0
  71. {proofctl-0.4.1 → proofctl-0.4.2}/proofctl.egg-info/requires.txt +0 -0
  72. {proofctl-0.4.1 → proofctl-0.4.2}/proofctl.egg-info/top_level.txt +0 -0
  73. {proofctl-0.4.1 → proofctl-0.4.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 Kolawolu Odunola
3
+ Copyright (c) 2025-2026 Kolawolu Odunola
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -0,0 +1,19 @@
1
+ graft proofctl
2
+ include README.md
3
+ include LICENSE
4
+ include pyproject.toml
5
+
6
+ # Internal-only — never ship to PyPI
7
+ prune tests
8
+ prune doc
9
+ prune docs
10
+ prune examples
11
+ prune build
12
+ prune dist
13
+ prune .github
14
+ exclude AUDIT_AND_ROADMAP.md
15
+ exclude AUDIT_VERIFICATION_v0.1.11.md
16
+
17
+ global-exclude __pycache__
18
+ global-exclude *.py[cod]
19
+ global-exclude .DS_Store
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: proofctl
3
- Version: 0.4.1
3
+ Version: 0.4.2
4
4
  Summary: Zero-dependency linter for Python, Terraform, Dockerfiles, Kubernetes, and GitHub Actions — catches AI slop and security misconfigurations pre-commit
5
5
  Author-email: Kolawolu Odunola <kolawolu.o@gmail.com>
6
6
  License: MIT
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: proofctl
3
- Version: 0.4.1
3
+ Version: 0.4.2
4
4
  Summary: Zero-dependency linter for Python, Terraform, Dockerfiles, Kubernetes, and GitHub Actions — catches AI slop and security misconfigurations pre-commit
5
5
  Author-email: Kolawolu Odunola <kolawolu.o@gmail.com>
6
6
  License: MIT
@@ -1,4 +1,5 @@
1
1
  LICENSE
2
+ MANIFEST.in
2
3
  README.md
3
4
  pyproject.toml
4
5
  proofctl/__init__.py
@@ -35,36 +36,4 @@ proofctl/checkers/yaml_checker.py
35
36
  proofctl/reporters/__init__.py
36
37
  proofctl/reporters/html_reporter.py
37
38
  proofctl/reporters/json_reporter.py
38
- proofctl/reporters/terminal.py
39
- tests/test_baseline.py
40
- tests/test_config_proofctl.py
41
- tests/test_dockerfile.py
42
- tests/test_engine.py
43
- tests/test_fixer.py
44
- tests/test_imports.py
45
- tests/test_leakage.py
46
- tests/test_llm.py
47
- tests/test_local_packages.py
48
- tests/test_phase1_audit_fixes.py
49
- tests/test_phase2_audit_fixes.py
50
- tests/test_phase3_audit_fixes.py
51
- tests/test_phase4_audit_fixes.py
52
- tests/test_phase5_llm_imports_fixes.py
53
- tests/test_phase5_p_l_v_fixes.py
54
- tests/test_phase5_quality_fixes.py
55
- tests/test_phase6_audit_fixes.py
56
- tests/test_phase8_audit_fixes.py
57
- tests/test_placeholders.py
58
- tests/test_quality.py
59
- tests/test_quality_ext.py
60
- tests/test_secrets.py
61
- tests/test_security.py
62
- tests/test_security_ext.py
63
- tests/test_security_external.py
64
- tests/test_suppression.py
65
- tests/test_terraform.py
66
- tests/test_terraform_ext.py
67
- tests/test_terragrunt.py
68
- tests/test_variants.py
69
- tests/test_yaml.py
70
- tests/test_yaml_k8s_gha.py
39
+ proofctl/reporters/terminal.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "proofctl"
7
- version = "0.4.1"
7
+ version = "0.4.2"
8
8
  description = "Zero-dependency linter for Python, Terraform, Dockerfiles, Kubernetes, and GitHub Actions — catches AI slop and security misconfigurations pre-commit"
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
@@ -1,133 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import json
4
- import tempfile
5
- from pathlib import Path
6
-
7
- from proofctl.baseline import (
8
- filter_new_findings,
9
- load_baseline,
10
- save_baseline,
11
- )
12
- from proofctl.models import Finding, Severity
13
-
14
-
15
- def _f(rule_id: str, file: str = "foo.py", msg: str = "test msg", line: int = 1) -> Finding:
16
- return Finding(
17
- file=file, line=line, col=0,
18
- rule_id=rule_id, rule_name="Test",
19
- severity=Severity.ERROR, message=msg,
20
- )
21
-
22
-
23
- # ── save / load ───────────────────────────────────────────────────────────────
24
-
25
- def test_save_creates_file():
26
- with tempfile.TemporaryDirectory() as td:
27
- root = Path(td)
28
- findings = [_f("PROOFCTL-P-001")]
29
- out = save_baseline(findings, root)
30
- assert out.exists()
31
-
32
-
33
- def test_save_load_roundtrip():
34
- """H-10: load_baseline returns the full versioned dict; the actual finding
35
- list lives under `findings`. Schema is bumped to 2 by save_baseline."""
36
- with tempfile.TemporaryDirectory() as td:
37
- root = Path(td)
38
- findings = [_f("PROOFCTL-P-001", msg="'foo' body is pass")]
39
- save_baseline(findings, root)
40
- loaded = load_baseline(root)
41
- assert loaded is not None
42
- assert loaded["schema_version"] >= 2
43
- assert len(loaded["findings"]) == 1
44
- assert loaded["findings"][0]["rule_id"] == "PROOFCTL-P-001"
45
- assert loaded["findings"][0]["message"] == "'foo' body is pass"
46
-
47
-
48
- def test_load_returns_none_when_no_file():
49
- with tempfile.TemporaryDirectory() as td:
50
- assert load_baseline(Path(td)) is None
51
-
52
-
53
- def test_load_returns_none_on_corrupt_file():
54
- with tempfile.TemporaryDirectory() as td:
55
- root = Path(td)
56
- (root / ".proofctl-baseline.json").write_text("not json")
57
- assert load_baseline(root) is None
58
-
59
-
60
- def test_save_count_field():
61
- with tempfile.TemporaryDirectory() as td:
62
- root = Path(td)
63
- save_baseline([_f("PROOFCTL-P-001"), _f("PROOFCTL-L-001")], root)
64
- data = json.loads((root / ".proofctl-baseline.json").read_text())
65
- assert data["count"] == 2
66
-
67
-
68
- # ── filter_new_findings ───────────────────────────────────────────────────────
69
-
70
- def test_all_in_baseline_suppressed():
71
- f = _f("PROOFCTL-P-001", msg="'foo' body is pass")
72
- baseline = [{"rule_id": "PROOFCTL-P-001", "file": "foo.py", "message": "'foo' body is pass"}]
73
- assert filter_new_findings([f], baseline) == []
74
-
75
-
76
- def test_new_finding_not_suppressed():
77
- f = _f("PROOFCTL-P-001", msg="'bar' body is pass")
78
- baseline = [{"rule_id": "PROOFCTL-P-001", "file": "foo.py", "message": "'foo' body is pass"}]
79
- assert filter_new_findings([f], baseline) == [f]
80
-
81
-
82
- def test_different_rule_not_suppressed():
83
- f = _f("PROOFCTL-L-001", msg="'foo' body is pass")
84
- baseline = [{"rule_id": "PROOFCTL-P-001", "file": "foo.py", "message": "'foo' body is pass"}]
85
- assert filter_new_findings([f], baseline) == [f]
86
-
87
-
88
- def test_different_file_not_suppressed():
89
- f = _f("PROOFCTL-P-001", file="bar.py", msg="'foo' body is pass")
90
- baseline = [{"rule_id": "PROOFCTL-P-001", "file": "foo.py", "message": "'foo' body is pass"}]
91
- assert filter_new_findings([f], baseline) == [f]
92
-
93
-
94
- def test_line_shift_suppressed():
95
- # Same bug moved from line 10 to line 42 — message unchanged → still suppressed.
96
- f = _f("PROOFCTL-P-001", msg="'foo' body is pass", line=42)
97
- baseline = [{"rule_id": "PROOFCTL-P-001", "file": "foo.py", "message": "'foo' body is pass"}]
98
- assert filter_new_findings([f], baseline) == []
99
-
100
-
101
- def test_empty_baseline_suppresses_nothing():
102
- f = _f("PROOFCTL-P-001")
103
- assert filter_new_findings([f], []) == [f]
104
-
105
-
106
- def test_multiset_exact_count_suppressed():
107
- # Two identical findings in baseline suppress exactly two in new run.
108
- f1 = _f("PROOFCTL-P-001", msg="'foo' body is pass")
109
- f2 = _f("PROOFCTL-P-001", msg="'foo' body is pass")
110
- baseline = [
111
- {"rule_id": "PROOFCTL-P-001", "file": "foo.py", "message": "'foo' body is pass"},
112
- {"rule_id": "PROOFCTL-P-001", "file": "foo.py", "message": "'foo' body is pass"},
113
- ]
114
- assert filter_new_findings([f1, f2], baseline) == []
115
-
116
-
117
- def test_multiset_one_extra_reported():
118
- # Three identical in new run, two in baseline → one new.
119
- f = _f("PROOFCTL-P-001", msg="'foo' body is pass")
120
- baseline = [
121
- {"rule_id": "PROOFCTL-P-001", "file": "foo.py", "message": "'foo' body is pass"},
122
- {"rule_id": "PROOFCTL-P-001", "file": "foo.py", "message": "'foo' body is pass"},
123
- ]
124
- result = filter_new_findings([f, f, f], baseline)
125
- assert len(result) == 1
126
-
127
-
128
- def test_mixed_findings():
129
- f_old = _f("PROOFCTL-P-001", msg="old")
130
- f_new = _f("PROOFCTL-Q-001", msg="new")
131
- baseline = [{"rule_id": "PROOFCTL-P-001", "file": "foo.py", "message": "old"}]
132
- result = filter_new_findings([f_old, f_new], baseline)
133
- assert result == [f_new]
@@ -1,133 +0,0 @@
1
- """Tests for proofctl config loading."""
2
- from __future__ import annotations
3
-
4
- from pathlib import Path
5
-
6
- import pytest
7
-
8
- from proofctl.config import ProofctlConfig, load_config
9
- from proofctl.models import Severity
10
-
11
-
12
- # ── defaults ──────────────────────────────────────────────────────────────────
13
-
14
- def test_load_config_no_file_returns_defaults(tmp_path):
15
- cfg = load_config(tmp_path)
16
- assert isinstance(cfg, ProofctlConfig)
17
- assert "**/.venv/**" in cfg.exclude_paths
18
- assert cfg.disable == []
19
- assert cfg.severity_overrides == {}
20
- assert cfg.any_threshold == 3
21
-
22
-
23
- def test_default_excludes_include_vendor_generated_paths(tmp_path):
24
- """All vendor/generated tool paths must be present in default excludes."""
25
- cfg = load_config(tmp_path)
26
- required = [
27
- # Flux CD bootstrap files
28
- "**/flux-system/gotk-components.yaml",
29
- "**/flux-system/gotk-sync.yaml",
30
- # ArgoCD Autopilot bootstrap files
31
- "**/bootstrap/argo-cd/kustomization.yaml",
32
- "**/bootstrap/argo-cd.yaml",
33
- # Terraform generated artifacts
34
- "**/*.tfstate",
35
- "**/*.tfplan",
36
- # CDK tools
37
- "**/cdk.out/**",
38
- "**/.gen/**",
39
- # Helm chart tarballs
40
- "**/charts/*.tgz",
41
- # Pulumi local backend
42
- "**/.pulumi/**",
43
- # Go vendor
44
- "**/vendor/**",
45
- # Python caches
46
- "**/.tox/**",
47
- "**/.pytest_cache/**",
48
- "**/.mypy_cache/**",
49
- ]
50
- for pat in required:
51
- assert pat in cfg.exclude_paths, f"missing default exclude: {pat}"
52
-
53
-
54
- def test_load_config_empty_file_returns_defaults(tmp_path):
55
- (tmp_path / ".proofctl.yaml").write_text("")
56
- cfg = load_config(tmp_path)
57
- assert cfg.any_threshold == 3
58
-
59
-
60
- # ── overrides ─────────────────────────────────────────────────────────────────
61
-
62
- def test_load_config_disable_rule(tmp_path):
63
- (tmp_path / ".proofctl.yaml").write_text("disable:\n - PROOFCTL-P-001\n")
64
- cfg = load_config(tmp_path)
65
- assert cfg.is_disabled("PROOFCTL-P-001")
66
- assert not cfg.is_disabled("PROOFCTL-P-002")
67
-
68
-
69
- def test_load_config_severity_override(tmp_path):
70
- yaml = "severity_overrides:\n PROOFCTL-P-001: ERROR\n"
71
- (tmp_path / ".proofctl.yaml").write_text(yaml)
72
- cfg = load_config(tmp_path)
73
- assert cfg.effective_severity("PROOFCTL-P-001", Severity.WARNING) == Severity.ERROR
74
-
75
-
76
- def test_load_config_severity_override_invalid_raises_at_load(tmp_path):
77
- """AUDIT H-8: bad severity_overrides values must fail at load_config(),
78
- not silently propagate to the first finding (which had no file context)."""
79
- yaml = "severity_overrides:\n PROOFCTL-P-001: BOGUS\n"
80
- (tmp_path / ".proofctl.yaml").write_text(yaml)
81
- with pytest.raises(ValueError, match="invalid"):
82
- load_config(tmp_path)
83
-
84
-
85
- def test_load_config_exclude_paths_override(tmp_path):
86
- (tmp_path / ".proofctl.yaml").write_text("exclude_paths:\n - '**/generated/**'\n")
87
- cfg = load_config(tmp_path)
88
- assert "**/generated/**" in cfg.exclude_paths
89
-
90
-
91
- # ── rule-level config ─────────────────────────────────────────────────────────
92
-
93
- def test_load_config_p002_any_threshold(tmp_path):
94
- yaml = "rules:\n PROOFCTL-Q-003:\n any_threshold: 5\n"
95
- (tmp_path / ".proofctl.yaml").write_text(yaml)
96
- cfg = load_config(tmp_path)
97
- assert cfg.any_threshold == 5
98
-
99
-
100
- def test_load_config_p002_todo_allowed(tmp_path):
101
- yaml = "rules:\n PROOFCTL-P-002:\n allowed_formats:\n - 'TODO\\(#\\d+\\)'\n"
102
- (tmp_path / ".proofctl.yaml").write_text(yaml)
103
- cfg = load_config(tmp_path)
104
- assert len(cfg.todo_allowed_formats) == 1
105
-
106
-
107
- # ── is_disabled ───────────────────────────────────────────────────────────────
108
-
109
- def test_is_disabled_true():
110
- cfg = ProofctlConfig(disable=["PROOFCTL-S-001"])
111
- assert cfg.is_disabled("PROOFCTL-S-001")
112
-
113
-
114
- def test_is_disabled_false():
115
- cfg = ProofctlConfig(disable=["PROOFCTL-S-001"])
116
- assert not cfg.is_disabled("PROOFCTL-S-002")
117
-
118
-
119
- def test_is_disabled_empty():
120
- cfg = ProofctlConfig()
121
- assert not cfg.is_disabled("ANYTHING")
122
-
123
-
124
- # ── effective_severity ────────────────────────────────────────────────────────
125
-
126
- def test_effective_severity_no_override_returns_default():
127
- cfg = ProofctlConfig()
128
- assert cfg.effective_severity("PROOFCTL-P-001", Severity.WARNING) == Severity.WARNING
129
-
130
-
131
- def test_effective_severity_override_applied():
132
- cfg = ProofctlConfig(severity_overrides={"PROOFCTL-P-001": "ERROR"})
133
- assert cfg.effective_severity("PROOFCTL-P-001", Severity.WARNING) == Severity.ERROR