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,632 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""Module to allow user to make changes to issues in an excel spreadsheet for user friendly experience"""
|
|
4
|
+
|
|
5
|
+
# standard python imports
|
|
6
|
+
import os
|
|
7
|
+
import shutil
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
import click
|
|
11
|
+
from openpyxl import Workbook, load_workbook
|
|
12
|
+
from openpyxl.styles import Protection, NamedStyle
|
|
13
|
+
from openpyxl.worksheet.datavalidation import DataValidation
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from rich.console import Console
|
|
16
|
+
from rich.table import Table
|
|
17
|
+
|
|
18
|
+
from regscale.core.app.logz import create_logger
|
|
19
|
+
from regscale.core.app.utils.app_utils import (
|
|
20
|
+
check_file_path,
|
|
21
|
+
error_and_exit,
|
|
22
|
+
reformat_str_date,
|
|
23
|
+
get_current_datetime,
|
|
24
|
+
get_user_names,
|
|
25
|
+
check_empty_nan,
|
|
26
|
+
)
|
|
27
|
+
from regscale.models.app_models.click import regscale_id, regscale_module
|
|
28
|
+
from regscale.models.regscale_models.issue import Issue
|
|
29
|
+
|
|
30
|
+
logger = create_logger()
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@click.group(name="issues")
|
|
34
|
+
def issues():
|
|
35
|
+
"""
|
|
36
|
+
Performs actions on POAM CLI Feature to update issues to RegScale.
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@issues.command(name="generate")
|
|
41
|
+
@regscale_id()
|
|
42
|
+
@regscale_module()
|
|
43
|
+
@click.option(
|
|
44
|
+
"--path",
|
|
45
|
+
type=click.Path(exists=False, dir_okay=True, path_type=Path),
|
|
46
|
+
help="Provide the desired path for excel files to be generated into.",
|
|
47
|
+
default=os.path.join(os.getcwd(), "artifacts"),
|
|
48
|
+
required=True,
|
|
49
|
+
)
|
|
50
|
+
def generate_all_issues(regscale_id: int, regscale_module: str, path: Path):
|
|
51
|
+
"""
|
|
52
|
+
This function will build and populate a spreadsheet of all issues
|
|
53
|
+
with the selected RegScale Parent Id and RegScale Module for users to make any neccessary edits.
|
|
54
|
+
|
|
55
|
+
"""
|
|
56
|
+
all_issues(regscale_id=regscale_id, regscale_module=regscale_module, path=path)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def all_issues(regscale_id: int, regscale_module: str, path: Path) -> None:
|
|
60
|
+
"""Function to build excel spreadsheet with all issues matching organizer records given.
|
|
61
|
+
|
|
62
|
+
:param int regscale_id: RegScale Parent Id
|
|
63
|
+
:param str regscale_module: RegScale Parent Module
|
|
64
|
+
:param Path path: directory of file location
|
|
65
|
+
:rtype: None
|
|
66
|
+
"""
|
|
67
|
+
# see if provided RegScale Module is an accepted option in Organizer Modules list
|
|
68
|
+
import pandas as pd # Optimize import performance
|
|
69
|
+
from regscale.core.app.api import Api
|
|
70
|
+
|
|
71
|
+
api = Api()
|
|
72
|
+
verify_organizer_module(regscale_module)
|
|
73
|
+
|
|
74
|
+
body = """
|
|
75
|
+
query {
|
|
76
|
+
issues (skip: 0, take: 50, where: {parentId: {eq: parent_id} parentModule: {eq: "parent_module"}}) {
|
|
77
|
+
items {
|
|
78
|
+
id
|
|
79
|
+
issueOwnerId
|
|
80
|
+
issueOwner {
|
|
81
|
+
firstName
|
|
82
|
+
lastName
|
|
83
|
+
userName
|
|
84
|
+
}
|
|
85
|
+
title
|
|
86
|
+
dateCreated
|
|
87
|
+
description
|
|
88
|
+
severityLevel
|
|
89
|
+
costEstimate
|
|
90
|
+
levelOfEffort
|
|
91
|
+
dueDate
|
|
92
|
+
identification
|
|
93
|
+
status
|
|
94
|
+
dateCompleted
|
|
95
|
+
activitiesObserved
|
|
96
|
+
failuresObserved
|
|
97
|
+
requirementsViolated
|
|
98
|
+
safetyImpact
|
|
99
|
+
securityImpact
|
|
100
|
+
qualityImpact
|
|
101
|
+
securityChecks
|
|
102
|
+
recommendedActions
|
|
103
|
+
parentId
|
|
104
|
+
parentModule
|
|
105
|
+
}
|
|
106
|
+
totalCount
|
|
107
|
+
pageInfo {
|
|
108
|
+
hasNextPage
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
""".replace(
|
|
113
|
+
"parent_module", regscale_module
|
|
114
|
+
).replace(
|
|
115
|
+
"parent_id", str(regscale_id)
|
|
116
|
+
)
|
|
117
|
+
existing_issue_data = api.graph(query=body)
|
|
118
|
+
|
|
119
|
+
if (
|
|
120
|
+
existing_issue_data["issues"]["totalCount"] > 0
|
|
121
|
+
): # Checking to see if assessment exists for selected RegScale Id and RegScale Module.
|
|
122
|
+
check_file_path(path)
|
|
123
|
+
|
|
124
|
+
# Loading data from db into two workbooks.
|
|
125
|
+
|
|
126
|
+
workbook = Workbook()
|
|
127
|
+
worksheet = workbook.active
|
|
128
|
+
worksheet.title = f"Issues({regscale_id}_{regscale_module})"
|
|
129
|
+
workbook.save(filename=os.path.join(path, "all_issues.xlsx"))
|
|
130
|
+
shutil.copy(
|
|
131
|
+
os.path.join(path, "all_issues.xlsx"),
|
|
132
|
+
os.path.join(path, "old_issues.xlsx"),
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
raw_data = existing_issue_data["issues"]["items"]
|
|
136
|
+
issues_data = []
|
|
137
|
+
for a in raw_data:
|
|
138
|
+
issue_id = a["id"]
|
|
139
|
+
issue_owner = (
|
|
140
|
+
(
|
|
141
|
+
str(a["issueOwner"]["lastName"]).strip()
|
|
142
|
+
+ ", "
|
|
143
|
+
+ str(a["issueOwner"]["firstName"]).strip()
|
|
144
|
+
+ " ("
|
|
145
|
+
+ str(a["issueOwner"]["userName"]).strip()
|
|
146
|
+
+ ")"
|
|
147
|
+
)
|
|
148
|
+
if a["issueOwner"]
|
|
149
|
+
else "None"
|
|
150
|
+
)
|
|
151
|
+
title = a["title"]
|
|
152
|
+
date_created = reformat_str_date(a["dateCreated"])
|
|
153
|
+
description = a["description"] if a["description"] else "None"
|
|
154
|
+
severity_level = a["severityLevel"]
|
|
155
|
+
cost_estimate = a["costEstimate"] if a["costEstimate"] and a["costEstimate"] != "None" else 0.00
|
|
156
|
+
level_of_effort = a["levelOfEffort"] if a["levelOfEffort"] and a["levelOfEffort"] != "None" else 0
|
|
157
|
+
due_date = reformat_str_date(a["dueDate"])
|
|
158
|
+
identification = a["identification"] if a["identification"] else "None"
|
|
159
|
+
status = a["status"] if a["status"] else "None"
|
|
160
|
+
date_completed = reformat_str_date(a["dateCompleted"]) if a["dateCompleted"] else ""
|
|
161
|
+
activities_observed = a["activitiesObserved"] or ""
|
|
162
|
+
failures_observed = a["failuresObserved"] or ""
|
|
163
|
+
requirements_violated = a["requirementsViolated"] or ""
|
|
164
|
+
safety_impact = a["safetyImpact"] or ""
|
|
165
|
+
security_impact = a["securityImpact"] or ""
|
|
166
|
+
quality_impact = a["qualityImpact"] or ""
|
|
167
|
+
security_checks = a["securityChecks"] or ""
|
|
168
|
+
recommended_actions = a["recommendedActions"] or ""
|
|
169
|
+
issues_data.append(
|
|
170
|
+
[
|
|
171
|
+
issue_id,
|
|
172
|
+
issue_owner,
|
|
173
|
+
title,
|
|
174
|
+
date_created,
|
|
175
|
+
description,
|
|
176
|
+
severity_level,
|
|
177
|
+
cost_estimate,
|
|
178
|
+
level_of_effort,
|
|
179
|
+
due_date,
|
|
180
|
+
identification,
|
|
181
|
+
status,
|
|
182
|
+
date_completed,
|
|
183
|
+
activities_observed,
|
|
184
|
+
failures_observed,
|
|
185
|
+
requirements_violated,
|
|
186
|
+
safety_impact,
|
|
187
|
+
security_impact,
|
|
188
|
+
quality_impact,
|
|
189
|
+
security_checks,
|
|
190
|
+
recommended_actions,
|
|
191
|
+
]
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
all_ass_df = pd.DataFrame(
|
|
195
|
+
issues_data,
|
|
196
|
+
columns=[
|
|
197
|
+
"Id",
|
|
198
|
+
"IssueOwner",
|
|
199
|
+
"Title",
|
|
200
|
+
"DateCreated",
|
|
201
|
+
"Description",
|
|
202
|
+
"SeverityLevel",
|
|
203
|
+
"CostEstimate",
|
|
204
|
+
"LevelOfEffort",
|
|
205
|
+
"DueDate",
|
|
206
|
+
"Identification",
|
|
207
|
+
"Status",
|
|
208
|
+
"DateCompleted",
|
|
209
|
+
"ActivitiesObserved",
|
|
210
|
+
"FailuresObserved",
|
|
211
|
+
"RequirementsViolated",
|
|
212
|
+
"SafetyImpact",
|
|
213
|
+
"SecurityImpact",
|
|
214
|
+
"QualityImpact",
|
|
215
|
+
"SecurityChecks",
|
|
216
|
+
"RecommendedActions",
|
|
217
|
+
],
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
with pd.ExcelWriter(
|
|
221
|
+
os.path.join(path, "all_issues.xlsx"),
|
|
222
|
+
mode="a",
|
|
223
|
+
engine="openpyxl",
|
|
224
|
+
if_sheet_exists="overlay",
|
|
225
|
+
) as writer:
|
|
226
|
+
all_ass_df.to_excel(
|
|
227
|
+
writer,
|
|
228
|
+
sheet_name=f"Issues({regscale_id}_{regscale_module})",
|
|
229
|
+
index=False,
|
|
230
|
+
)
|
|
231
|
+
with pd.ExcelWriter(
|
|
232
|
+
os.path.join(path, "old_issues.xlsx"),
|
|
233
|
+
mode="a",
|
|
234
|
+
engine="openpyxl",
|
|
235
|
+
if_sheet_exists="overlay",
|
|
236
|
+
) as writer:
|
|
237
|
+
all_ass_df.to_excel(
|
|
238
|
+
writer,
|
|
239
|
+
sheet_name=f"Issues({regscale_id}_{regscale_module})",
|
|
240
|
+
index=False,
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
# Pulling in Account Users into Excel Spreasheet to create drop down.
|
|
244
|
+
|
|
245
|
+
with pd.ExcelWriter(
|
|
246
|
+
os.path.join(path, "all_issues.xlsx"),
|
|
247
|
+
mode="a",
|
|
248
|
+
engine="openpyxl",
|
|
249
|
+
if_sheet_exists="overlay",
|
|
250
|
+
) as writer:
|
|
251
|
+
get_user_names().to_excel(
|
|
252
|
+
writer,
|
|
253
|
+
sheet_name="Accounts",
|
|
254
|
+
index=False,
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
# Pulling in Identifications into separate Excel Spreadsheet to create drop down. (Over 256 character Limit)
|
|
258
|
+
|
|
259
|
+
identification_list = [
|
|
260
|
+
"A-123 Review",
|
|
261
|
+
"Assessment/Audit (External)",
|
|
262
|
+
"Assessment/Audit (Internal)",
|
|
263
|
+
"Critical Control Review",
|
|
264
|
+
"FDCC/USGCB",
|
|
265
|
+
"GAO Audit",
|
|
266
|
+
"IG Audit",
|
|
267
|
+
"Incidnet Response Lessons Learned",
|
|
268
|
+
"ITAR",
|
|
269
|
+
"Other",
|
|
270
|
+
"Penetration Test",
|
|
271
|
+
"Risk Assessment",
|
|
272
|
+
"Security Authorization",
|
|
273
|
+
"Security Control Assessment",
|
|
274
|
+
"Vulnerability Assessment",
|
|
275
|
+
]
|
|
276
|
+
|
|
277
|
+
identifications = pd.DataFrame({"IdentificationOptions": identification_list})
|
|
278
|
+
|
|
279
|
+
with pd.ExcelWriter(
|
|
280
|
+
os.path.join(path, "all_issues.xlsx"),
|
|
281
|
+
mode="a",
|
|
282
|
+
engine="openpyxl",
|
|
283
|
+
if_sheet_exists="overlay",
|
|
284
|
+
) as writer:
|
|
285
|
+
identifications.to_excel(
|
|
286
|
+
writer,
|
|
287
|
+
sheet_name="Identifications",
|
|
288
|
+
index=False,
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
# Adding protection to "old_issues.xlsx" file that will be used as reference.
|
|
292
|
+
|
|
293
|
+
workbook2 = load_workbook(os.path.join(path, "old_issues.xlsx"))
|
|
294
|
+
worksheet2 = workbook2.active
|
|
295
|
+
worksheet2.protection.sheet = True
|
|
296
|
+
workbook2.save(filename=os.path.join(path, "old_issues.xlsx"))
|
|
297
|
+
|
|
298
|
+
# Adding Data Validation to "all_issues.xlsx" file to be adjusted internally.
|
|
299
|
+
|
|
300
|
+
workbook = load_workbook(os.path.join(path, "all_issues.xlsx"))
|
|
301
|
+
worksheet = workbook.active
|
|
302
|
+
accounts_worksheet = workbook["Accounts"]
|
|
303
|
+
identifications_worksheet = workbook["Identifications"]
|
|
304
|
+
|
|
305
|
+
accounts_worksheet.protection.sheet = True
|
|
306
|
+
worksheet.protection.sheet = True
|
|
307
|
+
identifications_worksheet.protection.sheet = True
|
|
308
|
+
|
|
309
|
+
# Adding DropDown Menu to Columns to Match RegScale options for fields
|
|
310
|
+
|
|
311
|
+
severitylevels = '"I - High - Signficant Deficiency, II - Moderate - Reportable Condition, III - Low - Other Weakness, IV - Not Asssigned"'
|
|
312
|
+
statuses = '"Closed, Draft, Open, Pending Decommission, Supply Chain/Procurement Dependency, Vendor Dependency for Fix, Delayed, Cancelled, Exception/Waiver"'
|
|
313
|
+
|
|
314
|
+
dv1 = DataValidation(
|
|
315
|
+
type="list",
|
|
316
|
+
formula1="=Accounts!$A$2:$A$" + str(get_maximum_rows(sheet_object=workbook["Accounts"])),
|
|
317
|
+
allow_blank=False,
|
|
318
|
+
showDropDown=False,
|
|
319
|
+
error="Your entry is not one of the available options",
|
|
320
|
+
errorTitle="Invalid Entry",
|
|
321
|
+
prompt="Please select from the list",
|
|
322
|
+
)
|
|
323
|
+
dv2 = DataValidation(
|
|
324
|
+
type="list",
|
|
325
|
+
formula1=severitylevels,
|
|
326
|
+
allow_blank=False,
|
|
327
|
+
showDropDown=False,
|
|
328
|
+
error="Your entry is not one of the available options",
|
|
329
|
+
errorTitle="Invalid Entry",
|
|
330
|
+
prompt="Please select from the list",
|
|
331
|
+
)
|
|
332
|
+
dv3 = DataValidation(
|
|
333
|
+
type="list",
|
|
334
|
+
formula1=statuses,
|
|
335
|
+
allow_blank=True,
|
|
336
|
+
showDropDown=False,
|
|
337
|
+
error="Your entry is not one of the available options",
|
|
338
|
+
errorTitle="Invalid Entry",
|
|
339
|
+
prompt="Please select from the list",
|
|
340
|
+
)
|
|
341
|
+
dv4 = DataValidation(
|
|
342
|
+
type="list",
|
|
343
|
+
formula1="=Identifications!$A$2:$A$" + str(get_maximum_rows(sheet_object=workbook["Identifications"])),
|
|
344
|
+
allow_blank=False,
|
|
345
|
+
showDropDown=False,
|
|
346
|
+
error="Your entry is not one of the available options",
|
|
347
|
+
errorTitle="Invalid Entry",
|
|
348
|
+
prompt="Please select from the list",
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
# Adding Date Style to Worksheet
|
|
352
|
+
|
|
353
|
+
date_style = NamedStyle(name="date_style", number_format="mm/dd/yyyy")
|
|
354
|
+
workbook.add_named_style(date_style)
|
|
355
|
+
currency = '"$"* #,##0.00_);("$"* #,##0.00);"$"* #,##0.00_);'
|
|
356
|
+
|
|
357
|
+
for col in ["D", "G", "I", "L"]:
|
|
358
|
+
for cell in worksheet[col]:
|
|
359
|
+
if col != "G" and cell.row > 1:
|
|
360
|
+
cell.style = date_style
|
|
361
|
+
elif col == "G" and cell.row > 1:
|
|
362
|
+
cell.number_format = currency
|
|
363
|
+
|
|
364
|
+
# Adding data validation to avoid manual error on entry columns
|
|
365
|
+
|
|
366
|
+
dv5 = DataValidation(
|
|
367
|
+
type="date",
|
|
368
|
+
allow_blank=False,
|
|
369
|
+
showErrorMessage=True,
|
|
370
|
+
showInputMessage=True,
|
|
371
|
+
showDropDown=False,
|
|
372
|
+
error="Your entry is not a valid option",
|
|
373
|
+
errorTitle="Invalid Entry",
|
|
374
|
+
prompt="Please enter valid date mm/dd/yyyy",
|
|
375
|
+
)
|
|
376
|
+
dv6 = DataValidation(
|
|
377
|
+
type="date",
|
|
378
|
+
allow_blank=True,
|
|
379
|
+
showErrorMessage=True,
|
|
380
|
+
showInputMessage=True,
|
|
381
|
+
showDropDown=False,
|
|
382
|
+
error="Your entry is not a valid option",
|
|
383
|
+
errorTitle="Invalid Entry",
|
|
384
|
+
prompt="Please enter valid date mm/dd/yyyy",
|
|
385
|
+
)
|
|
386
|
+
dv7 = DataValidation(
|
|
387
|
+
type="whole",
|
|
388
|
+
operator="greaterThanOrEqual",
|
|
389
|
+
formula1=0,
|
|
390
|
+
allow_blank=False,
|
|
391
|
+
showErrorMessage=True,
|
|
392
|
+
showInputMessage=True,
|
|
393
|
+
showDropDown=False,
|
|
394
|
+
error="Your entry is not a valid option",
|
|
395
|
+
errorTitle="Invalid Entry",
|
|
396
|
+
prompt="Please enter valid whole number denoting number of hours.",
|
|
397
|
+
)
|
|
398
|
+
worksheet.add_data_validation(dv1)
|
|
399
|
+
worksheet.add_data_validation(dv2)
|
|
400
|
+
worksheet.add_data_validation(dv3)
|
|
401
|
+
worksheet.add_data_validation(dv4)
|
|
402
|
+
worksheet.add_data_validation(dv5)
|
|
403
|
+
worksheet.add_data_validation(dv6)
|
|
404
|
+
worksheet.add_data_validation(dv7)
|
|
405
|
+
dv1.add("B2:B1048576")
|
|
406
|
+
dv2.add("F2:F1048576")
|
|
407
|
+
dv3.add("K2:K1048576")
|
|
408
|
+
dv4.add("J2:J1048576")
|
|
409
|
+
dv5.add("I2:I1048576")
|
|
410
|
+
dv6.add("D2:D1048576")
|
|
411
|
+
dv6.add("L2:L1048576")
|
|
412
|
+
dv7.add("H2:H1048576")
|
|
413
|
+
|
|
414
|
+
for col in worksheet.columns:
|
|
415
|
+
max_length = 0
|
|
416
|
+
column = col[0].column_letter # Get the column name
|
|
417
|
+
for cell in col:
|
|
418
|
+
if len(str(cell.value)) > max_length:
|
|
419
|
+
max_length = len(str(cell.value))
|
|
420
|
+
|
|
421
|
+
adjusted_width = (max_length + 2) * 1.2
|
|
422
|
+
worksheet.column_dimensions[column].width = adjusted_width
|
|
423
|
+
|
|
424
|
+
# Unlocking cells that can be edited in each Issue.
|
|
425
|
+
|
|
426
|
+
for col in [
|
|
427
|
+
"B",
|
|
428
|
+
"E",
|
|
429
|
+
"F",
|
|
430
|
+
"G",
|
|
431
|
+
"H",
|
|
432
|
+
"I",
|
|
433
|
+
"J",
|
|
434
|
+
"K",
|
|
435
|
+
"L",
|
|
436
|
+
"M",
|
|
437
|
+
"N",
|
|
438
|
+
"O",
|
|
439
|
+
"P",
|
|
440
|
+
"Q",
|
|
441
|
+
"R",
|
|
442
|
+
"S",
|
|
443
|
+
"T",
|
|
444
|
+
]: # Columns to edit.
|
|
445
|
+
for cell in worksheet[col]:
|
|
446
|
+
cell.protection = Protection(locked=False)
|
|
447
|
+
|
|
448
|
+
workbook.save(filename=os.path.join(path, "all_issues.xlsx"))
|
|
449
|
+
|
|
450
|
+
else:
|
|
451
|
+
logger.info("No Issues exist. Please check your selections for RegScale Id and RegScale Module and try again.")
|
|
452
|
+
error_and_exit("There was an error creating your workbook for the given RegScale Id and RegScale Module.")
|
|
453
|
+
|
|
454
|
+
logger.info(
|
|
455
|
+
"Your data has beeen loaded. Please open the all_issues workbook and make your desired changes %s. " % path
|
|
456
|
+
)
|
|
457
|
+
return None
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
@issues.command(name="load")
|
|
461
|
+
@click.option(
|
|
462
|
+
"--path",
|
|
463
|
+
type=click.Path(exists=False, dir_okay=True, path_type=Path),
|
|
464
|
+
help="Provide the desired path of excel workbook locations.",
|
|
465
|
+
default=os.path.join(os.getcwd(), "artifacts"),
|
|
466
|
+
required=True,
|
|
467
|
+
)
|
|
468
|
+
def generate_upload_data(path: Path):
|
|
469
|
+
"""This function uploads updated issues to the RegScale from the Excel files that users have edited."""
|
|
470
|
+
upload_data(path)
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
def upload_data(path: Path) -> None:
|
|
474
|
+
"""
|
|
475
|
+
This function uploads updated issues to the RegScale.
|
|
476
|
+
|
|
477
|
+
:param Path path: directory of file location
|
|
478
|
+
:rtype: None
|
|
479
|
+
"""
|
|
480
|
+
import pandas as pd # Optimize import performance
|
|
481
|
+
import numpy as np # Optimize import performance
|
|
482
|
+
|
|
483
|
+
# Checking all_issues file for differences before updating database
|
|
484
|
+
workbook = load_workbook(os.path.join(path, "all_issues.xlsx"))
|
|
485
|
+
sheet_name = workbook.sheetnames[0]
|
|
486
|
+
sheet_name = sheet_name[sheet_name.find("(") + 1 : sheet_name.find(")")].split("_")
|
|
487
|
+
|
|
488
|
+
# set the variables to the correct values
|
|
489
|
+
for item in set(sheet_name):
|
|
490
|
+
try:
|
|
491
|
+
regscale_parent_id = int(item)
|
|
492
|
+
except ValueError:
|
|
493
|
+
regscale_module = item
|
|
494
|
+
|
|
495
|
+
df1 = pd.read_excel(os.path.join(path, "old_issues.xlsx"), sheet_name=0, index_col="Id")
|
|
496
|
+
|
|
497
|
+
df2 = pd.read_excel(os.path.join(path, "all_issues.xlsx"), sheet_name=0, index_col="Id")
|
|
498
|
+
|
|
499
|
+
if df1.equals(df2):
|
|
500
|
+
logger.info("No differences detected.")
|
|
501
|
+
error_and_exit("No changes were made to the all_issues.xlsx file. Thank you!")
|
|
502
|
+
else:
|
|
503
|
+
logger.warning("*** WARNING *** Differences Found")
|
|
504
|
+
|
|
505
|
+
diff_mask = (df1 != df2) & ~(df1.isnull() & df2.isnull())
|
|
506
|
+
ne_stacked = diff_mask.stack()
|
|
507
|
+
changed = ne_stacked[ne_stacked]
|
|
508
|
+
changed.index.names = ["Id", "Column"]
|
|
509
|
+
difference_locations = np.where(diff_mask)
|
|
510
|
+
changed_to = df1.values[difference_locations]
|
|
511
|
+
changed_from = df2.values[difference_locations]
|
|
512
|
+
changes = pd.DataFrame({"From": changed_from, "To": changed_to}, index=changed.index)
|
|
513
|
+
changes.to_csv(
|
|
514
|
+
os.path.join(path, "differences.txt"),
|
|
515
|
+
header=True,
|
|
516
|
+
index=True,
|
|
517
|
+
sep=" ",
|
|
518
|
+
mode="a",
|
|
519
|
+
)
|
|
520
|
+
|
|
521
|
+
diff = pd.read_csv(os.path.join(path, "differences.txt"), header=0, sep=" ", index_col=None)
|
|
522
|
+
ids = []
|
|
523
|
+
for i, row in diff.iterrows():
|
|
524
|
+
ids.append(row["Id"])
|
|
525
|
+
|
|
526
|
+
id_df = pd.DataFrame(ids, index=None, columns=["Id"])
|
|
527
|
+
id_df2 = id_df.drop_duplicates()
|
|
528
|
+
updated_file = os.path.join(path, "all_issues.xlsx")
|
|
529
|
+
|
|
530
|
+
reader = pd.read_excel(updated_file)
|
|
531
|
+
updated = reader[reader["Id"].isin(id_df2["Id"])]
|
|
532
|
+
|
|
533
|
+
accounts = pd.read_excel(updated_file, sheet_name="Accounts")
|
|
534
|
+
accounts = accounts.rename(columns={"User": "IssueOwner", "UserId": "IssueOwnerId"})
|
|
535
|
+
updated = updated.merge(accounts, how="left", on="IssueOwner")
|
|
536
|
+
updated = updated.T.to_dict()
|
|
537
|
+
updated_issues = [
|
|
538
|
+
Issue(
|
|
539
|
+
id=value["Id"],
|
|
540
|
+
issueOwnerId=value["IssueOwnerId"],
|
|
541
|
+
title=value["Title"],
|
|
542
|
+
dateCreated=value["DateCreated"],
|
|
543
|
+
description=value["Description"],
|
|
544
|
+
severityLevel=value["SeverityLevel"],
|
|
545
|
+
costEstimate=value["CostEstimate"],
|
|
546
|
+
levelOfEffort=value["LevelOfEffort"],
|
|
547
|
+
dueDate=value["DueDate"],
|
|
548
|
+
identification=check_empty_nan(value["Identification"], "Other"),
|
|
549
|
+
status=value["Status"],
|
|
550
|
+
dateCompleted=check_empty_nan(value["DateCompleted"], ""),
|
|
551
|
+
activitiesObserved=check_empty_nan(value["ActivitiesObserved"]),
|
|
552
|
+
failuresObserved=check_empty_nan(value["FailuresObserved"]),
|
|
553
|
+
requirementsViolated=check_empty_nan(value["RequirementsViolated"]),
|
|
554
|
+
safetyImpact=check_empty_nan(value["SafetyImpact"]),
|
|
555
|
+
securityImpact=check_empty_nan(value["SecurityImpact"]),
|
|
556
|
+
qualityImpact=check_empty_nan(value["QualityImpact"]),
|
|
557
|
+
securityChecks=check_empty_nan(value["SecurityChecks"]),
|
|
558
|
+
recommendedActions=check_empty_nan(value["RecommendedActions"]),
|
|
559
|
+
dateLastUpdated=get_current_datetime(),
|
|
560
|
+
parentModule=regscale_module,
|
|
561
|
+
parentId=regscale_parent_id,
|
|
562
|
+
)
|
|
563
|
+
for value in updated.values()
|
|
564
|
+
]
|
|
565
|
+
Issue.batch_update(updated_issues)
|
|
566
|
+
logger.info("Changes made to existing files can be seen in differences.txt file. Thank you! %s" % path)
|
|
567
|
+
return None
|
|
568
|
+
|
|
569
|
+
|
|
570
|
+
@issues.command(name="delete_files")
|
|
571
|
+
@click.option(
|
|
572
|
+
"--path",
|
|
573
|
+
type=click.Path(exists=False, dir_okay=True, path_type=Path),
|
|
574
|
+
help="Provide the desired path of excel workbook locations.",
|
|
575
|
+
default=os.path.join(os.getcwd(), "artifacts"),
|
|
576
|
+
required=True,
|
|
577
|
+
)
|
|
578
|
+
def generate_delete_file(path: Path):
|
|
579
|
+
"""This function deletes files used during the POAM Editor process."""
|
|
580
|
+
delete_file(path)
|
|
581
|
+
|
|
582
|
+
|
|
583
|
+
def delete_file(path: Path) -> None:
|
|
584
|
+
"""
|
|
585
|
+
Deletes files used during the process.
|
|
586
|
+
|
|
587
|
+
:param Path path: Path for artifacts folder or location of excel files
|
|
588
|
+
:rtype: None
|
|
589
|
+
"""
|
|
590
|
+
os.remove(os.path.join(path, "all_issues.xlsx"))
|
|
591
|
+
os.remove(os.path.join(path, "old_issues.xlsx"))
|
|
592
|
+
if os.path.isfile(os.path.join(path, "differences.txt")):
|
|
593
|
+
os.remove(os.path.join(path, "differences.txt"))
|
|
594
|
+
else:
|
|
595
|
+
pass
|
|
596
|
+
logger.info("Files have been deleted. Thank you.")
|
|
597
|
+
return None
|
|
598
|
+
|
|
599
|
+
|
|
600
|
+
def get_maximum_rows(*, sheet_object: Any) -> int:
|
|
601
|
+
"""This function finds the last row containing data in a spreadsheet
|
|
602
|
+
|
|
603
|
+
:param Any sheet_object: excel worksheet to be referenced
|
|
604
|
+
:return: integer representing last row with data in spreadsheet
|
|
605
|
+
:rtype: int
|
|
606
|
+
"""
|
|
607
|
+
return sum(any(col.value is not None for col in row) for max_row, row in enumerate(sheet_object, 1))
|
|
608
|
+
|
|
609
|
+
|
|
610
|
+
def verify_organizer_module(module: str) -> None:
|
|
611
|
+
"""
|
|
612
|
+
Function to check the provided module is a valid RegScale Organizer Module and will display the acceptable RegScale modules
|
|
613
|
+
|
|
614
|
+
:param str module: desired module
|
|
615
|
+
:rtype: None
|
|
616
|
+
"""
|
|
617
|
+
|
|
618
|
+
# create console and table objects
|
|
619
|
+
console = Console()
|
|
620
|
+
table = Table("RegScale Module", "Accepted Value", title="RegScale Modules", safe_box=True)
|
|
621
|
+
|
|
622
|
+
# list of RegScaleOrganizer Modules
|
|
623
|
+
organizers = ["components", "policies", "projects", "securityplans", "supplychain"]
|
|
624
|
+
|
|
625
|
+
# iterate through items and add them to table object
|
|
626
|
+
for i in range(len(organizers)):
|
|
627
|
+
table.add_row(organizers[i], organizers[i])
|
|
628
|
+
|
|
629
|
+
if module not in organizers:
|
|
630
|
+
# print the table object in console
|
|
631
|
+
console.print(table)
|
|
632
|
+
error_and_exit("Please provide an option from the Accepted Value column.")
|