regscale-cli 6.20.4.1__py3-none-any.whl → 6.20.6.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/__init__.py +1 -1
- regscale/_version.py +39 -0
- regscale/core/app/internal/__init__.py +13 -0
- regscale/core/app/internal/model_editor.py +3 -3
- regscale/core/app/internal/set_permissions.py +173 -0
- regscale/core/app/utils/file_utils.py +11 -1
- regscale/core/app/utils/regscale_utils.py +34 -129
- regscale/core/utils/date.py +86 -30
- regscale/integrations/commercial/defender.py +3 -0
- regscale/integrations/commercial/qualys/__init__.py +40 -14
- regscale/integrations/commercial/qualys/containers.py +324 -0
- regscale/integrations/commercial/qualys/scanner.py +203 -8
- regscale/integrations/commercial/synqly/edr.py +10 -0
- regscale/integrations/commercial/wizv2/click.py +11 -7
- regscale/integrations/commercial/wizv2/constants.py +28 -0
- regscale/integrations/commercial/wizv2/issue.py +3 -2
- regscale/integrations/commercial/wizv2/parsers.py +23 -0
- regscale/integrations/commercial/wizv2/scanner.py +89 -30
- regscale/integrations/commercial/wizv2/utils.py +208 -75
- regscale/integrations/commercial/wizv2/variables.py +2 -1
- regscale/integrations/commercial/wizv2/wiz_auth.py +3 -3
- regscale/integrations/public/fedramp/fedramp_cis_crm.py +98 -20
- regscale/integrations/public/fedramp/fedramp_docx.py +2 -3
- regscale/integrations/scanner_integration.py +7 -2
- regscale/models/integration_models/cisa_kev_data.json +187 -5
- regscale/models/integration_models/synqly_models/capabilities.json +1 -1
- regscale/models/regscale_models/__init__.py +2 -0
- regscale/models/regscale_models/asset.py +1 -1
- regscale/models/regscale_models/catalog.py +16 -0
- regscale/models/regscale_models/file.py +2 -1
- regscale/models/regscale_models/form_field_value.py +59 -1
- regscale/models/regscale_models/issue.py +47 -0
- regscale/models/regscale_models/modules.py +88 -1
- regscale/models/regscale_models/organization.py +30 -0
- regscale/models/regscale_models/regscale_model.py +20 -6
- regscale/models/regscale_models/security_control.py +47 -0
- regscale/models/regscale_models/security_plan.py +32 -0
- regscale/models/regscale_models/vulnerability.py +3 -3
- regscale/models/regscale_models/vulnerability_mapping.py +2 -2
- regscale/regscale.py +2 -0
- {regscale_cli-6.20.4.1.dist-info → regscale_cli-6.20.6.0.dist-info}/METADATA +1 -1
- {regscale_cli-6.20.4.1.dist-info → regscale_cli-6.20.6.0.dist-info}/RECORD +49 -44
- tests/fixtures/test_fixture.py +33 -4
- tests/regscale/core/test_app.py +53 -32
- tests/regscale/test_init.py +94 -0
- {regscale_cli-6.20.4.1.dist-info → regscale_cli-6.20.6.0.dist-info}/LICENSE +0 -0
- {regscale_cli-6.20.4.1.dist-info → regscale_cli-6.20.6.0.dist-info}/WHEEL +0 -0
- {regscale_cli-6.20.4.1.dist-info → regscale_cli-6.20.6.0.dist-info}/entry_points.txt +0 -0
- {regscale_cli-6.20.4.1.dist-info → regscale_cli-6.20.6.0.dist-info}/top_level.txt +0 -0
|
@@ -16,8 +16,10 @@ from zipfile import ZipFile
|
|
|
16
16
|
import cachetools
|
|
17
17
|
import requests
|
|
18
18
|
from pydantic import ValidationError
|
|
19
|
+
from rich.progress import Progress, TaskID
|
|
19
20
|
|
|
20
21
|
from regscale.core.app.api import Api
|
|
22
|
+
from regscale.core.app.application import Application
|
|
21
23
|
from regscale.core.app.utils.app_utils import (
|
|
22
24
|
error_and_exit,
|
|
23
25
|
check_file_path,
|
|
@@ -27,19 +29,31 @@ from regscale.core.app.utils.app_utils import (
|
|
|
27
29
|
)
|
|
28
30
|
from regscale.core.utils.date import datetime_obj
|
|
29
31
|
from regscale.integrations.commercial.wizv2.constants import (
|
|
30
|
-
DOWNLOAD_QUERY,
|
|
31
32
|
BEARER,
|
|
32
|
-
|
|
33
|
+
CHECK_INTERVAL_FOR_DOWNLOAD_REPORT,
|
|
33
34
|
CONTENT_TYPE,
|
|
34
|
-
RATE_LIMIT_MSG,
|
|
35
35
|
CREATE_REPORT_QUERY,
|
|
36
|
+
DOWNLOAD_QUERY,
|
|
36
37
|
MAX_RETRIES,
|
|
37
|
-
|
|
38
|
+
RATE_LIMIT_MSG,
|
|
39
|
+
REPORTS_QUERY,
|
|
40
|
+
RERUN_REPORT_QUERY,
|
|
38
41
|
)
|
|
39
42
|
from regscale.integrations.commercial.wizv2.models import ComplianceReport, ComplianceCheckStatus
|
|
40
43
|
from regscale.integrations.commercial.wizv2.variables import WizVariables
|
|
41
44
|
from regscale.integrations.commercial.wizv2.wiz_auth import wiz_authenticate
|
|
42
|
-
from regscale.models import
|
|
45
|
+
from regscale.models import (
|
|
46
|
+
File,
|
|
47
|
+
Sbom,
|
|
48
|
+
SecurityControl,
|
|
49
|
+
SecurityPlan,
|
|
50
|
+
Catalog,
|
|
51
|
+
ControlImplementation,
|
|
52
|
+
Assessment,
|
|
53
|
+
regscale_models,
|
|
54
|
+
ControlImplementationStatus,
|
|
55
|
+
ImplementationObjective,
|
|
56
|
+
)
|
|
43
57
|
from regscale.utils import PaginatedGraphQLClient
|
|
44
58
|
from regscale.utils.decorators import deprecated
|
|
45
59
|
|
|
@@ -47,6 +61,31 @@ logger = logging.getLogger("regscale")
|
|
|
47
61
|
compliance_job_progress = create_progress_object()
|
|
48
62
|
|
|
49
63
|
|
|
64
|
+
def is_report_expired(report_run_at: str, max_age_days: int) -> bool:
|
|
65
|
+
"""
|
|
66
|
+
Check if a report is expired based on its run date
|
|
67
|
+
|
|
68
|
+
:param str report_run_at: Report run date in ISO format
|
|
69
|
+
:param int max_age_days: Maximum age in days
|
|
70
|
+
:return: True if report is expired, False otherwise
|
|
71
|
+
:rtype: bool
|
|
72
|
+
"""
|
|
73
|
+
try:
|
|
74
|
+
run_date = datetime_obj(report_run_at)
|
|
75
|
+
if not run_date:
|
|
76
|
+
return True
|
|
77
|
+
|
|
78
|
+
# Convert to naive datetime for comparison
|
|
79
|
+
run_date_naive = run_date.replace(tzinfo=None)
|
|
80
|
+
current_date = datetime.datetime.now()
|
|
81
|
+
age_in_days = (current_date - run_date_naive).days
|
|
82
|
+
|
|
83
|
+
return age_in_days >= max_age_days
|
|
84
|
+
except (ValueError, TypeError):
|
|
85
|
+
# If we can't parse the date, consider it expired
|
|
86
|
+
return True
|
|
87
|
+
|
|
88
|
+
|
|
50
89
|
def get_notes_from_wiz_props(wiz_entity_properties: Dict, external_id: str) -> str:
|
|
51
90
|
"""
|
|
52
91
|
Get notes from wiz properties
|
|
@@ -407,15 +446,28 @@ def get_or_create_report_id(
|
|
|
407
446
|
:param target_framework: Target framework name with underscores
|
|
408
447
|
:return: Single report ID
|
|
409
448
|
"""
|
|
449
|
+
app = Application()
|
|
450
|
+
report_age_days = app.config.get("wizReportAge", 15)
|
|
410
451
|
report_name = f"{target_framework}_project_{project_id}"
|
|
411
452
|
|
|
412
453
|
# Check for existing report with exact name
|
|
413
454
|
for report in existing_reports:
|
|
414
455
|
if report.get("name") == report_name:
|
|
415
456
|
logger.info(f"Found existing report '{report_name}' with ID {report['id']}")
|
|
416
|
-
return report["id"]
|
|
417
457
|
|
|
418
|
-
|
|
458
|
+
# Check if report is expired based on wizReportAge
|
|
459
|
+
run_at = report.get("lastRun", {}).get("runAt")
|
|
460
|
+
|
|
461
|
+
if run_at and is_report_expired(run_at, report_age_days):
|
|
462
|
+
logger.info(
|
|
463
|
+
f"Report '{report_name}' is expired (older than {report_age_days} days), will create new report"
|
|
464
|
+
)
|
|
465
|
+
break
|
|
466
|
+
else:
|
|
467
|
+
logger.info(f"Report '{report_name}' is still valid, using existing report")
|
|
468
|
+
return report["id"]
|
|
469
|
+
|
|
470
|
+
# Create new report if no valid existing report found
|
|
419
471
|
try:
|
|
420
472
|
framework_index = frameworks.index(target_framework)
|
|
421
473
|
framework_id = wiz_frameworks[framework_index].get("id")
|
|
@@ -439,13 +491,14 @@ def fetch_report_data(report_id: str) -> List[Dict]:
|
|
|
439
491
|
"""
|
|
440
492
|
try:
|
|
441
493
|
download_url = get_report_url_and_status(report_id)
|
|
442
|
-
logger.
|
|
494
|
+
logger.debug(f"Fetching report {report_id} from: {download_url}")
|
|
443
495
|
|
|
444
496
|
with closing(requests.get(url=download_url, stream=True, timeout=10)) as response:
|
|
445
497
|
response.raise_for_status()
|
|
446
|
-
logger.info(f"Streaming and parsing report {report_id}")
|
|
498
|
+
logger.info(f"Streaming and parsing report {report_id}...")
|
|
447
499
|
|
|
448
500
|
reader = csv.DictReader(codecs.iterdecode(response.iter_lines(), encoding="utf-8"), delimiter=",")
|
|
501
|
+
logger.info(f"Report {report_id} fetched successfully.")
|
|
449
502
|
return list(reader)
|
|
450
503
|
except requests.RequestException as e:
|
|
451
504
|
error_and_exit(f"Failed to fetch report {report_id}: {str(e)}")
|
|
@@ -586,7 +639,7 @@ def send_request(
|
|
|
586
639
|
"""
|
|
587
640
|
logger.debug("Sending a request to Wiz API")
|
|
588
641
|
api = Api()
|
|
589
|
-
payload =
|
|
642
|
+
payload = {"query": query, "variables": variables}
|
|
590
643
|
if api_endpoint_url is None:
|
|
591
644
|
api_endpoint_url = WizVariables.wizUrl
|
|
592
645
|
if WizVariables.wizAccessToken:
|
|
@@ -650,8 +703,7 @@ def get_report_url_and_status(report_id: str) -> str:
|
|
|
650
703
|
raise requests.RequestException("Failed to download report")
|
|
651
704
|
|
|
652
705
|
response_json = response.json()
|
|
653
|
-
errors
|
|
654
|
-
if errors:
|
|
706
|
+
if errors := response_json.get("errors"):
|
|
655
707
|
message = errors[0]["message"]
|
|
656
708
|
if RATE_LIMIT_MSG in message:
|
|
657
709
|
rate = errors[0]["extensions"]["retryAfter"]
|
|
@@ -664,6 +716,10 @@ def get_report_url_and_status(report_id: str) -> str:
|
|
|
664
716
|
status = response_json.get("data", {}).get("report", {}).get("lastRun", {}).get("status")
|
|
665
717
|
if status == "COMPLETED":
|
|
666
718
|
return response_json["data"]["report"]["lastRun"]["url"]
|
|
719
|
+
elif status == "EXPIRED":
|
|
720
|
+
logger.warning("Report %s is expired, rerunning report...", report_id)
|
|
721
|
+
rerun_expired_report({"reportId": report_id})
|
|
722
|
+
return get_report_url_and_status(report_id)
|
|
667
723
|
|
|
668
724
|
raise requests.RequestException("Download failed, exceeding the maximum number of retries")
|
|
669
725
|
|
|
@@ -680,13 +736,25 @@ def download_report(variables: Dict) -> requests.Response:
|
|
|
680
736
|
return response
|
|
681
737
|
|
|
682
738
|
|
|
739
|
+
def rerun_expired_report(variables: Dict) -> requests.Response:
|
|
740
|
+
"""
|
|
741
|
+
Rerun a report
|
|
742
|
+
|
|
743
|
+
:param Dict variables: Variables for Wiz request
|
|
744
|
+
:return: Response object from Wiz API
|
|
745
|
+
:rtype: requests.Response
|
|
746
|
+
"""
|
|
747
|
+
response = send_request(RERUN_REPORT_QUERY, variables=variables)
|
|
748
|
+
return response
|
|
749
|
+
|
|
750
|
+
|
|
683
751
|
def _sync_compliance(
|
|
684
752
|
wiz_project_id: str,
|
|
685
753
|
regscale_id: int,
|
|
686
754
|
regscale_module: str,
|
|
687
755
|
client_id: str,
|
|
688
756
|
client_secret: str,
|
|
689
|
-
catalog_id: int,
|
|
757
|
+
catalog_id: Optional[int] = None,
|
|
690
758
|
framework: Optional[str] = "NIST800-53R5",
|
|
691
759
|
) -> List[ComplianceReport]:
|
|
692
760
|
"""
|
|
@@ -697,7 +765,7 @@ def _sync_compliance(
|
|
|
697
765
|
:param str regscale_module: RegScale module
|
|
698
766
|
:param str client_id: Wiz Client ID
|
|
699
767
|
:param str client_secret: Wiz Client Secret
|
|
700
|
-
:param int catalog_id: Catalog ID, defaults to None
|
|
768
|
+
:param Optional[int] catalog_id: Catalog ID, defaults to None
|
|
701
769
|
:param Optional[str] framework: Framework, defaults to NIST800-53R5
|
|
702
770
|
:return: List of ComplianceReport objects
|
|
703
771
|
:rtype: List[ComplianceReport]
|
|
@@ -708,68 +776,84 @@ def _sync_compliance(
|
|
|
708
776
|
client_id=client_id,
|
|
709
777
|
client_secret=client_secret,
|
|
710
778
|
)
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
779
|
+
with compliance_job_progress:
|
|
780
|
+
report_job = compliance_job_progress.add_task("[#f68d1f]Fetching Wiz compliance report...", total=1)
|
|
781
|
+
fetch_regscale_data_job = compliance_job_progress.add_task(
|
|
782
|
+
"[#f68d1f]Fetching RegScale Catalog info for framework...", total=1
|
|
783
|
+
)
|
|
784
|
+
compliance_job_progress.update(report_job, completed=True, advance=1)
|
|
717
785
|
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
786
|
+
framework_mapping = {
|
|
787
|
+
"CSF": "NIST CSF v1.1",
|
|
788
|
+
"NIST800-53R5": "NIST SP 800-53 Revision 5",
|
|
789
|
+
"NIST800-53R4": "NIST SP 800-53 Revision 4",
|
|
790
|
+
}
|
|
791
|
+
sync_framework = framework_mapping.get(framework)
|
|
792
|
+
snake_framework = sync_framework.replace(" ", "_")
|
|
793
|
+
logger.debug(f"{snake_framework=}")
|
|
794
|
+
logger.info("Fetching Wiz compliance report for project ID %s...", wiz_project_id)
|
|
795
|
+
report_data = fetch_framework_report(wiz_project_id, snake_framework)
|
|
796
|
+
report_models = []
|
|
797
|
+
compliance_job_progress.update(report_job, completed=True, advance=1)
|
|
798
|
+
|
|
799
|
+
if catalog_id:
|
|
800
|
+
logger.info("Fetching all Controls for catalog #%s...", catalog_id)
|
|
801
|
+
catalog = Catalog.get_with_all_details(catalog_id=catalog_id)
|
|
802
|
+
controls = catalog.get("controls") if catalog else []
|
|
803
|
+
else:
|
|
804
|
+
# get all of the ControlImplementations for the security plan and get the controls from them
|
|
805
|
+
logger.info("Fetching all Controls for %s #%d...", regscale_module, regscale_id)
|
|
806
|
+
controls = SecurityControl.get_controls_by_parent_id_and_module(
|
|
807
|
+
parent_module=regscale_module, parent_id=regscale_id, return_dicts=True
|
|
808
|
+
)
|
|
809
|
+
logger.info("Received %d control(s) from RegScale.", len(controls))
|
|
810
|
+
|
|
811
|
+
passing_controls = {}
|
|
812
|
+
failing_controls = {}
|
|
813
|
+
controls_to_reports = {}
|
|
814
|
+
|
|
815
|
+
compliance_job_progress.update(fetch_regscale_data_job, completed=True, advance=1)
|
|
816
|
+
logger.info("Analyzing ComplianceReport for framework %s from Wiz...", sync_framework)
|
|
817
|
+
running_compliance_job = compliance_job_progress.add_task(
|
|
818
|
+
"[#f68d1f]Building compliance posture from wiz report...",
|
|
819
|
+
total=len(report_data),
|
|
820
|
+
)
|
|
821
|
+
for row in report_data:
|
|
822
|
+
try:
|
|
823
|
+
cr = ComplianceReport(**row)
|
|
824
|
+
if cr.framework == sync_framework:
|
|
825
|
+
check_compliance(
|
|
826
|
+
cr,
|
|
827
|
+
controls,
|
|
828
|
+
passing_controls,
|
|
829
|
+
failing_controls,
|
|
830
|
+
controls_to_reports,
|
|
831
|
+
)
|
|
832
|
+
report_models.append(cr)
|
|
833
|
+
except ValidationError:
|
|
834
|
+
error_message = traceback.format_exc()
|
|
835
|
+
logger.error(f"Error creating ComplianceReport: {error_message}")
|
|
836
|
+
finally:
|
|
755
837
|
compliance_job_progress.update(running_compliance_job, advance=1)
|
|
756
|
-
|
|
838
|
+
try:
|
|
839
|
+
saving_regscale_data_job = compliance_job_progress.add_task(
|
|
840
|
+
"[#f68d1f]Saving RegScale data...", total=len(controls_to_reports)
|
|
841
|
+
)
|
|
842
|
+
create_assessment_from_compliance_report(
|
|
843
|
+
controls_to_reports=controls_to_reports,
|
|
844
|
+
regscale_id=regscale_id,
|
|
845
|
+
regscale_module=regscale_module,
|
|
846
|
+
controls=controls,
|
|
847
|
+
progress=compliance_job_progress,
|
|
848
|
+
task=saving_regscale_data_job,
|
|
849
|
+
)
|
|
850
|
+
logger.info("Completed saving RegScale data.")
|
|
851
|
+
except Exception:
|
|
757
852
|
error_message = traceback.format_exc()
|
|
758
|
-
logger.error(f"Error creating
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
controls_to_reports=controls_to_reports,
|
|
763
|
-
regscale_id=regscale_id,
|
|
764
|
-
regscale_module=regscale_module,
|
|
765
|
-
controls=controls,
|
|
766
|
-
)
|
|
767
|
-
compliance_job_progress.update(saving_regscale_data_job, completed=True, advance=1)
|
|
768
|
-
|
|
769
|
-
except Exception:
|
|
770
|
-
error_message = traceback.format_exc()
|
|
771
|
-
logger.error(f"Error creating ControlImplementations from compliance report: {error_message}")
|
|
772
|
-
return report_models
|
|
853
|
+
logger.error(f"Error creating ControlImplementations from compliance report: {error_message}")
|
|
854
|
+
finally:
|
|
855
|
+
compliance_job_progress.update(saving_regscale_data_job, completed=True, advance=len(controls_to_reports))
|
|
856
|
+
return report_models
|
|
773
857
|
|
|
774
858
|
|
|
775
859
|
def check_compliance(
|
|
@@ -833,7 +917,7 @@ def _clean_passing_list(passing: Dict, failing: Dict) -> None:
|
|
|
833
917
|
|
|
834
918
|
|
|
835
919
|
def create_assessment_from_compliance_report(
|
|
836
|
-
controls_to_reports: Dict, regscale_id: int, regscale_module: str, controls: List
|
|
920
|
+
controls_to_reports: Dict, regscale_id: int, regscale_module: str, controls: List, progress: Progress, task: TaskID
|
|
837
921
|
) -> None:
|
|
838
922
|
"""
|
|
839
923
|
Create assessment from compliance report
|
|
@@ -842,6 +926,8 @@ def create_assessment_from_compliance_report(
|
|
|
842
926
|
:param int regscale_id: RegScale ID
|
|
843
927
|
:param str regscale_module: RegScale module
|
|
844
928
|
:param List controls: Controls
|
|
929
|
+
:param Progress progress: Progress object, used for progress bar updates
|
|
930
|
+
:param TaskID task: Task ID, used for progress bar updates
|
|
845
931
|
:return: None
|
|
846
932
|
:rtype: None
|
|
847
933
|
"""
|
|
@@ -854,6 +940,7 @@ def create_assessment_from_compliance_report(
|
|
|
854
940
|
break
|
|
855
941
|
filtered_results = [x for x in implementations if x.controlID == control_record_id]
|
|
856
942
|
create_report_assessment(filtered_results, reports, control_id)
|
|
943
|
+
progress.update(task, advance=1)
|
|
857
944
|
|
|
858
945
|
|
|
859
946
|
def create_report_assessment(filtered_results: List, reports: List, control_id: str) -> None:
|
|
@@ -870,7 +957,7 @@ def create_report_assessment(filtered_results: List, reports: List, control_id:
|
|
|
870
957
|
for report in reports:
|
|
871
958
|
html_summary = format_dict_to_html(report.dict())
|
|
872
959
|
if implementation:
|
|
873
|
-
Assessment(
|
|
960
|
+
a = Assessment(
|
|
874
961
|
leadAssessorId=implementation.createdById,
|
|
875
962
|
title=f"Wiz compliance report assessment for {control_id}",
|
|
876
963
|
assessmentType="Control Testing",
|
|
@@ -884,3 +971,49 @@ def create_report_assessment(filtered_results: List, reports: List, control_id:
|
|
|
884
971
|
parentModule="controls",
|
|
885
972
|
isPublic=True,
|
|
886
973
|
).create()
|
|
974
|
+
update_implementation_status(
|
|
975
|
+
implementation=implementation,
|
|
976
|
+
result=report.result,
|
|
977
|
+
)
|
|
978
|
+
logger.info(f"Created report assessment for {control_id}: {a.id}")
|
|
979
|
+
|
|
980
|
+
|
|
981
|
+
def update_implementation_status(implementation: ControlImplementation, result: str) -> ControlImplementation:
|
|
982
|
+
"""
|
|
983
|
+
Update implementation status based on the report result
|
|
984
|
+
|
|
985
|
+
:param ControlImplementation implementation: Control Implementation object
|
|
986
|
+
:param str result: Report result
|
|
987
|
+
:return: Updated Control Implementation object
|
|
988
|
+
:rtype: ControlImplementation
|
|
989
|
+
"""
|
|
990
|
+
objectives = ImplementationObjective.get_all_by_parent(
|
|
991
|
+
parent_module=implementation.get_module_slug(),
|
|
992
|
+
parent_id=implementation.id,
|
|
993
|
+
)
|
|
994
|
+
if objectives:
|
|
995
|
+
for objective in objectives:
|
|
996
|
+
objective.status = report_result_to_implementation_status(result)
|
|
997
|
+
objective.save()
|
|
998
|
+
logger.debug(f"Updated status for {objective.id}: {objective.status}")
|
|
999
|
+
else:
|
|
1000
|
+
implementation.objectives = []
|
|
1001
|
+
implementation.status = report_result_to_implementation_status(result)
|
|
1002
|
+
implementation.save()
|
|
1003
|
+
logger.info(f"Updated implementation status for {implementation.id}: {implementation.status}")
|
|
1004
|
+
|
|
1005
|
+
|
|
1006
|
+
def report_result_to_implementation_status(result: str) -> str:
|
|
1007
|
+
"""
|
|
1008
|
+
Convert report result to implementation status
|
|
1009
|
+
|
|
1010
|
+
:param str result: Report result
|
|
1011
|
+
:return: Implementation status
|
|
1012
|
+
:rtype: str
|
|
1013
|
+
"""
|
|
1014
|
+
if result == ComplianceCheckStatus.PASS.value:
|
|
1015
|
+
return ControlImplementationStatus.Implemented.value
|
|
1016
|
+
elif result == ComplianceCheckStatus.FAIL.value:
|
|
1017
|
+
return ControlImplementationStatus.InRemediation.value
|
|
1018
|
+
else:
|
|
1019
|
+
return ControlImplementationStatus.NotImplemented.value
|
|
@@ -31,7 +31,7 @@ class WizVariables(metaclass=RsVariablesMeta):
|
|
|
31
31
|
"PRIVATE_LINK", "RAW_ACCESS_POLICY", "REGISTERED_DOMAIN", "RESOURCE_GROUP", "SECRET",
|
|
32
32
|
"SECRET_CONTAINER", "SERVERLESS", "SERVERLESS_PACKAGE", "SERVICE_ACCOUNT", "SERVICE_CONFIGURATION",
|
|
33
33
|
"STORAGE_ACCOUNT", "SUBNET", "SUBSCRIPTION", "VIRTUAL_DESKTOP", "VIRTUAL_MACHINE",
|
|
34
|
-
"VIRTUAL_MACHINE_IMAGE", "VIRTUAL_NETWORK", "VOLUME", "WEB_SERVICE" ] }""",
|
|
34
|
+
"VIRTUAL_MACHINE_IMAGE", "VIRTUAL_NETWORK", "VOLUME", "WEB_SERVICE", "NETWORK_ADDRESS"] }""",
|
|
35
35
|
) # type: ignore
|
|
36
36
|
wizAccessToken: RsVariableType(str, "", sensitive=True, required=False) # type: ignore
|
|
37
37
|
wizClientId: RsVariableType(str, "", sensitive=True) # type: ignore
|
|
@@ -44,3 +44,4 @@ class WizVariables(metaclass=RsVariablesMeta):
|
|
|
44
44
|
default=["SERVER_APPLICATION", "CLIENT_APPLICATION", "VIRTUAL_APPLIANCE"],
|
|
45
45
|
required=False,
|
|
46
46
|
) # type: ignore
|
|
47
|
+
wizReportAge: RsVariableType(int, "14", default=14, required=False) # type: ignore
|
|
@@ -49,10 +49,10 @@ def wiz_authenticate(client_id: Optional[str] = None, client_secret: Optional[st
|
|
|
49
49
|
# get secrets
|
|
50
50
|
client_id = WizVariables.wizClientId if client_id is None else client_id
|
|
51
51
|
if not client_id:
|
|
52
|
-
|
|
52
|
+
error_and_exit("No Wiz Client ID provided in system environment or CLI command.")
|
|
53
53
|
client_secret = WizVariables.wizClientSecret if client_secret is None else client_secret
|
|
54
54
|
if not client_secret:
|
|
55
|
-
|
|
55
|
+
error_and_exit("No Wiz Client Secret provided in system environment or CLI command.")
|
|
56
56
|
wiz_auth_url = config.get("wizAuthUrl")
|
|
57
57
|
if not wiz_auth_url:
|
|
58
58
|
error_and_exit("No Wiz Authentication URL provided in the init.yaml file.")
|
|
@@ -100,7 +100,7 @@ def get_token(api: Api, client_id: str, client_secret: str, token_url: str) -> t
|
|
|
100
100
|
)
|
|
101
101
|
if response.ok:
|
|
102
102
|
status_code = 200
|
|
103
|
-
logger.
|
|
103
|
+
logger.info(response.reason)
|
|
104
104
|
# If response is unauthorized, try the first cognito url
|
|
105
105
|
if response.status_code == requests.codes.unauthorized:
|
|
106
106
|
try:
|