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,151 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""Upload files to RegScale."""
|
|
4
|
+
import logging
|
|
5
|
+
import xml.etree.ElementTree as ET
|
|
6
|
+
from typing import Optional, Union
|
|
7
|
+
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from regscale.core.app.api import Api
|
|
11
|
+
from regscale.models.regscale_models.file import File
|
|
12
|
+
from regscale.utils.b64conversion import decode_base64_to_bytesio, encode_file_to_base64
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger("regscale")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def file_upload(
|
|
18
|
+
regscale_id: int,
|
|
19
|
+
regscale_module: str,
|
|
20
|
+
file_path: str,
|
|
21
|
+
file_name: Optional[str] = None,
|
|
22
|
+
**kwargs: dict,
|
|
23
|
+
) -> Optional[Union[list, dict]]:
|
|
24
|
+
"""Upload files to RegScale
|
|
25
|
+
|
|
26
|
+
:param int regscale_id: RegScale ID
|
|
27
|
+
:param str regscale_module: RegScale module
|
|
28
|
+
:param str file_path: Path to file
|
|
29
|
+
:param Optional[str] file_name: Optional name of file to upload
|
|
30
|
+
:param dict **kwargs: Optional kwargs to pass to upload_file
|
|
31
|
+
:return: Results of upload_file
|
|
32
|
+
:rtype: Optional[Union[list, dict]]
|
|
33
|
+
"""
|
|
34
|
+
file = Path(file_path)
|
|
35
|
+
if file_name is None:
|
|
36
|
+
file_name = file.name
|
|
37
|
+
if not file.exists():
|
|
38
|
+
logger.error(f"File {file_path} does not exist.")
|
|
39
|
+
return
|
|
40
|
+
if file.suffix == ".xml":
|
|
41
|
+
return process_base64_in_xml(regscale_id, regscale_module, file_path, **kwargs)
|
|
42
|
+
filestring = encode_file_to_base64(file_path)
|
|
43
|
+
return upload_file(
|
|
44
|
+
ssp_id=regscale_id,
|
|
45
|
+
parent_module=regscale_module,
|
|
46
|
+
file_path=file_path,
|
|
47
|
+
filestring=filestring,
|
|
48
|
+
filename=file_name,
|
|
49
|
+
**kwargs,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def upload_file(
|
|
54
|
+
ssp_id: int,
|
|
55
|
+
parent_module: str,
|
|
56
|
+
file_path: str,
|
|
57
|
+
filestring: str,
|
|
58
|
+
filename: str,
|
|
59
|
+
**kwargs: dict,
|
|
60
|
+
) -> Union[dict, bool]:
|
|
61
|
+
"""Upload file to RegScale
|
|
62
|
+
|
|
63
|
+
:param int ssp_id: RegScale ID
|
|
64
|
+
:param str parent_module: RegScale module
|
|
65
|
+
:param str file_path: Path to file
|
|
66
|
+
:param str filestring: Base64-encoded file
|
|
67
|
+
:param str filename: Name of file to upload
|
|
68
|
+
:param dict **kwargs: Optional kwargs to pass to upload_file
|
|
69
|
+
:return: Results of upload_file, or False if upload fails
|
|
70
|
+
:rtype: Union[dict, bool]
|
|
71
|
+
"""
|
|
72
|
+
logger.info(f"Uploading {filename} to RegScale {parent_module} with ID {ssp_id}.")
|
|
73
|
+
if "api" not in kwargs:
|
|
74
|
+
api = Api()
|
|
75
|
+
kwargs["api"] = api
|
|
76
|
+
decoded_file = decode_base64_to_bytesio(filestring)
|
|
77
|
+
try:
|
|
78
|
+
results = File.upload_file_to_regscale(
|
|
79
|
+
file_name=filename or file_path,
|
|
80
|
+
parent_id=ssp_id,
|
|
81
|
+
parent_module=parent_module,
|
|
82
|
+
file_data=decoded_file.getvalue(),
|
|
83
|
+
**kwargs,
|
|
84
|
+
)
|
|
85
|
+
except Exception as e:
|
|
86
|
+
logger.error(f"Error uploading file: {e}")
|
|
87
|
+
return False
|
|
88
|
+
logger.info(f"File {filename} uploaded successfully.")
|
|
89
|
+
return results
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def process_base64_in_xml(
|
|
93
|
+
regscale_id: int,
|
|
94
|
+
regscale_module: str,
|
|
95
|
+
file_path: str,
|
|
96
|
+
file_name: str = None,
|
|
97
|
+
**kwargs: dict,
|
|
98
|
+
) -> list:
|
|
99
|
+
"""Process base64 in XML file
|
|
100
|
+
|
|
101
|
+
:param int regscale_id: RegScale ID
|
|
102
|
+
:param str regscale_module: RegScale module
|
|
103
|
+
:param str file_path: Path to XML file
|
|
104
|
+
:param str file_name: Optional name of file to upload
|
|
105
|
+
:param dict **kwargs: Optional kwargs to pass to upload_file
|
|
106
|
+
:return: Results of upload_file
|
|
107
|
+
:rtype: list
|
|
108
|
+
"""
|
|
109
|
+
results = []
|
|
110
|
+
base64_tags = process_base64_tags_in_xml(file_path)
|
|
111
|
+
for base64_tag in base64_tags:
|
|
112
|
+
filename = base64_tag["filename"]
|
|
113
|
+
filestring = base64_tag["base64"]
|
|
114
|
+
logger.info(f"Uploading base64-tagged file {filename} to RegScale {regscale_module} with ID {regscale_id}.")
|
|
115
|
+
result = upload_file(
|
|
116
|
+
ssp_id=regscale_id,
|
|
117
|
+
parent_module=regscale_module,
|
|
118
|
+
file_path=filename,
|
|
119
|
+
filestring=filestring,
|
|
120
|
+
filename=filename,
|
|
121
|
+
**kwargs,
|
|
122
|
+
)
|
|
123
|
+
results.append(result)
|
|
124
|
+
logger.info(f"Uploading XML file {file_path} to RegScale {regscale_module} with ID {regscale_id}.")
|
|
125
|
+
result = upload_file(
|
|
126
|
+
ssp_id=regscale_id,
|
|
127
|
+
parent_module=regscale_module,
|
|
128
|
+
file_path=file_name or file_path,
|
|
129
|
+
filestring=encode_file_to_base64(file_path),
|
|
130
|
+
filename=file_name or file_path,
|
|
131
|
+
**kwargs,
|
|
132
|
+
)
|
|
133
|
+
results.append(result)
|
|
134
|
+
return results
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def process_base64_tags_in_xml(xml_file: str) -> list[dict]:
|
|
138
|
+
"""Process base64 tags in XML file
|
|
139
|
+
|
|
140
|
+
:param str xml_file: Path to XML file
|
|
141
|
+
:return: List of dicts containing filename and base64 string
|
|
142
|
+
:rtype: list[dict]
|
|
143
|
+
"""
|
|
144
|
+
tree = ET.parse(xml_file)
|
|
145
|
+
root = tree.getroot()
|
|
146
|
+
results = []
|
|
147
|
+
for base64_tag in root.iter("base64"):
|
|
148
|
+
filename = base64_tag.attrib["filename"]
|
|
149
|
+
filestring = base64_tag.text.replace("\n", "")
|
|
150
|
+
results.append({"filename": filename, "base64": filestring})
|
|
151
|
+
return results
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""RegScale Healthcheck Status"""
|
|
4
|
+
|
|
5
|
+
# standard python imports
|
|
6
|
+
import sys
|
|
7
|
+
from json import JSONDecodeError
|
|
8
|
+
from urllib.parse import urljoin
|
|
9
|
+
|
|
10
|
+
from regscale.core.app.logz import create_logger
|
|
11
|
+
|
|
12
|
+
logger = create_logger()
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def status() -> None:
|
|
16
|
+
"""
|
|
17
|
+
Get Status of Client Application via RegScale API
|
|
18
|
+
|
|
19
|
+
:raises: FileNotFoundError if init.yaml was unable to be loaded
|
|
20
|
+
:raises: ValueError if domain in init.yaml is missing or null
|
|
21
|
+
:raises: General Error if unable to retrieve health check from RegScale API
|
|
22
|
+
:rtype: None
|
|
23
|
+
"""
|
|
24
|
+
from regscale.core.app.api import Api
|
|
25
|
+
from regscale.core.app.application import Application
|
|
26
|
+
|
|
27
|
+
app = Application()
|
|
28
|
+
api = Api()
|
|
29
|
+
config = app.config
|
|
30
|
+
|
|
31
|
+
if "domain" not in config or config["domain"] == "":
|
|
32
|
+
raise ValueError("No domain set in the initialization file.")
|
|
33
|
+
if "token" not in config or config["token"] == "":
|
|
34
|
+
raise ValueError("The token has not been set in the initialization file.")
|
|
35
|
+
|
|
36
|
+
url_login = urljoin(config["domain"], "health")
|
|
37
|
+
response = api.get(url=url_login)
|
|
38
|
+
|
|
39
|
+
if not response or not response.ok:
|
|
40
|
+
logger.error("Unable to retrieve health check data from RegScale. Please check your domain value in init.yaml.")
|
|
41
|
+
sys.exit(1)
|
|
42
|
+
|
|
43
|
+
try:
|
|
44
|
+
health_data = response.json()
|
|
45
|
+
except JSONDecodeError:
|
|
46
|
+
logger.error("Unable to decode health check data from RegScale.")
|
|
47
|
+
sys.exit(1)
|
|
48
|
+
|
|
49
|
+
status_loggers = {
|
|
50
|
+
"Healthy": logger.info,
|
|
51
|
+
"Degraded": logger.warning,
|
|
52
|
+
"Unhealthy": logger.error,
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
reg_status = health_data.get("status", "Unknown")
|
|
56
|
+
status_loggers.get(reg_status, logger.info)(f"System Status: {reg_status}")
|
|
57
|
+
|
|
58
|
+
if "entries" not in health_data:
|
|
59
|
+
logger.error("No data returned from system health check.")
|
|
60
|
+
sys.exit(1)
|
|
61
|
+
|
|
62
|
+
checks = health_data["entries"]
|
|
63
|
+
for chk in checks:
|
|
64
|
+
logger.info(f"System: {chk}, Status: " + checks[chk]["status"])
|
|
65
|
+
|
|
66
|
+
return health_data
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""Module to allow user to login to RegScale"""
|
|
4
|
+
|
|
5
|
+
# standard python imports
|
|
6
|
+
import base64
|
|
7
|
+
import contextlib
|
|
8
|
+
import json
|
|
9
|
+
import logging
|
|
10
|
+
import os
|
|
11
|
+
import sys
|
|
12
|
+
import uuid
|
|
13
|
+
from datetime import datetime
|
|
14
|
+
from ssl import SSLCertVerificationError
|
|
15
|
+
from typing import Optional, TYPE_CHECKING
|
|
16
|
+
from urllib.parse import urljoin
|
|
17
|
+
|
|
18
|
+
if TYPE_CHECKING:
|
|
19
|
+
from regscale.core.app.application import Application
|
|
20
|
+
from regscale.core.app.api import Api
|
|
21
|
+
|
|
22
|
+
import requests
|
|
23
|
+
|
|
24
|
+
logger = logging.getLogger("regscale")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def login(
|
|
28
|
+
str_user: Optional[str] = None,
|
|
29
|
+
str_password: Optional[str] = None,
|
|
30
|
+
host: Optional[str] = None,
|
|
31
|
+
app: Optional["Application"] = None,
|
|
32
|
+
token: Optional[str] = None,
|
|
33
|
+
mfa_token: Optional[str] = "",
|
|
34
|
+
) -> str:
|
|
35
|
+
"""
|
|
36
|
+
Wrapper for Login to RegScale
|
|
37
|
+
|
|
38
|
+
:param Optional[str] str_user: username to log in, defaults to None
|
|
39
|
+
:param Optional[str] str_password: password of provided user, defaults to None
|
|
40
|
+
:param Optional[str] host: host to log into, defaults to None
|
|
41
|
+
:param Optional[Application] app: Application object, defaults to None
|
|
42
|
+
:param Optional[str] token: a valid JWT token to pass, defaults to None
|
|
43
|
+
:param Optional[str] mfa_token: a valid MFA token to pass, defaults to ""
|
|
44
|
+
:raises: ValueError if no domain value found in init.yaml
|
|
45
|
+
:raises: TypeError if token or user id doesn't match expected data type
|
|
46
|
+
:raises: SSLCertVerificationError if unable to validate SSL certificate
|
|
47
|
+
:return: JWT Token after authentication
|
|
48
|
+
:rtype: str
|
|
49
|
+
"""
|
|
50
|
+
from regscale.models.platform import (
|
|
51
|
+
RegScaleAuth,
|
|
52
|
+
) # Adding the import here, to avoid a circular import with RegScaleAuth.get_token.
|
|
53
|
+
|
|
54
|
+
running_in_airflow = os.getenv("REGSCALE_AIRFLOW") == "true"
|
|
55
|
+
from regscale.core.app.application import Application
|
|
56
|
+
|
|
57
|
+
if not app and running_in_airflow:
|
|
58
|
+
app = Application(
|
|
59
|
+
config={
|
|
60
|
+
"domain": host,
|
|
61
|
+
"token": token,
|
|
62
|
+
}
|
|
63
|
+
)
|
|
64
|
+
elif not app:
|
|
65
|
+
app = Application()
|
|
66
|
+
config = app.config
|
|
67
|
+
# check to see if we are running in airflow
|
|
68
|
+
if config and running_in_airflow:
|
|
69
|
+
token = token or os.getenv("REGSCALE_TOKEN") or config.get("token")
|
|
70
|
+
config["domain"] = (host if host and host != "None" else config.get("REGSCALE_DOMAIN")) or os.getenv(
|
|
71
|
+
"REGSCALE_DOMAIN"
|
|
72
|
+
)
|
|
73
|
+
app.logger.info("Running in Airflow, logging in with token: %s", token)
|
|
74
|
+
else:
|
|
75
|
+
config["domain"] = host or config["domain"]
|
|
76
|
+
token = token or os.getenv("REGSCALE_TOKEN")
|
|
77
|
+
if config and token:
|
|
78
|
+
if verify_token(app, token):
|
|
79
|
+
config["userId"] = parse_user_id_from_jwt(app, token)
|
|
80
|
+
config["token"] = token if token.startswith("Bearer ") else f"Bearer {token}"
|
|
81
|
+
if not running_in_airflow:
|
|
82
|
+
logger.info("RegScale Token and userId has been saved in init.yaml")
|
|
83
|
+
app.save_config(conf=config)
|
|
84
|
+
return token
|
|
85
|
+
else:
|
|
86
|
+
logger.error("Invalid token provided.")
|
|
87
|
+
sys.exit(1)
|
|
88
|
+
from regscale.core.app.api import Api
|
|
89
|
+
|
|
90
|
+
if str_user and str_password:
|
|
91
|
+
if config and "REGSCALE_DOMAIN" not in os.environ and host is None:
|
|
92
|
+
host = config["domain"]
|
|
93
|
+
regscale_auth = RegScaleAuth.authenticate(
|
|
94
|
+
api=Api(),
|
|
95
|
+
username=str_user,
|
|
96
|
+
password=str_password,
|
|
97
|
+
domain=host,
|
|
98
|
+
mfa_token=mfa_token,
|
|
99
|
+
)
|
|
100
|
+
else:
|
|
101
|
+
regscale_auth = RegScaleAuth.authenticate(Api(), mfa_token=mfa_token)
|
|
102
|
+
if config and config["domain"] is None:
|
|
103
|
+
raise ValueError("No domain set in the init.yaml configuration file.")
|
|
104
|
+
if config and config["domain"] == "":
|
|
105
|
+
raise ValueError("The domain is blank in the init.yaml configuration file.")
|
|
106
|
+
|
|
107
|
+
# create object to authenticate
|
|
108
|
+
auth = {
|
|
109
|
+
"userName": regscale_auth.username,
|
|
110
|
+
"password": regscale_auth.password.get_secret_value(),
|
|
111
|
+
"oldPassword": "",
|
|
112
|
+
"mfaToken": mfa_token,
|
|
113
|
+
}
|
|
114
|
+
if auth["password"]:
|
|
115
|
+
try:
|
|
116
|
+
# update init file from login
|
|
117
|
+
if config:
|
|
118
|
+
config["token"] = regscale_auth.token
|
|
119
|
+
config["userId"] = regscale_auth.user_id
|
|
120
|
+
config["domain"] = regscale_auth.domain
|
|
121
|
+
# write the changes back to file
|
|
122
|
+
app.save_config(config)
|
|
123
|
+
# set variables
|
|
124
|
+
logger.info("User ID: %s", regscale_auth.user_id)
|
|
125
|
+
logger.info("New RegScale Token has been updated and saved in init.yaml")
|
|
126
|
+
# Truncate token for logging purposes
|
|
127
|
+
logger.debug("Token: %s", regscale_auth.token[:20])
|
|
128
|
+
except TypeError as ex:
|
|
129
|
+
logger.error("TypeError: %s", ex)
|
|
130
|
+
except SSLCertVerificationError as sslex:
|
|
131
|
+
logger.error("SSLError, python requests requires a valid ssl certificate.\n%s", sslex)
|
|
132
|
+
sys.exit(1)
|
|
133
|
+
config["domain"] = host
|
|
134
|
+
app.save_config(config)
|
|
135
|
+
return regscale_auth.token
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def is_valid(host: Optional[str] = None, app: Optional["Application"] = None) -> bool:
|
|
139
|
+
"""
|
|
140
|
+
Quick endpoint to check login status
|
|
141
|
+
|
|
142
|
+
:param Optional[str] host: host to verify login, defaults to None
|
|
143
|
+
:param Optional[Application] app: Application object, defaults to None
|
|
144
|
+
:return: Boolean if user is logged in or not
|
|
145
|
+
:rtype: bool
|
|
146
|
+
"""
|
|
147
|
+
from regscale.core.app.api import Api
|
|
148
|
+
|
|
149
|
+
if not app:
|
|
150
|
+
from regscale.core.app.application import Application
|
|
151
|
+
|
|
152
|
+
app = Application()
|
|
153
|
+
config = app.config
|
|
154
|
+
login_status = False
|
|
155
|
+
api = Api()
|
|
156
|
+
token_body = {"accessToken": ""}
|
|
157
|
+
try:
|
|
158
|
+
# Make sure url isn't default
|
|
159
|
+
# login with token
|
|
160
|
+
token_body["accessToken"] = config["token"]
|
|
161
|
+
app.logger.debug("config: %s", config)
|
|
162
|
+
url_login = urljoin(host or config["domain"], "/api/authentication/validateToken")
|
|
163
|
+
app.logger.debug("is_valid url: %s", url_login)
|
|
164
|
+
app.logger.debug("token_body: %s", token_body)
|
|
165
|
+
if response := api.post(url=url_login, headers={}, json=token_body):
|
|
166
|
+
app.logger.debug("is_valid response: %s", response.status_code)
|
|
167
|
+
login_status = response.status_code == 200
|
|
168
|
+
except KeyError as ex:
|
|
169
|
+
if str(ex).replace("'", "") == "token":
|
|
170
|
+
app.logger.debug("Token is missing, we will generate this")
|
|
171
|
+
except ConnectionError:
|
|
172
|
+
app.logger.error("ConnectionError: Unable to login user to RegScale, check the server domain.")
|
|
173
|
+
except json.JSONDecodeError as decode_ex:
|
|
174
|
+
app.logger.error(
|
|
175
|
+
"Login Error: Unable to login user to RegScale instance: %s.\n%s",
|
|
176
|
+
config["domain"],
|
|
177
|
+
decode_ex,
|
|
178
|
+
)
|
|
179
|
+
finally:
|
|
180
|
+
app.logger.debug("login status: %s", login_status)
|
|
181
|
+
return login_status
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def is_licensed(app: "Application") -> bool:
|
|
185
|
+
"""
|
|
186
|
+
Verify if the application is licensed
|
|
187
|
+
|
|
188
|
+
:param Application app: Application object
|
|
189
|
+
:return: License status
|
|
190
|
+
:rtype: bool
|
|
191
|
+
"""
|
|
192
|
+
from regscale.core.app.api import Api
|
|
193
|
+
|
|
194
|
+
api = Api()
|
|
195
|
+
try:
|
|
196
|
+
with contextlib.suppress(requests.RequestException):
|
|
197
|
+
if res := app.get_regscale_license(api=api):
|
|
198
|
+
lic = res.json()
|
|
199
|
+
else:
|
|
200
|
+
return False
|
|
201
|
+
license_date = parse_date(lic["expirationDate"])
|
|
202
|
+
if lic["licenseType"] == "Enterprise" and license_date > datetime.now():
|
|
203
|
+
return True
|
|
204
|
+
except (KeyError, ValueError, TypeError, AttributeError):
|
|
205
|
+
return False
|
|
206
|
+
return False
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def verify_token(app: "Application", token: str) -> bool:
|
|
210
|
+
"""
|
|
211
|
+
Function to verify if the provided JWT for RegScale is valid
|
|
212
|
+
|
|
213
|
+
:param Application app: Application object
|
|
214
|
+
:param str token: the JWT to verify
|
|
215
|
+
:return: Boolean if the token is valid or not
|
|
216
|
+
:rtype: bool
|
|
217
|
+
"""
|
|
218
|
+
from regscale.core.app.api import Api
|
|
219
|
+
|
|
220
|
+
api = Api()
|
|
221
|
+
response = api.post(url=f"{app.config['domain']}/api/authentication/validateToken", json={"accessToken": token})
|
|
222
|
+
return response.status_code == 200
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def parse_user_id_from_jwt(app: "Application", jwt_token: str) -> str:
|
|
226
|
+
"""
|
|
227
|
+
Decode JWT from RegScale to get the user id from the payload
|
|
228
|
+
|
|
229
|
+
:param Application app: Application object
|
|
230
|
+
:param str jwt_token: the JWT to decode
|
|
231
|
+
:raises ValueError: if the JWT token is invalid
|
|
232
|
+
:return: the user id
|
|
233
|
+
:rtype: str
|
|
234
|
+
"""
|
|
235
|
+
parts = jwt_token.split(".")
|
|
236
|
+
if len(parts) != 3:
|
|
237
|
+
raise ValueError("Invalid JWT token format. Provided token is not a valid JWT token. Token: %s", jwt_token)
|
|
238
|
+
|
|
239
|
+
payload = json.loads(_decode_base64(parts[1]).decode("utf-8"))
|
|
240
|
+
if "id" not in payload:
|
|
241
|
+
# iterate the payload to find the user id by using any uuid found and validating it
|
|
242
|
+
for value in payload.values():
|
|
243
|
+
try:
|
|
244
|
+
if uuid.UUID(value) and validate_user_id(app, value):
|
|
245
|
+
return value
|
|
246
|
+
except (ValueError, AttributeError):
|
|
247
|
+
continue
|
|
248
|
+
else:
|
|
249
|
+
return payload["id"]
|
|
250
|
+
app.logger.warning("No user id found in JWT token, please update userId manually in init.yaml.")
|
|
251
|
+
return ""
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def validate_user_id(app: "Application", user_id: str) -> bool:
|
|
255
|
+
"""
|
|
256
|
+
Validate the user id provided by the user in RegScale
|
|
257
|
+
|
|
258
|
+
:param Application app: Application object
|
|
259
|
+
:param str user_id: User id to validate
|
|
260
|
+
:return: Whether the provided user id is valid or not
|
|
261
|
+
:rtype: bool
|
|
262
|
+
"""
|
|
263
|
+
from regscale.core.app.api import Api
|
|
264
|
+
|
|
265
|
+
api = Api()
|
|
266
|
+
response = api.get(
|
|
267
|
+
url=f"{app.config['domain']}/api/accounts/find/{user_id}",
|
|
268
|
+
)
|
|
269
|
+
return response.status_code == 200
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
def _decode_base64(data: str) -> bytes:
|
|
273
|
+
"""
|
|
274
|
+
Decode base64, padding being optional
|
|
275
|
+
|
|
276
|
+
:param str data: the data to decode
|
|
277
|
+
:return: the decoded data
|
|
278
|
+
:rtype: bytes
|
|
279
|
+
"""
|
|
280
|
+
missing_padding = len(data) % 4
|
|
281
|
+
if missing_padding:
|
|
282
|
+
data += "=" * (4 - missing_padding)
|
|
283
|
+
return base64.urlsafe_b64decode(data)
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
def parse_date(date_str: str) -> datetime:
|
|
287
|
+
"""
|
|
288
|
+
Parse a date string in one of the supported formats
|
|
289
|
+
|
|
290
|
+
:param str date_str: the date string to parse
|
|
291
|
+
:raises ValueError: if unable to parse the provided date_str
|
|
292
|
+
:return: the parsed date
|
|
293
|
+
:rtype: datetime
|
|
294
|
+
"""
|
|
295
|
+
formats = ["%Y-%m-%d", "%d-%m-%Y", "%m-%d-%Y", "%Y/%m/%d", "%d/%m/%Y", "%m/%d/%Y"]
|
|
296
|
+
for fmt in formats:
|
|
297
|
+
try:
|
|
298
|
+
parsed_date = datetime.strptime(date_str, fmt)
|
|
299
|
+
return parsed_date # Return the parsed date as soon as parsing is successful
|
|
300
|
+
except ValueError:
|
|
301
|
+
continue # Continue to the next format if parsing fails
|
|
302
|
+
|
|
303
|
+
raise ValueError(
|
|
304
|
+
f"Could not parse the date string {date_str} in any of the provided formats: {', '.join(formats)}."
|
|
305
|
+
)
|