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,14 @@
|
|
|
1
|
+
from base64 import b64decode, b64encode
|
|
2
|
+
from io import BytesIO
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def encode_file_to_base64(file_path):
|
|
6
|
+
with open(file_path, "rb") as file:
|
|
7
|
+
file_bytes = file.read()
|
|
8
|
+
encoded_string = b64encode(file_bytes)
|
|
9
|
+
return encoded_string.decode("utf-8")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def decode_base64_to_bytesio(encoded_string):
|
|
13
|
+
decoded_bytes = b64decode(encoded_string)
|
|
14
|
+
return BytesIO(decoded_bytes)
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"""Provide utilities for interacting with click Objects."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Dict, Optional, Union
|
|
4
|
+
|
|
5
|
+
import click
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def process_click_group(
|
|
9
|
+
group: Union[click.Group, click.Command],
|
|
10
|
+
prefix: Optional[str] = None,
|
|
11
|
+
) -> Dict[str, Any]:
|
|
12
|
+
"""
|
|
13
|
+
Process a click group into a dictionary
|
|
14
|
+
|
|
15
|
+
:param Union[click.Group, click.Command] group: a click.Group or click.Command to extract info from
|
|
16
|
+
:param Optional[str] prefix: an optional prefix to name the application, defaults to `group.name`
|
|
17
|
+
:return: a dictionary of the click group
|
|
18
|
+
:rtype: Dict[str, Any]
|
|
19
|
+
"""
|
|
20
|
+
prefix = f"{group.name}" if prefix is None else f"{prefix}__{group.name}"
|
|
21
|
+
cmd_dict = {
|
|
22
|
+
"group": group,
|
|
23
|
+
"group_name": prefix,
|
|
24
|
+
}
|
|
25
|
+
for cmd_name, cmd in group.commands.items():
|
|
26
|
+
new_prefix = f"{prefix}__{cmd_name}"
|
|
27
|
+
if isinstance(cmd, click.Group):
|
|
28
|
+
cmd_dict[cmd_name] = process_click_group(cmd, new_prefix)
|
|
29
|
+
elif isinstance(cmd, click.Command):
|
|
30
|
+
cmd_dict[cmd_name] = process_command(cmd, new_prefix)
|
|
31
|
+
return cmd_dict
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def process_command(
|
|
35
|
+
cmd: click.Command,
|
|
36
|
+
cmd_name: str,
|
|
37
|
+
) -> Dict[str, Any]:
|
|
38
|
+
"""
|
|
39
|
+
Process a click command into a dictionary
|
|
40
|
+
|
|
41
|
+
:param click.Command cmd: a click.Command object
|
|
42
|
+
:param str cmd_name: the name of the command
|
|
43
|
+
:return: a dictionary of the click command
|
|
44
|
+
:rtype: Dict[str, Any]
|
|
45
|
+
"""
|
|
46
|
+
return {
|
|
47
|
+
"cmd": cmd,
|
|
48
|
+
"name": cmd_name,
|
|
49
|
+
"params": {param.name: process_option(param) for param in cmd.params if isinstance(param, click.Option)},
|
|
50
|
+
"callback": cmd.callback,
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def process_option(
|
|
55
|
+
option: click.Option,
|
|
56
|
+
) -> Dict[str, Any]:
|
|
57
|
+
"""
|
|
58
|
+
Process a click Option
|
|
59
|
+
|
|
60
|
+
:param click.Option option: a click Option object
|
|
61
|
+
:return: a dictionary of the click option
|
|
62
|
+
:rtype: Dict[str, Any]
|
|
63
|
+
"""
|
|
64
|
+
return {
|
|
65
|
+
"option": option,
|
|
66
|
+
"name": option.name,
|
|
67
|
+
"default": option.default,
|
|
68
|
+
"type": str(option.type),
|
|
69
|
+
"prompt": option.prompt,
|
|
70
|
+
"confirmation_prompt": option.confirmation_prompt,
|
|
71
|
+
"is_flag": option.is_flag,
|
|
72
|
+
"is_bool_flag": option.is_bool_flag,
|
|
73
|
+
"count": option.count,
|
|
74
|
+
"allow_from_autoenv": option.allow_from_autoenv,
|
|
75
|
+
"expose_value": option.expose_value,
|
|
76
|
+
"is_eager": option.is_eager,
|
|
77
|
+
"callback": option.callback,
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def find_file_path_parameters(group: Union[click.Group, click.Command], prefix: str = None) -> dict:
|
|
82
|
+
"""
|
|
83
|
+
Find all file path parameters in a click group
|
|
84
|
+
|
|
85
|
+
:param Union[click.Group, click.Command] group: a click.Group or click.Command to extract info from
|
|
86
|
+
:param str prefix: an optional prefix to name the application, defaults to `group.name`
|
|
87
|
+
:return: a dictionary of file path parameters
|
|
88
|
+
:rtype: dict
|
|
89
|
+
"""
|
|
90
|
+
file_path_parameters = {}
|
|
91
|
+
|
|
92
|
+
def add_to_dict(_key: str, _param: Any) -> None:
|
|
93
|
+
"""
|
|
94
|
+
Helper function to add to the dictionary
|
|
95
|
+
|
|
96
|
+
:param str _key: the key to add to the dictionary
|
|
97
|
+
:param Any _param: the parameter to add to the dictionary
|
|
98
|
+
:rtype: None
|
|
99
|
+
"""
|
|
100
|
+
if _key not in file_path_parameters:
|
|
101
|
+
file_path_parameters[_key] = []
|
|
102
|
+
file_path_parameters[_key].append(_param)
|
|
103
|
+
|
|
104
|
+
for cmd_name, cmd in group.commands.items():
|
|
105
|
+
current_suffix = cmd_name if not prefix else f"{prefix}__{cmd_name}"
|
|
106
|
+
|
|
107
|
+
if isinstance(cmd, click.Group):
|
|
108
|
+
file_path_parameters[cmd_name] = find_file_path_parameters(cmd, prefix)
|
|
109
|
+
inner_parameters = find_file_path_parameters(cmd, current_suffix)
|
|
110
|
+
for key, values in inner_parameters.items():
|
|
111
|
+
add_to_dict(key, values)
|
|
112
|
+
else:
|
|
113
|
+
for param in cmd.params:
|
|
114
|
+
if isinstance(param.type, (click.Path, click.File)):
|
|
115
|
+
add_to_dict(current_suffix, param)
|
|
116
|
+
elif "file" in param.name or "path" in param.name:
|
|
117
|
+
add_to_dict(current_suffix, param)
|
|
118
|
+
return file_path_parameters
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""
|
|
2
|
+
App decorators
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import warnings
|
|
6
|
+
import functools
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def deprecated(reason="This method is deprecated and may be removed in a future version."):
|
|
10
|
+
"""
|
|
11
|
+
Decorator to mark functions as deprecated.
|
|
12
|
+
|
|
13
|
+
:param reason: The reason for deprecation.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def decorator(func):
|
|
17
|
+
"""
|
|
18
|
+
Decorator to mark functions as deprecated.
|
|
19
|
+
:param func:
|
|
20
|
+
:return:
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
@functools.wraps(func)
|
|
24
|
+
def wrapper(*args, **kwargs):
|
|
25
|
+
"""
|
|
26
|
+
Wrapper function to mark functions as deprecated.
|
|
27
|
+
:param args:
|
|
28
|
+
:param kwargs:
|
|
29
|
+
:return:
|
|
30
|
+
"""
|
|
31
|
+
warnings.warn(f"{func.__name__} is deprecated: {reason}", category=DeprecationWarning, stacklevel=2)
|
|
32
|
+
return func(*args, **kwargs)
|
|
33
|
+
|
|
34
|
+
return wrapper
|
|
35
|
+
|
|
36
|
+
return decorator
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class classproperty: # pylint: disable=invalid-name # noqa: N801
|
|
40
|
+
"""
|
|
41
|
+
A class property decorator.
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
def __init__(self, func):
|
|
45
|
+
self.func = func
|
|
46
|
+
|
|
47
|
+
def __get__(self, instance, owner):
|
|
48
|
+
return self.func(owner)
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module contains utility functions for working with dictionaries.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Dict, List, Tuple, Any, Optional
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def get_value(data: dict, key: str) -> Any:
|
|
9
|
+
"""
|
|
10
|
+
Get a value from a dictionary even if nested dict using dot notation.
|
|
11
|
+
If the value is within a list, return a list of values. (e.g. "key1.key2" -> {key1: {key2: value2}}) -> value2
|
|
12
|
+
also fetches values from nested lists. (e.g. "key1.key2" -> {key1: [{key2: value2}, {key2: value3}]} -> [value2, value3])
|
|
13
|
+
:param dict data: The dictionary to get the value from.
|
|
14
|
+
:param str key: The key to get the value for.
|
|
15
|
+
:return: The value from the dictionary or None if the key is not found.
|
|
16
|
+
:rtype: Any
|
|
17
|
+
"""
|
|
18
|
+
keys = key.split(".")
|
|
19
|
+
value = data
|
|
20
|
+
for k in keys:
|
|
21
|
+
if isinstance(value, list):
|
|
22
|
+
value = [item.get(k, None) if isinstance(item, dict) else None for item in value]
|
|
23
|
+
elif isinstance(value, dict):
|
|
24
|
+
value = value.get(k, None)
|
|
25
|
+
else:
|
|
26
|
+
return None
|
|
27
|
+
if value and any(isinstance(i, list) for i in value):
|
|
28
|
+
value = [item for sublist in value for item in sublist if item is not None]
|
|
29
|
+
return value
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def flatten_dict(
|
|
33
|
+
d: Dict[str, Any], prefix: str = "", result: Optional[List[Tuple[str, Any]]] = None
|
|
34
|
+
) -> List[Tuple[str, Any]]:
|
|
35
|
+
"""
|
|
36
|
+
Recursively flattens a nested dictionary or list of dictionaries into a list of tuples,
|
|
37
|
+
preserving the hierarchy in the keys.
|
|
38
|
+
|
|
39
|
+
:param Dict[str, Any] d: The dictionary or list of dictionaries to flatten.
|
|
40
|
+
:param str prefix: The current prefix representing the hierarchy of keys, defaults to an empty string.
|
|
41
|
+
:param Optional[List[Tuple[str, Any]]] result: The accumulated list of tuples, This is used internally and should
|
|
42
|
+
not be set by the caller. defaults to None.
|
|
43
|
+
:return: A list of tuples where each tuple is a key-value pair, with the key representing the hierarchical path.
|
|
44
|
+
:rtype: List[Tuple[str, Any]]
|
|
45
|
+
"""
|
|
46
|
+
if result is None:
|
|
47
|
+
result = []
|
|
48
|
+
if isinstance(d, dict):
|
|
49
|
+
for key, value in d.items():
|
|
50
|
+
new_key = f"{prefix}{key}" if prefix else key
|
|
51
|
+
if isinstance(value, (dict, list)):
|
|
52
|
+
flatten_dict(value, f"{new_key}.", result)
|
|
53
|
+
else:
|
|
54
|
+
result.append((new_key, value))
|
|
55
|
+
elif isinstance(d, list):
|
|
56
|
+
for index, item in enumerate(d):
|
|
57
|
+
flatten_dict(item, f"{prefix}{index}.", result)
|
|
58
|
+
|
|
59
|
+
return result
|
regscale/utils/files.py
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"""Provide functions for dealing with files."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from tempfile import gettempdir
|
|
6
|
+
from types import TracebackType
|
|
7
|
+
from typing import Union, TextIO, Optional, Type
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def print_file_contents(file_path: Union[str, Path]) -> None:
|
|
11
|
+
"""
|
|
12
|
+
Print a file's contents to the console.
|
|
13
|
+
|
|
14
|
+
:param Union[str, Path] file_path: a string or Path object
|
|
15
|
+
:rtype: None
|
|
16
|
+
"""
|
|
17
|
+
if isinstance(file_path, str):
|
|
18
|
+
file_path = Path(file_path)
|
|
19
|
+
if file_path.is_file():
|
|
20
|
+
print(f'File "{file_path}" found!')
|
|
21
|
+
print(file_path.read_text(encoding="utf-8"))
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def print_current_directory(print_yaml: bool = False) -> None:
|
|
25
|
+
"""
|
|
26
|
+
Print the contents of the current directory and its path
|
|
27
|
+
|
|
28
|
+
:param bool print_yaml: should the contents of the yaml file be printed, defaults to False
|
|
29
|
+
:rtype: None
|
|
30
|
+
"""
|
|
31
|
+
current_dir = os.getcwd()
|
|
32
|
+
print(f"Current Working Directory: {current_dir}")
|
|
33
|
+
if print_yaml:
|
|
34
|
+
init_file = os.path.join(current_dir, "init.yaml")
|
|
35
|
+
print_file_contents(init_file)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class CustomTempFile:
|
|
39
|
+
"""
|
|
40
|
+
A context manager for creating temporary files
|
|
41
|
+
|
|
42
|
+
:param Union[str, Path] filename: the name of the file
|
|
43
|
+
:param bool delete: should the file be deleted when the context is exited? (default: True)
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
def __init__(self, filename: Union[str, Path], delete: bool = True):
|
|
47
|
+
self.temp_dir = gettempdir()
|
|
48
|
+
self.temp_filename = os.path.join(self.temp_dir, filename)
|
|
49
|
+
self.delete = delete
|
|
50
|
+
self.temp_file = None
|
|
51
|
+
|
|
52
|
+
def __enter__(self) -> TextIO:
|
|
53
|
+
"""
|
|
54
|
+
Open the file with read/write permissions
|
|
55
|
+
|
|
56
|
+
:return: the file object
|
|
57
|
+
:rtype: TextIO
|
|
58
|
+
"""
|
|
59
|
+
self.temp_file = open(self.temp_filename, "w+")
|
|
60
|
+
return self.temp_file
|
|
61
|
+
|
|
62
|
+
def __exit__(
|
|
63
|
+
self, exc_type: Optional[Type[BaseException]], exc_val: Optional[BaseException], exc_tb: Optional[TracebackType]
|
|
64
|
+
) -> None:
|
|
65
|
+
"""
|
|
66
|
+
Close the file
|
|
67
|
+
|
|
68
|
+
:param Optional[Type[BaseException]] exc_type: The exception type
|
|
69
|
+
:param Optional[BaseException] exc_val: The exception value
|
|
70
|
+
:param Optional[TracebackType] exc_tb: The traceback
|
|
71
|
+
:rtype: None
|
|
72
|
+
"""
|
|
73
|
+
# Close the file
|
|
74
|
+
if self.temp_file:
|
|
75
|
+
self.temp_file.close()
|
|
76
|
+
|
|
77
|
+
# Optionally, delete the file
|
|
78
|
+
if self.delete:
|
|
79
|
+
os.remove(self.temp_filename)
|
regscale/utils/fxns.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""Provide utilities for dealing with functions."""
|
|
2
|
+
|
|
3
|
+
import inspect
|
|
4
|
+
from typing import Any, List
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def get_callback_param(command: Any) -> List[str]:
|
|
8
|
+
"""
|
|
9
|
+
Return a list of parameter names in the callback function of a command
|
|
10
|
+
|
|
11
|
+
:param Any command: a function to get the parameters for
|
|
12
|
+
:return: a list of parameter names
|
|
13
|
+
:rtype: List[str]
|
|
14
|
+
"""
|
|
15
|
+
callback = command.callback
|
|
16
|
+
sig = inspect.signature(callback)
|
|
17
|
+
return list(sig.parameters.keys())
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def get_callback_defaults(command: Any) -> dict:
|
|
21
|
+
"""
|
|
22
|
+
Return a dictionary of callback defaults.
|
|
23
|
+
|
|
24
|
+
:param Any command: a function to get the defaults for
|
|
25
|
+
:return: a dictionary of parameter names and their defaults
|
|
26
|
+
:rtype: dict
|
|
27
|
+
"""
|
|
28
|
+
callback = command.callback
|
|
29
|
+
sig = inspect.signature(callback)
|
|
30
|
+
return {name: param.default if param.default != param.empty else None for name, param in sig.parameters.items()}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"""
|
|
2
|
+
A module for making paginated GraphQL queries.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
from typing import List, Dict, Optional, Any
|
|
7
|
+
|
|
8
|
+
from regscale.core.app.utils.app_utils import create_progress_object
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class PaginatedGraphQLClient:
|
|
14
|
+
"""
|
|
15
|
+
A class for making paginated GraphQL queries.
|
|
16
|
+
|
|
17
|
+
:param str endpoint: The GraphQL endpoint.
|
|
18
|
+
:param str query: The GraphQL query.
|
|
19
|
+
:param Optional[Dict[str, str]] headers: Optional headers to include in the request.
|
|
20
|
+
:param str logging_level: The logging level for the client (default: 'CRITICAL').
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
def __init__(
|
|
24
|
+
self,
|
|
25
|
+
endpoint: str,
|
|
26
|
+
query: str,
|
|
27
|
+
headers: Optional[Dict[str, str]] = None,
|
|
28
|
+
logging_level: str = logging.CRITICAL,
|
|
29
|
+
) -> None:
|
|
30
|
+
from gql import gql, Client # Optimize import performance
|
|
31
|
+
from gql.transport.requests import RequestsHTTPTransport
|
|
32
|
+
from gql.transport.requests import log as requests_logger
|
|
33
|
+
|
|
34
|
+
self.log_level = logging_level
|
|
35
|
+
self.endpoint = endpoint
|
|
36
|
+
self.query = gql(query)
|
|
37
|
+
self.headers = headers or {} # Ensure headers are a dictionary
|
|
38
|
+
self.transport = RequestsHTTPTransport(url=endpoint, headers=self.headers)
|
|
39
|
+
self.client = Client(transport=self.transport)
|
|
40
|
+
self.job_progress = create_progress_object()
|
|
41
|
+
requests_logger.setLevel(level=self.log_level)
|
|
42
|
+
|
|
43
|
+
def fetch_all(
|
|
44
|
+
self,
|
|
45
|
+
topic_key: str,
|
|
46
|
+
variables: Optional[Dict[str, Any]] = None,
|
|
47
|
+
) -> List[Dict[str, Any]]:
|
|
48
|
+
"""
|
|
49
|
+
Fetches all results from the paginated query.
|
|
50
|
+
|
|
51
|
+
:param str topic_key: The key to the topic in the response.
|
|
52
|
+
:param Optional[Dict[str, Any]] variables: Optional query variables.
|
|
53
|
+
:return: A list of results.
|
|
54
|
+
:rtype: List[Dict[str, Any]]
|
|
55
|
+
"""
|
|
56
|
+
self.job_progress.add_task("[#f68d1f]Fetching data...", total=None)
|
|
57
|
+
results = []
|
|
58
|
+
next_cursor = None
|
|
59
|
+
has_next_page = True
|
|
60
|
+
page_info_default = {"hasNextPage": False, "endCursor": None}
|
|
61
|
+
while has_next_page:
|
|
62
|
+
data = self.fetch_page(variables=variables, after=next_cursor)
|
|
63
|
+
if data:
|
|
64
|
+
results.extend(data.get(topic_key, {}).get("nodes", []))
|
|
65
|
+
page_info = data.get(topic_key, {}).get("pageInfo", page_info_default)
|
|
66
|
+
logger.debug(f"pageInfo: {page_info}")
|
|
67
|
+
has_next_page = page_info.get("hasNextPage", False)
|
|
68
|
+
next_cursor = page_info.get("endCursor", None)
|
|
69
|
+
if not has_next_page:
|
|
70
|
+
break
|
|
71
|
+
else:
|
|
72
|
+
break
|
|
73
|
+
return results
|
|
74
|
+
|
|
75
|
+
def fetch_page(self, variables: Optional[Dict[str, Any]] = None, after: Optional[str] = None) -> Dict[str, Any]:
|
|
76
|
+
"""
|
|
77
|
+
Fetches a single page of results.
|
|
78
|
+
|
|
79
|
+
:param Optional[Dict[str, Any]] variables: Optional query variables.
|
|
80
|
+
:param Optional[str] after: The cursor for pagination (optional, defaults to None for the first page).
|
|
81
|
+
:return: A dictionary containing the fetched page of results and pagination information.
|
|
82
|
+
:rtype: Dict[str, Any]
|
|
83
|
+
:raises: Exception if an error occurs during the query execution
|
|
84
|
+
"""
|
|
85
|
+
variables = variables or {}
|
|
86
|
+
variables["after"] = after
|
|
87
|
+
|
|
88
|
+
try:
|
|
89
|
+
result = self.client.execute(self.query, variable_values=variables)
|
|
90
|
+
return result
|
|
91
|
+
except Exception as e:
|
|
92
|
+
logger.error(f"An error occurred while executing the query: {str(e)}", exc_info=True)
|
|
93
|
+
logger.error(f"Query: {self.query}")
|
|
94
|
+
logger.error(f"Variables: {variables}")
|
|
95
|
+
raise
|
|
96
|
+
|
|
97
|
+
def fetch_results(self, variables: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
|
|
98
|
+
"""
|
|
99
|
+
Fetches a single page of results.
|
|
100
|
+
|
|
101
|
+
:param Optional[Dict[str, Any]] variables: Optional query variables.
|
|
102
|
+
:return: A dictionary containing the fetched page of results and pagination information.
|
|
103
|
+
:rtype: Dict[str, Any]
|
|
104
|
+
:raises: Exception if an error occurs during the query execution
|
|
105
|
+
"""
|
|
106
|
+
try:
|
|
107
|
+
result = self.client.execute(self.query, variable_values=variables)
|
|
108
|
+
return result
|
|
109
|
+
except Exception as e:
|
|
110
|
+
logger.error(f"An error occurred while executing the query: {str(e)}", exc_info=True)
|
|
111
|
+
logger.error(f"Query: {self.query}")
|
|
112
|
+
logger.error(f"Variables: {variables}")
|
|
113
|
+
raise
|
regscale/utils/lists.py
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""Provide utility functions for dealing with lists."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Tuple
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def add_and_return_unique(*lists: Tuple[Any]) -> list: # noqa: DOC103
|
|
7
|
+
"""Add lists together and return a list of unique elements
|
|
8
|
+
|
|
9
|
+
:param Tuple[Any] *lists: lists to add together
|
|
10
|
+
:return: a list of unique elements
|
|
11
|
+
:rtype: list
|
|
12
|
+
"""
|
|
13
|
+
unique_elements = set()
|
|
14
|
+
for lst in lists:
|
|
15
|
+
unique_elements.update(lst)
|
|
16
|
+
return list(unique_elements)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""Define functions relating to numbers"""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def is_number(value: Any) -> bool:
|
|
7
|
+
"""Determine if a value is a number
|
|
8
|
+
:param Any value: value to check
|
|
9
|
+
:return: whether the value is a number
|
|
10
|
+
:rtype: bool
|
|
11
|
+
"""
|
|
12
|
+
return isinstance(value, (int, float, complex))
|
regscale/utils/shell.py
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"""Define methods for use with CLI operations."""
|
|
2
|
+
|
|
3
|
+
from pprint import pprint
|
|
4
|
+
from shlex import split as shlexsplit
|
|
5
|
+
from subprocess import (
|
|
6
|
+
check_output,
|
|
7
|
+
Popen,
|
|
8
|
+
PIPE,
|
|
9
|
+
run,
|
|
10
|
+
CalledProcessError,
|
|
11
|
+
)
|
|
12
|
+
from typing import Union
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def strbyte(string: str, encoding: str = "utf-8") -> bytes:
|
|
16
|
+
"""Convert a string to bytes
|
|
17
|
+
|
|
18
|
+
String will have `\n` append and converted to encoding.
|
|
19
|
+
|
|
20
|
+
:param str string: the string to convert to bytes
|
|
21
|
+
:param str encoding: the encoding to use, defaults to "utf-8"
|
|
22
|
+
:return: a bytes object
|
|
23
|
+
:rtype: bytes
|
|
24
|
+
"""
|
|
25
|
+
if not string.endswith("\n"):
|
|
26
|
+
string += "\n"
|
|
27
|
+
return bytes(string, encoding=encoding)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
# FIXME - this was useful early on -- will any of this be useful once the SDK is in-place?
|
|
31
|
+
def send_input_to_process_via_communicate(
|
|
32
|
+
process: Popen,
|
|
33
|
+
input_: str,
|
|
34
|
+
encoding: str = "utf-8",
|
|
35
|
+
) -> tuple:
|
|
36
|
+
"""Send an input string to a process
|
|
37
|
+
|
|
38
|
+
When passed a Popen process, send the input as an encoded bytes
|
|
39
|
+
|
|
40
|
+
:param Popen process: the Popen process
|
|
41
|
+
:param str input_: a string to send to the process
|
|
42
|
+
:param str encoding: specify the encoding, defaults to "utf-8"
|
|
43
|
+
:return: a tuple of stdout, stderr
|
|
44
|
+
:rtype: tuple
|
|
45
|
+
"""
|
|
46
|
+
return process.communicate(strbyte(string=input_, encoding=encoding))
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def run_command(
|
|
50
|
+
cmd: Union[str, list],
|
|
51
|
+
) -> bool:
|
|
52
|
+
"""Run a shell command
|
|
53
|
+
|
|
54
|
+
Use python subprocess to run a command.
|
|
55
|
+
|
|
56
|
+
:param Union[str, list] cmd: a list or string of commands to execute
|
|
57
|
+
:raises CalledProcessError: if the command returns an error
|
|
58
|
+
:return: a bool indicating success or failure
|
|
59
|
+
:rtype: bool
|
|
60
|
+
"""
|
|
61
|
+
if isinstance(cmd, str):
|
|
62
|
+
cmd = shlexsplit(cmd)
|
|
63
|
+
try:
|
|
64
|
+
run(cmd, check=True, stdout=PIPE, stderr=PIPE)
|
|
65
|
+
return True
|
|
66
|
+
except CalledProcessError as exc:
|
|
67
|
+
print(f"Command '{' '.join(cmd)}' returned with error (code {exc.returncode}): {exc.output.decode()}")
|
|
68
|
+
raise exc
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def run_command_and_store_output(
|
|
72
|
+
cmd: Union[str, list],
|
|
73
|
+
output: bool = False,
|
|
74
|
+
) -> str:
|
|
75
|
+
"""Run a shell command and store the output
|
|
76
|
+
|
|
77
|
+
Runs a simple shell command and stores the output as a string.
|
|
78
|
+
|
|
79
|
+
:param Union[str, list] cmd: a list or string of commands
|
|
80
|
+
:param bool output: should pprint be used to display, defaults to False
|
|
81
|
+
:return: A string of the command output
|
|
82
|
+
:rtype: str
|
|
83
|
+
"""
|
|
84
|
+
if isinstance(cmd, list):
|
|
85
|
+
cmd = " ".join(cmd)
|
|
86
|
+
cmd_output = check_output(cmd, shell=True, text=True)
|
|
87
|
+
if output:
|
|
88
|
+
pprint(f"Command output:\n{cmd_output}")
|
|
89
|
+
return cmd_output
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def send_input_to_process(
|
|
93
|
+
process: Popen,
|
|
94
|
+
input_: str,
|
|
95
|
+
) -> None:
|
|
96
|
+
"""Send an input string to a process
|
|
97
|
+
|
|
98
|
+
When passed a Popen process, send the input as an encoded bytes
|
|
99
|
+
|
|
100
|
+
:param Popen process: the Popen process
|
|
101
|
+
:param str input_: a string to send to the process
|
|
102
|
+
return: None
|
|
103
|
+
"""
|
|
104
|
+
process.stdin.write(input_)
|
|
105
|
+
process.stdin.flush()
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def run_command_interactively(
|
|
109
|
+
cmd: Union[str, list],
|
|
110
|
+
inputs: Union[str, list],
|
|
111
|
+
output: bool = False,
|
|
112
|
+
include_error: bool = False,
|
|
113
|
+
) -> str:
|
|
114
|
+
"""Run a command by sending inputs
|
|
115
|
+
|
|
116
|
+
Runs a shell command and send inputs to it
|
|
117
|
+
|
|
118
|
+
:param Union[str, list] cmd: the initial command to invoke
|
|
119
|
+
:param Union[str, list] inputs: a single str of inputs or a list to pass to the command interactively
|
|
120
|
+
:param bool output: should output be pprinted? defaults to False
|
|
121
|
+
:param bool include_error: should error be output as well?, default False
|
|
122
|
+
:return: A string of the command output
|
|
123
|
+
:rtype: str
|
|
124
|
+
"""
|
|
125
|
+
if isinstance(cmd, list):
|
|
126
|
+
cmd = " ".join(cmd)
|
|
127
|
+
|
|
128
|
+
process = Popen(shlexsplit(cmd), stdin=PIPE, stdout=PIPE, stderr=PIPE, text=True)
|
|
129
|
+
|
|
130
|
+
if isinstance(inputs, str):
|
|
131
|
+
inputs = [inputs]
|
|
132
|
+
|
|
133
|
+
for input_ in inputs:
|
|
134
|
+
send_input_to_process(process=process, input_=input_)
|
|
135
|
+
|
|
136
|
+
stdout, stderr = process.communicate()
|
|
137
|
+
output_std = stdout or ""
|
|
138
|
+
output_err = stderr or ""
|
|
139
|
+
|
|
140
|
+
if output:
|
|
141
|
+
pprint(output_std)
|
|
142
|
+
if include_error:
|
|
143
|
+
pprint(output_err)
|
|
144
|
+
|
|
145
|
+
result = output_std
|
|
146
|
+
if include_error:
|
|
147
|
+
result += "\n" + output_err
|
|
148
|
+
return result
|