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,637 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
RegScale DuroSuite Package
|
|
5
|
+
|
|
6
|
+
This module provides functionality for integrating DuroSuite with RegScale,
|
|
7
|
+
including syncing findings, assets, and performing scans.
|
|
8
|
+
"""
|
|
9
|
+
import enum
|
|
10
|
+
import logging
|
|
11
|
+
import re
|
|
12
|
+
import tempfile
|
|
13
|
+
import time
|
|
14
|
+
from typing import Optional, List, Dict, Tuple
|
|
15
|
+
|
|
16
|
+
import click
|
|
17
|
+
from rich.progress import Progress
|
|
18
|
+
|
|
19
|
+
from regscale.core.lazy_group import LazyGroup
|
|
20
|
+
from regscale.integrations.commercial.durosuite import api
|
|
21
|
+
from regscale.integrations.commercial.durosuite.variables import DuroSuiteVariables
|
|
22
|
+
from regscale.integrations.commercial.stigv2.stig_integration import StigIntegration
|
|
23
|
+
from regscale.models import regscale_ssp_id
|
|
24
|
+
|
|
25
|
+
logger = logging.getLogger("regscale")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class DuroSuiteOS(enum.IntEnum):
|
|
29
|
+
"""
|
|
30
|
+
Enum for Operating Systems
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
UBUNTU_20 = 7
|
|
34
|
+
PALO_ALTO = 8
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@click.group(
|
|
38
|
+
cls=LazyGroup,
|
|
39
|
+
lazy_subcommands={
|
|
40
|
+
"scan": "regscale.integrations.commercial.durosuite.scanner.scan",
|
|
41
|
+
"import_audit": "regscale.integrations.commercial.durosuite.scanner.cli_import_audit",
|
|
42
|
+
},
|
|
43
|
+
name="durosuite",
|
|
44
|
+
)
|
|
45
|
+
def durosuite():
|
|
46
|
+
"""
|
|
47
|
+
DuroSuite Integrations
|
|
48
|
+
"""
|
|
49
|
+
logging.basicConfig(
|
|
50
|
+
level=logging.DEBUG, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", stream=sys.stderr
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@durosuite.command(name="scan")
|
|
55
|
+
@regscale_ssp_id()
|
|
56
|
+
@click.option(
|
|
57
|
+
"--ansible_user",
|
|
58
|
+
type=str,
|
|
59
|
+
required=True,
|
|
60
|
+
help="Remote user name for device connection",
|
|
61
|
+
)
|
|
62
|
+
@click.option(
|
|
63
|
+
"--ansible_ssh_pass",
|
|
64
|
+
type=str,
|
|
65
|
+
required=True,
|
|
66
|
+
help="Remote user password for device connection",
|
|
67
|
+
)
|
|
68
|
+
@click.option(
|
|
69
|
+
"--ansible_become_pass",
|
|
70
|
+
type=str,
|
|
71
|
+
required=True,
|
|
72
|
+
help="Password for privilege escalation",
|
|
73
|
+
)
|
|
74
|
+
@click.option(
|
|
75
|
+
"--device_name",
|
|
76
|
+
type=str,
|
|
77
|
+
default="Ubuntu Server",
|
|
78
|
+
help="Name of the device to scan",
|
|
79
|
+
)
|
|
80
|
+
@click.option(
|
|
81
|
+
"--os_id",
|
|
82
|
+
type=int,
|
|
83
|
+
default=7,
|
|
84
|
+
help="ID of the operating system",
|
|
85
|
+
)
|
|
86
|
+
@click.option(
|
|
87
|
+
"--log_level",
|
|
88
|
+
type=str,
|
|
89
|
+
default="INFO",
|
|
90
|
+
help="Log level for the scan",
|
|
91
|
+
)
|
|
92
|
+
def scan(
|
|
93
|
+
regscale_ssp_id: int,
|
|
94
|
+
ansible_user: str,
|
|
95
|
+
ansible_ssh_pass: str,
|
|
96
|
+
ansible_become_pass: str,
|
|
97
|
+
device_name: str,
|
|
98
|
+
os_id: int,
|
|
99
|
+
log_level: str,
|
|
100
|
+
):
|
|
101
|
+
"""
|
|
102
|
+
Scan DuroSuite.
|
|
103
|
+
|
|
104
|
+
This function initiates a scan in DuroSuite and syncs the results to RegScale.
|
|
105
|
+
"""
|
|
106
|
+
import logging
|
|
107
|
+
import sys
|
|
108
|
+
|
|
109
|
+
logging.basicConfig(
|
|
110
|
+
level=logging.DEBUG, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", stream=sys.stderr
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
# Call durosuite_scan with the provided arguments
|
|
114
|
+
durosuite_scan(
|
|
115
|
+
host=device_name,
|
|
116
|
+
os_id=os_id,
|
|
117
|
+
regscale_ssp_id=regscale_ssp_id,
|
|
118
|
+
ansible_user=ansible_user,
|
|
119
|
+
ansible_ssh_pass=ansible_ssh_pass,
|
|
120
|
+
ansible_become_pass=ansible_become_pass,
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
@durosuite.command(name="import_audit")
|
|
125
|
+
@regscale_ssp_id()
|
|
126
|
+
@click.option(
|
|
127
|
+
"-a",
|
|
128
|
+
"--audit_id",
|
|
129
|
+
type=click.INT,
|
|
130
|
+
help="The ID of the DuroSuite audit to import",
|
|
131
|
+
prompt="Enter DuroSuite Audit ID",
|
|
132
|
+
required=True,
|
|
133
|
+
)
|
|
134
|
+
def cli_import_audit(audit_id: int, regscale_ssp_id: int) -> None:
|
|
135
|
+
"""
|
|
136
|
+
Import a specific DuroSuite audit and sync it to RegScale.
|
|
137
|
+
|
|
138
|
+
This function imports a specific audit from DuroSuite and syncs it to RegScale.
|
|
139
|
+
|
|
140
|
+
:param int audit_id: The ID of the DuroSuite audit to import.
|
|
141
|
+
:param int regscale_ssp_id: RegScale System Security Plan ID.
|
|
142
|
+
"""
|
|
143
|
+
import_audit(audit_id, regscale_ssp_id)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def get_or_create_group(ds: api.DuroSuite, os_id: int, group_name: str = None) -> api.Group:
|
|
147
|
+
"""
|
|
148
|
+
Get an existing group for the OS or create a new one.
|
|
149
|
+
|
|
150
|
+
:param api.DuroSuite ds: DuroSuite client
|
|
151
|
+
:param int os_id: Operating system ID
|
|
152
|
+
:param str group_name: Optional group name, will be generated if not provided
|
|
153
|
+
:return: Group object
|
|
154
|
+
:rtype: api.Group
|
|
155
|
+
:raises ValueError: If group creation fails
|
|
156
|
+
"""
|
|
157
|
+
groups = [group for group in ds.get_groups() if group.os_id == os_id]
|
|
158
|
+
if any(groups):
|
|
159
|
+
return groups[0]
|
|
160
|
+
|
|
161
|
+
if not group_name:
|
|
162
|
+
# Get OS name from supported systems
|
|
163
|
+
os_list = ds.get_supported_operating_systems()
|
|
164
|
+
os_name = next((os["operating_system"] for os in os_list if os["id"] == os_id), f"OS-{os_id}")
|
|
165
|
+
group_name = f"{os_name} Group"
|
|
166
|
+
|
|
167
|
+
# Set required variables based on OS
|
|
168
|
+
variables = {}
|
|
169
|
+
if os_id == 7: # Ubuntu 20.XX
|
|
170
|
+
variables = {
|
|
171
|
+
"ansible_user": DuroSuiteVariables.duroSuiteUser,
|
|
172
|
+
"ansible_ssh_pass": DuroSuiteVariables.duroSuitePassword,
|
|
173
|
+
# "ansible_become_pass": "",
|
|
174
|
+
# "remote_server_variable": "",
|
|
175
|
+
# "require_disk_encryption": False,
|
|
176
|
+
# "space_left_variable": 250000,
|
|
177
|
+
# "time_zone_variable": "UTC",
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
response = ds.add_new_group({"group_name": group_name, "os_id": os_id, "variables": variables})
|
|
181
|
+
if not response:
|
|
182
|
+
raise ValueError(f"Failed to create group for OS {os_id}")
|
|
183
|
+
|
|
184
|
+
# Get the newly created group
|
|
185
|
+
groups = [group for group in ds.get_groups() if group.os_id == os_id]
|
|
186
|
+
if not any(groups):
|
|
187
|
+
raise ValueError(f"Group was created but not found for OS {os_id}")
|
|
188
|
+
return groups[0]
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def get_or_create_template(ds: api.DuroSuite, playbook_id: int, os_id: int, group_id: int) -> api.Template:
|
|
192
|
+
"""
|
|
193
|
+
Get an existing template for the OS or create a new one.
|
|
194
|
+
|
|
195
|
+
:param api.DuroSuite ds: DuroSuite client
|
|
196
|
+
:param int playbook_id: ID of the playbook
|
|
197
|
+
:param int os_id: Operating system ID
|
|
198
|
+
:param int group_id: Group ID
|
|
199
|
+
:return: Template object
|
|
200
|
+
:rtype: api.Template
|
|
201
|
+
:raises ValueError: If template creation fails
|
|
202
|
+
"""
|
|
203
|
+
try:
|
|
204
|
+
# Get templates for the group
|
|
205
|
+
templates = ds.get_template_ids_by_group(group_id)
|
|
206
|
+
|
|
207
|
+
# Look for an existing template that matches our criteria
|
|
208
|
+
for template in templates:
|
|
209
|
+
if template.os_id == os_id and template.playbook_id == playbook_id:
|
|
210
|
+
return template
|
|
211
|
+
|
|
212
|
+
# If no matching template exists, create a new one
|
|
213
|
+
template_name = f"Template_{playbook_id}_{time.strftime('%Y%m%d_%H%M%S')}"
|
|
214
|
+
template = ds.create_template(name=template_name, os_id=os_id, playbook_id=playbook_id, group_id=group_id)
|
|
215
|
+
if template:
|
|
216
|
+
return template
|
|
217
|
+
|
|
218
|
+
raise ValueError("Failed to create template")
|
|
219
|
+
except Exception as e:
|
|
220
|
+
raise ValueError(f"Failed to create template: {e}")
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def _get_device_vars_for_os(
|
|
224
|
+
os_id: int, host: str, ansible_user: str, ansible_ssh_pass: str, ansible_become_pass: Optional[str] = None
|
|
225
|
+
) -> List[Dict[str, str]]:
|
|
226
|
+
"""
|
|
227
|
+
Get device variables based on OS type.
|
|
228
|
+
|
|
229
|
+
:param int os_id: Operating system ID
|
|
230
|
+
:param str host: Host IP or hostname
|
|
231
|
+
:param str ansible_user: Remote user name
|
|
232
|
+
:param str ansible_ssh_pass: Remote user password
|
|
233
|
+
:param Optional[str] ansible_become_pass: Privilege escalation password
|
|
234
|
+
:return: List of device variables
|
|
235
|
+
:rtype: List[Dict[str, str]]
|
|
236
|
+
"""
|
|
237
|
+
if os_id == DuroSuiteOS.UBUNTU_20:
|
|
238
|
+
return [
|
|
239
|
+
{"var_name": "ansible_host", "var_value": host},
|
|
240
|
+
{"var_name": "ansible_user", "var_value": ansible_user},
|
|
241
|
+
{"var_name": "ansible_ssh_pass", "var_value": ansible_ssh_pass},
|
|
242
|
+
{"var_name": "ansible_become_pass", "var_value": ansible_become_pass},
|
|
243
|
+
]
|
|
244
|
+
elif os_id == DuroSuiteOS.PALO_ALTO:
|
|
245
|
+
return [
|
|
246
|
+
{"var_name": "ansible_host", "var_value": host},
|
|
247
|
+
{"var_name": "pan_username", "var_value": ansible_user},
|
|
248
|
+
{"var_name": "pan_password", "var_value": ansible_ssh_pass},
|
|
249
|
+
]
|
|
250
|
+
return []
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def _needs_device_update(
|
|
254
|
+
device: api.Device, os_id: int, host: str, ansible_user: str, ansible_ssh_pass: str, ansible_become_pass: str
|
|
255
|
+
) -> Tuple[bool, List[Dict[str, str]]]:
|
|
256
|
+
"""
|
|
257
|
+
Check if device needs variable updates.
|
|
258
|
+
|
|
259
|
+
:param api.Device device: Device to check
|
|
260
|
+
:param int os_id: Operating system ID
|
|
261
|
+
:param str host: Host IP or hostname
|
|
262
|
+
:param str ansible_user: Remote user name
|
|
263
|
+
:param str ansible_ssh_pass: Remote user password
|
|
264
|
+
:param str ansible_become_pass: Privilege escalation password
|
|
265
|
+
:return: Tuple of (needs_update, vars_to_update)
|
|
266
|
+
:rtype: Tuple[bool, List[Dict[str, str]]]
|
|
267
|
+
"""
|
|
268
|
+
device_vars = {var.name: var.value for var in device.device_vars} if device.device_vars else {}
|
|
269
|
+
|
|
270
|
+
if os_id == DuroSuiteOS.UBUNTU_20:
|
|
271
|
+
if (
|
|
272
|
+
device_vars.get("ansible_host") != host
|
|
273
|
+
or device_vars.get("ansible_user") != ansible_user
|
|
274
|
+
or device_vars.get("ansible_ssh_pass") != ansible_ssh_pass
|
|
275
|
+
or device_vars.get("ansible_become_pass") != ansible_become_pass
|
|
276
|
+
):
|
|
277
|
+
return True, _get_device_vars_for_os(os_id, host, ansible_user, ansible_ssh_pass, ansible_become_pass)
|
|
278
|
+
elif os_id == DuroSuiteOS.PALO_ALTO:
|
|
279
|
+
if (
|
|
280
|
+
device_vars.get("ansible_host") != host
|
|
281
|
+
or device_vars.get("pan_username") != ansible_user
|
|
282
|
+
or device_vars.get("pan_password") != ansible_ssh_pass
|
|
283
|
+
):
|
|
284
|
+
return True, _get_device_vars_for_os(os_id, host, ansible_user, ansible_ssh_pass)
|
|
285
|
+
|
|
286
|
+
return False, []
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
def _find_matching_device(
|
|
290
|
+
devices: List[api.Device], device_name: str, os_id: int, group_id: int
|
|
291
|
+
) -> Optional[api.Device]:
|
|
292
|
+
"""
|
|
293
|
+
Find a matching device from the list.
|
|
294
|
+
|
|
295
|
+
:param List[api.Device] devices: List of devices to search
|
|
296
|
+
:param str device_name: Name of the device to find
|
|
297
|
+
:param int os_id: Operating system ID
|
|
298
|
+
:param int group_id: Group ID
|
|
299
|
+
:return: Matching device or None
|
|
300
|
+
:rtype: Optional[api.Device]
|
|
301
|
+
"""
|
|
302
|
+
for device in devices:
|
|
303
|
+
if device.name == device_name and device.os_id == os_id and any(g.id == group_id for g in device.groups):
|
|
304
|
+
return device
|
|
305
|
+
return None
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
def get_or_create_device(
|
|
309
|
+
ds: api.DuroSuite,
|
|
310
|
+
device_name: str,
|
|
311
|
+
os_id: int,
|
|
312
|
+
group_id: int,
|
|
313
|
+
host: str,
|
|
314
|
+
ansible_user: str,
|
|
315
|
+
ansible_ssh_pass: str,
|
|
316
|
+
ansible_become_pass: str,
|
|
317
|
+
) -> api.Device:
|
|
318
|
+
"""
|
|
319
|
+
Get an existing device or create a new one.
|
|
320
|
+
|
|
321
|
+
:param api.DuroSuite ds: DuroSuite client
|
|
322
|
+
:param str device_name: Name of the device
|
|
323
|
+
:param int os_id: Operating system ID
|
|
324
|
+
:param int group_id: Group ID
|
|
325
|
+
:param str host: Host IP or hostname
|
|
326
|
+
:param str ansible_user: Remote user name
|
|
327
|
+
:param str ansible_ssh_pass: Remote user password
|
|
328
|
+
:param str ansible_become_pass: Privilege escalation password
|
|
329
|
+
:return: Device object
|
|
330
|
+
:rtype: api.Device
|
|
331
|
+
:raises ValueError: If device creation fails
|
|
332
|
+
"""
|
|
333
|
+
# First try to find an existing device
|
|
334
|
+
devices = ds.get_devices()
|
|
335
|
+
if devices:
|
|
336
|
+
if device := _find_matching_device(devices, device_name, os_id, group_id):
|
|
337
|
+
# Check if device needs updates
|
|
338
|
+
needs_update, vars_to_update = _needs_device_update(
|
|
339
|
+
device, os_id, host, ansible_user, ansible_ssh_pass, ansible_become_pass
|
|
340
|
+
)
|
|
341
|
+
if needs_update:
|
|
342
|
+
ds.update_device_vars(device.id, vars_to_update)
|
|
343
|
+
return device
|
|
344
|
+
|
|
345
|
+
# If no device exists, create a new one
|
|
346
|
+
try:
|
|
347
|
+
device_vars = _get_device_vars_for_os(os_id, host, ansible_user, ansible_ssh_pass, ansible_become_pass)
|
|
348
|
+
device_data = {"name": device_name, "os_id": os_id, "group_id": group_id, "device_vars": device_vars}
|
|
349
|
+
device = ds.add_new_device(device_data)
|
|
350
|
+
if device:
|
|
351
|
+
return device
|
|
352
|
+
except Exception as e:
|
|
353
|
+
logger.error(f"Failed to create device: {e}")
|
|
354
|
+
raise ValueError(f"Failed to create device: {e}")
|
|
355
|
+
|
|
356
|
+
raise ValueError("Failed to create device")
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
def get_stigs(ds: api.DuroSuite, os_id: int) -> list:
|
|
360
|
+
"""
|
|
361
|
+
Get STIGs for the given OS.
|
|
362
|
+
|
|
363
|
+
:param DuroSuite ds: DuroSuite API client.
|
|
364
|
+
:param int os_id: ID of the operating system.
|
|
365
|
+
|
|
366
|
+
:return: List of STIGs.
|
|
367
|
+
:rtype: list
|
|
368
|
+
"""
|
|
369
|
+
try:
|
|
370
|
+
stigs = ds.get_stigs_by_os_id(os_id=os_id)
|
|
371
|
+
return stigs
|
|
372
|
+
except Exception as e:
|
|
373
|
+
logger.error(f"Failed to get STIGs: {e}")
|
|
374
|
+
raise ValueError(f"Failed to get STIGs: {e}")
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
def _wait_for_audit_completion(ds: api.DuroSuite, audit_id: int) -> None:
|
|
378
|
+
"""
|
|
379
|
+
Wait for an audit to complete or fail.
|
|
380
|
+
|
|
381
|
+
:param api.DuroSuite ds: DuroSuite client
|
|
382
|
+
:param int audit_id: ID of the audit to monitor
|
|
383
|
+
:raises ValueError: If audit fails or is cancelled
|
|
384
|
+
:raises TimeoutError: If audit times out
|
|
385
|
+
"""
|
|
386
|
+
max_retries = 30 # 5 minutes total
|
|
387
|
+
retry_count = 0
|
|
388
|
+
while retry_count < max_retries:
|
|
389
|
+
audit_status = ds.get_audit_status(audit_id)
|
|
390
|
+
if not audit_status:
|
|
391
|
+
logger.error("Failed to get audit status")
|
|
392
|
+
break
|
|
393
|
+
|
|
394
|
+
status = audit_status.status.lower() if audit_status.status else "unknown"
|
|
395
|
+
logger.info(f"Audit status: {status}")
|
|
396
|
+
|
|
397
|
+
if status.startswith("complete"):
|
|
398
|
+
logger.info("Audit completed successfully")
|
|
399
|
+
return
|
|
400
|
+
elif status.startswith("fail"):
|
|
401
|
+
error_msg = audit_status.error_message or "Unknown error"
|
|
402
|
+
logger.error(f"Audit failed: {error_msg}")
|
|
403
|
+
raise ValueError(f"Audit failed: {error_msg}")
|
|
404
|
+
elif status.startswith("cancel"):
|
|
405
|
+
logger.error("Audit was cancelled")
|
|
406
|
+
raise ValueError("Audit was cancelled")
|
|
407
|
+
|
|
408
|
+
time.sleep(10) # Wait 10 seconds before checking again
|
|
409
|
+
retry_count += 1
|
|
410
|
+
|
|
411
|
+
if retry_count >= max_retries:
|
|
412
|
+
raise TimeoutError("Audit timed out")
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
def durosuite_scan(
|
|
416
|
+
host: str,
|
|
417
|
+
os_id: int,
|
|
418
|
+
regscale_ssp_id: int,
|
|
419
|
+
ansible_user: str,
|
|
420
|
+
ansible_ssh_pass: str,
|
|
421
|
+
ansible_become_pass: str,
|
|
422
|
+
device_name: Optional[str] = None,
|
|
423
|
+
progress: Optional[Progress] = None,
|
|
424
|
+
) -> None:
|
|
425
|
+
"""
|
|
426
|
+
Perform a DuroSuite scan and import the results to RegScale.
|
|
427
|
+
|
|
428
|
+
:param str host: Name of the device to scan
|
|
429
|
+
:param int os_id: ID of the operating system
|
|
430
|
+
:param int regscale_ssp_id: RegScale System Security Plan ID
|
|
431
|
+
:param str ansible_user: Remote user name for device connection
|
|
432
|
+
:param str ansible_ssh_pass: Remote user password for device connection
|
|
433
|
+
:param str ansible_become_pass: Password for privilege escalation
|
|
434
|
+
:param Optional[str] device_name: Optional name of the device
|
|
435
|
+
:param Optional[Progress] progress: Optional progress object to use instead of creating a new one
|
|
436
|
+
"""
|
|
437
|
+
# Get DuroSuite variables from init.yaml
|
|
438
|
+
base_url = DuroSuiteVariables.duroSuiteURL
|
|
439
|
+
username = DuroSuiteVariables.duroSuiteUser
|
|
440
|
+
password = DuroSuiteVariables.duroSuitePassword
|
|
441
|
+
|
|
442
|
+
# Determine if the host is an IP address or a FQDN
|
|
443
|
+
if re.match(r"^\d{1,3}(\.\d{1,3}){3}$", host):
|
|
444
|
+
device_ip = host
|
|
445
|
+
else:
|
|
446
|
+
device_ip = None
|
|
447
|
+
device_name = host
|
|
448
|
+
|
|
449
|
+
# Initialize DuroSuite API client with DuroSuite API credentials
|
|
450
|
+
ds = api.DuroSuite(base_url, username, password)
|
|
451
|
+
|
|
452
|
+
try:
|
|
453
|
+
# Initialize DuroSuite client
|
|
454
|
+
ds.login(username, password)
|
|
455
|
+
logger.debug("DuroSuite API client initialized")
|
|
456
|
+
|
|
457
|
+
# Get or create group
|
|
458
|
+
group = get_or_create_group(ds, os_id)
|
|
459
|
+
if not group:
|
|
460
|
+
logger.error("Failed to get or create group")
|
|
461
|
+
raise ValueError("Failed to get or create group")
|
|
462
|
+
|
|
463
|
+
logger.info(f"Using group: {group}")
|
|
464
|
+
|
|
465
|
+
# Create device
|
|
466
|
+
device = get_or_create_device(
|
|
467
|
+
ds,
|
|
468
|
+
host,
|
|
469
|
+
os_id,
|
|
470
|
+
group.id,
|
|
471
|
+
host,
|
|
472
|
+
ansible_user,
|
|
473
|
+
ansible_ssh_pass,
|
|
474
|
+
ansible_become_pass,
|
|
475
|
+
)
|
|
476
|
+
logger.info(f"Device created: {host}")
|
|
477
|
+
|
|
478
|
+
# Get STIG
|
|
479
|
+
stigs = get_stigs(ds, os_id)
|
|
480
|
+
|
|
481
|
+
# Get or create template
|
|
482
|
+
template = get_or_create_template(ds, stigs[0].id, os_id, group.id)
|
|
483
|
+
if not template:
|
|
484
|
+
logger.error("Failed to get or create template")
|
|
485
|
+
raise ValueError("Failed to get or create template")
|
|
486
|
+
logger.info(f"Template: {template}")
|
|
487
|
+
|
|
488
|
+
# Start audit
|
|
489
|
+
audit = ds.audit_device(device.id, group.id, stigs[0].id, template.id)
|
|
490
|
+
if not audit:
|
|
491
|
+
logger.error("Failed to start audit")
|
|
492
|
+
raise ValueError("Failed to start audit")
|
|
493
|
+
logger.info(f"Started audit: {audit}")
|
|
494
|
+
|
|
495
|
+
# Wait for audit completion and import results
|
|
496
|
+
try:
|
|
497
|
+
_wait_for_audit_completion(ds, audit.audit_id)
|
|
498
|
+
import_audit(
|
|
499
|
+
audit.audit_id, regscale_ssp_id, progress=progress, device_name=device_name, device_ip=device_ip
|
|
500
|
+
)
|
|
501
|
+
logger.info(f"Successfully imported audit {audit.audit_id} to RegScale SSP {regscale_ssp_id}")
|
|
502
|
+
except Exception as e:
|
|
503
|
+
logger.error(f"Failed to import audit results: {e}")
|
|
504
|
+
raise
|
|
505
|
+
|
|
506
|
+
except Exception as e:
|
|
507
|
+
logger.error(f"Failed to scan device: {e}")
|
|
508
|
+
raise
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
def _wait_for_audit_completion_and_checklist(ds: api.DuroSuite, audit_id: int) -> str:
|
|
512
|
+
"""
|
|
513
|
+
Wait for audit completion and retrieve the checklist file.
|
|
514
|
+
|
|
515
|
+
:param api.DuroSuite ds: DuroSuite client
|
|
516
|
+
:param int audit_id: The ID of the audit
|
|
517
|
+
:return: The checklist file content
|
|
518
|
+
:rtype: str
|
|
519
|
+
:raises TimeoutError: If waiting for checklist times out
|
|
520
|
+
"""
|
|
521
|
+
# Wait for the audit to complete
|
|
522
|
+
finished = False
|
|
523
|
+
while not finished:
|
|
524
|
+
response = ds.get_audit_record(audit_id=audit_id)
|
|
525
|
+
if response:
|
|
526
|
+
logger.info(f"Audit Status for {audit_id}: {response['status']}")
|
|
527
|
+
if response["status"].lower() == "complete":
|
|
528
|
+
finished = True
|
|
529
|
+
time.sleep(5)
|
|
530
|
+
|
|
531
|
+
# Retrieve the checklist file
|
|
532
|
+
checklist_file: Optional[str] = None
|
|
533
|
+
attempts = 0
|
|
534
|
+
max_attempts = 12 # 1 minute total wait time
|
|
535
|
+
while not checklist_file and attempts < max_attempts:
|
|
536
|
+
logger.info(f"Waiting for checklist file for {audit_id}")
|
|
537
|
+
checklist_file = ds.get_checklist_file_by_audit_id(audit_id)
|
|
538
|
+
time.sleep(5)
|
|
539
|
+
attempts += 1
|
|
540
|
+
|
|
541
|
+
if not checklist_file:
|
|
542
|
+
raise TimeoutError(f"Timed out waiting for checklist file for audit {audit_id}")
|
|
543
|
+
|
|
544
|
+
return checklist_file
|
|
545
|
+
|
|
546
|
+
|
|
547
|
+
def _update_xml_element(asset: "ET.Element", element_name: str, value: str) -> None:
|
|
548
|
+
"""
|
|
549
|
+
Update or create an XML element with the given value.
|
|
550
|
+
|
|
551
|
+
:param ET.Element asset: The asset element to update
|
|
552
|
+
:param str element_name: Name of the element to update
|
|
553
|
+
:param str value: Value to set
|
|
554
|
+
"""
|
|
555
|
+
element = asset.find(element_name)
|
|
556
|
+
if element is not None:
|
|
557
|
+
if not element.text:
|
|
558
|
+
element.text = value
|
|
559
|
+
else:
|
|
560
|
+
element = ET.SubElement(asset, element_name)
|
|
561
|
+
element.text = value
|
|
562
|
+
|
|
563
|
+
|
|
564
|
+
def _update_checklist_device_info(checklist_content: str, device_name: Optional[str], device_ip: Optional[str]) -> str:
|
|
565
|
+
"""
|
|
566
|
+
Update the checklist XML with device information.
|
|
567
|
+
|
|
568
|
+
:param str checklist_content: Original checklist content
|
|
569
|
+
:param Optional[str] device_name: Device name to add
|
|
570
|
+
:param Optional[str] device_ip: Device IP to add
|
|
571
|
+
:return: Updated checklist content
|
|
572
|
+
:rtype: str
|
|
573
|
+
"""
|
|
574
|
+
if not (device_name or device_ip):
|
|
575
|
+
return checklist_content
|
|
576
|
+
|
|
577
|
+
import xml.etree.ElementTree as ET
|
|
578
|
+
|
|
579
|
+
root = ET.fromstring(checklist_content)
|
|
580
|
+
asset = root.find(".//ASSET")
|
|
581
|
+
|
|
582
|
+
if asset is not None:
|
|
583
|
+
if device_name:
|
|
584
|
+
_update_xml_element(asset, "HOST_NAME", device_name)
|
|
585
|
+
|
|
586
|
+
if device_ip:
|
|
587
|
+
_update_xml_element(asset, "HOST_IP", device_ip)
|
|
588
|
+
# If no FQDN is set, generate one from the IP
|
|
589
|
+
_update_xml_element(asset, "HOST_FQDN", device_ip)
|
|
590
|
+
|
|
591
|
+
return ET.tostring(root, encoding="unicode")
|
|
592
|
+
|
|
593
|
+
|
|
594
|
+
def import_audit(
|
|
595
|
+
audit_id: int,
|
|
596
|
+
regscale_ssp_id: int,
|
|
597
|
+
progress: Optional[Progress] = None,
|
|
598
|
+
device_name: Optional[str] = None,
|
|
599
|
+
device_ip: Optional[str] = None,
|
|
600
|
+
) -> None:
|
|
601
|
+
"""
|
|
602
|
+
Import a DuroSuite audit and sync it to RegScale.
|
|
603
|
+
|
|
604
|
+
:param int audit_id: The ID of the audit to import.
|
|
605
|
+
:param int regscale_ssp_id: The ID of the RegScale SSP.
|
|
606
|
+
:param Optional[Progress] progress: Optional progress object to use instead of creating a new one
|
|
607
|
+
:param Optional[str] device_name: The name of the device
|
|
608
|
+
:param Optional[str] device_ip: The IP address of the device
|
|
609
|
+
"""
|
|
610
|
+
# Get DuroSuite credentials from init.yaml
|
|
611
|
+
base_url = DuroSuiteVariables.duroSuiteURL
|
|
612
|
+
username = DuroSuiteVariables.duroSuiteUser
|
|
613
|
+
password = DuroSuiteVariables.duroSuitePassword
|
|
614
|
+
|
|
615
|
+
ds = api.DuroSuite(base_url, username, password)
|
|
616
|
+
|
|
617
|
+
try:
|
|
618
|
+
# Wait for audit completion and get checklist
|
|
619
|
+
checklist_content = _wait_for_audit_completion_and_checklist(ds, audit_id)
|
|
620
|
+
|
|
621
|
+
# Update checklist with device information if provided
|
|
622
|
+
checklist_content = _update_checklist_device_info(checklist_content, device_name, device_ip)
|
|
623
|
+
|
|
624
|
+
logger.info(f"Processed checklist file for audit {audit_id}")
|
|
625
|
+
|
|
626
|
+
# Process the checklist file
|
|
627
|
+
with tempfile.NamedTemporaryFile(mode="w+", suffix=".ckl", delete=True) as tmp_file:
|
|
628
|
+
tmp_file.write(checklist_content)
|
|
629
|
+
tmp_file_path = tmp_file.name
|
|
630
|
+
|
|
631
|
+
# Sync the assets and findings
|
|
632
|
+
StigIntegration.sync_assets(plan_id=regscale_ssp_id, path=tmp_file_path, progress=progress) # type: ignore
|
|
633
|
+
StigIntegration.sync_findings(plan_id=regscale_ssp_id, path=tmp_file_path, progress=progress) # type: ignore
|
|
634
|
+
|
|
635
|
+
except Exception as e:
|
|
636
|
+
logger.error(f"Failed to import audit: {e}")
|
|
637
|
+
raise
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""DuroSuite Variables"""
|
|
4
|
+
|
|
5
|
+
from regscale.core.app.utils.variables import RsVariableType, RsVariablesMeta
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class DuroSuiteVariables(metaclass=RsVariablesMeta):
|
|
9
|
+
"""
|
|
10
|
+
DuroSuite Variables class to define class-level attributes with type annotations and examples
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
# Define class-level attributes with type annotations and examples
|
|
14
|
+
duroSuiteURL: RsVariableType(str, "https://example.com") # type: ignore # noqa: F722
|
|
15
|
+
duroSuiteUser: RsVariableType(str, "user") # type: ignore # noqa: F722,F821
|
|
16
|
+
duroSuitePassword: RsVariableType(str, "password", sensitive=True) # type: ignore # noqa: F722,F821
|
|
17
|
+
duroSuiteDemoHost: RsVariableType(str, "ip_address") # type: ignore # noqa: F722,F821
|
|
18
|
+
# Palo Alto device credentials
|
|
19
|
+
duroSuitePaloAltoUser: RsVariableType(str, "admin", required=False) # type: ignore # noqa: F722,F821
|
|
20
|
+
duroSuitePaloAltoPassword: RsVariableType(str, "password", sensitive=True, required=False) # type: ignore # noqa: F722,F821
|
|
21
|
+
duroSuiteEnabled: RsVariableType(bool, "true", default=False) # type: ignore # noqa: F722,F821
|