regscale-cli 6.16.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/__init__.py +1 -0
- regscale/airflow/__init__.py +9 -0
- regscale/airflow/azure/__init__.py +9 -0
- regscale/airflow/azure/cli.py +89 -0
- regscale/airflow/azure/upload_dags.py +116 -0
- regscale/airflow/click_dags.py +127 -0
- regscale/airflow/click_mixins.py +82 -0
- regscale/airflow/config.py +25 -0
- regscale/airflow/factories/__init__.py +0 -0
- regscale/airflow/factories/connections.py +58 -0
- regscale/airflow/factories/workflows.py +78 -0
- regscale/airflow/hierarchy.py +88 -0
- regscale/airflow/operators/__init__.py +0 -0
- regscale/airflow/operators/click.py +36 -0
- regscale/airflow/sensors/__init__.py +0 -0
- regscale/airflow/sensors/sql.py +107 -0
- regscale/airflow/sessions/__init__.py +0 -0
- regscale/airflow/sessions/sql/__init__.py +3 -0
- regscale/airflow/sessions/sql/queries.py +64 -0
- regscale/airflow/sessions/sql/sql_server_queries.py +248 -0
- regscale/airflow/tasks/__init__.py +0 -0
- regscale/airflow/tasks/branches.py +22 -0
- regscale/airflow/tasks/cli.py +116 -0
- regscale/airflow/tasks/click.py +73 -0
- regscale/airflow/tasks/debugging.py +9 -0
- regscale/airflow/tasks/groups.py +116 -0
- regscale/airflow/tasks/init.py +60 -0
- regscale/airflow/tasks/states.py +47 -0
- regscale/airflow/tasks/workflows.py +36 -0
- regscale/ansible/__init__.py +9 -0
- regscale/core/__init__.py +0 -0
- regscale/core/app/__init__.py +3 -0
- regscale/core/app/api.py +571 -0
- regscale/core/app/application.py +665 -0
- regscale/core/app/internal/__init__.py +136 -0
- regscale/core/app/internal/admin_actions.py +230 -0
- regscale/core/app/internal/assessments_editor.py +873 -0
- regscale/core/app/internal/catalog.py +316 -0
- regscale/core/app/internal/comparison.py +459 -0
- regscale/core/app/internal/control_editor.py +571 -0
- regscale/core/app/internal/encrypt.py +79 -0
- regscale/core/app/internal/evidence.py +1240 -0
- regscale/core/app/internal/file_uploads.py +151 -0
- regscale/core/app/internal/healthcheck.py +66 -0
- regscale/core/app/internal/login.py +305 -0
- regscale/core/app/internal/migrations.py +240 -0
- regscale/core/app/internal/model_editor.py +1701 -0
- regscale/core/app/internal/poam_editor.py +632 -0
- regscale/core/app/internal/workflow.py +105 -0
- regscale/core/app/logz.py +74 -0
- regscale/core/app/utils/XMLIR.py +258 -0
- regscale/core/app/utils/__init__.py +0 -0
- regscale/core/app/utils/api_handler.py +358 -0
- regscale/core/app/utils/app_utils.py +1110 -0
- regscale/core/app/utils/catalog_utils/__init__.py +0 -0
- regscale/core/app/utils/catalog_utils/common.py +91 -0
- regscale/core/app/utils/catalog_utils/compare_catalog.py +193 -0
- regscale/core/app/utils/catalog_utils/diagnostic_catalog.py +97 -0
- regscale/core/app/utils/catalog_utils/download_catalog.py +103 -0
- regscale/core/app/utils/catalog_utils/update_catalog.py +718 -0
- regscale/core/app/utils/catalog_utils/update_catalog_v2.py +1378 -0
- regscale/core/app/utils/catalog_utils/update_catalog_v3.py +1272 -0
- regscale/core/app/utils/catalog_utils/update_plans.py +334 -0
- regscale/core/app/utils/file_utils.py +238 -0
- regscale/core/app/utils/parser_utils.py +81 -0
- regscale/core/app/utils/pickle_file_handler.py +57 -0
- regscale/core/app/utils/regscale_utils.py +319 -0
- regscale/core/app/utils/report_utils.py +119 -0
- regscale/core/app/utils/variables.py +226 -0
- regscale/core/decorators.py +31 -0
- regscale/core/lazy_group.py +65 -0
- regscale/core/login.py +63 -0
- regscale/core/server/__init__.py +0 -0
- regscale/core/server/flask_api.py +473 -0
- regscale/core/server/helpers.py +373 -0
- regscale/core/server/rest.py +64 -0
- regscale/core/server/static/css/bootstrap.css +6030 -0
- regscale/core/server/static/css/bootstrap.min.css +6 -0
- regscale/core/server/static/css/main.css +176 -0
- regscale/core/server/static/images/regscale-cli.svg +49 -0
- regscale/core/server/static/images/regscale.svg +38 -0
- regscale/core/server/templates/base.html +74 -0
- regscale/core/server/templates/index.html +43 -0
- regscale/core/server/templates/login.html +28 -0
- regscale/core/server/templates/make_base64.html +22 -0
- regscale/core/server/templates/upload_STIG.html +109 -0
- regscale/core/server/templates/upload_STIG_result.html +26 -0
- regscale/core/server/templates/upload_ssp.html +144 -0
- regscale/core/server/templates/upload_ssp_result.html +128 -0
- regscale/core/static/__init__.py +0 -0
- regscale/core/static/regex.py +14 -0
- regscale/core/utils/__init__.py +117 -0
- regscale/core/utils/click_utils.py +13 -0
- regscale/core/utils/date.py +238 -0
- regscale/core/utils/graphql.py +254 -0
- regscale/core/utils/urls.py +23 -0
- regscale/dev/__init__.py +6 -0
- regscale/dev/analysis.py +454 -0
- regscale/dev/cli.py +235 -0
- regscale/dev/code_gen.py +492 -0
- regscale/dev/dirs.py +69 -0
- regscale/dev/docs.py +384 -0
- regscale/dev/monitoring.py +26 -0
- regscale/dev/profiling.py +216 -0
- regscale/exceptions/__init__.py +4 -0
- regscale/exceptions/license_exception.py +7 -0
- regscale/exceptions/validation_exception.py +9 -0
- regscale/integrations/__init__.py +1 -0
- regscale/integrations/commercial/__init__.py +486 -0
- regscale/integrations/commercial/ad.py +433 -0
- regscale/integrations/commercial/amazon/__init__.py +0 -0
- regscale/integrations/commercial/amazon/common.py +106 -0
- regscale/integrations/commercial/aqua/__init__.py +0 -0
- regscale/integrations/commercial/aqua/aqua.py +91 -0
- regscale/integrations/commercial/aws/__init__.py +6 -0
- regscale/integrations/commercial/aws/cli.py +322 -0
- regscale/integrations/commercial/aws/inventory/__init__.py +110 -0
- regscale/integrations/commercial/aws/inventory/base.py +64 -0
- regscale/integrations/commercial/aws/inventory/resources/__init__.py +19 -0
- regscale/integrations/commercial/aws/inventory/resources/compute.py +234 -0
- regscale/integrations/commercial/aws/inventory/resources/containers.py +113 -0
- regscale/integrations/commercial/aws/inventory/resources/database.py +101 -0
- regscale/integrations/commercial/aws/inventory/resources/integration.py +237 -0
- regscale/integrations/commercial/aws/inventory/resources/networking.py +253 -0
- regscale/integrations/commercial/aws/inventory/resources/security.py +240 -0
- regscale/integrations/commercial/aws/inventory/resources/storage.py +91 -0
- regscale/integrations/commercial/aws/scanner.py +823 -0
- regscale/integrations/commercial/azure/__init__.py +0 -0
- regscale/integrations/commercial/azure/common.py +32 -0
- regscale/integrations/commercial/azure/intune.py +488 -0
- regscale/integrations/commercial/azure/scanner.py +49 -0
- regscale/integrations/commercial/burp.py +78 -0
- regscale/integrations/commercial/cpe.py +144 -0
- regscale/integrations/commercial/crowdstrike.py +1117 -0
- regscale/integrations/commercial/defender.py +1511 -0
- regscale/integrations/commercial/dependabot.py +210 -0
- regscale/integrations/commercial/durosuite/__init__.py +0 -0
- regscale/integrations/commercial/durosuite/api.py +1546 -0
- regscale/integrations/commercial/durosuite/process_devices.py +101 -0
- regscale/integrations/commercial/durosuite/scanner.py +637 -0
- regscale/integrations/commercial/durosuite/variables.py +21 -0
- regscale/integrations/commercial/ecr.py +90 -0
- regscale/integrations/commercial/gcp/__init__.py +237 -0
- regscale/integrations/commercial/gcp/auth.py +96 -0
- regscale/integrations/commercial/gcp/control_tests.py +238 -0
- regscale/integrations/commercial/gcp/variables.py +18 -0
- regscale/integrations/commercial/gitlab.py +332 -0
- regscale/integrations/commercial/grype.py +165 -0
- regscale/integrations/commercial/ibm.py +90 -0
- regscale/integrations/commercial/import_all/__init__.py +0 -0
- regscale/integrations/commercial/import_all/import_all_cmd.py +467 -0
- regscale/integrations/commercial/import_all/scan_file_fingerprints.json +27 -0
- regscale/integrations/commercial/jira.py +1046 -0
- regscale/integrations/commercial/mappings/__init__.py +0 -0
- regscale/integrations/commercial/mappings/csf_controls.json +713 -0
- regscale/integrations/commercial/mappings/nist_800_53_r5_controls.json +1516 -0
- regscale/integrations/commercial/nessus/__init__.py +0 -0
- regscale/integrations/commercial/nessus/nessus_utils.py +429 -0
- regscale/integrations/commercial/nessus/scanner.py +416 -0
- regscale/integrations/commercial/nexpose.py +90 -0
- regscale/integrations/commercial/okta.py +798 -0
- regscale/integrations/commercial/opentext/__init__.py +0 -0
- regscale/integrations/commercial/opentext/click.py +99 -0
- regscale/integrations/commercial/opentext/scanner.py +143 -0
- regscale/integrations/commercial/prisma.py +91 -0
- regscale/integrations/commercial/qualys.py +1462 -0
- regscale/integrations/commercial/salesforce.py +980 -0
- regscale/integrations/commercial/sap/__init__.py +0 -0
- regscale/integrations/commercial/sap/click.py +31 -0
- regscale/integrations/commercial/sap/sysdig/__init__.py +0 -0
- regscale/integrations/commercial/sap/sysdig/click.py +57 -0
- regscale/integrations/commercial/sap/sysdig/sysdig_scanner.py +190 -0
- regscale/integrations/commercial/sap/tenable/__init__.py +0 -0
- regscale/integrations/commercial/sap/tenable/click.py +49 -0
- regscale/integrations/commercial/sap/tenable/scanner.py +196 -0
- regscale/integrations/commercial/servicenow.py +1756 -0
- regscale/integrations/commercial/sicura/__init__.py +0 -0
- regscale/integrations/commercial/sicura/api.py +855 -0
- regscale/integrations/commercial/sicura/commands.py +73 -0
- regscale/integrations/commercial/sicura/scanner.py +481 -0
- regscale/integrations/commercial/sicura/variables.py +16 -0
- regscale/integrations/commercial/snyk.py +90 -0
- regscale/integrations/commercial/sonarcloud.py +260 -0
- regscale/integrations/commercial/sqlserver.py +369 -0
- regscale/integrations/commercial/stig_mapper_integration/__init__.py +0 -0
- regscale/integrations/commercial/stig_mapper_integration/click_commands.py +38 -0
- regscale/integrations/commercial/stig_mapper_integration/mapping_engine.py +353 -0
- regscale/integrations/commercial/stigv2/__init__.py +0 -0
- regscale/integrations/commercial/stigv2/ckl_parser.py +349 -0
- regscale/integrations/commercial/stigv2/click_commands.py +95 -0
- regscale/integrations/commercial/stigv2/stig_integration.py +202 -0
- regscale/integrations/commercial/synqly/__init__.py +0 -0
- regscale/integrations/commercial/synqly/assets.py +46 -0
- regscale/integrations/commercial/synqly/ticketing.py +132 -0
- regscale/integrations/commercial/synqly/vulnerabilities.py +223 -0
- regscale/integrations/commercial/synqly_jira.py +840 -0
- regscale/integrations/commercial/tenablev2/__init__.py +0 -0
- regscale/integrations/commercial/tenablev2/authenticate.py +31 -0
- regscale/integrations/commercial/tenablev2/click.py +1584 -0
- regscale/integrations/commercial/tenablev2/scanner.py +504 -0
- regscale/integrations/commercial/tenablev2/stig_parsers.py +140 -0
- regscale/integrations/commercial/tenablev2/utils.py +78 -0
- regscale/integrations/commercial/tenablev2/variables.py +17 -0
- regscale/integrations/commercial/trivy.py +162 -0
- regscale/integrations/commercial/veracode.py +96 -0
- regscale/integrations/commercial/wizv2/WizDataMixin.py +97 -0
- regscale/integrations/commercial/wizv2/__init__.py +0 -0
- regscale/integrations/commercial/wizv2/click.py +429 -0
- regscale/integrations/commercial/wizv2/constants.py +1001 -0
- regscale/integrations/commercial/wizv2/issue.py +361 -0
- regscale/integrations/commercial/wizv2/models.py +112 -0
- regscale/integrations/commercial/wizv2/parsers.py +339 -0
- regscale/integrations/commercial/wizv2/sbom.py +115 -0
- regscale/integrations/commercial/wizv2/scanner.py +416 -0
- regscale/integrations/commercial/wizv2/utils.py +796 -0
- regscale/integrations/commercial/wizv2/variables.py +39 -0
- regscale/integrations/commercial/wizv2/wiz_auth.py +159 -0
- regscale/integrations/commercial/xray.py +91 -0
- regscale/integrations/integration/__init__.py +2 -0
- regscale/integrations/integration/integration.py +26 -0
- regscale/integrations/integration/inventory.py +17 -0
- regscale/integrations/integration/issue.py +100 -0
- regscale/integrations/integration_override.py +149 -0
- regscale/integrations/public/__init__.py +103 -0
- regscale/integrations/public/cisa.py +641 -0
- regscale/integrations/public/criticality_updater.py +70 -0
- regscale/integrations/public/emass.py +411 -0
- regscale/integrations/public/emass_slcm_import.py +697 -0
- regscale/integrations/public/fedramp/__init__.py +0 -0
- regscale/integrations/public/fedramp/appendix_parser.py +548 -0
- regscale/integrations/public/fedramp/click.py +479 -0
- regscale/integrations/public/fedramp/components.py +714 -0
- regscale/integrations/public/fedramp/docx_parser.py +259 -0
- regscale/integrations/public/fedramp/fedramp_cis_crm.py +1124 -0
- regscale/integrations/public/fedramp/fedramp_common.py +3181 -0
- regscale/integrations/public/fedramp/fedramp_docx.py +388 -0
- regscale/integrations/public/fedramp/fedramp_five.py +2343 -0
- regscale/integrations/public/fedramp/fedramp_traversal.py +138 -0
- regscale/integrations/public/fedramp/import_fedramp_r4_ssp.py +279 -0
- regscale/integrations/public/fedramp/import_workbook.py +495 -0
- regscale/integrations/public/fedramp/inventory_items.py +244 -0
- regscale/integrations/public/fedramp/mappings/__init__.py +0 -0
- regscale/integrations/public/fedramp/mappings/fedramp_r4_parts.json +7388 -0
- regscale/integrations/public/fedramp/mappings/fedramp_r5_params.json +8636 -0
- regscale/integrations/public/fedramp/mappings/fedramp_r5_parts.json +9605 -0
- regscale/integrations/public/fedramp/mappings/system_roles.py +34 -0
- regscale/integrations/public/fedramp/mappings/user.py +175 -0
- regscale/integrations/public/fedramp/mappings/values.py +141 -0
- regscale/integrations/public/fedramp/markdown_parser.py +150 -0
- regscale/integrations/public/fedramp/metadata.py +689 -0
- regscale/integrations/public/fedramp/models/__init__.py +59 -0
- regscale/integrations/public/fedramp/models/leveraged_auth_new.py +168 -0
- regscale/integrations/public/fedramp/models/poam_importer.py +522 -0
- regscale/integrations/public/fedramp/parts_mapper.py +107 -0
- regscale/integrations/public/fedramp/poam/__init__.py +0 -0
- regscale/integrations/public/fedramp/poam/scanner.py +851 -0
- regscale/integrations/public/fedramp/properties.py +201 -0
- regscale/integrations/public/fedramp/reporting.py +84 -0
- regscale/integrations/public/fedramp/resources.py +496 -0
- regscale/integrations/public/fedramp/rosetta.py +110 -0
- regscale/integrations/public/fedramp/ssp_logger.py +87 -0
- regscale/integrations/public/fedramp/system_characteristics.py +922 -0
- regscale/integrations/public/fedramp/system_control_implementations.py +582 -0
- regscale/integrations/public/fedramp/system_implementation.py +190 -0
- regscale/integrations/public/fedramp/xml_utils.py +87 -0
- regscale/integrations/public/nist_catalog.py +275 -0
- regscale/integrations/public/oscal.py +1946 -0
- regscale/integrations/public/otx.py +169 -0
- regscale/integrations/scanner_integration.py +2692 -0
- regscale/integrations/variables.py +25 -0
- regscale/models/__init__.py +7 -0
- regscale/models/app_models/__init__.py +5 -0
- regscale/models/app_models/catalog_compare.py +213 -0
- regscale/models/app_models/click.py +252 -0
- regscale/models/app_models/datetime_encoder.py +21 -0
- regscale/models/app_models/import_validater.py +321 -0
- regscale/models/app_models/mapping.py +260 -0
- regscale/models/app_models/pipeline.py +37 -0
- regscale/models/click_models.py +413 -0
- regscale/models/config.py +154 -0
- regscale/models/email_style.css +67 -0
- regscale/models/hierarchy.py +8 -0
- regscale/models/inspect_models.py +79 -0
- regscale/models/integration_models/__init__.py +0 -0
- regscale/models/integration_models/amazon_models/__init__.py +0 -0
- regscale/models/integration_models/amazon_models/inspector.py +262 -0
- regscale/models/integration_models/amazon_models/inspector_scan.py +206 -0
- regscale/models/integration_models/aqua.py +247 -0
- regscale/models/integration_models/azure_alerts.py +255 -0
- regscale/models/integration_models/base64.py +23 -0
- regscale/models/integration_models/burp.py +433 -0
- regscale/models/integration_models/burp_models.py +128 -0
- regscale/models/integration_models/cisa_kev_data.json +19333 -0
- regscale/models/integration_models/defender_data.py +93 -0
- regscale/models/integration_models/defenderimport.py +143 -0
- regscale/models/integration_models/drf.py +443 -0
- regscale/models/integration_models/ecr_models/__init__.py +0 -0
- regscale/models/integration_models/ecr_models/data.py +69 -0
- regscale/models/integration_models/ecr_models/ecr.py +239 -0
- regscale/models/integration_models/flat_file_importer.py +1079 -0
- regscale/models/integration_models/grype_import.py +247 -0
- regscale/models/integration_models/ibm.py +126 -0
- regscale/models/integration_models/implementation_results.py +85 -0
- regscale/models/integration_models/nexpose.py +140 -0
- regscale/models/integration_models/prisma.py +202 -0
- regscale/models/integration_models/qualys.py +720 -0
- regscale/models/integration_models/qualys_scanner.py +160 -0
- regscale/models/integration_models/sbom/__init__.py +0 -0
- regscale/models/integration_models/sbom/cyclone_dx.py +139 -0
- regscale/models/integration_models/send_reminders.py +620 -0
- regscale/models/integration_models/snyk.py +155 -0
- regscale/models/integration_models/synqly_models/__init__.py +0 -0
- regscale/models/integration_models/synqly_models/capabilities.json +1 -0
- regscale/models/integration_models/synqly_models/connector_types.py +22 -0
- regscale/models/integration_models/synqly_models/connectors/__init__.py +7 -0
- regscale/models/integration_models/synqly_models/connectors/assets.py +97 -0
- regscale/models/integration_models/synqly_models/connectors/ticketing.py +583 -0
- regscale/models/integration_models/synqly_models/connectors/vulnerabilities.py +169 -0
- regscale/models/integration_models/synqly_models/ocsf_mapper.py +331 -0
- regscale/models/integration_models/synqly_models/param.py +72 -0
- regscale/models/integration_models/synqly_models/synqly_model.py +733 -0
- regscale/models/integration_models/synqly_models/tenants.py +39 -0
- regscale/models/integration_models/tenable_models/__init__.py +0 -0
- regscale/models/integration_models/tenable_models/integration.py +187 -0
- regscale/models/integration_models/tenable_models/models.py +513 -0
- regscale/models/integration_models/trivy_import.py +231 -0
- regscale/models/integration_models/veracode.py +217 -0
- regscale/models/integration_models/xray.py +135 -0
- regscale/models/locking.py +100 -0
- regscale/models/platform.py +110 -0
- regscale/models/regscale_models/__init__.py +67 -0
- regscale/models/regscale_models/assessment.py +570 -0
- regscale/models/regscale_models/assessment_plan.py +52 -0
- regscale/models/regscale_models/asset.py +567 -0
- regscale/models/regscale_models/asset_mapping.py +190 -0
- regscale/models/regscale_models/case.py +42 -0
- regscale/models/regscale_models/catalog.py +261 -0
- regscale/models/regscale_models/cci.py +46 -0
- regscale/models/regscale_models/change.py +167 -0
- regscale/models/regscale_models/checklist.py +372 -0
- regscale/models/regscale_models/comment.py +49 -0
- regscale/models/regscale_models/compliance_settings.py +112 -0
- regscale/models/regscale_models/component.py +412 -0
- regscale/models/regscale_models/component_mapping.py +65 -0
- regscale/models/regscale_models/control.py +38 -0
- regscale/models/regscale_models/control_implementation.py +1128 -0
- regscale/models/regscale_models/control_objective.py +261 -0
- regscale/models/regscale_models/control_parameter.py +100 -0
- regscale/models/regscale_models/control_test.py +34 -0
- regscale/models/regscale_models/control_test_plan.py +75 -0
- regscale/models/regscale_models/control_test_result.py +52 -0
- regscale/models/regscale_models/custom_field.py +245 -0
- regscale/models/regscale_models/data.py +109 -0
- regscale/models/regscale_models/data_center.py +40 -0
- regscale/models/regscale_models/deviation.py +203 -0
- regscale/models/regscale_models/email.py +97 -0
- regscale/models/regscale_models/evidence.py +47 -0
- regscale/models/regscale_models/evidence_mapping.py +40 -0
- regscale/models/regscale_models/facility.py +59 -0
- regscale/models/regscale_models/file.py +382 -0
- regscale/models/regscale_models/filetag.py +37 -0
- regscale/models/regscale_models/form_field_value.py +94 -0
- regscale/models/regscale_models/group.py +169 -0
- regscale/models/regscale_models/implementation_objective.py +335 -0
- regscale/models/regscale_models/implementation_option.py +275 -0
- regscale/models/regscale_models/implementation_role.py +33 -0
- regscale/models/regscale_models/incident.py +177 -0
- regscale/models/regscale_models/interconnection.py +43 -0
- regscale/models/regscale_models/issue.py +1176 -0
- regscale/models/regscale_models/leveraged_authorization.py +125 -0
- regscale/models/regscale_models/line_of_inquiry.py +52 -0
- regscale/models/regscale_models/link.py +205 -0
- regscale/models/regscale_models/meta_data.py +64 -0
- regscale/models/regscale_models/mixins/__init__.py +0 -0
- regscale/models/regscale_models/mixins/parent_cache.py +124 -0
- regscale/models/regscale_models/module.py +224 -0
- regscale/models/regscale_models/modules.py +191 -0
- regscale/models/regscale_models/objective.py +14 -0
- regscale/models/regscale_models/parameter.py +87 -0
- regscale/models/regscale_models/ports_protocol.py +81 -0
- regscale/models/regscale_models/privacy.py +89 -0
- regscale/models/regscale_models/profile.py +50 -0
- regscale/models/regscale_models/profile_link.py +68 -0
- regscale/models/regscale_models/profile_mapping.py +124 -0
- regscale/models/regscale_models/project.py +63 -0
- regscale/models/regscale_models/property.py +278 -0
- regscale/models/regscale_models/question.py +85 -0
- regscale/models/regscale_models/questionnaire.py +87 -0
- regscale/models/regscale_models/questionnaire_instance.py +177 -0
- regscale/models/regscale_models/rbac.py +132 -0
- regscale/models/regscale_models/reference.py +86 -0
- regscale/models/regscale_models/regscale_model.py +1643 -0
- regscale/models/regscale_models/requirement.py +29 -0
- regscale/models/regscale_models/risk.py +274 -0
- regscale/models/regscale_models/sbom.py +54 -0
- regscale/models/regscale_models/scan_history.py +436 -0
- regscale/models/regscale_models/search.py +53 -0
- regscale/models/regscale_models/security_control.py +132 -0
- regscale/models/regscale_models/security_plan.py +204 -0
- regscale/models/regscale_models/software_inventory.py +159 -0
- regscale/models/regscale_models/stake_holder.py +64 -0
- regscale/models/regscale_models/stig.py +647 -0
- regscale/models/regscale_models/supply_chain.py +152 -0
- regscale/models/regscale_models/system_role.py +188 -0
- regscale/models/regscale_models/system_role_external_assignment.py +40 -0
- regscale/models/regscale_models/tag.py +37 -0
- regscale/models/regscale_models/tag_mapping.py +19 -0
- regscale/models/regscale_models/task.py +133 -0
- regscale/models/regscale_models/threat.py +196 -0
- regscale/models/regscale_models/user.py +175 -0
- regscale/models/regscale_models/user_group.py +55 -0
- regscale/models/regscale_models/vulnerability.py +242 -0
- regscale/models/regscale_models/vulnerability_mapping.py +162 -0
- regscale/models/regscale_models/workflow.py +55 -0
- regscale/models/regscale_models/workflow_action.py +34 -0
- regscale/models/regscale_models/workflow_instance.py +269 -0
- regscale/models/regscale_models/workflow_instance_step.py +114 -0
- regscale/models/regscale_models/workflow_template.py +58 -0
- regscale/models/regscale_models/workflow_template_step.py +45 -0
- regscale/regscale.py +815 -0
- regscale/utils/__init__.py +7 -0
- regscale/utils/b64conversion.py +14 -0
- regscale/utils/click_utils.py +118 -0
- regscale/utils/decorators.py +48 -0
- regscale/utils/dict_utils.py +59 -0
- regscale/utils/files.py +79 -0
- regscale/utils/fxns.py +30 -0
- regscale/utils/graphql_client.py +113 -0
- regscale/utils/lists.py +16 -0
- regscale/utils/numbers.py +12 -0
- regscale/utils/shell.py +148 -0
- regscale/utils/string.py +121 -0
- regscale/utils/synqly_utils.py +165 -0
- regscale/utils/threading/__init__.py +8 -0
- regscale/utils/threading/threadhandler.py +131 -0
- regscale/utils/threading/threadsafe_counter.py +47 -0
- regscale/utils/threading/threadsafe_dict.py +242 -0
- regscale/utils/threading/threadsafe_list.py +83 -0
- regscale/utils/version.py +104 -0
- regscale/validation/__init__.py +0 -0
- regscale/validation/address.py +37 -0
- regscale/validation/record.py +48 -0
- regscale/visualization/__init__.py +5 -0
- regscale/visualization/click.py +34 -0
- regscale_cli-6.16.0.0.dist-info/LICENSE +21 -0
- regscale_cli-6.16.0.0.dist-info/METADATA +659 -0
- regscale_cli-6.16.0.0.dist-info/RECORD +481 -0
- regscale_cli-6.16.0.0.dist-info/WHEEL +5 -0
- regscale_cli-6.16.0.0.dist-info/entry_points.txt +6 -0
- regscale_cli-6.16.0.0.dist-info/top_level.txt +2 -0
- tests/fixtures/__init__.py +2 -0
- tests/fixtures/api.py +87 -0
- tests/fixtures/models.py +91 -0
- tests/fixtures/test_fixture.py +144 -0
- tests/mocks/__init__.py +0 -0
- tests/mocks/objects.py +3 -0
- tests/mocks/response.py +32 -0
- tests/mocks/xml.py +13 -0
- tests/regscale/__init__.py +0 -0
- tests/regscale/core/__init__.py +0 -0
- tests/regscale/core/test_api.py +232 -0
- tests/regscale/core/test_app.py +406 -0
- tests/regscale/core/test_login.py +37 -0
- tests/regscale/core/test_logz.py +66 -0
- tests/regscale/core/test_sbom_generator.py +87 -0
- tests/regscale/core/test_validation_utils.py +163 -0
- tests/regscale/core/test_version.py +78 -0
- tests/regscale/models/__init__.py +0 -0
- tests/regscale/models/test_asset.py +71 -0
- tests/regscale/models/test_config.py +26 -0
- tests/regscale/models/test_control_implementation.py +27 -0
- tests/regscale/models/test_import.py +97 -0
- tests/regscale/models/test_issue.py +36 -0
- tests/regscale/models/test_mapping.py +52 -0
- tests/regscale/models/test_platform.py +31 -0
- tests/regscale/models/test_regscale_model.py +346 -0
- tests/regscale/models/test_report.py +32 -0
- tests/regscale/models/test_tenable_integrations.py +118 -0
- tests/regscale/models/test_user_model.py +121 -0
- tests/regscale/test_about.py +19 -0
- tests/regscale/test_authorization.py +65 -0
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""Integrate Azure Active Directory in RegScale"""
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
# standard python imports
|
|
7
|
+
from json import JSONDecodeError
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
import click
|
|
11
|
+
|
|
12
|
+
from regscale import __version__
|
|
13
|
+
from regscale.core.app.logz import create_logger
|
|
14
|
+
from regscale.core.app.utils.app_utils import (
|
|
15
|
+
check_file_path,
|
|
16
|
+
check_license,
|
|
17
|
+
error_and_exit,
|
|
18
|
+
save_data_to,
|
|
19
|
+
)
|
|
20
|
+
from regscale.models.regscale_models.user import User
|
|
21
|
+
|
|
22
|
+
logger = create_logger()
|
|
23
|
+
new_users = []
|
|
24
|
+
remove_users = []
|
|
25
|
+
|
|
26
|
+
######################################################################################################
|
|
27
|
+
#
|
|
28
|
+
# Microsoft MSAL Documentation:
|
|
29
|
+
# https://learn.microsoft.com/en-us/python/api/overview/azure/active-directory?view=azure-python
|
|
30
|
+
# Microsoft AD Github Repo:
|
|
31
|
+
# https://github.com/AzureAD/microsoft-authentication-library-for-python
|
|
32
|
+
#
|
|
33
|
+
######################################################################################################
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# Create group to handle Active Directory processing
|
|
37
|
+
@click.group()
|
|
38
|
+
def ad():
|
|
39
|
+
"""Performs directory and user synchronization functions with Azure Active Directory."""
|
|
40
|
+
check_license()
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@ad.command()
|
|
44
|
+
def authenticate():
|
|
45
|
+
"""Obtains an access token using the credentials provided."""
|
|
46
|
+
# authenticate the user
|
|
47
|
+
get_access_token()
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
# Get Active Directory groups
|
|
51
|
+
@ad.command(name="list_groups")
|
|
52
|
+
def list_groups():
|
|
53
|
+
"""Prints the lists of available RegScale groups the CLI can read."""
|
|
54
|
+
# authenticate the user
|
|
55
|
+
get_access_token()
|
|
56
|
+
|
|
57
|
+
# list all groups
|
|
58
|
+
list_ad_groups()
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
# Sync RegScale admins from Active Directory
|
|
62
|
+
@ad.command(name="sync_admins")
|
|
63
|
+
def sync_admins():
|
|
64
|
+
"""Syncs members of the RegScale-admins group and assigns roles."""
|
|
65
|
+
# authenticate the user
|
|
66
|
+
get_access_token()
|
|
67
|
+
|
|
68
|
+
# set the Microsoft Graph Endpoint
|
|
69
|
+
get_group("RegScale-admin")
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
# Sync RegScale general users from Active Directory
|
|
73
|
+
@ad.command(name="sync_general")
|
|
74
|
+
def sync_general():
|
|
75
|
+
"""Syncs members of the RegScale-general group and assigns roles."""
|
|
76
|
+
# authenticate the user
|
|
77
|
+
get_access_token()
|
|
78
|
+
|
|
79
|
+
# set the Microsoft Graph Endpoint
|
|
80
|
+
get_group("RegScale-general")
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
# Sync RegScale read only from Active Directory
|
|
84
|
+
@ad.command(name="sync_readonly")
|
|
85
|
+
def sync_readonly():
|
|
86
|
+
"""Syncs members of the RegScale-readonly group and assigns roles."""
|
|
87
|
+
# authenticate the user
|
|
88
|
+
get_access_token()
|
|
89
|
+
|
|
90
|
+
# set the Microsoft Graph Endpoint
|
|
91
|
+
get_group("RegScale-readonly")
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
# Supporting Functions
|
|
95
|
+
def get_access_token() -> dict:
|
|
96
|
+
"""
|
|
97
|
+
Function to authenticate in Active Directory and updates init.yaml with the returned JWT
|
|
98
|
+
|
|
99
|
+
:return: JWT from Azure Directory
|
|
100
|
+
:rtype: dict
|
|
101
|
+
"""
|
|
102
|
+
import msal
|
|
103
|
+
from regscale.core.app.application import Application
|
|
104
|
+
|
|
105
|
+
app = Application()
|
|
106
|
+
|
|
107
|
+
# get the config from the application
|
|
108
|
+
config = app.config
|
|
109
|
+
|
|
110
|
+
# generate the endpoint
|
|
111
|
+
auth_url = config["adAuthUrl"] + config["adTenantId"]
|
|
112
|
+
graph_url = config["adGraphUrl"]
|
|
113
|
+
version = __version__
|
|
114
|
+
|
|
115
|
+
# configure the Microsoft MSAL library to authenticate and gain an access token
|
|
116
|
+
ad_app = msal.ConfidentialClientApplication(
|
|
117
|
+
client_id=config["adClientId"],
|
|
118
|
+
app_name="RegScale CLI",
|
|
119
|
+
app_version=version,
|
|
120
|
+
authority=auth_url,
|
|
121
|
+
client_credential=config["adClientSecret"],
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
# use MSAL to get the token (no caching for security)
|
|
125
|
+
try:
|
|
126
|
+
token = ad_app.acquire_token_for_client(scopes=graph_url)
|
|
127
|
+
config["adAccessToken"] = "Bearer " + token["access_token"]
|
|
128
|
+
|
|
129
|
+
# write the changes back to file
|
|
130
|
+
app.save_config(config)
|
|
131
|
+
logger.info("Azure AD Login Successful!")
|
|
132
|
+
logger.info("Init.yaml file updated successfully with the access token.")
|
|
133
|
+
except JSONDecodeError as ex:
|
|
134
|
+
error_and_exit(f"Unable to authenticate to Azure AD.\nError: {ex}")
|
|
135
|
+
except KeyError as ex:
|
|
136
|
+
error_and_exit(f"Unable to obtain access token! Please verify credentials.\nError: {ex}\n{token}")
|
|
137
|
+
# return the result
|
|
138
|
+
return token
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def list_ad_groups() -> None:
|
|
142
|
+
"""
|
|
143
|
+
Function that lists all RegScale groups in Active Directory
|
|
144
|
+
|
|
145
|
+
:rtype: None
|
|
146
|
+
"""
|
|
147
|
+
from regscale.core.app.api import Api
|
|
148
|
+
from regscale.core.app.application import Application
|
|
149
|
+
|
|
150
|
+
app = Application()
|
|
151
|
+
api = Api()
|
|
152
|
+
|
|
153
|
+
# load the config from YAML
|
|
154
|
+
config = app.config
|
|
155
|
+
|
|
156
|
+
# trim the URL
|
|
157
|
+
graph_url = config["adGraphUrl"].replace(".default", "")
|
|
158
|
+
|
|
159
|
+
# set the endpoint
|
|
160
|
+
groups_url = f"{graph_url}v1.0/groups?$filter=startswith(displayName,'RegScale')"
|
|
161
|
+
|
|
162
|
+
# configure the headers for the API call
|
|
163
|
+
ad_headers = {"Authorization": config["adAccessToken"]}
|
|
164
|
+
|
|
165
|
+
# get the AD group info
|
|
166
|
+
logger.info("Fetching relevant AD Groups from Azure for RegScale.")
|
|
167
|
+
try:
|
|
168
|
+
groups_response = api.get(url=groups_url, headers=ad_headers)
|
|
169
|
+
groups_data = groups_response.json()
|
|
170
|
+
except JSONDecodeError as ex:
|
|
171
|
+
error_and_exit(f"Unable to retrieve group information from Azure Active Directory.\n{ex}")
|
|
172
|
+
# loop through the groups and log the results
|
|
173
|
+
if "value" in groups_data:
|
|
174
|
+
for g in groups_data["value"]:
|
|
175
|
+
logger.info("GROUP: " + g["displayName"])
|
|
176
|
+
logger.info("%s total group(s) retrieved.", len(groups_data["value"]))
|
|
177
|
+
elif "error" in groups_data:
|
|
178
|
+
try:
|
|
179
|
+
error_and_exit(f'{groups_data["error"]["code"]}: {groups_data["error"]["message"]}')
|
|
180
|
+
except Exception as ex:
|
|
181
|
+
error_and_exit(f"Unknown Error! {ex}\nData: {groups_data}")
|
|
182
|
+
|
|
183
|
+
# verify artifacts directory exists
|
|
184
|
+
check_file_path("artifacts")
|
|
185
|
+
|
|
186
|
+
# save group data to a json file
|
|
187
|
+
save_data_to(
|
|
188
|
+
file=Path("./artifacts/RegScale-AD-groups.json"),
|
|
189
|
+
data=groups_data,
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
# retrieves the RegScale groups from Azure AD
|
|
194
|
+
# flake8: noqa: C901
|
|
195
|
+
def get_group(str_group: str) -> None:
|
|
196
|
+
"""
|
|
197
|
+
Syncs members of the RegScale-admins group and assigns appropriate roles
|
|
198
|
+
|
|
199
|
+
:param str str_group: RegScale user group
|
|
200
|
+
:rtype: None
|
|
201
|
+
"""
|
|
202
|
+
from regscale.core.app.api import Api
|
|
203
|
+
from regscale.core.app.application import Application
|
|
204
|
+
|
|
205
|
+
# initialize app and api
|
|
206
|
+
app = Application()
|
|
207
|
+
api = Api()
|
|
208
|
+
|
|
209
|
+
# see if readonly
|
|
210
|
+
b_read_only = True if str_group == "RegScale-readonly" else False
|
|
211
|
+
|
|
212
|
+
# load the config from app
|
|
213
|
+
config = app.config
|
|
214
|
+
|
|
215
|
+
# trim the Graph URL
|
|
216
|
+
str_graph_url = config["adGraphUrl"].replace(".default", "")
|
|
217
|
+
|
|
218
|
+
# set the Microsoft Graph Endpoint
|
|
219
|
+
if str_group == "RegScale-admin":
|
|
220
|
+
groups_url = f"{str_graph_url}v1.0/groups?$filter=startswith(displayName,'RegScale-admin')"
|
|
221
|
+
elif str_group == "RegScale-general":
|
|
222
|
+
groups_url = f"{str_graph_url}v1.0/groups?$filter=startswith(displayName,'RegScale-general')"
|
|
223
|
+
elif str_group == "RegScale-readonly":
|
|
224
|
+
groups_url = f"{str_graph_url}v1.0/groups?$filter=startswith(displayName,'RegScale-readonly')"
|
|
225
|
+
else:
|
|
226
|
+
error_and_exit(f"Unknown RegScale group ({str_group}) requested for sync")
|
|
227
|
+
|
|
228
|
+
# set up the headers for the api call
|
|
229
|
+
ad_headers = {"Authorization": config["adAccessToken"]}
|
|
230
|
+
|
|
231
|
+
# get the AD group info
|
|
232
|
+
logger.info("Fetching relevant AD Groups from Azure for RegScale.")
|
|
233
|
+
try:
|
|
234
|
+
groups_response = api.get(groups_url, headers=ad_headers)
|
|
235
|
+
groups_data = groups_response.json()
|
|
236
|
+
except JSONDecodeError as ex:
|
|
237
|
+
error_and_exit(f"Unable to retrieve group information from Azure Active Directory.\n{ex}")
|
|
238
|
+
# verify artifacts directory exists
|
|
239
|
+
check_file_path("artifacts")
|
|
240
|
+
|
|
241
|
+
# save group data to json file
|
|
242
|
+
save_data_to(
|
|
243
|
+
file=Path(f"./artifacts/adGroupList-{str_group}.json"),
|
|
244
|
+
data=groups_data,
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
# loop through each group to find admins
|
|
248
|
+
if len(groups_data) == 0:
|
|
249
|
+
error_and_exit(f"{str_group} group has not been setup yet in Azure AD.")
|
|
250
|
+
else:
|
|
251
|
+
# get group info
|
|
252
|
+
if "value" in groups_data:
|
|
253
|
+
found_group = groups_data["value"][0]
|
|
254
|
+
group_id = found_group["id"]
|
|
255
|
+
else:
|
|
256
|
+
# error handling (log error)
|
|
257
|
+
if "error" in groups_data:
|
|
258
|
+
try:
|
|
259
|
+
error_and_exit(f'{groups_data["error"]["code"]}: {groups_data["error"]["message"]}')
|
|
260
|
+
except Exception as ex:
|
|
261
|
+
error_and_exit(f"Unknown Error! {ex}\nData: {groups_data}")
|
|
262
|
+
|
|
263
|
+
# get AD group members
|
|
264
|
+
members_url = f"{str_graph_url}v1.0/groups/{group_id}/members"
|
|
265
|
+
|
|
266
|
+
# get the member list for the AD group
|
|
267
|
+
logger.info("Fetching the list of members for this AD group - %s", str(group_id))
|
|
268
|
+
try:
|
|
269
|
+
member_response = api.get(members_url, headers=ad_headers)
|
|
270
|
+
member_data = member_response.json()
|
|
271
|
+
except JSONDecodeError:
|
|
272
|
+
error_and_exit(f"Unable to retrieve member list for Azure Active Directory group - {group_id}.")
|
|
273
|
+
# verify artifacts directory exists
|
|
274
|
+
check_file_path("artifacts")
|
|
275
|
+
|
|
276
|
+
# save member data to json file
|
|
277
|
+
save_data_to(
|
|
278
|
+
file=Path(f"./artifacts/adMemberList-{group_id}.json"),
|
|
279
|
+
data=member_data,
|
|
280
|
+
)
|
|
281
|
+
logger.info(member_data)
|
|
282
|
+
# retrieve the list of RegScale users
|
|
283
|
+
url_users = f'{config["domain"]}/api/accounts/getList'
|
|
284
|
+
try:
|
|
285
|
+
user_response = api.get(url_users)
|
|
286
|
+
user_data = user_response.json()
|
|
287
|
+
except JSONDecodeError:
|
|
288
|
+
error_and_exit("Unable to retrieve user list from RegScale.")
|
|
289
|
+
|
|
290
|
+
# retrieve the list of RegScale roles
|
|
291
|
+
url_roles = f'{config["domain"]}/api/accounts/getRoles'
|
|
292
|
+
try:
|
|
293
|
+
role_response = api.get(url_roles)
|
|
294
|
+
role_data = role_response.json()
|
|
295
|
+
except JSONDecodeError:
|
|
296
|
+
error_and_exit("Unable to retrieve roles from RegScale.")
|
|
297
|
+
|
|
298
|
+
# loop through the members of the AD group (create new user if not in RegScale)
|
|
299
|
+
for m in member_data["value"]:
|
|
300
|
+
# see if it exists
|
|
301
|
+
member_found = False
|
|
302
|
+
for u in user_data:
|
|
303
|
+
if "externalId" in u and m["id"] == u["externalId"]:
|
|
304
|
+
member_found = True
|
|
305
|
+
|
|
306
|
+
# handle new user flow
|
|
307
|
+
if not member_found:
|
|
308
|
+
# create a new user
|
|
309
|
+
new_user = User(
|
|
310
|
+
userName=m["userPrincipalName"],
|
|
311
|
+
email=m["mail"],
|
|
312
|
+
firstName=m["givenName"],
|
|
313
|
+
lastName=m["surname"],
|
|
314
|
+
workPhone=m["mobilePhone"],
|
|
315
|
+
activated=True,
|
|
316
|
+
jobTitle=m["jobTitle"],
|
|
317
|
+
tenantId=1,
|
|
318
|
+
ldapUser=True,
|
|
319
|
+
externalId=m["id"],
|
|
320
|
+
readOnly=b_read_only,
|
|
321
|
+
)
|
|
322
|
+
new_users.append(new_user.dict())
|
|
323
|
+
# loop through the users (disable if not in AD group)
|
|
324
|
+
for u in user_data:
|
|
325
|
+
if "externalId" in u:
|
|
326
|
+
disable_flag = True
|
|
327
|
+
for m in member_data["value"]:
|
|
328
|
+
if m["id"] == u["externalId"]:
|
|
329
|
+
disable_flag = False
|
|
330
|
+
if disable_flag:
|
|
331
|
+
remove_users.append(u)
|
|
332
|
+
# write out new user list to file
|
|
333
|
+
save_data_to(file=Path("./artifacts/newUsers.json"), data=new_users)
|
|
334
|
+
|
|
335
|
+
# write out disabled user list to file
|
|
336
|
+
save_data_to(file=Path("./artifacts/removeUsers.json"), data=remove_users)
|
|
337
|
+
|
|
338
|
+
# Logging
|
|
339
|
+
logger.info("%s new user(s) to process.", str(len(new_users)))
|
|
340
|
+
|
|
341
|
+
# loop through each user
|
|
342
|
+
regscale_new = []
|
|
343
|
+
for us in new_users:
|
|
344
|
+
# add new users in bulk
|
|
345
|
+
url_new_users = f'{config["domain"]}/api/accounts/azureAD'
|
|
346
|
+
try:
|
|
347
|
+
new_user = api.post(url_new_users, json=us)
|
|
348
|
+
user_new = {"id": new_user.text}
|
|
349
|
+
regscale_new.append(user_new)
|
|
350
|
+
logger.info("User created or updated: %s", us["userName"])
|
|
351
|
+
except Exception as ex:
|
|
352
|
+
error_and_exit(f"Unable to create new user {us['userName']}.\nError: {ex}")
|
|
353
|
+
|
|
354
|
+
# write out new user list to file
|
|
355
|
+
save_data_to(
|
|
356
|
+
file=Path("./artifacts/newRegScaleUsers.json"),
|
|
357
|
+
data=regscale_new,
|
|
358
|
+
)
|
|
359
|
+
|
|
360
|
+
# set the role
|
|
361
|
+
user_role = ""
|
|
362
|
+
if str_group == "RegScale-admin":
|
|
363
|
+
user_role = "Administrator"
|
|
364
|
+
elif str_group == "RegScale-general":
|
|
365
|
+
user_role = "GeneralUser"
|
|
366
|
+
elif str_group == "RegScale-readonly":
|
|
367
|
+
user_role = "ReadOnly"
|
|
368
|
+
|
|
369
|
+
# set the RegScale role based on the AD group
|
|
370
|
+
regscale_role = None
|
|
371
|
+
for role in role_data:
|
|
372
|
+
if role["name"] == user_role:
|
|
373
|
+
regscale_role = role
|
|
374
|
+
if role is None:
|
|
375
|
+
error_and_exit(f"Unable to locate RegScale role for group: {str_group}.")
|
|
376
|
+
|
|
377
|
+
# loop through the users and assign roles
|
|
378
|
+
int_roles = 0
|
|
379
|
+
for us in regscale_new:
|
|
380
|
+
# check the role
|
|
381
|
+
url_check_role = f'{config["domain"]}/api/accounts/checkRole/{us["id"]}/{regscale_role["id"]}'
|
|
382
|
+
try:
|
|
383
|
+
role_check = api.get(url=url_check_role)
|
|
384
|
+
str_check = role_check.text
|
|
385
|
+
except Exception as ex:
|
|
386
|
+
error_and_exit(f"Unable to check role: {us['id']}, {regscale_role['id']}.\nError: {ex}")
|
|
387
|
+
|
|
388
|
+
# add the role
|
|
389
|
+
if str_check == "false":
|
|
390
|
+
# add the role
|
|
391
|
+
url_assign_role = config["domain"] + "/api/accounts/assignRole/"
|
|
392
|
+
# role assignment object
|
|
393
|
+
assign = {"roleId": regscale_role["id"], "userId": us["id"]}
|
|
394
|
+
try:
|
|
395
|
+
api.post(url=url_assign_role, json=assign)
|
|
396
|
+
int_roles += 1
|
|
397
|
+
except Exception as ex:
|
|
398
|
+
error_and_exit(f"Unable to assign role: {us['id']}/{regscale_role['id']}.\nError: {ex}")
|
|
399
|
+
|
|
400
|
+
# output results
|
|
401
|
+
if int_roles > 0:
|
|
402
|
+
logger.info("Total Roles Assigned: %s.", str(int_roles))
|
|
403
|
+
|
|
404
|
+
# loop through and remove users
|
|
405
|
+
int_removals = 0
|
|
406
|
+
for us in remove_users:
|
|
407
|
+
# check the role
|
|
408
|
+
url_check_role = f'{config["domain"]}/api/accounts/checkRole/{us["id"]}/{regscale_role["id"]}'
|
|
409
|
+
try:
|
|
410
|
+
role_check = api.get(url=url_check_role)
|
|
411
|
+
str_check = role_check.text
|
|
412
|
+
except Exception as ex:
|
|
413
|
+
error_and_exit(f"Unable to check role: {us['id']}/{regscale_role['id']}.\nError: {ex}")
|
|
414
|
+
|
|
415
|
+
# add the role
|
|
416
|
+
if str_check == "true":
|
|
417
|
+
# remove the role
|
|
418
|
+
url_remove_role = f'{config["domain"]}/api/accounts/deleteRole/{us["id"]}/{regscale_role["id"]}'
|
|
419
|
+
try:
|
|
420
|
+
api.delete(url=url_remove_role)
|
|
421
|
+
int_removals += 1
|
|
422
|
+
except Exception as ex:
|
|
423
|
+
error_and_exit(f"Unable to remove role: {us['id']}/{regscale_role['id']}.\nError: {ex}")
|
|
424
|
+
|
|
425
|
+
# deactivate the user if they were in this role
|
|
426
|
+
url_deactivate = f'{config["domain"]}/api/accounts/changeUserStatus/{us["id"]}/false'
|
|
427
|
+
try:
|
|
428
|
+
api.get(url_deactivate)
|
|
429
|
+
logger.warning("%s account deactivated.", us["userName"])
|
|
430
|
+
except Exception as ex:
|
|
431
|
+
error_and_exit(f"Unable to check role: {us['id']}/{regscale_role['id']}.\nError: {ex}")
|
|
432
|
+
# output results
|
|
433
|
+
logger.info(str(int_removals) + " users had roles removed and accounts disabled.")
|
|
File without changes
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""RegScale AWS Integrations"""
|
|
4
|
+
import re
|
|
5
|
+
from datetime import datetime, timedelta
|
|
6
|
+
from typing import Any, Optional, Tuple
|
|
7
|
+
|
|
8
|
+
from botocore.client import BaseClient
|
|
9
|
+
from botocore.exceptions import ClientError
|
|
10
|
+
from dateutil import parser
|
|
11
|
+
|
|
12
|
+
from regscale.core.app.utils.app_utils import create_logger
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def check_finding_severity(comment: Optional[str]) -> str:
|
|
16
|
+
"""Check the severity of the finding
|
|
17
|
+
|
|
18
|
+
:param Optional[str] comment: Comment from AWS Security Hub finding
|
|
19
|
+
:return: Severity of the finding
|
|
20
|
+
:rtype: str
|
|
21
|
+
"""
|
|
22
|
+
result = ""
|
|
23
|
+
match = re.search(r"(?<=Finding Severity: ).*", comment)
|
|
24
|
+
if match:
|
|
25
|
+
severity = match.group()
|
|
26
|
+
result = severity # Output: "High"
|
|
27
|
+
return result
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def get_due_date(earliest_date_performed: datetime, days: int) -> datetime:
|
|
31
|
+
"""Returns the due date for an issue
|
|
32
|
+
|
|
33
|
+
:param datetime earliest_date_performed: Earliest date performed
|
|
34
|
+
:param int days: Days to add to the earliest date performed
|
|
35
|
+
:return: Due date
|
|
36
|
+
:rtype: datetime
|
|
37
|
+
"""
|
|
38
|
+
fmt = "%Y-%m-%dT%H:%M:%S.%fZ"
|
|
39
|
+
try:
|
|
40
|
+
due_date = datetime.strptime(earliest_date_performed, fmt) + timedelta(days=days)
|
|
41
|
+
except ValueError:
|
|
42
|
+
# Try to determine the date format from a string
|
|
43
|
+
due_date = parser.parse(earliest_date_performed) + timedelta(days)
|
|
44
|
+
return due_date
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def determine_status_and_results(finding: Any) -> Tuple[str, Optional[str]]:
|
|
48
|
+
"""
|
|
49
|
+
Determine Status and Results
|
|
50
|
+
|
|
51
|
+
:param Any finding: AWS Finding
|
|
52
|
+
:return: Status and Results
|
|
53
|
+
:rtype: Tuple[str, Optional[str]]
|
|
54
|
+
"""
|
|
55
|
+
status = "Pass"
|
|
56
|
+
results = None
|
|
57
|
+
if "Compliance" in finding.keys():
|
|
58
|
+
status = "Fail" if finding["Compliance"]["Status"] == "FAILED" else "Pass"
|
|
59
|
+
results = ", ".join(finding["Compliance"]["RelatedRequirements"])
|
|
60
|
+
if "FindingProviderFields" in finding.keys():
|
|
61
|
+
status = (
|
|
62
|
+
"Fail"
|
|
63
|
+
if finding["FindingProviderFields"]["Severity"]["Label"] in ["CRITICAL", "HIGH", "MEDIUM", "LOW"]
|
|
64
|
+
else "Pass"
|
|
65
|
+
)
|
|
66
|
+
if "PatchSummary" in finding.keys() and not results:
|
|
67
|
+
results = (
|
|
68
|
+
f"{finding['PatchSummary']['MissingCount']} Missing Patch(s) of "
|
|
69
|
+
"{finding['PatchSummary']['InstalledCount']}"
|
|
70
|
+
)
|
|
71
|
+
return status, results
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def get_comments(finding: dict) -> str:
|
|
75
|
+
"""
|
|
76
|
+
Get Comments
|
|
77
|
+
|
|
78
|
+
:param dict finding: AWS Finding
|
|
79
|
+
:return: Comments
|
|
80
|
+
:rtype: str
|
|
81
|
+
"""
|
|
82
|
+
try:
|
|
83
|
+
return (
|
|
84
|
+
finding["Remediation"]["Recommendation"]["Text"]
|
|
85
|
+
+ "<br></br>"
|
|
86
|
+
+ finding["Remediation"]["Recommendation"]["Url"]
|
|
87
|
+
+ "<br></br>"
|
|
88
|
+
+ f"""Finding Severity: {finding["FindingProviderFields"]["Severity"]["Label"]}"""
|
|
89
|
+
)
|
|
90
|
+
except KeyError:
|
|
91
|
+
return "No remediation recommendation available"
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def fetch_aws_findings(aws_client: BaseClient) -> list:
|
|
95
|
+
"""Fetch AWS Findings
|
|
96
|
+
|
|
97
|
+
:param BaseClient aws_client: AWS Security Hub Client
|
|
98
|
+
:return: AWS Findings
|
|
99
|
+
:rtype: list
|
|
100
|
+
"""
|
|
101
|
+
findings = []
|
|
102
|
+
try:
|
|
103
|
+
findings = aws_client.get_findings()["Findings"]
|
|
104
|
+
except ClientError as cex:
|
|
105
|
+
create_logger().error("Unexpected error: %s", cex)
|
|
106
|
+
return findings
|
|
File without changes
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""Aqua RegScale integration"""
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from os import PathLike
|
|
6
|
+
from typing import Optional
|
|
7
|
+
|
|
8
|
+
import click
|
|
9
|
+
|
|
10
|
+
from regscale.models.integration_models.aqua import Aqua
|
|
11
|
+
from regscale.models.integration_models.flat_file_importer import FlatFileImporter
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@click.group()
|
|
15
|
+
def aqua():
|
|
16
|
+
"""Performs actions on Aqua Scanner artifacts."""
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@aqua.command(name="import_aqua")
|
|
21
|
+
@FlatFileImporter.common_scanner_options(
|
|
22
|
+
message="File path to the folder containing Aqua .csv files to process to RegScale.",
|
|
23
|
+
prompt="File path for Aqua files",
|
|
24
|
+
import_name="aqua",
|
|
25
|
+
)
|
|
26
|
+
def import_aqua(
|
|
27
|
+
folder_path: PathLike[str],
|
|
28
|
+
regscale_ssp_id: int,
|
|
29
|
+
scan_date: datetime,
|
|
30
|
+
mappings_path: PathLike[str],
|
|
31
|
+
disable_mapping: bool,
|
|
32
|
+
s3_bucket: str,
|
|
33
|
+
s3_prefix: str,
|
|
34
|
+
aws_profile: str,
|
|
35
|
+
upload_file: bool,
|
|
36
|
+
):
|
|
37
|
+
"""
|
|
38
|
+
Import Aqua scan data to RegScale
|
|
39
|
+
"""
|
|
40
|
+
import_aqua_scan(
|
|
41
|
+
folder_path,
|
|
42
|
+
regscale_ssp_id,
|
|
43
|
+
scan_date,
|
|
44
|
+
mappings_path,
|
|
45
|
+
disable_mapping,
|
|
46
|
+
s3_bucket,
|
|
47
|
+
s3_prefix,
|
|
48
|
+
aws_profile,
|
|
49
|
+
upload_file,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def import_aqua_scan(
|
|
54
|
+
folder_path: PathLike[str],
|
|
55
|
+
regscale_ssp_id: int,
|
|
56
|
+
scan_date: datetime,
|
|
57
|
+
mappings_path: PathLike[str],
|
|
58
|
+
disable_mapping: bool,
|
|
59
|
+
s3_bucket: str,
|
|
60
|
+
s3_prefix: str,
|
|
61
|
+
aws_profile: str,
|
|
62
|
+
upload_file: Optional[bool] = True,
|
|
63
|
+
) -> None:
|
|
64
|
+
"""
|
|
65
|
+
Import Aqua scans, vulnerabilities and assets to RegScale from Aqua files
|
|
66
|
+
|
|
67
|
+
:param PathLike[str] folder_path: File path to the folder containing Aqua .csv files to process to RegScale
|
|
68
|
+
:param int regscale_ssp_id: The RegScale SSP ID
|
|
69
|
+
:param datetime scan_date: The date of the scan
|
|
70
|
+
:param PathLike[str] mappings_path: The path to the mappings file
|
|
71
|
+
:param bool disable_mapping: Whether to disable custom mappings
|
|
72
|
+
:param str s3_bucket: The S3 bucket to download the files from
|
|
73
|
+
:param str s3_prefix: The S3 prefix to download the files from
|
|
74
|
+
:param str aws_profile: The AWS profile to use for S3 access
|
|
75
|
+
:param Optional[bool] upload_file: Whether to upload the file to RegScale after processing, defaults to True
|
|
76
|
+
:rtype: None
|
|
77
|
+
"""
|
|
78
|
+
FlatFileImporter.import_files(
|
|
79
|
+
import_type=Aqua,
|
|
80
|
+
import_name="Aqua",
|
|
81
|
+
file_types=[".csv", ".xlsx"],
|
|
82
|
+
folder_path=folder_path,
|
|
83
|
+
regscale_ssp_id=regscale_ssp_id,
|
|
84
|
+
scan_date=scan_date,
|
|
85
|
+
mappings_path=mappings_path,
|
|
86
|
+
disable_mapping=disable_mapping,
|
|
87
|
+
s3_bucket=s3_bucket,
|
|
88
|
+
s3_prefix=s3_prefix,
|
|
89
|
+
aws_profile=aws_profile,
|
|
90
|
+
upload_file=upload_file,
|
|
91
|
+
)
|