regscale-cli 6.27.2.0__py3-none-any.whl → 6.28.0.0__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.
Potentially problematic release.
This version of regscale-cli might be problematic. Click here for more details.
- regscale/_version.py +1 -1
- regscale/core/app/application.py +1 -0
- regscale/core/app/internal/control_editor.py +73 -21
- regscale/core/app/internal/login.py +4 -1
- regscale/core/app/internal/model_editor.py +219 -64
- regscale/core/app/utils/app_utils.py +11 -2
- regscale/core/login.py +21 -4
- regscale/core/utils/date.py +77 -1
- regscale/dev/cli.py +26 -0
- regscale/dev/version.py +72 -0
- regscale/integrations/commercial/__init__.py +15 -1
- regscale/integrations/commercial/amazon/amazon/__init__.py +0 -0
- regscale/integrations/commercial/amazon/amazon/common.py +204 -0
- regscale/integrations/commercial/amazon/common.py +48 -58
- regscale/integrations/commercial/aws/audit_manager_compliance.py +2671 -0
- regscale/integrations/commercial/aws/cli.py +3093 -55
- regscale/integrations/commercial/aws/cloudtrail_control_mappings.py +333 -0
- regscale/integrations/commercial/aws/cloudtrail_evidence.py +501 -0
- regscale/integrations/commercial/aws/cloudwatch_control_mappings.py +357 -0
- regscale/integrations/commercial/aws/cloudwatch_evidence.py +490 -0
- regscale/integrations/commercial/aws/config_compliance.py +914 -0
- regscale/integrations/commercial/aws/conformance_pack_mappings.py +198 -0
- regscale/integrations/commercial/aws/evidence_generator.py +283 -0
- regscale/integrations/commercial/aws/guardduty_control_mappings.py +340 -0
- regscale/integrations/commercial/aws/guardduty_evidence.py +1053 -0
- regscale/integrations/commercial/aws/iam_control_mappings.py +368 -0
- regscale/integrations/commercial/aws/iam_evidence.py +574 -0
- regscale/integrations/commercial/aws/inventory/__init__.py +223 -22
- regscale/integrations/commercial/aws/inventory/base.py +107 -5
- regscale/integrations/commercial/aws/inventory/resources/audit_manager.py +513 -0
- regscale/integrations/commercial/aws/inventory/resources/cloudtrail.py +315 -0
- regscale/integrations/commercial/aws/inventory/resources/cloudtrail_logs_metadata.py +476 -0
- regscale/integrations/commercial/aws/inventory/resources/cloudwatch.py +191 -0
- regscale/integrations/commercial/aws/inventory/resources/compute.py +66 -9
- regscale/integrations/commercial/aws/inventory/resources/config.py +464 -0
- regscale/integrations/commercial/aws/inventory/resources/containers.py +74 -9
- regscale/integrations/commercial/aws/inventory/resources/database.py +106 -31
- regscale/integrations/commercial/aws/inventory/resources/guardduty.py +286 -0
- regscale/integrations/commercial/aws/inventory/resources/iam.py +470 -0
- regscale/integrations/commercial/aws/inventory/resources/inspector.py +476 -0
- regscale/integrations/commercial/aws/inventory/resources/integration.py +175 -61
- regscale/integrations/commercial/aws/inventory/resources/kms.py +447 -0
- regscale/integrations/commercial/aws/inventory/resources/networking.py +103 -67
- regscale/integrations/commercial/aws/inventory/resources/s3.py +394 -0
- regscale/integrations/commercial/aws/inventory/resources/security.py +268 -72
- regscale/integrations/commercial/aws/inventory/resources/securityhub.py +473 -0
- regscale/integrations/commercial/aws/inventory/resources/storage.py +53 -29
- regscale/integrations/commercial/aws/inventory/resources/systems_manager.py +657 -0
- regscale/integrations/commercial/aws/inventory/resources/vpc.py +655 -0
- regscale/integrations/commercial/aws/kms_control_mappings.py +288 -0
- regscale/integrations/commercial/aws/kms_evidence.py +879 -0
- regscale/integrations/commercial/aws/ocsf/__init__.py +7 -0
- regscale/integrations/commercial/aws/ocsf/constants.py +115 -0
- regscale/integrations/commercial/aws/ocsf/mapper.py +435 -0
- regscale/integrations/commercial/aws/org_control_mappings.py +286 -0
- regscale/integrations/commercial/aws/org_evidence.py +666 -0
- regscale/integrations/commercial/aws/s3_control_mappings.py +356 -0
- regscale/integrations/commercial/aws/s3_evidence.py +632 -0
- regscale/integrations/commercial/aws/scanner.py +853 -205
- regscale/integrations/commercial/aws/security_hub.py +319 -0
- regscale/integrations/commercial/aws/session_manager.py +282 -0
- regscale/integrations/commercial/aws/ssm_control_mappings.py +291 -0
- regscale/integrations/commercial/aws/ssm_evidence.py +492 -0
- regscale/integrations/commercial/synqly/query_builder.py +4 -1
- regscale/integrations/compliance_integration.py +308 -38
- regscale/integrations/control_matcher.py +78 -23
- regscale/integrations/due_date_handler.py +3 -0
- regscale/integrations/public/csam/csam.py +572 -763
- regscale/integrations/public/csam/csam_agency_defined.py +179 -0
- regscale/integrations/public/csam/csam_common.py +154 -0
- regscale/integrations/public/csam/csam_controls.py +432 -0
- regscale/integrations/public/csam/csam_poam.py +124 -0
- regscale/integrations/public/fedramp/click.py +17 -4
- regscale/integrations/public/fedramp/fedramp_cis_crm.py +271 -62
- regscale/integrations/public/fedramp/poam/scanner.py +74 -7
- regscale/integrations/scanner_integration.py +415 -85
- regscale/models/integration_models/cisa_kev_data.json +80 -20
- regscale/models/integration_models/synqly_models/capabilities.json +1 -1
- regscale/models/integration_models/synqly_models/connectors/vulnerabilities.py +44 -3
- regscale/models/integration_models/synqly_models/ocsf_mapper.py +41 -12
- regscale/models/platform.py +3 -0
- regscale/models/regscale_models/__init__.py +5 -0
- regscale/models/regscale_models/assessment.py +2 -1
- regscale/models/regscale_models/component.py +1 -1
- regscale/models/regscale_models/control_implementation.py +55 -24
- regscale/models/regscale_models/control_objective.py +74 -5
- regscale/models/regscale_models/file.py +2 -0
- regscale/models/regscale_models/issue.py +2 -5
- regscale/models/regscale_models/organization.py +3 -0
- regscale/models/regscale_models/regscale_model.py +17 -5
- regscale/models/regscale_models/security_plan.py +1 -0
- regscale/regscale.py +11 -1
- {regscale_cli-6.27.2.0.dist-info → regscale_cli-6.28.0.0.dist-info}/METADATA +1 -1
- {regscale_cli-6.27.2.0.dist-info → regscale_cli-6.28.0.0.dist-info}/RECORD +140 -57
- tests/regscale/core/test_login.py +171 -4
- tests/regscale/integrations/commercial/aws/__init__.py +0 -0
- tests/regscale/integrations/commercial/aws/test_audit_manager_compliance.py +1304 -0
- tests/regscale/integrations/commercial/aws/test_audit_manager_evidence_aggregation.py +341 -0
- tests/regscale/integrations/commercial/aws/test_aws_audit_manager_collector.py +1155 -0
- tests/regscale/integrations/commercial/aws/test_aws_cloudtrail_collector.py +534 -0
- tests/regscale/integrations/commercial/aws/test_aws_config_collector.py +400 -0
- tests/regscale/integrations/commercial/aws/test_aws_guardduty_collector.py +315 -0
- tests/regscale/integrations/commercial/aws/test_aws_iam_collector.py +458 -0
- tests/regscale/integrations/commercial/aws/test_aws_inspector_collector.py +353 -0
- tests/regscale/integrations/commercial/aws/test_aws_inventory_integration.py +530 -0
- tests/regscale/integrations/commercial/aws/test_aws_kms_collector.py +919 -0
- tests/regscale/integrations/commercial/aws/test_aws_s3_collector.py +722 -0
- tests/regscale/integrations/commercial/aws/test_aws_scanner_integration.py +722 -0
- tests/regscale/integrations/commercial/aws/test_aws_securityhub_collector.py +792 -0
- tests/regscale/integrations/commercial/aws/test_aws_systems_manager_collector.py +918 -0
- tests/regscale/integrations/commercial/aws/test_aws_vpc_collector.py +996 -0
- tests/regscale/integrations/commercial/aws/test_cli_evidence.py +431 -0
- tests/regscale/integrations/commercial/aws/test_cloudtrail_control_mappings.py +452 -0
- tests/regscale/integrations/commercial/aws/test_cloudtrail_evidence.py +788 -0
- tests/regscale/integrations/commercial/aws/test_config_compliance.py +298 -0
- tests/regscale/integrations/commercial/aws/test_conformance_pack_mappings.py +200 -0
- tests/regscale/integrations/commercial/aws/test_evidence_generator.py +386 -0
- tests/regscale/integrations/commercial/aws/test_guardduty_control_mappings.py +564 -0
- tests/regscale/integrations/commercial/aws/test_guardduty_evidence.py +1041 -0
- tests/regscale/integrations/commercial/aws/test_iam_control_mappings.py +718 -0
- tests/regscale/integrations/commercial/aws/test_iam_evidence.py +1375 -0
- tests/regscale/integrations/commercial/aws/test_kms_control_mappings.py +656 -0
- tests/regscale/integrations/commercial/aws/test_kms_evidence.py +1163 -0
- tests/regscale/integrations/commercial/aws/test_ocsf_mapper.py +370 -0
- tests/regscale/integrations/commercial/aws/test_org_control_mappings.py +546 -0
- tests/regscale/integrations/commercial/aws/test_org_evidence.py +1240 -0
- tests/regscale/integrations/commercial/aws/test_s3_control_mappings.py +672 -0
- tests/regscale/integrations/commercial/aws/test_s3_evidence.py +987 -0
- tests/regscale/integrations/commercial/aws/test_scanner_evidence.py +373 -0
- tests/regscale/integrations/commercial/aws/test_security_hub_config_filtering.py +539 -0
- tests/regscale/integrations/commercial/aws/test_session_manager.py +516 -0
- tests/regscale/integrations/commercial/aws/test_ssm_control_mappings.py +588 -0
- tests/regscale/integrations/commercial/aws/test_ssm_evidence.py +735 -0
- tests/regscale/integrations/commercial/test_aws.py +55 -56
- tests/regscale/integrations/test_control_matcher.py +24 -0
- tests/regscale/models/test_control_implementation.py +118 -3
- {regscale_cli-6.27.2.0.dist-info → regscale_cli-6.28.0.0.dist-info}/LICENSE +0 -0
- {regscale_cli-6.27.2.0.dist-info → regscale_cli-6.28.0.0.dist-info}/WHEEL +0 -0
- {regscale_cli-6.27.2.0.dist-info → regscale_cli-6.28.0.0.dist-info}/entry_points.txt +0 -0
- {regscale_cli-6.27.2.0.dist-info → regscale_cli-6.28.0.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""AWS Organizations Control Mappings for RegScale Compliance Integration."""
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
from typing import Dict, List, Optional
|
|
7
|
+
|
|
8
|
+
logger = logging.getLogger("regscale")
|
|
9
|
+
|
|
10
|
+
# NIST 800-53 R5 Control Mappings for AWS Organizations
|
|
11
|
+
ORG_CONTROL_MAPPINGS = {
|
|
12
|
+
"AC-1": {
|
|
13
|
+
"name": "Policy and Procedures",
|
|
14
|
+
"description": "Develop, document, and disseminate access control policy and procedures",
|
|
15
|
+
"checks": {
|
|
16
|
+
"scp_attached": {
|
|
17
|
+
"weight": 100,
|
|
18
|
+
"pass_criteria": "Organization has Service Control Policies attached to enforce access controls",
|
|
19
|
+
"fail_criteria": "No SCPs attached or SCPs not enforcing proper access restrictions",
|
|
20
|
+
},
|
|
21
|
+
"organizational_structure": {
|
|
22
|
+
"weight": 80,
|
|
23
|
+
"pass_criteria": "Clear OU hierarchy established for governance",
|
|
24
|
+
"fail_criteria": "Flat structure with no organizational units",
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
"PM-9": {
|
|
29
|
+
"name": "Risk Management Strategy",
|
|
30
|
+
"description": "Develop comprehensive risk management strategy for the organization",
|
|
31
|
+
"checks": {
|
|
32
|
+
"account_governance": {
|
|
33
|
+
"weight": 100,
|
|
34
|
+
"pass_criteria": "Accounts organized by risk profile (prod, dev, sandbox) with appropriate SCPs",
|
|
35
|
+
"fail_criteria": "All accounts in same OU without risk-based segmentation",
|
|
36
|
+
},
|
|
37
|
+
"policy_enforcement": {
|
|
38
|
+
"weight": 90,
|
|
39
|
+
"pass_criteria": "SCPs enforce security guardrails (e.g., region restrictions, service restrictions)",
|
|
40
|
+
"fail_criteria": "No restrictive SCPs or only default FullAWSAccess policy",
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
"AC-2": {
|
|
45
|
+
"name": "Account Management",
|
|
46
|
+
"description": "Manage system accounts including creation, enabling, modification, and removal",
|
|
47
|
+
"checks": {
|
|
48
|
+
"active_accounts": {
|
|
49
|
+
"weight": 100,
|
|
50
|
+
"pass_criteria": "All accounts are ACTIVE with proper metadata (email, name)",
|
|
51
|
+
"fail_criteria": "SUSPENDED or accounts missing contact information",
|
|
52
|
+
},
|
|
53
|
+
"account_tracking": {
|
|
54
|
+
"weight": 80,
|
|
55
|
+
"pass_criteria": "Accounts have tags or metadata for ownership and purpose",
|
|
56
|
+
"fail_criteria": "Accounts lack identification or ownership information",
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
"AC-6": {
|
|
61
|
+
"name": "Least Privilege",
|
|
62
|
+
"description": "Employ the principle of least privilege",
|
|
63
|
+
"checks": {
|
|
64
|
+
"restrictive_scps": {
|
|
65
|
+
"weight": 100,
|
|
66
|
+
"pass_criteria": "SCPs implement least privilege by denying unnecessary services/actions",
|
|
67
|
+
"fail_criteria": "SCPs use FullAWSAccess or overly permissive policies",
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
# ISO 27001 Control Mappings
|
|
74
|
+
ISO_27001_MAPPINGS = {
|
|
75
|
+
"A.6.1.1": {
|
|
76
|
+
"name": "Information security roles and responsibilities",
|
|
77
|
+
"org_attributes": ["organizational_units", "account_tags", "scp_policies"],
|
|
78
|
+
},
|
|
79
|
+
"A.6.1.2": {
|
|
80
|
+
"name": "Segregation of duties",
|
|
81
|
+
"org_attributes": ["organizational_structure", "scp_enforcement", "account_separation"],
|
|
82
|
+
},
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
# SCP patterns that indicate good security posture
|
|
86
|
+
RESTRICTIVE_SCP_PATTERNS = [
|
|
87
|
+
"DenyAllOutsideRegion",
|
|
88
|
+
"RestrictRegions",
|
|
89
|
+
"DenyRootAccount",
|
|
90
|
+
"RequireMFA",
|
|
91
|
+
"DenyLeaveOrganization",
|
|
92
|
+
"PreventSCPRemoval",
|
|
93
|
+
"DenyCloudTrailDelete",
|
|
94
|
+
"DenyGuardDutyDisable",
|
|
95
|
+
"DenyConfigDisable",
|
|
96
|
+
]
|
|
97
|
+
|
|
98
|
+
# Account statuses that are compliant
|
|
99
|
+
COMPLIANT_ACCOUNT_STATUSES = ["ACTIVE"]
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class OrgControlMapper:
|
|
103
|
+
"""Map AWS Organizations attributes to compliance control status."""
|
|
104
|
+
|
|
105
|
+
def __init__(self, framework: str = "NIST800-53R5"):
|
|
106
|
+
"""
|
|
107
|
+
Initialize Organizations control mapper.
|
|
108
|
+
|
|
109
|
+
:param str framework: Compliance framework (NIST800-53R5 or ISO27001)
|
|
110
|
+
"""
|
|
111
|
+
self.framework = framework
|
|
112
|
+
self.mappings = ORG_CONTROL_MAPPINGS if framework == "NIST800-53R5" else ISO_27001_MAPPINGS
|
|
113
|
+
|
|
114
|
+
def assess_organization_compliance(self, org_data: Dict) -> Dict[str, str]:
|
|
115
|
+
"""
|
|
116
|
+
Assess AWS Organizations compliance against all mapped controls.
|
|
117
|
+
|
|
118
|
+
:param Dict org_data: Organization structure and metadata
|
|
119
|
+
:return: Dictionary mapping control IDs to compliance results (PASS/FAIL)
|
|
120
|
+
:rtype: Dict[str, str]
|
|
121
|
+
"""
|
|
122
|
+
results = {}
|
|
123
|
+
|
|
124
|
+
if self.framework == "NIST800-53R5":
|
|
125
|
+
results["AC-1"] = self._assess_ac1(org_data)
|
|
126
|
+
results["PM-9"] = self._assess_pm9(org_data)
|
|
127
|
+
results["AC-2"] = self._assess_ac2(org_data)
|
|
128
|
+
results["AC-6"] = self._assess_ac6(org_data)
|
|
129
|
+
|
|
130
|
+
return results
|
|
131
|
+
|
|
132
|
+
def _assess_ac1(self, org_data: Dict) -> str:
|
|
133
|
+
"""
|
|
134
|
+
Assess AC-1 (Access Control Policy and Procedures) compliance.
|
|
135
|
+
|
|
136
|
+
:param Dict org_data: Organization data
|
|
137
|
+
:return: Compliance result (PASS/FAIL)
|
|
138
|
+
:rtype: str
|
|
139
|
+
"""
|
|
140
|
+
scps = org_data.get("service_control_policies", [])
|
|
141
|
+
ous = org_data.get("organizational_units", [])
|
|
142
|
+
|
|
143
|
+
# Check if organization has SCPs beyond default FullAWSAccess
|
|
144
|
+
restrictive_scps = [scp for scp in scps if scp.get("Name") != "FullAWSAccess"]
|
|
145
|
+
|
|
146
|
+
if not restrictive_scps:
|
|
147
|
+
logger.debug("Organization FAILS AC-1: No restrictive SCPs attached")
|
|
148
|
+
return "FAIL"
|
|
149
|
+
|
|
150
|
+
# Check for organizational structure (OUs)
|
|
151
|
+
if len(ous) < 2: # Should have at least root + 1 OU
|
|
152
|
+
logger.debug("Organization FAILS AC-1: No organizational structure (only root OU)")
|
|
153
|
+
return "FAIL"
|
|
154
|
+
|
|
155
|
+
logger.debug(f"Organization PASSES AC-1: {len(restrictive_scps)} restrictive SCPs, {len(ous)} OUs")
|
|
156
|
+
return "PASS"
|
|
157
|
+
|
|
158
|
+
def _assess_pm9(self, org_data: Dict) -> str:
|
|
159
|
+
"""
|
|
160
|
+
Assess PM-9 (Risk Management Strategy) compliance.
|
|
161
|
+
|
|
162
|
+
:param Dict org_data: Organization data
|
|
163
|
+
:return: Compliance result (PASS/FAIL)
|
|
164
|
+
:rtype: str
|
|
165
|
+
"""
|
|
166
|
+
ous = org_data.get("organizational_units", [])
|
|
167
|
+
scps = org_data.get("service_control_policies", [])
|
|
168
|
+
|
|
169
|
+
# Check for risk-based OU structure (prod, dev, sandbox, etc.)
|
|
170
|
+
ou_names = [ou.get("Name", "").lower() for ou in ous]
|
|
171
|
+
has_env_separation = any(
|
|
172
|
+
env in " ".join(ou_names) for env in ["prod", "production", "dev", "development", "sandbox", "test"]
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
if not has_env_separation:
|
|
176
|
+
logger.debug("Organization FAILS PM-9: No environment-based OU separation")
|
|
177
|
+
return "FAIL"
|
|
178
|
+
|
|
179
|
+
# Check for restrictive SCPs
|
|
180
|
+
has_restrictive_scps = any(
|
|
181
|
+
any(pattern.lower() in scp.get("Name", "").lower() for pattern in RESTRICTIVE_SCP_PATTERNS) for scp in scps
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
if not has_restrictive_scps:
|
|
185
|
+
logger.debug("Organization FAILS PM-9: No restrictive SCPs enforcing security guardrails")
|
|
186
|
+
return "FAIL"
|
|
187
|
+
|
|
188
|
+
logger.debug("Organization PASSES PM-9: Environment separation and restrictive SCPs present")
|
|
189
|
+
return "PASS"
|
|
190
|
+
|
|
191
|
+
def _assess_ac2(self, org_data: Dict) -> str:
|
|
192
|
+
"""
|
|
193
|
+
Assess AC-2 (Account Management) compliance.
|
|
194
|
+
|
|
195
|
+
:param Dict org_data: Organization data
|
|
196
|
+
:return: Compliance result (PASS/FAIL)
|
|
197
|
+
:rtype: str
|
|
198
|
+
"""
|
|
199
|
+
accounts = org_data.get("accounts", [])
|
|
200
|
+
|
|
201
|
+
if not accounts:
|
|
202
|
+
logger.debug("Organization FAILS AC-2: No accounts found")
|
|
203
|
+
return "FAIL"
|
|
204
|
+
|
|
205
|
+
# Check account statuses
|
|
206
|
+
non_active_accounts = [acc for acc in accounts if acc.get("Status") not in COMPLIANT_ACCOUNT_STATUSES]
|
|
207
|
+
|
|
208
|
+
if non_active_accounts:
|
|
209
|
+
logger.debug(f"Organization FAILS AC-2: {len(non_active_accounts)} accounts not in ACTIVE status")
|
|
210
|
+
return "FAIL"
|
|
211
|
+
|
|
212
|
+
# Check for accounts missing email
|
|
213
|
+
accounts_missing_email = [acc for acc in accounts if not acc.get("Email")]
|
|
214
|
+
|
|
215
|
+
if accounts_missing_email:
|
|
216
|
+
logger.debug(f"Organization FAILS AC-2: {len(accounts_missing_email)} accounts missing contact email")
|
|
217
|
+
return "FAIL"
|
|
218
|
+
|
|
219
|
+
logger.debug(f"Organization PASSES AC-2: All {len(accounts)} accounts are ACTIVE with contact info")
|
|
220
|
+
return "PASS"
|
|
221
|
+
|
|
222
|
+
def _assess_ac6(self, org_data: Dict) -> str:
|
|
223
|
+
"""
|
|
224
|
+
Assess AC-6 (Least Privilege) compliance.
|
|
225
|
+
|
|
226
|
+
:param Dict org_data: Organization data
|
|
227
|
+
:return: Compliance result (PASS/FAIL)
|
|
228
|
+
:rtype: str
|
|
229
|
+
"""
|
|
230
|
+
scps = org_data.get("service_control_policies", [])
|
|
231
|
+
|
|
232
|
+
# Check if only FullAWSAccess is attached (not least privilege)
|
|
233
|
+
only_full_access = len(scps) == 1 and scps[0].get("Name") == "FullAWSAccess"
|
|
234
|
+
|
|
235
|
+
if only_full_access:
|
|
236
|
+
logger.debug("Organization FAILS AC-6: Only FullAWSAccess SCP attached (not least privilege)")
|
|
237
|
+
return "FAIL"
|
|
238
|
+
|
|
239
|
+
# Check for at least one restrictive SCP
|
|
240
|
+
has_restrictive = any(
|
|
241
|
+
any(pattern.lower() in scp.get("Name", "").lower() for pattern in RESTRICTIVE_SCP_PATTERNS)
|
|
242
|
+
or "Deny" in scp.get("Name", "")
|
|
243
|
+
for scp in scps
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
if not has_restrictive:
|
|
247
|
+
logger.debug("Organization FAILS AC-6: No restrictive/deny SCPs implementing least privilege")
|
|
248
|
+
return "FAIL"
|
|
249
|
+
|
|
250
|
+
logger.debug("Organization PASSES AC-6: Restrictive SCPs implementing least privilege")
|
|
251
|
+
return "PASS"
|
|
252
|
+
|
|
253
|
+
def get_control_description(self, control_id: str) -> Optional[str]:
|
|
254
|
+
"""
|
|
255
|
+
Get human-readable description for a control.
|
|
256
|
+
|
|
257
|
+
:param str control_id: Control identifier (e.g., AC-1)
|
|
258
|
+
:return: Control description or None
|
|
259
|
+
:rtype: Optional[str]
|
|
260
|
+
"""
|
|
261
|
+
control_data = self.mappings.get(control_id)
|
|
262
|
+
if control_data:
|
|
263
|
+
return f"{control_data.get('name')}: {control_data.get('description', '')}"
|
|
264
|
+
return None
|
|
265
|
+
|
|
266
|
+
def get_mapped_controls(self) -> List[str]:
|
|
267
|
+
"""
|
|
268
|
+
Get list of all control IDs mapped for this framework.
|
|
269
|
+
|
|
270
|
+
:return: List of control IDs
|
|
271
|
+
:rtype: List[str]
|
|
272
|
+
"""
|
|
273
|
+
return list(self.mappings.keys())
|
|
274
|
+
|
|
275
|
+
def get_check_details(self, control_id: str) -> Optional[Dict]:
|
|
276
|
+
"""
|
|
277
|
+
Get detailed check criteria for a control.
|
|
278
|
+
|
|
279
|
+
:param str control_id: Control identifier
|
|
280
|
+
:return: Dictionary of check details or None
|
|
281
|
+
:rtype: Optional[Dict]
|
|
282
|
+
"""
|
|
283
|
+
control_data = self.mappings.get(control_id)
|
|
284
|
+
if control_data:
|
|
285
|
+
return control_data.get("checks", {})
|
|
286
|
+
return None
|