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,47 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""Class for evidence model in RegScale platform"""
|
|
4
|
+
|
|
5
|
+
from typing import Optional
|
|
6
|
+
from pydantic import ConfigDict, Field
|
|
7
|
+
|
|
8
|
+
from regscale.models.regscale_models.regscale_model import RegScaleModel
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Evidence(RegScaleModel):
|
|
12
|
+
"""Evidence Model"""
|
|
13
|
+
|
|
14
|
+
_module_slug = "evidence"
|
|
15
|
+
_unique_fields: list[str] = [["title"]]
|
|
16
|
+
|
|
17
|
+
id: int = 0
|
|
18
|
+
isPublic: Optional[bool] = True
|
|
19
|
+
uuid: Optional[str] = None
|
|
20
|
+
title: Optional[str] = None
|
|
21
|
+
description: Optional[str] = None
|
|
22
|
+
evidenceOwnerId: Optional[str] = Field(default_factory=RegScaleModel.get_user_id)
|
|
23
|
+
updateFrequency: Optional[int] = 365
|
|
24
|
+
lastEvidenceUpdate: Optional[str] = None # YY-mm-dd
|
|
25
|
+
dueDate: Optional[str] = None # YY-mm-dd
|
|
26
|
+
|
|
27
|
+
@staticmethod
|
|
28
|
+
def _get_additional_endpoints() -> ConfigDict:
|
|
29
|
+
"""
|
|
30
|
+
Get additional endpoints for the Evidence model
|
|
31
|
+
|
|
32
|
+
:return: A dictionary of additional endpoints
|
|
33
|
+
:rtype: ConfigDict
|
|
34
|
+
"""
|
|
35
|
+
return ConfigDict(
|
|
36
|
+
get_count="/api/{model_slug}/getCount",
|
|
37
|
+
graph="/api/{model_slug}/graph",
|
|
38
|
+
graph_by_date="/api/{model_slug}/graphByDate/{strGroupBy}/{year}",
|
|
39
|
+
get_evidence_by_date="/api/{model_slug}/getEvidenceByDate/{intDays}",
|
|
40
|
+
get_controls_by_evidence="/api/{model_slug}/getControlsByEvidence/{intEvidenceId}",
|
|
41
|
+
get_evidence_by_control="/api/{model_slug}/getEvidenceByControl/{intControl}",
|
|
42
|
+
get_evidence_by_security_plan="/api/{model_slug}/getEvidenceBySecurityPlan/{intId}",
|
|
43
|
+
filter_evidence="/api/{model_slug}/filterEvidence",
|
|
44
|
+
query_by_custom_field="/api/{model_slug}/queryByCustomField/{strFieldName}/{strValue}",
|
|
45
|
+
mega_api="/api/{model_slug}/megaApi/{intId}",
|
|
46
|
+
get_my_evidence_due_soon="/api/{model_slug}/getMyEvidenceDueSoon/{intDays}/{intPage}/{intPageSize}",
|
|
47
|
+
)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""Class for evidence mapping model in RegScale platform"""
|
|
4
|
+
|
|
5
|
+
from typing import Optional
|
|
6
|
+
from pydantic import ConfigDict, Field
|
|
7
|
+
|
|
8
|
+
from regscale.core.app.utils.app_utils import get_current_datetime
|
|
9
|
+
from regscale.models.regscale_models.regscale_model import RegScaleModel
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class EvidenceMapping(RegScaleModel):
|
|
13
|
+
"""Evidence mapping Model"""
|
|
14
|
+
|
|
15
|
+
_module_slug = "evidenceMapping"
|
|
16
|
+
_module_string = "evidenceMapping"
|
|
17
|
+
|
|
18
|
+
id: int = 0
|
|
19
|
+
createdById: Optional[str] = Field(default_factory=RegScaleModel.get_user_id)
|
|
20
|
+
dateCreated: Optional[str] = Field(default_factory=get_current_datetime)
|
|
21
|
+
lastUpdatedById: Optional[str] = Field(default_factory=RegScaleModel.get_user_id)
|
|
22
|
+
dateLastUpdated: Optional[str] = Field(default_factory=get_current_datetime)
|
|
23
|
+
isPublic: Optional[bool] = True
|
|
24
|
+
evidenceID: Optional[int] = 0
|
|
25
|
+
mappedID: Optional[int] = 0
|
|
26
|
+
mappingType: Optional[str] = None
|
|
27
|
+
|
|
28
|
+
@staticmethod
|
|
29
|
+
def _get_additional_endpoints() -> ConfigDict:
|
|
30
|
+
"""
|
|
31
|
+
Get additional endpoints for the Evidence model
|
|
32
|
+
|
|
33
|
+
:return: A dictionary of additional endpoints
|
|
34
|
+
:rtype: ConfigDict
|
|
35
|
+
"""
|
|
36
|
+
return ConfigDict(
|
|
37
|
+
get_all_by_evidence="/api/{model_slug}/getAllByEvudence/{intID}",
|
|
38
|
+
get_summary_by_evidence="/api/{model_slug}/getSummaryByEvidence/{intID}",
|
|
39
|
+
batch_create="/api/{model_slug}/batchCreate",
|
|
40
|
+
)
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""Facility model for RegScale."""
|
|
2
|
+
|
|
3
|
+
import warnings
|
|
4
|
+
from typing import Optional
|
|
5
|
+
from urllib.parse import urljoin
|
|
6
|
+
|
|
7
|
+
from regscale.core.app.api import Api
|
|
8
|
+
from regscale.core.app.application import Application
|
|
9
|
+
from regscale.models.regscale_models.regscale_model import RegScaleModel
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Facility(RegScaleModel):
|
|
13
|
+
"""Data Model for Facilities"""
|
|
14
|
+
|
|
15
|
+
_module_slug = "facilities"
|
|
16
|
+
|
|
17
|
+
id: int = 0
|
|
18
|
+
name: str = ""
|
|
19
|
+
description: str = ""
|
|
20
|
+
address: str = ""
|
|
21
|
+
city: str = ""
|
|
22
|
+
state: str = ""
|
|
23
|
+
zipCode: str = ""
|
|
24
|
+
status: str = ""
|
|
25
|
+
latitude: float = 0
|
|
26
|
+
longitude: float = 0
|
|
27
|
+
createdBy: Optional[str] = None
|
|
28
|
+
createdById: Optional[str] = None
|
|
29
|
+
dateCreated: Optional[str] = None
|
|
30
|
+
lastUpdatedBy: Optional[str] = None
|
|
31
|
+
lastUpdatedById: Optional[str] = None
|
|
32
|
+
isPublic: bool = True
|
|
33
|
+
dateLastUpdated: Optional[str] = None
|
|
34
|
+
|
|
35
|
+
def post(self, app: Application) -> Optional[dict]:
|
|
36
|
+
"""Post a Facility to RegScale
|
|
37
|
+
|
|
38
|
+
:param Application app: The application instance
|
|
39
|
+
:return: The response from the API or None
|
|
40
|
+
:rtype: Optional[dict]
|
|
41
|
+
"""
|
|
42
|
+
warnings.warn(
|
|
43
|
+
"The 'post' method is deprecated, use 'create' method instead",
|
|
44
|
+
DeprecationWarning,
|
|
45
|
+
)
|
|
46
|
+
api = Api()
|
|
47
|
+
url = urljoin(app.config.get("domain", ""), "/api/facilities")
|
|
48
|
+
data = self.dict()
|
|
49
|
+
response = api.post(url, json=data)
|
|
50
|
+
return response.json() if response.ok else None
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class Facilities(Facility):
|
|
54
|
+
def __init__(self, *args, **kwargs):
|
|
55
|
+
warnings.warn(
|
|
56
|
+
"The 'Facilities' class is deprecated, use 'Facility' instead",
|
|
57
|
+
DeprecationWarning,
|
|
58
|
+
)
|
|
59
|
+
super().__init__(*args, **kwargs)
|
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
# !/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""Model for a RegScale File"""
|
|
4
|
+
|
|
5
|
+
# flake8: noqa
|
|
6
|
+
# standard python imports
|
|
7
|
+
import gzip
|
|
8
|
+
import logging
|
|
9
|
+
import mimetypes
|
|
10
|
+
import os
|
|
11
|
+
import sys
|
|
12
|
+
from io import BytesIO
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Optional, Union, Tuple
|
|
15
|
+
|
|
16
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
17
|
+
from requests import JSONDecodeError
|
|
18
|
+
|
|
19
|
+
from regscale.core.app.api import Api
|
|
20
|
+
from regscale.core.app.application import Application
|
|
21
|
+
from regscale.core.app.utils.app_utils import (
|
|
22
|
+
compute_hash,
|
|
23
|
+
error_and_exit,
|
|
24
|
+
get_current_datetime,
|
|
25
|
+
get_file_name,
|
|
26
|
+
get_file_type,
|
|
27
|
+
)
|
|
28
|
+
from regscale.models.regscale_models.tag import Tag
|
|
29
|
+
from regscale.models.regscale_models.tag_mapping import TagMapping
|
|
30
|
+
|
|
31
|
+
logger = logging.getLogger(__name__)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class File(BaseModel):
|
|
35
|
+
"""File Model"""
|
|
36
|
+
|
|
37
|
+
model_config = ConfigDict(populate_by_name=True)
|
|
38
|
+
|
|
39
|
+
# fileHash and shaHash are not required because this is due
|
|
40
|
+
# fileHash is the old method and shaHash is the new method in RegScale
|
|
41
|
+
# We are not sure which one will be used/returned
|
|
42
|
+
id: str
|
|
43
|
+
trustedDisplayName: str
|
|
44
|
+
trustedStorageName: str
|
|
45
|
+
size: int
|
|
46
|
+
fullPath: str
|
|
47
|
+
mimeType: Optional[str] = ""
|
|
48
|
+
partType: Optional[str] = ""
|
|
49
|
+
partId: Optional[str] = ""
|
|
50
|
+
folder: Optional[str] = ""
|
|
51
|
+
uploadedById: Optional[str] = None
|
|
52
|
+
uploadDate: str = Field(default_factory=get_current_datetime, alias="uploadedDate")
|
|
53
|
+
fileName: Optional[str] = Field("", alias="file_name")
|
|
54
|
+
fileHash: Optional[str] = None
|
|
55
|
+
shaHash: Optional[str] = None
|
|
56
|
+
parentId: int = 0
|
|
57
|
+
parentModule: str = ""
|
|
58
|
+
tags: Optional[str] = ""
|
|
59
|
+
|
|
60
|
+
@staticmethod
|
|
61
|
+
def download_file_from_regscale_to_memory(
|
|
62
|
+
api: Api, record_id: int, module: str, stored_name: str, file_hash: str
|
|
63
|
+
) -> bytes:
|
|
64
|
+
"""
|
|
65
|
+
Download a file from RegScale
|
|
66
|
+
|
|
67
|
+
:param Api api: API object
|
|
68
|
+
:param int record_id: RegScale record ID
|
|
69
|
+
:param str module: RegScale module
|
|
70
|
+
:param str stored_name: RegScale stored name
|
|
71
|
+
:param str file_hash: RegScale file hash
|
|
72
|
+
:return: Bytes of file as BytesIO object
|
|
73
|
+
:rtype: bytes
|
|
74
|
+
"""
|
|
75
|
+
response = api.get(
|
|
76
|
+
url=f'{api.config["domain"]}/api/files/downloadFile/{record_id}/{module}/{stored_name}/{file_hash}'
|
|
77
|
+
)
|
|
78
|
+
return response.content
|
|
79
|
+
|
|
80
|
+
@staticmethod
|
|
81
|
+
def get_files_for_parent_from_regscale(
|
|
82
|
+
parent_id: int, parent_module: str, api: Optional[Api] = None
|
|
83
|
+
) -> list["File"]:
|
|
84
|
+
"""
|
|
85
|
+
Function to download all files from RegScale for the provided parent ID and module
|
|
86
|
+
|
|
87
|
+
:param int parent_id: RegScale parent ID
|
|
88
|
+
:param str parent_module: RegScale module
|
|
89
|
+
:param Optional[Api] api: API object
|
|
90
|
+
:return: List of File objects
|
|
91
|
+
:rtype: list[File]
|
|
92
|
+
"""
|
|
93
|
+
if not api:
|
|
94
|
+
api = Api()
|
|
95
|
+
# get the files from RegScale
|
|
96
|
+
files = []
|
|
97
|
+
try:
|
|
98
|
+
file_response = api.get(url=f"{api.config['domain']}/api/files/{parent_id}/{parent_module}").json()
|
|
99
|
+
files = [File(**file) for file in file_response]
|
|
100
|
+
except JSONDecodeError:
|
|
101
|
+
api.logger.error("Unable to retrieve files from RegScale for the provided ID & module.")
|
|
102
|
+
except Exception as ex:
|
|
103
|
+
error_and_exit(f"Unable to retrieve files from RegScale.\n{ex}")
|
|
104
|
+
return files
|
|
105
|
+
|
|
106
|
+
@staticmethod
|
|
107
|
+
def delete_file(app: Application, file: "File") -> bool:
|
|
108
|
+
"""
|
|
109
|
+
Delete a file from RegScale
|
|
110
|
+
|
|
111
|
+
:param Application app: Application Instance
|
|
112
|
+
:param File file: File to delete in RegScale
|
|
113
|
+
:return: Whether the file was deleted
|
|
114
|
+
:rtype: bool
|
|
115
|
+
"""
|
|
116
|
+
api = Api()
|
|
117
|
+
|
|
118
|
+
response = api.delete(app.config["domain"] + f"/api/files/{file.id}")
|
|
119
|
+
return response.ok
|
|
120
|
+
|
|
121
|
+
@staticmethod
|
|
122
|
+
def upload_file_to_regscale(
|
|
123
|
+
file_name: str,
|
|
124
|
+
parent_id: int,
|
|
125
|
+
parent_module: str,
|
|
126
|
+
api: Api,
|
|
127
|
+
file_data: Optional[Union[bytes, dict, bool]] = None,
|
|
128
|
+
return_object: Optional[bool] = False,
|
|
129
|
+
tags: Optional[str] = None,
|
|
130
|
+
) -> Optional[Union[bytes, dict, bool]]:
|
|
131
|
+
"""
|
|
132
|
+
Function that will create and upload a file to RegScale to the provided parent_module and parent_id
|
|
133
|
+
returns whether the file upload was successful or not
|
|
134
|
+
|
|
135
|
+
:param str file_name: Path to the file to upload
|
|
136
|
+
:param int parent_id: RegScale parent ID
|
|
137
|
+
:param str parent_module: RegScale module
|
|
138
|
+
:param Api api: API object
|
|
139
|
+
:param Optional[Union[bytes, dict, bool]] file_data: File data to upload, defaults to None
|
|
140
|
+
:param Optional[bool] return_object: Whether to return the file object from RegScale, defaults to False
|
|
141
|
+
:param Optional[str] tags: Tags to add to the file, defaults to None
|
|
142
|
+
:return: Boolean indicating whether the file upload was successful or not
|
|
143
|
+
:rtype: Optional[bytes, dict, bool]
|
|
144
|
+
"""
|
|
145
|
+
|
|
146
|
+
if regscale_file := File._create_regscale_file(
|
|
147
|
+
file_path=file_name,
|
|
148
|
+
parent_id=parent_id,
|
|
149
|
+
parent_module=parent_module,
|
|
150
|
+
api=api,
|
|
151
|
+
file_data=file_data,
|
|
152
|
+
):
|
|
153
|
+
# set up headers for file upload
|
|
154
|
+
file_headers = {
|
|
155
|
+
"Authorization": api.config["token"],
|
|
156
|
+
"accept": "application/json, text/plain, */*",
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if "id" not in regscale_file:
|
|
160
|
+
ext = Path(file_name).suffix
|
|
161
|
+
api.logger.error(
|
|
162
|
+
"Unable to upload file to RegScale. Please check to see if %s "
|
|
163
|
+
+ "extension is enabled in RegScale admin files configuration.",
|
|
164
|
+
ext,
|
|
165
|
+
)
|
|
166
|
+
return False
|
|
167
|
+
|
|
168
|
+
mime_type = File.determine_mime_type(Path(file_name).suffix)
|
|
169
|
+
if not mime_type:
|
|
170
|
+
return False
|
|
171
|
+
# set up file_data payload with the regscale_file dictionary
|
|
172
|
+
new_file = File(
|
|
173
|
+
parentId=parent_id,
|
|
174
|
+
tags=tags,
|
|
175
|
+
parentModule=parent_module,
|
|
176
|
+
uploadedById=api.config["userId"],
|
|
177
|
+
mimeType=mime_type,
|
|
178
|
+
id=regscale_file["id"],
|
|
179
|
+
fullPath=regscale_file["fullPath"],
|
|
180
|
+
trustedDisplayName=regscale_file["trustedDisplayName"],
|
|
181
|
+
trustedStorageName=regscale_file["trustedStorageName"],
|
|
182
|
+
uploadDate=regscale_file["uploadDate"],
|
|
183
|
+
fileHash=regscale_file["fileHash"],
|
|
184
|
+
shaHash=regscale_file["shaHash"],
|
|
185
|
+
size=(sys.getsizeof(file_data) if file_data else regscale_file["size"]),
|
|
186
|
+
)
|
|
187
|
+
# post the regscale_file data via RegScale API
|
|
188
|
+
file_res = api.post(
|
|
189
|
+
url=f"{api.config['domain']}/api/files",
|
|
190
|
+
headers=file_headers,
|
|
191
|
+
json=new_file.dict(),
|
|
192
|
+
)
|
|
193
|
+
if file_res.ok and return_object:
|
|
194
|
+
return File(**file_res.json()).model_dump()
|
|
195
|
+
else:
|
|
196
|
+
return False
|
|
197
|
+
return file_res.ok
|
|
198
|
+
|
|
199
|
+
@staticmethod
|
|
200
|
+
def get_existing_tags_dict() -> dict:
|
|
201
|
+
"""Fetch existing tags and return a dictionary mapping tag titles to their IDs.
|
|
202
|
+
:return: Dictionary mapping tag titles to their IDs
|
|
203
|
+
:rtype: dict
|
|
204
|
+
"""
|
|
205
|
+
existing_tag_list = Tag.get_list()
|
|
206
|
+
return {tag.title: tag.id for tag in existing_tag_list}
|
|
207
|
+
|
|
208
|
+
@staticmethod
|
|
209
|
+
def process_tag(tag: str, file_id: str, tags_dict: dict):
|
|
210
|
+
"""Process a single tag and create a TagMapping if the tag exists.
|
|
211
|
+
:param str tag: The tag to process
|
|
212
|
+
:param str file_id: The file uuid
|
|
213
|
+
:param dict tags_dict: The dictionary mapping tag titles to their IDs
|
|
214
|
+
"""
|
|
215
|
+
tag_id = tags_dict.get(tag)
|
|
216
|
+
if tag_id:
|
|
217
|
+
tag_mapping = TagMapping(parentId=file_id, parentModule="files", tagId=tag_id)
|
|
218
|
+
tag_mapping.create()
|
|
219
|
+
|
|
220
|
+
@staticmethod
|
|
221
|
+
def create_tag_mappings(file_res: any):
|
|
222
|
+
"""Create tag mappings for the given file response.
|
|
223
|
+
:param any file_res: The file response from RegScale
|
|
224
|
+
"""
|
|
225
|
+
if file_id := file_res.json().get("id"):
|
|
226
|
+
tags_dict = File.get_existing_tags_dict()
|
|
227
|
+
tags = file_res.json().get("tags", "")
|
|
228
|
+
for tag in tags.replace(" ", "").split(","):
|
|
229
|
+
File.process_tag(tag, file_id, tags_dict)
|
|
230
|
+
|
|
231
|
+
@staticmethod
|
|
232
|
+
def _check_compression(
|
|
233
|
+
size_limit_mb: int = 25, file_path: str = None, file_data: Optional[bytes] = None
|
|
234
|
+
) -> Tuple[str, float]:
|
|
235
|
+
"""
|
|
236
|
+
Function to check if the file should be auto compressed.
|
|
237
|
+
|
|
238
|
+
:param int size_limit_mb: The size limit in MB, defaults to 25
|
|
239
|
+
:param str file_path: The file path, defaults to None
|
|
240
|
+
:param Optional[bytes] file_data: File data to calculate size from, defaults to None
|
|
241
|
+
:return: The file path
|
|
242
|
+
:rtype: Tuple[str, float]
|
|
243
|
+
"""
|
|
244
|
+
app = Application()
|
|
245
|
+
try:
|
|
246
|
+
size = os.path.getsize(file_path) # kb
|
|
247
|
+
except FileNotFoundError:
|
|
248
|
+
# get size from file_data
|
|
249
|
+
size = sys.getsizeof(file_data) # bytes
|
|
250
|
+
# convert bytes to kb
|
|
251
|
+
return file_path, size / 1024
|
|
252
|
+
app.logger.debug("File size: %i MB", size_limit_mb)
|
|
253
|
+
if size > size_limit_mb * 1024 * 1024:
|
|
254
|
+
app.logger.warning("The file is over %i MB. It will be compressed.", size_limit_mb)
|
|
255
|
+
# compress the file
|
|
256
|
+
output_path = Path(file_path).parent / Path(file_path).with_suffix(".gz").name
|
|
257
|
+
file_path = File._compress_file(file_path, output_path)
|
|
258
|
+
size = os.path.getsize(file_path)
|
|
259
|
+
return file_path, size
|
|
260
|
+
|
|
261
|
+
@staticmethod
|
|
262
|
+
def _compress_file(input_file_path: Union[Path, str], output_file_path: Union[Path, str]) -> str:
|
|
263
|
+
"""
|
|
264
|
+
Function to compress a file using gzip
|
|
265
|
+
|
|
266
|
+
:param Union[Path, str] input_file_path: The input file path
|
|
267
|
+
:param Union[Path, str] output_file_path: The output file path
|
|
268
|
+
:return: The output file path
|
|
269
|
+
:rtype: str
|
|
270
|
+
"""
|
|
271
|
+
with open(input_file_path, "rb") as f_in:
|
|
272
|
+
# Max compression
|
|
273
|
+
with gzip.GzipFile(filename=output_file_path, mode="wb", compresslevel=9) as f_out:
|
|
274
|
+
f_out.write(f_in.read())
|
|
275
|
+
return str(output_file_path)
|
|
276
|
+
|
|
277
|
+
@staticmethod
|
|
278
|
+
def _create_regscale_file(
|
|
279
|
+
file_path: str,
|
|
280
|
+
parent_id: int,
|
|
281
|
+
parent_module: str,
|
|
282
|
+
api: Api,
|
|
283
|
+
file_data: Optional[bytes] = None,
|
|
284
|
+
) -> Optional[dict]:
|
|
285
|
+
"""
|
|
286
|
+
Function to create a file within RegScale via API
|
|
287
|
+
:param str file_path: Path to the file
|
|
288
|
+
:param int parent_id: RegScale parent ID
|
|
289
|
+
:param str parent_module: RegScale module
|
|
290
|
+
:param Api api: API object
|
|
291
|
+
:param Optional[bytes] file_data: File data to upload, defaults to None
|
|
292
|
+
:raises: General error if unacceptable file type was provided
|
|
293
|
+
:return: Dictionary of the file object from RegScale or None
|
|
294
|
+
:rtype: Optional[dict]
|
|
295
|
+
"""
|
|
296
|
+
|
|
297
|
+
# check if the file should be auto compressed
|
|
298
|
+
file_path, file_size = File._check_compression(file_path=file_path, size_limit_mb=100, file_data=file_data)
|
|
299
|
+
|
|
300
|
+
# get the file type of the provided file_path
|
|
301
|
+
file_type = get_file_type(file_path)
|
|
302
|
+
|
|
303
|
+
# get the file name from the provided file_path
|
|
304
|
+
file_name = get_file_name(file_path)
|
|
305
|
+
|
|
306
|
+
if file_size == 0:
|
|
307
|
+
raise ValueError("File size is 0 bytes")
|
|
308
|
+
|
|
309
|
+
if file_size > 104857600:
|
|
310
|
+
mb_size = file_size / 1024 / 1024
|
|
311
|
+
limit_size = 104857600 / 1024 / 1024 # 100 MB
|
|
312
|
+
raise ValueError(f"File size is {mb_size} MB. This is over the max file size of {limit_size} MB")
|
|
313
|
+
|
|
314
|
+
# set up file headers
|
|
315
|
+
file_headers = {
|
|
316
|
+
"Authorization": api.config["token"],
|
|
317
|
+
"Accept": "application/json",
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
# get the file type header
|
|
321
|
+
file_type_header = File.determine_mime_type(file_type)
|
|
322
|
+
|
|
323
|
+
# set the files up for the RegScale API Call
|
|
324
|
+
files = [
|
|
325
|
+
(
|
|
326
|
+
"file",
|
|
327
|
+
(
|
|
328
|
+
file_name,
|
|
329
|
+
file_data or open(file_path, "rb").read(),
|
|
330
|
+
file_type_header,
|
|
331
|
+
),
|
|
332
|
+
)
|
|
333
|
+
]
|
|
334
|
+
|
|
335
|
+
file_like_object = BytesIO(file_data) if file_data else open(file_path, "rb")
|
|
336
|
+
|
|
337
|
+
with file_like_object:
|
|
338
|
+
data = {
|
|
339
|
+
"id": parent_id,
|
|
340
|
+
"module": parent_module,
|
|
341
|
+
"shaHash": compute_hash(file_like_object),
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
# make the api call
|
|
345
|
+
file_response = api.post(
|
|
346
|
+
url=f"{api.config['domain']}/api/files/file",
|
|
347
|
+
headers=file_headers,
|
|
348
|
+
data=data,
|
|
349
|
+
files=files,
|
|
350
|
+
)
|
|
351
|
+
if not file_response.ok:
|
|
352
|
+
api.logger.warning(f"{file_response.status_code} - {file_response.text}")
|
|
353
|
+
return None
|
|
354
|
+
if file_response.ok:
|
|
355
|
+
data = file_response.json()
|
|
356
|
+
data["size"] = file_size
|
|
357
|
+
return data
|
|
358
|
+
|
|
359
|
+
@staticmethod
|
|
360
|
+
def determine_mime_type(file_type: str) -> Optional[str]:
|
|
361
|
+
"""
|
|
362
|
+
Function to determine the mime type of a file
|
|
363
|
+
|
|
364
|
+
:param str file_type: The file type
|
|
365
|
+
:return: The mime type, if able to determine
|
|
366
|
+
:rtype: Optional[str]
|
|
367
|
+
"""
|
|
368
|
+
# see file_type is an acceptable format and set the file_type_header accordingly
|
|
369
|
+
try:
|
|
370
|
+
file_type_header = mimetypes.types_map[file_type]
|
|
371
|
+
except KeyError:
|
|
372
|
+
if file_type == ".xlsx":
|
|
373
|
+
file_type_header = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
|
374
|
+
elif file_type == ".nessus":
|
|
375
|
+
file_type_header = "text/xml"
|
|
376
|
+
elif file_type == ".gz":
|
|
377
|
+
file_type_header = "application/gzip"
|
|
378
|
+
else:
|
|
379
|
+
logger = logging.getLogger("regscale")
|
|
380
|
+
logger.warning(f"Unacceptable file type for upload: {file_type}")
|
|
381
|
+
return None
|
|
382
|
+
return file_type_header
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
from pydantic import Field
|
|
5
|
+
|
|
6
|
+
from regscale.core.app.utils.app_utils import get_current_datetime
|
|
7
|
+
from regscale.models.regscale_models.regscale_model import RegScaleModel
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class TagTypeEnum(Enum):
|
|
11
|
+
"""
|
|
12
|
+
TagTypeEnum class
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
SYSTEM = "System"
|
|
16
|
+
EXPORT = "Export"
|
|
17
|
+
IMPORT = "Import"
|
|
18
|
+
DATA = "Data"
|
|
19
|
+
USER = "User"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class FileTag(RegScaleModel):
|
|
23
|
+
_module_slug = "filetags"
|
|
24
|
+
|
|
25
|
+
id: int = 0
|
|
26
|
+
uuid: Optional[str] = None
|
|
27
|
+
title: str = "" # required
|
|
28
|
+
tagType: TagTypeEnum = TagTypeEnum.USER.value # default to user. Use System for Export or Import
|
|
29
|
+
isPublic: bool = True
|
|
30
|
+
OscalRequired: bool = False
|
|
31
|
+
tagColor: Optional[str] = None # not currently implemented yet
|
|
32
|
+
tagTextColor: Optional[str] = None # not currently implemented yet
|
|
33
|
+
tenantsId: int = 1
|
|
34
|
+
createdById: str = Field(default_factory=RegScaleModel.get_user_id)
|
|
35
|
+
dateCreated: str = Field(default_factory=get_current_datetime)
|
|
36
|
+
lastUpdatedById: str = Field(default_factory=RegScaleModel.get_user_id)
|
|
37
|
+
dateLastUpdated: str = Field(default_factory=get_current_datetime)
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""Model for Custom Fields in the application"""
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
from typing import Any, List, Optional, Dict
|
|
7
|
+
|
|
8
|
+
from pydantic import ConfigDict, Field
|
|
9
|
+
|
|
10
|
+
from regscale.models.regscale_models.regscale_model import RegScaleModel
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class FormFieldValue(RegScaleModel):
|
|
16
|
+
_module_slug = "formFieldValue"
|
|
17
|
+
formFieldName: Optional[str] = None
|
|
18
|
+
formFieldId: Optional[int] = None
|
|
19
|
+
data: Optional[str] = Field(default=None, alias="fieldValue")
|
|
20
|
+
|
|
21
|
+
@staticmethod
|
|
22
|
+
def _get_additional_endpoints() -> ConfigDict:
|
|
23
|
+
"""
|
|
24
|
+
Get additional endpoints for the CustomFieldData model.
|
|
25
|
+
record id is the recordId like cases id or change id
|
|
26
|
+
formId is the tab_id from the module calls
|
|
27
|
+
:return: A dictionary of additional endpoints
|
|
28
|
+
:rtype: ConfigDict
|
|
29
|
+
"""
|
|
30
|
+
return ConfigDict(
|
|
31
|
+
post_save_form_fields="/api/{model_slug}/saveFormFields/{recordId}/{moduleName}",
|
|
32
|
+
get_field_value="/api/{model_slug}/getFieldValues/{recordId}/{moduleName}/{formId}",
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
@staticmethod
|
|
36
|
+
def filter_dict_keys(data: Dict[str, Any], allowed_fields: List[str]) -> Dict[str, Any]:
|
|
37
|
+
"""
|
|
38
|
+
Return a new dictionary containing only the keys from allowed_fields.
|
|
39
|
+
|
|
40
|
+
:param data: The original dictionary.
|
|
41
|
+
:param allowed_fields: A list of keys to keep in the dictionary.
|
|
42
|
+
:return: A new dictionary with only the allowed keys.
|
|
43
|
+
"""
|
|
44
|
+
return {key: value for key, value in data.items() if key in allowed_fields}
|
|
45
|
+
|
|
46
|
+
@classmethod
|
|
47
|
+
def save_custom_data(cls, record_id: int, module_name: str, data: List[Any]) -> bool:
|
|
48
|
+
"""
|
|
49
|
+
Save custom data for a record
|
|
50
|
+
:param record_id: record id
|
|
51
|
+
:param module_name: module name
|
|
52
|
+
:param data: data to save
|
|
53
|
+
:return: list of custom fields
|
|
54
|
+
"""
|
|
55
|
+
fields = ["formFieldId", "data"]
|
|
56
|
+
|
|
57
|
+
# Suppose data is a list of Pydantic model instances.
|
|
58
|
+
# First, convert each instance to a dict.
|
|
59
|
+
data_dicts = [d.dict() for d in data]
|
|
60
|
+
|
|
61
|
+
# Now, filter each dictionary so that only the keys in `fields` remain.
|
|
62
|
+
filtered_data = [cls.filter_dict_keys(item, fields) for item in data_dicts]
|
|
63
|
+
|
|
64
|
+
result = cls._get_api_handler().post(
|
|
65
|
+
endpoint=cls.get_endpoint("post_save_form_fields").format(
|
|
66
|
+
model_slug=cls.get_module_slug(), recordId=record_id, moduleName=module_name
|
|
67
|
+
),
|
|
68
|
+
data=filtered_data,
|
|
69
|
+
)
|
|
70
|
+
if result and result.ok:
|
|
71
|
+
return True
|
|
72
|
+
else:
|
|
73
|
+
cls.log_response_error(response=result)
|
|
74
|
+
return False
|
|
75
|
+
|
|
76
|
+
@classmethod
|
|
77
|
+
def get_field_values(cls, record_id: int, module_name: str, form_id: int) -> List["FormFieldValue"]:
|
|
78
|
+
"""
|
|
79
|
+
Get custom data for a record
|
|
80
|
+
:param record_id: record id
|
|
81
|
+
:param module_name: module name
|
|
82
|
+
:param form_id: form id
|
|
83
|
+
:return: list of custom fields
|
|
84
|
+
"""
|
|
85
|
+
result = cls._get_api_handler().get(
|
|
86
|
+
endpoint=cls.get_endpoint("get_field_value").format(
|
|
87
|
+
model_slug=cls.get_module_slug(), recordId=record_id, moduleName=module_name, formId=form_id
|
|
88
|
+
)
|
|
89
|
+
)
|
|
90
|
+
if result and result.ok:
|
|
91
|
+
return [cls(**o) for o in result.json()]
|
|
92
|
+
else:
|
|
93
|
+
cls.log_response_error(response=result)
|
|
94
|
+
return []
|