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,496 @@
|
|
|
1
|
+
"""Module to parse the back-matter and resources from an SSP and post the items into RegScale"""
|
|
2
|
+
|
|
3
|
+
# flake8: noqa: C901
|
|
4
|
+
import base64
|
|
5
|
+
import json
|
|
6
|
+
import mimetypes
|
|
7
|
+
from io import BytesIO
|
|
8
|
+
from typing import Any, List, Optional
|
|
9
|
+
|
|
10
|
+
from lxml.etree import Element
|
|
11
|
+
|
|
12
|
+
from regscale.core.app.api import Api
|
|
13
|
+
from regscale.core.app.application import Application
|
|
14
|
+
from regscale.core.app.logz import create_logger
|
|
15
|
+
from regscale.integrations.public.fedramp.reporting import log_error, log_event
|
|
16
|
+
from regscale.models.regscale_models import File, Link, Reference
|
|
17
|
+
|
|
18
|
+
logger = create_logger()
|
|
19
|
+
RESOURCE = "Resources"
|
|
20
|
+
NS_TITLE = "ns1:title"
|
|
21
|
+
NS_CAPTION = "ns1:caption"
|
|
22
|
+
NS_DESC = "ns1:description"
|
|
23
|
+
NS_PROP = 'ns1:prop[@name="type"]'
|
|
24
|
+
|
|
25
|
+
TYPE_MAPPING = [
|
|
26
|
+
("Acronym", "acronyms"),
|
|
27
|
+
("Administrator Guide", "administrators-guide"),
|
|
28
|
+
("Agreement", "agreement"),
|
|
29
|
+
("Artifact", "artifact"),
|
|
30
|
+
("Citation", "citations"),
|
|
31
|
+
("Evidence", "evidence"),
|
|
32
|
+
("Guidance", "external-guidance"),
|
|
33
|
+
("Image", "image"),
|
|
34
|
+
("Interview Notes", "interview-notes"),
|
|
35
|
+
("Law", "law"),
|
|
36
|
+
("Logo", "logo"),
|
|
37
|
+
("Plan", "plan"),
|
|
38
|
+
("Policy", "policy"),
|
|
39
|
+
("Procedure", "procedure"),
|
|
40
|
+
("Questionnaire", "questionnaire"),
|
|
41
|
+
("Raw Data", "raw-data"),
|
|
42
|
+
("Regulation", "regulation"),
|
|
43
|
+
("Report", "report"),
|
|
44
|
+
("Rules of Behavior", "rules-of-behavior"),
|
|
45
|
+
("Screenshot", "screen-shot"),
|
|
46
|
+
("Standard", "standard"),
|
|
47
|
+
("System Guide", "system-guide"),
|
|
48
|
+
("Tool Output", "tool-output"),
|
|
49
|
+
("User Guide", "users-guide"),
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def parse_backmatter(resource_elem: Any, back_matter: Any, root: Any, ns: dict, ssp_id: int, events_list: list) -> dict:
|
|
54
|
+
"""
|
|
55
|
+
A function to parse a <resource> element from an SSP and post it to RegScale
|
|
56
|
+
|
|
57
|
+
:param Any resource_elem: The data element that is being passed to be parsed into a resource
|
|
58
|
+
:param Any back_matter: The back-matter element of the SSP
|
|
59
|
+
:param Any root: The root element of the xml document
|
|
60
|
+
:param dict ns: Namespace dict to use for xpath element selection
|
|
61
|
+
:param int ssp_id: SSP ID in RegScale
|
|
62
|
+
:param list events_list: List of events to send to logs
|
|
63
|
+
:return: dictionary containing the results of the resource uploads
|
|
64
|
+
:rtype: dict
|
|
65
|
+
"""
|
|
66
|
+
app = Application()
|
|
67
|
+
api = Api()
|
|
68
|
+
results = {
|
|
69
|
+
"filesUploaded": 0,
|
|
70
|
+
"linksCreated": 0,
|
|
71
|
+
"referencesCreated": 0,
|
|
72
|
+
}
|
|
73
|
+
# remove resources that do not have a uuid
|
|
74
|
+
resources = {
|
|
75
|
+
resource.attrib["uuid"]: resource_to_dict(resource)
|
|
76
|
+
for resource in resource_elem
|
|
77
|
+
if resource.attrib.get("uuid") is not None
|
|
78
|
+
}
|
|
79
|
+
# iterate the resources and put them in the right list
|
|
80
|
+
for uuid, resource in resources.items():
|
|
81
|
+
# check for references of the uuid elsewhere
|
|
82
|
+
matching_elements = root.xpath(f".//*[@uuid='{uuid}']", namespaces=ns)
|
|
83
|
+
|
|
84
|
+
# Exclude back-matter from results
|
|
85
|
+
if filtered_elements := [el for el in matching_elements if back_matter not in el.iterancestors()]:
|
|
86
|
+
resource["references"] = filtered_elements
|
|
87
|
+
|
|
88
|
+
if resource["hasBase64"]:
|
|
89
|
+
upload = File.upload_file_to_regscale(
|
|
90
|
+
file_name=resource["base64_filename"],
|
|
91
|
+
parent_id=ssp_id,
|
|
92
|
+
parent_module="securityplans",
|
|
93
|
+
api=api,
|
|
94
|
+
file_data=base64.b64decode(resource["base64_data"]),
|
|
95
|
+
return_object=True,
|
|
96
|
+
)
|
|
97
|
+
if upload:
|
|
98
|
+
results["filesUploaded"] += 1
|
|
99
|
+
events_list.append(
|
|
100
|
+
log_event(
|
|
101
|
+
record_type="File",
|
|
102
|
+
event_msg=f"File {resource['base64_filename']} uploaded successfully.",
|
|
103
|
+
model_layer=RESOURCE,
|
|
104
|
+
)
|
|
105
|
+
)
|
|
106
|
+
else:
|
|
107
|
+
events_list.append(
|
|
108
|
+
log_error(
|
|
109
|
+
record_type="File",
|
|
110
|
+
event_msg=f"File {resource['base64_filename']} failed to upload.",
|
|
111
|
+
model_layer=RESOURCE,
|
|
112
|
+
)
|
|
113
|
+
)
|
|
114
|
+
# if there is no base64, then there should be a link
|
|
115
|
+
other_attributes = None
|
|
116
|
+
if "title_rlink_href" in resource:
|
|
117
|
+
other_attributes = None
|
|
118
|
+
try:
|
|
119
|
+
if "title_prop" in resource:
|
|
120
|
+
other_attributes = ", ".join(
|
|
121
|
+
[
|
|
122
|
+
f"{key}: {value}"
|
|
123
|
+
for key, value in resource["title_prop"].items()
|
|
124
|
+
if resource.get("title_prop")
|
|
125
|
+
]
|
|
126
|
+
)
|
|
127
|
+
except KeyError:
|
|
128
|
+
other_attributes = None
|
|
129
|
+
link_to_post = Link(
|
|
130
|
+
title=resource.get("title") or uuid,
|
|
131
|
+
url=resource["title_rlink_href"],
|
|
132
|
+
parentID=ssp_id,
|
|
133
|
+
parentModule="securityplans",
|
|
134
|
+
createdById=app.config["userId"],
|
|
135
|
+
externalId=uuid,
|
|
136
|
+
otherAttributes=other_attributes,
|
|
137
|
+
)
|
|
138
|
+
if _ := Link.insert_link(app, link_to_post):
|
|
139
|
+
results["linksCreated"] += 1
|
|
140
|
+
events_list.append(
|
|
141
|
+
log_event(
|
|
142
|
+
record_type="Link",
|
|
143
|
+
event_msg=f"Link {resource['title_rlink_href']} created successfully.",
|
|
144
|
+
model_layer=RESOURCE,
|
|
145
|
+
)
|
|
146
|
+
)
|
|
147
|
+
else:
|
|
148
|
+
events_list.append(
|
|
149
|
+
log_error(
|
|
150
|
+
record_type="Link",
|
|
151
|
+
event_msg=f"Link {resource['title_rlink_href']} failed to be created.",
|
|
152
|
+
model_layer=RESOURCE,
|
|
153
|
+
)
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
if references := resource.get("references"):
|
|
157
|
+
for reference in references:
|
|
158
|
+
if post_dict_reference(
|
|
159
|
+
api=api,
|
|
160
|
+
ssp_id=ssp_id,
|
|
161
|
+
reference_data=reference_to_dict(reference, ns),
|
|
162
|
+
resource_uuid=uuid,
|
|
163
|
+
resource=resource,
|
|
164
|
+
):
|
|
165
|
+
results["referencesCreated"] += 1
|
|
166
|
+
events_list.append(
|
|
167
|
+
log_event(
|
|
168
|
+
record_type="Reference",
|
|
169
|
+
event_msg=f"Reference {reference.attrib['uuid']} created successfully.",
|
|
170
|
+
model_layer=RESOURCE,
|
|
171
|
+
)
|
|
172
|
+
)
|
|
173
|
+
else:
|
|
174
|
+
events_list.append(
|
|
175
|
+
log_error(
|
|
176
|
+
record_type="Reference",
|
|
177
|
+
event_msg=f"Reference {reference.attrib['uuid']} failed to be created.",
|
|
178
|
+
model_layer=RESOURCE,
|
|
179
|
+
)
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
return results
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def post_dict_reference(
|
|
186
|
+
api: Api, ssp_id: int, reference_data: dict, resource: dict, resource_uuid: str
|
|
187
|
+
) -> Optional[Reference]:
|
|
188
|
+
"""
|
|
189
|
+
A function to post a reference to RegScale
|
|
190
|
+
|
|
191
|
+
:param Api api: Api object
|
|
192
|
+
:param int ssp_id: ID of the SSP to post the reference to
|
|
193
|
+
:param dict reference_data: Reference to parse and post to RegScale
|
|
194
|
+
:param dict resource: Resource that the reference is associated with
|
|
195
|
+
:param str resource_uuid: UUID of the resource that the reference is associated with
|
|
196
|
+
:return: Reference object if successful, None otherwise
|
|
197
|
+
:rtype: Optional[Reference]
|
|
198
|
+
"""
|
|
199
|
+
reference_to_post = Reference(
|
|
200
|
+
createdById=api.config["userId"],
|
|
201
|
+
identificationNumber=resource_uuid,
|
|
202
|
+
title=reference_data.get("title"),
|
|
203
|
+
parentId=ssp_id,
|
|
204
|
+
parentModule="securityplans",
|
|
205
|
+
referenceType="Other",
|
|
206
|
+
link=resource.get("base64_filename") or resource.get("title_rlink_href"),
|
|
207
|
+
)
|
|
208
|
+
return reference_to_post.create_new_references(return_object=True)
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def reference_to_dict(reference: Element, ns: dict) -> dict:
|
|
212
|
+
"""
|
|
213
|
+
Function to convert a reference, lxml Element, into a dictionary
|
|
214
|
+
|
|
215
|
+
:param Element reference: reference to parse
|
|
216
|
+
:param dict ns: Namespace dict to use for xpath element selection
|
|
217
|
+
:return: dictionary of the provided reference
|
|
218
|
+
:rtype: dict
|
|
219
|
+
"""
|
|
220
|
+
ref = {}
|
|
221
|
+
# DESCRIPTION
|
|
222
|
+
if reference.find(NS_DESC, namespaces=ns) is not None:
|
|
223
|
+
ref["description"] = ""
|
|
224
|
+
for p in reference.find(NS_DESC, namespaces=ns).findall("ns1:p", namespaces=ns):
|
|
225
|
+
ref["description"] = ref["description"] + p.text + " "
|
|
226
|
+
|
|
227
|
+
# TITLE (RegScale required)
|
|
228
|
+
if reference.find(NS_TITLE, namespaces=ns) is not None: # first check for title element
|
|
229
|
+
ref["title"] = reference.find(NS_TITLE, namespaces=ns).text
|
|
230
|
+
elif reference.find(NS_CAPTION, namespaces=ns) is not None: # if not that, use caption for title
|
|
231
|
+
ref["title"] = reference.find(NS_CAPTION, namespaces=ns).text
|
|
232
|
+
elif reference.find(NS_DESC, namespaces=ns) is not None: # if no caption, use description up to 50 char
|
|
233
|
+
ref["title"] = ref["description"][:50]
|
|
234
|
+
else: # if all else fails, just make it "Untitled
|
|
235
|
+
ref["title"] = "Untitled"
|
|
236
|
+
|
|
237
|
+
# TYPE (RegScale required)
|
|
238
|
+
if reference.find(NS_PROP, namespaces=ns) is not None:
|
|
239
|
+
ref["referenceType"] = apply_type_mapping(
|
|
240
|
+
TYPE_MAPPING,
|
|
241
|
+
reference.find(NS_PROP, namespaces=ns)[0].text,
|
|
242
|
+
)
|
|
243
|
+
else:
|
|
244
|
+
ref["referenceType"] = "Other"
|
|
245
|
+
|
|
246
|
+
return ref
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def apply_type_mapping(mapping: List[tuple], value: str) -> Any:
|
|
250
|
+
"""
|
|
251
|
+
A function to apply a mapping to a value
|
|
252
|
+
|
|
253
|
+
:param List[tuple] mapping: List of mapping pair tuples - (new, original)
|
|
254
|
+
:param str value: Thing to be mapped to a new value
|
|
255
|
+
:return: The new value
|
|
256
|
+
:rtype: Any
|
|
257
|
+
"""
|
|
258
|
+
for new, original in mapping:
|
|
259
|
+
if value == original:
|
|
260
|
+
value = new
|
|
261
|
+
break
|
|
262
|
+
else:
|
|
263
|
+
value = "Other"
|
|
264
|
+
return value
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
def resource_to_dict(resource: Element) -> dict:
|
|
268
|
+
"""
|
|
269
|
+
Recursive function to convert a lxml Element into a dictionary
|
|
270
|
+
|
|
271
|
+
:param Element resource: The lxml Element to convert to a dict
|
|
272
|
+
:return: Dictionary representation of the Element
|
|
273
|
+
:rtype: dict
|
|
274
|
+
"""
|
|
275
|
+
resource_dict = {"hasBase64": False} # Initialize dictionary for each resource
|
|
276
|
+
|
|
277
|
+
for child in resource:
|
|
278
|
+
tag = str(child.tag).split("}")[-1] # Convert tag to string and then strip namespace
|
|
279
|
+
|
|
280
|
+
if tag == "title":
|
|
281
|
+
resource_dict["title"] = child.text
|
|
282
|
+
|
|
283
|
+
elif tag == "description":
|
|
284
|
+
for p_tag in child.findall(".//p"):
|
|
285
|
+
resource_dict["title_description"] = p_tag.text
|
|
286
|
+
|
|
287
|
+
elif tag == "prop":
|
|
288
|
+
name = child.get("name")
|
|
289
|
+
value = child.get("value")
|
|
290
|
+
if name and value:
|
|
291
|
+
resource_dict["title_prop"] = {"name": name, "value": value}
|
|
292
|
+
|
|
293
|
+
elif tag == "rlink":
|
|
294
|
+
href = child.get("href")
|
|
295
|
+
media_type = child.get("media-type")
|
|
296
|
+
if href:
|
|
297
|
+
resource_dict["title_rlink_href"] = href
|
|
298
|
+
if media_type:
|
|
299
|
+
resource_dict["title_media-type"] = media_type
|
|
300
|
+
|
|
301
|
+
elif tag == "base64":
|
|
302
|
+
resource_dict["hasBase64"] = True
|
|
303
|
+
base64_data = child.text.strip() # Get base64 content and strip whitespace
|
|
304
|
+
filename = child.get("filename")
|
|
305
|
+
media_type = child.get("media-type")
|
|
306
|
+
resource_dict["base64_data"] = base64_data
|
|
307
|
+
if filename:
|
|
308
|
+
resource_dict["base64_filename"] = filename
|
|
309
|
+
if media_type:
|
|
310
|
+
resource_dict["base64_media-type"] = media_type
|
|
311
|
+
|
|
312
|
+
return resource_dict
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
def parse_title(resource: Any, ref: dict, ns: dict, resource_elem: Any) -> str:
|
|
316
|
+
"""
|
|
317
|
+
Function to parse the title of a resource
|
|
318
|
+
|
|
319
|
+
:param Any resource: The resource to parse
|
|
320
|
+
:param dict ref: Reference dictionary
|
|
321
|
+
:param dict ns: Namespace dictionary
|
|
322
|
+
:param Any resource_elem: The resource element to parse
|
|
323
|
+
:return: The title of the resource
|
|
324
|
+
:rtype: str
|
|
325
|
+
"""
|
|
326
|
+
if resource.find(NS_TITLE, namespaces=ns) is not None: # first check for title element
|
|
327
|
+
return resource.find(NS_TITLE, namespaces=ns).text
|
|
328
|
+
elif resource.find(NS_CAPTION, namespaces=ns) is not None: # if not that, use caption for title
|
|
329
|
+
return resource.find(NS_CAPTION, namespaces=ns).text
|
|
330
|
+
elif resource_elem.find(NS_CAPTION, namespaces=ns) is not None: # also check referring element for caption
|
|
331
|
+
return resource_elem.find(NS_CAPTION, namespaces=ns).text
|
|
332
|
+
elif resource.find(NS_DESC, namespaces=ns) is not None: # if no caption, use description up to to 50 char
|
|
333
|
+
return ref["description"][:50]
|
|
334
|
+
else: # if all else fails, just make it "Untitled
|
|
335
|
+
return "Untitled"
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
def record_resource(resource_elem: Any, root: Any, ns: dict, ssp_id: int, tags: Optional[Any] = None) -> None:
|
|
339
|
+
"""
|
|
340
|
+
A function to parse a <resource> element from an SSP and post it to RegScale
|
|
341
|
+
|
|
342
|
+
:param Any resource_elem: The data element that is being passed to be parsed into a resource
|
|
343
|
+
:param Any root: The root element of the xml document
|
|
344
|
+
:param dict ns: Namespace dict to use for xpath element selection
|
|
345
|
+
:param int ssp_id: SSP ID in RegScale
|
|
346
|
+
:param Optional[Any] tags: Optional string of semicolon-delimited tags to identify specific critical assets like network diagrams, defaults to None
|
|
347
|
+
:rtype: None
|
|
348
|
+
"""
|
|
349
|
+
api = Api()
|
|
350
|
+
object_uuid = resource_elem.attrib[
|
|
351
|
+
"uuid"
|
|
352
|
+
] # the id of the object that the back-matter resource is intended to describe
|
|
353
|
+
resource_link_id = resource_elem.find("ns1:link", namespaces=ns).attrib["href"].replace("#", "") # get uuid URI
|
|
354
|
+
|
|
355
|
+
# find the <resource> assembly whose uuid matches the URI
|
|
356
|
+
query_string = f"/ns1:system-security-plan/ns1:back-matter/ns1:resource[@uuid='{resource_link_id}']"
|
|
357
|
+
resource = root.xpath(query_string, namespaces=ns)[0]
|
|
358
|
+
|
|
359
|
+
ref = {}
|
|
360
|
+
|
|
361
|
+
# DESCRIPTION
|
|
362
|
+
if resource.find(NS_DESC, namespaces=ns) is not None:
|
|
363
|
+
ref["description"] = ""
|
|
364
|
+
for p in resource.find(NS_DESC, namespaces=ns).findall("ns1:p", namespaces=ns):
|
|
365
|
+
ref["description"] = ref["description"] + p.text + " "
|
|
366
|
+
|
|
367
|
+
# TITLE (RegScale required)
|
|
368
|
+
ref["title"] = parse_title(resource, ref, ns, resource_elem)
|
|
369
|
+
|
|
370
|
+
# TYPE (RegScale required)
|
|
371
|
+
if resource.find(NS_PROP, namespaces=ns) is not None:
|
|
372
|
+
ref["referenceType"] = apply_type_mapping(TYPE_MAPPING, resource.find(NS_PROP, namespaces=ns)[0].text)
|
|
373
|
+
else:
|
|
374
|
+
ref["referenceType"] = "Other"
|
|
375
|
+
# PARENT
|
|
376
|
+
ref["parentID"] = ssp_id
|
|
377
|
+
ref["parentModule"] = "securityplans"
|
|
378
|
+
if object_uuid is not None:
|
|
379
|
+
ref["identificationNumber"] = object_uuid
|
|
380
|
+
|
|
381
|
+
# RLINKS
|
|
382
|
+
for rlink in resource.findall("ns1:rlink", namespaces=ns):
|
|
383
|
+
new_reference = ref # start a new instance of a reference with the shared default values
|
|
384
|
+
new_reference["link"] = rlink.attrib["href"]
|
|
385
|
+
post_reference(new_reference)
|
|
386
|
+
|
|
387
|
+
# BASE64
|
|
388
|
+
for base64elem in resource.findall("ns1:base64", namespaces=ns):
|
|
389
|
+
new_reference = ref # start a new instance of a reference with the shared default values
|
|
390
|
+
new_reference["link"] = base64elem.attrib["filename"]
|
|
391
|
+
post_reference(new_reference)
|
|
392
|
+
file_metadata = {
|
|
393
|
+
"trustedDisplayName": base64elem.attrib["filename"],
|
|
394
|
+
"filesize": len(base64elem.text) * 0.75 - (base64elem.text[len(base64elem.text) - 2 :].count("=")),
|
|
395
|
+
}
|
|
396
|
+
if "media-type" in base64elem.attrib:
|
|
397
|
+
file_metadata["mimeType"] = base64elem.attrib["media-type"]
|
|
398
|
+
else:
|
|
399
|
+
file_metadata["mimeType"], _ = mimetypes.guess_type(file_metadata["trustedDisplayName"])
|
|
400
|
+
if tags:
|
|
401
|
+
file_metadata["tags"] = tags
|
|
402
|
+
file_metadata["parentId"] = (ssp_id,)
|
|
403
|
+
file_metadata["ParentModule"] = ("securityplans",)
|
|
404
|
+
file_response = File.upload_file_to_regscale(
|
|
405
|
+
file_name=file_metadata["trustedDisplayName"],
|
|
406
|
+
parent_id=ssp_id,
|
|
407
|
+
parent_module="securityplans",
|
|
408
|
+
api=api,
|
|
409
|
+
file_data=base64.b64decode(base64elem.text),
|
|
410
|
+
)
|
|
411
|
+
logger.info(file_response)
|
|
412
|
+
# upload_base64_file(file_metadata, base64elem.text, ssp_id)
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
def post_reference(reference_dict: dict) -> None:
|
|
416
|
+
"""
|
|
417
|
+
A function to post a reference to RegScale
|
|
418
|
+
|
|
419
|
+
:param dict reference_dict: Reference object to post to RegScale
|
|
420
|
+
:rtype: None
|
|
421
|
+
"""
|
|
422
|
+
app = Application()
|
|
423
|
+
api = Api()
|
|
424
|
+
headers_json = {
|
|
425
|
+
"accept": "*/*",
|
|
426
|
+
"Content-Type": "application/json-patch+json",
|
|
427
|
+
"Authorization": app.config["token"],
|
|
428
|
+
}
|
|
429
|
+
ssp_json = json.dumps(reference_dict)
|
|
430
|
+
response = api.post(
|
|
431
|
+
url=app.config["domain"] + "/api/references",
|
|
432
|
+
data=ssp_json,
|
|
433
|
+
headers=headers_json,
|
|
434
|
+
)
|
|
435
|
+
if response.status_code == 200:
|
|
436
|
+
ref_id = json.loads(response.text)["id"]
|
|
437
|
+
ref_title = reference_dict["title"]
|
|
438
|
+
log_event(
|
|
439
|
+
record_type="Resource",
|
|
440
|
+
model_layer="Back-matter",
|
|
441
|
+
event_msg=f"Successfully posted reference #: {ref_id} - {ref_title}.",
|
|
442
|
+
)
|
|
443
|
+
else:
|
|
444
|
+
log_error(
|
|
445
|
+
record_type="Resource",
|
|
446
|
+
model_layer="Back-matter",
|
|
447
|
+
event_msg="Problem posting reference.",
|
|
448
|
+
)
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
def upload_base64_file(file_metadata: dict, filestring: str, ssp_id: int) -> None:
|
|
452
|
+
"""
|
|
453
|
+
A function to upload a base64 file to RegScale
|
|
454
|
+
|
|
455
|
+
:param dict file_metadata: Metadata for the file to be uploaded
|
|
456
|
+
:param str filestring: The base64 string of the file to be uploaded
|
|
457
|
+
:param int ssp_id: The ID of the SSP to upload the file to
|
|
458
|
+
:rtype: None
|
|
459
|
+
"""
|
|
460
|
+
app = Application()
|
|
461
|
+
api = Api()
|
|
462
|
+
decoded_file = base64.b64decode(filestring)
|
|
463
|
+
files = {"file": (file_metadata["trustedDisplayName"], BytesIO(decoded_file))}
|
|
464
|
+
data = {"id": ssp_id, "module": "securityplans"}
|
|
465
|
+
response = api.post(
|
|
466
|
+
url=app.config["domain"] + "/files/file",
|
|
467
|
+
files=files,
|
|
468
|
+
data=data,
|
|
469
|
+
)
|
|
470
|
+
if response.status_code == 200:
|
|
471
|
+
logger.info("File uploaded successfully!")
|
|
472
|
+
logger.debug("Response content:", response.text)
|
|
473
|
+
response_data = json.loads(response.text)
|
|
474
|
+
|
|
475
|
+
file_metadata["fullPath"] = (response_data["fullPath"],)
|
|
476
|
+
file_metadata["fileHash"] = (response_data["fileHash"],)
|
|
477
|
+
file_metadata["shaHash"] = (response_data["shaHash"],)
|
|
478
|
+
file_metadata["uploadDate"] = (response_data["uploadDate"],)
|
|
479
|
+
|
|
480
|
+
file_metadata_json = json.dumps(file_metadata)
|
|
481
|
+
response = api.post(
|
|
482
|
+
url=app.config["domain"] + "/files",
|
|
483
|
+
data=file_metadata_json,
|
|
484
|
+
)
|
|
485
|
+
if response.status_code == 200:
|
|
486
|
+
logger.info("File entered to database")
|
|
487
|
+
logger.debug(response.text)
|
|
488
|
+
else:
|
|
489
|
+
logger.debug(response.status_code)
|
|
490
|
+
logger.debug(response.text)
|
|
491
|
+
|
|
492
|
+
elif response.status_code == 401:
|
|
493
|
+
logger.info("401: Unauthorized")
|
|
494
|
+
else:
|
|
495
|
+
logger.info("File upload failed. Status code:", response.status_code)
|
|
496
|
+
logger.debug("Response content:", response.text)
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Rosetta Stone class Standardized approach to mapping identifiers between control id in FedRAMP and other frameworks
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from typing import Dict
|
|
7
|
+
from regscale.core.decorators import singleton
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@singleton
|
|
12
|
+
class RosettaStone:
|
|
13
|
+
"""
|
|
14
|
+
Rosetta Stone class Standardized approach to mapping identifiers between control id in FedRAMP and other frameworks
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def __init__(self):
|
|
18
|
+
self.map = None
|
|
19
|
+
self.rs_data = {}
|
|
20
|
+
self.rosetta = {}
|
|
21
|
+
self.name = ""
|
|
22
|
+
self.uuid = ""
|
|
23
|
+
self.description = ""
|
|
24
|
+
self.list0_name = ""
|
|
25
|
+
self.list1_name = ""
|
|
26
|
+
self.list2_name = ""
|
|
27
|
+
self.stone = []
|
|
28
|
+
|
|
29
|
+
def __str__(self):
|
|
30
|
+
return self.name
|
|
31
|
+
|
|
32
|
+
def loads(self, json_str: str):
|
|
33
|
+
"""
|
|
34
|
+
Load json from a str
|
|
35
|
+
:param str json_str: JSON string
|
|
36
|
+
"""
|
|
37
|
+
parsed_json = json.loads(json_str)
|
|
38
|
+
self._populate(parsed_json)
|
|
39
|
+
|
|
40
|
+
def load_json_from_file(self, json_file: str):
|
|
41
|
+
"""
|
|
42
|
+
Load json from a file
|
|
43
|
+
:param str json_file: string name of a file
|
|
44
|
+
"""
|
|
45
|
+
with open(json_file) as jf:
|
|
46
|
+
parsed_json = json.load(jf)
|
|
47
|
+
self._populate(parsed_json)
|
|
48
|
+
|
|
49
|
+
def load_fedramp_version_5_mapping(self):
|
|
50
|
+
"""
|
|
51
|
+
Load FedRAMP version 5 mapping
|
|
52
|
+
"""
|
|
53
|
+
from importlib.resources import path as resource_path
|
|
54
|
+
|
|
55
|
+
with resource_path("regscale.integrations.public.fedramp.mappings", "fedramp_r5_params.json") as json_file_path:
|
|
56
|
+
self.load_json_from_file(json_file_path.__str__())
|
|
57
|
+
|
|
58
|
+
def _populate(self, rs_dict: Dict):
|
|
59
|
+
"""
|
|
60
|
+
Populate attributes from dictionary
|
|
61
|
+
:param Dict rs_dict: Dictionary of Rosetta Stone data
|
|
62
|
+
"""
|
|
63
|
+
self.rs_data = rs_dict
|
|
64
|
+
self.rosetta = self.rs_data.get("rosetta", None)
|
|
65
|
+
self.name = self.rosetta.get("name", None)
|
|
66
|
+
self.uuid = self.rosetta.get("uuid", None)
|
|
67
|
+
self.description = self.rosetta.get("description", None)
|
|
68
|
+
self.list0_name = self.rosetta.get("list0_name", None)
|
|
69
|
+
self.list1_name = self.rosetta.get("list1_name", None)
|
|
70
|
+
self.list2_name = self.rosetta.get("list2_name", None)
|
|
71
|
+
self.stone = self.rosetta.get("stone", None)
|
|
72
|
+
# create quick_maps
|
|
73
|
+
self.quick_map = self.lookup_l1_by_l0()
|
|
74
|
+
self.reverse_quick_map = self.lookup_l0_by_l1()
|
|
75
|
+
self.list_guessed = self.guessed()
|
|
76
|
+
|
|
77
|
+
def lookup_l1_by_l0(self) -> Dict:
|
|
78
|
+
"""
|
|
79
|
+
Map first items of list0, list1 as dictionary
|
|
80
|
+
:return: Dict
|
|
81
|
+
:rtype: Dict
|
|
82
|
+
"""
|
|
83
|
+
self.map = {}
|
|
84
|
+
for item in self.stone:
|
|
85
|
+
self.map[item["list0"][0]] = item["list1"][0]
|
|
86
|
+
return self.map
|
|
87
|
+
|
|
88
|
+
def lookup_l0_by_l1(self) -> Dict:
|
|
89
|
+
"""
|
|
90
|
+
Map first items of list0, list1 as dictionary
|
|
91
|
+
:return: Dict
|
|
92
|
+
:rtype: Dict
|
|
93
|
+
"""
|
|
94
|
+
self.map = {}
|
|
95
|
+
for item in self.stone:
|
|
96
|
+
self.map[item["list1"][0]] = item["list0"][0]
|
|
97
|
+
return self.map
|
|
98
|
+
|
|
99
|
+
def guessed(self) -> Dict:
|
|
100
|
+
"""
|
|
101
|
+
Return list of items with guesses
|
|
102
|
+
:return: Dict
|
|
103
|
+
:rtype: Dict
|
|
104
|
+
"""
|
|
105
|
+
self.map = {}
|
|
106
|
+
for line in self.stone:
|
|
107
|
+
for c_score in line.get("confidence", None):
|
|
108
|
+
if 0 < c_score < 1:
|
|
109
|
+
self.map[line.get("list0")[0]] = line.get("list1")[0]
|
|
110
|
+
return self.map
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
from regscale.integrations.public.fedramp.reporting import (
|
|
2
|
+
write_events,
|
|
3
|
+
log_error,
|
|
4
|
+
log_event,
|
|
5
|
+
)
|
|
6
|
+
|
|
7
|
+
import logging
|
|
8
|
+
from regscale.core.app.logz import create_logger
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class CaptureEventsHandler:
|
|
12
|
+
def __init__(self, events, errors, infos):
|
|
13
|
+
self.handler = logging.Handler()
|
|
14
|
+
self.events = events
|
|
15
|
+
self.errors = errors
|
|
16
|
+
self.infos = infos
|
|
17
|
+
|
|
18
|
+
def emit(self, record):
|
|
19
|
+
self.handler.emit(record)
|
|
20
|
+
try:
|
|
21
|
+
log_entry = self.handler.format(record)
|
|
22
|
+
if record.levelname == "INFO":
|
|
23
|
+
self.events.append(log_entry)
|
|
24
|
+
elif record.levelname == "ERROR":
|
|
25
|
+
self.errors.append(log_entry)
|
|
26
|
+
except Exception:
|
|
27
|
+
self.handler.handleError(record)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class SSPLogger:
|
|
31
|
+
def __init__(self):
|
|
32
|
+
self.events = []
|
|
33
|
+
self.errors = []
|
|
34
|
+
self.infos = []
|
|
35
|
+
self.capture_handler = CaptureEventsHandler(self.events, self.errors, self.infos)
|
|
36
|
+
self.logger = create_logger(custom_handler=self.capture_handler)
|
|
37
|
+
|
|
38
|
+
def create_logger(self):
|
|
39
|
+
return self.logger
|
|
40
|
+
|
|
41
|
+
def info(self, event_msg: str, record_type: str = "", model_layer: str = ""):
|
|
42
|
+
self.logger.info(event_msg)
|
|
43
|
+
info = {
|
|
44
|
+
"event_msg": event_msg,
|
|
45
|
+
"record_type": record_type,
|
|
46
|
+
"model_layer": model_layer,
|
|
47
|
+
}
|
|
48
|
+
self.infos.append(log_event(**info, level="Info"))
|
|
49
|
+
|
|
50
|
+
def debug(self, msg, *args, **kwargs):
|
|
51
|
+
self.logger.debug(msg, *args, **kwargs)
|
|
52
|
+
|
|
53
|
+
def error(
|
|
54
|
+
self,
|
|
55
|
+
event_msg: str,
|
|
56
|
+
record_type: str = "",
|
|
57
|
+
model_layer: str = "",
|
|
58
|
+
missing_element: str = "",
|
|
59
|
+
):
|
|
60
|
+
self.logger.error(event_msg)
|
|
61
|
+
error = {
|
|
62
|
+
"event_msg": event_msg,
|
|
63
|
+
"missing_element": missing_element,
|
|
64
|
+
"record_type": record_type,
|
|
65
|
+
"model_layer": model_layer,
|
|
66
|
+
}
|
|
67
|
+
self.errors.append(log_error(**error, level="Error"))
|
|
68
|
+
|
|
69
|
+
def warning(self, event_msg: str, record_type: str = "", model_layer: str = ""):
|
|
70
|
+
self.logger.warning(event_msg)
|
|
71
|
+
warning = {
|
|
72
|
+
"event_msg": event_msg,
|
|
73
|
+
"record_type": record_type,
|
|
74
|
+
"model_layer": model_layer,
|
|
75
|
+
}
|
|
76
|
+
self.infos.append(log_event(**warning, level="Warning"))
|
|
77
|
+
|
|
78
|
+
def get_events(self):
|
|
79
|
+
return self.events
|
|
80
|
+
|
|
81
|
+
def get_errors(self):
|
|
82
|
+
return self.errors
|
|
83
|
+
|
|
84
|
+
def write_events(self):
|
|
85
|
+
# Write the events.
|
|
86
|
+
final_list = [*self.events, *self.errors, *self.infos]
|
|
87
|
+
write_events(final_list)
|