proofctl 0.5.4__tar.gz → 0.5.6__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.5.4/proofctl.egg-info → proofctl-0.5.6}/PKG-INFO +1 -1
- {proofctl-0.5.4 → proofctl-0.5.6}/proofctl/checkers/terraform.py +66 -3
- {proofctl-0.5.4 → proofctl-0.5.6/proofctl.egg-info}/PKG-INFO +1 -1
- {proofctl-0.5.4 → proofctl-0.5.6}/pyproject.toml +1 -1
- {proofctl-0.5.4 → proofctl-0.5.6}/LICENSE +0 -0
- {proofctl-0.5.4 → proofctl-0.5.6}/MANIFEST.in +0 -0
- {proofctl-0.5.4 → proofctl-0.5.6}/README.md +0 -0
- {proofctl-0.5.4 → proofctl-0.5.6}/proofctl/__init__.py +0 -0
- {proofctl-0.5.4 → proofctl-0.5.6}/proofctl/_globmatch.py +0 -0
- {proofctl-0.5.4 → proofctl-0.5.6}/proofctl/baseline.py +0 -0
- {proofctl-0.5.4 → proofctl-0.5.6}/proofctl/checkers/__init__.py +0 -0
- {proofctl-0.5.4 → proofctl-0.5.6}/proofctl/checkers/base.py +0 -0
- {proofctl-0.5.4 → proofctl-0.5.6}/proofctl/checkers/dockerfile.py +0 -0
- {proofctl-0.5.4 → proofctl-0.5.6}/proofctl/checkers/hcl_utils.py +0 -0
- {proofctl-0.5.4 → proofctl-0.5.6}/proofctl/checkers/imports.py +0 -0
- {proofctl-0.5.4 → proofctl-0.5.6}/proofctl/checkers/leakage.py +0 -0
- {proofctl-0.5.4 → proofctl-0.5.6}/proofctl/checkers/llm_integration.py +0 -0
- {proofctl-0.5.4 → proofctl-0.5.6}/proofctl/checkers/placeholders.py +0 -0
- {proofctl-0.5.4 → proofctl-0.5.6}/proofctl/checkers/quality.py +0 -0
- {proofctl-0.5.4 → proofctl-0.5.6}/proofctl/checkers/secrets.py +0 -0
- {proofctl-0.5.4 → proofctl-0.5.6}/proofctl/checkers/security.py +0 -0
- {proofctl-0.5.4 → proofctl-0.5.6}/proofctl/checkers/shell_checker.py +0 -0
- {proofctl-0.5.4 → proofctl-0.5.6}/proofctl/checkers/terragrunt.py +0 -0
- {proofctl-0.5.4 → proofctl-0.5.6}/proofctl/checkers/variants.py +0 -0
- {proofctl-0.5.4 → proofctl-0.5.6}/proofctl/checkers/yaml_checker.py +0 -0
- {proofctl-0.5.4 → proofctl-0.5.6}/proofctl/cli.py +0 -0
- {proofctl-0.5.4 → proofctl-0.5.6}/proofctl/config.py +0 -0
- {proofctl-0.5.4 → proofctl-0.5.6}/proofctl/engine.py +0 -0
- {proofctl-0.5.4 → proofctl-0.5.6}/proofctl/fixer.py +0 -0
- {proofctl-0.5.4 → proofctl-0.5.6}/proofctl/models.py +0 -0
- {proofctl-0.5.4 → proofctl-0.5.6}/proofctl/registry.py +0 -0
- {proofctl-0.5.4 → proofctl-0.5.6}/proofctl/reporters/__init__.py +0 -0
- {proofctl-0.5.4 → proofctl-0.5.6}/proofctl/reporters/html_reporter.py +0 -0
- {proofctl-0.5.4 → proofctl-0.5.6}/proofctl/reporters/json_reporter.py +0 -0
- {proofctl-0.5.4 → proofctl-0.5.6}/proofctl/reporters/terminal.py +0 -0
- {proofctl-0.5.4 → proofctl-0.5.6}/proofctl.egg-info/SOURCES.txt +0 -0
- {proofctl-0.5.4 → proofctl-0.5.6}/proofctl.egg-info/dependency_links.txt +0 -0
- {proofctl-0.5.4 → proofctl-0.5.6}/proofctl.egg-info/entry_points.txt +0 -0
- {proofctl-0.5.4 → proofctl-0.5.6}/proofctl.egg-info/requires.txt +0 -0
- {proofctl-0.5.4 → proofctl-0.5.6}/proofctl.egg-info/top_level.txt +0 -0
- {proofctl-0.5.4 → proofctl-0.5.6}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: proofctl
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.6
|
|
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
|
|
@@ -1632,12 +1632,41 @@ class TerraformChecker(HclFileChecker):
|
|
|
1632
1632
|
))
|
|
1633
1633
|
return out
|
|
1634
1634
|
|
|
1635
|
+
# ── GKE Autopilot detection (0.5.6) ──────────────────────────────────
|
|
1636
|
+
#
|
|
1637
|
+
# GKE Autopilot is a managed-node mode where Google forces hardened
|
|
1638
|
+
# defaults that cannot be overridden. Many rules in this family target
|
|
1639
|
+
# `node_config` attributes that are illegal to set on Autopilot
|
|
1640
|
+
# clusters — flagging them produces false positives whose suggested
|
|
1641
|
+
# fix wouldn't even apply.
|
|
1642
|
+
#
|
|
1643
|
+
# The two helpers below let downstream rules skip themselves (or
|
|
1644
|
+
# demote severity) when scanning an Autopilot cluster. The detection
|
|
1645
|
+
# is whole-block string-match — adequate because the attribute name
|
|
1646
|
+
# is unambiguous.
|
|
1647
|
+
|
|
1648
|
+
@staticmethod
|
|
1649
|
+
def _is_gke_autopilot(b: HclBlock) -> bool:
|
|
1650
|
+
"""True iff the cluster has `enable_autopilot = true`."""
|
|
1651
|
+
if b.label1 != "google_container_cluster":
|
|
1652
|
+
return False
|
|
1653
|
+
val = (b.attr_value("enable_autopilot") or "").strip().lower()
|
|
1654
|
+
return val == "true"
|
|
1655
|
+
|
|
1656
|
+
@staticmethod
|
|
1657
|
+
def _has_workload_identity(b: HclBlock) -> bool:
|
|
1658
|
+
"""True iff `workload_identity_config { … }` block is nested."""
|
|
1659
|
+
return b.has_nested("workload_identity_config")
|
|
1660
|
+
|
|
1635
1661
|
def _g034(self, path: Path, blocks: list[HclBlock]) -> list[Finding]:
|
|
1636
1662
|
"""G-034 — GKE cluster missing explicit enable_legacy_abac = false."""
|
|
1637
1663
|
out = []
|
|
1638
1664
|
for b in blocks:
|
|
1639
1665
|
if b.kind != "resource" or b.label1 != "google_container_cluster":
|
|
1640
1666
|
continue
|
|
1667
|
+
# Autopilot: legacy ABAC is forced false and unchangeable.
|
|
1668
|
+
if self._is_gke_autopilot(b):
|
|
1669
|
+
continue
|
|
1641
1670
|
val = b.attr_value("enable_legacy_abac")
|
|
1642
1671
|
if val is None:
|
|
1643
1672
|
# Absent — provider default is false now, but old default was true.
|
|
@@ -1680,6 +1709,10 @@ class TerraformChecker(HclFileChecker):
|
|
|
1680
1709
|
for b in blocks:
|
|
1681
1710
|
if b.kind != "resource" or b.label1 not in ("google_container_cluster", "google_container_node_pool"):
|
|
1682
1711
|
continue
|
|
1712
|
+
# Autopilot: node_config is not settable and Autopilot forces
|
|
1713
|
+
# disable-legacy-endpoints = "true" by default. Skip.
|
|
1714
|
+
if b.label1 == "google_container_cluster" and self._is_gke_autopilot(b):
|
|
1715
|
+
continue
|
|
1683
1716
|
# Heuristic: require disable-legacy-endpoints = "true" anywhere in the block.
|
|
1684
1717
|
if not b.contains(r'disable-legacy-endpoints\s*=\s*"true"'):
|
|
1685
1718
|
out.append(self._f(
|
|
@@ -1699,6 +1732,10 @@ class TerraformChecker(HclFileChecker):
|
|
|
1699
1732
|
for b in blocks:
|
|
1700
1733
|
if b.kind != "resource" or b.label1 not in ("google_container_cluster", "google_container_node_pool"):
|
|
1701
1734
|
continue
|
|
1735
|
+
# Autopilot: shielded VM is forced on and node_config is not
|
|
1736
|
+
# settable. The suggested fix would even fail provider validation.
|
|
1737
|
+
if b.label1 == "google_container_cluster" and self._is_gke_autopilot(b):
|
|
1738
|
+
continue
|
|
1702
1739
|
has_block = b.contains(r'shielded_instance_config\s*\{')
|
|
1703
1740
|
has_secure = b.contains(r'enable_secure_boot\s*=\s*true')
|
|
1704
1741
|
has_integrity = b.contains(r'enable_integrity_monitoring\s*=\s*true')
|
|
@@ -1716,14 +1753,23 @@ class TerraformChecker(HclFileChecker):
|
|
|
1716
1753
|
|
|
1717
1754
|
def _g038(self, path: Path, blocks: list[HclBlock]) -> list[Finding]:
|
|
1718
1755
|
"""G-038 — GKE cluster without release_channel pinned to STABLE/REGULAR/RAPID."""
|
|
1719
|
-
|
|
1756
|
+
_channel_literal_re = re.compile(r'channel\s*=\s*"(STABLE|REGULAR|RAPID)"')
|
|
1757
|
+
# `channel = var.something` is also a valid pin — the value comes
|
|
1758
|
+
# from a typed variable, not a hardcoded mistake. Recognise it.
|
|
1759
|
+
_channel_var_re = re.compile(r'channel\s*=\s*var\.[a-zA-Z_][a-zA-Z0-9_]*')
|
|
1760
|
+
# `channel = local.something` similarly.
|
|
1761
|
+
_channel_local_re = re.compile(r'channel\s*=\s*local\.[a-zA-Z_][a-zA-Z0-9_]*')
|
|
1720
1762
|
out = []
|
|
1721
1763
|
for b in blocks:
|
|
1722
1764
|
if b.kind != "resource" or b.label1 != "google_container_cluster":
|
|
1723
1765
|
continue
|
|
1724
1766
|
body = "\n".join(b.raw_lines)
|
|
1725
1767
|
has_block = bool(re.search(r'release_channel\s*\{', body))
|
|
1726
|
-
has_channel =
|
|
1768
|
+
has_channel = (
|
|
1769
|
+
bool(_channel_literal_re.search(body))
|
|
1770
|
+
or bool(_channel_var_re.search(body))
|
|
1771
|
+
or bool(_channel_local_re.search(body))
|
|
1772
|
+
)
|
|
1727
1773
|
if not has_block or not has_channel:
|
|
1728
1774
|
out.append(self._f(
|
|
1729
1775
|
path, b.start_line,
|
|
@@ -1747,10 +1793,16 @@ class TerraformChecker(HclFileChecker):
|
|
|
1747
1793
|
continue
|
|
1748
1794
|
val = (b.attr_value("enable_shielded_nodes") or "").strip().lower()
|
|
1749
1795
|
if val != "true":
|
|
1796
|
+
# Autopilot: shielded nodes are forced on regardless. The
|
|
1797
|
+
# explicit attribute remains useful as documentation — demote
|
|
1798
|
+
# severity to INFO so the gate doesn't fail prod CI on it.
|
|
1799
|
+
severity = (
|
|
1800
|
+
Severity.INFO if self._is_gke_autopilot(b) else Severity.WARNING
|
|
1801
|
+
)
|
|
1750
1802
|
out.append(self._f(
|
|
1751
1803
|
path, b.attr_line("enable_shielded_nodes") or b.start_line,
|
|
1752
1804
|
"PROOFCTL-TF-G040", "GKE shielded nodes not enabled",
|
|
1753
|
-
|
|
1805
|
+
severity,
|
|
1754
1806
|
f'Cluster "{b.label2}" has enable_shielded_nodes not set to true',
|
|
1755
1807
|
hint="Set enable_shielded_nodes = true on the cluster.",
|
|
1756
1808
|
authority="CIS GKE Benchmark 6.5.5",
|
|
@@ -1765,6 +1817,17 @@ class TerraformChecker(HclFileChecker):
|
|
|
1765
1817
|
for b in blocks:
|
|
1766
1818
|
if b.kind != "resource" or b.label1 not in ("google_container_cluster", "google_container_node_pool"):
|
|
1767
1819
|
continue
|
|
1820
|
+
# Autopilot + Workload Identity: workloads get GCP API access via
|
|
1821
|
+
# Workload Identity bindings to GSAs, not via the node SA. The
|
|
1822
|
+
# node SA is mostly inert. Skip the warning when the cluster is
|
|
1823
|
+
# Autopilot AND has workload_identity_config — that's the
|
|
1824
|
+
# recommended Autopilot security model.
|
|
1825
|
+
if (
|
|
1826
|
+
b.label1 == "google_container_cluster"
|
|
1827
|
+
and self._is_gke_autopilot(b)
|
|
1828
|
+
and self._has_workload_identity(b)
|
|
1829
|
+
):
|
|
1830
|
+
continue
|
|
1768
1831
|
body = "\n".join(b.raw_lines)
|
|
1769
1832
|
uses_default = bool(_default_sa_re.search(body))
|
|
1770
1833
|
# Absence of any service_account inside node_config also implies default SA.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: proofctl
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.6
|
|
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
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "proofctl"
|
|
7
|
-
version = "0.5.
|
|
7
|
+
version = "0.5.6"
|
|
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" }
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|