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,34 @@
|
|
|
1
|
+
"""Mappings for System Roles."""
|
|
2
|
+
|
|
3
|
+
from lxml import etree
|
|
4
|
+
|
|
5
|
+
from regscale.core.app.application import Application
|
|
6
|
+
from regscale.integrations.public.fedramp.mappings.values import (
|
|
7
|
+
UUID,
|
|
8
|
+
FunctionPerformed,
|
|
9
|
+
Title,
|
|
10
|
+
)
|
|
11
|
+
from regscale.core.app.utils.app_utils import get_current_datetime
|
|
12
|
+
from regscale.models.regscale_models.system_role import SystemRole
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def create_system_role(element: etree._Element) -> SystemRole:
|
|
16
|
+
"""
|
|
17
|
+
Create a SystemRoles object from an XML Element
|
|
18
|
+
|
|
19
|
+
:param etree._Element element: The XML Element to parse
|
|
20
|
+
:return: A SystemRole object
|
|
21
|
+
:rtype: SystemRole
|
|
22
|
+
"""
|
|
23
|
+
data = {}
|
|
24
|
+
for field in [UUID, Title, FunctionPerformed]:
|
|
25
|
+
for elem in element:
|
|
26
|
+
if results := field.parse_from_element(elem):
|
|
27
|
+
data[field.value] = results[1]
|
|
28
|
+
app = Application()
|
|
29
|
+
data["id"] = 0
|
|
30
|
+
data["createdById"] = app.config.get("userId")
|
|
31
|
+
data["lastUpdatedById"] = app.config.get("userId")
|
|
32
|
+
data["dateCreated"] = get_current_datetime(dt_format="%Y-%m-%dT%H:%M:%S.%fZ")
|
|
33
|
+
data["dateLastUpdated"] = get_current_datetime(dt_format="%Y-%m-%dT%H:%M:%S.%fZ")
|
|
34
|
+
return SystemRole(**data)
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# flake8: noqa
|
|
2
|
+
"""LeveragedAuthMapping classes for FedRAMP."""
|
|
3
|
+
|
|
4
|
+
from typing import List, Optional
|
|
5
|
+
|
|
6
|
+
from lxml import etree
|
|
7
|
+
|
|
8
|
+
from regscale.core.app.api import Api
|
|
9
|
+
from regscale.core.app.application import Application
|
|
10
|
+
from regscale.core.app.logz import create_logger
|
|
11
|
+
from regscale.integrations.public.fedramp.fedramp_traversal import FedrampTraversal
|
|
12
|
+
from regscale.core.app.utils.XMLIR import XMLIR2, XMLIRTraversal
|
|
13
|
+
from regscale.models.regscale_models.system_role import SystemRole
|
|
14
|
+
|
|
15
|
+
logger = create_logger()
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class UserMappingIRAuthorizedPrivilegesIR(XMLIR2):
|
|
19
|
+
title: Optional[str] = None
|
|
20
|
+
|
|
21
|
+
def get_title(self, trv: XMLIRTraversal) -> Optional[str]:
|
|
22
|
+
"""The title of the authorized privilege."""
|
|
23
|
+
vlist = trv.el_xpath(".//oscal:title")
|
|
24
|
+
return vlist[0].text if vlist else None
|
|
25
|
+
|
|
26
|
+
description: Optional[str] = None
|
|
27
|
+
|
|
28
|
+
def get_description(self, trv: XMLIRTraversal) -> Optional[str]:
|
|
29
|
+
"""The description of the authorized privilege."""
|
|
30
|
+
vlist = trv.el_xpath(".//oscal:description")
|
|
31
|
+
return vlist[0].text if vlist else None
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class UserMappingIR(XMLIR2):
|
|
35
|
+
title: Optional[str] = None
|
|
36
|
+
|
|
37
|
+
def get_title(self, trv: XMLIRTraversal) -> Optional[str]:
|
|
38
|
+
"""The user's title"""
|
|
39
|
+
vlist = trv.el_xpath(".//oscal:title")
|
|
40
|
+
return vlist[0].text if vlist else None
|
|
41
|
+
|
|
42
|
+
type: Optional[str] = None
|
|
43
|
+
|
|
44
|
+
def get_type(self, trv: XMLIRTraversal) -> Optional[str]:
|
|
45
|
+
"""The type of the user."""
|
|
46
|
+
vlist = trv.el_xpath('.//oscal:prop[@name="type"]')
|
|
47
|
+
return vlist[0].get("value") if vlist else None
|
|
48
|
+
|
|
49
|
+
sensitivity: Optional[str] = None
|
|
50
|
+
|
|
51
|
+
def get_sensitivity(self, trv: XMLIRTraversal) -> Optional[str]:
|
|
52
|
+
"""The sensitivity of the user."""
|
|
53
|
+
vlist = trv.el_xpath('.//oscal:prop[@name="sensitivity"]')
|
|
54
|
+
|
|
55
|
+
return vlist[0].get("value") if vlist else None
|
|
56
|
+
|
|
57
|
+
privilege_level: Optional[str] = None
|
|
58
|
+
|
|
59
|
+
def get_privilege_level(self, trv: XMLIRTraversal) -> Optional[str]:
|
|
60
|
+
"""The privilege level of the user."""
|
|
61
|
+
vlist = trv.el_xpath('.//oscal:prop[@name="privilege-level"]')
|
|
62
|
+
|
|
63
|
+
return vlist[0].get("value") if vlist else None
|
|
64
|
+
|
|
65
|
+
role_id: Optional[str] = None
|
|
66
|
+
|
|
67
|
+
def get_role_id(self, trv: XMLIRTraversal) -> Optional[str]:
|
|
68
|
+
"""The role id of the user."""
|
|
69
|
+
vlist = trv.el_xpath(".//oscal:role-id")
|
|
70
|
+
|
|
71
|
+
return vlist[0].text if vlist else None
|
|
72
|
+
|
|
73
|
+
authorized_privileges: List[UserMappingIRAuthorizedPrivilegesIR] = []
|
|
74
|
+
|
|
75
|
+
def get_authorized_privileges(self, trv: XMLIRTraversal) -> List[UserMappingIRAuthorizedPrivilegesIR]:
|
|
76
|
+
"""The authorized privileges of the user."""
|
|
77
|
+
vlist = trv.el_xpath(".//oscal:authorized-privilege")
|
|
78
|
+
|
|
79
|
+
return [
|
|
80
|
+
UserMappingIRAuthorizedPrivilegesIR(
|
|
81
|
+
XMLIRTraversal(xpathToThis="....", el=el, root=trv.root, namespaces=trv.namespaces)
|
|
82
|
+
)
|
|
83
|
+
for el in vlist
|
|
84
|
+
]
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def handle_user(trv: FedrampTraversal):
|
|
88
|
+
"""
|
|
89
|
+
Extract user nodes from the SSP and send them to the RegScale API.
|
|
90
|
+
"""
|
|
91
|
+
try:
|
|
92
|
+
api = trv.api
|
|
93
|
+
root = trv.root
|
|
94
|
+
|
|
95
|
+
namespaces = {
|
|
96
|
+
"oscal": "http://csrc.nist.gov/ns/oscal/1.0",
|
|
97
|
+
"fedramp": "https://fedramp.gov/ns/oscal",
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
# Extract user nodes
|
|
101
|
+
users = root.xpath(".//oscal:system-implementation/oscal:user", namespaces=namespaces)
|
|
102
|
+
|
|
103
|
+
if len(users) == 0:
|
|
104
|
+
trv.log_info(
|
|
105
|
+
{
|
|
106
|
+
"model_layer": "system-implementation",
|
|
107
|
+
"record_type": "user",
|
|
108
|
+
"event_msg": "No users / System Roles detected.",
|
|
109
|
+
}
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
for elem in users:
|
|
113
|
+
res = UserMappingIR(XMLIRTraversal(xpathToThis="....", el=elem, root=root, namespaces=namespaces))
|
|
114
|
+
|
|
115
|
+
logger.debug("parsed object", res)
|
|
116
|
+
|
|
117
|
+
sending = {
|
|
118
|
+
"id": 0,
|
|
119
|
+
# Title
|
|
120
|
+
"roleName": res.title,
|
|
121
|
+
"fedrampRoleId": res.role_id,
|
|
122
|
+
"roleType": res.type,
|
|
123
|
+
"assignedUserId": None,
|
|
124
|
+
"accessLevel": res.privilege_level,
|
|
125
|
+
"sensitivityLevel": res.sensitivity,
|
|
126
|
+
"privilegeDescription": res.privilege_level,
|
|
127
|
+
"functions": ", ".join([str(dict(r)) for r in res.authorized_privileges]),
|
|
128
|
+
"securityPlanId": trv.ssp_id,
|
|
129
|
+
"createdById": api.config["userId"],
|
|
130
|
+
"isPublic": True,
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
system_roles = SystemRole(**sending)
|
|
134
|
+
if system_roles.insert_systemrole(api.app):
|
|
135
|
+
trv.log_info(
|
|
136
|
+
{
|
|
137
|
+
"model_layer": "system-implementation",
|
|
138
|
+
"record_type": "user",
|
|
139
|
+
"event_msg": f"Created user '{res.title}' with role id '{res.role_id}'",
|
|
140
|
+
}
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
logger.info("System role was created successfully in RegScale.")
|
|
144
|
+
else:
|
|
145
|
+
trv.log_error(
|
|
146
|
+
{
|
|
147
|
+
"model_layer": "system-implementation",
|
|
148
|
+
"record_type": "user",
|
|
149
|
+
"event_msg": "Failed to create user",
|
|
150
|
+
}
|
|
151
|
+
)
|
|
152
|
+
except Exception as e:
|
|
153
|
+
trv.log_error(
|
|
154
|
+
{
|
|
155
|
+
"model_layer": "system-implementation",
|
|
156
|
+
"record_type": "user",
|
|
157
|
+
"event_msg": f"Unknown issue: Failed to create user (ERROR: {str(e)})",
|
|
158
|
+
}
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
if __name__ == "__main__":
|
|
163
|
+
# If data is incomplete This fails w/ 500 error ( which means the json string being received by the server is either malformed or missing something
|
|
164
|
+
__app = Application()
|
|
165
|
+
__api = Api()
|
|
166
|
+
|
|
167
|
+
def basic_test():
|
|
168
|
+
tree = etree.parse("fr_ssp_gold_v1.1.xml")
|
|
169
|
+
root = tree.getroot()
|
|
170
|
+
ARG_SSP_ID = 360
|
|
171
|
+
|
|
172
|
+
handle_user(FedrampTraversal(api=__api, root=root, ssp_id=ARG_SSP_ID))
|
|
173
|
+
|
|
174
|
+
# Run tests
|
|
175
|
+
basic_test()
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"""Provide base models for values in the FedRAMP SSP."""
|
|
2
|
+
|
|
3
|
+
from typing import Callable, List, Optional, Tuple, Type, Union
|
|
4
|
+
|
|
5
|
+
from lxml import etree
|
|
6
|
+
from pydantic import BaseModel
|
|
7
|
+
|
|
8
|
+
from regscale.core.app.logz import create_logger
|
|
9
|
+
from regscale.integrations.public.fedramp.xml_utils import extract_markup_content
|
|
10
|
+
|
|
11
|
+
logger = create_logger()
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class SSPField(BaseModel):
|
|
15
|
+
value: str
|
|
16
|
+
xpath: str
|
|
17
|
+
type_: Type = str
|
|
18
|
+
namespace: Optional[dict] = None
|
|
19
|
+
callable: Optional[Callable] = None
|
|
20
|
+
|
|
21
|
+
def parse_from_element(
|
|
22
|
+
self,
|
|
23
|
+
element: etree._Element,
|
|
24
|
+
) -> Union[Tuple[str, str], List[Tuple[str, str]]]:
|
|
25
|
+
"""Parse an SSPField from an XML Element
|
|
26
|
+
|
|
27
|
+
:param etree._Element element: The XML Element to parse
|
|
28
|
+
:return: A tuple of the field name and value
|
|
29
|
+
:rtype: Union[Tuple[str, str], List[Tuple[str, str]]]
|
|
30
|
+
"""
|
|
31
|
+
result_list = element.xpath(self.xpath, namespaces=self.namespace)
|
|
32
|
+
output = []
|
|
33
|
+
|
|
34
|
+
def _helper(result):
|
|
35
|
+
if self.callable and callable(self.callable):
|
|
36
|
+
return self.value, self.type_(self.callable(result))
|
|
37
|
+
return self.value, self.type_(result)
|
|
38
|
+
|
|
39
|
+
if len(result_list) == 0:
|
|
40
|
+
logger.warning(f"No results found for {self.value} in {element.tag}")
|
|
41
|
+
if result_list and len(result_list) > 0:
|
|
42
|
+
output = [_helper(result) for result in result_list]
|
|
43
|
+
try:
|
|
44
|
+
return output[0][1] if len(result_list) == 1 and output and len(output[0]) > 1 else output
|
|
45
|
+
except IndexError:
|
|
46
|
+
return output
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
UUID = SSPField(value="uuid", xpath="@uuid")
|
|
50
|
+
Link = SSPField(value="link", xpath="link/@href")
|
|
51
|
+
Title = SSPField(value="title", xpath="title/text()")
|
|
52
|
+
PartyUUID = SSPField(
|
|
53
|
+
value="party_uuid",
|
|
54
|
+
xpath="party-uuid/text()",
|
|
55
|
+
namespace={"oscal": "http://csrc.nist.gov/ns/oscal/1.0"},
|
|
56
|
+
)
|
|
57
|
+
DateAuthorized = SSPField(
|
|
58
|
+
value="date_authorized",
|
|
59
|
+
xpath="date-authorized/text()",
|
|
60
|
+
namespace={"oscal": "http://csrc.nist.gov/ns/oscal/1.0"},
|
|
61
|
+
)
|
|
62
|
+
Remarks = SSPField(value="remarks", xpath="remarks", callable=extract_markup_content)
|
|
63
|
+
Description = SSPField(value="description", xpath="description", callable=extract_markup_content)
|
|
64
|
+
RoleId = SSPField(value="role-id", xpath="role-id/text()")
|
|
65
|
+
PropName = SSPField(value="prop-name", xpath="prop/@name")
|
|
66
|
+
PropValue = SSPField(value="prop-value", xpath="prop/@value")
|
|
67
|
+
UserUUID = SSPField(value="user-uuid", xpath="user/@uuid")
|
|
68
|
+
FunctionPerformed = SSPField(value="function-performed", xpath="function-performed/text()")
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
if __name__ == "__main__":
|
|
72
|
+
from regscale.models.regscale_models import (
|
|
73
|
+
LeveragedAuthorization,
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
xml_string = """<leveraged-authorization uuid="5a9c98ab-8e5e-433d-a7bd-515c07cd1497">
|
|
77
|
+
<title>AWS GovCloud</title>
|
|
78
|
+
<prop ns="https://fedramp.gov/ns/oscal" name="leveraged-system-identifier" value="F1603047866"/>
|
|
79
|
+
<link href="//path/to/leveraged_system_ssp.xml"/>
|
|
80
|
+
<link href="//path/to/leveraged_system_legacy_crm.xslt"/>
|
|
81
|
+
<link href="//path/to/leveraged_system_responsibility_and_inheritance.xml"/>
|
|
82
|
+
<party-uuid>f0bc13a4-3303-47dd-80d3-380e159c8362</party-uuid>
|
|
83
|
+
<date-authorized>2015-01-01</date-authorized>
|
|
84
|
+
<remarks>
|
|
85
|
+
<h1>Remarks</h1>
|
|
86
|
+
<p>The leveraged-authorizaton assembly is supposed to have a required uuid flag instead
|
|
87
|
+
of an optional id flag. This will be fixed in the syntax shortly.</p>
|
|
88
|
+
<p>Use one leveraged-authorization assembly for each underlying system. (In the legacy
|
|
89
|
+
world, these may be general support systems.</p>
|
|
90
|
+
<p>The link fields are optional, but preferred where known. Often, a leveraging system's
|
|
91
|
+
SSP author will not have access to the leveraged system's SSP, but should have access
|
|
92
|
+
to the leveraged system's CRM.</p>
|
|
93
|
+
</remarks>
|
|
94
|
+
<description>
|
|
95
|
+
<p>The description of the object contains the remarks.</p>
|
|
96
|
+
<h2>Services Used</h2>
|
|
97
|
+
<p>Services used by the leveraged system:</p>
|
|
98
|
+
<ul>
|
|
99
|
+
<li>EC2</li>
|
|
100
|
+
</ul>
|
|
101
|
+
</description>
|
|
102
|
+
</leveraged-authorization>
|
|
103
|
+
"""
|
|
104
|
+
root = etree.fromstring(xml_string)
|
|
105
|
+
uuid = UUID.parse_from_element(root)
|
|
106
|
+
print(uuid)
|
|
107
|
+
date_authorized = DateAuthorized.parse_from_element(root)
|
|
108
|
+
print(date_authorized)
|
|
109
|
+
party_uuid = PartyUUID.parse_from_element(root)
|
|
110
|
+
print(party_uuid)
|
|
111
|
+
links = Link.parse_from_element(root)
|
|
112
|
+
print(links)
|
|
113
|
+
title = Title.parse_from_element(root)
|
|
114
|
+
print(title)
|
|
115
|
+
remarks = Remarks.parse_from_element(root)
|
|
116
|
+
print(remarks)
|
|
117
|
+
description = Description.parse_from_element(root)
|
|
118
|
+
print(description)
|
|
119
|
+
from regscale.core.app.application import Application
|
|
120
|
+
from regscale.core.app.utils.app_utils import get_current_datetime
|
|
121
|
+
|
|
122
|
+
app = Application()
|
|
123
|
+
leveraged_authorizations = LeveragedAuthorization(
|
|
124
|
+
uuid=uuid[1],
|
|
125
|
+
title=title[1],
|
|
126
|
+
fedrampId=None,
|
|
127
|
+
ownerId=party_uuid[1],
|
|
128
|
+
securityPlanId=1,
|
|
129
|
+
dateAuthorized=date_authorized[1],
|
|
130
|
+
description=remarks[1],
|
|
131
|
+
servicesUsed=None,
|
|
132
|
+
securityPlanLink=links[0][1],
|
|
133
|
+
crmLink=links[1][1],
|
|
134
|
+
responsibilityAndInheritanceLink=links[2][1],
|
|
135
|
+
createdById=app.config["userId"],
|
|
136
|
+
dateCreated=get_current_datetime(dt_format="%Y-%m-%dT%H:%M:%S.%fZ"),
|
|
137
|
+
lastUpdatedById=app.config["userId"],
|
|
138
|
+
dateLastUpdated=get_current_datetime(dt_format="%Y-%m-%dT%H:%M:%S.%fZ"),
|
|
139
|
+
tenantsId=None,
|
|
140
|
+
)
|
|
141
|
+
print(leveraged_authorizations)
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module contains the MDDocParser class, which is used to parse an SSP Appendix A file
|
|
3
|
+
and return a dictionary representing the data in the markdown document.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import re
|
|
7
|
+
import logging
|
|
8
|
+
import zipfile # Assuming you need this for other file handling
|
|
9
|
+
import pypandoc
|
|
10
|
+
from collections import defaultdict
|
|
11
|
+
from typing import Dict, TextIO, Optional, Tuple
|
|
12
|
+
from regscale.models import ProfileMapping
|
|
13
|
+
|
|
14
|
+
# Configure logger
|
|
15
|
+
logging.basicConfig(level=logging.DEBUG)
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
# Tokens used in HTML parsing
|
|
19
|
+
BEGINPARTTOKEN = "<tr>"
|
|
20
|
+
ENDPARTTOKEN = "</tr>"
|
|
21
|
+
BODYSTARTTOKEN = "<tbody>"
|
|
22
|
+
BODYENDTOKEN = "</tbody>"
|
|
23
|
+
CONTROLSUMMARYTOKEN = "What is the solution"
|
|
24
|
+
|
|
25
|
+
FULL_SUMMARY_TOKEN = "What is the solution and how is it implemented?"
|
|
26
|
+
html_tag_pattern = re.compile(r"</?[^>]+>")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def clean_part(part: str) -> str:
|
|
30
|
+
"""
|
|
31
|
+
Cleans an HTML part string by removing specific HTML tags.
|
|
32
|
+
|
|
33
|
+
:param part: The HTML part string
|
|
34
|
+
:return: A cleaned HTML part string with specific tags removed
|
|
35
|
+
"""
|
|
36
|
+
# Pattern to match specified HTML tags, using non-capturing groups for better performance
|
|
37
|
+
pattern = re.compile(r"</?(td|tr|th|tbody|thead)(?: [^>]*)?>", re.IGNORECASE)
|
|
38
|
+
return pattern.sub("", part).strip()
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class MDDocParser:
|
|
42
|
+
"""
|
|
43
|
+
Parses an SSP .md file and extracts control parts into a dictionary.
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
def __init__(self, md_path: str, profile_id: int):
|
|
47
|
+
"""
|
|
48
|
+
Initializes the MDDocParser with the path to the markdown file.
|
|
49
|
+
|
|
50
|
+
:param str md_path: Path to the markdown file
|
|
51
|
+
:param int profile_id: The profile ID to associate with the control parts
|
|
52
|
+
"""
|
|
53
|
+
# List of controls to parse
|
|
54
|
+
self.md_path = md_path
|
|
55
|
+
try:
|
|
56
|
+
self.controls = [profile_map.controlId for profile_map in ProfileMapping.get_by_profile(profile_id)]
|
|
57
|
+
# Convert .md file to markdown_strict format and save output
|
|
58
|
+
self.md_text = pypandoc.convert_file(md_path, "markdown_strict", outputfile="app_a.md")
|
|
59
|
+
self.md_doc = "app_a.md"
|
|
60
|
+
except Exception as e:
|
|
61
|
+
logger.error(f"Error converting file: {e}")
|
|
62
|
+
raise
|
|
63
|
+
|
|
64
|
+
def get_parts(self) -> Dict[str, str]:
|
|
65
|
+
"""
|
|
66
|
+
Parses the .md file and extracts control parts.
|
|
67
|
+
|
|
68
|
+
:return: A dictionary of control parts, keyed by control ID
|
|
69
|
+
"""
|
|
70
|
+
control_parts_dict = defaultdict(str)
|
|
71
|
+
try:
|
|
72
|
+
with open(self.md_doc, "r") as file:
|
|
73
|
+
for line in file:
|
|
74
|
+
if CONTROLSUMMARYTOKEN in line:
|
|
75
|
+
control_id = self._handle_control_summary_line(line)
|
|
76
|
+
if not control_id:
|
|
77
|
+
continue
|
|
78
|
+
# Skip lines to find the table content
|
|
79
|
+
next(file) # Skip HTML table definition line
|
|
80
|
+
# Loop through file to capture parts between tbody tags
|
|
81
|
+
self.find_parts(file, control_parts_dict, control_id)
|
|
82
|
+
except FileNotFoundError as e:
|
|
83
|
+
logger.error(f"File not found: {e}")
|
|
84
|
+
except Exception as e:
|
|
85
|
+
logger.error(f"Error parsing file: {e}")
|
|
86
|
+
return control_parts_dict
|
|
87
|
+
|
|
88
|
+
@staticmethod
|
|
89
|
+
def clean_html_and_newlines(input_text: str) -> str:
|
|
90
|
+
"""
|
|
91
|
+
Cleans HTML tags and newlines from a string.
|
|
92
|
+
:param str input_text: The text to clean
|
|
93
|
+
:return: The cleaned text
|
|
94
|
+
:rtype: str
|
|
95
|
+
"""
|
|
96
|
+
# Remove HTML tags
|
|
97
|
+
cleaner_text = html_tag_pattern.sub("", input_text)
|
|
98
|
+
# Remove newlines
|
|
99
|
+
return cleaner_text.replace("\n", "")
|
|
100
|
+
|
|
101
|
+
def _handle_control_summary_line(self, line: str) -> Optional[str]:
|
|
102
|
+
"""
|
|
103
|
+
Handles a line of text from the markdown file.
|
|
104
|
+
|
|
105
|
+
:param str line: The line of text
|
|
106
|
+
:return: The control ID
|
|
107
|
+
:rtype: Optional[str]
|
|
108
|
+
"""
|
|
109
|
+
# Extract control ID and clean it
|
|
110
|
+
html_free_line = self.clean_html_and_newlines(line)
|
|
111
|
+
clean_line = html_free_line.replace(FULL_SUMMARY_TOKEN, "")
|
|
112
|
+
if not clean_line:
|
|
113
|
+
return None
|
|
114
|
+
clean_control_id_from_line = clean_line.strip()
|
|
115
|
+
return clean_control_id_from_line
|
|
116
|
+
|
|
117
|
+
def find_parts(self, file: TextIO, control_parts_dict: Dict, cntrlid: str):
|
|
118
|
+
"""
|
|
119
|
+
Parses and collects parts from a markdown file into a dictionary by control ID.
|
|
120
|
+
|
|
121
|
+
:param file: The markdown file
|
|
122
|
+
:param control_parts_dict: Dictionary to store parts by control ID
|
|
123
|
+
:param cntrlid: The control ID
|
|
124
|
+
"""
|
|
125
|
+
allparts = ""
|
|
126
|
+
for line in file:
|
|
127
|
+
if BODYSTARTTOKEN in line:
|
|
128
|
+
continue
|
|
129
|
+
elif BODYENDTOKEN in line:
|
|
130
|
+
break
|
|
131
|
+
allparts += self.part_cleaner(file, line)
|
|
132
|
+
|
|
133
|
+
control_parts_dict[cntrlid] = allparts
|
|
134
|
+
logger.debug(f"Control ID: {cntrlid}, Parts: {allparts}")
|
|
135
|
+
|
|
136
|
+
@staticmethod
|
|
137
|
+
def part_cleaner(file: TextIO, line: str) -> str:
|
|
138
|
+
"""
|
|
139
|
+
Cleans and accumulates parts of text from the markdown file.
|
|
140
|
+
|
|
141
|
+
:param file: The markdown file
|
|
142
|
+
:param line: The current line of text
|
|
143
|
+
:return: The cleaned part as a string
|
|
144
|
+
"""
|
|
145
|
+
part = ""
|
|
146
|
+
for next_line in file:
|
|
147
|
+
part += " " + clean_part(next_line)
|
|
148
|
+
if ENDPARTTOKEN in next_line:
|
|
149
|
+
break
|
|
150
|
+
return part
|