kekkai-cli 1.0.5__py3-none-any.whl → 1.1.1__py3-none-any.whl

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 (53) hide show
  1. kekkai/cli.py +789 -19
  2. kekkai/compliance/__init__.py +68 -0
  3. kekkai/compliance/hipaa.py +235 -0
  4. kekkai/compliance/mappings.py +136 -0
  5. kekkai/compliance/owasp.py +517 -0
  6. kekkai/compliance/owasp_agentic.py +267 -0
  7. kekkai/compliance/pci_dss.py +205 -0
  8. kekkai/compliance/soc2.py +209 -0
  9. kekkai/dojo.py +91 -14
  10. kekkai/dojo_import.py +9 -1
  11. kekkai/fix/__init__.py +47 -0
  12. kekkai/fix/audit.py +278 -0
  13. kekkai/fix/differ.py +427 -0
  14. kekkai/fix/engine.py +500 -0
  15. kekkai/fix/prompts.py +251 -0
  16. kekkai/output.py +10 -12
  17. kekkai/report/__init__.py +41 -0
  18. kekkai/report/compliance_matrix.py +98 -0
  19. kekkai/report/generator.py +365 -0
  20. kekkai/report/html.py +69 -0
  21. kekkai/report/pdf.py +63 -0
  22. kekkai/report/unified.py +226 -0
  23. kekkai/scanners/container.py +33 -3
  24. kekkai/scanners/gitleaks.py +3 -1
  25. kekkai/scanners/semgrep.py +1 -1
  26. kekkai/scanners/trivy.py +1 -1
  27. kekkai/threatflow/model_adapter.py +143 -1
  28. kekkai/triage/__init__.py +54 -1
  29. kekkai/triage/loader.py +196 -0
  30. kekkai_cli-1.1.1.dist-info/METADATA +379 -0
  31. {kekkai_cli-1.0.5.dist-info → kekkai_cli-1.1.1.dist-info}/RECORD +34 -33
  32. {kekkai_cli-1.0.5.dist-info → kekkai_cli-1.1.1.dist-info}/entry_points.txt +0 -1
  33. {kekkai_cli-1.0.5.dist-info → kekkai_cli-1.1.1.dist-info}/top_level.txt +0 -1
  34. kekkai_cli-1.0.5.dist-info/METADATA +0 -135
  35. portal/__init__.py +0 -19
  36. portal/api.py +0 -155
  37. portal/auth.py +0 -103
  38. portal/enterprise/__init__.py +0 -32
  39. portal/enterprise/audit.py +0 -435
  40. portal/enterprise/licensing.py +0 -342
  41. portal/enterprise/rbac.py +0 -276
  42. portal/enterprise/saml.py +0 -595
  43. portal/ops/__init__.py +0 -53
  44. portal/ops/backup.py +0 -553
  45. portal/ops/log_shipper.py +0 -469
  46. portal/ops/monitoring.py +0 -517
  47. portal/ops/restore.py +0 -469
  48. portal/ops/secrets.py +0 -408
  49. portal/ops/upgrade.py +0 -591
  50. portal/tenants.py +0 -340
  51. portal/uploads.py +0 -259
  52. portal/web.py +0 -384
  53. {kekkai_cli-1.0.5.dist-info → kekkai_cli-1.1.1.dist-info}/WHEEL +0 -0
