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,346 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
from unittest.mock import Mock, patch
|
|
3
|
+
|
|
4
|
+
import pytest
|
|
5
|
+
|
|
6
|
+
from regscale.models.regscale_models.regscale_model import RegScaleModel
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class TestModel(RegScaleModel):
|
|
10
|
+
_unique_fields = [["name"]]
|
|
11
|
+
_parent_id_field = "parentId"
|
|
12
|
+
id: Optional[int] = None
|
|
13
|
+
name: str
|
|
14
|
+
value: int
|
|
15
|
+
parentId: int
|
|
16
|
+
parentModule: str = "test_module"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class TestModelMultipleUnique(RegScaleModel):
|
|
20
|
+
_unique_fields = [["field1", "field2"], ["field3"]]
|
|
21
|
+
_parent_id_field = "parentId"
|
|
22
|
+
id: Optional[int] = None
|
|
23
|
+
field1: Optional[str] = None
|
|
24
|
+
field2: Optional[str] = None
|
|
25
|
+
field3: Optional[str] = None
|
|
26
|
+
parentId: int
|
|
27
|
+
parentModule: str = "test_module"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@pytest.fixture
|
|
31
|
+
def mock_api_handler():
|
|
32
|
+
with patch("regscale.models.regscale_models.regscale_model.APIHandler") as mock:
|
|
33
|
+
yield mock
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@pytest.fixture
|
|
37
|
+
def mocked_model():
|
|
38
|
+
with patch.object(TestModel, "get_cached_object") as mock_get_cached, patch.object(
|
|
39
|
+
TestModel, "cache_object"
|
|
40
|
+
) as mock_cache, patch.object(TestModel, "create") as mock_create, patch.object(
|
|
41
|
+
TestModel, "_perform_save"
|
|
42
|
+
) as mock_perform_save:
|
|
43
|
+
yield TestModel(name="test", value=1, parentId=1), {
|
|
44
|
+
"get_cached": mock_get_cached,
|
|
45
|
+
"cache": mock_cache,
|
|
46
|
+
"create": mock_create,
|
|
47
|
+
"perform_save": mock_perform_save,
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def test_create_new_instance(mocked_model):
|
|
52
|
+
model, mocks = mocked_model
|
|
53
|
+
mocks["get_cached"].return_value = None
|
|
54
|
+
mocks["create"].return_value = TestModel(id=1, name="test", value=1, parentId=1)
|
|
55
|
+
|
|
56
|
+
result = model.create_or_update()
|
|
57
|
+
|
|
58
|
+
assert result.id == 1
|
|
59
|
+
mocks["create"].assert_called_once()
|
|
60
|
+
mocks["perform_save"].assert_not_called()
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def test_update_existing_instance(mocked_model):
|
|
64
|
+
model, mocks = mocked_model
|
|
65
|
+
cached_instance = TestModel(id=2, name="test", value=2, parentId=1)
|
|
66
|
+
mocks["get_cached"].return_value = cached_instance
|
|
67
|
+
model.value = 3 # This change should trigger an update
|
|
68
|
+
mocks["perform_save"].return_value = TestModel(id=2, name="test", value=3, parentId=1)
|
|
69
|
+
|
|
70
|
+
result = model.create_or_update()
|
|
71
|
+
|
|
72
|
+
assert model._original_data == {
|
|
73
|
+
"id": 2,
|
|
74
|
+
"name": "test",
|
|
75
|
+
"value": 2,
|
|
76
|
+
"parentId": 1,
|
|
77
|
+
"parentModule": "test_module",
|
|
78
|
+
}, "Original data should be set to cached instance data"
|
|
79
|
+
assert result.id == 2
|
|
80
|
+
assert result.value == 3
|
|
81
|
+
mocks["perform_save"].assert_called_once()
|
|
82
|
+
assert model._original_data == {
|
|
83
|
+
"id": 2,
|
|
84
|
+
"name": "test",
|
|
85
|
+
"value": 2,
|
|
86
|
+
"parentId": 1,
|
|
87
|
+
"parentModule": "test_module",
|
|
88
|
+
}, "Original data should not change after save"
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def test_no_update_when_no_changes(mocked_model):
|
|
92
|
+
model, mocks = mocked_model
|
|
93
|
+
cached_instance = TestModel(id=3, name="test", value=1, parentId=1)
|
|
94
|
+
mocks["get_cached"].return_value = cached_instance
|
|
95
|
+
|
|
96
|
+
result = model.create_or_update()
|
|
97
|
+
|
|
98
|
+
mocks["get_cached"].assert_called_once()
|
|
99
|
+
mocks["perform_save"].assert_not_called()
|
|
100
|
+
|
|
101
|
+
assert result == cached_instance, "Should return the cached instance without changes"
|
|
102
|
+
assert model._original_data == cached_instance.dict(
|
|
103
|
+
exclude_unset=True
|
|
104
|
+
), "Original data should be set to cached instance data"
|
|
105
|
+
|
|
106
|
+
print(f"Result: {result}")
|
|
107
|
+
print(f"Cached instance: {cached_instance}")
|
|
108
|
+
print(f"Model _original_data: {model._original_data}")
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
@pytest.mark.parametrize(
|
|
112
|
+
"initial_value,new_value,expected_calls",
|
|
113
|
+
[
|
|
114
|
+
(1, 2, 1), # Different value, should update
|
|
115
|
+
(1, 1, 0), # Same value, should not update
|
|
116
|
+
],
|
|
117
|
+
)
|
|
118
|
+
def test_update_behavior(mocked_model, initial_value, new_value, expected_calls):
|
|
119
|
+
model, mocks = mocked_model
|
|
120
|
+
cached_instance = TestModel(id=1, name="test", value=initial_value, parentId=1)
|
|
121
|
+
mocks["get_cached"].return_value = cached_instance
|
|
122
|
+
model.value = new_value
|
|
123
|
+
mocks["perform_save"].return_value = TestModel(id=1, name="test", value=new_value, parentId=1)
|
|
124
|
+
|
|
125
|
+
model.create_or_update()
|
|
126
|
+
|
|
127
|
+
assert mocks["perform_save"].call_count == expected_calls
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
class TestFindByUnique:
|
|
131
|
+
@pytest.fixture
|
|
132
|
+
def mock_get_all_by_parent(self):
|
|
133
|
+
with patch.object(TestModel, "get_all_by_parent") as mock:
|
|
134
|
+
yield mock
|
|
135
|
+
|
|
136
|
+
def test_find_by_unique_single_field_match(self, mock_get_all_by_parent):
|
|
137
|
+
"""Test finding an instance with a single unique field match"""
|
|
138
|
+
instance = TestModel(name="test", value=1, parentId=1)
|
|
139
|
+
existing = TestModel(id=1, name="test", value=2, parentId=1)
|
|
140
|
+
mock_get_all_by_parent.return_value = [existing]
|
|
141
|
+
|
|
142
|
+
result = instance.find_by_unique()
|
|
143
|
+
|
|
144
|
+
assert result == existing
|
|
145
|
+
mock_get_all_by_parent.assert_called_once_with(parent_id=1, parent_module="test_module")
|
|
146
|
+
|
|
147
|
+
def test_find_by_unique_case_insensitive(self, mock_get_all_by_parent):
|
|
148
|
+
"""Test case-insensitive matching"""
|
|
149
|
+
instance = TestModel(name="Test", value=1, parentId=1)
|
|
150
|
+
existing = TestModel(id=1, name="test", value=2, parentId=1)
|
|
151
|
+
mock_get_all_by_parent.return_value = [existing]
|
|
152
|
+
|
|
153
|
+
result = instance.find_by_unique()
|
|
154
|
+
|
|
155
|
+
assert result == existing
|
|
156
|
+
|
|
157
|
+
def test_find_by_unique_no_match(self, mock_get_all_by_parent):
|
|
158
|
+
"""Test when no match is found"""
|
|
159
|
+
instance = TestModel(name="test1", value=1, parentId=1)
|
|
160
|
+
existing = TestModel(id=1, name="test2", value=2, parentId=1)
|
|
161
|
+
mock_get_all_by_parent.return_value = [existing]
|
|
162
|
+
|
|
163
|
+
result = instance.find_by_unique()
|
|
164
|
+
|
|
165
|
+
assert result is None
|
|
166
|
+
|
|
167
|
+
def test_find_by_unique_no_unique_fields(self):
|
|
168
|
+
"""Test when no unique fields are defined"""
|
|
169
|
+
|
|
170
|
+
class NoUniqueModel(RegScaleModel):
|
|
171
|
+
_unique_fields = []
|
|
172
|
+
name: str
|
|
173
|
+
|
|
174
|
+
instance = NoUniqueModel(name="test")
|
|
175
|
+
|
|
176
|
+
with pytest.raises(NotImplementedError):
|
|
177
|
+
instance.find_by_unique()
|
|
178
|
+
|
|
179
|
+
def test_find_by_unique_no_parent_id(self):
|
|
180
|
+
"""Test when parent ID is missing"""
|
|
181
|
+
instance = TestModel(name="test", value=1) # No parentId
|
|
182
|
+
|
|
183
|
+
with pytest.raises(ValueError):
|
|
184
|
+
instance.find_by_unique()
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
class TestMultipleUniqueFields:
|
|
188
|
+
@pytest.fixture
|
|
189
|
+
def mock_get_all_by_parent(self):
|
|
190
|
+
with patch.object(TestModelMultipleUnique, "get_all_by_parent") as mock:
|
|
191
|
+
yield mock
|
|
192
|
+
|
|
193
|
+
def test_find_by_unique_first_set_match(self, mock_get_all_by_parent):
|
|
194
|
+
"""Test matching on first set of unique fields"""
|
|
195
|
+
instance = TestModelMultipleUnique(
|
|
196
|
+
field1="test1",
|
|
197
|
+
field2="test2",
|
|
198
|
+
field3="different", # Different value doesn't matter for first set match
|
|
199
|
+
parentId=1,
|
|
200
|
+
)
|
|
201
|
+
existing = TestModelMultipleUnique(
|
|
202
|
+
id=1,
|
|
203
|
+
field1="test1",
|
|
204
|
+
field2="test2",
|
|
205
|
+
field3="also_different", # Different value doesn't matter for first set match
|
|
206
|
+
parentId=1,
|
|
207
|
+
)
|
|
208
|
+
mock_get_all_by_parent.return_value = [existing]
|
|
209
|
+
|
|
210
|
+
result = instance.find_by_unique()
|
|
211
|
+
|
|
212
|
+
# Should match because first set of unique fields matches
|
|
213
|
+
assert result == existing
|
|
214
|
+
|
|
215
|
+
def test_find_by_unique_second_set_match(self, mock_get_all_by_parent):
|
|
216
|
+
"""Test matching on second set of unique fields"""
|
|
217
|
+
instance = TestModelMultipleUnique(
|
|
218
|
+
field1="different1", field2="different2", field3="test3", parentId=1 # Matches on second set
|
|
219
|
+
)
|
|
220
|
+
existing = TestModelMultipleUnique(
|
|
221
|
+
id=1, field1="test1", field2="test2", field3="test3", parentId=1 # Matches on second set
|
|
222
|
+
)
|
|
223
|
+
mock_get_all_by_parent.return_value = [existing]
|
|
224
|
+
|
|
225
|
+
result = instance.find_by_unique()
|
|
226
|
+
|
|
227
|
+
# Should match because second set of unique fields matches
|
|
228
|
+
assert result == existing
|
|
229
|
+
|
|
230
|
+
def test_find_by_unique_no_match(self, mock_get_all_by_parent):
|
|
231
|
+
"""Test when no unique field sets match"""
|
|
232
|
+
instance = TestModelMultipleUnique(field1="different1", field2="different2", field3="different3", parentId=1)
|
|
233
|
+
existing = TestModelMultipleUnique(id=1, field1="test1", field2="test2", field3="test3", parentId=1)
|
|
234
|
+
mock_get_all_by_parent.return_value = [existing]
|
|
235
|
+
|
|
236
|
+
result = instance.find_by_unique()
|
|
237
|
+
|
|
238
|
+
# Should not match because no unique field sets match
|
|
239
|
+
assert result is None
|
|
240
|
+
|
|
241
|
+
def test_find_by_unique_with_none_values(self, mock_get_all_by_parent):
|
|
242
|
+
"""Test handling of None values in multiple unique fields"""
|
|
243
|
+
instance = TestModelMultipleUnique(
|
|
244
|
+
field1="test1", field2=None, field3="different3", parentId=1 # None in first set # Different in second set
|
|
245
|
+
)
|
|
246
|
+
existing = TestModelMultipleUnique(
|
|
247
|
+
id=1, field1="test1", field2=None, field3="test3", parentId=1 # None in first set
|
|
248
|
+
)
|
|
249
|
+
mock_get_all_by_parent.return_value = [existing]
|
|
250
|
+
|
|
251
|
+
result = instance.find_by_unique()
|
|
252
|
+
|
|
253
|
+
# Should not match because first set has None values and second set doesn't match
|
|
254
|
+
assert result is None
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
class TestCaching:
|
|
258
|
+
def test_cache_hit(self, mocked_model):
|
|
259
|
+
"""Test when object is found in cache"""
|
|
260
|
+
model, mocks = mocked_model
|
|
261
|
+
cached = TestModel(id=1, name="test", value=1, parentId=1)
|
|
262
|
+
mocks["get_cached"].return_value = cached
|
|
263
|
+
|
|
264
|
+
result = model.find_by_unique()
|
|
265
|
+
|
|
266
|
+
assert result == cached
|
|
267
|
+
mocks["get_cached"].assert_called_once()
|
|
268
|
+
|
|
269
|
+
def test_cache_update_after_save(self, mocked_model):
|
|
270
|
+
"""Test that cache is updated after saving"""
|
|
271
|
+
model, mocks = mocked_model
|
|
272
|
+
updated = TestModel(id=1, name="test", value=2, parentId=1)
|
|
273
|
+
mocks["perform_save"].return_value = updated
|
|
274
|
+
|
|
275
|
+
model.value = 2
|
|
276
|
+
model.create_or_update()
|
|
277
|
+
|
|
278
|
+
mocks["cache"].assert_called_with(updated)
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
class TestErrorHandling:
|
|
282
|
+
@pytest.fixture
|
|
283
|
+
def mock_get_all_by_parent(self):
|
|
284
|
+
with patch.object(TestModel, "get_all_by_parent") as mock:
|
|
285
|
+
yield mock
|
|
286
|
+
|
|
287
|
+
def test_create_or_update_with_api_error(self, mocked_model):
|
|
288
|
+
"""Test handling of API errors during create/update"""
|
|
289
|
+
model, mocks = mocked_model
|
|
290
|
+
mocks["get_cached"].return_value = None
|
|
291
|
+
mocks["create"].side_effect = Exception("API Error")
|
|
292
|
+
|
|
293
|
+
with pytest.raises(Exception) as exc_info:
|
|
294
|
+
model.create_or_update()
|
|
295
|
+
|
|
296
|
+
assert str(exc_info.value) == "API Error"
|
|
297
|
+
|
|
298
|
+
@pytest.mark.parametrize("attribute_error_field", ["name", "value", "non_existent_field"])
|
|
299
|
+
def test_find_by_unique_attribute_error(self, attribute_error_field, mocker):
|
|
300
|
+
"""Test handling of AttributeError during find_by_unique"""
|
|
301
|
+
# Use mocker fixture instead of manual patch
|
|
302
|
+
mock_get_all_by_parent = mocker.patch.object(TestModel, "get_all_by_parent")
|
|
303
|
+
|
|
304
|
+
instance = TestModel(name="test", value=1, parentId=1)
|
|
305
|
+
|
|
306
|
+
# Create a mock instance that will raise AttributeError for the specified field
|
|
307
|
+
class MockTestModel(TestModel):
|
|
308
|
+
def __getattr__(self, name):
|
|
309
|
+
if name == attribute_error_field:
|
|
310
|
+
raise AttributeError(f"Mock object has no attribute '{name}'")
|
|
311
|
+
return super().__getattr__(name)
|
|
312
|
+
|
|
313
|
+
mock_instance = MockTestModel(name="test_value", value=1, parentId=1)
|
|
314
|
+
mock_get_all_by_parent.return_value = [mock_instance]
|
|
315
|
+
|
|
316
|
+
# Should not raise AttributeError
|
|
317
|
+
result = instance.find_by_unique()
|
|
318
|
+
assert result is None
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
class TestConcurrency:
|
|
322
|
+
def test_concurrent_cache_access(self):
|
|
323
|
+
"""Test concurrent access to cache"""
|
|
324
|
+
import threading
|
|
325
|
+
import time
|
|
326
|
+
|
|
327
|
+
model = TestModel(name="test", value=1, parentId=1)
|
|
328
|
+
cache_key = model._get_cache_key(model)
|
|
329
|
+
|
|
330
|
+
def cache_operation():
|
|
331
|
+
with model._get_lock(cache_key):
|
|
332
|
+
time.sleep(0.1) # Simulate some work
|
|
333
|
+
model.cache_object(model)
|
|
334
|
+
|
|
335
|
+
threads = [threading.Thread(target=cache_operation) for _ in range(5)]
|
|
336
|
+
for t in threads:
|
|
337
|
+
t.start()
|
|
338
|
+
for t in threads:
|
|
339
|
+
t.join()
|
|
340
|
+
|
|
341
|
+
# Verify that cache operations completed without errors
|
|
342
|
+
assert model.get_cached_object(cache_key) is not None
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
if __name__ == "__main__":
|
|
346
|
+
pytest.main()
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from regscale.core.app.utils.report_utils import ReportGenerator
|
|
2
|
+
from regscale.models import Asset
|
|
3
|
+
from tests.fixtures.test_fixture import CLITestFixture
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class TestImport(CLITestFixture):
|
|
7
|
+
"""
|
|
8
|
+
Test for Report Generator
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
def test_basic_report(self):
|
|
12
|
+
"""
|
|
13
|
+
Test the basic report
|
|
14
|
+
"""
|
|
15
|
+
assets = Asset.get_all_by_parent(3, "securityplans")
|
|
16
|
+
ReportGenerator(assets)
|
|
17
|
+
|
|
18
|
+
def test_advanced_report(self):
|
|
19
|
+
"""
|
|
20
|
+
Test the advanced report
|
|
21
|
+
"""
|
|
22
|
+
assets = Asset.get_all_by_parent(3, "securityplans")
|
|
23
|
+
ReportGenerator(objects=assets, to_file=True, report_name="test_report")
|
|
24
|
+
|
|
25
|
+
def test_save_to_regscale(self):
|
|
26
|
+
"""
|
|
27
|
+
Test saving the report to Regscale
|
|
28
|
+
"""
|
|
29
|
+
assets = Asset.get_all_by_parent(3, "securityplans")
|
|
30
|
+
ReportGenerator(
|
|
31
|
+
objects=assets, to_file=True, report_name="test_report", regscale_id=3, regscale_module="securityplans"
|
|
32
|
+
)
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from random import randint
|
|
3
|
+
from unittest.mock import patch
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
from lxml import etree
|
|
7
|
+
|
|
8
|
+
from regscale.integrations.commercial.nessus.nessus_utils import (
|
|
9
|
+
cpe_xml_to_dict,
|
|
10
|
+
get_cpe_file,
|
|
11
|
+
lookup_cpe_item_by_name,
|
|
12
|
+
lookup_kev,
|
|
13
|
+
)
|
|
14
|
+
from regscale.integrations.public.cisa import pull_cisa_kev
|
|
15
|
+
from regscale.models.integration_models.tenable_models.models import TenableIOAsset
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@pytest.fixture
|
|
19
|
+
def sync_vuln_result():
|
|
20
|
+
dat = {
|
|
21
|
+
"asset": {
|
|
22
|
+
"device_type": "general-purpose",
|
|
23
|
+
"hostname": "WIN-HJFQ8SOFVCP",
|
|
24
|
+
"uuid": "ef2eed0a-29b3-45a2-af6a-3d12141d1a71",
|
|
25
|
+
"ipv4": "10.40.16.200",
|
|
26
|
+
"netbios_name": "WIN-HJFQ8SOFVCP",
|
|
27
|
+
"operating_system": ["Microsoft Windows"],
|
|
28
|
+
"network_id": "32df72f3-5914-4c54-8e28-26a924c8c6ca",
|
|
29
|
+
"tracked": True,
|
|
30
|
+
},
|
|
31
|
+
"output": "\nAn SMB server is running on this port.\n",
|
|
32
|
+
"plugin": {
|
|
33
|
+
"bid": [11011],
|
|
34
|
+
"checks_for_default_account": False,
|
|
35
|
+
"checks_for_malware": False,
|
|
36
|
+
"description": "The remote service understands the CIFS (Common Internet File System) or "
|
|
37
|
+
"Server Message Block (SMB) protocol, used to provide shared access to files, "
|
|
38
|
+
"printers, etc between nodes on a network.",
|
|
39
|
+
"exploited_by_malware": False,
|
|
40
|
+
"exploited_by_nessus": False,
|
|
41
|
+
"family": "Windows",
|
|
42
|
+
"family_id": 7,
|
|
43
|
+
"id": 11011,
|
|
44
|
+
"in_the_news": False,
|
|
45
|
+
"name": "Microsoft Windows SMB Service Detection",
|
|
46
|
+
"modification_date": "2021-02-11T00:00:00Z",
|
|
47
|
+
"publication_date": "2002-06-05T00:00:00Z",
|
|
48
|
+
"risk_factor": "info",
|
|
49
|
+
"synopsis": "A file / print sharing service is listening on the remote host.",
|
|
50
|
+
"type": "REMOTE",
|
|
51
|
+
"unsupported_by_vendor": False,
|
|
52
|
+
"version": "1.43",
|
|
53
|
+
},
|
|
54
|
+
"port": {"port": 139, "protocol": "TCP", "service": "smb"},
|
|
55
|
+
"scan": {
|
|
56
|
+
"schedule_uuid": "template-0962c046-6816-1fa3-a5c4-ab987819db38a7aa1358e9a1e7eb",
|
|
57
|
+
"started_at": "2023-11-05T04:05:03.266Z",
|
|
58
|
+
"uuid": "0ec1bf66-28e1-4e19-9894-60a19556c1d9",
|
|
59
|
+
},
|
|
60
|
+
"severity": "info",
|
|
61
|
+
"severity_id": 0,
|
|
62
|
+
"severity_default_id": 0,
|
|
63
|
+
"severity_modification_type": "NONE",
|
|
64
|
+
"first_found": "2022-09-18T10:44:50.586Z",
|
|
65
|
+
"last_found": "2023-11-05T07:21:39.476Z",
|
|
66
|
+
"state": "OPEN",
|
|
67
|
+
"indexed": "2023-11-05T07:22:28.474691Z",
|
|
68
|
+
}
|
|
69
|
+
result = NessusReport(**dat)
|
|
70
|
+
return iter([result])
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@pytest.fixture
|
|
74
|
+
def cpe_items():
|
|
75
|
+
cpe_root = etree.parse(get_cpe_file())
|
|
76
|
+
dat = cpe_xml_to_dict(cpe_root)
|
|
77
|
+
return dat
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
@pytest.fixture
|
|
81
|
+
def new_assets():
|
|
82
|
+
with open("./tests/test_data/ten_assets.json", "r") as f:
|
|
83
|
+
dat = json.load(f)
|
|
84
|
+
assets = [TenableIOAsset(**a) for a in dat]
|
|
85
|
+
return assets
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
@patch("regscale.core.app.application.Application")
|
|
89
|
+
@patch("regscale.models.integration_models.tenable_models.models.TenableIOAsset.sync_to_regscale")
|
|
90
|
+
def test_fetch_assets(mock_app, new_assets):
|
|
91
|
+
# Call the fetch_assets function
|
|
92
|
+
assets = new_assets
|
|
93
|
+
app = mock_app
|
|
94
|
+
with patch.object(TenableIOAsset, "sync_to_regscale") as mock_sync:
|
|
95
|
+
mock_sync(app=app, assets=assets, ssp_id=2)
|
|
96
|
+
|
|
97
|
+
# Check that the sync_to_regscale method was called with the correct arguments
|
|
98
|
+
mock_sync.assert_called_once_with(app=app, assets=assets, ssp_id=2)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def test_kev_lookup():
|
|
102
|
+
cve = "CVE-1234-3456"
|
|
103
|
+
data = pull_cisa_kev()
|
|
104
|
+
avail = [dat["cveID"] for dat in data["vulnerabilities"]]
|
|
105
|
+
index = randint(0, len(avail))
|
|
106
|
+
assert lookup_kev(cve, data)[0] is None
|
|
107
|
+
assert lookup_kev(avail[index], data)[0]
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def test_cpe_lookup(cpe_items):
|
|
111
|
+
name = "cpe:/a:gobalsky:vega:0.49.4"
|
|
112
|
+
lookup_cpe_item_by_name(name, cpe_items)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
@pytest.mark.skip("This test needs to be updated for the new tenable rewrite.")
|
|
116
|
+
def test_sync_vulns_data(sync_vuln_result):
|
|
117
|
+
vulns = sync_vuln_result
|
|
118
|
+
assert vulns
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""Tests for the User model"""
|
|
4
|
+
|
|
5
|
+
import unittest
|
|
6
|
+
from unittest.mock import patch, MagicMock
|
|
7
|
+
|
|
8
|
+
from regscale.models.regscale_models.user import User
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class TestUser(unittest.TestCase):
|
|
12
|
+
"""Test cases for the User model"""
|
|
13
|
+
|
|
14
|
+
def setUp(self):
|
|
15
|
+
"""Set up test cases"""
|
|
16
|
+
self.test_user_data = {
|
|
17
|
+
"userName": "testuser",
|
|
18
|
+
"email": "test@example.com",
|
|
19
|
+
"firstName": "Test",
|
|
20
|
+
"lastName": "User",
|
|
21
|
+
"homePageUrl": "/custom-dashboard",
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@patch("regscale.models.regscale_models.user.User._get_api_handler")
|
|
25
|
+
def test_homepage_url_below_min_version(self, mock_api_handler):
|
|
26
|
+
"""Test homePageUrl is None when version < 6.14.0.0"""
|
|
27
|
+
# Setup mock
|
|
28
|
+
mock_handler = MagicMock()
|
|
29
|
+
mock_handler.regscale_version = "6.11.0.0"
|
|
30
|
+
mock_api_handler.return_value = mock_handler
|
|
31
|
+
|
|
32
|
+
# Create user instance
|
|
33
|
+
user = User(**self.test_user_data)
|
|
34
|
+
|
|
35
|
+
# Verify homePageUrl is None for version < 6.14.0.0
|
|
36
|
+
self.assertIsNone(user.homePageUrl)
|
|
37
|
+
# Verify the underlying field still has the value
|
|
38
|
+
self.assertEqual(user.homePageUrl_, "/custom-dashboard")
|
|
39
|
+
|
|
40
|
+
@patch("regscale.models.regscale_models.user.User._get_api_handler")
|
|
41
|
+
def test_homepage_url_at_min_version(self, mock_api_handler):
|
|
42
|
+
"""Test homePageUrl is accessible when version = 6.14.0.0"""
|
|
43
|
+
# Setup mock
|
|
44
|
+
mock_handler = MagicMock()
|
|
45
|
+
mock_handler.regscale_version = "6.14.0.0"
|
|
46
|
+
mock_api_handler.return_value = mock_handler
|
|
47
|
+
|
|
48
|
+
# Create user instance
|
|
49
|
+
user = User(**self.test_user_data)
|
|
50
|
+
|
|
51
|
+
# Verify homePageUrl is accessible for version = 6.14.0.0
|
|
52
|
+
self.assertEqual(user.homePageUrl, "/custom-dashboard")
|
|
53
|
+
|
|
54
|
+
@patch("regscale.models.regscale_models.user.User._get_api_handler")
|
|
55
|
+
def test_homepage_url_above_min_version(self, mock_api_handler):
|
|
56
|
+
"""Test homePageUrl is accessible when version > 6.14.0.0"""
|
|
57
|
+
# Setup mock
|
|
58
|
+
mock_handler = MagicMock()
|
|
59
|
+
mock_handler.regscale_version = "6.14.0.1"
|
|
60
|
+
mock_api_handler.return_value = mock_handler
|
|
61
|
+
|
|
62
|
+
# Create user instance
|
|
63
|
+
user = User(**self.test_user_data)
|
|
64
|
+
|
|
65
|
+
# Verify homePageUrl is accessible for version > 6.14.0.0
|
|
66
|
+
self.assertEqual(user.homePageUrl, "/custom-dashboard")
|
|
67
|
+
|
|
68
|
+
@patch("regscale.models.regscale_models.user.User._get_api_handler")
|
|
69
|
+
def test_homepage_url_setter(self, mock_api_handler):
|
|
70
|
+
"""Test homePageUrl setter works correctly"""
|
|
71
|
+
# Setup mock
|
|
72
|
+
mock_handler = MagicMock()
|
|
73
|
+
mock_handler.regscale_version = "6.14.0.1"
|
|
74
|
+
mock_api_handler.return_value = mock_handler
|
|
75
|
+
|
|
76
|
+
# Create user instance
|
|
77
|
+
user = User(**self.test_user_data)
|
|
78
|
+
|
|
79
|
+
# Test setting a new value
|
|
80
|
+
new_url = "/new-dashboard"
|
|
81
|
+
user.homePageUrl = new_url
|
|
82
|
+
|
|
83
|
+
# Verify both the property and underlying field are updated
|
|
84
|
+
self.assertEqual(user.homePageUrl, new_url)
|
|
85
|
+
self.assertEqual(user.homePageUrl_, new_url)
|
|
86
|
+
|
|
87
|
+
@patch("regscale.models.regscale_models.user.User._get_api_handler")
|
|
88
|
+
def test_homepage_url_default_value(self, mock_api_handler):
|
|
89
|
+
"""Test homePageUrl default value behavior"""
|
|
90
|
+
# Setup mock
|
|
91
|
+
mock_handler = MagicMock()
|
|
92
|
+
mock_handler.regscale_version = "6.14.0.0"
|
|
93
|
+
mock_api_handler.return_value = mock_handler
|
|
94
|
+
|
|
95
|
+
# Create user instance without specifying homePageUrl
|
|
96
|
+
user = User(userName="testuser", email="test@example.com")
|
|
97
|
+
|
|
98
|
+
# Verify default value is set correctly
|
|
99
|
+
self.assertEqual(user.homePageUrl, "/workbench")
|
|
100
|
+
self.assertEqual(user.homePageUrl_, "/workbench")
|
|
101
|
+
|
|
102
|
+
@patch("regscale.models.regscale_models.user.User._get_api_handler")
|
|
103
|
+
def test_homepage_url_none_value(self, mock_api_handler):
|
|
104
|
+
"""Test homePageUrl with None value"""
|
|
105
|
+
# Setup mock
|
|
106
|
+
mock_handler = MagicMock()
|
|
107
|
+
mock_handler.regscale_version = "6.14.0.0"
|
|
108
|
+
mock_api_handler.return_value = mock_handler
|
|
109
|
+
|
|
110
|
+
# Create test data with None homePageUrl
|
|
111
|
+
test_data = self.test_user_data.copy()
|
|
112
|
+
test_data["homePageUrl"] = None
|
|
113
|
+
user = User(**test_data)
|
|
114
|
+
|
|
115
|
+
# Verify None value is handled correctly
|
|
116
|
+
self.assertIsNone(user.homePageUrl)
|
|
117
|
+
self.assertIsNone(user.homePageUrl_)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
if __name__ == "__main__":
|
|
121
|
+
unittest.main()
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from unittest.mock import patch
|
|
3
|
+
from click.testing import CliRunner
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def test_about_no_variable_fetch():
|
|
7
|
+
"""
|
|
8
|
+
Test that the about command runs successfully without fetching any variables
|
|
9
|
+
"""
|
|
10
|
+
with patch("regscale.core.app.utils.variables.RsVariablesMeta.fetch_config_value") as mock_fetch:
|
|
11
|
+
# Import after patching to ensure the mock takes effect
|
|
12
|
+
from regscale.regscale import cli
|
|
13
|
+
|
|
14
|
+
runner = CliRunner()
|
|
15
|
+
result = runner.invoke(cli, ["about"])
|
|
16
|
+
|
|
17
|
+
assert result.exit_code == 0
|
|
18
|
+
assert "RegScale CLI Version:" in result.output
|
|
19
|
+
mock_fetch.assert_not_called()
|