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,647 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""Model for STIGs in the application"""
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import re
|
|
7
|
+
from enum import Enum
|
|
8
|
+
from pathlib import PosixPath
|
|
9
|
+
from typing import Any, Optional
|
|
10
|
+
|
|
11
|
+
from requests import JSONDecodeError
|
|
12
|
+
from rich.console import Console
|
|
13
|
+
from xmltodict import parse
|
|
14
|
+
|
|
15
|
+
from regscale.core.app.api import Api
|
|
16
|
+
from regscale.core.app.application import Application
|
|
17
|
+
from regscale.core.app.logz import create_logger
|
|
18
|
+
from regscale.models.integration_models.implementation_results import (
|
|
19
|
+
ImplementationResults,
|
|
20
|
+
)
|
|
21
|
+
from regscale.models.regscale_models import (
|
|
22
|
+
Component,
|
|
23
|
+
Checklist,
|
|
24
|
+
ImplementationObjective,
|
|
25
|
+
ImplementationOptionDeprecated,
|
|
26
|
+
T,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class Status(Enum):
|
|
31
|
+
"""
|
|
32
|
+
Map STIG Status
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
NOT_REVIEWED = "Not Reviewed" # Create POAM
|
|
36
|
+
OPEN = "Open" # Create POAM
|
|
37
|
+
NOTAFINDING = "Not A Finding" # Pass
|
|
38
|
+
NOT_APPLICABLE = "Not Applicable" # Pass
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class Severity(Enum):
|
|
42
|
+
"""
|
|
43
|
+
Map STIG Severity to RegScale
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
HIGH = "I - High - Significant Deficiency"
|
|
47
|
+
MEDIUM = "II - Moderate - Reportable Condition"
|
|
48
|
+
LOW = "III - Low - Other Weakness"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class STIG_FILE:
|
|
52
|
+
"""CKL File Processing to RegScale"""
|
|
53
|
+
|
|
54
|
+
def __init__(
|
|
55
|
+
self,
|
|
56
|
+
file_path: PosixPath,
|
|
57
|
+
ssp_id: int,
|
|
58
|
+
mapping: dict,
|
|
59
|
+
control_objectives: list,
|
|
60
|
+
security_controls: list,
|
|
61
|
+
assets: set,
|
|
62
|
+
control_implementations: list[dict],
|
|
63
|
+
app: Application = None,
|
|
64
|
+
):
|
|
65
|
+
self.logger = create_logger(propagate=True)
|
|
66
|
+
self.app = app
|
|
67
|
+
self.api = Api(timeout=40)
|
|
68
|
+
self.security_controls = security_controls
|
|
69
|
+
self.existing_components = Component.get_components_from_ssp(app=self.app, ssp_id=ssp_id)
|
|
70
|
+
self.existing_assets = assets
|
|
71
|
+
self.update_assets = []
|
|
72
|
+
self.insert_assets = []
|
|
73
|
+
self.control_objectives = control_objectives
|
|
74
|
+
self.assessed_controls = []
|
|
75
|
+
self.parentids = set()
|
|
76
|
+
self.impids = set()
|
|
77
|
+
self.assets = []
|
|
78
|
+
self.file_path = file_path
|
|
79
|
+
self.mtime = os.path.getmtime(file_path)
|
|
80
|
+
self.obj = self._parse_xml()
|
|
81
|
+
metadata = self.obj["CHECKLIST"]["STIGS"]["iSTIG"]["STIG_INFO"]["SI_DATA"]
|
|
82
|
+
self.metadata = metadata
|
|
83
|
+
platform_objectives = []
|
|
84
|
+
self.platform_objectives = platform_objectives
|
|
85
|
+
self.ssp_id = ssp_id
|
|
86
|
+
self.control_implementations = control_implementations
|
|
87
|
+
self.implementation_options = []
|
|
88
|
+
self.cci_mapping = mapping
|
|
89
|
+
dict_data = self._to_dict()
|
|
90
|
+
self.dict_data = dict_data
|
|
91
|
+
self.issue_list = []
|
|
92
|
+
self.existing_checklists = []
|
|
93
|
+
self.update_checklists = set()
|
|
94
|
+
self.insert_checklists = set()
|
|
95
|
+
console = Console()
|
|
96
|
+
self.implementation_results = ImplementationResults(stig_file_name=self.file_path.name, console=console)
|
|
97
|
+
self.update_checks()
|
|
98
|
+
self._process_rules()
|
|
99
|
+
|
|
100
|
+
self.logger.debug("Finished processing %s", self.file_path.name)
|
|
101
|
+
|
|
102
|
+
def update_checks(self) -> None:
|
|
103
|
+
"""
|
|
104
|
+
Update existing
|
|
105
|
+
|
|
106
|
+
:rtype: None
|
|
107
|
+
"""
|
|
108
|
+
self.existing_checklists = []
|
|
109
|
+
for component in self.existing_components:
|
|
110
|
+
self.existing_checklists.extend(Checklist.get_checklists(component["id"]))
|
|
111
|
+
|
|
112
|
+
@classmethod
|
|
113
|
+
def _find_dict_by_key(cls, input_list: list, search_key: Any, search_value: Any) -> Optional[T]:
|
|
114
|
+
"""
|
|
115
|
+
Find a dictionary in a list of dictionaries by searching for a key value pair
|
|
116
|
+
|
|
117
|
+
:param list input_list: List of dictionaries
|
|
118
|
+
:param Any search_key: Key to search for
|
|
119
|
+
:param Any search_value: Value to search for
|
|
120
|
+
:return: A dictionary from the list
|
|
121
|
+
:rtype: Optional[T]
|
|
122
|
+
"""
|
|
123
|
+
return next((item for item in input_list if item.get(search_key) == search_value), None)
|
|
124
|
+
|
|
125
|
+
def _parse_xml(self) -> dict:
|
|
126
|
+
"""
|
|
127
|
+
Convert CKL to a dictionary
|
|
128
|
+
|
|
129
|
+
:return: A dictionary with the CKL data
|
|
130
|
+
:rtype: dict
|
|
131
|
+
"""
|
|
132
|
+
|
|
133
|
+
with open(self.file_path, encoding="utf-8") as file:
|
|
134
|
+
return parse(file.read(), dict_constructor=dict)
|
|
135
|
+
|
|
136
|
+
def _to_dict(self) -> dict:
|
|
137
|
+
"""
|
|
138
|
+
Convert xmltodict object to friendly dictionary
|
|
139
|
+
|
|
140
|
+
:return: A dictionary with the CKL data
|
|
141
|
+
:rtype: dict
|
|
142
|
+
"""
|
|
143
|
+
|
|
144
|
+
def extract_value(key: str) -> Any:
|
|
145
|
+
"""
|
|
146
|
+
Extract a value from the metadata
|
|
147
|
+
|
|
148
|
+
:param str key: Key to search for
|
|
149
|
+
:return: Value from the metadata
|
|
150
|
+
:rtype: Any
|
|
151
|
+
"""
|
|
152
|
+
data = ""
|
|
153
|
+
try:
|
|
154
|
+
dat = [name for name in self.metadata if name["SID_NAME"] == key][0]
|
|
155
|
+
if "SID_DATA" in dat.keys():
|
|
156
|
+
data = dat["SID_DATA"]
|
|
157
|
+
data = {k.replace('"', ""): v for k, v in dat.items()}
|
|
158
|
+
except IndexError:
|
|
159
|
+
return ""
|
|
160
|
+
return data
|
|
161
|
+
|
|
162
|
+
data = {}
|
|
163
|
+
data["Title"] = extract_value("title")
|
|
164
|
+
data["Description"] = extract_value("description")
|
|
165
|
+
data["Version"] = extract_value("version")
|
|
166
|
+
data["Release"] = extract_value("release")
|
|
167
|
+
data["Notice"] = extract_value("notice")
|
|
168
|
+
data["UUID"] = extract_value("uuid")
|
|
169
|
+
data["Source"] = extract_value("source")
|
|
170
|
+
data["Rules"] = self._parse_rules()
|
|
171
|
+
data["StigID"] = extract_value("stigid")
|
|
172
|
+
data["Classification"] = extract_value("classification")
|
|
173
|
+
return data
|
|
174
|
+
|
|
175
|
+
def _has_assets(self) -> bool:
|
|
176
|
+
"""
|
|
177
|
+
Determine if the CKL has assets
|
|
178
|
+
|
|
179
|
+
:return: Whether the CKL has assets
|
|
180
|
+
:rtype: bool
|
|
181
|
+
"""
|
|
182
|
+
data = self.obj["CHECKLIST"]["ASSET"]
|
|
183
|
+
if isinstance(data, dict) and data["HOST_NAME"] is None:
|
|
184
|
+
self.logger.warning("%s contains missing asset information, exiting..", self.file_path)
|
|
185
|
+
return False
|
|
186
|
+
return True
|
|
187
|
+
|
|
188
|
+
@staticmethod
|
|
189
|
+
def _format_type(key: Any, rule: Any) -> str:
|
|
190
|
+
"""
|
|
191
|
+
Function to deal with list of str or strings
|
|
192
|
+
|
|
193
|
+
:param Any key: Rule key
|
|
194
|
+
:param Any rule: Rule object
|
|
195
|
+
:return: concatenated string or ""
|
|
196
|
+
:rtype: str
|
|
197
|
+
"""
|
|
198
|
+
result = ""
|
|
199
|
+
if isinstance(rule, list):
|
|
200
|
+
res = ". ".join(rule)
|
|
201
|
+
elif isinstance(rule, dict):
|
|
202
|
+
res = rule[key]
|
|
203
|
+
elif isinstance(rule, str):
|
|
204
|
+
res = rule
|
|
205
|
+
if isinstance(res, list) and res:
|
|
206
|
+
result = ". ".join(res)
|
|
207
|
+
return result
|
|
208
|
+
|
|
209
|
+
def _get_component_id(self, asset_type: str) -> dict:
|
|
210
|
+
"""
|
|
211
|
+
Return the component id for the asset type
|
|
212
|
+
|
|
213
|
+
:param str asset_type: Asset type (e.g. hardware, software, etc)
|
|
214
|
+
:return: component dictionary
|
|
215
|
+
:rtype: dict
|
|
216
|
+
"""
|
|
217
|
+
res = [cmp for cmp in self.existing_components if cmp["componentType"] == asset_type.lower()]
|
|
218
|
+
if res:
|
|
219
|
+
return res[0]
|
|
220
|
+
|
|
221
|
+
def _process_rule(self, rule: dict) -> None:
|
|
222
|
+
"""
|
|
223
|
+
Process a single rule (from the CKL)
|
|
224
|
+
|
|
225
|
+
:param dict rule: CKL rule
|
|
226
|
+
:rtype: None
|
|
227
|
+
"""
|
|
228
|
+
ccis = rule["CCI"] # Gather list of CCI IDs
|
|
229
|
+
controls = self._get_control_ids(ccis=ccis)
|
|
230
|
+
for cci_info in controls: # Get CCI to Control Mapping
|
|
231
|
+
control_id = cci_info["ctl_id_main"]
|
|
232
|
+
# security_control_id = self.api.get(url=self.)
|
|
233
|
+
# Match rules to regcsale objectives
|
|
234
|
+
if not control_id:
|
|
235
|
+
return
|
|
236
|
+
# Create Component Control if not exists
|
|
237
|
+
if control_id:
|
|
238
|
+
status = "Fail"
|
|
239
|
+
obj_status = "Not Implemented"
|
|
240
|
+
try:
|
|
241
|
+
if (
|
|
242
|
+
"Status" in rule
|
|
243
|
+
and isinstance(rule["Status"], str)
|
|
244
|
+
and rule["Status"].lower() == Status.NOTAFINDING.name.lower()
|
|
245
|
+
):
|
|
246
|
+
status = "Pass"
|
|
247
|
+
obj_status = "Fully Implemented"
|
|
248
|
+
except AttributeError:
|
|
249
|
+
self.logger.debug(
|
|
250
|
+
"Unable to process status for %s\nstatus will be set to 'Not Implemented'",
|
|
251
|
+
rule["RuleID"],
|
|
252
|
+
)
|
|
253
|
+
# Map STIG CCI to RegScale Control
|
|
254
|
+
security_control_list = [
|
|
255
|
+
cntrl for cntrl in self.security_controls if cntrl["controlId"].upper() == control_id.upper()
|
|
256
|
+
]
|
|
257
|
+
if security_control_list:
|
|
258
|
+
security_control = security_control_list[0]
|
|
259
|
+
else:
|
|
260
|
+
continue
|
|
261
|
+
implementations = self._get_control_implementations(security_control=security_control)
|
|
262
|
+
raw_asset = self.obj["CHECKLIST"]["ASSET"]
|
|
263
|
+
# Link this checklist to assets
|
|
264
|
+
assets = [
|
|
265
|
+
asset.dict()
|
|
266
|
+
for asset in self.existing_assets
|
|
267
|
+
if raw_asset["HOST_FQDN"].lower() == asset["fqdn"].lower()
|
|
268
|
+
and raw_asset["TARGET_KEY"] == asset["otherTrackingNumber"]
|
|
269
|
+
]
|
|
270
|
+
if not assets:
|
|
271
|
+
self.logger.debug(
|
|
272
|
+
"No assets found for %s or %s, skipping rule..",
|
|
273
|
+
raw_asset["HOST_FQDN"],
|
|
274
|
+
raw_asset["TARGET_KEY"],
|
|
275
|
+
)
|
|
276
|
+
return
|
|
277
|
+
component_id = self._get_component_id(asset_type=assets[0]["assetCategory"])["id"]
|
|
278
|
+
# grab the correct implementation based on asset type and component
|
|
279
|
+
imps = [imp for imp in implementations if imp["parentId"] == component_id]
|
|
280
|
+
|
|
281
|
+
if imps: # and (status.lower() == Status.OPEN.value.lower()):
|
|
282
|
+
implementation = imps[0]
|
|
283
|
+
imp_id = implementation["id"]
|
|
284
|
+
# Assets are loaded, lets update checklists
|
|
285
|
+
|
|
286
|
+
self.implementation_results.add_result(obj_status)
|
|
287
|
+
|
|
288
|
+
# Select Option to update the Implementation Objective (required)
|
|
289
|
+
comments = self._format_type(rule=rule, key="Comments")
|
|
290
|
+
finding_details = self._format_type(rule=rule, key="FindingDetails")
|
|
291
|
+
|
|
292
|
+
if not finding_details and status == "Pass":
|
|
293
|
+
finding_details = "Not a finding"
|
|
294
|
+
if not finding_details and status == "Fail":
|
|
295
|
+
finding_details = "An Unknown Error leading to failed check. STIG contains no finding details"
|
|
296
|
+
|
|
297
|
+
for asset in assets:
|
|
298
|
+
assert asset["id"]
|
|
299
|
+
for _, cci in enumerate(ccis):
|
|
300
|
+
baseline = (((self.file_path).name).split(".")[0]).split("-")[0].strip()
|
|
301
|
+
checklist = Checklist(
|
|
302
|
+
assetId=asset["id"],
|
|
303
|
+
status=status,
|
|
304
|
+
tool="STIGs",
|
|
305
|
+
vulnerabilityId=rule["VulnID"],
|
|
306
|
+
ruleId=rule["RuleID"],
|
|
307
|
+
cci=cci,
|
|
308
|
+
baseline=baseline,
|
|
309
|
+
check=(
|
|
310
|
+
rule["RuleTitle"] + "\n" + rule["Check_Content"]
|
|
311
|
+
), # TODO: Where should i implement fix text?
|
|
312
|
+
results=finding_details,
|
|
313
|
+
comments=comments,
|
|
314
|
+
)
|
|
315
|
+
if checklist not in {Checklist(**chk) for chk in self.existing_checklists}:
|
|
316
|
+
# Post
|
|
317
|
+
self.insert_checklists.add(checklist)
|
|
318
|
+
else:
|
|
319
|
+
# Update
|
|
320
|
+
existing_checklist = {
|
|
321
|
+
Checklist(**chk)
|
|
322
|
+
for chk in self.existing_checklists
|
|
323
|
+
if Checklist(**chk) == checklist
|
|
324
|
+
}.pop()
|
|
325
|
+
checklist.id = existing_checklist.id
|
|
326
|
+
if checklist.status != existing_checklist.status:
|
|
327
|
+
self.update_checklists.add(checklist)
|
|
328
|
+
self.impids.add(imp_id)
|
|
329
|
+
|
|
330
|
+
# end default constructor
|
|
331
|
+
# flake8: noqa: C901
|
|
332
|
+
def _process_rules(self) -> None:
|
|
333
|
+
"""
|
|
334
|
+
Convert Stig vulnerabilities/rules to RegScale objects
|
|
335
|
+
|
|
336
|
+
:rtype: None
|
|
337
|
+
"""
|
|
338
|
+
|
|
339
|
+
if not self._has_assets():
|
|
340
|
+
return
|
|
341
|
+
for rule in self.dict_data["Rules"]:
|
|
342
|
+
self._process_rule(rule)
|
|
343
|
+
self.implementation_results.report_log()
|
|
344
|
+
self._update_checklists()
|
|
345
|
+
|
|
346
|
+
def _update_checklists(self) -> None:
|
|
347
|
+
"""
|
|
348
|
+
Update or Insert checklists into RegScale
|
|
349
|
+
|
|
350
|
+
:rtype: None
|
|
351
|
+
"""
|
|
352
|
+
if self.update_checklists:
|
|
353
|
+
res = self.api.post(
|
|
354
|
+
url=self.app.config["domain"] + "/api/securitychecklist/batchUpdate",
|
|
355
|
+
json=[chk for chk in self.update_checklists],
|
|
356
|
+
)
|
|
357
|
+
# update list
|
|
358
|
+
updated = res.json()
|
|
359
|
+
# update existing
|
|
360
|
+
for ix, check in enumerate(self.existing_checklists):
|
|
361
|
+
found_check = self._find_dict_by_key(input_list=updated, search_key="id", search_value=check["id"])
|
|
362
|
+
if found_check:
|
|
363
|
+
self.existing_checklists[ix] = found_check
|
|
364
|
+
|
|
365
|
+
if self.insert_checklists:
|
|
366
|
+
res = self.api.post(
|
|
367
|
+
url=self.app.config["domain"] + "/api/securitychecklist/batchCreate",
|
|
368
|
+
json=[chk.dict() for chk in self.insert_checklists],
|
|
369
|
+
)
|
|
370
|
+
if res.status_code == 200:
|
|
371
|
+
self.existing_checklists.append(res.json())
|
|
372
|
+
|
|
373
|
+
def _get_saved_implementation_objectives(self, control_id: int) -> list[dict]:
|
|
374
|
+
"""
|
|
375
|
+
Return implementation objectives for a given control
|
|
376
|
+
|
|
377
|
+
:param int control_id: The control id to lookup
|
|
378
|
+
:return: list containing implementation objective matching the control id
|
|
379
|
+
:rtype: list[dict]
|
|
380
|
+
"""
|
|
381
|
+
return ImplementationObjective.fetch_implementation_objectives(self.app, control_id)
|
|
382
|
+
|
|
383
|
+
def _control_id_lookup(self, control_name: str) -> int:
|
|
384
|
+
"""
|
|
385
|
+
Lookup a control id from a friendly string id. (ex: AC-10)
|
|
386
|
+
|
|
387
|
+
:param str control_name: The control name to lookup
|
|
388
|
+
:return: control id
|
|
389
|
+
:rtype: int
|
|
390
|
+
"""
|
|
391
|
+
ids = []
|
|
392
|
+
result = None
|
|
393
|
+
try:
|
|
394
|
+
ids = [
|
|
395
|
+
control
|
|
396
|
+
for control in [imp["control"] for imp in self.control_implementations]
|
|
397
|
+
if control["controlId"].lower() == control_name.lower()
|
|
398
|
+
]
|
|
399
|
+
except (AttributeError, TypeError) as aex:
|
|
400
|
+
self.logger.warning("Unable to find control id for %s\n%s", control_name, aex)
|
|
401
|
+
return result
|
|
402
|
+
if ids:
|
|
403
|
+
result = ids[0]["id"]
|
|
404
|
+
return result
|
|
405
|
+
|
|
406
|
+
def _get_control_objectives(self, control_id: int) -> list[dict]:
|
|
407
|
+
"""
|
|
408
|
+
Return control objectives for a given control ID
|
|
409
|
+
|
|
410
|
+
:param int control_id: id to fetch objectives for
|
|
411
|
+
:return: A list of control objectives
|
|
412
|
+
:rtype: list[dict]
|
|
413
|
+
"""
|
|
414
|
+
control_objectives = []
|
|
415
|
+
try:
|
|
416
|
+
response = self.api.get(self.app.config["domain"] + f"/api/controlObjectives/getByControl/{control_id}")
|
|
417
|
+
if not response.raise_for_status():
|
|
418
|
+
control_objectives = response.json()
|
|
419
|
+
except (JSONDecodeError, IndexError) as jex:
|
|
420
|
+
self.logger.error(jex)
|
|
421
|
+
return control_objectives
|
|
422
|
+
|
|
423
|
+
def _get_control_ids(self, ccis: list) -> list[Any]:
|
|
424
|
+
"""
|
|
425
|
+
Return friendly control id
|
|
426
|
+
|
|
427
|
+
:param list ccis: A list of CCIs to lookup
|
|
428
|
+
:return: A list of dict with control id and control name
|
|
429
|
+
:rtype: list[Any]
|
|
430
|
+
"""
|
|
431
|
+
# TODO:
|
|
432
|
+
# [5:07 PM] Greg Elin
|
|
433
|
+
# A single control in a catalog will have multiple CCIs. Each CCI identfies an explicit "chieck" or "detail" in a control since controls often referred to multiple activities a team needs to do. Example, a control will say "Organization will define and disseminate access policy to users." In this case two CCIs exist, one to reference "define access policy" and one to reference "disseminate access policy"
|
|
434
|
+
# like 1
|
|
435
|
+
# Example, a control will say "Organization will define and disseminate access policy to users." In this case two CCIs exist, one to reference "define access policy" and one to reference "disseminate access policy"
|
|
436
|
+
# Awareness training controls, organizational..
|
|
437
|
+
result = []
|
|
438
|
+
# 99% of the cci-ref entries should be the following form of NIST SP 800-53:
|
|
439
|
+
if ccis is None:
|
|
440
|
+
ccis = {"CCI-000366"}
|
|
441
|
+
result = ccis
|
|
442
|
+
return result
|
|
443
|
+
try:
|
|
444
|
+
result = self.cci_mapping[ccis[0]]
|
|
445
|
+
except TypeError as tex:
|
|
446
|
+
self.logger.error("Unable to fetch control id %s\n%s", ccis, tex)
|
|
447
|
+
return result
|
|
448
|
+
|
|
449
|
+
@staticmethod
|
|
450
|
+
def _gen_notes(data: tuple[str, str, str, str, str]) -> str:
|
|
451
|
+
"""
|
|
452
|
+
Generate notes section in a similar format to the STIGViewer
|
|
453
|
+
(vuln_id, check_text, fix_text, discussion, rule_title)
|
|
454
|
+
|
|
455
|
+
:param tuple[str, str, str, str, str] data: A tuple of strings
|
|
456
|
+
:return: A formatted string
|
|
457
|
+
:rtype: str
|
|
458
|
+
"""
|
|
459
|
+
notes = f"""Vul ID: {data[0]}
|
|
460
|
+
Rule Title: {data[4]}
|
|
461
|
+
Discussion: {data[3]}
|
|
462
|
+
Check Text: {data[1]}
|
|
463
|
+
Fix Text: {data[2]}
|
|
464
|
+
"""
|
|
465
|
+
|
|
466
|
+
return notes
|
|
467
|
+
|
|
468
|
+
def _get_control_implementations(self, security_control: dict) -> list[dict]:
|
|
469
|
+
"""
|
|
470
|
+
Lookup or create a control implementation for a given checklist rule
|
|
471
|
+
|
|
472
|
+
:param dict security_control: Security Control as a dictionary from RegScale
|
|
473
|
+
:return: List of a Control implementation
|
|
474
|
+
:rtype: list[dict]
|
|
475
|
+
"""
|
|
476
|
+
control_implementations = [
|
|
477
|
+
imp for imp in self.control_implementations if imp["controlID"] == security_control["id"]
|
|
478
|
+
]
|
|
479
|
+
return control_implementations
|
|
480
|
+
|
|
481
|
+
def _option_lookup(self, control_id: int) -> list[ImplementationOptionDeprecated]:
|
|
482
|
+
"""
|
|
483
|
+
Fetch implementation options by security control id
|
|
484
|
+
|
|
485
|
+
:param int control_id: Security Control ID
|
|
486
|
+
:return: A list of implementation options
|
|
487
|
+
:rtype: list[ImplementationOptionDeprecated]
|
|
488
|
+
"""
|
|
489
|
+
return ImplementationOptionDeprecated.fetch_implementation_options(app=self.app, control_id=control_id)
|
|
490
|
+
|
|
491
|
+
def _attribute_lookup(self, j_array: dict, key: str) -> list:
|
|
492
|
+
"""
|
|
493
|
+
Attribute lookup
|
|
494
|
+
|
|
495
|
+
:param dict j_array: json object of attributes for a STIG
|
|
496
|
+
:param str key: key to filter STIG attributes
|
|
497
|
+
:return: list of attributes
|
|
498
|
+
:rtype: list
|
|
499
|
+
"""
|
|
500
|
+
result = []
|
|
501
|
+
try:
|
|
502
|
+
result = [value for value in j_array if value["VULN_ATTRIBUTE"].lower() == key.lower()]
|
|
503
|
+
except AttributeError as aex:
|
|
504
|
+
self.logger.error("Unable to pull attribute value\n%s", aex)
|
|
505
|
+
return result
|
|
506
|
+
|
|
507
|
+
def _process_stig_data(self, info: dict, key: str) -> Any:
|
|
508
|
+
"""
|
|
509
|
+
Check data length, if valid return
|
|
510
|
+
|
|
511
|
+
:param dict info: A dict of stig information
|
|
512
|
+
:param str key: key to look up in the dictionary
|
|
513
|
+
:return: A list or string with lookup data
|
|
514
|
+
:rtype: Any
|
|
515
|
+
"""
|
|
516
|
+
dat = info[key.upper()] if key.upper() in info else None
|
|
517
|
+
try:
|
|
518
|
+
if not dat:
|
|
519
|
+
dat = self._attribute_lookup(info["STIG_DATA"], key)
|
|
520
|
+
if len(dat) > 0:
|
|
521
|
+
if key == "cci_ref":
|
|
522
|
+
return [data["ATTRIBUTE_DATA"] for data in dat if "CCI" in data["ATTRIBUTE_DATA"]]
|
|
523
|
+
if dat and "ATTRIBUTE_DATA" in dat[0]:
|
|
524
|
+
return dat[0]["ATTRIBUTE_DATA"]
|
|
525
|
+
except TypeError:
|
|
526
|
+
self.logger.error("Unable to process %s\n", key)
|
|
527
|
+
return dat
|
|
528
|
+
|
|
529
|
+
def _parse_rules(self) -> list:
|
|
530
|
+
"""
|
|
531
|
+
Format the rule data to a simple list.
|
|
532
|
+
|
|
533
|
+
:return: list of rules
|
|
534
|
+
:rtype: list
|
|
535
|
+
"""
|
|
536
|
+
stig_vulns = self.obj["CHECKLIST"]["STIGS"]["iSTIG"]["VULN"]
|
|
537
|
+
result = []
|
|
538
|
+
for info in stig_vulns:
|
|
539
|
+
if isinstance(info, dict) and "STIG_DATA" in info:
|
|
540
|
+
rule = {
|
|
541
|
+
"VulnID": "",
|
|
542
|
+
"RuleID": "",
|
|
543
|
+
"StigID": "",
|
|
544
|
+
"Severity": "",
|
|
545
|
+
"Cat": "",
|
|
546
|
+
"Classification": "",
|
|
547
|
+
"GroupTitle": "",
|
|
548
|
+
"RuleTitle": "",
|
|
549
|
+
"Description": "",
|
|
550
|
+
"VulnDiscussion": "",
|
|
551
|
+
"FalsePositives": "",
|
|
552
|
+
"FalseNegatives": "",
|
|
553
|
+
"Documentable": "",
|
|
554
|
+
"Mitigations": "",
|
|
555
|
+
"SeverityOverrideGuidance": "",
|
|
556
|
+
"PotentialImpacts": "",
|
|
557
|
+
"ThirdPartyTools": "",
|
|
558
|
+
"MitigationControl": "",
|
|
559
|
+
"Responsibility": "",
|
|
560
|
+
"IAControls": "",
|
|
561
|
+
"CheckText": "",
|
|
562
|
+
"FixText": "",
|
|
563
|
+
"CCI": "",
|
|
564
|
+
}
|
|
565
|
+
try:
|
|
566
|
+
info["STATUS"].replace("_", " ") if "STATUS" in info else None
|
|
567
|
+
except AttributeError:
|
|
568
|
+
info["STATUS"] = "" # Leave Empty
|
|
569
|
+
severity = (
|
|
570
|
+
self._process_stig_data(info, "severity").upper()
|
|
571
|
+
if self._process_stig_data(info, "severity")
|
|
572
|
+
else None
|
|
573
|
+
)
|
|
574
|
+
rule["GroupTitle"] = self._process_stig_data(info, "group_title")
|
|
575
|
+
rule["Check_Content"] = self._process_stig_data(info, "check_content")
|
|
576
|
+
rule["Description"] = self._process_stig_data(info, "description")
|
|
577
|
+
rule["Documentable"] = self._process_stig_data(info, "documentable")
|
|
578
|
+
rule["Mitigations"] = self._process_stig_data(info, "mitigatons")
|
|
579
|
+
rule["PotentialImpacts"] = self._process_stig_data(info, "potential_impact")
|
|
580
|
+
rule["FalsePositives"] = self._process_stig_data(info, "false_positives")
|
|
581
|
+
rule["FalseNegatives"] = self._process_stig_data(info, "false_negatives")
|
|
582
|
+
rule["ThirdPartyTools"] = self._process_stig_data(info, "third_party_tools")
|
|
583
|
+
rule["MitigationControl"] = self._process_stig_data(info, "mitigation_control")
|
|
584
|
+
rule["Responsibility"] = self._process_stig_data(info, "responsibility")
|
|
585
|
+
rule["Status"] = self._process_stig_data(info, "status")
|
|
586
|
+
rule["FindingDetails"] = self._process_stig_data(info, "finding_details")
|
|
587
|
+
rule["Comments"] = self._process_stig_data(info, "comments")
|
|
588
|
+
rule["SecurityOverride"] = self._process_stig_data(info, "security_override")
|
|
589
|
+
rule["SecurityJustification"] = self._process_stig_data(info, "security_justification")
|
|
590
|
+
rule["Severity"] = severity
|
|
591
|
+
rule["VulnID"] = self._process_stig_data(info, "vuln_num")
|
|
592
|
+
rule["RuleTitle"] = self._process_stig_data(info, "rule_title")
|
|
593
|
+
rule["RuleID"] = self._process_stig_data(info, "rule_id")
|
|
594
|
+
rule["IAControls"] = self._process_stig_data(info, "ia_controls")
|
|
595
|
+
rule["StigID"] = self._process_stig_data(info, "stig_id")
|
|
596
|
+
rule["FixText"] = self._process_stig_data(info, "fix_text")
|
|
597
|
+
rule["CheckText"] = self._process_stig_data(info, "check_text")
|
|
598
|
+
rule["CCI"] = self._process_stig_data(info, "cci_ref") # TODO: handle multiple cci-refs
|
|
599
|
+
rule["Weight"] = self._process_stig_data(info, "weight")
|
|
600
|
+
rule["Classification"] = self._process_stig_data(info, "class")
|
|
601
|
+
rule["SecurityOverrideGuidence"] = self._process_stig_data(info, "security_override_Guidence")
|
|
602
|
+
rule["STIGRef"] = self._process_stig_data(info, "stigref")
|
|
603
|
+
discussion = self._process_stig_data(info, "vuln_discuss")
|
|
604
|
+
rule["VulnDiscussion"] = discussion if discussion is not None else rule["FixText"]
|
|
605
|
+
if rule["CCI"]:
|
|
606
|
+
result.append(rule)
|
|
607
|
+
return result
|
|
608
|
+
|
|
609
|
+
def oscalize_control_id(self, cl_id: str) -> Any:
|
|
610
|
+
"""
|
|
611
|
+
Output an oscal standard control id from various common formats for control ids
|
|
612
|
+
Source: https://github.com/RegScale/ComponentHub/blob/389347aa8a267aeed96b9b856c66e88c5c1127d9/muse/ComponentTools.py#L218
|
|
613
|
+
|
|
614
|
+
:param str cl_id: A standard control id
|
|
615
|
+
:return: An oscal control id
|
|
616
|
+
:rtype: Any
|
|
617
|
+
"""
|
|
618
|
+
# Handle improperly formatted control id
|
|
619
|
+
# Recognize only properly formmated control id:
|
|
620
|
+
pattern = re.compile("^[A-Za-z][A-Za-z]-[0-9() .a-z]*$")
|
|
621
|
+
if not pattern.match(cl_id):
|
|
622
|
+
self.logger.error("Problem OSCAL-izing %s", cl_id)
|
|
623
|
+
return "at.4"
|
|
624
|
+
# Handle properly formatted existing id
|
|
625
|
+
# Transform various patterns of control ids into OSCAL format
|
|
626
|
+
# Fix leading zero in at-01, ac-02.3, ac-02 (3)
|
|
627
|
+
cl_id = re.sub(r"^([A-Za-z][A-Za-z]-)0(.*)$", r"\1\2", cl_id)
|
|
628
|
+
# Change paranthesis into a dot
|
|
629
|
+
# Match: AU-3, AU-3 c, IA-5 (1), IA-5 (1) (c), IA-2 (12)
|
|
630
|
+
match = re.match(
|
|
631
|
+
r"^([A-Za-z][A-Za-z]-)([0-9]*)([ ]*[a-z]*)(\(([0-9][0-9]*)\))*( \(([a-z]*)\))?$",
|
|
632
|
+
cl_id,
|
|
633
|
+
)
|
|
634
|
+
cl_id = (
|
|
635
|
+
"".join(filter(None, (match.group(1), match.group(2)))).lower().strip()
|
|
636
|
+
+ "."
|
|
637
|
+
+ "".join(filter(None, (match.group(4),))).lower().strip()
|
|
638
|
+
)
|
|
639
|
+
cl_pid = "".join(filter(None, (match.group(6),))).lower().strip()
|
|
640
|
+
# Remove trailing space
|
|
641
|
+
cl_id = cl_id.strip(" ").strip(".")
|
|
642
|
+
# Remove paranthesis
|
|
643
|
+
cl_id = re.sub(r"[()]", "", cl_id)
|
|
644
|
+
cl_pid = re.sub(r"[()]", "", cl_pid)
|
|
645
|
+
# Set to lowercase
|
|
646
|
+
cl_id = cl_id.lower()
|
|
647
|
+
return cl_id, cl_pid
|