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
regscale/dev/code_gen.py
ADDED
|
@@ -0,0 +1,492 @@
|
|
|
1
|
+
"""Code generation to build automation manager jobs for the platform and click commands for the RegScale CLI"""
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
from regscale.models.integration_models.synqly_models.synqly_model import SynqlyModel
|
|
7
|
+
|
|
8
|
+
from regscale.models.integration_models.synqly_models.connector_types import ConnectorType
|
|
9
|
+
from regscale.models.integration_models.synqly_models.param import Param
|
|
10
|
+
|
|
11
|
+
SUPPORTED_CONNECTORS = [ConnectorType.Ticketing, ConnectorType.Vulnerabilities, ConnectorType.Assets]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def generate_dags() -> None:
|
|
15
|
+
"""Generate Airflow DAGs for the platform"""
|
|
16
|
+
from regscale.core.app.utils.app_utils import check_file_path
|
|
17
|
+
from regscale.models.integration_models.synqly_models.synqly_model import SynqlyModel
|
|
18
|
+
|
|
19
|
+
model = SynqlyModel()
|
|
20
|
+
configs = model._get_integrations_and_secrets(True)
|
|
21
|
+
# iterate through connectors and generate DAGs
|
|
22
|
+
for connector in SUPPORTED_CONNECTORS:
|
|
23
|
+
connector_configs = {
|
|
24
|
+
integration: configs[integration] for integration in configs if connector in integration.lower()
|
|
25
|
+
}
|
|
26
|
+
# sort the connector configs by the key for repeatability
|
|
27
|
+
connector_configs = dict(sorted(connector_configs.items()))
|
|
28
|
+
description = _build_description(configs=connector_configs, connector=connector)
|
|
29
|
+
# check airflow/dags for existing DAGs and skip them
|
|
30
|
+
for integration, config in connector_configs.items():
|
|
31
|
+
save_dir = f"airflow/dags/{integration.split('_')[0].lower()}"
|
|
32
|
+
integration_name = integration[integration.find("_") + 1 :]
|
|
33
|
+
# check if the directory exists, if not create it
|
|
34
|
+
check_file_path(save_dir)
|
|
35
|
+
_create_and_save_dag(
|
|
36
|
+
model=model,
|
|
37
|
+
integration=integration,
|
|
38
|
+
config=config,
|
|
39
|
+
integration_name=integration_name,
|
|
40
|
+
description=description,
|
|
41
|
+
save_dir=save_dir,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _create_and_save_dag(
|
|
46
|
+
model: "SynqlyModel", integration: str, config: dict, integration_name: str, description: str, save_dir: str
|
|
47
|
+
) -> None:
|
|
48
|
+
"""
|
|
49
|
+
Create and save a DAG for the given integration
|
|
50
|
+
|
|
51
|
+
:param SynqlyModel model: The model to use for the DAG
|
|
52
|
+
:param str integration: The integration to create the DAG for
|
|
53
|
+
:param dict config: The config for the integration
|
|
54
|
+
:param str integration_name: The name of the integration
|
|
55
|
+
:param str description: The description for the DAG
|
|
56
|
+
:param str save_dir: The directory to save the DAG to
|
|
57
|
+
:rtype: None
|
|
58
|
+
"""
|
|
59
|
+
import re
|
|
60
|
+
|
|
61
|
+
capabilities = config.get("capabilities", [])
|
|
62
|
+
op_kwargs = ""
|
|
63
|
+
doc_string = f"{description}\nimage: {integration.split('_')[0]}.jpg\ndocs: None\n"
|
|
64
|
+
# replace the integration config with a flattened version
|
|
65
|
+
config = model._flatten_secrets(integration=integration, return_secrets=True)
|
|
66
|
+
for param_type in ["expected_params", "optional_params", "required_secrets"]:
|
|
67
|
+
op_kwargs, doc_string = _build_op_kwargs_and_docstring(
|
|
68
|
+
config=config,
|
|
69
|
+
integration=integration,
|
|
70
|
+
param_type=param_type,
|
|
71
|
+
op_kwargs=op_kwargs,
|
|
72
|
+
doc_string=doc_string,
|
|
73
|
+
capabilities=capabilities,
|
|
74
|
+
)
|
|
75
|
+
# add config to op_kwargs
|
|
76
|
+
op_kwargs += '\n "config": "{{ dag_run.conf }}",'
|
|
77
|
+
# this indent is important to keep the code valid python
|
|
78
|
+
dag_code = f"""
|
|
79
|
+
from airflow import DAG
|
|
80
|
+
|
|
81
|
+
from regscale.airflow.config import DEFAULT_ARGS, yesterday
|
|
82
|
+
from regscale.airflow.hierarchy import AIRFLOW_CLICK_OPERATORS as OPERATORS
|
|
83
|
+
from regscale.airflow.tasks.groups import email_on_fail_operator
|
|
84
|
+
|
|
85
|
+
DAG_NAME = "{integration}"
|
|
86
|
+
|
|
87
|
+
dag = DAG(
|
|
88
|
+
DAG_NAME,
|
|
89
|
+
default_args=DEFAULT_ARGS,
|
|
90
|
+
schedule_interval=None,
|
|
91
|
+
start_date=yesterday(),
|
|
92
|
+
description=__doc__,
|
|
93
|
+
is_paused_upon_creation=False,
|
|
94
|
+
render_template_as_native_obj=True,
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
integration_operator = OPERATORS["{integration.split('_')[0].lower()}__sync_{integration_name.lower()}"]["lambda"](
|
|
98
|
+
dag=dag,
|
|
99
|
+
suffix=DAG_NAME,
|
|
100
|
+
op_kwargs={{{op_kwargs}\n }},
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
email = email_on_fail_operator(dag, email_tag=DAG_NAME)
|
|
104
|
+
|
|
105
|
+
integration_operator >> email
|
|
106
|
+
"""
|
|
107
|
+
with open(f"{save_dir}/{integration_name.lower()}.py", "w") as f:
|
|
108
|
+
f.write("# flake8: noqa E501\n# pylint: disable=line-too-long\n")
|
|
109
|
+
f.write('"""')
|
|
110
|
+
# replace all instances of "synqly" with the integration name
|
|
111
|
+
f.write(re.sub(r"(?i)synqly", integration_name, doc_string))
|
|
112
|
+
f.write('"""\n')
|
|
113
|
+
f.write("# pylint: enable=line-too-long\n")
|
|
114
|
+
# replace all instances of "synqly" with the integration name
|
|
115
|
+
f.write(re.sub(r"(?i)synqly", integration_name, dag_code))
|
|
116
|
+
print(f"Generated DAG for {integration_name}.")
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _build_description(configs: dict[str, dict], connector: str) -> str:
|
|
120
|
+
"""
|
|
121
|
+
Build the description for the DAG
|
|
122
|
+
|
|
123
|
+
:param dict[str, dict] configs: The configs for the integrations
|
|
124
|
+
:return: The description for the DAG
|
|
125
|
+
:rtype: str
|
|
126
|
+
"""
|
|
127
|
+
sync_attachments = []
|
|
128
|
+
integrations = []
|
|
129
|
+
for integration, config in configs.items():
|
|
130
|
+
integration_name = integration.replace(f"{connector.lower()}_", "").replace("_", " ").title()
|
|
131
|
+
integrations.append(integration_name)
|
|
132
|
+
capabilities = config.get("capabilities", [])
|
|
133
|
+
if (
|
|
134
|
+
connector == ConnectorType.Ticketing
|
|
135
|
+
and "create_attachment" in capabilities
|
|
136
|
+
and "download_attachment" in capabilities
|
|
137
|
+
):
|
|
138
|
+
sync_attachments.append(integration_name)
|
|
139
|
+
description = f"Sync {connector.capitalize()} data between {', '.join(integrations)} and RegScale data."
|
|
140
|
+
if sync_attachments:
|
|
141
|
+
description += f" You are also able to sync attachments between {', '.join(sync_attachments)} and RegScale."
|
|
142
|
+
return description
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def _build_op_kwargs_and_docstring(
|
|
146
|
+
config: dict, integration: str, param_type: str, op_kwargs: str, doc_string: str, capabilities: list[str]
|
|
147
|
+
) -> tuple[str, str]:
|
|
148
|
+
"""
|
|
149
|
+
Build the op_kwargs and docstring for the DAG
|
|
150
|
+
|
|
151
|
+
:param dict config: The config for the integration
|
|
152
|
+
:param str integration: The name of the integration, typically connector_integration
|
|
153
|
+
:param str param_type: The type of parameter to build
|
|
154
|
+
:param str op_kwargs: The op_kwargs to add to the DAG
|
|
155
|
+
:param str doc_string: The docstring to add to the DAG
|
|
156
|
+
:param list[str] capabilities: The capabilities of the integration
|
|
157
|
+
:return: The op_kwargs and docstring
|
|
158
|
+
:rtype: tuple[str, str]
|
|
159
|
+
"""
|
|
160
|
+
proper_type = param_type.replace("_", " ").title()
|
|
161
|
+
op_kwargs, doc_string = _build_expected_params(
|
|
162
|
+
param_type=param_type,
|
|
163
|
+
integration=integration,
|
|
164
|
+
op_kwargs=op_kwargs,
|
|
165
|
+
doc_string=doc_string,
|
|
166
|
+
capabilities=capabilities,
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
if ConnectorType.Vulnerabilities.lower() in integration and param_type == "optional_params":
|
|
170
|
+
if param_type == "optional_params" and ConnectorType.Vulnerabilities in integration:
|
|
171
|
+
vuln_params: dict[str, Param] = {
|
|
172
|
+
"vuln_filter": Param(
|
|
173
|
+
name="vuln_filter",
|
|
174
|
+
type="choice",
|
|
175
|
+
description="Filter the vulnerabilities for the selected severity. (Options: critical, high, medium, low, info)",
|
|
176
|
+
default=None,
|
|
177
|
+
),
|
|
178
|
+
"scan_date": Param(
|
|
179
|
+
name="scan_date",
|
|
180
|
+
type="string",
|
|
181
|
+
description="The date of the scan to sync vulnerabilities into RegScale.",
|
|
182
|
+
default="Critical",
|
|
183
|
+
),
|
|
184
|
+
"all_scans": Param(
|
|
185
|
+
name="all_scans",
|
|
186
|
+
type="boolean",
|
|
187
|
+
description="Whether to sync all vulnerabilities into RegScale.",
|
|
188
|
+
default=False,
|
|
189
|
+
),
|
|
190
|
+
}
|
|
191
|
+
config[param_type] = {**config[param_type], **vuln_params}
|
|
192
|
+
if config.get(param_type):
|
|
193
|
+
if proper_type not in doc_string:
|
|
194
|
+
doc_string += f"{proper_type}:\n"
|
|
195
|
+
for param in config[param_type]:
|
|
196
|
+
op_kwargs, doc_string = _build_other_params(
|
|
197
|
+
config=config,
|
|
198
|
+
param=param,
|
|
199
|
+
param_type=param_type,
|
|
200
|
+
proper_type=proper_type,
|
|
201
|
+
integration=integration,
|
|
202
|
+
op_kwargs=op_kwargs,
|
|
203
|
+
doc_string=doc_string,
|
|
204
|
+
)
|
|
205
|
+
return op_kwargs, doc_string
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def _build_expected_params(
|
|
209
|
+
param_type: str, integration: str, op_kwargs: str, doc_string: str, capabilities: list[str]
|
|
210
|
+
) -> tuple[str, str]:
|
|
211
|
+
"""
|
|
212
|
+
Build the expected params for the DAG and add them to the op_kwargs and docstring
|
|
213
|
+
|
|
214
|
+
:param str param_type: The type of parameter to build
|
|
215
|
+
:param str integration: The name of the integration, typically connector_integration
|
|
216
|
+
:param str op_kwargs: The op_kwargs to add to the DAG
|
|
217
|
+
:param str doc_string: The docstring to add to the DAG
|
|
218
|
+
:param list[str] capabilities: The capabilities of the integration
|
|
219
|
+
:return: The op_kwargs and docstring
|
|
220
|
+
:rtype: tuple[str, str]
|
|
221
|
+
"""
|
|
222
|
+
if param_type == "expected_params" and ConnectorType.Ticketing in integration:
|
|
223
|
+
regscale_id_jinja = "'regscale_id'"
|
|
224
|
+
regscale_module_jinja = "'regscale_module'"
|
|
225
|
+
op_kwargs += f'\n "regscale_id": "{{{{ dag_run.conf[{regscale_id_jinja}] }}}}",'
|
|
226
|
+
op_kwargs += f'\n "regscale_module": "{{{{ dag_run.conf[{regscale_module_jinja}] }}}}",'
|
|
227
|
+
doc_string += "Expected Params:\n"
|
|
228
|
+
doc_string += " regscale_id: INTEGER ID from RegScale of the RegScale object\n"
|
|
229
|
+
doc_string += " regscale_module: STRING name of the RegScale module to use with the provided ID\n"
|
|
230
|
+
op_kwargs, doc_string = add_connector_specific_params(capabilities, integration, op_kwargs, doc_string)
|
|
231
|
+
elif param_type == "expected_params":
|
|
232
|
+
regscale_ssp_id_jinja = "'regscale_ssp_id'"
|
|
233
|
+
op_kwargs += f'\n "regscale_ssp_id": "{{{{ dag_run.conf[{regscale_ssp_id_jinja}] }}}}",'
|
|
234
|
+
doc_string += "Expected Params:\n"
|
|
235
|
+
doc_string += " regscale_ssp_id: INTEGER ID from RegScale of the System Security Plan\n"
|
|
236
|
+
op_kwargs, doc_string = add_connector_specific_params(capabilities, integration, op_kwargs, doc_string)
|
|
237
|
+
return op_kwargs, doc_string
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def _build_other_params(
|
|
241
|
+
config: dict, param: str, param_type: str, proper_type: str, integration: str, op_kwargs: str, doc_string: str
|
|
242
|
+
) -> tuple[str, str]:
|
|
243
|
+
"""
|
|
244
|
+
Build the other params for the DAG by adding them to the op_kwargs and docstring
|
|
245
|
+
|
|
246
|
+
:param str param_type: The type of parameter to build
|
|
247
|
+
:param str integration: The name of the integration, typically connector_integration
|
|
248
|
+
:param str op_kwargs: The op_kwargs to add to the DAG
|
|
249
|
+
:param str doc_string: The docstring to add to the DAG
|
|
250
|
+
:return: The op_kwargs and docstring
|
|
251
|
+
:rtype: tuple[str, str]
|
|
252
|
+
"""
|
|
253
|
+
param_obj: Param = config[param_type][param]
|
|
254
|
+
param_name = f"{integration.lower()}_{param}" if param_type == "required_secrets" else param
|
|
255
|
+
jinja_key = f"'{param_name}'"
|
|
256
|
+
if default := param_obj.default:
|
|
257
|
+
if param_obj.data_type.lower() == "str":
|
|
258
|
+
jinja_default = f"'{default}'"
|
|
259
|
+
else:
|
|
260
|
+
jinja_default = default
|
|
261
|
+
else:
|
|
262
|
+
jinja_default = None
|
|
263
|
+
if param_type == "optional_params":
|
|
264
|
+
op_kwargs += f'\n "{param_name}": "{{{{ dag_run.conf[{jinja_key}] if {jinja_key} in dag_run.conf else {jinja_default} }}}}",'
|
|
265
|
+
doc_string += f" {param_name}: {param_obj.expected_type.upper()} {param_obj.description} {f'(Default: {param_obj.default})' if 'Options' not in param_obj.description else ''}\n"
|
|
266
|
+
else:
|
|
267
|
+
op_kwargs += f'\n "{param_name}": "{{{{ dag_run.conf[{jinja_key}] }}}}",'
|
|
268
|
+
doc_string += f" {param_name}: {param_obj.expected_type.upper()} {param_obj.description or proper_type}\n"
|
|
269
|
+
return op_kwargs, doc_string
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
def add_connector_specific_params(
|
|
273
|
+
capabilities: list[str], integration: str, op_kwargs: str, doc_string: str
|
|
274
|
+
) -> tuple[str, str]:
|
|
275
|
+
"""
|
|
276
|
+
Updated the op_kwargs and docstring for the DAG to include specific params for the connector based on capabilities
|
|
277
|
+
|
|
278
|
+
:param list[str] capabilities: The capabilities of the integration
|
|
279
|
+
:param str integration: The name of the integration, typically connector_integration
|
|
280
|
+
:param str op_kwargs: The op_kwargs to add to the DAG
|
|
281
|
+
:param str doc_string: The docstring to add to the DAG
|
|
282
|
+
:return: The updated op_kwargs and docstring
|
|
283
|
+
:rtype: tuple[str, str]
|
|
284
|
+
"""
|
|
285
|
+
if (
|
|
286
|
+
ConnectorType.Ticketing in integration
|
|
287
|
+
and "create_attachment" in capabilities
|
|
288
|
+
and "download_attachment" in capabilities
|
|
289
|
+
):
|
|
290
|
+
sync_attachments_jinja = "'sync_attachments'"
|
|
291
|
+
op_kwargs += f'\n "sync_attachments": "{{{{ dag_run.conf[{sync_attachments_jinja}] if {sync_attachments_jinja} in dag_run.conf else False }}}}",'
|
|
292
|
+
doc_string += " sync_attachments: BOOLEAN Whether to sync attachments between integration and RegScale\n"
|
|
293
|
+
return op_kwargs, doc_string
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
def generate_click_connectors() -> None:
|
|
297
|
+
"""Generate Click Connectors for the RegScale CLI"""
|
|
298
|
+
from regscale.core.app.utils.app_utils import check_file_path
|
|
299
|
+
from regscale.models.integration_models.synqly_models.synqly_model import SynqlyModel
|
|
300
|
+
|
|
301
|
+
model = SynqlyModel()
|
|
302
|
+
configs = model._get_integrations_and_secrets(True)
|
|
303
|
+
# iterate through connectors and generate DAGs
|
|
304
|
+
for connector in SUPPORTED_CONNECTORS:
|
|
305
|
+
save_dir = "regscale/integrations/commercial/synqly"
|
|
306
|
+
check_file_path(save_dir)
|
|
307
|
+
connector_configs = {
|
|
308
|
+
integration: configs[integration] for integration in configs if connector in integration.lower()
|
|
309
|
+
}
|
|
310
|
+
# sort the connector configs by the key for repeatability
|
|
311
|
+
connector_configs = dict(sorted(connector_configs.items()))
|
|
312
|
+
# check airflow/dags for existing DAGs and skip them
|
|
313
|
+
_create_and_save_click_command(
|
|
314
|
+
model=model,
|
|
315
|
+
connector=connector,
|
|
316
|
+
integration_configs=connector_configs,
|
|
317
|
+
save_dir=save_dir,
|
|
318
|
+
)
|
|
319
|
+
# add the new click group to regscale.py
|
|
320
|
+
_add_command_to_regscale(connector)
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
def _create_and_save_click_command(
|
|
324
|
+
model: "SynqlyModel", connector: str, integration_configs: dict[str, dict], save_dir: str
|
|
325
|
+
) -> None:
|
|
326
|
+
"""
|
|
327
|
+
Create and save a click command for the given integration and connector
|
|
328
|
+
|
|
329
|
+
:param SynqlyModel model: The model to use for the DAG
|
|
330
|
+
:param str connector: The connector type to create click commands for
|
|
331
|
+
:param dict[str, dict] integration_configs: Dictionary containing the integration configs for the given connector
|
|
332
|
+
:param str save_dir: The directory to save the DAG to
|
|
333
|
+
:rtype: None
|
|
334
|
+
"""
|
|
335
|
+
integrations_count = 0
|
|
336
|
+
doc_string = f"{connector.capitalize()} connector commands for the RegScale CLI"
|
|
337
|
+
if connector == ConnectorType.Ticketing:
|
|
338
|
+
import_command = "from regscale.models import regscale_id, regscale_module"
|
|
339
|
+
elif connector == ConnectorType.Vulnerabilities:
|
|
340
|
+
import_command = "from datetime import datetime\nfrom regscale.models import regscale_ssp_id"
|
|
341
|
+
else:
|
|
342
|
+
import_command = "from regscale.models import regscale_ssp_id"
|
|
343
|
+
# this indent is important to keep the code valid python
|
|
344
|
+
cli_code = f"""
|
|
345
|
+
\"\"\"{doc_string}\"\"\"\n
|
|
346
|
+
import click
|
|
347
|
+
{import_command}
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
@click.group()
|
|
351
|
+
def {connector}() -> None:
|
|
352
|
+
\"\"\"{doc_string}\"\"\"
|
|
353
|
+
pass
|
|
354
|
+
"""
|
|
355
|
+
|
|
356
|
+
# replace the integration config with a flattened version
|
|
357
|
+
for integration, config in integration_configs.items():
|
|
358
|
+
capabilities = config.get("capabilities", [])
|
|
359
|
+
integration_name = integration[integration.find("_") + 1 :]
|
|
360
|
+
config = model._flatten_secrets(integration=integration, return_secrets=True)
|
|
361
|
+
click_options_and_command = _build_click_options_and_command(
|
|
362
|
+
config=config,
|
|
363
|
+
connector=connector,
|
|
364
|
+
integration_name=integration_name,
|
|
365
|
+
capabilities=capabilities,
|
|
366
|
+
)
|
|
367
|
+
cli_code += f"\n\n{click_options_and_command}"
|
|
368
|
+
integrations_count += 1
|
|
369
|
+
|
|
370
|
+
with open(f"{save_dir}/{connector.lower()}.py", "w") as f:
|
|
371
|
+
f.write("# flake8: noqa E501\n# pylint: disable=line-too-long\n")
|
|
372
|
+
f.write(cli_code)
|
|
373
|
+
f.write("# pylint: enable=line-too-long\n")
|
|
374
|
+
print(f"Generated click commands for {integrations_count} {connector} connector(s).")
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
def _build_all_params(integration_name: str, connector: str) -> tuple[list[str], list[str], list[str]]:
|
|
378
|
+
"""
|
|
379
|
+
Function to build the click options, function params, and function kwargs for the integration
|
|
380
|
+
|
|
381
|
+
:param str integration_name: The name of the integration
|
|
382
|
+
:param str connector: The connector type
|
|
383
|
+
:return: The click options, function params, and function kwargs
|
|
384
|
+
:rtype: tuple[list[str], list[str], list[str]]
|
|
385
|
+
"""
|
|
386
|
+
if connector == ConnectorType.Vulnerabilities:
|
|
387
|
+
vuln_filter_option = "@click.option(\n '--vuln_filter',\n help='Filter the vulnerabilities for the selected severity. (Options: critical, high, medium, low, info)',\n required=False,\n type=click.Choice(['critical', 'high', 'medium', 'low', 'info']),\n default=None)\n"
|
|
388
|
+
scan_date_option = f"@click.option(\n '--scan_date',\n help='The date of the scan to sync vulnerabilities from {integration_name}',\n required=False,\n type=click.DateTime(formats=['%Y-%m-%d']),\n default=None)\n"
|
|
389
|
+
all_vulns_flag = f"@click.option(\n '--all_scans',\n help='Whether to sync all vulnerabilities from {integration_name}',\n required=False,\n is_flag=True,\n default=False)\n"
|
|
390
|
+
click_options = ["@regscale_ssp_id()", vuln_filter_option, scan_date_option, all_vulns_flag]
|
|
391
|
+
function_params = ["regscale_ssp_id: int", "vuln_filter: str", "scan_date: datetime", "all_scans: bool"]
|
|
392
|
+
function_kwargs = [
|
|
393
|
+
"regscale_ssp_id=regscale_ssp_id",
|
|
394
|
+
"vuln_filter=vuln_filter",
|
|
395
|
+
"scan_date=scan_date",
|
|
396
|
+
"all_scans=all_scans",
|
|
397
|
+
]
|
|
398
|
+
elif connector == ConnectorType.Assets:
|
|
399
|
+
click_options = ["@regscale_ssp_id()"]
|
|
400
|
+
function_params = ["regscale_ssp_id: int"]
|
|
401
|
+
function_kwargs = ["regscale_ssp_id=regscale_ssp_id"]
|
|
402
|
+
else:
|
|
403
|
+
click_options = ["@regscale_id()", "@regscale_module()"]
|
|
404
|
+
function_params = ["regscale_id: int", "regscale_module: str"]
|
|
405
|
+
function_kwargs = ["regscale_id=regscale_id", "regscale_module=regscale_module"]
|
|
406
|
+
return click_options, function_params, function_kwargs
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
def _build_click_options_and_command(
|
|
410
|
+
config: dict, connector: str, integration_name: str, capabilities: list[str]
|
|
411
|
+
) -> str:
|
|
412
|
+
"""
|
|
413
|
+
Function to use the config to build the click options and command for the integration
|
|
414
|
+
|
|
415
|
+
:param dict config: The config for the integration
|
|
416
|
+
:param str connector: The connector type
|
|
417
|
+
:param str integration_name: The name of the integration
|
|
418
|
+
:param list[str] capabilities: The capabilities of the integration
|
|
419
|
+
:return: The click options as a string
|
|
420
|
+
:rtype: str
|
|
421
|
+
"""
|
|
422
|
+
doc_string_name = integration_name.replace("_", " ").title()
|
|
423
|
+
# add regscale_ssp_id as a default option
|
|
424
|
+
click_options, function_params, function_kwargs = _build_all_params(doc_string_name, connector)
|
|
425
|
+
for param_type in ["expected_params", "optional_params"]:
|
|
426
|
+
for param in config.get(param_type, []):
|
|
427
|
+
param_data = config[param_type][param]
|
|
428
|
+
if not param_data.click_type:
|
|
429
|
+
continue
|
|
430
|
+
# indentation is important to keep the code valid python
|
|
431
|
+
click_option = f"""@click.option(
|
|
432
|
+
'--{param}',
|
|
433
|
+
type={param_data.click_type},
|
|
434
|
+
help='{config[param_type][param].description}',
|
|
435
|
+
required={not param_data.optional},
|
|
436
|
+
{"prompt='" + config[param_type][param].description + "'," if not param_data.optional else ""}
|
|
437
|
+
)"""
|
|
438
|
+
function_params.append(f"{param}: {param_data.data_type}")
|
|
439
|
+
function_kwargs.append(f"{param}={param}")
|
|
440
|
+
click_options.append(click_option)
|
|
441
|
+
if (
|
|
442
|
+
ConnectorType.Ticketing == connector
|
|
443
|
+
and "create_attachment" in capabilities
|
|
444
|
+
and "download_attachment" in capabilities
|
|
445
|
+
):
|
|
446
|
+
click_options.append(
|
|
447
|
+
f"""@click.option(
|
|
448
|
+
'--sync_attachments',
|
|
449
|
+
type=click.BOOL,
|
|
450
|
+
help='Whether to sync attachments between {doc_string_name} and RegScale',
|
|
451
|
+
required=False,
|
|
452
|
+
default=True,
|
|
453
|
+
)"""
|
|
454
|
+
)
|
|
455
|
+
function_params.append("sync_attachments: bool")
|
|
456
|
+
function_kwargs.append("sync_attachments=sync_attachments")
|
|
457
|
+
click_options = "\n".join(click_options)
|
|
458
|
+
function_params = ", ".join(function_params)
|
|
459
|
+
# indentation is important to keep the code valid python
|
|
460
|
+
click_command = f"""@{connector}.command(name="sync_{integration_name}")
|
|
461
|
+
{click_options}
|
|
462
|
+
def sync_{integration_name}({function_params}) -> None:
|
|
463
|
+
\"\"\"Sync {connector.title()} {"data between" if connector == ConnectorType.Ticketing else "from"} {doc_string_name} {"and" if connector == ConnectorType.Ticketing else "to"} RegScale.\"\"\"
|
|
464
|
+
from regscale.models.integration_models.synqly_models.connectors import {connector.title()}
|
|
465
|
+
{connector}_{integration_name} = {connector.title()}('{integration_name}')
|
|
466
|
+
{connector}_{integration_name}.run_sync({', '.join(function_kwargs)})
|
|
467
|
+
"""
|
|
468
|
+
return click_command
|
|
469
|
+
|
|
470
|
+
|
|
471
|
+
def _add_command_to_regscale(connector: str) -> None:
|
|
472
|
+
"""
|
|
473
|
+
Add the new click group and command to the regscale.py file
|
|
474
|
+
|
|
475
|
+
:param str connector: The connector type
|
|
476
|
+
:rtype: None
|
|
477
|
+
"""
|
|
478
|
+
import_section = 'burp = import_command_with_timing(COMMERCIAL, "burp")'
|
|
479
|
+
command_section = "cli.add_command(burp) # add Burp File Integration"
|
|
480
|
+
with open("regscale/regscale.py", "r") as f:
|
|
481
|
+
regscale_code = f.read()
|
|
482
|
+
if f"{connector} =" in regscale_code:
|
|
483
|
+
print(f"{connector.title()} click commands already exists in regscale.py.")
|
|
484
|
+
return
|
|
485
|
+
import_line = f'{connector} = import_command_with_timing("regscale.integrations.commercial.synqly.{connector}", "{connector}")'
|
|
486
|
+
regscale_code = regscale_code.replace(import_section, f"{import_section}\n{import_line}")
|
|
487
|
+
regscale_code = regscale_code.replace(
|
|
488
|
+
command_section, f"{command_section}\ncli.add_command({connector}) # add {connector.capitalize()} connector"
|
|
489
|
+
)
|
|
490
|
+
with open("regscale/regscale.py", "w") as f:
|
|
491
|
+
f.write(regscale_code)
|
|
492
|
+
print(f"Added {connector} click group to regscale.py.")
|
regscale/dev/dirs.py
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""Directory paths for regscale package."""
|
|
2
|
+
|
|
3
|
+
import contextlib
|
|
4
|
+
import os
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Union, List
|
|
7
|
+
import statistics
|
|
8
|
+
|
|
9
|
+
PROFILING_DIRS = [
|
|
10
|
+
"python3.8",
|
|
11
|
+
"python3.9",
|
|
12
|
+
"python3.10",
|
|
13
|
+
"python3.11",
|
|
14
|
+
"regscale-cli",
|
|
15
|
+
"site-packages",
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def get_regscale_root(file_path: str) -> str:
|
|
20
|
+
"""Get the root directory of the regscale directory
|
|
21
|
+
|
|
22
|
+
:param str file_path: Path to a file in the regscale directory
|
|
23
|
+
:return: Path to the root directory of the regscale directory
|
|
24
|
+
:rtype: str
|
|
25
|
+
"""
|
|
26
|
+
current_file_path = os.path.abspath(file_path)
|
|
27
|
+
# start climbing the directory tree
|
|
28
|
+
current_dir_path = os.path.dirname(current_file_path)
|
|
29
|
+
# keep climbing until we find the regscale directory
|
|
30
|
+
while True:
|
|
31
|
+
last_part = os.path.basename(current_dir_path)
|
|
32
|
+
if last_part == "regscale":
|
|
33
|
+
# we found the regscale folder, get its parent
|
|
34
|
+
root_dir = os.path.dirname(current_dir_path)
|
|
35
|
+
break
|
|
36
|
+
current_dir_path = os.path.dirname(current_dir_path)
|
|
37
|
+
return root_dir
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def trim_relative_subpath(
|
|
41
|
+
path: Union[str, Path] = os.getcwd(),
|
|
42
|
+
target_paths: List[Union[str, Path]] = PROFILING_DIRS,
|
|
43
|
+
) -> str:
|
|
44
|
+
"""Trim the relative subpath from the path
|
|
45
|
+
|
|
46
|
+
:param Union[str, Path] path: The path to trim
|
|
47
|
+
:param List[Union[str, Path]] target_paths: The relative subpaths to trim
|
|
48
|
+
:return: The trimmed path
|
|
49
|
+
:rtype: str
|
|
50
|
+
"""
|
|
51
|
+
try:
|
|
52
|
+
path = Path(path)
|
|
53
|
+
except Exception:
|
|
54
|
+
return str(path)
|
|
55
|
+
if not path.is_absolute():
|
|
56
|
+
return str(path)
|
|
57
|
+
path_parts = path.parts
|
|
58
|
+
last_found_index = -1
|
|
59
|
+
for target_path in target_paths:
|
|
60
|
+
if isinstance(target_path, str):
|
|
61
|
+
target_path = Path(target_path)
|
|
62
|
+
target_parts = target_path.parts
|
|
63
|
+
for i, part in enumerate(path_parts):
|
|
64
|
+
if part in target_parts:
|
|
65
|
+
last_found_index = i
|
|
66
|
+
if last_found_index == -1:
|
|
67
|
+
return str(path)
|
|
68
|
+
else:
|
|
69
|
+
return str(Path(*path_parts[last_found_index + 1 :]))
|