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,231 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Module for processing Trivy scan results and loading them into RegScale as assets, issues, and vulnerabilities.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
import traceback
|
|
7
|
+
from typing import Any, Dict, Iterator, List, Optional
|
|
8
|
+
|
|
9
|
+
from regscale.core.app.utils.parser_utils import safe_datetime_str
|
|
10
|
+
from regscale.exceptions import ValidationException
|
|
11
|
+
from regscale.integrations.scanner_integration import IntegrationAsset, IntegrationFinding
|
|
12
|
+
from regscale.models import ImportValidater
|
|
13
|
+
from regscale.models.integration_models.flat_file_importer import FlatFileImporter
|
|
14
|
+
from regscale.models.regscale_models import AssetStatus, IssueSeverity, IssueStatus
|
|
15
|
+
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class TrivyImport(FlatFileImporter):
|
|
20
|
+
"""Class for handling Trivy scanner integration."""
|
|
21
|
+
|
|
22
|
+
asset_identifier_field = "otherTrackingNumber"
|
|
23
|
+
finding_severity_map = {
|
|
24
|
+
"CRITICAL": IssueSeverity.Critical.value,
|
|
25
|
+
"HIGH": IssueSeverity.High.value,
|
|
26
|
+
"MEDIUM": IssueSeverity.Moderate.value,
|
|
27
|
+
"LOW": IssueSeverity.Low.value,
|
|
28
|
+
"UNKNOWN": IssueSeverity.High.value,
|
|
29
|
+
"NEGLIGIBLE": IssueSeverity.High.value,
|
|
30
|
+
}
|
|
31
|
+
identifier: Optional[str] = None
|
|
32
|
+
|
|
33
|
+
def __init__(self, **kwargs: Any):
|
|
34
|
+
self.name = kwargs.get("name", "Trivy")
|
|
35
|
+
self.identifier = None
|
|
36
|
+
self.required_headers = [
|
|
37
|
+
"Metadata",
|
|
38
|
+
]
|
|
39
|
+
self.mapping_file = kwargs.get("mappings_path")
|
|
40
|
+
self.disable_mapping = kwargs.get("disable_mapping")
|
|
41
|
+
self.validater = ImportValidater(
|
|
42
|
+
self.required_headers,
|
|
43
|
+
kwargs.get("file_path"),
|
|
44
|
+
self.mapping_file,
|
|
45
|
+
self.disable_mapping,
|
|
46
|
+
)
|
|
47
|
+
self.headers = self.validater.parsed_headers
|
|
48
|
+
self.mapping = self.validater.mapping
|
|
49
|
+
if kwargs.get("scan_date"):
|
|
50
|
+
self.scan_date = kwargs.pop("scan_date")
|
|
51
|
+
else:
|
|
52
|
+
self.scan_date = safe_datetime_str(self.validater.data.get("CreatedAt"))
|
|
53
|
+
# even if a user doesn't specify a scan_date, we want to remove it from the kwargs and use the scan_date from
|
|
54
|
+
# the attributes after the scan_date is set in the previous logic
|
|
55
|
+
if "scan_date" in kwargs:
|
|
56
|
+
kwargs.pop("scan_date")
|
|
57
|
+
if "sha256-" in kwargs["file_name"]:
|
|
58
|
+
logger.debug("found sha256 in file name %s", kwargs["file_name"])
|
|
59
|
+
self.identifier = "sha256-" + kwargs["file_name"].split("sha256-")[1].split(".json")[0]
|
|
60
|
+
else:
|
|
61
|
+
logger.debug("using imageID for identifier")
|
|
62
|
+
self.identifier = self.mapping.get_value(self.validater.data, "Metadata", {}).get("ImageID")
|
|
63
|
+
logger.debug("self.identifier: %s", self.identifier)
|
|
64
|
+
self.integration_name = self.identifier
|
|
65
|
+
self.other_tracking_number = self.mapping.get_value(self.validater.data, "ArtifactName", self.identifier)
|
|
66
|
+
self.notes = f"{kwargs['file_name']}"
|
|
67
|
+
vuln_count = 0
|
|
68
|
+
for item in self.mapping.get_value(self.validater.data, "Results", []):
|
|
69
|
+
vuln_count += len(item.get("Vulnerabilities", []))
|
|
70
|
+
super().__init__(
|
|
71
|
+
logger=logger,
|
|
72
|
+
headers=self.headers,
|
|
73
|
+
extra_headers_allowed=True,
|
|
74
|
+
finding_severity_map=self.finding_severity_map,
|
|
75
|
+
vuln_func=self.create_vuln,
|
|
76
|
+
asset_func=self.create_asset,
|
|
77
|
+
scan_date=self.scan_date,
|
|
78
|
+
asset_identifier_field=self.asset_identifier_field,
|
|
79
|
+
vuln_count=vuln_count,
|
|
80
|
+
asset_count=1,
|
|
81
|
+
**kwargs,
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
def parse_asset(self, **kwargs) -> IntegrationAsset:
|
|
85
|
+
"""
|
|
86
|
+
Parse assets from Trivy scan data.
|
|
87
|
+
|
|
88
|
+
:return: Integration asset
|
|
89
|
+
:rtype: IntegrationAsset
|
|
90
|
+
"""
|
|
91
|
+
os_data = kwargs.pop("os_data")
|
|
92
|
+
return IntegrationAsset(
|
|
93
|
+
identifier=self.identifier,
|
|
94
|
+
name=self.integration_name,
|
|
95
|
+
ip_address="0.0.0.0",
|
|
96
|
+
cpu=0,
|
|
97
|
+
ram=0,
|
|
98
|
+
status=AssetStatus.Active.value,
|
|
99
|
+
asset_type="Other",
|
|
100
|
+
asset_category="Software",
|
|
101
|
+
operating_system=f"{os_data.get('Family', '')} {os_data.get('Name', '')}",
|
|
102
|
+
notes=self.notes,
|
|
103
|
+
other_tracking_number=self.other_tracking_number,
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
def create_asset(self, *args, **kwargs) -> Iterator[IntegrationAsset]:
|
|
107
|
+
"""
|
|
108
|
+
Fetches assets from the processed json files
|
|
109
|
+
|
|
110
|
+
:yields: Iterator[IntegrationAsset]
|
|
111
|
+
"""
|
|
112
|
+
if assets := self.fetch_assets(**kwargs):
|
|
113
|
+
for asset in assets:
|
|
114
|
+
yield asset
|
|
115
|
+
|
|
116
|
+
def create_vuln(self, *args, **kwargs) -> Iterator[IntegrationFinding]:
|
|
117
|
+
"""
|
|
118
|
+
Fetches findings from the processed json files
|
|
119
|
+
|
|
120
|
+
:return: A list of findings
|
|
121
|
+
:rtype: List[IntegrationFinding]
|
|
122
|
+
"""
|
|
123
|
+
if findings := self.fetch_findings(**kwargs):
|
|
124
|
+
for finding in findings:
|
|
125
|
+
yield finding
|
|
126
|
+
|
|
127
|
+
def fetch_findings(self, **_) -> List[IntegrationFinding]:
|
|
128
|
+
"""
|
|
129
|
+
Fetch findings from Trivy scan data.
|
|
130
|
+
|
|
131
|
+
:raises ValidationException: If there is an error fetching/parsing findings
|
|
132
|
+
:return: List of IntegrationFinding
|
|
133
|
+
:rtype: List[IntegrationFinding]
|
|
134
|
+
"""
|
|
135
|
+
|
|
136
|
+
findings = []
|
|
137
|
+
try:
|
|
138
|
+
for item in self.mapping.get_value(self.validater.data, "Results", []):
|
|
139
|
+
for finding in item.get("Vulnerabilities", []):
|
|
140
|
+
findings.append(
|
|
141
|
+
IntegrationFinding(
|
|
142
|
+
title=finding.get("Title", finding.get("PkgName")),
|
|
143
|
+
description=finding.get("Description", "No description available"),
|
|
144
|
+
severity=(
|
|
145
|
+
self.process_severity(finding.get("Severity"))
|
|
146
|
+
if finding.get("Severity")
|
|
147
|
+
else IssueSeverity.NotAssigned.value
|
|
148
|
+
),
|
|
149
|
+
status=IssueStatus.Open.value,
|
|
150
|
+
cvss_v3_score=self.get_cvss_score(finding),
|
|
151
|
+
cvss_v3_base_score=self.get_cvss_score(finding),
|
|
152
|
+
plugin_name=finding.get("DataSource", {}).get("Name", self.name),
|
|
153
|
+
plugin_id=finding.get("DataSource", {}).get("ID", self.name),
|
|
154
|
+
asset_identifier=self.identifier,
|
|
155
|
+
cve=finding.get("VulnerabilityID"),
|
|
156
|
+
first_seen=self.scan_date,
|
|
157
|
+
last_seen=self.scan_date,
|
|
158
|
+
scan_date=self.scan_date,
|
|
159
|
+
category="Software",
|
|
160
|
+
control_labels=[],
|
|
161
|
+
)
|
|
162
|
+
)
|
|
163
|
+
return findings
|
|
164
|
+
except Exception:
|
|
165
|
+
error_message = traceback.format_exc()
|
|
166
|
+
logger.error(f"Error fetching findings: {error_message}")
|
|
167
|
+
raise ValidationException(f"Error fetching findings: {error_message}")
|
|
168
|
+
|
|
169
|
+
def process_severity(self, severity: str) -> str:
|
|
170
|
+
"""
|
|
171
|
+
Process the severity of a finding.
|
|
172
|
+
|
|
173
|
+
:param str severity: The severity of the finding
|
|
174
|
+
:return: IssueSeverity corresponding to the severity
|
|
175
|
+
:rtype: str
|
|
176
|
+
"""
|
|
177
|
+
from regscale.core.app.application import Application
|
|
178
|
+
|
|
179
|
+
app = Application()
|
|
180
|
+
severity_default = app.config.get("vulnerabilityMappingDefault", IssueSeverity.NotAssigned.value)
|
|
181
|
+
return self.finding_severity_map.get(severity.upper(), severity_default)
|
|
182
|
+
|
|
183
|
+
@staticmethod
|
|
184
|
+
def process_status(status: str) -> str:
|
|
185
|
+
"""
|
|
186
|
+
Process the status of a finding.
|
|
187
|
+
|
|
188
|
+
:param str status: The status of the finding
|
|
189
|
+
:return: The corresponding Issue status
|
|
190
|
+
:rtype: str
|
|
191
|
+
"""
|
|
192
|
+
if status.lower() == "fixed":
|
|
193
|
+
return IssueStatus.Closed.value
|
|
194
|
+
else:
|
|
195
|
+
return IssueStatus.Open.value
|
|
196
|
+
|
|
197
|
+
@staticmethod
|
|
198
|
+
def get_cvss_score(finding: Dict) -> float:
|
|
199
|
+
"""
|
|
200
|
+
Get the CVSS score from the finding data.
|
|
201
|
+
|
|
202
|
+
:param dict finding: The finding data
|
|
203
|
+
:return: The CVSS score
|
|
204
|
+
:rtype: float
|
|
205
|
+
"""
|
|
206
|
+
value = 0.0
|
|
207
|
+
if cvs := finding.get("CVSS"):
|
|
208
|
+
if nvd := cvs.get("nvd"):
|
|
209
|
+
value = nvd.get("V3Score", 0.0)
|
|
210
|
+
elif redhat := cvs.get("redhat"):
|
|
211
|
+
value = redhat.get("V3Score", 0.0)
|
|
212
|
+
return value
|
|
213
|
+
|
|
214
|
+
def fetch_assets(self, **_) -> List[IntegrationAsset]:
|
|
215
|
+
"""
|
|
216
|
+
Fetch assets from Trivy scan data.
|
|
217
|
+
|
|
218
|
+
:raises ValidationException: If there is an error fetching/parsing assets
|
|
219
|
+
:return: List of IntegrationAsset
|
|
220
|
+
:rtype: List[IntegrationAsset]
|
|
221
|
+
"""
|
|
222
|
+
data = self.validater.data
|
|
223
|
+
assets: List[IntegrationAsset] = []
|
|
224
|
+
os_data = self.mapping.get_value(data, "Metadata", {}, warnings=False).get("OS", {})
|
|
225
|
+
try:
|
|
226
|
+
assets.append(self.parse_asset(asset=data, os_data=os_data))
|
|
227
|
+
return assets
|
|
228
|
+
except Exception:
|
|
229
|
+
error_message = traceback.format_exc()
|
|
230
|
+
logger.error(f"Error fetching assets: {error_message}")
|
|
231
|
+
raise ValidationException(f"Error fetching assets: {error_message}")
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
from typing import List, Optional
|
|
2
|
+
|
|
3
|
+
from regscale.core.app.logz import create_logger
|
|
4
|
+
from regscale.core.app.utils.app_utils import get_current_datetime
|
|
5
|
+
from regscale.models import Asset, Vulnerability, Mapping, ImportValidater
|
|
6
|
+
from regscale.models.integration_models.flat_file_importer import FlatFileImporter
|
|
7
|
+
|
|
8
|
+
APP_NAME = "@app_name"
|
|
9
|
+
VERSION = "@version"
|
|
10
|
+
ACCOUNT_ID = "@account_id"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Veracode(FlatFileImporter):
|
|
14
|
+
def __init__(self, **kwargs):
|
|
15
|
+
self.name = kwargs.get("name", "Veracode")
|
|
16
|
+
logger = create_logger()
|
|
17
|
+
self.vuln_title = "PROBLEM_TITLE"
|
|
18
|
+
self.fmt = "%Y-%m-%d"
|
|
19
|
+
self.dt_format = "%Y-%m-%d %H:%M:%S"
|
|
20
|
+
csv_headers = [
|
|
21
|
+
"Source",
|
|
22
|
+
]
|
|
23
|
+
xml_headers = [
|
|
24
|
+
"app_name",
|
|
25
|
+
]
|
|
26
|
+
self.mapping_file = kwargs.get("mappings_path")
|
|
27
|
+
self.disable_mapping = kwargs.get("disable_mapping")
|
|
28
|
+
file_type = kwargs.get("file_type")
|
|
29
|
+
if file_type == ".xml":
|
|
30
|
+
self.required_headers = xml_headers
|
|
31
|
+
xml_tag = "detailedreport"
|
|
32
|
+
else:
|
|
33
|
+
self.required_headers = csv_headers
|
|
34
|
+
xml_tag = None
|
|
35
|
+
self.validater = ImportValidater(
|
|
36
|
+
self.required_headers, kwargs.get("file_path"), self.mapping_file, self.disable_mapping, xml_tag=xml_tag
|
|
37
|
+
)
|
|
38
|
+
self.headers = self.validater.parsed_headers
|
|
39
|
+
self.mapping = self.validater.mapping
|
|
40
|
+
super().__init__(
|
|
41
|
+
logger=logger,
|
|
42
|
+
headers=self.headers,
|
|
43
|
+
asset_func=self.create_asset,
|
|
44
|
+
vuln_func=self.create_vuln,
|
|
45
|
+
extra_headers_allowed=False,
|
|
46
|
+
**kwargs,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
def create_asset(self, dat: Optional[dict] = None) -> List[Asset]:
|
|
50
|
+
"""
|
|
51
|
+
Create a RegScale asset from an asset in the Veracode export file
|
|
52
|
+
|
|
53
|
+
:param Optional[dict] dat: The data from the Veracode export file
|
|
54
|
+
:return: List of RegScale Asset objects
|
|
55
|
+
:rtype: List[Asset]
|
|
56
|
+
"""
|
|
57
|
+
version = None
|
|
58
|
+
# Veracode is a Web Application Security Scanner, so these will be software assets, scanning a
|
|
59
|
+
# single web application
|
|
60
|
+
if "detailedreport" in self.mapping.mapping.keys():
|
|
61
|
+
name = self.mapping.get_value(dat, "detailedreport", {}).get(APP_NAME, "")
|
|
62
|
+
account_id = self.mapping.get_value(dat, "detailedreport", {}).get(ACCOUNT_ID, "")
|
|
63
|
+
version = self.mapping.get_value(dat, "detailedreport", {}).get(VERSION, "")
|
|
64
|
+
else:
|
|
65
|
+
name = self.mapping.get_value(dat, "Source", "")
|
|
66
|
+
account_id = str(self.mapping.get_value(dat, "ID", ""))
|
|
67
|
+
asset = Asset(
|
|
68
|
+
**{
|
|
69
|
+
"id": 0,
|
|
70
|
+
"name": name,
|
|
71
|
+
"otherTrackingNumber": account_id,
|
|
72
|
+
"ipAddress": "0.0.0.0",
|
|
73
|
+
"isPublic": True,
|
|
74
|
+
"status": "Active (On Network)",
|
|
75
|
+
"assetCategory": "Software",
|
|
76
|
+
"bLatestScan": True,
|
|
77
|
+
"bAuthenticatedScan": True,
|
|
78
|
+
"scanningTool": self.name,
|
|
79
|
+
"assetOwnerId": self.config["userId"],
|
|
80
|
+
"assetType": "Other",
|
|
81
|
+
"softwareVendor": "Veracode",
|
|
82
|
+
"softwareName": name,
|
|
83
|
+
"softwareVersion": version,
|
|
84
|
+
"systemAdministratorId": self.config["userId"],
|
|
85
|
+
"parentId": self.attributes.parent_id,
|
|
86
|
+
"parentModule": self.attributes.parent_module,
|
|
87
|
+
}
|
|
88
|
+
)
|
|
89
|
+
return [asset]
|
|
90
|
+
|
|
91
|
+
def create_vuln(self, dat: Optional[dict] = None, **kwargs) -> List[Vulnerability]:
|
|
92
|
+
"""
|
|
93
|
+
Create a RegScale vulnerability from a vulnerability in the Veracode export file
|
|
94
|
+
|
|
95
|
+
:param Optional[dict] dat: The data from the Veracode export file
|
|
96
|
+
:return: List of RegScale Vulnerability objects
|
|
97
|
+
:rtype: List[Vulnerability]
|
|
98
|
+
"""
|
|
99
|
+
import_type = "xml" if isinstance(dat, str) else "csv"
|
|
100
|
+
# Veracode is a Web Application Security Scanner, so these will be software assets,
|
|
101
|
+
# scanning a single web application
|
|
102
|
+
if import_type == "xml":
|
|
103
|
+
name = self.mapping.get_value(dat, "detailedreport", {}).get(APP_NAME, "")
|
|
104
|
+
all_sev_data = self.mapping.get_value(dat, "detailedreport", {}).get("severity", [])
|
|
105
|
+
severity = self.severity_info(all_sev_data)[0] if all_sev_data else "low"
|
|
106
|
+
if severity_data := self.severity_info(all_sev_data):
|
|
107
|
+
if isinstance(severity_data, list) and len(severity_data) >= 2:
|
|
108
|
+
cwes = [
|
|
109
|
+
f"{c.get('cweid')} {c.get('cwename')}" for c in severity_data[1].get("cwe", [])
|
|
110
|
+
] # Multiple cwes per asset in official XML
|
|
111
|
+
else:
|
|
112
|
+
cwes = []
|
|
113
|
+
else:
|
|
114
|
+
name = self.mapping.get_value(dat, "Source", "")
|
|
115
|
+
severity = self.mapping.get_value(dat, "Sev", "").lower()
|
|
116
|
+
cwes = [self.mapping.get_value(dat, "CWE ID & Name", [])] # Coalfire should flatten data for asset -> cwes
|
|
117
|
+
|
|
118
|
+
return self.process_csv_vulns(name, cwes, severity)
|
|
119
|
+
|
|
120
|
+
def process_csv_vulns(self, hostname: str, cwes: List[str], severity: str) -> List[Vulnerability]:
|
|
121
|
+
"""
|
|
122
|
+
Process the CSV findings from the ECR scan
|
|
123
|
+
|
|
124
|
+
:param str hostname: The hostname
|
|
125
|
+
:param List[str] cwes: The CWEs
|
|
126
|
+
:param str severity: The severity
|
|
127
|
+
:return: A list of vulnerabilities
|
|
128
|
+
:rtype: List[Vulnerability]
|
|
129
|
+
"""
|
|
130
|
+
vulns = []
|
|
131
|
+
for cwe in cwes:
|
|
132
|
+
severity = self.determine_severity(severity)
|
|
133
|
+
if asset := self.get_asset(hostname):
|
|
134
|
+
vuln = self.create_vulnerability_object(asset, hostname, cwe, severity, "")
|
|
135
|
+
vulns.append(vuln)
|
|
136
|
+
return vulns
|
|
137
|
+
|
|
138
|
+
def create_vulnerability_object(
|
|
139
|
+
self, asset: Asset, hostname: str, cwe: str, severity: str, description: str
|
|
140
|
+
) -> Vulnerability:
|
|
141
|
+
"""
|
|
142
|
+
Create a vulnerability from a row in the Veracode file
|
|
143
|
+
|
|
144
|
+
:param Asset asset: The asset
|
|
145
|
+
:param str hostname: The hostname
|
|
146
|
+
:param str cwe: The CWE
|
|
147
|
+
:param str severity: The severity
|
|
148
|
+
:param str description: The description
|
|
149
|
+
:return: The vulnerability
|
|
150
|
+
:rtype: Vulnerability
|
|
151
|
+
"""
|
|
152
|
+
config = self.attributes.app.config
|
|
153
|
+
|
|
154
|
+
return Vulnerability( # type: ignore
|
|
155
|
+
id=0,
|
|
156
|
+
scanId=0,
|
|
157
|
+
parentId=asset.id,
|
|
158
|
+
parentModule="assets",
|
|
159
|
+
ipAddress="0.0.0.0",
|
|
160
|
+
lastSeen=get_current_datetime(), # No timestamp on Veracode
|
|
161
|
+
firstSeen=get_current_datetime(), # No timestamp on Veracode
|
|
162
|
+
daysOpen=None,
|
|
163
|
+
dns=hostname,
|
|
164
|
+
mitigated=None,
|
|
165
|
+
operatingSystem=asset.operatingSystem,
|
|
166
|
+
severity=severity,
|
|
167
|
+
plugInName=cwe,
|
|
168
|
+
cve="",
|
|
169
|
+
tenantsId=0,
|
|
170
|
+
title=f"{cwe} on asset {asset.name}",
|
|
171
|
+
description=cwe,
|
|
172
|
+
plugInText=description,
|
|
173
|
+
createdById=config["userId"],
|
|
174
|
+
lastUpdatedById=config["userId"],
|
|
175
|
+
dateCreated=get_current_datetime(),
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
def get_asset(self, hostname: str) -> Optional[Asset]:
|
|
179
|
+
"""
|
|
180
|
+
Get the asset from the hostname
|
|
181
|
+
|
|
182
|
+
:param str hostname: The hostname
|
|
183
|
+
:return: The asset, if found
|
|
184
|
+
:rtype: Optional[Asset]
|
|
185
|
+
"""
|
|
186
|
+
asset_match = [asset for asset in self.data["assets"] if asset.name == hostname]
|
|
187
|
+
return asset_match[0] if asset_match else None
|
|
188
|
+
|
|
189
|
+
def severity_info(self, severity_list: list) -> Optional[tuple]:
|
|
190
|
+
"""
|
|
191
|
+
Get the severity level and category of the vulnerability
|
|
192
|
+
|
|
193
|
+
:param list severity_list: List of severity levels
|
|
194
|
+
:return: Severity level and category
|
|
195
|
+
:rtype: Optional[tuple]
|
|
196
|
+
"""
|
|
197
|
+
hit = [sev for sev in severity_list if sev.get("category")]
|
|
198
|
+
if hit:
|
|
199
|
+
return (self.hit_mapping().get(hit[0].get("level"), "low"), hit[0].get("category"))
|
|
200
|
+
return None
|
|
201
|
+
|
|
202
|
+
@staticmethod
|
|
203
|
+
def hit_mapping() -> dict:
|
|
204
|
+
"""
|
|
205
|
+
Mapping of severity levels
|
|
206
|
+
|
|
207
|
+
:return: Mapping of severity levels
|
|
208
|
+
:rtype: dict
|
|
209
|
+
"""
|
|
210
|
+
return {
|
|
211
|
+
"5": "critical",
|
|
212
|
+
"4": "high",
|
|
213
|
+
"3": "moderate",
|
|
214
|
+
"2": "low",
|
|
215
|
+
"1": "low",
|
|
216
|
+
"0": "info",
|
|
217
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Nexpose Scan information
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import List, Optional
|
|
6
|
+
|
|
7
|
+
from regscale.core.app.application import Application
|
|
8
|
+
from regscale.core.app.logz import create_logger
|
|
9
|
+
from regscale.core.app.utils.app_utils import epoch_to_datetime, get_current_datetime
|
|
10
|
+
from regscale.models import ImportValidater, Mapping
|
|
11
|
+
from regscale.models.integration_models.flat_file_importer import FlatFileImporter
|
|
12
|
+
from regscale.models.regscale_models.asset import Asset
|
|
13
|
+
from regscale.models.regscale_models.vulnerability import Vulnerability
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class XRay(FlatFileImporter):
|
|
17
|
+
"""JFrog Xray Scan information
|
|
18
|
+
|
|
19
|
+
:param str name: Name of the scan
|
|
20
|
+
:param Application app: RegScale Application object
|
|
21
|
+
:param str file_path: Path to the JSON files
|
|
22
|
+
:param int regscale_ssp_id: RegScale System Security Plan ID
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(self, **kwargs):
|
|
26
|
+
self.name = kwargs.get("name")
|
|
27
|
+
regscale_ssp_id = kwargs.get("regscale_ssp_id")
|
|
28
|
+
self.cvss3_score = "cvss_v3_score"
|
|
29
|
+
self.vuln_title = "cve"
|
|
30
|
+
self.required_headers = [
|
|
31
|
+
"impacted_artifact",
|
|
32
|
+
]
|
|
33
|
+
self.mapping_file = kwargs.get("mappings_path")
|
|
34
|
+
self.disable_mapping = kwargs.get("disable_mapping")
|
|
35
|
+
self.validater = ImportValidater(
|
|
36
|
+
self.required_headers, kwargs.get("file_path"), self.mapping_file, self.disable_mapping
|
|
37
|
+
)
|
|
38
|
+
self.headers = self.validater.parsed_headers
|
|
39
|
+
self.mapping = self.validater.mapping
|
|
40
|
+
logger = create_logger()
|
|
41
|
+
super().__init__(
|
|
42
|
+
logger=logger,
|
|
43
|
+
app=Application(),
|
|
44
|
+
headers=None,
|
|
45
|
+
parent_id=regscale_ssp_id,
|
|
46
|
+
parent_module="securityplans",
|
|
47
|
+
asset_func=self.create_asset,
|
|
48
|
+
vuln_func=self.create_vuln,
|
|
49
|
+
**kwargs,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
def create_asset(self, dat: Optional[dict] = None) -> Optional[Asset]:
|
|
53
|
+
"""
|
|
54
|
+
Create an asset from a row in the Xray JSON file
|
|
55
|
+
|
|
56
|
+
:param Optional[dict] dat: Data row from JSON file, defaults to None
|
|
57
|
+
:return: RegScale Asset object
|
|
58
|
+
:rtype: Optional[Asset]
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
if asset_name := self.mapping.get_value(dat, "impacted_artifact") if isinstance(dat, dict) else dat:
|
|
62
|
+
return Asset(
|
|
63
|
+
**{
|
|
64
|
+
"id": 0,
|
|
65
|
+
"name": asset_name,
|
|
66
|
+
"ipAddress": "0.0.0.0",
|
|
67
|
+
"isPublic": True,
|
|
68
|
+
"status": "Active (On Network)",
|
|
69
|
+
"assetCategory": "Software",
|
|
70
|
+
"bLatestScan": True,
|
|
71
|
+
"bAuthenticatedScan": True,
|
|
72
|
+
"scanningTool": self.name,
|
|
73
|
+
"assetOwnerId": self.config["userId"],
|
|
74
|
+
"assetType": "Other",
|
|
75
|
+
"fqdn": None,
|
|
76
|
+
"operatingSystem": "Linux",
|
|
77
|
+
"systemAdministratorId": self.config["userId"],
|
|
78
|
+
"parentId": self.attributes.parent_id,
|
|
79
|
+
"parentModule": self.attributes.parent_module,
|
|
80
|
+
}
|
|
81
|
+
)
|
|
82
|
+
return None
|
|
83
|
+
|
|
84
|
+
def create_vuln(self, dat: Optional[dict] = None, **kwargs) -> List[Vulnerability]:
|
|
85
|
+
"""
|
|
86
|
+
Create a vulnerability from a row in the JFrog Xray JSON file
|
|
87
|
+
|
|
88
|
+
:param Optional[dict] dat: Data row from JSON file, defaults to None
|
|
89
|
+
:return: List of RegScale Vulnerability object, if any
|
|
90
|
+
:rtype: List[Vulnerability]
|
|
91
|
+
"""
|
|
92
|
+
asset_match = [
|
|
93
|
+
asset for asset in self.data["assets"] if asset.name == self.mapping.get_value(dat, "impacted_artifact")
|
|
94
|
+
]
|
|
95
|
+
asset = asset_match[0] if asset_match else None
|
|
96
|
+
vulns = []
|
|
97
|
+
for vuln in self.mapping.get_value(dat, "cves", []):
|
|
98
|
+
# CVE IS A VULN, A VULN IS A CVE, Finkle is Einhorn
|
|
99
|
+
regscale_vuln = None
|
|
100
|
+
severity = (
|
|
101
|
+
Vulnerability.determine_cvss3_severity_text(float(vuln[self.cvss3_score]))
|
|
102
|
+
if vuln.get(self.cvss3_score)
|
|
103
|
+
else "low"
|
|
104
|
+
)
|
|
105
|
+
if asset_match:
|
|
106
|
+
cves = [c["cve"] for c in self.mapping.get_value(dat, "cves", []) if c.get("cve")]
|
|
107
|
+
for cve in cves:
|
|
108
|
+
regscale_vuln = Vulnerability(
|
|
109
|
+
id=0,
|
|
110
|
+
scanId=0, # set later
|
|
111
|
+
parentId=asset.id,
|
|
112
|
+
parentModule="assets",
|
|
113
|
+
ipAddress="0.0.0.0", # No ip address available
|
|
114
|
+
lastSeen=self.scan_date,
|
|
115
|
+
firstSeen=epoch_to_datetime(self.create_epoch),
|
|
116
|
+
daysOpen=None,
|
|
117
|
+
dns=self.mapping.get_value(dat, "impacted_artifact"),
|
|
118
|
+
mitigated=None,
|
|
119
|
+
operatingSystem="Linux",
|
|
120
|
+
severity=severity,
|
|
121
|
+
plugInName=self.mapping.get_value(dat, "issue_id", "XRay"),
|
|
122
|
+
plugInId=int(self.mapping.get_value(dat, "issue_id", "Xray-0000")[5:]),
|
|
123
|
+
cve=cve,
|
|
124
|
+
vprScore=None,
|
|
125
|
+
tenantsId=0, # Need a way to figure this out programmatically
|
|
126
|
+
title=f"{self.mapping.get_value(dat, 'issue_id', warnings=False) or self.mapping.get_value(dat, 'summary', f'XRay Vulnerability from Import {get_current_datetime()}', warnings=False)} on asset {asset.name}",
|
|
127
|
+
description=self.mapping.get_value(dat, "summary"),
|
|
128
|
+
plugInText=vuln.get("cve"),
|
|
129
|
+
extra_data={
|
|
130
|
+
"references": self.mapping.get_value(dat, "references", "None"),
|
|
131
|
+
"solution": self.mapping.get_value(dat, "fixed_versions", "None"),
|
|
132
|
+
},
|
|
133
|
+
)
|
|
134
|
+
vulns.append(regscale_vuln)
|
|
135
|
+
return vulns
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"""Class to lock a file to prevent concurrent access to it."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import time
|
|
5
|
+
from types import TracebackType
|
|
6
|
+
from typing import Optional, Type
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class FileLock:
|
|
10
|
+
"""
|
|
11
|
+
Class to lock a file to prevent concurrent access to it
|
|
12
|
+
|
|
13
|
+
:param str lock_file: File to lock, defaults to "results/xdist_lock.txt"
|
|
14
|
+
:param bool skip_lock: Whether to skip the lock, defaults to False
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
lock_file: str
|
|
18
|
+
lock_scope: str
|
|
19
|
+
skip_lock: bool
|
|
20
|
+
|
|
21
|
+
def __init__(self, lock_file: str = "results/xdist_lock.txt", skip_lock: bool = False):
|
|
22
|
+
self.lock_file: str = lock_file
|
|
23
|
+
self.lock_scope: str = f"{os.getpid()}".ljust(10, ".")
|
|
24
|
+
self.skip_lock = skip_lock
|
|
25
|
+
lock_folder = os.path.dirname(self.lock_file)
|
|
26
|
+
if not os.path.isdir(lock_folder):
|
|
27
|
+
os.makedirs(lock_folder)
|
|
28
|
+
|
|
29
|
+
def __enter__(self) -> "FileLock":
|
|
30
|
+
"""
|
|
31
|
+
Enter the context manager.
|
|
32
|
+
|
|
33
|
+
:return: The FileLock object
|
|
34
|
+
:rtype: FileLock
|
|
35
|
+
"""
|
|
36
|
+
if not self.skip_lock:
|
|
37
|
+
self.acquire_lock()
|
|
38
|
+
return self
|
|
39
|
+
|
|
40
|
+
def __exit__(
|
|
41
|
+
self, exc_type: Optional[Type[BaseException]], exc_val: Optional[BaseException], exc_tb: Optional[TracebackType]
|
|
42
|
+
) -> None:
|
|
43
|
+
"""
|
|
44
|
+
Exit the context manager.
|
|
45
|
+
|
|
46
|
+
:param Optional[Type[BaseException]] exc_type: The exception type
|
|
47
|
+
:param Optional[BaseException] exc_val: The exception value
|
|
48
|
+
:param Optional[TracebackType] exc_tb: The traceback
|
|
49
|
+
:rtype: None
|
|
50
|
+
"""
|
|
51
|
+
if not self.skip_lock:
|
|
52
|
+
self.release_lock()
|
|
53
|
+
|
|
54
|
+
def lock_contents(self) -> str:
|
|
55
|
+
"""
|
|
56
|
+
Get the contents of the lock file.
|
|
57
|
+
|
|
58
|
+
:return: Contents of the lock file as a string
|
|
59
|
+
:rtype: str
|
|
60
|
+
"""
|
|
61
|
+
with open(self.lock_file, "r") as lockfile:
|
|
62
|
+
contents = lockfile.read()
|
|
63
|
+
return contents
|
|
64
|
+
|
|
65
|
+
def acquire_lock(self) -> None:
|
|
66
|
+
"""
|
|
67
|
+
Acquire the lock.
|
|
68
|
+
|
|
69
|
+
:rtype: None
|
|
70
|
+
"""
|
|
71
|
+
try:
|
|
72
|
+
while os.path.isfile(self.lock_file):
|
|
73
|
+
# Another process is holding the lock. Waiting to acquire...
|
|
74
|
+
time.sleep(0.1)
|
|
75
|
+
# Create the lock file with the pid inside
|
|
76
|
+
with open(self.lock_file, "w") as lockfile:
|
|
77
|
+
lockfile.write(f"{self.lock_scope}")
|
|
78
|
+
# Read the lock file to make sure the contents is ours
|
|
79
|
+
with open(self.lock_file, "r") as lockfile:
|
|
80
|
+
contents = lockfile.read()
|
|
81
|
+
# If the contents is not ours, race condition -> back to square one
|
|
82
|
+
if contents != f"{self.lock_scope}":
|
|
83
|
+
self.acquire_lock()
|
|
84
|
+
except Exception:
|
|
85
|
+
self.acquire_lock()
|
|
86
|
+
|
|
87
|
+
def release_lock(self) -> None:
|
|
88
|
+
"""
|
|
89
|
+
Release the lock.
|
|
90
|
+
|
|
91
|
+
:rtype: None
|
|
92
|
+
"""
|
|
93
|
+
if os.path.isfile(self.lock_file):
|
|
94
|
+
with open(self.lock_file, "r") as lockfile:
|
|
95
|
+
scope = str(lockfile.read().strip())
|
|
96
|
+
|
|
97
|
+
if scope == str(self.lock_scope):
|
|
98
|
+
os.remove(self.lock_file) # Lock released
|
|
99
|
+
else:
|
|
100
|
+
pass # Lock can only be released by {self.lock_scope}
|