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,436 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""Model for Scan in the application"""
|
|
4
|
+
import logging
|
|
5
|
+
import pickle
|
|
6
|
+
import warnings
|
|
7
|
+
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
8
|
+
from datetime import datetime
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import Dict, List, Optional, Tuple, Union
|
|
11
|
+
|
|
12
|
+
from pydantic import ConfigDict, Field
|
|
13
|
+
from requests import JSONDecodeError, RequestException, Response
|
|
14
|
+
|
|
15
|
+
from regscale.core.app.api import Api
|
|
16
|
+
from regscale.core.app.application import Application
|
|
17
|
+
from regscale.core.app.utils.app_utils import (
|
|
18
|
+
convert_datetime_to_regscale_string,
|
|
19
|
+
create_progress_object,
|
|
20
|
+
get_current_datetime,
|
|
21
|
+
)
|
|
22
|
+
from regscale.core.utils.date import normalize_date
|
|
23
|
+
from regscale.models.regscale_models.regscale_model import RegScaleModel
|
|
24
|
+
|
|
25
|
+
logger = logging.getLogger("regscale")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class ScanHistory(RegScaleModel):
|
|
29
|
+
"""Model for ScanHistory in the application"""
|
|
30
|
+
|
|
31
|
+
_module_slug = "scanhistory"
|
|
32
|
+
_unique_fields = [
|
|
33
|
+
["scanningTool", "parentId", "parentModule"],
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
id: int = 0
|
|
37
|
+
scanningTool: str
|
|
38
|
+
dateCreated: str = Field(default_factory=get_current_datetime)
|
|
39
|
+
dateLastUpdated: str = Field(default_factory=get_current_datetime)
|
|
40
|
+
createdById: str = Field(default_factory=RegScaleModel.get_user_id)
|
|
41
|
+
lastUpdatedById: str = Field(default_factory=RegScaleModel.get_user_id)
|
|
42
|
+
tenantsId: int = 1
|
|
43
|
+
uuid: Optional[str] = None
|
|
44
|
+
sicuraId: Optional[str] = None
|
|
45
|
+
tenableId: Optional[str] = None
|
|
46
|
+
scanDate: Optional[str] = None
|
|
47
|
+
scannedIPs: Optional[int] = None
|
|
48
|
+
checks: Optional[int] = None
|
|
49
|
+
vInfo: Optional[int] = None
|
|
50
|
+
vLow: int = 0
|
|
51
|
+
vMedium: int = 0
|
|
52
|
+
vHigh: int = 0
|
|
53
|
+
vCritical: int = 0
|
|
54
|
+
parentId: Optional[int] = None
|
|
55
|
+
parentModule: Optional[str] = None
|
|
56
|
+
isPublic: bool = True
|
|
57
|
+
|
|
58
|
+
@staticmethod
|
|
59
|
+
def _get_additional_endpoints() -> ConfigDict:
|
|
60
|
+
"""
|
|
61
|
+
Get additional endpoints for the ScanHistory model, using {model_slug} as a placeholder for the model slug.
|
|
62
|
+
|
|
63
|
+
:return: A dictionary of additional endpoints
|
|
64
|
+
:rtype: ConfigDict
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
return ConfigDict( # type: ignore
|
|
68
|
+
get_by_parent_recursive="/api/{model_slug}/getAllByParentRecursive/{intParentID}/{strModule}/{filterDate}",
|
|
69
|
+
get_all_by_parent="/api/{model_slug}/getAllByParent/{intParentID}/{strModule}",
|
|
70
|
+
get_count="/api/{model_slug}/getCount",
|
|
71
|
+
get_scan_dates_by_parent="/api/{model_slug}/getScanDatesByParent/{intID}/{strModule}",
|
|
72
|
+
filter_scans="/api/{model_slug}/filterScans/{intID}/{strModule}/{intPage}/{intPageSize}",
|
|
73
|
+
insert="/api/{model_slug}",
|
|
74
|
+
update="/api/{model_slug}",
|
|
75
|
+
batch_create="/api/{model_slug}/batchCreate",
|
|
76
|
+
get="/api/{model_slug}/find/{id}",
|
|
77
|
+
find_by_guid="/api/{model_slug}/findByGUID/{strGUID}",
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
@classmethod
|
|
81
|
+
def get_by_parent_recursive(cls, parent_id: int, parent_module: str, filter_date: str = "") -> List["ScanHistory"]:
|
|
82
|
+
"""
|
|
83
|
+
Get a list of control implementations by plan ID.
|
|
84
|
+
|
|
85
|
+
:param int parent_id: Parent ID
|
|
86
|
+
:param str parent_module: Parent Module
|
|
87
|
+
:param str filter_date: Filter Date
|
|
88
|
+
:return: A list of ScanHistory objects
|
|
89
|
+
:rtype: List[ScanHistory]
|
|
90
|
+
:raises RequestException: If the API request fails
|
|
91
|
+
"""
|
|
92
|
+
endpoint = cls.get_endpoint("get_by_parent_recursive").format(
|
|
93
|
+
model_slug=cls._module_slug, intParentID=parent_id, strModule=parent_module, filterDate=filter_date
|
|
94
|
+
)
|
|
95
|
+
logger.debug(f"Endpoint: {endpoint}")
|
|
96
|
+
response = cls._get_api_handler().get(endpoint=endpoint)
|
|
97
|
+
logger.debug(f"Response: {response.status_code}")
|
|
98
|
+
if response and response.ok:
|
|
99
|
+
return [cls(**ci) for ci in response.json()]
|
|
100
|
+
else:
|
|
101
|
+
raise RequestException(f"API request failed with status code {response.status_code}")
|
|
102
|
+
|
|
103
|
+
def __hash__(self) -> int:
|
|
104
|
+
"""
|
|
105
|
+
Hash items in Scan class
|
|
106
|
+
|
|
107
|
+
:return: Hashed Scan
|
|
108
|
+
:rtype: int
|
|
109
|
+
"""
|
|
110
|
+
fmt = "%Y-%m-%dT%H:%M:%S"
|
|
111
|
+
return hash(
|
|
112
|
+
(
|
|
113
|
+
self.tenableId,
|
|
114
|
+
self.parentId,
|
|
115
|
+
self.parentModule,
|
|
116
|
+
normalize_date(self.scanDate, fmt),
|
|
117
|
+
)
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
def __eq__(self, other: Union["ScanHistory", dict]) -> bool:
|
|
121
|
+
"""
|
|
122
|
+
Compare two Scan objects for equality.
|
|
123
|
+
|
|
124
|
+
:param other: Other Scan object or dictionary to compare
|
|
125
|
+
:type other: Union["ScanHistory", dict]
|
|
126
|
+
:return: True if equal, False otherwise
|
|
127
|
+
:rtype: bool
|
|
128
|
+
"""
|
|
129
|
+
fmt = "%Y-%m-%dT%H:%M:%S"
|
|
130
|
+
if isinstance(other, ScanHistory):
|
|
131
|
+
return (
|
|
132
|
+
self.tenableId == other.tenableId
|
|
133
|
+
and self.parentId == other.parentId
|
|
134
|
+
and self.parentModule == other.parentModule
|
|
135
|
+
and normalize_date(self.scanDate, fmt) == normalize_date(other.scanDate, fmt)
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
return (
|
|
139
|
+
self.tenableId == other["tenableId"]
|
|
140
|
+
and self.parentId == other["parentId"]
|
|
141
|
+
and self.parentModule == other["parentModule"]
|
|
142
|
+
and normalize_date(self.scanDate, fmt) == normalize_date(other["scanDate"], fmt)
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
@staticmethod
|
|
146
|
+
def post_scan(app: Application, api: Api, scan: "ScanHistory") -> "ScanHistory":
|
|
147
|
+
"""
|
|
148
|
+
Post a Scan to RegScale.
|
|
149
|
+
|
|
150
|
+
:param Application app: Application Instance
|
|
151
|
+
:param Api api: Api Instance
|
|
152
|
+
:param ScanHistory scan: Scan Object
|
|
153
|
+
:return: RegScale Scan
|
|
154
|
+
:rtype: ScanHistory
|
|
155
|
+
"""
|
|
156
|
+
res = api.post(url=app.config["domain"] + "/api/scanhistory", json=scan.dict())
|
|
157
|
+
if res.status_code != 200:
|
|
158
|
+
api.logger.error(res)
|
|
159
|
+
return ScanHistory(**res.json())
|
|
160
|
+
|
|
161
|
+
@staticmethod
|
|
162
|
+
def group_vulns_by_severity(associated_vulns: List[dict]) -> Dict[str, List[dict]]:
|
|
163
|
+
"""
|
|
164
|
+
Groups vulnerabilities by severity
|
|
165
|
+
|
|
166
|
+
:param List[dict] associated_vulns: A list of associated vulnerabilities
|
|
167
|
+
:return: Dictionary of vulnerabilities grouped by severity
|
|
168
|
+
:rtype: Dict[str, List[dict]]
|
|
169
|
+
"""
|
|
170
|
+
return {
|
|
171
|
+
vuln["severity"]: [v for v in associated_vulns if v["severity"] == vuln["severity"]]
|
|
172
|
+
for vuln in associated_vulns
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
@staticmethod
|
|
176
|
+
def get_existing_scan_history(app: Application, reg_asset: dict) -> List[dict]:
|
|
177
|
+
"""
|
|
178
|
+
Gets existing scan history for a RegScale asset
|
|
179
|
+
|
|
180
|
+
:param Application app: Application Instance
|
|
181
|
+
:param dict reg_asset: RegScale Asset
|
|
182
|
+
:return: List of existing scan history
|
|
183
|
+
:rtype: List[dict]
|
|
184
|
+
"""
|
|
185
|
+
api = Api()
|
|
186
|
+
res = api.get(url=app.config["domain"] + f"/api/scanhistory/getAllByParent/{reg_asset.id}/assets")
|
|
187
|
+
if not res.raise_for_status():
|
|
188
|
+
return res.json()
|
|
189
|
+
|
|
190
|
+
@staticmethod
|
|
191
|
+
def create_scan_from_tenable(
|
|
192
|
+
associated_vulns: List[dict], reg_asset: dict, config: dict, tenant_id: int
|
|
193
|
+
) -> "ScanHistory":
|
|
194
|
+
"""
|
|
195
|
+
Creates a Scan object from a Tenable scan
|
|
196
|
+
|
|
197
|
+
:param List[dict] associated_vulns: List of associated vulnerabilities
|
|
198
|
+
:param dict reg_asset: RegScale Asset
|
|
199
|
+
:param dict config: Application Config
|
|
200
|
+
:param int tenant_id: Tenant ID
|
|
201
|
+
:return: Scan object
|
|
202
|
+
:rtype: ScanHistory
|
|
203
|
+
"""
|
|
204
|
+
grouped_vulns = ScanHistory.group_vulns_by_severity(associated_vulns)
|
|
205
|
+
return ScanHistory(
|
|
206
|
+
id=0,
|
|
207
|
+
uuid=associated_vulns[0]["scan"]["uuid"],
|
|
208
|
+
scanningTool="NESSUS",
|
|
209
|
+
tenableId=associated_vulns[0]["scan"]["uuid"],
|
|
210
|
+
scanDate=convert_datetime_to_regscale_string(associated_vulns[0]["scan"]["started_at"]),
|
|
211
|
+
scannedIPs=1,
|
|
212
|
+
checks=len(associated_vulns),
|
|
213
|
+
vInfo=len(grouped_vulns["info"]) if "info" in grouped_vulns else 0,
|
|
214
|
+
vLow=len(grouped_vulns["low"]) if "low" in grouped_vulns else 0,
|
|
215
|
+
vMedium=len(grouped_vulns["medium"]) if "medium" in grouped_vulns else 0,
|
|
216
|
+
vHigh=len(grouped_vulns["high"]) if "high" in grouped_vulns else 0,
|
|
217
|
+
vCritical=(len(grouped_vulns["critical"]) if "critical" in grouped_vulns else 0),
|
|
218
|
+
parentId=reg_asset.id,
|
|
219
|
+
parentModule="assets",
|
|
220
|
+
createdById=config["userId"],
|
|
221
|
+
lastUpdatedById=config["userId"],
|
|
222
|
+
dateCreated=convert_datetime_to_regscale_string(datetime.now()),
|
|
223
|
+
tenantsId=tenant_id,
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
@staticmethod
|
|
227
|
+
def prepare_scan_history_for_sync(
|
|
228
|
+
app: Application,
|
|
229
|
+
nessus_list: List[dict],
|
|
230
|
+
existing_assets: List[dict],
|
|
231
|
+
) -> List["ScanHistory"]:
|
|
232
|
+
"""
|
|
233
|
+
Prepares scan history data for synchronization.
|
|
234
|
+
|
|
235
|
+
:param Application app: The Application object to use for database operations.
|
|
236
|
+
:param List[dict] nessus_list: A list of Nessus scan history data.
|
|
237
|
+
:param List[dict] existing_assets: A list of existing Asset objects to compare against.
|
|
238
|
+
:return: List of scan history objects
|
|
239
|
+
:rtype: List["ScanHistory"]
|
|
240
|
+
"""
|
|
241
|
+
new_scan_history = []
|
|
242
|
+
assets = {asset["asset"]["uuid"] for asset in nessus_list}
|
|
243
|
+
asset_count = 0
|
|
244
|
+
api = Api()
|
|
245
|
+
config = app.config
|
|
246
|
+
tenant_id = api.get(url=api.config["domain"] + "/api/tenants/config").json()["id"]
|
|
247
|
+
|
|
248
|
+
def process_asset(asset: str) -> None:
|
|
249
|
+
"""
|
|
250
|
+
Process an asset from the Nessus scan history data.
|
|
251
|
+
|
|
252
|
+
:param str asset: Asset UUID
|
|
253
|
+
:rtype: None
|
|
254
|
+
"""
|
|
255
|
+
nonlocal asset_count
|
|
256
|
+
asset_count += 1
|
|
257
|
+
if asset_count % 100 == 0:
|
|
258
|
+
app.logger.debug(f"Processing asset {asset_count} of {len(assets)}")
|
|
259
|
+
associated_vulns = [ness for ness in nessus_list if ness["asset"]["uuid"] == asset]
|
|
260
|
+
reg_assets = [reg for reg in existing_assets if reg["tenableId"] == asset]
|
|
261
|
+
if reg_assets:
|
|
262
|
+
reg_asset = reg_assets[0] if reg_assets else None
|
|
263
|
+
existing_scans = ScanHistory.get_existing_scan_history(app, reg_asset)
|
|
264
|
+
scan = ScanHistory.create_scan_from_tenable(associated_vulns, reg_asset, config, tenant_id)
|
|
265
|
+
if scan not in existing_scans:
|
|
266
|
+
new_scan_history.append(scan)
|
|
267
|
+
|
|
268
|
+
with ThreadPoolExecutor(max_workers=30) as executor:
|
|
269
|
+
executor.map(process_asset, assets)
|
|
270
|
+
|
|
271
|
+
return new_scan_history
|
|
272
|
+
|
|
273
|
+
@staticmethod
|
|
274
|
+
def sync_scan_history_to_regscale(
|
|
275
|
+
app: Application,
|
|
276
|
+
new_scan_history: List["ScanHistory"],
|
|
277
|
+
) -> Tuple[List[Response], List["ScanHistory"]]:
|
|
278
|
+
"""
|
|
279
|
+
Synchronizes scan history to RegScale
|
|
280
|
+
|
|
281
|
+
:param Application app: Application Instance
|
|
282
|
+
:param List[ScanHistory] new_scan_history: List of new scan history items
|
|
283
|
+
:return: Tuple of Response and Scan
|
|
284
|
+
:rtype: Tuple[List[Response], List[ScanHistory]]
|
|
285
|
+
"""
|
|
286
|
+
tup_res = []
|
|
287
|
+
if new_scan_history:
|
|
288
|
+
app.logger.info(f"Inserting {len(new_scan_history)} new scan history item(s)")
|
|
289
|
+
tup_res = ScanHistory.bulk_insert(app, new_scan_history)
|
|
290
|
+
app.logger.info("Done!")
|
|
291
|
+
return tup_res
|
|
292
|
+
|
|
293
|
+
@staticmethod
|
|
294
|
+
def convert_from_tenable(
|
|
295
|
+
str_path: str,
|
|
296
|
+
existing_assets: List[dict],
|
|
297
|
+
) -> List["ScanHistory"]:
|
|
298
|
+
"""
|
|
299
|
+
Converts a TenableScan object to a RegScale Scan object
|
|
300
|
+
|
|
301
|
+
:param str str_path: A path to a temporary directory to store the Nessus scan history data.
|
|
302
|
+
:param List[dict] existing_assets: Existing RegScale Assets
|
|
303
|
+
:return: List of RegScale Scans
|
|
304
|
+
:rtype: List[ScanHistory]
|
|
305
|
+
"""
|
|
306
|
+
app = Application()
|
|
307
|
+
existing_scan_history_list = []
|
|
308
|
+
file_list = list(Path(str_path).glob("*"))
|
|
309
|
+
with create_progress_object() as progress:
|
|
310
|
+
processing_pages = progress.add_task(
|
|
311
|
+
f"[#ef5d23]Processing {len(file_list)} pages from Tenable...",
|
|
312
|
+
total=len(file_list),
|
|
313
|
+
)
|
|
314
|
+
for index, file in enumerate(file_list):
|
|
315
|
+
app.logger.debug(f"Processing page {index + 1} of {len(file_list)}")
|
|
316
|
+
with open(file, "rb") as vuln_file_wrapper:
|
|
317
|
+
new_scan_data = []
|
|
318
|
+
# import dict from json file
|
|
319
|
+
nessus_list = [vuln.dict() for vuln in pickle.load(vuln_file_wrapper)]
|
|
320
|
+
new_scan_data.extend(ScanHistory.prepare_scan_history_for_sync(app, nessus_list, existing_assets))
|
|
321
|
+
existing_scan_history_list.extend(ScanHistory.sync_scan_history_to_regscale(app, new_scan_data))
|
|
322
|
+
progress.update(processing_pages, advance=1)
|
|
323
|
+
|
|
324
|
+
return existing_scan_history_list
|
|
325
|
+
|
|
326
|
+
@staticmethod
|
|
327
|
+
def bulk_insert(
|
|
328
|
+
app: Application, scans: List["ScanHistory"], max_workers: Optional[int] = 10
|
|
329
|
+
) -> List[Tuple[Response, "ScanHistory"]]:
|
|
330
|
+
"""Bulk insert assets using the RegScale API and ThreadPoolExecutor
|
|
331
|
+
|
|
332
|
+
:param Application app: Application Instance
|
|
333
|
+
:param List[ScanHistory] scans: List of Scans
|
|
334
|
+
:param Optional[int] max_workers: Max Workers, defaults to 10
|
|
335
|
+
:return: List of Tuples containing Response and Scan
|
|
336
|
+
:rtype: List[Tuple[Response, ScanHistory]]
|
|
337
|
+
"""
|
|
338
|
+
api = Api()
|
|
339
|
+
res = []
|
|
340
|
+
with ThreadPoolExecutor(max_workers=max_workers) as executor:
|
|
341
|
+
futures = [
|
|
342
|
+
executor.submit(
|
|
343
|
+
ScanHistory.insert_scan,
|
|
344
|
+
app,
|
|
345
|
+
api,
|
|
346
|
+
scan,
|
|
347
|
+
)
|
|
348
|
+
for scan in scans
|
|
349
|
+
]
|
|
350
|
+
for future in as_completed(futures):
|
|
351
|
+
res.append(future.result()[1])
|
|
352
|
+
return res
|
|
353
|
+
|
|
354
|
+
@staticmethod
|
|
355
|
+
def bulk_update(
|
|
356
|
+
app: Application, scans: List["ScanHistory"], max_workers: Optional[int] = 10
|
|
357
|
+
) -> List["ScanHistory"]:
|
|
358
|
+
"""
|
|
359
|
+
Bulk update assets using the RegScale API and ThreadPoolExecutor
|
|
360
|
+
|
|
361
|
+
:param Application app: Application Instance
|
|
362
|
+
:param List[ScanHistory] scans: List of Scans
|
|
363
|
+
:param Optional[int] max_workers: Max Workers, defaults to 10
|
|
364
|
+
:return: List of Scan
|
|
365
|
+
:rtype: List[ScanHistory]
|
|
366
|
+
"""
|
|
367
|
+
api = Api()
|
|
368
|
+
res = []
|
|
369
|
+
with ThreadPoolExecutor(max_workers=max_workers) as executor:
|
|
370
|
+
futures = [
|
|
371
|
+
executor.submit(
|
|
372
|
+
ScanHistory.update_scan,
|
|
373
|
+
app,
|
|
374
|
+
api,
|
|
375
|
+
scan,
|
|
376
|
+
)
|
|
377
|
+
for scan in scans
|
|
378
|
+
]
|
|
379
|
+
for future in as_completed(futures):
|
|
380
|
+
res.append(future.result()[1])
|
|
381
|
+
return res
|
|
382
|
+
|
|
383
|
+
@staticmethod
|
|
384
|
+
def update_scan(app: Application, api: Api, regscale_scan: "ScanHistory") -> Tuple[Response, "ScanHistory"]:
|
|
385
|
+
"""
|
|
386
|
+
Api wrapper to update a scan
|
|
387
|
+
|
|
388
|
+
:param Application app: Application Instance
|
|
389
|
+
:param Api api: Api Instance
|
|
390
|
+
:param ScanHistory regscale_scan: Regscale Scan
|
|
391
|
+
:return: RegScale Scan and Response
|
|
392
|
+
:rtype: Tuple[Response, ScanHistory]
|
|
393
|
+
"""
|
|
394
|
+
scan_res = api.put(
|
|
395
|
+
url=app.config["domain"] + "/api/scanHistory", # no ID needed on this endpoint
|
|
396
|
+
json=regscale_scan.model_dump(),
|
|
397
|
+
)
|
|
398
|
+
regscale_scan.id = scan_res.json()["id"]
|
|
399
|
+
return scan_res, regscale_scan
|
|
400
|
+
|
|
401
|
+
@staticmethod
|
|
402
|
+
def insert_scan(app: Application, api: Api, regscale_scan: "ScanHistory") -> Tuple[Response, "ScanHistory"]:
|
|
403
|
+
"""
|
|
404
|
+
Api wrapper to insert a scan
|
|
405
|
+
|
|
406
|
+
:param Application app: Application Instance
|
|
407
|
+
:param Api api: Api Instance
|
|
408
|
+
:param ScanHistory regscale_scan: Regscale Scan
|
|
409
|
+
:return: RegScale Scan and Response
|
|
410
|
+
:rtype: Tuple[Response, ScanHistory]
|
|
411
|
+
"""
|
|
412
|
+
scan_res = api.post(
|
|
413
|
+
url=app.config["domain"] + "/api/scanHistory",
|
|
414
|
+
json=regscale_scan.model_dump(),
|
|
415
|
+
)
|
|
416
|
+
if not scan_res.ok:
|
|
417
|
+
api.logger.error(f"Unable to insert scan: {scan_res.status_code}: {scan_res.reason}. {scan_res.text}")
|
|
418
|
+
else:
|
|
419
|
+
try:
|
|
420
|
+
regscale_scan.id = scan_res.json()["id"]
|
|
421
|
+
except (KeyError, JSONDecodeError) as ex:
|
|
422
|
+
api.logger.error(f"Unable to insert scan: {ex}")
|
|
423
|
+
return scan_res, regscale_scan
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
class Scan(ScanHistory):
|
|
427
|
+
"""
|
|
428
|
+
DEPRECATED: Scan class is deprecated. Use ScanHistory instead.
|
|
429
|
+
"""
|
|
430
|
+
|
|
431
|
+
def __init__(self, *args, **kwargs):
|
|
432
|
+
warnings.warn(
|
|
433
|
+
"Scan class is deprecated. Use ScanHistory instead.",
|
|
434
|
+
DeprecationWarning,
|
|
435
|
+
)
|
|
436
|
+
super().__init__(*args, **kwargs)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""
|
|
2
|
+
QueryParameter, Query, and Search models used for assets
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
from typing import List, Optional
|
|
7
|
+
|
|
8
|
+
from pydantic import BaseModel
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class QueryParameter(BaseModel):
|
|
12
|
+
"""
|
|
13
|
+
QueryParameter object
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
id: int = 0
|
|
17
|
+
field: str = ""
|
|
18
|
+
name: str = ""
|
|
19
|
+
type: str = ""
|
|
20
|
+
operator: str = ""
|
|
21
|
+
value: str = ""
|
|
22
|
+
viewName: Optional[str] = ""
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class Query(BaseModel):
|
|
26
|
+
id: int = 0
|
|
27
|
+
viewName: str = ""
|
|
28
|
+
module: str = ""
|
|
29
|
+
scope: str = ""
|
|
30
|
+
createdById: str = ""
|
|
31
|
+
dateCreated: Optional[datetime] = datetime.now()
|
|
32
|
+
parameters: List[QueryParameter] = []
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class Search(BaseModel):
|
|
36
|
+
"""
|
|
37
|
+
Search object
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
parentID: int = 0
|
|
41
|
+
module: str = ""
|
|
42
|
+
friendlyName: str = ""
|
|
43
|
+
workbench: str = ""
|
|
44
|
+
base: str = ""
|
|
45
|
+
sort: str = "id"
|
|
46
|
+
direction: str = "Ascending"
|
|
47
|
+
simpleSearch: str = ""
|
|
48
|
+
page: int = 0
|
|
49
|
+
pageSize: int = 0
|
|
50
|
+
query: Optional[Query] = None
|
|
51
|
+
groupBy: str = ""
|
|
52
|
+
intDays: int = 0
|
|
53
|
+
subTab: bool = False
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""Dataclass for Security Control in the application"""
|
|
4
|
+
|
|
5
|
+
from typing import Any, List, Optional
|
|
6
|
+
|
|
7
|
+
from pydantic import Field, ConfigDict
|
|
8
|
+
|
|
9
|
+
from regscale.core.app.api import Api
|
|
10
|
+
from regscale.core.app.application import Application
|
|
11
|
+
from regscale.core.app.utils.app_utils import get_current_datetime
|
|
12
|
+
from regscale.models.regscale_models.regscale_model import RegScaleModel
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class SecurityControl(RegScaleModel):
|
|
16
|
+
"""Security Control
|
|
17
|
+
|
|
18
|
+
:return: A RegScale Security Control instance
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
_module_slug = "SecurityControls"
|
|
22
|
+
_module_str = "securitycontrol"
|
|
23
|
+
_unique_fields = [
|
|
24
|
+
["controlId", "catalogueId"],
|
|
25
|
+
]
|
|
26
|
+
_parent_id_field = "catalogueId"
|
|
27
|
+
|
|
28
|
+
id: int = 0
|
|
29
|
+
isPublic: bool = True
|
|
30
|
+
uuid: Optional[str] = None
|
|
31
|
+
controlId: Optional[str] = None
|
|
32
|
+
sortId: Optional[str] = None
|
|
33
|
+
title: Optional[str] = None
|
|
34
|
+
description: Optional[str] = None
|
|
35
|
+
controlType: Optional[str] = None
|
|
36
|
+
references: Optional[str] = None
|
|
37
|
+
relatedControls: Optional[str] = None
|
|
38
|
+
subControls: Optional[str] = None
|
|
39
|
+
enhancements: Optional[str] = None
|
|
40
|
+
family: Optional[str] = None
|
|
41
|
+
mappings: Optional[str] = None
|
|
42
|
+
assessmentPlan: Optional[str] = None
|
|
43
|
+
weight: float
|
|
44
|
+
catalogueId: int = Field(..., alias="catalogueID")
|
|
45
|
+
practiceLevel: Optional[str] = None
|
|
46
|
+
objectives: Optional[List[object]] = None
|
|
47
|
+
tests: Optional[List[object]] = None
|
|
48
|
+
parameters: Optional[List[object]] = None
|
|
49
|
+
archived: bool = False
|
|
50
|
+
createdById: Optional[str] = Field(default_factory=RegScaleModel.get_user_id)
|
|
51
|
+
dateCreated: Optional[str] = Field(default_factory=get_current_datetime)
|
|
52
|
+
lastUpdatedById: Optional[str] = Field(default_factory=RegScaleModel.get_user_id)
|
|
53
|
+
dateLastUpdated: Optional[str] = Field(default_factory=get_current_datetime)
|
|
54
|
+
criticality: Optional[str] = None
|
|
55
|
+
|
|
56
|
+
@staticmethod
|
|
57
|
+
def _get_additional_endpoints() -> ConfigDict:
|
|
58
|
+
"""
|
|
59
|
+
Get additional endpoints for the SecurityControl
|
|
60
|
+
|
|
61
|
+
:return: Additional endpoints for the SecurityControl
|
|
62
|
+
:rtype: ConfigDict
|
|
63
|
+
"""
|
|
64
|
+
return ConfigDict(
|
|
65
|
+
get_all_by_parent="/api/{model_slug}/getAllByCatalog/{intParentID}",
|
|
66
|
+
get_list="/api/{model_slug}/getList/{catalogId}",
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
def __hash__(self) -> hash:
|
|
70
|
+
"""
|
|
71
|
+
Enable object to be hashable
|
|
72
|
+
|
|
73
|
+
:return: Hashed SecurityControl
|
|
74
|
+
:rtype: hash
|
|
75
|
+
"""
|
|
76
|
+
return hash((self.controlId, self.catalogueId))
|
|
77
|
+
|
|
78
|
+
def __eq__(self, other: "SecurityControl") -> bool:
|
|
79
|
+
"""
|
|
80
|
+
Update items in SecurityControl class
|
|
81
|
+
|
|
82
|
+
:param SecurityControl other: SecurityControl Object to compare to
|
|
83
|
+
:return: Whether the two objects are equal
|
|
84
|
+
:rtype: bool
|
|
85
|
+
"""
|
|
86
|
+
return self.controlId == other.controlId and self.catalogueId == other.catalogueID
|
|
87
|
+
|
|
88
|
+
@classmethod
|
|
89
|
+
def get_list_by_catalog(cls, catalog_id: int) -> List["Catalog"]:
|
|
90
|
+
"""
|
|
91
|
+
Get list of Security Controls for the provided Catalog ID
|
|
92
|
+
|
|
93
|
+
:param int catalog_id: Catalog ID
|
|
94
|
+
:return: list of catalogs
|
|
95
|
+
:rtype: List["Catalog"]
|
|
96
|
+
"""
|
|
97
|
+
return cls._handle_list_response(
|
|
98
|
+
cls._get_api_handler().get(cls.get_endpoint("get_list").format(catalogId=catalog_id))
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
@staticmethod
|
|
102
|
+
def lookup_control(
|
|
103
|
+
app: Application,
|
|
104
|
+
control_id: int,
|
|
105
|
+
) -> "SecurityControl":
|
|
106
|
+
"""
|
|
107
|
+
Return a Security Control in RegScale via API
|
|
108
|
+
|
|
109
|
+
:param Application app: Application Instance
|
|
110
|
+
:param int control_id: ID of the Security Control to look up
|
|
111
|
+
:return: A Security Control from RegScale
|
|
112
|
+
:rtype: SecurityControl
|
|
113
|
+
"""
|
|
114
|
+
api = Api()
|
|
115
|
+
control = api.get(url=app.config["domain"] + f"/api/securitycontrols/{control_id}").json()
|
|
116
|
+
return SecurityControl(**control)
|
|
117
|
+
|
|
118
|
+
@staticmethod
|
|
119
|
+
def lookup_control_by_name(app: Application, control_name: str, catalog_id: int) -> Optional["SecurityControl"]:
|
|
120
|
+
"""
|
|
121
|
+
Lookup a Security Control by name and catalog ID
|
|
122
|
+
|
|
123
|
+
:param Application app: Application instance
|
|
124
|
+
:param str control_name: Name of the security control
|
|
125
|
+
:param int catalog_id: Catalog ID for the security control
|
|
126
|
+
:return: A Security Control from RegScale, if found
|
|
127
|
+
:rtype: Optional[SecurityControl]
|
|
128
|
+
"""
|
|
129
|
+
api = Api()
|
|
130
|
+
config = api.config
|
|
131
|
+
res = api.get(config["domain"] + f"/api/securitycontrols/findByUniqueId/{control_name}/{catalog_id}")
|
|
132
|
+
return SecurityControl(**res.json()) if res.status_code == 200 else None
|