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,495 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
"""Script to parse a .xlsx file and load the inventory into RegScale as assets"""
|
|
3
|
+
|
|
4
|
+
import json
|
|
5
|
+
import os
|
|
6
|
+
import re
|
|
7
|
+
from datetime import datetime
|
|
8
|
+
from json import JSONDecodeError
|
|
9
|
+
from typing import Any, Dict, List, Optional, Union, Literal
|
|
10
|
+
|
|
11
|
+
import rich.progress
|
|
12
|
+
|
|
13
|
+
from regscale.core.app.api import Api
|
|
14
|
+
from regscale.core.app.utils.app_utils import create_logger, create_progress_object, check_file_path
|
|
15
|
+
from regscale.core.utils.date import date_str
|
|
16
|
+
from regscale.models import Asset, ImportValidater, Property
|
|
17
|
+
|
|
18
|
+
api = Api()
|
|
19
|
+
config = api.config
|
|
20
|
+
SOFTWARE_VENDOR = "Software/ Database Vendor"
|
|
21
|
+
SOFTWARE_NAME = "Software/ Database Name & Version"
|
|
22
|
+
PATCH_LEVEL = "Patch Level"
|
|
23
|
+
HARDWARE_MAKE = "Hardware Make/Model"
|
|
24
|
+
MAC_ADDRESS = "MAC Address"
|
|
25
|
+
OS_NAME = "OS Name and Version"
|
|
26
|
+
fmt = "%Y-%m-%d %H:%M:%S"
|
|
27
|
+
UNIQUE_ASSET_IDENTIFIER = "UNIQUE ASSET IDENTIFIER"
|
|
28
|
+
NETBIOS_NAME = "NetBIOS Name"
|
|
29
|
+
BASELINE_CONFIGURATION_NAME = "Baseline Configuration Name"
|
|
30
|
+
SERIAL_NUMBER = "Serial #/Asset Tag#"
|
|
31
|
+
DNS_NAME = "DNS Name or URL"
|
|
32
|
+
AUTHENTICATED_SCAN = "Authenticated Scan"
|
|
33
|
+
IN_LATEST_SCAN = "In Latest Scan"
|
|
34
|
+
IPV4_OR_IPV6_ADDRESS = "IPv4 or IPv6\nAddress"
|
|
35
|
+
ASSET_TYPE = "Asset Type"
|
|
36
|
+
VLAN_NETWORK_ID = "VLAN/\nNetwork ID"
|
|
37
|
+
FUNCTION = "Function"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def check_text(text: Optional[str] = None) -> str:
|
|
41
|
+
"""
|
|
42
|
+
Check for NULL values and return empty string if NULL
|
|
43
|
+
:param Optional[str] text: string to check if it is NULL, defaults to None
|
|
44
|
+
:return: empty string if NULL, otherwise the string
|
|
45
|
+
:rtype: str
|
|
46
|
+
"""
|
|
47
|
+
return str(text or "")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def save_to_json(file_name: str, data: Any) -> None:
|
|
51
|
+
"""
|
|
52
|
+
Save the data to a JSON file
|
|
53
|
+
:param str file_name: name of the file to save
|
|
54
|
+
:param Any data: data to save to the file
|
|
55
|
+
:rtype: None
|
|
56
|
+
"""
|
|
57
|
+
if not data:
|
|
58
|
+
return
|
|
59
|
+
if isinstance(data, list) and isinstance(data[0], Asset):
|
|
60
|
+
lst = []
|
|
61
|
+
for item in data:
|
|
62
|
+
lst.append(item.dict())
|
|
63
|
+
data = lst
|
|
64
|
+
|
|
65
|
+
elif not isinstance(data, str):
|
|
66
|
+
lst = []
|
|
67
|
+
for key, value in data.items():
|
|
68
|
+
lst.append(data[key]["asset"].dict())
|
|
69
|
+
data = lst
|
|
70
|
+
|
|
71
|
+
if file_name.endswith(".json"):
|
|
72
|
+
file_name = file_name[:-5]
|
|
73
|
+
with open(f"{file_name}.json", "w") as outfile:
|
|
74
|
+
outfile.write(json.dumps(data, indent=4))
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def map_str_to_bool(value: Optional[Union[bool, str]] = None) -> bool:
|
|
78
|
+
"""
|
|
79
|
+
Map a string to a boolean value
|
|
80
|
+
:param Optional[Union[bool, str]] value: string or bool value to map to a bool, defaults to False
|
|
81
|
+
:return: boolean value
|
|
82
|
+
:rtype: bool
|
|
83
|
+
"""
|
|
84
|
+
import math
|
|
85
|
+
|
|
86
|
+
if isinstance(value, bool):
|
|
87
|
+
return value
|
|
88
|
+
if isinstance(value, float) and math.isnan(value):
|
|
89
|
+
return False
|
|
90
|
+
if value.lower() in ["yes", "true"]:
|
|
91
|
+
return True
|
|
92
|
+
elif value.lower() in ["no", "false"]:
|
|
93
|
+
return False
|
|
94
|
+
else:
|
|
95
|
+
return False
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def determine_ip_address_version(ip_address: Optional[str] = None) -> Optional[str]:
|
|
99
|
+
"""
|
|
100
|
+
Determine if the IP address is IPv4 or IPv6
|
|
101
|
+
:param Optional[str] ip_address: IP address to check, defaults to None
|
|
102
|
+
:return: Key for the IP address version in the asset object
|
|
103
|
+
:rtype: Optional[str]
|
|
104
|
+
"""
|
|
105
|
+
if not isinstance(ip_address, str) or not ip_address:
|
|
106
|
+
return None
|
|
107
|
+
ip_address = ip_address.strip()
|
|
108
|
+
|
|
109
|
+
# IPv4 pattern - matches numbers 1-255 for first octet and 0-255 for remaining octets
|
|
110
|
+
ipv4_pattern = (
|
|
111
|
+
r"^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[1-9])\." # First octet: 1-255
|
|
112
|
+
r"(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\." # Second octet: 0-255
|
|
113
|
+
r"(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\." # Third octet: 0-255
|
|
114
|
+
r"(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9]))$" # Fourth octet: 0-255
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
# IPv6 pattern - handles all valid IPv6 formats including compressed notation
|
|
118
|
+
ipv6_pattern = (
|
|
119
|
+
r"^(?:"
|
|
120
|
+
r"(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|"
|
|
121
|
+
r"(?:[0-9a-fA-F]{1,4}:){1,7}:|"
|
|
122
|
+
r"(?:[0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|"
|
|
123
|
+
r"(?:[0-9a-fA-F]{1,4}:){1,5}(?::[0-9a-fA-F]{1,4}){1,2}|"
|
|
124
|
+
r"(?:[0-9a-fA-F]{1,4}:){1,4}(?::[0-9a-fA-F]{1,4}){1,3}|"
|
|
125
|
+
r"(?:[0-9a-fA-F]{1,4}:){1,3}(?::[0-9a-fA-F]{1,4}){1,4}|"
|
|
126
|
+
r"(?:[0-9a-fA-F]{1,4}:){1,2}(?::[0-9a-fA-F]{1,4}){1,5}|"
|
|
127
|
+
r"[0-9a-fA-F]{1,4}:(?:(?::[0-9a-fA-F]{1,4}){1,6})|"
|
|
128
|
+
r":(?:(?::[0-9a-fA-F]{1,4}){1,7}|:)|"
|
|
129
|
+
r"fe80:(?::[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]+|"
|
|
130
|
+
r"::(?:ffff(?::0{1,4})?:)?(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9][0-9]?)"
|
|
131
|
+
r"\.(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9][0-9]?)"
|
|
132
|
+
r"\.(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9][0-9]?)"
|
|
133
|
+
r"\.(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9][0-9]?)|"
|
|
134
|
+
r"(?:[0-9a-fA-F]{1,4}:){1,4}:"
|
|
135
|
+
r"(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9][0-9]?)"
|
|
136
|
+
r"\.(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9][0-9]?)"
|
|
137
|
+
r"\.(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9][0-9]?)"
|
|
138
|
+
r"\.(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9][0-9]?)"
|
|
139
|
+
r")$"
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
# Check for IPv4
|
|
143
|
+
try:
|
|
144
|
+
if re.fullmatch(ipv4_pattern, ip_address):
|
|
145
|
+
return "ipAddress"
|
|
146
|
+
# Check for IPv6
|
|
147
|
+
elif re.fullmatch(ipv6_pattern, ip_address):
|
|
148
|
+
return "iPv6Address"
|
|
149
|
+
else:
|
|
150
|
+
return None
|
|
151
|
+
except Exception:
|
|
152
|
+
return None
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def determine_asset_category(inventory: dict, mapping: "ImportValidater.mapping") -> str:
|
|
156
|
+
"""
|
|
157
|
+
Determine the asset category based on the inventory item
|
|
158
|
+
:param dict inventory: inventory item to parse & determine the asset category
|
|
159
|
+
:param ImportValidater.mapping mapping: Mapping object to use for mapping
|
|
160
|
+
:return: asset category of Hardware, Software, or Unknown
|
|
161
|
+
:rtype: str
|
|
162
|
+
"""
|
|
163
|
+
software_fields = [
|
|
164
|
+
check_text(mapping.get_value(inventory, SOFTWARE_VENDOR)),
|
|
165
|
+
check_text(mapping.get_value(inventory, SOFTWARE_NAME)),
|
|
166
|
+
check_text(mapping.get_value(inventory, PATCH_LEVEL)),
|
|
167
|
+
]
|
|
168
|
+
hardware_fields = [
|
|
169
|
+
check_text(mapping.get_value(inventory, HARDWARE_MAKE)),
|
|
170
|
+
check_text(mapping.get_value(inventory, MAC_ADDRESS)),
|
|
171
|
+
check_text(mapping.get_value(inventory, OS_NAME)),
|
|
172
|
+
]
|
|
173
|
+
software_set = set(software_fields)
|
|
174
|
+
hardware_set = set(hardware_fields)
|
|
175
|
+
if len(hardware_set) > len(software_set):
|
|
176
|
+
return "Hardware"
|
|
177
|
+
if len(software_set) > len(hardware_set):
|
|
178
|
+
return "Software"
|
|
179
|
+
return "Unknown"
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def map_inventory_to_asset(
|
|
183
|
+
inventory: dict, parent_id: int, parent_module: str, mapping: "ImportValidater.mapping"
|
|
184
|
+
) -> Optional[Asset]:
|
|
185
|
+
"""
|
|
186
|
+
Map the inventory to a RegScale asset
|
|
187
|
+
:param dict inventory: inventory item to map to a RegScale asset
|
|
188
|
+
:param int parent_id: RegScale Record ID to use as parentId
|
|
189
|
+
:param str parent_module: RegScale Module to use as parentModule
|
|
190
|
+
:param ImportValidater.mapping mapping: Mapping object to use for mapping
|
|
191
|
+
:return: RegScale asset, if it has a unique identifier or DNS name
|
|
192
|
+
:rtype: Optional[Asset]
|
|
193
|
+
"""
|
|
194
|
+
# create a new asset
|
|
195
|
+
asset_category = determine_asset_category(inventory, mapping)
|
|
196
|
+
if asset_name := check_text(mapping.get_value(inventory, UNIQUE_ASSET_IDENTIFIER)) or check_text(
|
|
197
|
+
mapping.get_value(inventory, DNS_NAME)
|
|
198
|
+
):
|
|
199
|
+
new_asset = {
|
|
200
|
+
"id": 0,
|
|
201
|
+
"isPublic": True,
|
|
202
|
+
"uuid": "",
|
|
203
|
+
"name": asset_name,
|
|
204
|
+
"otherTrackingNumber": "",
|
|
205
|
+
"serialNumber": check_text(mapping.get_value(inventory, SERIAL_NUMBER)),
|
|
206
|
+
"macAddress": check_text(mapping.get_value(inventory, MAC_ADDRESS)),
|
|
207
|
+
"manufacturer": "",
|
|
208
|
+
"model": check_text(mapping.get_value(inventory, HARDWARE_MAKE)),
|
|
209
|
+
"assetOwnerId": config["userId"],
|
|
210
|
+
"systemAdministratorId": None,
|
|
211
|
+
"operatingSystem": "",
|
|
212
|
+
"osVersion": check_text(mapping.get_value(inventory, OS_NAME)),
|
|
213
|
+
"assetType": check_text(mapping.get_value(inventory, ASSET_TYPE) or "Unknown"),
|
|
214
|
+
"location": check_text(mapping.get_value(inventory, "Location")),
|
|
215
|
+
"cmmcAssetType": "",
|
|
216
|
+
"cpu": 0,
|
|
217
|
+
"ram": 0,
|
|
218
|
+
"diskStorage": 0,
|
|
219
|
+
"description": "",
|
|
220
|
+
"endOfLifeDate": date_str(mapping.get_value(inventory, "End-of-Life ", "", warnings=False)),
|
|
221
|
+
"purchaseDate": None,
|
|
222
|
+
"status": "Active (On Network)",
|
|
223
|
+
"wizId": "",
|
|
224
|
+
"wizInfo": "",
|
|
225
|
+
"notes": check_text(mapping.get_value(inventory, "Comments")),
|
|
226
|
+
"softwareVendor": check_text(mapping.get_value(inventory, SOFTWARE_VENDOR)),
|
|
227
|
+
"softwareVersion": check_text(mapping.get_value(inventory, SOFTWARE_NAME)),
|
|
228
|
+
"softwareFunction": check_text(mapping.get_value(inventory, FUNCTION)),
|
|
229
|
+
"patchLevel": check_text(mapping.get_value(inventory, PATCH_LEVEL)),
|
|
230
|
+
"assetCategory": asset_category,
|
|
231
|
+
"bVirtual": map_str_to_bool(mapping.get_value(inventory, "Virtual")),
|
|
232
|
+
"bPublicFacing": map_str_to_bool(mapping.get_value(inventory, "Public")),
|
|
233
|
+
"bAuthenticatedScan": map_str_to_bool(mapping.get_value(inventory, AUTHENTICATED_SCAN)),
|
|
234
|
+
"bLatestScan": map_str_to_bool(mapping.get_value(inventory, IN_LATEST_SCAN)),
|
|
235
|
+
"netBIOS": check_text(mapping.get_value(inventory, NETBIOS_NAME)),
|
|
236
|
+
"baselineConfiguration": check_text(mapping.get_value(inventory, BASELINE_CONFIGURATION_NAME)),
|
|
237
|
+
"fqdn": check_text(mapping.get_value(inventory, DNS_NAME)),
|
|
238
|
+
"assetTagNumber": "",
|
|
239
|
+
"vlanId": check_text(mapping.get_value(inventory, VLAN_NETWORK_ID)),
|
|
240
|
+
"facilityId": None,
|
|
241
|
+
"orgId": None,
|
|
242
|
+
"parentId": parent_id,
|
|
243
|
+
"parentModule": parent_module,
|
|
244
|
+
"createdById": config["userId"],
|
|
245
|
+
"dateCreated": datetime.now().strftime(fmt),
|
|
246
|
+
"lastUpdatedById": config["userId"],
|
|
247
|
+
"dateLastUpdated": datetime.now().strftime(fmt),
|
|
248
|
+
}
|
|
249
|
+
else:
|
|
250
|
+
return None
|
|
251
|
+
_update_ip_addresses(new_asset, inventory, mapping)
|
|
252
|
+
if asset_category == "Hardware":
|
|
253
|
+
new_asset["purpose"] = check_text(mapping.get_value(inventory, FUNCTION))
|
|
254
|
+
elif asset_category == "Software":
|
|
255
|
+
new_asset["softwareFunction"] = check_text(mapping.get_value(inventory, FUNCTION))
|
|
256
|
+
return Asset(**new_asset)
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def _update_ip_addresses(asset: dict, inventory: dict, mapping: "ImportValidater.mapping") -> None:
|
|
260
|
+
"""
|
|
261
|
+
Update the IPv4 and IPv6 address fields for the provided asset
|
|
262
|
+
|
|
263
|
+
:param dict asset: Asset to update
|
|
264
|
+
:param dict inventory: Inventory item to parse
|
|
265
|
+
:param ImportValidater.mapping mapping: Mapping object to use for mapping
|
|
266
|
+
:rtype: None
|
|
267
|
+
"""
|
|
268
|
+
if ip_address_data := check_text(mapping.get_value(inventory, IPV4_OR_IPV6_ADDRESS)):
|
|
269
|
+
v6_addresses = []
|
|
270
|
+
v4_addresses = []
|
|
271
|
+
for ip_address in [addr.strip() for addr in re.split(r"\s*[;,]\s*|\n", ip_address_data) if addr.strip()]:
|
|
272
|
+
if ipaddress_key := determine_ip_address_version(ip_address):
|
|
273
|
+
if ipaddress_key == "iPv6Address":
|
|
274
|
+
v6_addresses.append(ip_address)
|
|
275
|
+
else:
|
|
276
|
+
v4_addresses.append(ip_address)
|
|
277
|
+
asset["ipAddress"] = ", ".join(v4_addresses) if v4_addresses else None
|
|
278
|
+
asset["iPv6Address"] = ", ".join(v6_addresses) if v6_addresses else None
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def create_properties(data: dict, parent_id: int, parent_module: str, progress: rich.progress.Progress) -> bool:
|
|
282
|
+
"""
|
|
283
|
+
Create a list of properties and upload them to RegScale for the provided asset
|
|
284
|
+
:param dict data: Dictionary of data to parse and create properties from
|
|
285
|
+
:param int parent_id: ID to create properties for
|
|
286
|
+
:param str parent_module: Parent module to create properties for
|
|
287
|
+
:param rich.progress.Progress progress: Progress object used for batch creation
|
|
288
|
+
:return: If batch update was successful
|
|
289
|
+
:rtype: bool
|
|
290
|
+
"""
|
|
291
|
+
import numpy as np # Optimize import performance
|
|
292
|
+
|
|
293
|
+
properties: list = []
|
|
294
|
+
for key, value in data.items():
|
|
295
|
+
# skip the item if the key is id or contains unnamed
|
|
296
|
+
if "unnamed" in key.lower():
|
|
297
|
+
continue
|
|
298
|
+
# see if the value is datetime
|
|
299
|
+
elif isinstance(value, datetime):
|
|
300
|
+
value = value.strftime("%b %d, %Y")
|
|
301
|
+
# see if the value is a boolean
|
|
302
|
+
elif isinstance(value, np.bool_):
|
|
303
|
+
value = str(value).title()
|
|
304
|
+
regscale_property = Property(
|
|
305
|
+
createdById=config["userId"],
|
|
306
|
+
lastUpdatedById=config["userId"],
|
|
307
|
+
key=key,
|
|
308
|
+
value=value,
|
|
309
|
+
parentId=parent_id,
|
|
310
|
+
parentModule=parent_module,
|
|
311
|
+
)
|
|
312
|
+
properties.append(regscale_property)
|
|
313
|
+
new_props = Property.batch_create(properties, progress_context=progress, remove_progress=True)
|
|
314
|
+
create_logger().debug(f"Created {len(new_props)}/{len(properties)} properties for asset #{parent_id}")
|
|
315
|
+
return new_props is not None
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
def validate_columns(file_path: str, version: Literal["rev4", "rev5", "4", "5"], sheet_name: str) -> ImportValidater:
|
|
319
|
+
"""
|
|
320
|
+
Validate the columns in the inventory
|
|
321
|
+
|
|
322
|
+
:param str file_path: path to the inventory .xlsx file
|
|
323
|
+
:param Literal["rev4", "rev5", "4", "5"] version: FedRAMP version to import
|
|
324
|
+
:param str sheet_name: sheet name in the inventory .xlsx file to validate
|
|
325
|
+
:return: Import validator to facilitate header validation and custom mappings
|
|
326
|
+
:rtype: ImportValidater
|
|
327
|
+
"""
|
|
328
|
+
if "5" in version:
|
|
329
|
+
expected_cols = [
|
|
330
|
+
UNIQUE_ASSET_IDENTIFIER,
|
|
331
|
+
IPV4_OR_IPV6_ADDRESS,
|
|
332
|
+
"Virtual",
|
|
333
|
+
"Public",
|
|
334
|
+
DNS_NAME,
|
|
335
|
+
NETBIOS_NAME,
|
|
336
|
+
MAC_ADDRESS,
|
|
337
|
+
AUTHENTICATED_SCAN,
|
|
338
|
+
BASELINE_CONFIGURATION_NAME,
|
|
339
|
+
OS_NAME,
|
|
340
|
+
"Location",
|
|
341
|
+
ASSET_TYPE,
|
|
342
|
+
HARDWARE_MAKE,
|
|
343
|
+
IN_LATEST_SCAN,
|
|
344
|
+
SOFTWARE_VENDOR,
|
|
345
|
+
SOFTWARE_NAME,
|
|
346
|
+
PATCH_LEVEL,
|
|
347
|
+
"Diagram Label",
|
|
348
|
+
"Comments",
|
|
349
|
+
SERIAL_NUMBER,
|
|
350
|
+
VLAN_NETWORK_ID,
|
|
351
|
+
"System Administrator/ Owner",
|
|
352
|
+
"Application Administrator/ Owner",
|
|
353
|
+
FUNCTION,
|
|
354
|
+
]
|
|
355
|
+
mapping_dir = os.path.join("./", "mappings", "fedramp_inventory_rev5")
|
|
356
|
+
else:
|
|
357
|
+
expected_cols = [
|
|
358
|
+
UNIQUE_ASSET_IDENTIFIER,
|
|
359
|
+
IPV4_OR_IPV6_ADDRESS,
|
|
360
|
+
"Virtual",
|
|
361
|
+
"Public",
|
|
362
|
+
DNS_NAME,
|
|
363
|
+
NETBIOS_NAME,
|
|
364
|
+
MAC_ADDRESS,
|
|
365
|
+
AUTHENTICATED_SCAN,
|
|
366
|
+
BASELINE_CONFIGURATION_NAME,
|
|
367
|
+
OS_NAME,
|
|
368
|
+
"Location",
|
|
369
|
+
ASSET_TYPE,
|
|
370
|
+
HARDWARE_MAKE,
|
|
371
|
+
IN_LATEST_SCAN,
|
|
372
|
+
SOFTWARE_VENDOR,
|
|
373
|
+
SOFTWARE_NAME,
|
|
374
|
+
PATCH_LEVEL,
|
|
375
|
+
FUNCTION,
|
|
376
|
+
"Comments",
|
|
377
|
+
SERIAL_NUMBER,
|
|
378
|
+
VLAN_NETWORK_ID,
|
|
379
|
+
"System Administrator/ Owner",
|
|
380
|
+
"Application Administrator/ Owner",
|
|
381
|
+
]
|
|
382
|
+
mapping_dir = os.path.join("./", "mappings", "fedramp_inventory_rev4")
|
|
383
|
+
return ImportValidater(
|
|
384
|
+
required_headers=expected_cols,
|
|
385
|
+
file_path=file_path,
|
|
386
|
+
mapping_file_path=mapping_dir,
|
|
387
|
+
disable_mapping=False,
|
|
388
|
+
worksheet_name=sheet_name,
|
|
389
|
+
skip_rows=2,
|
|
390
|
+
)
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
def upload(
|
|
394
|
+
inventory: str,
|
|
395
|
+
record_id: int,
|
|
396
|
+
module: str,
|
|
397
|
+
version: Literal["rev4", "rev5", "4", "5"],
|
|
398
|
+
sheet_name: str = "Inventory",
|
|
399
|
+
) -> None:
|
|
400
|
+
"""
|
|
401
|
+
Main function to parse the inventory and load into RegScale
|
|
402
|
+
:param str inventory: path to the inventory .xlsx file
|
|
403
|
+
:param int record_id: RegScale Record ID to update
|
|
404
|
+
:param str module: RegScale Module for the provided ID
|
|
405
|
+
:param Literal["rev4", "rev5", "4", "5"] version: FedRAMP version to import
|
|
406
|
+
:param str sheet_name: sheet name in the inventory .xlsx file to parse, defaults to "Inventory"
|
|
407
|
+
:rtype: None
|
|
408
|
+
"""
|
|
409
|
+
from regscale.exceptions.validation_exception import ValidationException
|
|
410
|
+
|
|
411
|
+
logger = create_logger()
|
|
412
|
+
|
|
413
|
+
try:
|
|
414
|
+
import_validator = validate_columns(inventory, version, sheet_name)
|
|
415
|
+
df = import_validator.data
|
|
416
|
+
except FileNotFoundError:
|
|
417
|
+
logger.error(f"[red]File not found: {inventory}")
|
|
418
|
+
return
|
|
419
|
+
except (ValueError, ValidationException) as e:
|
|
420
|
+
logger.error(
|
|
421
|
+
"There is an issue with the file: %s, please check the file and try again. Error: %s. Skipping...",
|
|
422
|
+
inventory,
|
|
423
|
+
e,
|
|
424
|
+
)
|
|
425
|
+
return
|
|
426
|
+
|
|
427
|
+
# convert into dictionary
|
|
428
|
+
inventory_json = df.to_json(orient="records")
|
|
429
|
+
inventory_list = df.to_dict(orient="records")
|
|
430
|
+
|
|
431
|
+
# save locally
|
|
432
|
+
save_to_json("inventory.json", inventory_json)
|
|
433
|
+
logger.info(f"[yellow]{len(inventory_list)} total inventory item(s) saved to inventory.json")
|
|
434
|
+
|
|
435
|
+
# process the inventory
|
|
436
|
+
inventory: Dict[int, Dict[str, Asset]] = {}
|
|
437
|
+
existing_assets = Asset.get_all_by_parent(parent_id=record_id, parent_module=module)
|
|
438
|
+
already_inserted: List[Asset] = []
|
|
439
|
+
job_progress = create_progress_object()
|
|
440
|
+
with job_progress as progress:
|
|
441
|
+
process_task = progress.add_task("Processing inventory...", total=len(inventory_list))
|
|
442
|
+
for inv in range(len(inventory_list)):
|
|
443
|
+
asset = map_inventory_to_asset(inventory_list[inv], record_id, module, import_validator.mapping)
|
|
444
|
+
if not asset:
|
|
445
|
+
progress.update(process_task, advance=1)
|
|
446
|
+
logger.warning(
|
|
447
|
+
f"[yellow]Skipping {inventory_list[inv]}, unable to determine Asset name from"
|
|
448
|
+
f" {UNIQUE_ASSET_IDENTIFIER} and {DNS_NAME}."
|
|
449
|
+
)
|
|
450
|
+
continue
|
|
451
|
+
if asset not in existing_assets:
|
|
452
|
+
inventory[inv] = {}
|
|
453
|
+
inventory[inv]["asset"] = asset
|
|
454
|
+
inventory[inv]["raw_data"] = inventory_list[inv] # noqa
|
|
455
|
+
else:
|
|
456
|
+
already_inserted.append(asset)
|
|
457
|
+
progress.update(process_task, advance=1)
|
|
458
|
+
# reindex dict
|
|
459
|
+
reindexed_dict = {new_index: inventory[old_index] for new_index, old_index in enumerate(inventory)}
|
|
460
|
+
# print new objectives
|
|
461
|
+
save_to_json("regscale-inventory", reindexed_dict)
|
|
462
|
+
|
|
463
|
+
if not reindexed_dict:
|
|
464
|
+
logger.warning("[yellow]No new inventory items to load, exiting...")
|
|
465
|
+
return
|
|
466
|
+
logger.info(
|
|
467
|
+
f"[yellow]{len(reindexed_dict)} total inventory item(s) ready to load ({len(already_inserted)} "
|
|
468
|
+
f"already exist(s)) Saved to regscale-inventory.json"
|
|
469
|
+
)
|
|
470
|
+
# loop through each asset in the inventory list
|
|
471
|
+
processed = []
|
|
472
|
+
failed = []
|
|
473
|
+
with job_progress as progress:
|
|
474
|
+
loading_task = progress.add_task("Loading inventory into RegScale...", total=len(reindexed_dict))
|
|
475
|
+
for inv in reindexed_dict.values():
|
|
476
|
+
try:
|
|
477
|
+
res_data = inv["asset"].create() # noqa
|
|
478
|
+
processed.append(res_data)
|
|
479
|
+
if not create_properties(inv["raw_data"], res_data["id"], "assets", progress): # noqa
|
|
480
|
+
logger.error(
|
|
481
|
+
f"[red]Failed to create properties for asset #{res_data['id']}: {inv['asset']['name']}" # noqa
|
|
482
|
+
)
|
|
483
|
+
except JSONDecodeError:
|
|
484
|
+
failed.append(inv)
|
|
485
|
+
continue
|
|
486
|
+
progress.update(loading_task, advance=1)
|
|
487
|
+
|
|
488
|
+
if failed:
|
|
489
|
+
save_to_json("failed-inventory", failed)
|
|
490
|
+
logger.error(f"[red]{len(failed)} total inventory item(s) failed to load. Saved to failed-inventory.json")
|
|
491
|
+
# print new objectives
|
|
492
|
+
save_to_json("processed-inventory", processed)
|
|
493
|
+
logger.info(
|
|
494
|
+
f"[yellow]{len(processed)} total RegScale inventory successfully uploaded. Saved to processed-inventory.json"
|
|
495
|
+
)
|