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,718 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""Add functionality to upgrade application catalog information via API."""
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
# pylint: disable=line-too-long, global-statement, global-at-module-level, abstract-class-instantiated, too-many-lines
|
|
7
|
+
|
|
8
|
+
# Standard Imports
|
|
9
|
+
import contextlib
|
|
10
|
+
import operator
|
|
11
|
+
import sys
|
|
12
|
+
from typing import Optional, Tuple
|
|
13
|
+
|
|
14
|
+
import click # type: ignore
|
|
15
|
+
from requests import JSONDecodeError # type: ignore
|
|
16
|
+
|
|
17
|
+
from regscale.core.app.api import Api
|
|
18
|
+
from regscale.core.app.logz import create_logger
|
|
19
|
+
from regscale.core.app.utils.app_utils import create_progress_object, error_and_exit
|
|
20
|
+
from regscale.core.app.utils.catalog_utils.common import get_new_catalog
|
|
21
|
+
from regscale.models.app_models.catalog_compare import CatalogCompare
|
|
22
|
+
|
|
23
|
+
# create logger function to log to the console
|
|
24
|
+
logger = create_logger()
|
|
25
|
+
# create progress object
|
|
26
|
+
job_progress = create_progress_object()
|
|
27
|
+
|
|
28
|
+
DOWNLOAD_URL: str = ""
|
|
29
|
+
CAT_UUID: str = ""
|
|
30
|
+
SECURITY_CONTROL_ID_KEY: list = []
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def display_menu() -> None:
|
|
34
|
+
"""
|
|
35
|
+
Start the process of comparing two catalogs, one from the master catalog list
|
|
36
|
+
and one from the user's RegScale instance
|
|
37
|
+
|
|
38
|
+
:rtype: None
|
|
39
|
+
"""
|
|
40
|
+
# set system environment variables
|
|
41
|
+
api = Api()
|
|
42
|
+
api.timeout = 180
|
|
43
|
+
|
|
44
|
+
# start menu build process
|
|
45
|
+
menu_counter: list = []
|
|
46
|
+
# import master catalog list
|
|
47
|
+
data = CatalogCompare.get_master_catalogs(api=api)
|
|
48
|
+
# sort master catalogue list
|
|
49
|
+
catalogues = data["catalogues"]
|
|
50
|
+
catalogues.sort(key=operator.itemgetter("id"))
|
|
51
|
+
for i, catalog in enumerate(catalogues):
|
|
52
|
+
# print each catalog in the master catalog list
|
|
53
|
+
print(f'{catalog["id"]}: {catalog["value"]}')
|
|
54
|
+
menu_counter.append(i)
|
|
55
|
+
# set status to False to run loop
|
|
56
|
+
status: bool = False
|
|
57
|
+
while not status:
|
|
58
|
+
# select catalog to run diagnostic
|
|
59
|
+
value = click.prompt(
|
|
60
|
+
"Please enter the number of the catalog you would like to run diagnostics on",
|
|
61
|
+
type=int,
|
|
62
|
+
)
|
|
63
|
+
# check if value exist that is selected
|
|
64
|
+
if value < min(menu_counter) or value > max(menu_counter):
|
|
65
|
+
print("That is not a valid selection, please try again")
|
|
66
|
+
else:
|
|
67
|
+
status = True
|
|
68
|
+
# choose catalog to run diagnostics on
|
|
69
|
+
for catalog in catalogues:
|
|
70
|
+
if catalog["id"] == value:
|
|
71
|
+
global CAT_UUID
|
|
72
|
+
CAT_UUID = catalog["metadata"]["uuid"]
|
|
73
|
+
if catalog["download"] is True:
|
|
74
|
+
if catalog["paid"] is False:
|
|
75
|
+
global DOWNLOAD_URL
|
|
76
|
+
DOWNLOAD_URL = catalog["link"]
|
|
77
|
+
if catalog["paid"] is True:
|
|
78
|
+
logger.warning("This is a paid catalog, please contact RegScale customer support.")
|
|
79
|
+
sys.exit()
|
|
80
|
+
break
|
|
81
|
+
compare_and_update_catalog_elements(api=api)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def compare_and_update_catalog_elements(api: Api) -> None:
|
|
85
|
+
"""
|
|
86
|
+
Function to compare and update elements between catalogs
|
|
87
|
+
|
|
88
|
+
:param Api api: Api object
|
|
89
|
+
:rtype: None
|
|
90
|
+
"""
|
|
91
|
+
new_catalog_elements = parse_new_catalog()
|
|
92
|
+
old_catalog_elements = parse_old_catalog(api=api)
|
|
93
|
+
update_security_controls(
|
|
94
|
+
new_security_controls=new_catalog_elements[0],
|
|
95
|
+
old_security_controls=old_catalog_elements[0],
|
|
96
|
+
api=api,
|
|
97
|
+
)
|
|
98
|
+
update_ccis(
|
|
99
|
+
new_ccis=new_catalog_elements[1],
|
|
100
|
+
old_ccis=old_catalog_elements[1],
|
|
101
|
+
api=api,
|
|
102
|
+
)
|
|
103
|
+
update_objectives(
|
|
104
|
+
new_objectives=new_catalog_elements[2],
|
|
105
|
+
old_objectives=old_catalog_elements[2],
|
|
106
|
+
api=api,
|
|
107
|
+
)
|
|
108
|
+
update_parameters(
|
|
109
|
+
new_parameters=new_catalog_elements[3],
|
|
110
|
+
old_parameters=old_catalog_elements[3],
|
|
111
|
+
api=api,
|
|
112
|
+
)
|
|
113
|
+
update_tests(
|
|
114
|
+
new_tests=new_catalog_elements[4],
|
|
115
|
+
old_tests=old_catalog_elements[4],
|
|
116
|
+
api=api,
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def update_security_controls(new_security_controls: list[dict], old_security_controls: list[dict], api: Api) -> None:
|
|
121
|
+
"""
|
|
122
|
+
Function to compare and update security controls
|
|
123
|
+
|
|
124
|
+
:param list[dict] new_security_controls: security controls from new catalog
|
|
125
|
+
:param list[dict] old_security_controls: security controls from old catalog
|
|
126
|
+
:param Api api: api object
|
|
127
|
+
:rtype: None
|
|
128
|
+
"""
|
|
129
|
+
archived_list = []
|
|
130
|
+
updated_list = []
|
|
131
|
+
created_list = []
|
|
132
|
+
element_exists = False
|
|
133
|
+
for new_security_control in new_security_controls:
|
|
134
|
+
for old_security_control in old_security_controls:
|
|
135
|
+
if new_security_control.get("controlId") == old_security_control.get("controlId"):
|
|
136
|
+
key_dict = {
|
|
137
|
+
"old_sc_id": old_security_control["id"],
|
|
138
|
+
"new_sc_id": new_security_control["id"],
|
|
139
|
+
}
|
|
140
|
+
SECURITY_CONTROL_ID_KEY.append(key_dict)
|
|
141
|
+
element_exists = True
|
|
142
|
+
with contextlib.suppress(KeyError):
|
|
143
|
+
if new_security_control["archived"] is True:
|
|
144
|
+
old_security_control["archived"] = True
|
|
145
|
+
archived_list.append(old_security_control)
|
|
146
|
+
break
|
|
147
|
+
for key in old_security_control:
|
|
148
|
+
try:
|
|
149
|
+
if key not in [
|
|
150
|
+
"id",
|
|
151
|
+
"catalogueID",
|
|
152
|
+
"tenantsId",
|
|
153
|
+
"sortId",
|
|
154
|
+
"lastUpdatedById",
|
|
155
|
+
]:
|
|
156
|
+
old_security_control[key] = new_security_control[key]
|
|
157
|
+
else:
|
|
158
|
+
continue
|
|
159
|
+
except KeyError:
|
|
160
|
+
old_security_control["archived"] = False
|
|
161
|
+
update = api.put(
|
|
162
|
+
url=api.config["domain"] + f"/api/SecurityControls/{old_security_control['id']}",
|
|
163
|
+
json=old_security_control,
|
|
164
|
+
)
|
|
165
|
+
update.raise_for_status()
|
|
166
|
+
if update.ok:
|
|
167
|
+
logger.info(
|
|
168
|
+
"Updated Security Control for Control ID: %i",
|
|
169
|
+
old_security_control["id"],
|
|
170
|
+
)
|
|
171
|
+
updated_list.append(old_security_control)
|
|
172
|
+
if element_exists is False:
|
|
173
|
+
try:
|
|
174
|
+
new_security_control["catalogueID"] = old_security_controls[0]["controls"]["catalogueID"]
|
|
175
|
+
except KeyError:
|
|
176
|
+
new_security_control["catalogueID"] = old_security_controls[0]["catalogueID"]
|
|
177
|
+
create = api.post(
|
|
178
|
+
url=api.config["domain"] + "/api/SecurityControls",
|
|
179
|
+
json=new_security_control,
|
|
180
|
+
)
|
|
181
|
+
create.raise_for_status()
|
|
182
|
+
if create.ok:
|
|
183
|
+
logger.info(
|
|
184
|
+
"Created Security Control for Control ID: %i",
|
|
185
|
+
new_security_control["id"],
|
|
186
|
+
)
|
|
187
|
+
created_list.append(new_security_control)
|
|
188
|
+
data_report(
|
|
189
|
+
data_name="SecurityControls",
|
|
190
|
+
archived=archived_list,
|
|
191
|
+
updated=updated_list,
|
|
192
|
+
created=created_list,
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def update_ccis(new_ccis: list[dict], old_ccis: list[dict], api: Api) -> None:
|
|
197
|
+
"""
|
|
198
|
+
Function to compare and update ccis
|
|
199
|
+
|
|
200
|
+
:param list[dict] new_ccis: ccis from new catalog
|
|
201
|
+
:param list[dict] old_ccis: ccis from old catalog
|
|
202
|
+
:param Api api: api object
|
|
203
|
+
:rtype: None
|
|
204
|
+
"""
|
|
205
|
+
archived_list = []
|
|
206
|
+
updated_list = []
|
|
207
|
+
created_list = []
|
|
208
|
+
element_exists = False
|
|
209
|
+
for new_cci in new_ccis:
|
|
210
|
+
for old_cci in old_ccis:
|
|
211
|
+
for cci in old_cci:
|
|
212
|
+
if new_cci["name"] == cci["name"]:
|
|
213
|
+
element_exists = True
|
|
214
|
+
with contextlib.suppress(KeyError):
|
|
215
|
+
if new_cci["archived"] is True:
|
|
216
|
+
cci["archived"] = True
|
|
217
|
+
archived_list.append(cci)
|
|
218
|
+
break
|
|
219
|
+
for key in cci:
|
|
220
|
+
if key == "isPublic":
|
|
221
|
+
cci["isPublic"] = False
|
|
222
|
+
elif key not in ["id", "securityControlId"]:
|
|
223
|
+
cci[key] = new_cci[key]
|
|
224
|
+
else:
|
|
225
|
+
continue
|
|
226
|
+
key_set = next(
|
|
227
|
+
(item for item in SECURITY_CONTROL_ID_KEY if item["new_sc_id"] == new_cci["securityControlId"]),
|
|
228
|
+
None,
|
|
229
|
+
)
|
|
230
|
+
old_sc_id = key_set.get("old_sc_id")
|
|
231
|
+
cci["securityControlId"] = old_sc_id
|
|
232
|
+
update = api.put(
|
|
233
|
+
url=api.config["domain"] + f"/api/cci/{cci['id']}",
|
|
234
|
+
json=cci,
|
|
235
|
+
)
|
|
236
|
+
update.raise_for_status()
|
|
237
|
+
if update.ok:
|
|
238
|
+
logger.info(
|
|
239
|
+
"Updated CCI for CCI ID: %i",
|
|
240
|
+
cci["id"],
|
|
241
|
+
)
|
|
242
|
+
updated_list.append(cci)
|
|
243
|
+
if element_exists is False:
|
|
244
|
+
key_set = next(
|
|
245
|
+
(item for item in SECURITY_CONTROL_ID_KEY if item["new_sc_id"] == new_cci["securityControlId"]),
|
|
246
|
+
None,
|
|
247
|
+
)
|
|
248
|
+
old_sc_id = key_set.get("old_sc_id")
|
|
249
|
+
new_cci["securityControlId"] = old_sc_id
|
|
250
|
+
create = api.post(
|
|
251
|
+
url=api.config["domain"] + "/api/cci",
|
|
252
|
+
json=new_cci,
|
|
253
|
+
)
|
|
254
|
+
create.raise_for_status()
|
|
255
|
+
if create.ok:
|
|
256
|
+
logger.info(
|
|
257
|
+
"Created CCI for CCI ID: %i",
|
|
258
|
+
new_cci["id"],
|
|
259
|
+
)
|
|
260
|
+
created_list.append(new_cci)
|
|
261
|
+
data_report(
|
|
262
|
+
data_name="CCIs",
|
|
263
|
+
archived=archived_list,
|
|
264
|
+
updated=updated_list,
|
|
265
|
+
created=created_list,
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
def update_objectives(new_objectives: list[dict], old_objectives: list[dict], api: Api) -> None:
|
|
270
|
+
"""
|
|
271
|
+
Function to compare and update objectives
|
|
272
|
+
|
|
273
|
+
:param list[dict] new_objectives: objectives from new catalog
|
|
274
|
+
:param list[dict] old_objectives: objectives from old catalog
|
|
275
|
+
:param Api api: Api object
|
|
276
|
+
:rtype: None
|
|
277
|
+
"""
|
|
278
|
+
archived_list = []
|
|
279
|
+
updated_list = []
|
|
280
|
+
created_list = []
|
|
281
|
+
element_exists = False
|
|
282
|
+
for new_objective in new_objectives:
|
|
283
|
+
for old_objective in old_objectives:
|
|
284
|
+
if new_objective["name"] == old_objective["name"]:
|
|
285
|
+
element_exists = True
|
|
286
|
+
with contextlib.suppress(KeyError):
|
|
287
|
+
if new_objective["archived"] is True:
|
|
288
|
+
old_objective["archived"] = True
|
|
289
|
+
archived_list.append(old_objective)
|
|
290
|
+
break
|
|
291
|
+
for key in old_objective:
|
|
292
|
+
if key == "isPublic":
|
|
293
|
+
old_objective["isPublic"] = False
|
|
294
|
+
elif key not in ["id", "securityControlId", "tenantsId"]:
|
|
295
|
+
old_objective[key] = new_objective[key]
|
|
296
|
+
else:
|
|
297
|
+
continue
|
|
298
|
+
key_set = next(
|
|
299
|
+
(
|
|
300
|
+
item
|
|
301
|
+
for item in SECURITY_CONTROL_ID_KEY
|
|
302
|
+
if item["new_sc_id"] == new_objective["securityControlId"]
|
|
303
|
+
),
|
|
304
|
+
None,
|
|
305
|
+
)
|
|
306
|
+
old_sc_id = key_set.get("old_sc_id")
|
|
307
|
+
old_objective["securityControlId"] = old_sc_id
|
|
308
|
+
if old_objective.get("tenantsId") is not None:
|
|
309
|
+
del old_objective["tenantsId"]
|
|
310
|
+
update = api.put(
|
|
311
|
+
url=api.config["domain"] + f"/api/controlObjectives/{old_objective['id']}",
|
|
312
|
+
json=old_objective,
|
|
313
|
+
)
|
|
314
|
+
update.raise_for_status()
|
|
315
|
+
if update.ok:
|
|
316
|
+
logger.info(
|
|
317
|
+
"Updated Objective for Objective ID: %i",
|
|
318
|
+
old_objective["id"],
|
|
319
|
+
)
|
|
320
|
+
updated_list.append(old_objective)
|
|
321
|
+
if element_exists is False:
|
|
322
|
+
key_set = next(
|
|
323
|
+
(item for item in SECURITY_CONTROL_ID_KEY if item["new_sc_id"] == new_objective["securityControlId"]),
|
|
324
|
+
None,
|
|
325
|
+
)
|
|
326
|
+
old_sc_id = key_set.get("old_sc_id")
|
|
327
|
+
new_objective["securityControlId"] = old_sc_id
|
|
328
|
+
create = api.post(
|
|
329
|
+
url=api.config["domain"] + "/api/controlObjectives",
|
|
330
|
+
json=new_objective,
|
|
331
|
+
)
|
|
332
|
+
create.raise_for_status()
|
|
333
|
+
if create.ok:
|
|
334
|
+
logger.info(
|
|
335
|
+
"Created Objective for Objective ID: %i",
|
|
336
|
+
new_objective["id"],
|
|
337
|
+
)
|
|
338
|
+
created_list.append(new_objective)
|
|
339
|
+
data_report(
|
|
340
|
+
data_name="Objectives",
|
|
341
|
+
archived=archived_list,
|
|
342
|
+
updated=updated_list,
|
|
343
|
+
created=created_list,
|
|
344
|
+
)
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
def parse_parameters(data: dict) -> dict:
|
|
348
|
+
"""
|
|
349
|
+
Function to parse keys from the provided dictionary
|
|
350
|
+
|
|
351
|
+
:param dict data: parameters from catalog
|
|
352
|
+
:return: dictionary with parsed keys
|
|
353
|
+
:rtype: dict
|
|
354
|
+
"""
|
|
355
|
+
for key in data:
|
|
356
|
+
if key == "isPublic":
|
|
357
|
+
data["isPublic"] = False
|
|
358
|
+
elif key == "default":
|
|
359
|
+
data["default"] = None
|
|
360
|
+
elif key == "dataType":
|
|
361
|
+
data["dataType"] = None
|
|
362
|
+
elif key != "id" or key != "securityControlId":
|
|
363
|
+
continue
|
|
364
|
+
return data
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
def update_parameters(new_parameters: list[dict], old_parameters: list[dict], api: Api) -> None:
|
|
368
|
+
"""
|
|
369
|
+
Function to compare and update parameters
|
|
370
|
+
|
|
371
|
+
:param list[dict] new_parameters: parameters from new catalog
|
|
372
|
+
:param list[dict] old_parameters: parameters from old catalog
|
|
373
|
+
:param Api api: Api object
|
|
374
|
+
:rtype: None
|
|
375
|
+
"""
|
|
376
|
+
archived_list = []
|
|
377
|
+
updated_list = []
|
|
378
|
+
created_list = []
|
|
379
|
+
element_exists = False
|
|
380
|
+
for new_parameter in new_parameters:
|
|
381
|
+
for old_parameter in old_parameters:
|
|
382
|
+
if new_parameter["parameterId"] == old_parameter["parameterId"]:
|
|
383
|
+
element_exists = True
|
|
384
|
+
with contextlib.suppress(KeyError):
|
|
385
|
+
if new_parameter["archived"] is True:
|
|
386
|
+
old_parameter["archived"] = True
|
|
387
|
+
archived_list.append(old_parameter)
|
|
388
|
+
break
|
|
389
|
+
old_parameter = parse_parameters(old_parameter)
|
|
390
|
+
key_set = next(
|
|
391
|
+
(
|
|
392
|
+
item
|
|
393
|
+
for item in SECURITY_CONTROL_ID_KEY
|
|
394
|
+
if item["new_sc_id"] == new_parameter["securityControlId"]
|
|
395
|
+
),
|
|
396
|
+
None,
|
|
397
|
+
)
|
|
398
|
+
old_sc_id = key_set.get("old_sc_id")
|
|
399
|
+
old_parameter["securityControlId"] = old_sc_id
|
|
400
|
+
update = api.put(
|
|
401
|
+
url=api.config["domain"] + f"/api/controlParameters/{old_parameter['id']}",
|
|
402
|
+
json=old_parameter,
|
|
403
|
+
)
|
|
404
|
+
update.raise_for_status()
|
|
405
|
+
if update.ok:
|
|
406
|
+
logger.info(
|
|
407
|
+
"Updated Parameter for Parameter ID: %i",
|
|
408
|
+
old_parameter["id"],
|
|
409
|
+
)
|
|
410
|
+
updated_list.append(old_parameter)
|
|
411
|
+
if element_exists is False:
|
|
412
|
+
key_set = next(
|
|
413
|
+
(item for item in SECURITY_CONTROL_ID_KEY if item["new_sc_id"] == new_parameter["securityControlId"]),
|
|
414
|
+
None,
|
|
415
|
+
)
|
|
416
|
+
old_sc_id = key_set.get("old_sc_id")
|
|
417
|
+
new_parameter["securityControlId"] = old_sc_id
|
|
418
|
+
create = api.post(
|
|
419
|
+
url=api.config["domain"] + "/api/controlParameters",
|
|
420
|
+
json=new_parameter,
|
|
421
|
+
)
|
|
422
|
+
create.raise_for_status()
|
|
423
|
+
if create.ok:
|
|
424
|
+
logger.info(
|
|
425
|
+
"Created Parameter for Parameter ID: %i",
|
|
426
|
+
new_parameter["id"],
|
|
427
|
+
)
|
|
428
|
+
created_list.append(new_parameter)
|
|
429
|
+
data_report(
|
|
430
|
+
data_name="Parameters",
|
|
431
|
+
archived=archived_list,
|
|
432
|
+
updated=updated_list,
|
|
433
|
+
created=created_list,
|
|
434
|
+
)
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
def update_tests(new_tests: list[dict], old_tests: list[dict], api: Api) -> None:
|
|
438
|
+
"""
|
|
439
|
+
Function to compare and update tests
|
|
440
|
+
|
|
441
|
+
:param list[dict] new_tests: tests from new catalog
|
|
442
|
+
:param list[dict] old_tests: tests from old catalog
|
|
443
|
+
:param Api api: API Object
|
|
444
|
+
:rtype: None
|
|
445
|
+
"""
|
|
446
|
+
archived_list = []
|
|
447
|
+
updated_list = []
|
|
448
|
+
created_list = []
|
|
449
|
+
element_exists = False
|
|
450
|
+
for new_test in new_tests:
|
|
451
|
+
for old_test in old_tests:
|
|
452
|
+
if new_test["testId"] == old_test["testId"]:
|
|
453
|
+
element_exists = True
|
|
454
|
+
with contextlib.suppress(KeyError):
|
|
455
|
+
if new_test["archived"] is True:
|
|
456
|
+
old_test["archived"] = True
|
|
457
|
+
archived_list.append(old_test)
|
|
458
|
+
break
|
|
459
|
+
for key in old_test:
|
|
460
|
+
if key == "isPublic":
|
|
461
|
+
old_test["isPublic"] = False
|
|
462
|
+
elif key not in ["id", "securityControlId", "tenantsId"]:
|
|
463
|
+
old_test[key] = new_test[key]
|
|
464
|
+
else:
|
|
465
|
+
continue
|
|
466
|
+
key_set = next(
|
|
467
|
+
(item for item in SECURITY_CONTROL_ID_KEY if item["new_sc_id"] == new_test["securityControlId"]),
|
|
468
|
+
None,
|
|
469
|
+
)
|
|
470
|
+
old_sc_id = key_set.get("old_sc_id")
|
|
471
|
+
old_test["securityControlId"] = old_sc_id
|
|
472
|
+
update = api.put(
|
|
473
|
+
url=api.config["domain"] + f"/api/controlTestPlans/{old_test['id']}",
|
|
474
|
+
json=old_test,
|
|
475
|
+
)
|
|
476
|
+
update.raise_for_status()
|
|
477
|
+
if update.ok:
|
|
478
|
+
logger.info(
|
|
479
|
+
"Updated test for test ID: %i",
|
|
480
|
+
old_test["id"],
|
|
481
|
+
)
|
|
482
|
+
updated_list.append(old_test)
|
|
483
|
+
if element_exists is False:
|
|
484
|
+
key_set = next(
|
|
485
|
+
(item for item in SECURITY_CONTROL_ID_KEY if item["new_sc_id"] == new_test["securityControlId"]),
|
|
486
|
+
None,
|
|
487
|
+
)
|
|
488
|
+
old_sc_id = key_set.get("old_sc_id")
|
|
489
|
+
new_test["securityControlId"] = old_sc_id
|
|
490
|
+
create = api.post(
|
|
491
|
+
url=api.config["domain"] + "/api/controlTestPlans",
|
|
492
|
+
json=new_test,
|
|
493
|
+
)
|
|
494
|
+
create.raise_for_status()
|
|
495
|
+
if create.ok:
|
|
496
|
+
logger.info(
|
|
497
|
+
"Created test for test ID: %i",
|
|
498
|
+
new_test["id"],
|
|
499
|
+
)
|
|
500
|
+
created_list.append(new_test)
|
|
501
|
+
data_report(
|
|
502
|
+
data_name="Tests",
|
|
503
|
+
archived=archived_list,
|
|
504
|
+
updated=updated_list,
|
|
505
|
+
created=created_list,
|
|
506
|
+
)
|
|
507
|
+
|
|
508
|
+
|
|
509
|
+
def parse_new_catalog() -> Tuple[list, list, list, list, list]:
|
|
510
|
+
"""
|
|
511
|
+
Function to parse elements from the new catalog
|
|
512
|
+
|
|
513
|
+
:return: Tuple containing lists of new catalog data elements
|
|
514
|
+
:rtype: Tuple[list, list, list, list, list]
|
|
515
|
+
"""
|
|
516
|
+
with job_progress:
|
|
517
|
+
# add task for retrieving new catalog
|
|
518
|
+
retrieving_new_catalog = job_progress.add_task(
|
|
519
|
+
"[#f8b737]Retrieving selected catalog from RegScale.com/regulations.",
|
|
520
|
+
total=6,
|
|
521
|
+
)
|
|
522
|
+
# retrieve new catalog to run diagnostics on
|
|
523
|
+
new_catalog = get_new_catalog(url=DOWNLOAD_URL)
|
|
524
|
+
# update the task as complete
|
|
525
|
+
job_progress.update(retrieving_new_catalog, advance=1)
|
|
526
|
+
# retrieve new catalog security controls
|
|
527
|
+
new_security_controls = parse_dict_and_sublevel(
|
|
528
|
+
data=new_catalog,
|
|
529
|
+
key="catalogue",
|
|
530
|
+
sub_key="securityControls",
|
|
531
|
+
del_key="tenantsId",
|
|
532
|
+
)
|
|
533
|
+
# update the task as complete
|
|
534
|
+
job_progress.update(retrieving_new_catalog, advance=1)
|
|
535
|
+
# retrieve new catalog ccis
|
|
536
|
+
new_ccis = parse_dict_and_sublevel(data=new_catalog, key="catalogue", sub_key="ccis")
|
|
537
|
+
# update the task as complete
|
|
538
|
+
job_progress.update(retrieving_new_catalog, advance=1)
|
|
539
|
+
# retrieve new catalog objectives
|
|
540
|
+
new_objectives = parse_dict_and_sublevel(data=new_catalog, key="catalogue", sub_key="objectives")
|
|
541
|
+
# update the task as complete
|
|
542
|
+
job_progress.update(retrieving_new_catalog, advance=1)
|
|
543
|
+
# retrieve new catalog parameters
|
|
544
|
+
new_parameters = parse_dict_and_sublevel(data=new_catalog, key="catalogue", sub_key="parameters")
|
|
545
|
+
# update the task as complete
|
|
546
|
+
job_progress.update(retrieving_new_catalog, advance=1)
|
|
547
|
+
# retrieve new catalog tests
|
|
548
|
+
new_tests = parse_dict_and_sublevel(data=new_catalog, key="catalogue", sub_key="tests")
|
|
549
|
+
# update the task as complete
|
|
550
|
+
job_progress.update(retrieving_new_catalog, completed=6)
|
|
551
|
+
return new_security_controls, new_ccis, new_objectives, new_parameters, new_tests
|
|
552
|
+
|
|
553
|
+
|
|
554
|
+
def parse_old_catalog(api: Api) -> Tuple[list, list, list, list, list]:
|
|
555
|
+
"""
|
|
556
|
+
Function to parse elements from the old catalog
|
|
557
|
+
|
|
558
|
+
:param Api api: RegScale API object
|
|
559
|
+
:return: Tuple containing lists of old catalog elements
|
|
560
|
+
:rtype: Tuple[list, list, list, list, list]
|
|
561
|
+
"""
|
|
562
|
+
with job_progress:
|
|
563
|
+
# add task for retrieving old catalog
|
|
564
|
+
retrieving_old_catalog = job_progress.add_task(
|
|
565
|
+
"[#ef5d23]Retrieving selected catalog from RegScale application instance.",
|
|
566
|
+
total=5,
|
|
567
|
+
)
|
|
568
|
+
# retrieve old catalog security controls
|
|
569
|
+
security_controls = parse_controls(api=api)
|
|
570
|
+
old_security_controls = security_controls[0]
|
|
571
|
+
# update the task as complete
|
|
572
|
+
job_progress.update(retrieving_old_catalog, advance=1)
|
|
573
|
+
# retrive old catalog ccis
|
|
574
|
+
old_ccis = security_controls[4]
|
|
575
|
+
# update the task as complete
|
|
576
|
+
job_progress.update(retrieving_old_catalog, advance=1)
|
|
577
|
+
# retrieve old catalog objectives
|
|
578
|
+
old_objectives = security_controls[2]
|
|
579
|
+
# update the task as complete
|
|
580
|
+
job_progress.update(retrieving_old_catalog, advance=1)
|
|
581
|
+
# retrieve old catalog parameters
|
|
582
|
+
old_parameters = security_controls[1]
|
|
583
|
+
# update the task as complete
|
|
584
|
+
job_progress.update(retrieving_old_catalog, advance=1)
|
|
585
|
+
# retrieve old catalog tests
|
|
586
|
+
old_tests = security_controls[3]
|
|
587
|
+
# update the task as complete
|
|
588
|
+
job_progress.update(retrieving_old_catalog, advance=1)
|
|
589
|
+
|
|
590
|
+
return old_security_controls, old_ccis, old_objectives, old_parameters, old_tests
|
|
591
|
+
|
|
592
|
+
|
|
593
|
+
def parse_dict_and_sublevel(data: dict, key: str, sub_key: str, del_key: Optional[str] = None) -> list:
|
|
594
|
+
"""
|
|
595
|
+
Function to parse a dictionary and retrieve data from the sublevel dictionary key
|
|
596
|
+
|
|
597
|
+
:param dict data: dictionary to parse
|
|
598
|
+
:param str key: key to be extracted from the dictionary
|
|
599
|
+
:param str sub_key: the sub-level key being looked for
|
|
600
|
+
:param Optional[str] del_key: the sub-level key to delete, defaults to None
|
|
601
|
+
:return: a list containing the parsed data elements
|
|
602
|
+
:rtype: list
|
|
603
|
+
"""
|
|
604
|
+
parse_list = []
|
|
605
|
+
with contextlib.suppress(KeyError):
|
|
606
|
+
parse_list.extend(iter(data[key][sub_key]))
|
|
607
|
+
if del_key:
|
|
608
|
+
for parsed_item in parse_list:
|
|
609
|
+
del parsed_item[del_key]
|
|
610
|
+
return parse_list
|
|
611
|
+
|
|
612
|
+
|
|
613
|
+
def data_report(data_name: str, archived: list, updated: list, created: list) -> None:
|
|
614
|
+
"""Creates output data report for changed data elements in the catalog
|
|
615
|
+
|
|
616
|
+
:param str data_name: catalog data element being updated
|
|
617
|
+
:param list archived: archived data elements
|
|
618
|
+
:param list updated: updated data elements
|
|
619
|
+
:param list created: created data elements
|
|
620
|
+
:rtype: None
|
|
621
|
+
"""
|
|
622
|
+
import pandas as pd # Optimize import performance
|
|
623
|
+
|
|
624
|
+
archived_data = pd.DataFrame.from_dict(archived)
|
|
625
|
+
updated_data = pd.DataFrame.from_dict(updated)
|
|
626
|
+
created_data = pd.DataFrame.from_dict(created)
|
|
627
|
+
with pd.ExcelWriter(f"{data_name}.xlsx") as writer:
|
|
628
|
+
archived_data.to_excel(writer, sheet_name="Archived", index=False)
|
|
629
|
+
updated_data.to_excel(writer, sheet_name="Updated", index=False)
|
|
630
|
+
created_data.to_excel(writer, sheet_name="Created", index=False)
|
|
631
|
+
|
|
632
|
+
|
|
633
|
+
def get_old_security_controls(uuid_value: str, api: Api) -> list[dict]:
|
|
634
|
+
"""
|
|
635
|
+
Function to retrieve the old catalog security controls from a RegScale instance via API & GraphQL
|
|
636
|
+
|
|
637
|
+
:param str uuid_value: UUID of the catalog to retrieve
|
|
638
|
+
:param Api api: RegScale API object
|
|
639
|
+
:return: a list containing security controls
|
|
640
|
+
:rtype: list[dict]
|
|
641
|
+
"""
|
|
642
|
+
body = """
|
|
643
|
+
query {
|
|
644
|
+
catalogues(
|
|
645
|
+
skip: 0
|
|
646
|
+
take: 50
|
|
647
|
+
where: { uuid: { eq: "uuid_value" } }
|
|
648
|
+
) {
|
|
649
|
+
items {
|
|
650
|
+
id
|
|
651
|
+
}
|
|
652
|
+
pageInfo {
|
|
653
|
+
hasNextPage
|
|
654
|
+
}
|
|
655
|
+
totalCount
|
|
656
|
+
}
|
|
657
|
+
}""".replace(
|
|
658
|
+
"uuid_value", uuid_value
|
|
659
|
+
)
|
|
660
|
+
try:
|
|
661
|
+
catalogue_id = api.graph(query=body)["catalogues"]["items"][0]["id"]
|
|
662
|
+
except (IndexError, KeyError):
|
|
663
|
+
error_and_exit(f"Catalog with UUID: {uuid_value} not found in RegScale instance.")
|
|
664
|
+
try:
|
|
665
|
+
old_security_controls = api.get(
|
|
666
|
+
url=api.config["domain"] + f"/api/SecurityControls/getAllByCatalogWithDetails/{catalogue_id}"
|
|
667
|
+
).json()
|
|
668
|
+
if len(old_security_controls) == 0:
|
|
669
|
+
error_and_exit("This catalog does not currently exist in the RegScale application")
|
|
670
|
+
except JSONDecodeError as ex:
|
|
671
|
+
error_and_exit(f"Unable to retrieve control objectives from RegScale.\n{ex}")
|
|
672
|
+
except TimeoutError:
|
|
673
|
+
error_and_exit("The selected catalog is too large to update, please contact RegScale customer service.")
|
|
674
|
+
return old_security_controls
|
|
675
|
+
|
|
676
|
+
|
|
677
|
+
def parse_controls(
|
|
678
|
+
api: Api,
|
|
679
|
+
) -> Tuple[list[dict], list[dict], list[dict], list[dict], list[dict]]:
|
|
680
|
+
"""
|
|
681
|
+
Function to retrieve the old catalog security controls from a RegScale instance via API & GraphQL
|
|
682
|
+
|
|
683
|
+
:param Api api: RegScale API object
|
|
684
|
+
:return: a tuple containing a list for each catalog element
|
|
685
|
+
:rtype: Tuple[list[dict], list[dict], list[dict], list[dict], list[dict]]
|
|
686
|
+
"""
|
|
687
|
+
old_security_controls = get_old_security_controls(uuid_value=CAT_UUID, api=api)
|
|
688
|
+
parsed_old_security_controls = []
|
|
689
|
+
for old_control in old_security_controls:
|
|
690
|
+
parsed_old_security_controls.append(old_control["control"])
|
|
691
|
+
old_parameters = []
|
|
692
|
+
for control in old_security_controls:
|
|
693
|
+
for parameter in control["parameters"]:
|
|
694
|
+
old_parameters.append(parameter)
|
|
695
|
+
old_objectives = []
|
|
696
|
+
for control in old_security_controls:
|
|
697
|
+
for objective in control["objectives"]:
|
|
698
|
+
old_objectives.append(objective)
|
|
699
|
+
old_tests = []
|
|
700
|
+
for control in old_security_controls:
|
|
701
|
+
for test in control["tests"]:
|
|
702
|
+
old_tests.append(test)
|
|
703
|
+
old_ccis = []
|
|
704
|
+
for control in old_security_controls:
|
|
705
|
+
id_number = control["control"]["id"]
|
|
706
|
+
try:
|
|
707
|
+
ccis = api.get(url=api.config["domain"] + f"/api/cci/getByControl/{id_number}").json()
|
|
708
|
+
if ccis:
|
|
709
|
+
old_ccis.append(ccis)
|
|
710
|
+
except JSONDecodeError as ex:
|
|
711
|
+
error_and_exit(f"Unable to retrieve control objectives from RegScale.\n{ex}")
|
|
712
|
+
return (
|
|
713
|
+
parsed_old_security_controls,
|
|
714
|
+
old_parameters,
|
|
715
|
+
old_objectives,
|
|
716
|
+
old_tests,
|
|
717
|
+
old_ccis,
|
|
718
|
+
)
|