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,70 @@
|
|
|
1
|
+
import click
|
|
2
|
+
from regscale.models.regscale_models.security_control import SecurityControl
|
|
3
|
+
import logging
|
|
4
|
+
|
|
5
|
+
logger = logging.getLogger(__name__)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# Function to update the security control's criticality using the API
|
|
9
|
+
def update_security_control_criticality(control_id: str, criticality: str, control_dict: dict):
|
|
10
|
+
"""
|
|
11
|
+
Update the security control's criticality using the API.
|
|
12
|
+
:param control_dict:
|
|
13
|
+
:param str control_id:
|
|
14
|
+
:param str criticality:
|
|
15
|
+
"""
|
|
16
|
+
control_id = control_id.lower().strip().replace(" ", "")
|
|
17
|
+
matching_control: SecurityControl = control_dict.get(control_id.lower().strip())
|
|
18
|
+
logger.info(
|
|
19
|
+
f"Updating control {control_id} == {matching_control.controlId.lower().strip() if matching_control else None} with criticality {criticality}"
|
|
20
|
+
)
|
|
21
|
+
if control := control_dict.get(control_id):
|
|
22
|
+
control.criticality = criticality
|
|
23
|
+
control.save()
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@click.group(name="criticality_updater")
|
|
27
|
+
def criticality_updater():
|
|
28
|
+
"""
|
|
29
|
+
Update the criticality of security controls in the catalog.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@criticality_updater.command(name="import")
|
|
34
|
+
@click.option("--file_path", "-f", help="Path to the Excel file", required=True, type=click.Path(exists=True))
|
|
35
|
+
@click.option("--catalog_id", "-cat", help="Catalog ID", required=True, type=int)
|
|
36
|
+
@click.option(
|
|
37
|
+
"--column_header_control_id",
|
|
38
|
+
"-ci",
|
|
39
|
+
help="Column header for the Security Control ID",
|
|
40
|
+
default="Security Control #",
|
|
41
|
+
required=True,
|
|
42
|
+
)
|
|
43
|
+
@click.option(
|
|
44
|
+
"--column_header_criticality",
|
|
45
|
+
"-c",
|
|
46
|
+
help="Column header for the Criticality Rating",
|
|
47
|
+
default="Security Control Criticality Rating",
|
|
48
|
+
required=True,
|
|
49
|
+
)
|
|
50
|
+
def update_control_criticality(
|
|
51
|
+
file_path: str, catalog_id: int, column_header_control_id: str, column_header_criticality: str
|
|
52
|
+
):
|
|
53
|
+
"""
|
|
54
|
+
Update the criticality of security controls in the catalog.
|
|
55
|
+
"""
|
|
56
|
+
import pandas as pd # Optimize import performance
|
|
57
|
+
|
|
58
|
+
df = pd.read_excel(file_path)
|
|
59
|
+
controls = SecurityControl.get_all_by_parent(parent_id=catalog_id, parent_module="catalogs") # Get all the controls
|
|
60
|
+
logger.info(f"Found {len(controls)} controls")
|
|
61
|
+
control_dict = {control.controlId.lower(): control for control in controls} # Create a dictionary for easy access
|
|
62
|
+
# Loop through the DataFrame and map the controls
|
|
63
|
+
for index, row in df.iterrows():
|
|
64
|
+
control_id = row.get(column_header_control_id) # Column A - Security Control
|
|
65
|
+
criticality = row.get(column_header_criticality) # Column D - Criticality Rating
|
|
66
|
+
|
|
67
|
+
if pd.notna(control_id) and pd.notna(criticality): # Ensure the values are not empty
|
|
68
|
+
# Update the security control with the new criticality
|
|
69
|
+
update_security_control_criticality(control_id, criticality, control_dict)
|
|
70
|
+
logger.info("Finished processing all records.")
|
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""eMASS integration to the CLI to allow support for eMASS documents"""
|
|
4
|
+
|
|
5
|
+
# standard python imports
|
|
6
|
+
import os
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
import click
|
|
10
|
+
from openpyxl import load_workbook
|
|
11
|
+
from openpyxl.comments import Comment
|
|
12
|
+
from openpyxl.styles import PatternFill
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
from regscale.core.app.api import Api
|
|
16
|
+
from regscale.integrations.public.emass_slcm_import import import_emass_slcm_file
|
|
17
|
+
from regscale.core.app.utils.app_utils import (
|
|
18
|
+
check_file_path,
|
|
19
|
+
create_progress_object,
|
|
20
|
+
error_and_exit,
|
|
21
|
+
get_current_datetime,
|
|
22
|
+
get_file_type,
|
|
23
|
+
reformat_str_date,
|
|
24
|
+
)
|
|
25
|
+
from regscale.models import regscale_id
|
|
26
|
+
|
|
27
|
+
SKIP_ROWS: int = 7
|
|
28
|
+
COLUMNS = ["M", "N", "O", "P"]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@click.group()
|
|
32
|
+
def emass():
|
|
33
|
+
"""Performs bulk processing of eMASS files (Upload trusted data only)."""
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@emass.command("populate_controls")
|
|
37
|
+
@click.option(
|
|
38
|
+
"--file_name",
|
|
39
|
+
type=click.Path(exists=True, dir_okay=False, file_okay=True),
|
|
40
|
+
required=True,
|
|
41
|
+
prompt="Enter the full file path of the eMASS controls document.",
|
|
42
|
+
help="Enter the full file path of the eMASS controls document to populate with RegScale data.",
|
|
43
|
+
)
|
|
44
|
+
@regscale_id(help="Enter the desired SSP ID # from RegScale.")
|
|
45
|
+
def populate_workbook(file_name: click.Path, regscale_id: int) -> None:
|
|
46
|
+
"""
|
|
47
|
+
[BETA] Populate controls from a System Security Plan in RegScale into an eMASS formatted excel workbook.
|
|
48
|
+
"""
|
|
49
|
+
populate_emass_workbook(file_name=file_name, regscale_id=regscale_id)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@emass.command("import_slcm")
|
|
53
|
+
@click.option(
|
|
54
|
+
"--file_name",
|
|
55
|
+
type=click.Path(exists=True, dir_okay=False, file_okay=True),
|
|
56
|
+
required=True,
|
|
57
|
+
prompt="Enter the full file path of the eMASS controls document.",
|
|
58
|
+
help="Enter the full file path of the eMASS controls document to populate with RegScale data.",
|
|
59
|
+
)
|
|
60
|
+
@regscale_id(help="Enter the desired SSP ID # from RegScale.")
|
|
61
|
+
@click.option(
|
|
62
|
+
"--catalogue_id",
|
|
63
|
+
"-c",
|
|
64
|
+
type=click.INT,
|
|
65
|
+
help="The RegScale ID # of the catalogue to use for controls in the profile.",
|
|
66
|
+
required=True,
|
|
67
|
+
)
|
|
68
|
+
@click.option(
|
|
69
|
+
"--tenant_id",
|
|
70
|
+
"-t",
|
|
71
|
+
type=click.INT,
|
|
72
|
+
help="The RegScale ID # of the tenant to use for this security plan.",
|
|
73
|
+
required=True,
|
|
74
|
+
)
|
|
75
|
+
def import_slcm(file_name: click.Path, regscale_id: int, catalogue_id: int, tenant_id: int) -> None:
|
|
76
|
+
"""
|
|
77
|
+
[BETA] Populate controls from a System Security Plan in RegScale into an eMASS formatted excel workbook.
|
|
78
|
+
"""
|
|
79
|
+
import_emass_slcm_file(file_name=file_name, regscale_id=regscale_id, catalogue_id=catalogue_id, tenant_id=tenant_id)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def fetch_template_from_blob() -> None:
|
|
83
|
+
"""
|
|
84
|
+
Fetch a template for the eMASS controls document
|
|
85
|
+
|
|
86
|
+
:rtype: None
|
|
87
|
+
"""
|
|
88
|
+
api = Api()
|
|
89
|
+
|
|
90
|
+
# check if the artifacts folder exists
|
|
91
|
+
check_file_path("artifacts")
|
|
92
|
+
|
|
93
|
+
# get the template from the API
|
|
94
|
+
template = api.get(
|
|
95
|
+
url="https://regscaleblob.blob.core.windows.net/blob/eMASS_Control_Template.xlsx",
|
|
96
|
+
headers={},
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
# write the template to a file
|
|
100
|
+
with open(f".{os.sep}artifacts{os.sep}eMASS_Template.xlsx", "wb") as f:
|
|
101
|
+
f.write(template.content)
|
|
102
|
+
api.logger.info(f"Template saved to .{os.sep}artifacts{os.sep}eMASS_Template.xlsx")
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def populate_emass_workbook(file_name: Path, regscale_id: int) -> None:
|
|
106
|
+
"""
|
|
107
|
+
Function to populate an eMASS workbook with control assessments from RegScale
|
|
108
|
+
|
|
109
|
+
:param Path file_name: Path to the eMASS control workbook
|
|
110
|
+
:param int regscale_id: ID of the SSP in RegScale to get the controls & assessments from
|
|
111
|
+
:rtype: None
|
|
112
|
+
"""
|
|
113
|
+
# make sure the user gave a path to an Excel workbook
|
|
114
|
+
if get_file_type(file_name) not in [".xlsx", ".xls"]:
|
|
115
|
+
error_and_exit("Please provide a file path to an Excel workbook in .xlsx or .xls format.")
|
|
116
|
+
|
|
117
|
+
# convert file_name to a Path object
|
|
118
|
+
file_name = Path(file_name)
|
|
119
|
+
|
|
120
|
+
# initialize the Application and API classes
|
|
121
|
+
api = Api()
|
|
122
|
+
|
|
123
|
+
# populate the controls in the Excel workbook
|
|
124
|
+
output_name = populate_assessment_results(file_name=file_name, ssp_id=regscale_id, api=api)
|
|
125
|
+
api.logger.info("Please open %s and verify the data before uploading into eMASS.", output_name)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def map_ccis(file_data_dict: dict, file_name: str) -> dict:
|
|
129
|
+
"""
|
|
130
|
+
Function to map each cci and its row number in the eMASS workbook
|
|
131
|
+
|
|
132
|
+
:param dict file_data_dict: Dictionary of an Excel file column
|
|
133
|
+
:param str file_name: Name of the file file_data_dict is from
|
|
134
|
+
:return: dictionary of ccis and their row numbers
|
|
135
|
+
:rtype: dict
|
|
136
|
+
"""
|
|
137
|
+
# convert the control names to match RegScale control names
|
|
138
|
+
try:
|
|
139
|
+
formatted_ccis = {
|
|
140
|
+
# create a dictionary with the key as the control name and the value as the row number
|
|
141
|
+
# cci has a prefix of CCI- and must be a 6-digit number
|
|
142
|
+
f"CCI-{val:06}": {
|
|
143
|
+
"cci": f"CCI-{val:06}",
|
|
144
|
+
"row": key + SKIP_ROWS,
|
|
145
|
+
}
|
|
146
|
+
for key, val in file_data_dict["CCI"].items()
|
|
147
|
+
}
|
|
148
|
+
except KeyError:
|
|
149
|
+
error_and_exit(
|
|
150
|
+
f"{file_name} doesn't match the expected eMASS format.\nPlease view an example "
|
|
151
|
+
"template here: https://regscale.readme.io/docs/emass-beta#template"
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
return formatted_ccis or {}
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def fetch_assessments_and_controls(ssp_id: int, api: Api) -> list:
|
|
158
|
+
"""
|
|
159
|
+
Fetch assessments and controls from RegScale
|
|
160
|
+
|
|
161
|
+
:param int ssp_id: SSP ID from RegScale
|
|
162
|
+
:param Api api: API Object
|
|
163
|
+
:return: List of controls with assessments
|
|
164
|
+
:rtype: list
|
|
165
|
+
"""
|
|
166
|
+
# create the GraphQL query
|
|
167
|
+
query = f"""
|
|
168
|
+
query {{
|
|
169
|
+
controls:controlImplementations(
|
|
170
|
+
take: 50
|
|
171
|
+
skip: 0
|
|
172
|
+
where: {{
|
|
173
|
+
parentId: {{ eq: {ssp_id} }}
|
|
174
|
+
parentModule: {{ eq: "securityplans" }}
|
|
175
|
+
assessments: {{ any: true }}
|
|
176
|
+
}}
|
|
177
|
+
) {{
|
|
178
|
+
items {{
|
|
179
|
+
id
|
|
180
|
+
control {{
|
|
181
|
+
controlId
|
|
182
|
+
cci {{
|
|
183
|
+
name
|
|
184
|
+
description
|
|
185
|
+
}}
|
|
186
|
+
}}
|
|
187
|
+
assessments {{
|
|
188
|
+
id
|
|
189
|
+
actualFinish
|
|
190
|
+
assessmentResult
|
|
191
|
+
summaryOfResults
|
|
192
|
+
leadAssessor {{
|
|
193
|
+
firstName
|
|
194
|
+
lastName
|
|
195
|
+
}}
|
|
196
|
+
}}
|
|
197
|
+
}}
|
|
198
|
+
totalCount
|
|
199
|
+
pageInfo {{
|
|
200
|
+
hasNextPage
|
|
201
|
+
}}
|
|
202
|
+
}}
|
|
203
|
+
}}
|
|
204
|
+
"""
|
|
205
|
+
|
|
206
|
+
# get the data from GraphQL
|
|
207
|
+
response = api.graph(query=query)
|
|
208
|
+
|
|
209
|
+
# try to get the items from the GraphQL response
|
|
210
|
+
try:
|
|
211
|
+
controls = response["controls"]["items"]
|
|
212
|
+
except KeyError:
|
|
213
|
+
controls = []
|
|
214
|
+
|
|
215
|
+
total_controls = api.get(
|
|
216
|
+
f"{api.config['domain']}/api/controlImplementation/getCountByParent/{ssp_id}/securityplans"
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
if not total_controls.ok:
|
|
220
|
+
error_and_exit(f"Received unexpected response: {total_controls.status_code}\n{total_controls.text}")
|
|
221
|
+
|
|
222
|
+
if controls:
|
|
223
|
+
api.logger.info(
|
|
224
|
+
"Received %s/%s controls with Assessments. Total control count for SSP #%s in RegScale: %s.",
|
|
225
|
+
len(controls),
|
|
226
|
+
response["controls"]["totalCount"],
|
|
227
|
+
ssp_id,
|
|
228
|
+
total_controls.text,
|
|
229
|
+
)
|
|
230
|
+
for control in controls:
|
|
231
|
+
try:
|
|
232
|
+
control["ccis"] = [cci["name"] for cci in control["control"]["cci"]]
|
|
233
|
+
except (KeyError, TypeError):
|
|
234
|
+
control["ccis"] = []
|
|
235
|
+
else:
|
|
236
|
+
error_and_exit(
|
|
237
|
+
"The RegScale SSP provided has no assessments associated with the controls. "
|
|
238
|
+
+ "Please add assessments to the controls and try again."
|
|
239
|
+
)
|
|
240
|
+
return controls
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def populate_assessment_results(file_name: Path, ssp_id: int, api: Api) -> Path:
|
|
244
|
+
"""
|
|
245
|
+
Populate assessment results from a System Security Plan in RegScale into an eMASS formatted excel workbook
|
|
246
|
+
|
|
247
|
+
:param Path file_name: path to the Excel workbook to populate with assessments from SSP
|
|
248
|
+
:param int ssp_id: ID for a System Security Plan from RegScale
|
|
249
|
+
:param Api api: API Object
|
|
250
|
+
:return: Path to output file
|
|
251
|
+
:rtype: Path
|
|
252
|
+
"""
|
|
253
|
+
import pandas as pd # Optimize import performance
|
|
254
|
+
|
|
255
|
+
author = "RegScale CLI"
|
|
256
|
+
job_progress = create_progress_object()
|
|
257
|
+
logger = api.logger
|
|
258
|
+
controls = fetch_assessments_and_controls(ssp_id=ssp_id, api=api)
|
|
259
|
+
# load the Excel file in pandas to find row # to update the data
|
|
260
|
+
file_data = pd.read_excel(file_name, skiprows=SKIP_ROWS - 2)
|
|
261
|
+
|
|
262
|
+
# load the workbook using openpyxl to retain worksheet styling
|
|
263
|
+
wb = load_workbook(file_name)
|
|
264
|
+
|
|
265
|
+
# set the sheet to the first sheet in the provided workbook
|
|
266
|
+
sheet = wb.active
|
|
267
|
+
|
|
268
|
+
# convert to a dictionary
|
|
269
|
+
file_data_dict = file_data.to_dict()
|
|
270
|
+
|
|
271
|
+
# format the controls
|
|
272
|
+
cci_mappings = map_ccis(file_data_dict=file_data_dict, file_name=file_name.name)
|
|
273
|
+
|
|
274
|
+
# create variable to count number of rows updated and skipped
|
|
275
|
+
update_counter: int = 0
|
|
276
|
+
skipped_counter: int = 0
|
|
277
|
+
|
|
278
|
+
# create a dictionary of all ccis and their assessments
|
|
279
|
+
regscale_cci_assessments = {
|
|
280
|
+
cci: {"assessment": ctrl["assessments"][0]}
|
|
281
|
+
for ctrl in controls
|
|
282
|
+
for cci in ctrl.get("ccis", [])
|
|
283
|
+
if "ccis" in ctrl
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
# create comment & fill attribute for columns with missing data
|
|
287
|
+
comment = Comment(
|
|
288
|
+
text=f"SSP #{ssp_id} doesn't contain an assessment associated with this control.",
|
|
289
|
+
author=author,
|
|
290
|
+
height=150,
|
|
291
|
+
)
|
|
292
|
+
yellow_fill = PatternFill(start_color="FFFF00", end_color="FFFF00", fill_type="solid")
|
|
293
|
+
|
|
294
|
+
with job_progress:
|
|
295
|
+
populating_controls = job_progress.add_task(
|
|
296
|
+
f"[#21a5bb]Analyzing controls in {file_name.name}...",
|
|
297
|
+
total=len(cci_mappings),
|
|
298
|
+
)
|
|
299
|
+
# iterate through the ccis
|
|
300
|
+
for cci in cci_mappings.values():
|
|
301
|
+
row_number = cci["row"]
|
|
302
|
+
cci_id = cci["cci"]
|
|
303
|
+
|
|
304
|
+
# see if the cci has an assessment by comparing it to our GraphQL query results
|
|
305
|
+
if cci_id not in regscale_cci_assessments or not regscale_cci_assessments[cci_id].get("assessment"):
|
|
306
|
+
# increment the skip counter
|
|
307
|
+
skipped_counter += 1
|
|
308
|
+
|
|
309
|
+
# highlight and add a comment
|
|
310
|
+
for column in COLUMNS:
|
|
311
|
+
sheet[f"{column}{row_number}"].comment = comment
|
|
312
|
+
sheet[f"{column}{row_number}"].fill = yellow_fill
|
|
313
|
+
job_progress.update(populating_controls, advance=1)
|
|
314
|
+
continue
|
|
315
|
+
# get the assessment for the cci
|
|
316
|
+
assessment = regscale_cci_assessments[cci_id]["assessment"]
|
|
317
|
+
|
|
318
|
+
map_finish_date(
|
|
319
|
+
assessment=assessment,
|
|
320
|
+
sheet=sheet,
|
|
321
|
+
row_number=row_number,
|
|
322
|
+
author=author,
|
|
323
|
+
yellow_fill=yellow_fill,
|
|
324
|
+
)
|
|
325
|
+
|
|
326
|
+
sheet[f"O{row_number}"] = (
|
|
327
|
+
f'{assessment["leadAssessor"]["firstName"]} {assessment["leadAssessor"]["lastName"]}'
|
|
328
|
+
)
|
|
329
|
+
if assessment["summaryOfResults"]:
|
|
330
|
+
sheet[f"P{row_number}"] = assessment["summaryOfResults"]
|
|
331
|
+
else:
|
|
332
|
+
sheet[f"P{row_number}"].comment = Comment(
|
|
333
|
+
text=f"RegScale assessment #{assessment['id']} doesn't have any information in Summary of Results.",
|
|
334
|
+
author=author,
|
|
335
|
+
height=150,
|
|
336
|
+
)
|
|
337
|
+
sheet[f"P{row_number}"].fill = yellow_fill
|
|
338
|
+
|
|
339
|
+
# update the counter
|
|
340
|
+
update_counter += 1
|
|
341
|
+
# update the progress bar
|
|
342
|
+
job_progress.update(populating_controls, advance=1)
|
|
343
|
+
|
|
344
|
+
# add the date and time to the output filename
|
|
345
|
+
output_name = Path(
|
|
346
|
+
os.path.join(
|
|
347
|
+
file_name.parent,
|
|
348
|
+
file_name.stem + get_current_datetime("_Updated_%Y%m%d_%H%M%S") + file_name.suffix,
|
|
349
|
+
)
|
|
350
|
+
)
|
|
351
|
+
|
|
352
|
+
# save the updated workbook
|
|
353
|
+
wb.save(output_name)
|
|
354
|
+
|
|
355
|
+
logger.info(
|
|
356
|
+
"%s has been created with %i update(s). %i row(s) were skipped because of missing controls in SSP #%i.",
|
|
357
|
+
output_name.name,
|
|
358
|
+
update_counter,
|
|
359
|
+
skipped_counter,
|
|
360
|
+
ssp_id,
|
|
361
|
+
)
|
|
362
|
+
# return the output path
|
|
363
|
+
return output_name
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
def determine_assessment_result(assessment: dict) -> str:
|
|
367
|
+
"""
|
|
368
|
+
Determine the assessment result based on the assessment data
|
|
369
|
+
|
|
370
|
+
:param dict assessment: Assessment data
|
|
371
|
+
:return: Assessment result
|
|
372
|
+
:rtype: str
|
|
373
|
+
"""
|
|
374
|
+
if assessment["assessmentResult"] == "Pass":
|
|
375
|
+
return "Compliant"
|
|
376
|
+
elif assessment["assessmentResult"] in ["Fail", "Partial Pass"]:
|
|
377
|
+
return "Non-Compliant"
|
|
378
|
+
else:
|
|
379
|
+
return "Not Applicable"
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
def map_finish_date(
|
|
383
|
+
assessment: dict,
|
|
384
|
+
sheet: Any,
|
|
385
|
+
row_number: int,
|
|
386
|
+
author: str,
|
|
387
|
+
yellow_fill: PatternFill,
|
|
388
|
+
) -> None:
|
|
389
|
+
"""
|
|
390
|
+
Map the finish date of the assessment
|
|
391
|
+
|
|
392
|
+
:param dict assessment: Assessment data
|
|
393
|
+
:param Any sheet: Excel sheet object
|
|
394
|
+
:param int row_number: Row number
|
|
395
|
+
:param str author: Author of the comment
|
|
396
|
+
:param PatternFill yellow_fill: Yellow fill object
|
|
397
|
+
:rtype: None
|
|
398
|
+
"""
|
|
399
|
+
finish_date = reformat_str_date(assessment["actualFinish"], "%d-%b-%Y") if assessment["actualFinish"] else None
|
|
400
|
+
|
|
401
|
+
# map the control to the Excel spreadsheet
|
|
402
|
+
sheet[f"M{row_number}"] = determine_assessment_result(assessment)
|
|
403
|
+
if finish_date:
|
|
404
|
+
sheet[f"N{row_number}"] = finish_date
|
|
405
|
+
else:
|
|
406
|
+
sheet[f"N{row_number}"].comment = Comment(
|
|
407
|
+
text=f"Assessment #{assessment['id']} in RegScale doesn't have a finish date.",
|
|
408
|
+
author=author,
|
|
409
|
+
height=150,
|
|
410
|
+
)
|
|
411
|
+
sheet[f"N{row_number}"].fill = yellow_fill
|