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.
- {proofctl-0.4.1 → proofctl-0.4.2}/LICENSE +1 -1
- proofctl-0.4.2/MANIFEST.in +19 -0
- {proofctl-0.4.1 → proofctl-0.4.2}/PKG-INFO +1 -1
- {proofctl-0.4.1 → proofctl-0.4.2}/proofctl.egg-info/PKG-INFO +1 -1
- {proofctl-0.4.1 → proofctl-0.4.2}/proofctl.egg-info/SOURCES.txt +2 -33
- {proofctl-0.4.1 → proofctl-0.4.2}/pyproject.toml +1 -1
- proofctl-0.4.1/tests/test_baseline.py +0 -133
- proofctl-0.4.1/tests/test_config_proofctl.py +0 -133
- proofctl-0.4.1/tests/test_dockerfile.py +0 -473
- proofctl-0.4.1/tests/test_engine.py +0 -191
- proofctl-0.4.1/tests/test_fixer.py +0 -163
- proofctl-0.4.1/tests/test_imports.py +0 -312
- proofctl-0.4.1/tests/test_leakage.py +0 -179
- proofctl-0.4.1/tests/test_llm.py +0 -279
- proofctl-0.4.1/tests/test_local_packages.py +0 -239
- proofctl-0.4.1/tests/test_phase1_audit_fixes.py +0 -176
- proofctl-0.4.1/tests/test_phase2_audit_fixes.py +0 -311
- proofctl-0.4.1/tests/test_phase3_audit_fixes.py +0 -305
- proofctl-0.4.1/tests/test_phase4_audit_fixes.py +0 -416
- proofctl-0.4.1/tests/test_phase5_llm_imports_fixes.py +0 -306
- proofctl-0.4.1/tests/test_phase5_p_l_v_fixes.py +0 -279
- proofctl-0.4.1/tests/test_phase5_quality_fixes.py +0 -240
- proofctl-0.4.1/tests/test_phase6_audit_fixes.py +0 -359
- proofctl-0.4.1/tests/test_phase8_audit_fixes.py +0 -328
- proofctl-0.4.1/tests/test_placeholders.py +0 -239
- proofctl-0.4.1/tests/test_quality.py +0 -595
- proofctl-0.4.1/tests/test_quality_ext.py +0 -286
- proofctl-0.4.1/tests/test_secrets.py +0 -512
- proofctl-0.4.1/tests/test_security.py +0 -509
- proofctl-0.4.1/tests/test_security_ext.py +0 -476
- proofctl-0.4.1/tests/test_security_external.py +0 -546
- proofctl-0.4.1/tests/test_suppression.py +0 -137
- proofctl-0.4.1/tests/test_terraform.py +0 -861
- proofctl-0.4.1/tests/test_terraform_ext.py +0 -2806
- proofctl-0.4.1/tests/test_terragrunt.py +0 -313
- proofctl-0.4.1/tests/test_variants.py +0 -136
- proofctl-0.4.1/tests/test_yaml.py +0 -469
- proofctl-0.4.1/tests/test_yaml_k8s_gha.py +0 -1387
- {proofctl-0.4.1 → proofctl-0.4.2}/README.md +0 -0
- {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/__init__.py +0 -0
- {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/_globmatch.py +0 -0
- {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/baseline.py +0 -0
- {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/checkers/__init__.py +0 -0
- {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/checkers/base.py +0 -0
- {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/checkers/dockerfile.py +0 -0
- {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/checkers/hcl_utils.py +0 -0
- {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/checkers/imports.py +0 -0
- {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/checkers/leakage.py +0 -0
- {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/checkers/llm_integration.py +0 -0
- {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/checkers/placeholders.py +0 -0
- {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/checkers/quality.py +0 -0
- {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/checkers/secrets.py +0 -0
- {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/checkers/security.py +0 -0
- {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/checkers/shell_checker.py +0 -0
- {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/checkers/terraform.py +0 -0
- {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/checkers/terragrunt.py +0 -0
- {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/checkers/variants.py +0 -0
- {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/checkers/yaml_checker.py +0 -0
- {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/cli.py +0 -0
- {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/config.py +0 -0
- {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/engine.py +0 -0
- {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/fixer.py +0 -0
- {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/models.py +0 -0
- {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/registry.py +0 -0
- {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/reporters/__init__.py +0 -0
- {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/reporters/html_reporter.py +0 -0
- {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/reporters/json_reporter.py +0 -0
- {proofctl-0.4.1 → proofctl-0.4.2}/proofctl/reporters/terminal.py +0 -0
- {proofctl-0.4.1 → proofctl-0.4.2}/proofctl.egg-info/dependency_links.txt +0 -0
- {proofctl-0.4.1 → proofctl-0.4.2}/proofctl.egg-info/entry_points.txt +0 -0
- {proofctl-0.4.1 → proofctl-0.4.2}/proofctl.egg-info/requires.txt +0 -0
- {proofctl-0.4.1 → proofctl-0.4.2}/proofctl.egg-info/top_level.txt +0 -0
- {proofctl-0.4.1 → proofctl-0.4.2}/setup.cfg +0 -0
|
@@ -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.
|
|
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.
|
|
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.
|
|
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
|