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
|
File without changes
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""RegScale Azure Integrations"""
|
|
4
|
+
import os
|
|
5
|
+
import msal
|
|
6
|
+
from regscale.core.app.application import Application
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def get_token(app: Application) -> str:
|
|
10
|
+
"""
|
|
11
|
+
Fetch Azure AD Token
|
|
12
|
+
|
|
13
|
+
:param Application app: The application
|
|
14
|
+
:rtype: str
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
scope = ["https://graph.microsoft.com/.default"]
|
|
18
|
+
try:
|
|
19
|
+
azure_tenant_id = os.environ["AZURE_TENANT_ID"]
|
|
20
|
+
client_id = os.environ["AZURE_CLIENT_ID"]
|
|
21
|
+
client_secret = os.environ["AZURE_CLIENT_SECRET"]
|
|
22
|
+
except KeyError:
|
|
23
|
+
# Azure environment is not set, use init.yaml
|
|
24
|
+
client_id = app.config["azureCloudClientId"]
|
|
25
|
+
client_secret = app.config["azureCloudSecret"]
|
|
26
|
+
azure_tenant_id = app.config["azureCloudTenantId"]
|
|
27
|
+
authority = f"https://login.microsoftonline.com/{azure_tenant_id}"
|
|
28
|
+
client = msal.ConfidentialClientApplication(client_id, authority=authority, client_credential=client_secret)
|
|
29
|
+
token_result = client.acquire_token_for_client(scopes=scope)
|
|
30
|
+
token = token_result["access_token"]
|
|
31
|
+
|
|
32
|
+
return token
|
|
@@ -0,0 +1,488 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""RegScale Azure InTune Integration"""
|
|
4
|
+
import json
|
|
5
|
+
import logging
|
|
6
|
+
import re
|
|
7
|
+
from datetime import datetime, timedelta
|
|
8
|
+
from time import sleep
|
|
9
|
+
from typing import Iterator, Optional
|
|
10
|
+
|
|
11
|
+
import click
|
|
12
|
+
import requests
|
|
13
|
+
import rich.progress
|
|
14
|
+
|
|
15
|
+
from regscale.core.app.api import Api
|
|
16
|
+
from regscale.core.app.application import Application
|
|
17
|
+
from regscale.core.app.utils.api_handler import APIHandler
|
|
18
|
+
from regscale.core.app.utils.app_utils import create_progress_object, error_and_exit
|
|
19
|
+
from regscale.core.app.utils.regscale_utils import verify_provided_module
|
|
20
|
+
from regscale.integrations.scanner_integration import IntegrationAsset, IntegrationFinding
|
|
21
|
+
from regscale.models import Asset, Sbom, regscale_id, regscale_models, regscale_module
|
|
22
|
+
from regscale.models.integration_models.sbom.cyclone_dx import CycloneDXJsonGenerator
|
|
23
|
+
from regscale.validation.record import validate_regscale_object
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@click.group()
|
|
27
|
+
def intune():
|
|
28
|
+
"""Microsoft Azure InTune Integrations"""
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@intune.command(name="sync_intune")
|
|
32
|
+
@regscale_id()
|
|
33
|
+
@regscale_module()
|
|
34
|
+
def sync_intune(regscale_id: int, regscale_module: str):
|
|
35
|
+
"""Sync Intune Alerts with RegScale Assets."""
|
|
36
|
+
|
|
37
|
+
from regscale.integrations.commercial.azure.scanner import IntuneIntegration
|
|
38
|
+
|
|
39
|
+
verify_provided_module(regscale_module)
|
|
40
|
+
try:
|
|
41
|
+
assert validate_regscale_object(parent_id=regscale_id, parent_module=regscale_module)
|
|
42
|
+
except AssertionError:
|
|
43
|
+
error_and_exit(
|
|
44
|
+
"This RegScale object does not exist. Please check your RegScale Parent ID \
|
|
45
|
+
and Module."
|
|
46
|
+
)
|
|
47
|
+
access_token = get_access_token(config=Application().config)
|
|
48
|
+
api = Api()
|
|
49
|
+
|
|
50
|
+
with create_progress_object() as device_progress:
|
|
51
|
+
device_task = device_progress.add_task("[#f68d1f]Fetching Device List...", total=1)
|
|
52
|
+
software_task = device_progress.add_task("[#1f96f6]Updating Software List...")
|
|
53
|
+
devices = get_device_list(api=api, access_token=access_token, device_progress=device_progress, task=device_task)
|
|
54
|
+
device_progress.update(task_id=software_task, total=len(devices))
|
|
55
|
+
for dev in devices:
|
|
56
|
+
full_data = get_device_data_by_device(api=api, access_token=access_token, device_id=dev.get("id"))
|
|
57
|
+
detected_apps = full_data.get("detectedApps")
|
|
58
|
+
if detected_apps:
|
|
59
|
+
dev["detectedApps"] = detected_apps
|
|
60
|
+
device_progress.update(task_id=software_task, advance=1)
|
|
61
|
+
|
|
62
|
+
if devices:
|
|
63
|
+
in_scan = IntuneIntegration(plan_id=regscale_id)
|
|
64
|
+
in_scan.sync_assets(
|
|
65
|
+
plan_id=regscale_id,
|
|
66
|
+
asset_num=len(devices),
|
|
67
|
+
integration_assets=fetch_intune_assets(
|
|
68
|
+
regscale_parent_id=regscale_id,
|
|
69
|
+
regscale_module=regscale_module,
|
|
70
|
+
devices=devices,
|
|
71
|
+
access_token=access_token,
|
|
72
|
+
),
|
|
73
|
+
)
|
|
74
|
+
in_scan.sync_findings(
|
|
75
|
+
plan_id=regscale_id,
|
|
76
|
+
integration_findings=fetch_intune_findings(devices=devices),
|
|
77
|
+
)
|
|
78
|
+
else:
|
|
79
|
+
click.echo("No devices found.")
|
|
80
|
+
|
|
81
|
+
update_sbom(devices=devices, parent_id=regscale_id, parent_module=regscale_module)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def check_if_phone(device: dict) -> Optional[str]:
|
|
85
|
+
"""
|
|
86
|
+
Check if the device is a phone or tablet
|
|
87
|
+
|
|
88
|
+
:param dict device: The device dictionary
|
|
89
|
+
:return: The device type
|
|
90
|
+
:rtype: Optional[str]
|
|
91
|
+
"""
|
|
92
|
+
|
|
93
|
+
if "iphone" in device["operatingSystem"].lower():
|
|
94
|
+
return "Phone"
|
|
95
|
+
if "android" in device["operatingSystem"].lower():
|
|
96
|
+
return "Phone"
|
|
97
|
+
if "ipad" in device["operatingSystem"].lower():
|
|
98
|
+
return "Tablet"
|
|
99
|
+
return None
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def determine_asset_type(device: dict) -> str:
|
|
103
|
+
"""
|
|
104
|
+
Determine the asset type
|
|
105
|
+
|
|
106
|
+
:param dict device: The device dictionary
|
|
107
|
+
:return: The asset type
|
|
108
|
+
:rtype: str
|
|
109
|
+
"""
|
|
110
|
+
asset_type = check_if_phone(device)
|
|
111
|
+
if not asset_type:
|
|
112
|
+
if device.get("operatingSystem", "").lower() in ["macmdm", "windows", "linux", "macOS"]:
|
|
113
|
+
if device.get("model") and "vm" in device.get("model", "").lower():
|
|
114
|
+
asset_type = "Virtual Machine"
|
|
115
|
+
else:
|
|
116
|
+
asset_type = "Laptop"
|
|
117
|
+
else:
|
|
118
|
+
asset_type = "Virtual Machine"
|
|
119
|
+
return asset_type
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def fetch_intune_assets(
|
|
123
|
+
regscale_parent_id: int,
|
|
124
|
+
regscale_module: str,
|
|
125
|
+
devices: list[dict],
|
|
126
|
+
access_token: str,
|
|
127
|
+
) -> Iterator[IntegrationAsset]:
|
|
128
|
+
"""
|
|
129
|
+
Fetch InTune Assets
|
|
130
|
+
|
|
131
|
+
:param int regscale_parent_id: RegScale Parent ID
|
|
132
|
+
:param str regscale_module: RegScale Module
|
|
133
|
+
:param list[dict] devices: The list of devices
|
|
134
|
+
:param str access_token: The access token
|
|
135
|
+
:yields: IntegrationAsset
|
|
136
|
+
:rtype: Iterator[IntegrationAsset]
|
|
137
|
+
"""
|
|
138
|
+
api = Api()
|
|
139
|
+
logger = logging.getLogger("regscale")
|
|
140
|
+
config = api.config
|
|
141
|
+
|
|
142
|
+
context = {
|
|
143
|
+
"regscale_parent_id": regscale_parent_id,
|
|
144
|
+
"regscale_module": regscale_module,
|
|
145
|
+
"api": api,
|
|
146
|
+
"access_token": access_token,
|
|
147
|
+
"config": config,
|
|
148
|
+
"logger": logger,
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
for device in devices:
|
|
152
|
+
try:
|
|
153
|
+
asset = create_asset(device=device, context=context)
|
|
154
|
+
if asset:
|
|
155
|
+
yield asset
|
|
156
|
+
except Exception as e:
|
|
157
|
+
logger.error(f"Error creating asset for device {device.get('deviceName')}: {e}")
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def fetch_intune_findings(devices: list[dict]) -> Iterator[IntegrationFinding]:
|
|
161
|
+
"""
|
|
162
|
+
Fetch InTune Assets
|
|
163
|
+
|
|
164
|
+
:param list[dict] devices: The list of devices
|
|
165
|
+
:yields: IntegrationAsset
|
|
166
|
+
:rtype: Iterator[IntegrationFinding]
|
|
167
|
+
"""
|
|
168
|
+
logger = logging.getLogger("regscale")
|
|
169
|
+
|
|
170
|
+
for device in devices:
|
|
171
|
+
try:
|
|
172
|
+
if asset := create_finding(device=device):
|
|
173
|
+
yield asset
|
|
174
|
+
except Exception as e:
|
|
175
|
+
logger.error(f"Error creating asset for device {device.get('deviceName')}: {e}")
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def create_finding(device: dict) -> Optional[IntegrationFinding]:
|
|
179
|
+
"""
|
|
180
|
+
Create an asset from the device dictionary
|
|
181
|
+
|
|
182
|
+
:param dict device: The device dictionary
|
|
183
|
+
:return: The finding
|
|
184
|
+
:rtype: Optional[IntegrationFinding]
|
|
185
|
+
"""
|
|
186
|
+
|
|
187
|
+
compliance = device.get("complianceState") == "compliant"
|
|
188
|
+
if not compliance:
|
|
189
|
+
# Create a finding
|
|
190
|
+
control_labels = []
|
|
191
|
+
title = ""
|
|
192
|
+
category = ""
|
|
193
|
+
plugin_name = "Intune compliance"
|
|
194
|
+
severity = regscale_models.IssueSeverity.High
|
|
195
|
+
description = "Intune Compliance Failure"
|
|
196
|
+
status = regscale_models.IssueStatus.Open
|
|
197
|
+
asset_id = device.get("azureADDeviceId")
|
|
198
|
+
return IntegrationFinding(
|
|
199
|
+
control_labels=control_labels,
|
|
200
|
+
title=title,
|
|
201
|
+
category=category,
|
|
202
|
+
plugin_name=plugin_name,
|
|
203
|
+
severity=severity,
|
|
204
|
+
description=description,
|
|
205
|
+
status=status,
|
|
206
|
+
asset_identifier=asset_id,
|
|
207
|
+
)
|
|
208
|
+
return None
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def create_asset(device: dict, context: dict) -> Optional[IntegrationAsset]:
|
|
212
|
+
"""
|
|
213
|
+
Create an asset from the device dictionary
|
|
214
|
+
|
|
215
|
+
:param dict device: The device dictionary
|
|
216
|
+
:param dict context: The context dictionary containing regscale_parent_id, regscale_module, config, and logger
|
|
217
|
+
:return: The asset
|
|
218
|
+
:rtype: Optional[IntegrationAsset]
|
|
219
|
+
"""
|
|
220
|
+
regscale_parent_id = context["regscale_parent_id"]
|
|
221
|
+
regscale_module = context["regscale_module"]
|
|
222
|
+
config = context["config"]
|
|
223
|
+
logger = context["logger"]
|
|
224
|
+
|
|
225
|
+
software_list = [
|
|
226
|
+
{"name": app.get("displayName"), "version": app.get("version")} for app in device.get("detectedApps", [])
|
|
227
|
+
]
|
|
228
|
+
|
|
229
|
+
compliance = device.get("complianceState") == "compliant"
|
|
230
|
+
if device.get("lastSyncDateTime"):
|
|
231
|
+
last_sign_in = datetime.strptime(device["lastSyncDateTime"], "%Y-%m-%dT%H:%M:%SZ")
|
|
232
|
+
status = "Active (On-Network)" if determine_if_recent(last_sign_in) or compliance else "Off-Network"
|
|
233
|
+
else:
|
|
234
|
+
status = "Off-Network"
|
|
235
|
+
asset_type = determine_asset_type(device)
|
|
236
|
+
ips = device.get("hardwareInformation", {}).get("wiredIPv4Addresses", [])
|
|
237
|
+
|
|
238
|
+
try:
|
|
239
|
+
return IntegrationAsset(
|
|
240
|
+
name=device.get("deviceName"),
|
|
241
|
+
other_tracking_number=device.get("azureADDeviceId"),
|
|
242
|
+
azure_identifier=device.get("azureADDeviceId"),
|
|
243
|
+
identifier=device.get("azureADDeviceId"),
|
|
244
|
+
parent_id=regscale_parent_id,
|
|
245
|
+
parent_module=regscale_module,
|
|
246
|
+
manufacturer=device.get("manufacturer"),
|
|
247
|
+
model=device["model"],
|
|
248
|
+
operating_system=device.get("operatingSystem"),
|
|
249
|
+
asset_owner_id=config["userId"],
|
|
250
|
+
asset_type=asset_type if asset_type else "Other",
|
|
251
|
+
asset_category=regscale_models.AssetCategory.Hardware,
|
|
252
|
+
status=status,
|
|
253
|
+
notes=f"<p>isCompliant: <strong>{compliance}</strong><br>isEncrypted: "
|
|
254
|
+
+ f"<strong>{device['isEncrypted']}</strong><br>isRooted: <strong>"
|
|
255
|
+
+ f"{device['jailBroken']}</strong><br>lastSyncDateTime: <strong>"
|
|
256
|
+
+ f"{device['lastSyncDateTime']}</strong>",
|
|
257
|
+
mac_address=convert_str_to_mac(device.get("wiFiMacAddress") or device.get("ethernetMacAddress")),
|
|
258
|
+
serial_number=device.get("serialNumber") or device.get("hardwareInformation", {}).get("serialNumber"),
|
|
259
|
+
os_version=device.get("osVersion"),
|
|
260
|
+
software_inventory=software_list,
|
|
261
|
+
ip_address=", ".join(ips),
|
|
262
|
+
)
|
|
263
|
+
except KeyError as e:
|
|
264
|
+
logger.error(f"Error creating asset: {e}")
|
|
265
|
+
return None
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
def get_access_token(config: dict) -> str:
|
|
269
|
+
"""
|
|
270
|
+
Authenticate and return an access token.
|
|
271
|
+
|
|
272
|
+
:param dict config: The configuration dictionary
|
|
273
|
+
:return: The access token
|
|
274
|
+
:rtype: str
|
|
275
|
+
"""
|
|
276
|
+
import msal
|
|
277
|
+
|
|
278
|
+
authority = f"https://login.microsoftonline.com/{config.get('azureCloudTenantId')}"
|
|
279
|
+
scope = ["https://graph.microsoft.com/.default"]
|
|
280
|
+
|
|
281
|
+
app = msal.ConfidentialClientApplication(
|
|
282
|
+
client_id=config.get("azureCloudClientId"),
|
|
283
|
+
client_credential=config.get("azureCloudSecret"),
|
|
284
|
+
authority=authority,
|
|
285
|
+
)
|
|
286
|
+
result = app.acquire_token_for_client(scopes=scope)
|
|
287
|
+
|
|
288
|
+
if "access_token" in result:
|
|
289
|
+
return result["access_token"]
|
|
290
|
+
|
|
291
|
+
error_and_exit(f"Error acquiring token: {result.get('error')}")
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
def get_device_list(
|
|
295
|
+
api: Api, access_token: str, device_progress: rich.progress.Progress, task: rich.progress.TaskID
|
|
296
|
+
) -> list[dict]:
|
|
297
|
+
"""
|
|
298
|
+
Retrieve device data from Microsoft Intune.
|
|
299
|
+
|
|
300
|
+
:param Api api: The API object
|
|
301
|
+
:param str access_token: The access token
|
|
302
|
+
:param rich.progress.Progress job_progress: The job progress object
|
|
303
|
+
:param rich.progress.TaskID task: The task ID
|
|
304
|
+
:return: The device data
|
|
305
|
+
:rtype: list[dict]
|
|
306
|
+
"""
|
|
307
|
+
url = "https://graph.microsoft.com/beta/deviceManagement/managedDevices?$expand=detectedApps"
|
|
308
|
+
headers = {"Authorization": f"Bearer {access_token}"}
|
|
309
|
+
devices = []
|
|
310
|
+
|
|
311
|
+
# Pagination to retrieve all devices
|
|
312
|
+
while url:
|
|
313
|
+
response = backoff_retry(api=api, url=url, headers=headers)
|
|
314
|
+
count = response.json().get("@odata.count")
|
|
315
|
+
if count:
|
|
316
|
+
device_progress.update(task_id=task, total=count)
|
|
317
|
+
if response.status_code == 200:
|
|
318
|
+
data = response.json()
|
|
319
|
+
devices.extend(data["value"])
|
|
320
|
+
device_progress.update(task_id=task, advance=len(response.json().get("value", [])))
|
|
321
|
+
url = data.get("@odata.nextLink") # Check for pagination
|
|
322
|
+
else:
|
|
323
|
+
error_and_exit(f"Error retrieving device data: {response.status_code}\n{response.text}")
|
|
324
|
+
|
|
325
|
+
return devices
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
def get_device_data_by_device(api: Api, access_token: str, device_id: str) -> dict:
|
|
329
|
+
"""
|
|
330
|
+
Retrieve device data from Microsoft Intune.
|
|
331
|
+
|
|
332
|
+
:param Api api: The API object
|
|
333
|
+
:param str access_token: The access token
|
|
334
|
+
:param str device_id: The device ID
|
|
335
|
+
:return: The device data
|
|
336
|
+
:rtype: dict
|
|
337
|
+
"""
|
|
338
|
+
url = f"https://graph.microsoft.com/beta/deviceManagement/managedDevices/{device_id}?$expand=detectedApps"
|
|
339
|
+
headers = {"Authorization": f"Bearer {access_token}"}
|
|
340
|
+
|
|
341
|
+
# Pagination to retrieve all devices
|
|
342
|
+
response = backoff_retry(api=api, url=url, headers=headers)
|
|
343
|
+
data = {}
|
|
344
|
+
if response.status_code == 200:
|
|
345
|
+
data = response.json()
|
|
346
|
+
else:
|
|
347
|
+
error_and_exit(f"Error retrieving device data: {response.status_code}\n{response.text}")
|
|
348
|
+
return data
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
def update_sbom_for_device(args: tuple):
|
|
352
|
+
"""
|
|
353
|
+
Update the SBOM for a device
|
|
354
|
+
|
|
355
|
+
:args: tuple containing the asset ID, device dictionary, progress object, and task ID
|
|
356
|
+
:rtype: None
|
|
357
|
+
:return: None
|
|
358
|
+
"""
|
|
359
|
+
regscale_version, fix_version, asset_id, device, progress_object, progress_task, logger = args
|
|
360
|
+
components = []
|
|
361
|
+
generator = CycloneDXJsonGenerator(device=device, logger=logger)
|
|
362
|
+
for app in device.get("detectedApps", []):
|
|
363
|
+
display_name = app.get("displayName")
|
|
364
|
+
version = app.get("version") or "Unknown"
|
|
365
|
+
app_type = "application"
|
|
366
|
+
if display_name:
|
|
367
|
+
component = {
|
|
368
|
+
"type": app_type,
|
|
369
|
+
"name": display_name,
|
|
370
|
+
"version": version,
|
|
371
|
+
}
|
|
372
|
+
components.append(component)
|
|
373
|
+
sbom = Sbom(
|
|
374
|
+
tool=device.get("deviceName"),
|
|
375
|
+
parentId=asset_id,
|
|
376
|
+
parentModule="assets",
|
|
377
|
+
name=device.get("deviceName"),
|
|
378
|
+
standardVersion=device.get("osVersion"),
|
|
379
|
+
results=json.dumps(generator.generate_sbom(components=components)),
|
|
380
|
+
sbomStandard="CycloneDX",
|
|
381
|
+
)
|
|
382
|
+
if regscale_version >= fix_version:
|
|
383
|
+
sbom.create_or_update()
|
|
384
|
+
else:
|
|
385
|
+
# Create if not exist
|
|
386
|
+
sbom.get_or_create()
|
|
387
|
+
|
|
388
|
+
# sbom.create_or_update()
|
|
389
|
+
progress_object.update(task_id=progress_task, advance=len(device.get("detectedApps", [])))
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
def update_sbom(devices: list[dict], parent_id: int, parent_module: str):
|
|
393
|
+
"""
|
|
394
|
+
Update the SBOM for devices
|
|
395
|
+
|
|
396
|
+
:param list[dict] devices: The list of devices
|
|
397
|
+
:param int parent_id: The parent ID
|
|
398
|
+
:param str parent_module: The parent module
|
|
399
|
+
:rtype: None
|
|
400
|
+
:return: None
|
|
401
|
+
"""
|
|
402
|
+
app = Application()
|
|
403
|
+
existing_assets = Asset.get_all_by_parent(parent_id=parent_id, parent_module=parent_module)
|
|
404
|
+
regscale_version = APIHandler().regscale_version
|
|
405
|
+
fix_version = "6.9.0.4"
|
|
406
|
+
if not re.match(r"^\d+\.\d+(\.\d+){0,2}$", regscale_version) or regscale_version < fix_version:
|
|
407
|
+
app.logger.warning(
|
|
408
|
+
"SBOM functionality is limited and unable to update SBOM, please update to the latest "
|
|
409
|
+
"RegScale version to resolve."
|
|
410
|
+
)
|
|
411
|
+
return
|
|
412
|
+
|
|
413
|
+
with create_progress_object() as sbom_progress:
|
|
414
|
+
total_applications = sum(len(device.get("detectedApps", [])) for device in devices)
|
|
415
|
+
sbom_task = sbom_progress.add_task("[#00ff00]Updating SBOM(s) in RegScale...", total=total_applications)
|
|
416
|
+
for device in devices:
|
|
417
|
+
matching_asset: Optional[Asset] = next(
|
|
418
|
+
(asset for asset in existing_assets if asset.azureIdentifier == device.get("azureADDeviceId")), None
|
|
419
|
+
)
|
|
420
|
+
if matching_asset:
|
|
421
|
+
app.thread_manager.submit_task(
|
|
422
|
+
func=update_sbom_for_device,
|
|
423
|
+
args=(
|
|
424
|
+
regscale_version,
|
|
425
|
+
fix_version,
|
|
426
|
+
matching_asset.id,
|
|
427
|
+
device,
|
|
428
|
+
sbom_progress,
|
|
429
|
+
sbom_task,
|
|
430
|
+
app.logger,
|
|
431
|
+
),
|
|
432
|
+
)
|
|
433
|
+
_ = app.thread_manager.execute_and_verify()
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
def determine_if_recent(date: datetime, days: int = 7) -> bool:
|
|
437
|
+
"""
|
|
438
|
+
Determine if a date is recent
|
|
439
|
+
|
|
440
|
+
:param datetime date: The date to check
|
|
441
|
+
:param int days: The number of days to consider recent
|
|
442
|
+
:return: True if the date is recent, False otherwise
|
|
443
|
+
:rtype: bool
|
|
444
|
+
"""
|
|
445
|
+
# Using three days ago as the threshold
|
|
446
|
+
days_ago = datetime.now() - timedelta(days=days)
|
|
447
|
+
return date >= days_ago
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
def convert_str_to_mac(mac: str):
|
|
451
|
+
"""
|
|
452
|
+
Convert a string to a MAC address
|
|
453
|
+
|
|
454
|
+
:param str mac: The MAC address string
|
|
455
|
+
:return: The MAC address
|
|
456
|
+
:rtype: str
|
|
457
|
+
"""
|
|
458
|
+
if mac:
|
|
459
|
+
mac = mac.replace(":", "").replace("-", "").replace(".", "").replace(" ", "").upper()
|
|
460
|
+
return ":".join(mac[i : i + 2] for i in range(0, 12, 2))
|
|
461
|
+
return None
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
def backoff_retry(api: Api, url: str, headers: dict, max_retries: int = 5, backoff_factor: int = 2):
|
|
465
|
+
"""
|
|
466
|
+
Perform a GET request with exponential backoff retry on HTTP 429.
|
|
467
|
+
|
|
468
|
+
:param Api api: The API object
|
|
469
|
+
:param str url: The URL to request
|
|
470
|
+
:param dict headers: The request headers
|
|
471
|
+
:param int max_retries: The maximum number of retries
|
|
472
|
+
:param int backoff_factor: The backoff factor (multiplier for the delay)
|
|
473
|
+
:return: The response object
|
|
474
|
+
:rtype: requests.Response
|
|
475
|
+
"""
|
|
476
|
+
retries = 0
|
|
477
|
+
response = requests.Response()
|
|
478
|
+
while retries < max_retries:
|
|
479
|
+
response = api.get(url, headers=headers)
|
|
480
|
+
if response.status_code == 429:
|
|
481
|
+
retries += 1
|
|
482
|
+
sleep_time = backoff_factor**retries
|
|
483
|
+
print(f"Rate limited. Retrying in {sleep_time} seconds...")
|
|
484
|
+
sleep(sleep_time)
|
|
485
|
+
else:
|
|
486
|
+
return response
|
|
487
|
+
response.raise_for_status()
|
|
488
|
+
return response
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Intune Integration
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
from typing import Any, Dict, Iterator
|
|
7
|
+
|
|
8
|
+
from regscale.integrations.scanner_integration import IntegrationAsset, IntegrationFinding, ScannerIntegration
|
|
9
|
+
from regscale.models import regscale_models
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger("regscale")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class IntuneIntegration(ScannerIntegration):
|
|
15
|
+
"""Integration class for Intune Device Manager."""
|
|
16
|
+
|
|
17
|
+
title: str = "Intune"
|
|
18
|
+
asset_identifier_field: str = "azureIdentifier"
|
|
19
|
+
finding_severity_map: Dict[str, regscale_models.IssueSeverity] = {
|
|
20
|
+
"critical": regscale_models.IssueSeverity.Critical,
|
|
21
|
+
"high": regscale_models.IssueSeverity.High,
|
|
22
|
+
"medium": regscale_models.IssueSeverity.Moderate,
|
|
23
|
+
"low": regscale_models.IssueSeverity.Low,
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
def fetch_assets(self, *args: Any, **kwargs: Any) -> Iterator[IntegrationAsset]:
|
|
27
|
+
"""
|
|
28
|
+
Fetches assets from Intune integration
|
|
29
|
+
|
|
30
|
+
:param Tuple args: Additional arguments
|
|
31
|
+
:param dict kwargs: Additional keyword arguments
|
|
32
|
+
:yields: Iterator[IntegrationAsset]
|
|
33
|
+
"""
|
|
34
|
+
if asset_num := kwargs.get("asset_num"):
|
|
35
|
+
self.num_assets_to_process = asset_num
|
|
36
|
+
integration_assets = kwargs.get("integration_assets")
|
|
37
|
+
yield from integration_assets
|
|
38
|
+
|
|
39
|
+
def fetch_findings(self, *args: Any, **kwargs: dict) -> Iterator[IntegrationFinding]:
|
|
40
|
+
"""
|
|
41
|
+
Fetches findings from the Intune integration
|
|
42
|
+
|
|
43
|
+
:param Tuple args: Additional arguments
|
|
44
|
+
:param dict kwargs: Additional keyword arguments
|
|
45
|
+
:yields: Iterator[IntegrationFinding]
|
|
46
|
+
|
|
47
|
+
"""
|
|
48
|
+
integration_findings = kwargs.get("integration_findings")
|
|
49
|
+
yield from integration_findings
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""Burp Scanner RegScale integration"""
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
import click
|
|
7
|
+
|
|
8
|
+
from regscale.core.app.application import Application
|
|
9
|
+
from regscale.core.app.logz import create_logger
|
|
10
|
+
from regscale.models.integration_models.burp import Burp
|
|
11
|
+
from regscale.models.integration_models.flat_file_importer import FlatFileIntegration
|
|
12
|
+
|
|
13
|
+
logger = create_logger(__name__)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# Create group to handle Burp .xml file processing
|
|
17
|
+
@click.group()
|
|
18
|
+
def burp():
|
|
19
|
+
"""Performs actions on Burp Scanner artifacts."""
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@burp.command(name="import_burp")
|
|
23
|
+
@click.option(
|
|
24
|
+
"--folder_path",
|
|
25
|
+
help="File path to the folder containing Burp files to process to RegScale.",
|
|
26
|
+
prompt="File path for Burp files",
|
|
27
|
+
type=click.Path(exists=True, dir_okay=True, resolve_path=True),
|
|
28
|
+
)
|
|
29
|
+
@click.option(
|
|
30
|
+
"--regscale_ssp_id",
|
|
31
|
+
type=click.INT,
|
|
32
|
+
help="The ID number from RegScale of the System Security Plan.",
|
|
33
|
+
prompt="Enter RegScale System Security Plan ID",
|
|
34
|
+
required=True,
|
|
35
|
+
)
|
|
36
|
+
@click.option(
|
|
37
|
+
"--scan_date",
|
|
38
|
+
type=click.DateTime(formats=["%Y-%m-%d"]),
|
|
39
|
+
help="The the scan date of the file.",
|
|
40
|
+
required=False,
|
|
41
|
+
)
|
|
42
|
+
@click.option(
|
|
43
|
+
"--upload_file",
|
|
44
|
+
"--upload",
|
|
45
|
+
type=click.BOOL,
|
|
46
|
+
help="Whether to upload the file to RegScale after processing. Default is True.",
|
|
47
|
+
default=True,
|
|
48
|
+
required=False,
|
|
49
|
+
)
|
|
50
|
+
def import_burp(
|
|
51
|
+
folder_path: click.Path, regscale_ssp_id: click.INT, scan_date: click.DateTime, upload_file: click.BOOL
|
|
52
|
+
):
|
|
53
|
+
"""
|
|
54
|
+
Import Burp scans, vulnerabilities and assets to RegScale from burp files
|
|
55
|
+
|
|
56
|
+
"""
|
|
57
|
+
app = Application()
|
|
58
|
+
if len(list(Path(folder_path).glob("*.xml"))) == 0:
|
|
59
|
+
logger.warning("No Burp files found in the specified folder.")
|
|
60
|
+
return
|
|
61
|
+
for file in Path(folder_path).glob("*.xml"):
|
|
62
|
+
burp = Burp(app, file, parentId=regscale_ssp_id, parentModule="securityplans")
|
|
63
|
+
flat_int = FlatFileIntegration(plan_id=regscale_ssp_id)
|
|
64
|
+
flat_int.num_findings_to_process = burp.num_findings
|
|
65
|
+
flat_int.num_assets_to_process = burp.num_assets
|
|
66
|
+
flat_int.sync_assets(
|
|
67
|
+
plan_id=regscale_ssp_id,
|
|
68
|
+
integration_assets=burp.integration_assets,
|
|
69
|
+
title="Burp Suite",
|
|
70
|
+
)
|
|
71
|
+
flat_int.sync_findings(
|
|
72
|
+
plan_id=regscale_ssp_id,
|
|
73
|
+
integration_findings=burp.integration_findings,
|
|
74
|
+
title="Burp Suite",
|
|
75
|
+
enable_finding_date_update=True,
|
|
76
|
+
scan_date=scan_date,
|
|
77
|
+
)
|
|
78
|
+
burp.move_files(upload_file=upload_file)
|