@@ -0,0 +1,68 @@
1
+ """Compliance framework mapping for security findings.
2
+
3
+ Maps security findings to compliance framework controls for audit reporting.
4
+
5
+ Supported frameworks:
6
+ - PCI-DSS v4.0 (Payment Card Industry)
7
+ - SOC 2 Type II (Service Organization Controls)
8
+ - OWASP Top 10 2025 (Web Application Security)
9
+ - OWASP Agentic AI Top 10 (Autonomous AI Agent Security)
10
+ - HIPAA (Health Insurance Portability and Accountability)
11
+
12
+ Security considerations:
13
+ - Mappings are advisory, not compliance certifications
14
+ - Always include disclaimer in generated reports
15
+ - Raw finding data shown, no compliance assessments
16
+
17
+ ASVS Requirements:
18
+ - V5.3.1: Output encoding for reports
19
+ - V8.1.1: Reports stored in user-specified paths only
20
+ """
21
+
22
+ from __future__ import annotations
23
+
24
+ from .hipaa import HIPAA_SAFEGUARDS, HIPAASafeguard, map_to_hipaa
25
+ from .mappings import (
26
+ ComplianceMapping,
27
+ ComplianceMappingResult,
28
+ FrameworkControl,
29
+ map_finding_to_frameworks,
30
+ map_findings_to_all_frameworks,
31
+ )
32
+ from .owasp import OWASP_TOP_10, OWASPCategory, map_to_owasp
33
+ from .owasp_agentic import (
34
+ OWASP_AGENTIC_TOP_10,
35
+ OWASPAgenticCategory,
36
+ map_to_owasp_agentic,
37
+ )
38
+ from .pci_dss import PCI_DSS_CONTROLS, PCIDSSControl, map_to_pci_dss
39
+ from .soc2 import SOC2_CRITERIA, SOC2Criterion, map_to_soc2
40
+
41
+ __all__ = [
42
+ # Core mapping
43
+ "ComplianceMapping",
44
+ "ComplianceMappingResult",
45
+ "FrameworkControl",
46
+ "map_finding_to_frameworks",
47
+ "map_findings_to_all_frameworks",
48
+ # PCI-DSS
49
+ "PCIDSSControl",
50
+ "PCI_DSS_CONTROLS",
51
+ "map_to_pci_dss",
52
+ # SOC 2
53
+ "SOC2Criterion",
54
+ "SOC2_CRITERIA",
55
+ "map_to_soc2",
56
+ # OWASP Top 10 2025
57
+ "OWASPCategory",
58
+ "OWASP_TOP_10",
59
+ "map_to_owasp",
60
+ # OWASP Agentic AI Top 10
61
+ "OWASPAgenticCategory",
62
+ "OWASP_AGENTIC_TOP_10",
63
+ "map_to_owasp_agentic",
64
+ # HIPAA
65
+ "HIPAASafeguard",
66
+ "HIPAA_SAFEGUARDS",
67
+ "map_to_hipaa",
68
+ ]
@@ -0,0 +1,235 @@
1
+ """HIPAA Security Rule safeguard mapping for security findings.
2
+
3
+ Maps findings to HIPAA Security Rule safeguards based on CWE IDs and rule patterns.
4
+ Reference: https://www.hhs.gov/hipaa/for-professionals/security/index.html
5
+
6
+ Note: HIPAA mappings are advisory and apply primarily to healthcare-related
7
+ applications handling Protected Health Information (PHI).
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ from dataclasses import dataclass
13
+ from typing import TYPE_CHECKING
14
+
15
+ from .mappings import FrameworkControl
16
+
17
+ if TYPE_CHECKING:
18
+ from kekkai.scanners.base import Finding
19
+
20
+
21
+ @dataclass(frozen=True)
22
+ class HIPAASafeguard:
23
+ """HIPAA Security Rule safeguard definition."""
24
+
25
+ id: str
26
+ title: str
27
+ description: str
28
+ category: str # Administrative, Physical, Technical
29
+ implementation: str # Required, Addressable
30
+ cwes: frozenset[int]
31
+ rule_patterns: tuple[str, ...]
32
+
33
+
34
+ # HIPAA Security Rule safeguards relevant to application security
35
+ HIPAA_SAFEGUARDS: dict[str, HIPAASafeguard] = {
36
+ # Technical Safeguards
37
+ "164.312(a)(1)": HIPAASafeguard(
38
+ id="164.312(a)(1)",
39
+ title="Access Control",
40
+ description=(
41
+ "Implement technical policies and procedures for electronic "
42
+ "information systems that maintain ePHI"
43
+ ),
44
+ category="Technical",
45
+ implementation="Required",
46
+ cwes=frozenset({264, 284, 285, 287, 306, 639, 862, 863}),
47
+ rule_patterns=("access-control", "authorization", "authentication"),
48
+ ),
49
+ "164.312(a)(2)(i)": HIPAASafeguard(
50
+ id="164.312(a)(2)(i)",
51
+ title="Unique User Identification",
52
+ description="Assign a unique name and/or number for identifying and tracking user identity",
53
+ category="Technical",
54
+ implementation="Required",
55
+ cwes=frozenset({287, 288, 521}),
56
+ rule_patterns=("user-identification", "identity", "authentication"),
57
+ ),
58
+ "164.312(a)(2)(ii)": HIPAASafeguard(
59
+ id="164.312(a)(2)(ii)",
60
+ title="Emergency Access Procedure",
61
+ description="Establish procedures for obtaining necessary ePHI during an emergency",
62
+ category="Technical",
63
+ implementation="Required",
64
+ cwes=frozenset({269}),
65
+ rule_patterns=("emergency-access", "break-glass"),
66
+ ),
67
+ "164.312(a)(2)(iii)": HIPAASafeguard(
68
+ id="164.312(a)(2)(iii)",
69
+ title="Automatic Logoff",
70
+ description=(
71
+ "Implement electronic procedures that terminate an electronic session after inactivity"
72
+ ),
73
+ category="Technical",
74
+ implementation="Addressable",
75
+ cwes=frozenset({613}),
76
+ rule_patterns=("session", "timeout", "logoff", "idle"),
77
+ ),
78
+ "164.312(a)(2)(iv)": HIPAASafeguard(
79
+ id="164.312(a)(2)(iv)",
80
+ title="Encryption and Decryption",
81
+ description="Implement a mechanism to encrypt and decrypt ePHI",
82
+ category="Technical",
83
+ implementation="Addressable",
84
+ cwes=frozenset({311, 312, 319, 326, 327, 328}),
85
+ rule_patterns=("encryption", "crypto", "decrypt"),
86
+ ),
87
+ "164.312(b)": HIPAASafeguard(
88
+ id="164.312(b)",
89
+ title="Audit Controls",
90
+ description=(
91
+ "Implement hardware, software, and/or procedures to record and examine activity"
92
+ ),
93
+ category="Technical",
94
+ implementation="Required",
95
+ cwes=frozenset({117, 223, 532, 778}),
96
+ rule_patterns=("audit", "logging", "monitoring", "log-injection"),
97
+ ),
98
+ "164.312(c)(1)": HIPAASafeguard(
99
+ id="164.312(c)(1)",
100
+ title="Integrity",
101
+ description=(
102
+ "Implement policies and procedures to protect ePHI from "
103
+ "improper alteration or destruction"
104
+ ),
105
+ category="Technical",
106
+ implementation="Required",
107
+ cwes=frozenset({345, 353, 494, 502}),
108
+ rule_patterns=("integrity", "tampering", "modification"),
109
+ ),
110
+ "164.312(c)(2)": HIPAASafeguard(
111
+ id="164.312(c)(2)",
112
+ title="Mechanism to Authenticate ePHI",
113
+ description="Implement electronic mechanisms to corroborate that ePHI has not been altered",
114
+ category="Technical",
115
+ implementation="Addressable",
116
+ cwes=frozenset({345, 347, 354}),
117
+ rule_patterns=("authentication", "signature", "hash", "checksum"),
118
+ ),
119
+ "164.312(d)": HIPAASafeguard(
120
+ id="164.312(d)",
121
+ title="Person or Entity Authentication",
122
+ description=(
123
+ "Implement procedures to verify that a person or entity seeking "
124
+ "access is the one claimed"
125
+ ),
126
+ category="Technical",
127
+ implementation="Required",
128
+ cwes=frozenset({287, 290, 294, 295, 302, 306, 307}),
129
+ rule_patterns=("authentication", "verify", "identity", "credential"),
130
+ ),
131
+ "164.312(e)(1)": HIPAASafeguard(
132
+ id="164.312(e)(1)",
133
+ title="Transmission Security",
134
+ description=(
135
+ "Implement technical security measures to guard against unauthorized access to ePHI"
136
+ ),
137
+ category="Technical",
138
+ implementation="Required",
139
+ cwes=frozenset({319, 523, 757}),
140
+ rule_patterns=("transmission", "tls", "ssl", "transport"),
141
+ ),
142
+ "164.312(e)(2)(i)": HIPAASafeguard(
143
+ id="164.312(e)(2)(i)",
144
+ title="Integrity Controls",
145
+ description=(
146
+ "Implement security measures to ensure electronically transmitted "
147
+ "ePHI is not improperly modified"
148
+ ),
149
+ category="Technical",
150
+ implementation="Addressable",
151
+ cwes=frozenset({319, 345}),
152
+ rule_patterns=("integrity", "transmission", "modification"),
153
+ ),
154
+ "164.312(e)(2)(ii)": HIPAASafeguard(
155
+ id="164.312(e)(2)(ii)",
156
+ title="Encryption",
157
+ description="Implement mechanism to encrypt ePHI whenever deemed appropriate",
158
+ category="Technical",
159
+ implementation="Addressable",
160
+ cwes=frozenset({311, 319, 326, 327}),
161
+ rule_patterns=("encryption", "tls", "ssl"),
162
+ ),
163
+ # Administrative Safeguards (security-relevant)
164
+ "164.308(a)(1)(ii)(A)": HIPAASafeguard(
165
+ id="164.308(a)(1)(ii)(A)",
166
+ title="Risk Analysis",
167
+ description=(
168
+ "Conduct an accurate and thorough assessment of potential risks and vulnerabilities"
169
+ ),
170
+ category="Administrative",
171
+ implementation="Required",
172
+ cwes=frozenset({937, 1035, 1104}),
173
+ rule_patterns=("vulnerability", "risk", "cve-", "scan"),
174
+ ),
175
+ "164.308(a)(5)(ii)(B)": HIPAASafeguard(
176
+ id="164.308(a)(5)(ii)(B)",
177
+ title="Protection from Malicious Software",
178
+ description="Procedures for guarding against, detecting, and reporting malicious software",
179
+ category="Administrative",
180
+ implementation="Addressable",
181
+ cwes=frozenset({94, 502, 829}),
182
+ rule_patterns=("malware", "malicious", "injection"),
183
+ ),
184
+ }
185
+
186
+
187
+ def _extract_cwe_id(cwe_str: str | None) -> int | None:
188
+ """Extract numeric CWE ID from string."""
189
+ if not cwe_str:
190
+ return None
191
+ cwe_str = cwe_str.upper().replace("CWE-", "").replace("CWE", "")
192
+ try:
193
+ return int(cwe_str.strip())
194
+ except ValueError:
195
+ return None
196
+
197
+
198
+ def map_to_hipaa(finding: Finding) -> list[FrameworkControl]:
199
+ """Map a finding to HIPAA Security Rule safeguards."""
200
+ controls: list[FrameworkControl] = []
201
+
202
+ cwe_id = _extract_cwe_id(finding.cwe)
203
+ rule_id_lower = (finding.rule_id or "").lower()
204
+ title_lower = finding.title.lower()
205
+
206
+ for safeguard in HIPAA_SAFEGUARDS.values():
207
+ matched = False
208
+
209
+ # Match by CWE
210
+ if cwe_id and cwe_id in safeguard.cwes:
211
+ matched = True
212
+
213
+ # Match by rule pattern
214
+ if not matched:
215
+ for pattern in safeguard.rule_patterns:
216
+ if pattern in rule_id_lower or pattern in title_lower:
217
+ matched = True
218
+ break
219
+
220
+ # CVEs map to 164.308(a)(1)(ii)(A) (risk analysis)
221
+ if not matched and safeguard.id == "164.308(a)(1)(ii)(A)" and finding.cve:
222
+ matched = True
223
+
224
+ if matched:
225
+ controls.append(
226
+ FrameworkControl(
227
+ framework="HIPAA",
228
+ control_id=safeguard.id,
229
+ title=safeguard.title,
230
+ description=safeguard.description,
231
+ requirement_level=safeguard.implementation.lower(),
232
+ )
233
+ )
234
+
235
+ return controls
@@ -0,0 +1,136 @@
1
+ """Core compliance mapping engine.
2
+
3
+ Maps security findings to compliance framework controls using CWE IDs,
4
+ rule patterns, and severity levels.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from dataclasses import dataclass, field
10
+ from typing import TYPE_CHECKING
11
+
12
+ if TYPE_CHECKING:
13
+ from collections.abc import Sequence
14
+
15
+ from kekkai.scanners.base import Finding
16
+
17
+
18
+ @dataclass(frozen=True)
19
+ class FrameworkControl:
20
+ """A single compliance framework control."""
21
+
22
+ framework: str
23
+ control_id: str
24
+ title: str
25
+ description: str
26
+ requirement_level: str = "required" # required, recommended, optional
27
+
28
+
29
+ @dataclass
30
+ class ComplianceMapping:
31
+ """Mapping of a finding to compliance controls."""
32
+
33
+ finding_hash: str
34
+ finding_title: str
35
+ finding_severity: str
36
+ controls: list[FrameworkControl] = field(default_factory=list)
37
+
38
+ def add_control(self, control: FrameworkControl) -> None:
39
+ """Add a control to this mapping."""
40
+ self.controls.append(control)
41
+
42
+ def has_framework(self, framework: str) -> bool:
43
+ """Check if any control from a framework is mapped."""
44
+ return any(c.framework == framework for c in self.controls)
45
+
46
+
47
+ @dataclass
48
+ class ComplianceMappingResult:
49
+ """Result of mapping findings to all frameworks."""
50
+
51
+ mappings: list[ComplianceMapping] = field(default_factory=list)
52
+ framework_summary: dict[str, int] = field(default_factory=dict)
53
+ unmapped_count: int = 0
54
+ total_findings: int = 0
55
+
56
+ def get_controls_by_framework(self, framework: str) -> list[FrameworkControl]:
57
+ """Get all unique controls for a framework."""
58
+ seen: set[str] = set()
59
+ result: list[FrameworkControl] = []
60
+ for mapping in self.mappings:
61
+ for control in mapping.controls:
62
+ if control.framework == framework and control.control_id not in seen:
63
+ seen.add(control.control_id)
64
+ result.append(control)
65
+ return sorted(result, key=lambda c: c.control_id)
66
+
67
+ def get_findings_for_control(self, framework: str, control_id: str) -> list[ComplianceMapping]:
68
+ """Get all findings mapped to a specific control."""
69
+ return [
70
+ m
71
+ for m in self.mappings
72
+ if any(c.framework == framework and c.control_id == control_id for c in m.controls)
73
+ ]
74
+
75
+
76
+ def map_finding_to_frameworks(finding: Finding) -> ComplianceMapping:
77
+ """Map a single finding to all applicable compliance frameworks."""
78
+ from .hipaa import map_to_hipaa
79
+ from .owasp import map_to_owasp
80
+ from .owasp_agentic import map_to_owasp_agentic
81
+ from .pci_dss import map_to_pci_dss
82
+ from .soc2 import map_to_soc2
83
+
84
+ mapping = ComplianceMapping(
85
+ finding_hash=finding.dedupe_hash(),
86
+ finding_title=finding.title,
87
+ finding_severity=finding.severity.value,
88
+ )
89
+
90
+ # Map to each framework
91
+ for control in map_to_pci_dss(finding):
92
+ mapping.add_control(control)
93
+
94
+ for control in map_to_soc2(finding):
95
+ mapping.add_control(control)
96
+
97
+ for control in map_to_owasp(finding):
98
+ mapping.add_control(control)
99
+
100
+ for control in map_to_owasp_agentic(finding):
101
+ mapping.add_control(control)
102
+
103
+ for control in map_to_hipaa(finding):
104
+ mapping.add_control(control)
105
+
106
+ return mapping
107
+
108
+
109
+ def map_findings_to_all_frameworks(
110
+ findings: Sequence[Finding],
111
+ ) -> ComplianceMappingResult:
112
+ """Map all findings to compliance frameworks."""
113
+ result = ComplianceMappingResult(total_findings=len(findings))
114
+
115
+ framework_counts: dict[str, set[str]] = {
116
+ "PCI-DSS": set(),
117
+ "SOC2": set(),
118
+ "OWASP": set(),
119
+ "OWASP-Agentic": set(),
120
+ "HIPAA": set(),
121
+ }
122
+
123
+ for finding in findings:
124
+ mapping = map_finding_to_frameworks(finding)
125
+ result.mappings.append(mapping)
126
+
127
+ if not mapping.controls:
128
+ result.unmapped_count += 1
129
+ else:
130
+ for control in mapping.controls:
131
+ if control.framework in framework_counts:
132
+ framework_counts[control.framework].add(control.control_id)
133
+
134
+ result.framework_summary = {k: len(v) for k, v in framework_counts.items()}
135
+
136
+ return result