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,169 @@
|
|
|
1
|
+
"""Vulnerabilities Connector Model"""
|
|
2
|
+
|
|
3
|
+
from typing import Iterator, Optional
|
|
4
|
+
|
|
5
|
+
from pydantic import ConfigDict
|
|
6
|
+
|
|
7
|
+
from regscale.integrations.scanner_integration import IntegrationAsset, IntegrationFinding, ScannerIntegration
|
|
8
|
+
from regscale.models.integration_models.synqly_models.synqly_model import SynqlyModel
|
|
9
|
+
from regscale.models.regscale_models import IssueSeverity
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class VulnerabilitiesIntegration(ScannerIntegration):
|
|
13
|
+
title = "Vulnerabilities Connector Integration"
|
|
14
|
+
# Required fields from ScannerIntegration
|
|
15
|
+
asset_identifier_field = "otherTrackingNumber"
|
|
16
|
+
finding_severity_map = {
|
|
17
|
+
"Critical": IssueSeverity.Critical,
|
|
18
|
+
"High": IssueSeverity.High,
|
|
19
|
+
"Medium": IssueSeverity.Moderate,
|
|
20
|
+
"Low": IssueSeverity.Low,
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
def fetch_assets(self, *args, **kwargs) -> Iterator[IntegrationAsset]:
|
|
24
|
+
"""
|
|
25
|
+
Fetches assets from Synqly
|
|
26
|
+
|
|
27
|
+
:yields: Iterator[IntegrationAsset]
|
|
28
|
+
"""
|
|
29
|
+
integration_assets = kwargs.get("integration_assets")
|
|
30
|
+
for asset in integration_assets:
|
|
31
|
+
yield asset
|
|
32
|
+
|
|
33
|
+
def fetch_findings(self, *args, **kwargs) -> Iterator[IntegrationFinding]:
|
|
34
|
+
"""
|
|
35
|
+
Fetches findings from the Synqly
|
|
36
|
+
|
|
37
|
+
:yields: Iterator[IntegrationFinding]
|
|
38
|
+
"""
|
|
39
|
+
integration_findings = kwargs.get("integration_findings")
|
|
40
|
+
for finding in integration_findings:
|
|
41
|
+
yield finding
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class Vulnerabilities(SynqlyModel):
|
|
45
|
+
"""Vulnerabilities Connector Model"""
|
|
46
|
+
|
|
47
|
+
model_config = ConfigDict(populate_by_name=True, use_enum_values=True, arbitrary_types_allowed=True)
|
|
48
|
+
|
|
49
|
+
integration_id: str = ""
|
|
50
|
+
scanner_integration: Optional["VulnerabilitiesIntegration"] = None
|
|
51
|
+
provider: str = ""
|
|
52
|
+
can_fetch_assets: bool = False
|
|
53
|
+
can_fetch_vulns: bool = False
|
|
54
|
+
|
|
55
|
+
def __init__(self, integration: str, **kwargs):
|
|
56
|
+
SynqlyModel.__init__(self, connector_type=self.__class__.__name__, integration=integration, **kwargs)
|
|
57
|
+
self.integration_id = f"{self._connector_type.lower()}_{self.integration.lower()}"
|
|
58
|
+
integration_company = self.integration.split("_")[0] if "_" in self.integration else self.integration # noqa
|
|
59
|
+
self.provider = integration_company
|
|
60
|
+
self.can_fetch_assets = "query_assets" in self.capabilities
|
|
61
|
+
self.can_fetch_vulns = "query_findings" in self.capabilities
|
|
62
|
+
|
|
63
|
+
@staticmethod
|
|
64
|
+
def _handle_scan_date_options(regscale_ssp_id: int, **kwargs) -> list[str]:
|
|
65
|
+
"""
|
|
66
|
+
Handle scan date options for the integration sync process
|
|
67
|
+
|
|
68
|
+
:param int regscale_ssp_id: The RegScale SSP ID
|
|
69
|
+
:return: List of strings to filter vulnerabilities
|
|
70
|
+
:rtype: list[str]
|
|
71
|
+
"""
|
|
72
|
+
from regscale.integrations.commercial.tenablev2.utils import get_last_pull_epoch
|
|
73
|
+
|
|
74
|
+
if vuln_filter := kwargs.get("vuln_filter"):
|
|
75
|
+
kwargs.pop("vuln_filter")
|
|
76
|
+
if isinstance(vuln_filter, str):
|
|
77
|
+
vuln_filter = [f"severity[in]{vuln_filter}"]
|
|
78
|
+
else:
|
|
79
|
+
vuln_filter = ["severity[in]critical,high,medium,low"]
|
|
80
|
+
if kwargs.get("all_scans"):
|
|
81
|
+
vuln_filter.append("finding.last_seen_time[gte]915148800") # Friday, January 1, 1999 12:00:00 AM UTC
|
|
82
|
+
elif scan_date := kwargs.get("scan_date"):
|
|
83
|
+
from regscale.core.utils.date import date_obj
|
|
84
|
+
|
|
85
|
+
if scan_date := date_obj(scan_date):
|
|
86
|
+
vuln_filter.append(f"finding.last_seen_time[gte]{scan_date.isoformat()}")
|
|
87
|
+
else:
|
|
88
|
+
raise ValueError(f"Invalid scan date: {scan_date}")
|
|
89
|
+
else:
|
|
90
|
+
vuln_filter.append(f"finding.last_seen_time[gte]{get_last_pull_epoch(regscale_ssp_id)}")
|
|
91
|
+
return vuln_filter
|
|
92
|
+
|
|
93
|
+
def integration_sync(self, regscale_ssp_id: int, **kwargs) -> None:
|
|
94
|
+
"""
|
|
95
|
+
Runs the integration sync process
|
|
96
|
+
|
|
97
|
+
:param int regscale_ssp_id: The RegScale SSP ID
|
|
98
|
+
:rtype: None
|
|
99
|
+
"""
|
|
100
|
+
vuln_filter = self._handle_scan_date_options(regscale_ssp_id=regscale_ssp_id, **kwargs)
|
|
101
|
+
self.logger.debug(f"Vulnerability filter: {vuln_filter}")
|
|
102
|
+
self.logger.info(f"Fetching vulnerability data from {self.integration_name}...")
|
|
103
|
+
findings = (
|
|
104
|
+
self.fetch_integration_data(
|
|
105
|
+
func=self.tenant.engine_client.vulnerabilities.query_findings,
|
|
106
|
+
filter=vuln_filter,
|
|
107
|
+
**kwargs,
|
|
108
|
+
)
|
|
109
|
+
if self.can_fetch_vulns
|
|
110
|
+
else []
|
|
111
|
+
)
|
|
112
|
+
self.logger.info(f"Fetching asset data from {self.integration_name}...")
|
|
113
|
+
assets = (
|
|
114
|
+
self.fetch_integration_data(func=self.tenant.engine_client.vulnerabilities.query_assets, **kwargs)
|
|
115
|
+
if self.can_fetch_assets
|
|
116
|
+
else []
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
self.scanner_integration = VulnerabilitiesIntegration(plan_id=regscale_ssp_id)
|
|
120
|
+
self.logger.info(f"Mapping {self.provider} asset(s) data to RegScale asset(s)...")
|
|
121
|
+
if assets:
|
|
122
|
+
self.app.thread_manager.submit_tasks_from_list(
|
|
123
|
+
func=self.mapper.to_regscale,
|
|
124
|
+
items=assets,
|
|
125
|
+
args=None,
|
|
126
|
+
connector=self,
|
|
127
|
+
regscale_ssp_id=regscale_ssp_id,
|
|
128
|
+
**kwargs,
|
|
129
|
+
)
|
|
130
|
+
integration_assets = self.app.thread_manager.execute_and_verify(return_passed=True)
|
|
131
|
+
self.logger.info(f"Mapped {len(integration_assets)} {self.provider} asset(s) to RegScale asset(s)...")
|
|
132
|
+
self.scanner_integration.sync_assets(
|
|
133
|
+
title=f"{self.integration_name} Vulnerabilities",
|
|
134
|
+
plan_id=regscale_ssp_id,
|
|
135
|
+
integration_assets=integration_assets,
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
if findings:
|
|
139
|
+
integration_findings = []
|
|
140
|
+
self.logger.info(f"Mapping {self.provider} finding(s) data to RegScale finding(s)...")
|
|
141
|
+
self.app.thread_manager.submit_tasks_from_list(
|
|
142
|
+
func=self.mapper.to_regscale,
|
|
143
|
+
items=findings,
|
|
144
|
+
args=None,
|
|
145
|
+
connector=self,
|
|
146
|
+
regscale_ssp_id=regscale_ssp_id,
|
|
147
|
+
**kwargs,
|
|
148
|
+
)
|
|
149
|
+
mapped_findings = self.app.thread_manager.execute_and_verify(return_passed=True)
|
|
150
|
+
for finding in mapped_findings:
|
|
151
|
+
if isinstance(finding, list):
|
|
152
|
+
integration_findings.extend(finding)
|
|
153
|
+
else:
|
|
154
|
+
integration_findings.append(finding)
|
|
155
|
+
self.logger.info(f"Mapped {len(integration_findings)} {self.provider} finding(s) to RegScale finding(s)...")
|
|
156
|
+
self.scanner_integration.sync_findings(
|
|
157
|
+
title=f"{self.integration_name} Vulnerabilities",
|
|
158
|
+
plan_id=regscale_ssp_id,
|
|
159
|
+
integration_findings=integration_findings,
|
|
160
|
+
)
|
|
161
|
+
self.logger.info(f"[green]Sync from {self.integration_name} to RegScale completed.")
|
|
162
|
+
|
|
163
|
+
def run_sync(self, *args, **kwargs) -> None:
|
|
164
|
+
"""
|
|
165
|
+
Syncs RegScale issues with Vulnerability connector using Synqly
|
|
166
|
+
|
|
167
|
+
:rtype: None
|
|
168
|
+
"""
|
|
169
|
+
self.run_integration_sync(*args, **kwargs)
|
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
"""Class to handle mapping RegScale models to OCSF models for Synqly integration"""
|
|
2
|
+
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from typing import Any, Union, TYPE_CHECKING, Optional
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from regscale.models.integration_models.synqly_models.connectors import Ticketing, Vulnerabilities
|
|
8
|
+
from synqly.engine.resources.ocsf.resources.v_1_1_0.resources.securityfinding import ResourceDetails, Vulnerability
|
|
9
|
+
|
|
10
|
+
from synqly import engine
|
|
11
|
+
from synqly.engine import CreateTicketRequest
|
|
12
|
+
from synqly.engine.resources.ticketing.types.priority import Priority
|
|
13
|
+
|
|
14
|
+
from regscale.core.app.utils.app_utils import (
|
|
15
|
+
error_and_exit,
|
|
16
|
+
convert_datetime_to_regscale_string,
|
|
17
|
+
)
|
|
18
|
+
from synqly.engine.resources.ticketing.types.ticket import Ticket
|
|
19
|
+
from synqly.engine.resources.vulnerabilities.types import Asset as OCSFAsset, SecurityFinding
|
|
20
|
+
from regscale.models.regscale_models import Issue
|
|
21
|
+
from regscale.integrations.scanner_integration import IntegrationAsset, IntegrationFinding
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class Mapper:
|
|
25
|
+
"""Mapping class to handle RegScale models to OCSF models for Synqly integration"""
|
|
26
|
+
|
|
27
|
+
date_format = "%Y-%m-%dT%H:%M:%S"
|
|
28
|
+
|
|
29
|
+
def to_ocsf(self, regscale_object: Any, **kwargs) -> Any:
|
|
30
|
+
"""
|
|
31
|
+
Convert RegScale object to OCSF object
|
|
32
|
+
|
|
33
|
+
:param Any regscale_object: RegScale object to convert to an OCSF object
|
|
34
|
+
:return: The comparable OCSF object
|
|
35
|
+
:rtype: Any
|
|
36
|
+
"""
|
|
37
|
+
if isinstance(regscale_object, Issue):
|
|
38
|
+
return self._regscale_issue_to_ticket(regscale_object, **kwargs)
|
|
39
|
+
else:
|
|
40
|
+
error_and_exit(f"Unsupported object type {type(regscale_object)}")
|
|
41
|
+
|
|
42
|
+
def to_regscale(self, ocsf_object: Any, connector: Union["Ticketing", "Vulnerabilities"], **kwargs) -> Any:
|
|
43
|
+
"""
|
|
44
|
+
Convert OCSF object to RegScale object
|
|
45
|
+
|
|
46
|
+
:param Any ocsf_object: OCSF object to convert to a RegScale object
|
|
47
|
+
:param Union["Ticketing", "Vulnerabilities"] connector: Connector class object
|
|
48
|
+
:return: The comparable RegScale object
|
|
49
|
+
:rtype: Any
|
|
50
|
+
"""
|
|
51
|
+
if isinstance(ocsf_object, Ticket):
|
|
52
|
+
return self._ticket_to_regscale(connector, ocsf_object, **kwargs)
|
|
53
|
+
elif isinstance(ocsf_object, OCSFAsset):
|
|
54
|
+
return self._ocsf_asset_to_regscale(connector, ocsf_object, **kwargs)
|
|
55
|
+
elif isinstance(ocsf_object, SecurityFinding):
|
|
56
|
+
return self._security_finding_to_regscale(connector, ocsf_object, **kwargs)
|
|
57
|
+
else:
|
|
58
|
+
error_and_exit(f"Unsupported object type {type(ocsf_object)}")
|
|
59
|
+
|
|
60
|
+
def _ticket_to_regscale(self, connector: "Ticketing", ticket: Ticket, **kwargs) -> Issue:
|
|
61
|
+
"""
|
|
62
|
+
Convert OCSF Ticket to RegScale Issue
|
|
63
|
+
|
|
64
|
+
:param "Ticketing" connector: Ticketing connector class object
|
|
65
|
+
:param Ticket ticket: OCSF Ticket to convert to a RegScale Issue
|
|
66
|
+
:param dict **kwargs: Keyword Arguments
|
|
67
|
+
:return: The comparable RegScale Issue
|
|
68
|
+
:rtype: Issue
|
|
69
|
+
"""
|
|
70
|
+
due_date = convert_datetime_to_regscale_string(ticket.due_date)
|
|
71
|
+
if not due_date:
|
|
72
|
+
due_date = self._determine_due_date(ticket.priority)
|
|
73
|
+
ticket_dict = ticket.dict()
|
|
74
|
+
key_val_desc = "All fields:\n"
|
|
75
|
+
for k, v in ticket_dict.items():
|
|
76
|
+
key_val_desc += f"{k.replace('_', ' ').title()}: {str(v) or 'NULL'}\n"
|
|
77
|
+
regscale_issue = Issue(
|
|
78
|
+
title=ticket.summary,
|
|
79
|
+
severityLevel=Issue.assign_severity(ticket.priority),
|
|
80
|
+
dueDate=due_date,
|
|
81
|
+
description=f"Description {ticket.description}\n{key_val_desc}",
|
|
82
|
+
status=("Closed" if ticket.status.lower() == "done" else "Draft"),
|
|
83
|
+
dateCompleted=(
|
|
84
|
+
convert_datetime_to_regscale_string(ticket.completion_date) if ticket.status.lower() == "done" else None
|
|
85
|
+
),
|
|
86
|
+
**kwargs,
|
|
87
|
+
)
|
|
88
|
+
# update the correct integration field names or manual detection fields
|
|
89
|
+
if connector.has_integration_field:
|
|
90
|
+
setattr(regscale_issue, connector.integration_id_field, ticket.id)
|
|
91
|
+
else:
|
|
92
|
+
regscale_issue.manualDetectionSource = connector.integration
|
|
93
|
+
regscale_issue.manualDetectionId = ticket.id
|
|
94
|
+
return regscale_issue
|
|
95
|
+
|
|
96
|
+
@staticmethod
|
|
97
|
+
def _ocsf_asset_to_regscale(connector: "Vulnerabilities", asset: OCSFAsset, **kwargs) -> IntegrationAsset:
|
|
98
|
+
"""
|
|
99
|
+
Convert OCSF Asset to RegScale Asset
|
|
100
|
+
|
|
101
|
+
:param Vulnerabilities connector: Vulnerabilities connector class object
|
|
102
|
+
:param OCSFAsset asset: OCSF Asset to convert to an IntegrationAsset
|
|
103
|
+
:return: The comparable IntegrationAsset object
|
|
104
|
+
:rtype: IntegrationAsset
|
|
105
|
+
"""
|
|
106
|
+
from regscale.models.regscale_models import AssetCategory, SecurityPlan
|
|
107
|
+
|
|
108
|
+
device_data = asset.device
|
|
109
|
+
os_data = device_data.os
|
|
110
|
+
if device_data.sw_info:
|
|
111
|
+
software_inventory = [
|
|
112
|
+
{"name": sw.name, "version": sw.version} for sw in device_data.sw_info if getattr(sw, "name", None)
|
|
113
|
+
]
|
|
114
|
+
else:
|
|
115
|
+
software_inventory = []
|
|
116
|
+
return IntegrationAsset(
|
|
117
|
+
name=device_data.name or device_data.hostname or f"{connector.provider} Asset: {device_data.instance_uid}",
|
|
118
|
+
identifier=device_data.uid,
|
|
119
|
+
asset_type=device_data.type,
|
|
120
|
+
asset_category=AssetCategory.Hardware,
|
|
121
|
+
parent_id=kwargs.pop("regscale_ssp_id"),
|
|
122
|
+
parent_module=SecurityPlan.get_module_string(),
|
|
123
|
+
mac_address=device_data.mac,
|
|
124
|
+
fqdn=device_data.hostname,
|
|
125
|
+
ip_address=", ".join(device_data.ip_addresses) if device_data.ip_addresses else device_data.ip,
|
|
126
|
+
location=device_data.location or device_data.zone,
|
|
127
|
+
vlan_id=device_data.vlan_uid,
|
|
128
|
+
other_tracking_number=device_data.uid,
|
|
129
|
+
serial_number=device_data.hw_info.serial_number if device_data.hw_info else None,
|
|
130
|
+
cpu=device_data.hw_info.cpu_cores if device_data.hw_info else None,
|
|
131
|
+
ram=device_data.hw_info.ram_size if device_data.hw_info else None,
|
|
132
|
+
operating_system=os_data.name if os_data else None,
|
|
133
|
+
os_version=os_data.version if os_data else None,
|
|
134
|
+
software_inventory=software_inventory,
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
@staticmethod
|
|
138
|
+
def _parse_finding_data(finding: "SecurityFinding", vuln: Optional["Vulnerability"] = None) -> dict:
|
|
139
|
+
"""
|
|
140
|
+
Parse the data from the SecurityFinding object
|
|
141
|
+
|
|
142
|
+
:param Optional[Vulnerability] vuln: OCSF Vulnerability object, defaults to None
|
|
143
|
+
:return: A dictionary of the parsed data
|
|
144
|
+
:rtype: dict
|
|
145
|
+
"""
|
|
146
|
+
from synqly.engine.resources.ocsf.resources.v_1_1_0.resources.securityfinding import Remediation
|
|
147
|
+
|
|
148
|
+
finding_data = {
|
|
149
|
+
"cve": None,
|
|
150
|
+
"first_seen": vuln.first_seen_time_dt if vuln else finding.finding.first_seen_time_dt,
|
|
151
|
+
"last_seen": vuln.last_seen_time_dt if vuln else finding.finding.last_seen_time_dt,
|
|
152
|
+
"plugin_id": vuln.cve.uid if vuln else finding.finding.product_uid,
|
|
153
|
+
"severity": int(vuln.severity) if vuln else finding.severity_id,
|
|
154
|
+
"remediation": getattr(vuln, "remediation") if vuln else finding.finding.remediation.desc,
|
|
155
|
+
}
|
|
156
|
+
if vuln:
|
|
157
|
+
finding_data["cve"] = vuln.cve.uid
|
|
158
|
+
else:
|
|
159
|
+
finding_data["cve"] = finding.finding.title if "cve" in finding.finding.title.lower() else None
|
|
160
|
+
if isinstance(finding_data["remediation"], Remediation):
|
|
161
|
+
finding_data["remediation"] = finding_data["remediation"].desc
|
|
162
|
+
elif isinstance(finding_data["remediation"], dict):
|
|
163
|
+
remediation_string = ""
|
|
164
|
+
for f, v in finding_data["remediation"].items():
|
|
165
|
+
remediation_string += f"{f}: {v}\n"
|
|
166
|
+
finding_data["remediation"] = remediation_string
|
|
167
|
+
elif isinstance(finding_data["remediation"], list):
|
|
168
|
+
finding_data["remediation"] = "\n".join(finding_data["remediation"])
|
|
169
|
+
return finding_data
|
|
170
|
+
|
|
171
|
+
@staticmethod
|
|
172
|
+
def _populate_cvs_scores(finding_obj: IntegrationFinding, vuln: Optional["Vulnerability"] = None) -> None:
|
|
173
|
+
"""
|
|
174
|
+
Populates the CVSS scores for the provided IntegrationFinding object
|
|
175
|
+
|
|
176
|
+
:param IntegrationFinding finding_obj: IntegrationFinding object
|
|
177
|
+
:param Vulnerability vuln: OCSF Vulnerability object, defaults to None
|
|
178
|
+
:rtype: None
|
|
179
|
+
"""
|
|
180
|
+
if vuln:
|
|
181
|
+
for cvs in getattr(vuln.cve, "cvss", []):
|
|
182
|
+
if "3" in cvs.version:
|
|
183
|
+
finding_obj.cvss_v3_score = cvs.base_score
|
|
184
|
+
elif "2" in cvs.version:
|
|
185
|
+
finding_obj.cvss_v2_score = cvs.base_score
|
|
186
|
+
else:
|
|
187
|
+
finding_obj.cvss_score = cvs.base_score
|
|
188
|
+
|
|
189
|
+
def _security_finding_to_regscale(
|
|
190
|
+
self, connector: "Vulnerabilities", finding: SecurityFinding, **_
|
|
191
|
+
) -> list[IntegrationFinding]:
|
|
192
|
+
"""
|
|
193
|
+
Convert OCSF SecurityFinding to RegScale IntegrationFinding
|
|
194
|
+
|
|
195
|
+
:param "Vulnerabilities" connector: Vulnerabilities connector class object
|
|
196
|
+
:param SecurityFinding finding: OCSF SecurityFinding to convert to an IntegrationFinding
|
|
197
|
+
:return: List of comparable IntegrationFinding objects
|
|
198
|
+
:rtype: list[IntegrationFinding]
|
|
199
|
+
"""
|
|
200
|
+
findings = []
|
|
201
|
+
|
|
202
|
+
def _create_finding(resource: "ResourceDetails", vuln: Optional["Vulnerability"] = None) -> IntegrationFinding:
|
|
203
|
+
"""
|
|
204
|
+
Create an IntegrationFinding object from a resource and vulnerability
|
|
205
|
+
|
|
206
|
+
:param ResourceDetails resource: OCSF ResourceDetails object
|
|
207
|
+
:param Optional[Vulnerability] vuln: OCSF Vulnerability object, defaults to None
|
|
208
|
+
:return: An IntegrationFinding object
|
|
209
|
+
:rtype: IntegrationFinding
|
|
210
|
+
"""
|
|
211
|
+
base = vuln if vuln else finding.finding
|
|
212
|
+
finding_data = self._parse_finding_data(finding, vuln)
|
|
213
|
+
if resource.data:
|
|
214
|
+
dns = resource.data.get("hostname")
|
|
215
|
+
ip_address = resource.data.get("ipv4")
|
|
216
|
+
else:
|
|
217
|
+
dns = resource.uid if vuln else None
|
|
218
|
+
ip_address = None
|
|
219
|
+
|
|
220
|
+
finding_obj = IntegrationFinding(
|
|
221
|
+
control_labels=[],
|
|
222
|
+
category=f"{connector.integration_name} Vulnerability",
|
|
223
|
+
title=base.title,
|
|
224
|
+
plugin_name=connector.integration_name,
|
|
225
|
+
severity=Issue.assign_severity(finding.severity), # type: ignore
|
|
226
|
+
description=base.desc,
|
|
227
|
+
status=finding.status or "Open",
|
|
228
|
+
first_seen=self._datetime_to_str(finding_data["first_seen"]),
|
|
229
|
+
last_seen=self._datetime_to_str(finding_data["last_seen"]),
|
|
230
|
+
ip_address=ip_address,
|
|
231
|
+
plugin_id=finding_data["plugin_id"],
|
|
232
|
+
dns=dns,
|
|
233
|
+
severity_int=finding_data["severity"],
|
|
234
|
+
issue_title=base.title,
|
|
235
|
+
cve=finding_data["cve"],
|
|
236
|
+
evidence=finding.evidence,
|
|
237
|
+
impact=finding.impact,
|
|
238
|
+
asset_identifier=resource.uid,
|
|
239
|
+
source_report=connector.integration_name,
|
|
240
|
+
remediation=finding_data["remediation"],
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
self._populate_cvs_scores(finding_obj, vuln)
|
|
244
|
+
|
|
245
|
+
return finding_obj
|
|
246
|
+
|
|
247
|
+
for asset in finding.resources:
|
|
248
|
+
if finding.vulnerabilities:
|
|
249
|
+
findings.extend(_create_finding(asset, vuln) for vuln in finding.vulnerabilities)
|
|
250
|
+
else:
|
|
251
|
+
findings.append(_create_finding(asset))
|
|
252
|
+
|
|
253
|
+
return findings
|
|
254
|
+
|
|
255
|
+
def _datetime_to_str(self, date_time: Optional[datetime] = None) -> str:
|
|
256
|
+
"""
|
|
257
|
+
Convert a datetime object to a string
|
|
258
|
+
|
|
259
|
+
:param Optional[datetime] date_time: The datetime object to convert, defaults to None
|
|
260
|
+
:return: The datetime as a string
|
|
261
|
+
:rtype: str
|
|
262
|
+
"""
|
|
263
|
+
from regscale.core.utils.date import datetime_str
|
|
264
|
+
|
|
265
|
+
return datetime_str(date_time, self.date_format)
|
|
266
|
+
|
|
267
|
+
@staticmethod
|
|
268
|
+
def _map_ticket_priority(severity: str) -> Priority:
|
|
269
|
+
"""
|
|
270
|
+
Map RegScale severity to OCSF priority
|
|
271
|
+
|
|
272
|
+
:param str severity: RegScale severity
|
|
273
|
+
:return: OCSF priority
|
|
274
|
+
:rtype: Priority
|
|
275
|
+
"""
|
|
276
|
+
if "high" in severity.lower():
|
|
277
|
+
return Priority.HIGH
|
|
278
|
+
elif "moderate" in severity.lower():
|
|
279
|
+
return Priority.MEDIUM
|
|
280
|
+
else:
|
|
281
|
+
return Priority.LOW
|
|
282
|
+
|
|
283
|
+
def _determine_due_date(self, severity: str) -> str:
|
|
284
|
+
"""
|
|
285
|
+
Determine the due date based on the provided severity
|
|
286
|
+
|
|
287
|
+
:param str severity: RegScale severity
|
|
288
|
+
:return: Due date for the issue
|
|
289
|
+
:rtype: str
|
|
290
|
+
"""
|
|
291
|
+
from datetime import timedelta
|
|
292
|
+
|
|
293
|
+
if "high" in severity.lower():
|
|
294
|
+
return (datetime.now() + timedelta(days=30)).strftime(self.date_format)
|
|
295
|
+
elif "medium" in severity.lower():
|
|
296
|
+
return (datetime.now() + timedelta(days=60)).strftime(self.date_format)
|
|
297
|
+
else:
|
|
298
|
+
return (datetime.now() + timedelta(days=90)).strftime(self.date_format)
|
|
299
|
+
|
|
300
|
+
def _regscale_issue_to_ticket(self, regscale_issue: Issue, **kwargs) -> CreateTicketRequest:
|
|
301
|
+
"""
|
|
302
|
+
Maps a RegScale issue to a JIRA issue
|
|
303
|
+
|
|
304
|
+
:param Issue regscale_issue: RegScale issue object
|
|
305
|
+
:return: Synqly CreateTicketRequest object
|
|
306
|
+
:rtype: CreateTicketRequest
|
|
307
|
+
"""
|
|
308
|
+
description = ""
|
|
309
|
+
for key, value in regscale_issue.dict().items():
|
|
310
|
+
if key not in ["id"] and value:
|
|
311
|
+
description += f"{key.title()}: {value}\n"
|
|
312
|
+
if project := kwargs.get("default_project"):
|
|
313
|
+
kwargs.pop("default_project")
|
|
314
|
+
return engine.CreateTicketRequest(
|
|
315
|
+
name=regscale_issue.title,
|
|
316
|
+
description=f"RegScale Issue #{regscale_issue.id}:\n{description}",
|
|
317
|
+
summary=regscale_issue.title,
|
|
318
|
+
creator=kwargs.get("creator", "RegScale CLI"),
|
|
319
|
+
priority=self._map_ticket_priority(regscale_issue.severityLevel),
|
|
320
|
+
project=project,
|
|
321
|
+
**kwargs,
|
|
322
|
+
)
|
|
323
|
+
else:
|
|
324
|
+
return engine.CreateTicketRequest(
|
|
325
|
+
name=regscale_issue.title,
|
|
326
|
+
description=f"RegScale Issue #{regscale_issue.id}:\n{description}",
|
|
327
|
+
summary=regscale_issue.title,
|
|
328
|
+
creator=kwargs.get("creator", "RegScale CLI"),
|
|
329
|
+
priority=self._map_ticket_priority(regscale_issue.severityLevel),
|
|
330
|
+
**kwargs,
|
|
331
|
+
)
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
from typing import Any, Optional
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel, ConfigDict, Field, model_validator
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Param(BaseModel):
|
|
7
|
+
model_config = ConfigDict(populate_by_name=True, frozen=True)
|
|
8
|
+
|
|
9
|
+
name: Optional[str] = Field("", description="The name of the parameter")
|
|
10
|
+
description: Optional[str] = Field("", description="The description of the parameter")
|
|
11
|
+
expected_type: str = Field("STRING", description="The expected type of the parameter as a string", alias="type")
|
|
12
|
+
optional: bool = Field(description="Whether the parameter is optional or not", alias="optional", default=False)
|
|
13
|
+
data_type: Optional[Any] = Field(None, description="The allowed data type of the parameter")
|
|
14
|
+
click_type: Optional[str] = Field(None, description="The click type of the parameter")
|
|
15
|
+
default: Optional[Any] = Field("None", description="The default value of the parameter")
|
|
16
|
+
|
|
17
|
+
@model_validator(mode="before")
|
|
18
|
+
def set_data_types(cls, values: dict) -> dict:
|
|
19
|
+
"""
|
|
20
|
+
Set the data type of the parameter based on the expected type
|
|
21
|
+
|
|
22
|
+
:param values: The values of the model
|
|
23
|
+
:return: Updated values
|
|
24
|
+
:rtype: dict
|
|
25
|
+
"""
|
|
26
|
+
if expected_type := values.get("type"):
|
|
27
|
+
values["data_type"] = cls._map_types(expected_type)
|
|
28
|
+
values["click_type"] = cls._map_click_types(expected_type)
|
|
29
|
+
return values
|
|
30
|
+
|
|
31
|
+
@classmethod
|
|
32
|
+
def _map_click_types(cls, type_str: str) -> Optional[str]:
|
|
33
|
+
"""
|
|
34
|
+
Map the string type to the equivalent click type
|
|
35
|
+
|
|
36
|
+
:param str type_str: The data type as a string
|
|
37
|
+
:return: The equivalent click type, if it exists
|
|
38
|
+
:rtype: Optional[str]
|
|
39
|
+
"""
|
|
40
|
+
click_types = {
|
|
41
|
+
"string": "click.STRING",
|
|
42
|
+
"number": "click.FLOAT",
|
|
43
|
+
"integer": "click.INT",
|
|
44
|
+
"bool": "click.BOOL",
|
|
45
|
+
"choice": "click.Choice",
|
|
46
|
+
}
|
|
47
|
+
return click_types.get(type_str)
|
|
48
|
+
|
|
49
|
+
@classmethod
|
|
50
|
+
def _map_types(cls, type_str: str) -> Any:
|
|
51
|
+
"""
|
|
52
|
+
Map the javascript string type to python type
|
|
53
|
+
|
|
54
|
+
:param str type_str: The data type as a string
|
|
55
|
+
:return: The actual data type in python
|
|
56
|
+
:rtype: Any
|
|
57
|
+
"""
|
|
58
|
+
data_types = {
|
|
59
|
+
"string": "str",
|
|
60
|
+
"object": "dict",
|
|
61
|
+
"array": "list",
|
|
62
|
+
"number": "float",
|
|
63
|
+
"integer": "int",
|
|
64
|
+
"boolean": "bool",
|
|
65
|
+
"choice": "choice",
|
|
66
|
+
}
|
|
67
|
+
if type_str in data_types:
|
|
68
|
+
return data_types[type_str]
|
|
69
|
+
try:
|
|
70
|
+
return eval(type_str)
|
|
71
|
+
except NameError:
|
|
72
|
+
raise ValueError(f"Invalid type: {type_str}")
|