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
regscale/dev/docs.py
ADDED
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
"""Tools and functions for the generation of documentation."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import subprocess
|
|
5
|
+
from typing import Optional, TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
import requests
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from regscale.core.app.api import Api
|
|
11
|
+
|
|
12
|
+
from sphinx.application import Sphinx
|
|
13
|
+
from sphinx.cmd.quickstart import generate
|
|
14
|
+
|
|
15
|
+
from regscale import __version__
|
|
16
|
+
|
|
17
|
+
INDEX_RST = "index.rst"
|
|
18
|
+
APP_JSON = "application/json"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def init_sphinx(
|
|
22
|
+
docs_path: str = "docs",
|
|
23
|
+
project_name: str = "RegScale-CLI",
|
|
24
|
+
project_version: str = __version__,
|
|
25
|
+
project_author: str = "Travis Howerton",
|
|
26
|
+
) -> None:
|
|
27
|
+
"""Initialize Sphinx for generating documentation
|
|
28
|
+
|
|
29
|
+
:param str docs_path: Path to the docs folder
|
|
30
|
+
:param str project_name: Name of the project
|
|
31
|
+
:param str project_version: Version of the project
|
|
32
|
+
:param str project_author: Author of the project
|
|
33
|
+
:rtype: None
|
|
34
|
+
"""
|
|
35
|
+
generate(
|
|
36
|
+
{
|
|
37
|
+
"path": docs_path,
|
|
38
|
+
"sep": False,
|
|
39
|
+
"dot": "_",
|
|
40
|
+
"project": project_name,
|
|
41
|
+
"name": project_name,
|
|
42
|
+
"author": project_author,
|
|
43
|
+
"version": project_version,
|
|
44
|
+
"release": project_version,
|
|
45
|
+
"suffix": ".rst",
|
|
46
|
+
"ext_autodoc": True,
|
|
47
|
+
"ext_doctest": False, # change to true later?
|
|
48
|
+
"ext_intersphinx": False, # change to true later?
|
|
49
|
+
"ext_todo": False, # change to true later?
|
|
50
|
+
"ext_coverage": False, # change to true later?
|
|
51
|
+
"ext_mathjax": False, # change to true later?
|
|
52
|
+
"ext_ifconfig": False, # change to true later?
|
|
53
|
+
"ext_viewcode": False, # change to true later?
|
|
54
|
+
"makefile": True,
|
|
55
|
+
"batchfile": False,
|
|
56
|
+
"make_mode": False,
|
|
57
|
+
"quiet": True,
|
|
58
|
+
"master": "index",
|
|
59
|
+
"root_doc": "index",
|
|
60
|
+
}
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def enable_extensions_in_conf(docs_path: str, hide_source: bool = False) -> None:
|
|
65
|
+
"""Enable extensions in the conf.py file
|
|
66
|
+
|
|
67
|
+
:param str docs_path: Path to the docs folder
|
|
68
|
+
:param bool hide_source: Hide the source code link in the generated documentation, defaults to False
|
|
69
|
+
:rtype: None
|
|
70
|
+
"""
|
|
71
|
+
conf_file_path = os.path.join(docs_path, "conf.py")
|
|
72
|
+
with open(conf_file_path, "r+") as f:
|
|
73
|
+
lines = f.readlines()
|
|
74
|
+
f.seek(0)
|
|
75
|
+
for line in lines:
|
|
76
|
+
if line.startswith("extensions = []"):
|
|
77
|
+
f.write("extensions = [\n")
|
|
78
|
+
f.write(
|
|
79
|
+
" 'sphinx.ext.autodoc',\n"
|
|
80
|
+
" 'sphinx.ext.napoleon',\n"
|
|
81
|
+
" 'sphinx.ext.autosectionlabel',\n"
|
|
82
|
+
" 'sphinx.ext.autodoc.typehints',\n"
|
|
83
|
+
" 'sphinx.ext.coverage',\n"
|
|
84
|
+
" 'sphinx_click',\n"
|
|
85
|
+
)
|
|
86
|
+
if not hide_source:
|
|
87
|
+
f.write(" 'sphinx.ext.viewcode',\n")
|
|
88
|
+
f.write("]\n")
|
|
89
|
+
elif line.startswith("html_theme"):
|
|
90
|
+
f.write("html_theme = 'classic'\ntodo_include_todos = True\n")
|
|
91
|
+
else:
|
|
92
|
+
f.write(line)
|
|
93
|
+
f.truncate()
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def create_master_index_rst(docs_path: str, src_path: str, title: str = "RegScale-CLI Documentation") -> None:
|
|
97
|
+
"""Create the master index.rst file
|
|
98
|
+
|
|
99
|
+
:param str docs_path: Path to the docs folder
|
|
100
|
+
:param str src_path: Path to the source folder
|
|
101
|
+
:param str title: Title of the documentation, defaults to "RegScale-CLI Documentation"
|
|
102
|
+
:rtype: None
|
|
103
|
+
"""
|
|
104
|
+
with open(os.path.join(docs_path, INDEX_RST), "w") as f:
|
|
105
|
+
f.write(f"{title}\n")
|
|
106
|
+
f.write("=" * len(title) + "\n\n")
|
|
107
|
+
f.write(".. toctree::\n")
|
|
108
|
+
f.write(" :maxdepth: 2\n\n")
|
|
109
|
+
f.write(" click_commands\n")
|
|
110
|
+
f.write(" regscale_regscale\n")
|
|
111
|
+
for item in os.listdir(src_path):
|
|
112
|
+
if os.path.isdir(os.path.join(src_path, item)) and item not in [
|
|
113
|
+
"__pycache__",
|
|
114
|
+
"__init__.py",
|
|
115
|
+
]:
|
|
116
|
+
f.write(f" {item}/index\n")
|
|
117
|
+
for item in os.listdir(docs_path):
|
|
118
|
+
if item.endswith(".rst") and item != INDEX_RST:
|
|
119
|
+
module_name = os.path.splitext(item)[0]
|
|
120
|
+
f.write(f" {module_name}\n")
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def create_click_commands_rst(docs_path: str) -> None:
|
|
124
|
+
"""Create .rst file for the click commands
|
|
125
|
+
|
|
126
|
+
:param str docs_path: Path to the docs folder
|
|
127
|
+
:rtype: None
|
|
128
|
+
"""
|
|
129
|
+
# this format cannot be altered because it will break the Sphinx build
|
|
130
|
+
content = """
|
|
131
|
+
RegScale-CLI Click Commands
|
|
132
|
+
===========================
|
|
133
|
+
|
|
134
|
+
.. click:: regscale.regscale:cli
|
|
135
|
+
:prog: regscale
|
|
136
|
+
:show-nested:
|
|
137
|
+
|
|
138
|
+
.. click:: regscale.dev.cli:cli
|
|
139
|
+
:prog: regscale-dev
|
|
140
|
+
:show-nested:
|
|
141
|
+
|
|
142
|
+
"""
|
|
143
|
+
with open(os.path.join(docs_path, "click_commands.rst"), "w") as f:
|
|
144
|
+
f.write(content)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def create_rst_for_module(module_name: str, rst_path: str) -> None:
|
|
148
|
+
"""Create .rst file for a Python module
|
|
149
|
+
|
|
150
|
+
:param str module_name: Name of the module
|
|
151
|
+
:param str rst_path: Path to the .rst file
|
|
152
|
+
:rtype: None
|
|
153
|
+
"""
|
|
154
|
+
# this format cannot be altered because it will break the Sphinx build
|
|
155
|
+
content = f"""
|
|
156
|
+
{module_name}
|
|
157
|
+
{'=' * len(module_name)}
|
|
158
|
+
|
|
159
|
+
.. automodule:: {module_name.replace(',', '_')}
|
|
160
|
+
:members:
|
|
161
|
+
:undoc-members:
|
|
162
|
+
:show-inheritance:
|
|
163
|
+
"""
|
|
164
|
+
with open(os.path.join(rst_path, f"{module_name.replace('.', '_')}.rst"), "w") as f:
|
|
165
|
+
f.write(content)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def traverse_and_create_rst(
|
|
169
|
+
root_path: str,
|
|
170
|
+
current_path: str,
|
|
171
|
+
rst_path: str,
|
|
172
|
+
prefix: str = "",
|
|
173
|
+
exclude_dirs: Optional[list[str]] = None,
|
|
174
|
+
) -> None:
|
|
175
|
+
"""
|
|
176
|
+
Traverse through the directory recursively and create .rst files for each Python module
|
|
177
|
+
|
|
178
|
+
:param str root_path: Root path of the project
|
|
179
|
+
:param str current_path: Current path of the directory
|
|
180
|
+
:param str rst_path: Path to the .rst file(s)
|
|
181
|
+
:param str prefix: Prefix to be added to the module name, defaults to ""
|
|
182
|
+
:param Optional[list[str]] exclude_dirs: List of directories to exclude, defaults to ["__pycache__"]
|
|
183
|
+
:rtype: None
|
|
184
|
+
"""
|
|
185
|
+
# Check if the directory has any subdirectories with Python files
|
|
186
|
+
if exclude_dirs is None:
|
|
187
|
+
exclude_dirs = ["__pycache__"]
|
|
188
|
+
has_subdir_with_py = any(
|
|
189
|
+
os.path.isdir(os.path.join(current_path, item))
|
|
190
|
+
and any(sub_item.endswith(".py") for sub_item in os.listdir(os.path.join(current_path, item)))
|
|
191
|
+
for item in os.listdir(current_path)
|
|
192
|
+
if item not in exclude_dirs
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
for item in os.listdir(current_path):
|
|
196
|
+
if item in exclude_dirs:
|
|
197
|
+
continue
|
|
198
|
+
item_path = os.path.join(current_path, item)
|
|
199
|
+
if os.path.isdir(item_path):
|
|
200
|
+
new_rst_path = os.path.join(rst_path, item)
|
|
201
|
+
os.makedirs(new_rst_path, exist_ok=True)
|
|
202
|
+
new_prefix = f"{prefix}.{item}" if prefix else item
|
|
203
|
+
|
|
204
|
+
# Recur further only if this directory has subdirectories with Python files
|
|
205
|
+
if has_subdir_with_py:
|
|
206
|
+
traverse_and_create_rst(root_path, item_path, new_rst_path, new_prefix, exclude_dirs)
|
|
207
|
+
|
|
208
|
+
# Generate index.rst for this sub-directory
|
|
209
|
+
with open(os.path.join(new_rst_path, "index.rst"), "w") as f:
|
|
210
|
+
f.write(f"{item}\n")
|
|
211
|
+
f.write("=" * len(item) + "\n\n")
|
|
212
|
+
f.write(".. toctree::\n :maxdepth: 1\n\n")
|
|
213
|
+
for sub_item in os.listdir(new_rst_path):
|
|
214
|
+
if sub_item.endswith(".rst"):
|
|
215
|
+
module_name = os.path.splitext(sub_item)[0]
|
|
216
|
+
f.write(f" {module_name}\n")
|
|
217
|
+
elif os.path.isdir(os.path.join(new_rst_path, sub_item)):
|
|
218
|
+
f.write(f" {sub_item}/index\n")
|
|
219
|
+
elif item.endswith(".py") and item != "__init__.py":
|
|
220
|
+
# Generate RST only if this directory does not have subdirectories with Python files
|
|
221
|
+
if not has_subdir_with_py:
|
|
222
|
+
module_name = f"{prefix}.{os.path.splitext(item)[0]}" if prefix else os.path.splitext(item)[0]
|
|
223
|
+
create_rst_for_module(module_name, rst_path)
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def build_docs(src_path: str, build_path: str, doctype: str) -> None:
|
|
227
|
+
"""Build the documentation
|
|
228
|
+
|
|
229
|
+
:param str src_path: Path to the source folder
|
|
230
|
+
:param str build_path: Path to the build folder
|
|
231
|
+
:param str doctype: Type of documentation
|
|
232
|
+
:rtype: None
|
|
233
|
+
"""
|
|
234
|
+
app = Sphinx(src_path, src_path, build_path, build_path, doctype)
|
|
235
|
+
app.build()
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def generate_docs(
|
|
239
|
+
project_path: str = os.getcwd(),
|
|
240
|
+
src_folder_name: str = "regscale",
|
|
241
|
+
docs_folder_name: str = "docs",
|
|
242
|
+
hide_source: bool = False,
|
|
243
|
+
) -> None:
|
|
244
|
+
"""Generate the documentation
|
|
245
|
+
|
|
246
|
+
:param str project_path: Path to the project, defaults to os.getcwd()
|
|
247
|
+
:param str src_folder_name: Name of the source folder, defaults to "regscale"
|
|
248
|
+
:param str docs_folder_name: Name of the docs folder, defaults to "docs"
|
|
249
|
+
:param bool hide_source: Hide the source code in the documentation, defaults to False
|
|
250
|
+
:rtype: None
|
|
251
|
+
"""
|
|
252
|
+
docs_path = os.path.join(project_path, docs_folder_name)
|
|
253
|
+
src_path = os.path.join(project_path, src_folder_name)
|
|
254
|
+
exclude_dirs = None
|
|
255
|
+
os.makedirs(docs_path, exist_ok=True)
|
|
256
|
+
init_sphinx(docs_path)
|
|
257
|
+
enable_extensions_in_conf(docs_path="docs", hide_source=hide_source)
|
|
258
|
+
create_click_commands_rst(docs_path)
|
|
259
|
+
create_master_index_rst(docs_path, src_path)
|
|
260
|
+
# traverse through the regscale directory recursively to create .rst files
|
|
261
|
+
if hide_source:
|
|
262
|
+
exclude_dirs = ["dev", "airflow", "ansible", "regscale-dev", "__pycache__", "docs"]
|
|
263
|
+
traverse_and_create_rst(
|
|
264
|
+
root_path=src_path, current_path=src_path, rst_path=docs_path, prefix=src_folder_name, exclude_dirs=exclude_dirs
|
|
265
|
+
)
|
|
266
|
+
# build the documentation
|
|
267
|
+
build_path = os.path.join(docs_path, "_build")
|
|
268
|
+
build_docs(docs_path, build_path, "html")
|
|
269
|
+
# build_docs(docs_path, build_path, 'text')
|
|
270
|
+
subprocess.run([f"sphinx-apidoc -o {docs_path} {src_path}"], shell=True)
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def update_readme_io(api: "Api", root: str, file: str) -> None:
|
|
274
|
+
"""
|
|
275
|
+
Update the readme.io documentation for the CLI
|
|
276
|
+
|
|
277
|
+
:param Api api: The API object to use to update the documentation
|
|
278
|
+
:param str root: The root directory of containing file with readme io slug and data
|
|
279
|
+
:param str file: File name to parse the readme io slug and data to update readme.io
|
|
280
|
+
:rtype: None
|
|
281
|
+
"""
|
|
282
|
+
readme_slug = None
|
|
283
|
+
payload_data = ""
|
|
284
|
+
with open(f"{root}/{file}", "r") as f:
|
|
285
|
+
for line in f:
|
|
286
|
+
if "# readme_slug:" in line:
|
|
287
|
+
readme_slug = line.split(":")[1].strip()
|
|
288
|
+
else:
|
|
289
|
+
for payload_line in f:
|
|
290
|
+
payload_data += payload_line
|
|
291
|
+
payload_data = payload_data.lstrip("\n")
|
|
292
|
+
|
|
293
|
+
# get the current data from the readme.io project
|
|
294
|
+
res = api.get(f"https://dash.readme.com/api/v1/docs/{readme_slug}")
|
|
295
|
+
if res.raise_for_status() and not res.ok:
|
|
296
|
+
api.logger.error(
|
|
297
|
+
f"Failed to retrieve readme.io slug: {readme_slug}\n{res.status_code}: {res.reason}\n{res.text}"
|
|
298
|
+
)
|
|
299
|
+
current_data = {"body": "", "hidden": False}
|
|
300
|
+
else:
|
|
301
|
+
current_data = res.json()
|
|
302
|
+
|
|
303
|
+
if current_data["body"] == payload_data:
|
|
304
|
+
api.logger.info(f"Readme.io slug: {readme_slug} is already up to date")
|
|
305
|
+
return
|
|
306
|
+
api.logger.info(f"Updating readme.io slug: {readme_slug} with {root}/{file} and payload {payload_data}")
|
|
307
|
+
res = api.put(
|
|
308
|
+
f"https://dash.readme.com/api/v1/docs/{readme_slug}", # This is the same url for every readme.io project
|
|
309
|
+
json={"hidden": current_data["hidden"], "body": payload_data},
|
|
310
|
+
headers={"Content-Type": APP_JSON},
|
|
311
|
+
)
|
|
312
|
+
if not res.raise_for_status() and res.ok:
|
|
313
|
+
api.logger.info(f"Successfully updated readme.io slug: {readme_slug}")
|
|
314
|
+
else:
|
|
315
|
+
api.logger.error(f"Failed to update readme.io slug: {readme_slug}\n{res.status_code}: {res.reason}\n{res.text}")
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
def update_confluence(api: "Api", url: str, root: str, file: str) -> None:
|
|
319
|
+
"""
|
|
320
|
+
Update the confluence documentation for the CLI
|
|
321
|
+
|
|
322
|
+
:param Api api: The API object to use to update the documentation
|
|
323
|
+
:param str url: The base URL for the confluence instance
|
|
324
|
+
:param str root: The root directory of containing file with confluence id and data
|
|
325
|
+
:param str file: File name to parse the confluence id and data from to update confluence
|
|
326
|
+
:rtype: None
|
|
327
|
+
"""
|
|
328
|
+
import json
|
|
329
|
+
|
|
330
|
+
payload = {
|
|
331
|
+
"id": None,
|
|
332
|
+
"type": "page",
|
|
333
|
+
"status": "current",
|
|
334
|
+
"title": None,
|
|
335
|
+
"version": {"number": 1},
|
|
336
|
+
"body": {"storage": {"value": "", "representation": "storage"}},
|
|
337
|
+
}
|
|
338
|
+
headers = {"Content-Type": APP_JSON}
|
|
339
|
+
confluence_id, parsed_data = _parse_confluence_md(root, file)
|
|
340
|
+
|
|
341
|
+
# get the current version of the confluence page
|
|
342
|
+
res = api.get(f"{url}/rest/api/content/{confluence_id}?expand=body.storage,version", headers=headers)
|
|
343
|
+
if res.raise_for_status() or not res.ok:
|
|
344
|
+
api.logger.error(f"Failed to get confluence id: {confluence_id}\n{res.status_code}: {res.reason}\n{res.text}")
|
|
345
|
+
return
|
|
346
|
+
json_data = res.json()
|
|
347
|
+
payload["title"] = json_data["title"]
|
|
348
|
+
payload["body"]["storage"]["value"] = parsed_data
|
|
349
|
+
payload["version"]["number"] = json_data["version"]["number"] + 1
|
|
350
|
+
api.logger.debug(f"Updated version number from {json_data['version']['number']} to {payload['version']['number']}")
|
|
351
|
+
api.logger.info(f"Updating confluence id {confluence_id} with {root}/{file} and body {json_data}")
|
|
352
|
+
res = api.put(
|
|
353
|
+
f"{url}/rest/api/content/{confluence_id}",
|
|
354
|
+
json=payload,
|
|
355
|
+
headers=headers,
|
|
356
|
+
)
|
|
357
|
+
if not res.raise_for_status() and res.ok:
|
|
358
|
+
api.logger.info(f"Successfully updated confluence id: {confluence_id}")
|
|
359
|
+
else:
|
|
360
|
+
api.logger.error(
|
|
361
|
+
f"Failed to update confluence id: {confluence_id}\n{res.status_code}: {res.reason}\n{res.text}"
|
|
362
|
+
)
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
def _parse_confluence_md(root: str, file: str) -> tuple[str, str]:
|
|
366
|
+
"""
|
|
367
|
+
Parse the confluence id and data from the markdown file
|
|
368
|
+
|
|
369
|
+
:param str root: The root directory of containing file with confluence id and data
|
|
370
|
+
:param str file: File name to parse the confluence id and data from
|
|
371
|
+
:rtype: tuple[str, str]
|
|
372
|
+
"""
|
|
373
|
+
confluence_id = None
|
|
374
|
+
payload = ""
|
|
375
|
+
with open(f"{root}/{file}", "r") as f:
|
|
376
|
+
for line in f:
|
|
377
|
+
if "# ConfluenceID:" in line:
|
|
378
|
+
confluence_id = line.split(":")[1].strip()
|
|
379
|
+
else:
|
|
380
|
+
for payload_line in f:
|
|
381
|
+
payload += payload_line
|
|
382
|
+
# parse the string data between the first and last occurrence of ``` to get the payload
|
|
383
|
+
payload = payload[payload.find("```html") + 7 : payload.rfind("```")]
|
|
384
|
+
return confluence_id, payload
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""Provide development tools for monitoring."""
|
|
2
|
+
|
|
3
|
+
from watchdog.events import FileSystemEventHandler, FileSystemEvent
|
|
4
|
+
|
|
5
|
+
from regscale.utils.files import print_file_contents
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class FileModifiedHandler(FileSystemEventHandler):
|
|
9
|
+
"""Handler for file modification events
|
|
10
|
+
|
|
11
|
+
:param str file_path: Path to the file to monitor
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
def __init__(self, file_path: str) -> None:
|
|
15
|
+
super().__init__()
|
|
16
|
+
self.file_path = file_path
|
|
17
|
+
|
|
18
|
+
def on_modified(self, event: FileSystemEvent) -> None:
|
|
19
|
+
"""Handle a file modification event and print the file contents
|
|
20
|
+
|
|
21
|
+
:param FileSystemEvent event: The event to handle
|
|
22
|
+
:rtype: None
|
|
23
|
+
"""
|
|
24
|
+
if not event.is_directory and event.src_path == self.file_path:
|
|
25
|
+
print(f"{self.file_path} modified!")
|
|
26
|
+
print_file_contents(self.file_path)
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
"""Profiling tools for use to measure performance of RegScale-CLI."""
|
|
2
|
+
|
|
3
|
+
import cProfile
|
|
4
|
+
import csv
|
|
5
|
+
import gc
|
|
6
|
+
import platform
|
|
7
|
+
import re
|
|
8
|
+
import subprocess
|
|
9
|
+
import sys
|
|
10
|
+
import time
|
|
11
|
+
from contextlib import contextmanager
|
|
12
|
+
from contextlib import suppress
|
|
13
|
+
from pstats import Stats
|
|
14
|
+
from typing import Callable, List, Tuple
|
|
15
|
+
|
|
16
|
+
from click.testing import CliRunner
|
|
17
|
+
from rich.console import Console
|
|
18
|
+
from rich.progress import track
|
|
19
|
+
from rich.table import Table
|
|
20
|
+
|
|
21
|
+
from regscale.dev.dirs import trim_relative_subpath, PROFILING_DIRS
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@contextmanager
|
|
25
|
+
def suppress_system_exit():
|
|
26
|
+
"""Suppress SystemExit exceptions when profiling functions in the CLI
|
|
27
|
+
|
|
28
|
+
:yields: Generator
|
|
29
|
+
"""
|
|
30
|
+
with suppress(SystemExit):
|
|
31
|
+
yield
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def parse_time(output: str, time_type: str) -> float:
|
|
35
|
+
"""Parse the time from the output of the time command
|
|
36
|
+
|
|
37
|
+
:param str output: The output of the time command
|
|
38
|
+
:param str time_type: The type of time to parse
|
|
39
|
+
:return: The parsed time
|
|
40
|
+
:rtype: float
|
|
41
|
+
"""
|
|
42
|
+
time_type_2 = "total" if time_type == "real" else time_type
|
|
43
|
+
match = re.search(rf"{time_type}\s+(?:(\d+)m)?(\d+\.\d+)s", output) or re.search(
|
|
44
|
+
rf"(?:(\d+)m)?(\d+\.\d+)s\s+{time_type_2}", output
|
|
45
|
+
)
|
|
46
|
+
if match:
|
|
47
|
+
return sum(float(x) * 60**i if x is not None else 0 for i, x in enumerate(reversed(match.groups())))
|
|
48
|
+
return 0
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def profile_my_function(func: Callable, *args: Tuple, iterations: int = 100, **kwargs: dict) -> None:
|
|
52
|
+
"""Profile a function using cProfile
|
|
53
|
+
|
|
54
|
+
:param Callable func: The function to profile
|
|
55
|
+
:param Tuple *args: The args to pass to the function
|
|
56
|
+
:param int iterations: The number of times to run the function, defaults to 100
|
|
57
|
+
:param dict **kwargs: The kwargs to pass to the function
|
|
58
|
+
:rtype: None
|
|
59
|
+
"""
|
|
60
|
+
stats_list: List[Stats] = []
|
|
61
|
+
for _ in track(
|
|
62
|
+
range(iterations),
|
|
63
|
+
description=f"Timing RegScale-CLI function {func.__name__} {iterations} times...",
|
|
64
|
+
):
|
|
65
|
+
gc.collect()
|
|
66
|
+
profiler = cProfile.Profile()
|
|
67
|
+
profiler.enable()
|
|
68
|
+
with suppress_system_exit():
|
|
69
|
+
profiler.runcall(func, *args, **kwargs)
|
|
70
|
+
profiler.disable()
|
|
71
|
+
stats = Stats(profiler)
|
|
72
|
+
stats_list.append(stats)
|
|
73
|
+
|
|
74
|
+
master_stats = Stats()
|
|
75
|
+
|
|
76
|
+
for stats in stats_list:
|
|
77
|
+
master_stats.add(stats)
|
|
78
|
+
|
|
79
|
+
master_stats.dump_stats("profile_stats.pstat")
|
|
80
|
+
# initialize summary variables
|
|
81
|
+
total_time: float = 0
|
|
82
|
+
all_times: List[float] = []
|
|
83
|
+
# write the stats to a CSV file
|
|
84
|
+
with open("profile_stats.csv", "w") as file:
|
|
85
|
+
csv_writer = csv.writer(file)
|
|
86
|
+
csv_writer.writerow(
|
|
87
|
+
[
|
|
88
|
+
"Module",
|
|
89
|
+
"Function",
|
|
90
|
+
"Primitive Calls",
|
|
91
|
+
"Total Calls",
|
|
92
|
+
"Time",
|
|
93
|
+
"Cumulative Time",
|
|
94
|
+
"Percentage",
|
|
95
|
+
]
|
|
96
|
+
)
|
|
97
|
+
for func_info, func_stats in master_stats.stats.items():
|
|
98
|
+
_, _, func_name = func_info
|
|
99
|
+
cc, nc, tt, ct, _ = func_stats
|
|
100
|
+
total_time += tt
|
|
101
|
+
all_times.append(tt)
|
|
102
|
+
|
|
103
|
+
for func_info, func_stats in master_stats.stats.items():
|
|
104
|
+
filename, _, func_name = func_info
|
|
105
|
+
cc, nc, tt, ct, _ = func_stats
|
|
106
|
+
percentage = "{:.3f}%".format(((tt * 1000) / (total_time / 1000)) * 100)
|
|
107
|
+
row = [
|
|
108
|
+
trim_relative_subpath(filename, PROFILING_DIRS) or filename, # trim the relative path from the filename
|
|
109
|
+
func_name,
|
|
110
|
+
cc,
|
|
111
|
+
nc,
|
|
112
|
+
"{:.8f}".format(tt),
|
|
113
|
+
"{:.8f}".format(ct),
|
|
114
|
+
percentage,
|
|
115
|
+
]
|
|
116
|
+
csv_writer.writerow(row)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def profile_about_command() -> None:
|
|
120
|
+
"""Profile the about command
|
|
121
|
+
|
|
122
|
+
:rtype: None
|
|
123
|
+
"""
|
|
124
|
+
runner = CliRunner()
|
|
125
|
+
from regscale.regscale import cli
|
|
126
|
+
|
|
127
|
+
_ = runner.invoke(cli, ["about"])
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def calculate_cli_import_time() -> float:
|
|
131
|
+
"""Calculate the import time for the CLI
|
|
132
|
+
|
|
133
|
+
:return: The import time
|
|
134
|
+
:rtype: float
|
|
135
|
+
"""
|
|
136
|
+
start_time = time.time()
|
|
137
|
+
# pylint: disable=unused-import
|
|
138
|
+
|
|
139
|
+
# pylint: enable=unused-import
|
|
140
|
+
end_time = time.time()
|
|
141
|
+
return end_time - start_time
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def calculate_load_times(command: str = "regscale about", iterations: int = 100, no_output: bool = False) -> dict:
|
|
145
|
+
"""Calculate the load times for a command
|
|
146
|
+
|
|
147
|
+
:param str command: The command to run
|
|
148
|
+
:param int iterations: The number of times to run the command
|
|
149
|
+
:param bool no_output: Whether to output the results to the console
|
|
150
|
+
:return: The load times
|
|
151
|
+
:rtype: dict
|
|
152
|
+
"""
|
|
153
|
+
total_user, min_user, max_user = 0, float("inf"), 0
|
|
154
|
+
total_sys, min_sys, max_sys = 0, float("inf"), 0
|
|
155
|
+
total_real, min_real, max_real = 0, float("inf"), 0
|
|
156
|
+
if platform.system() == "Windows":
|
|
157
|
+
console = Console()
|
|
158
|
+
console.print("[red]Calculating start time on Windows is not supported.")
|
|
159
|
+
sys.exit(0)
|
|
160
|
+
else:
|
|
161
|
+
sub_process_command = f'bash -c "time {command}"'
|
|
162
|
+
for _ in track(range(iterations), description=f"Timing RegScale-CLI load {iterations} times..."):
|
|
163
|
+
result = subprocess.run(
|
|
164
|
+
sub_process_command,
|
|
165
|
+
shell=True,
|
|
166
|
+
stderr=subprocess.PIPE,
|
|
167
|
+
stdout=subprocess.PIPE,
|
|
168
|
+
)
|
|
169
|
+
output = result.stderr.decode("utf-8")
|
|
170
|
+
# extract user, sys, and real time using regular expressions
|
|
171
|
+
user_time = parse_time(output, "user")
|
|
172
|
+
sys_time = parse_time(output, "sys")
|
|
173
|
+
real_time = parse_time(output, "real")
|
|
174
|
+
|
|
175
|
+
# update total, min, and max values
|
|
176
|
+
total_user += user_time
|
|
177
|
+
min_user = min(min_user, user_time)
|
|
178
|
+
max_user = max(max_user, user_time)
|
|
179
|
+
total_sys += sys_time
|
|
180
|
+
min_sys = min(min_sys, sys_time)
|
|
181
|
+
max_sys = max(max_sys, sys_time)
|
|
182
|
+
total_real += real_time
|
|
183
|
+
min_real = min(min_real, real_time)
|
|
184
|
+
max_real = max(max_real, real_time)
|
|
185
|
+
|
|
186
|
+
avg_user = round(total_user / iterations, 3)
|
|
187
|
+
avg_sys = round(total_sys / iterations, 3)
|
|
188
|
+
avg_real = round(total_real / iterations, 3)
|
|
189
|
+
|
|
190
|
+
if not no_output:
|
|
191
|
+
console = Console()
|
|
192
|
+
table = Table(title=f"Load times over {iterations} iterations")
|
|
193
|
+
table.add_column("Metric")
|
|
194
|
+
table.add_column("User Time (s)")
|
|
195
|
+
table.add_column("Sys Time (s)")
|
|
196
|
+
table.add_column("Real Time (s)")
|
|
197
|
+
table.add_row(
|
|
198
|
+
"[green]Min",
|
|
199
|
+
f"[green]{min_user}",
|
|
200
|
+
f"[green]{min_sys}",
|
|
201
|
+
f"[green]{min_real}",
|
|
202
|
+
)
|
|
203
|
+
table.add_row("[red]Max", f"[red]{max_user}", f"[red]{max_sys}", f"[red]{max_real}")
|
|
204
|
+
table.add_row(
|
|
205
|
+
"[yellow]Avg",
|
|
206
|
+
f"[yellow]{avg_user}",
|
|
207
|
+
f"[yellow]{avg_sys}",
|
|
208
|
+
f"[yellow]{avg_real}",
|
|
209
|
+
)
|
|
210
|
+
console.print(table)
|
|
211
|
+
sys.exit(0)
|
|
212
|
+
return {
|
|
213
|
+
"Avg User Time": avg_user,
|
|
214
|
+
"Avg Sys Time": avg_sys,
|
|
215
|
+
"Avg Real Time": avg_real,
|
|
216
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from regscale.integrations.integration import Integration
|