From 5df8e241822fa80d1066cb135904d69438eb2460 Mon Sep 17 00:00:00 2001 From: bkaiserinfosec <49665796+bkaiserinfosec@users.noreply.github.com> Date: Fri, 29 Dec 2023 20:53:22 -0800 Subject: [PATCH 01/21] Update pipeline-config.yaml (#440) --- pipeline-config.yaml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/pipeline-config.yaml b/pipeline-config.yaml index 3c3e8bea..9d98c47f 100644 --- a/pipeline-config.yaml +++ b/pipeline-config.yaml @@ -9,54 +9,54 @@ stages: branches: - release unitTesting: - enabled: false + enabled: true branches: [] secretScanning: - enabled: false + enabled: true branches: - release sca: - enabled: false + enabled: true branches: - release codeLanguages: - Python - Javascript sast: - enabled: false + enabled: true branches: - release codeLanguages: - Python iac: - enabled: false + enabled: true branches: - release buildDocker: - enabled: false + enabled: true branches: - release containerScan: - enabled: false + enabled: true branches: - release containerName: secusphere containerTag: latest releaseToTest: - enabled: false + enabled: true branches: - release serviceName: secusphere containerTag: latest testRelease: - enabled: false + enabled: true branches: - release targetUrl: 'http://192.168.0.68:5010' dastTestType: full apiTargetUrl: 'http://192.168.0.68:5010/api/openapi.yaml' securityQualityGate: - enabled: false + enabled: true branches: - release deploy: @@ -83,7 +83,7 @@ stages: app.smtp.passwordRef: "SENDGRID-SMTP-PW" app.az.keyVaultName: "BkDevSecOpsKeyVault" post: - enabled: false + enabled: true branches: - release recipientEmails: 'brian@jbfinegoods.com' From c3fb035bf7c9b3c54717eb12a205942eef53905e Mon Sep 17 00:00:00 2001 From: bkaiserinfosec <49665796+bkaiserinfosec@users.noreply.github.com> Date: Fri, 29 Dec 2023 21:09:41 -0800 Subject: [PATCH 02/21] Update tox.ini (#441) --- src/tox.ini | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tox.ini b/src/tox.ini index 5c4f7a01..eedeee12 100644 --- a/src/tox.ini +++ b/src/tox.ini @@ -7,7 +7,7 @@ deps = pytest coverage pytest-cov - Flask==2.2.2 + Flask==2.3.3 Flask-SQLAlchemy==3.0.3 Flask-Login==0.6.2 Flask-Moment==1.0.5 @@ -15,11 +15,11 @@ deps = Flask-Markdown==0.3 Flask-Bootstrap==3.3.7.1 pyotp==2.8.0 - PyJWT==2.6.0 + PyJWT==2.7.0 pycryptodome==3.17 PyQRCode==1.2.1 python-dateutil==2.8.2 - requests==2.28.2 + requests==2.31.0 azure-identity==1.12.0 azure-keyvault-secrets==4.6.0 azure-keyvault-certificates==4.6.0 From 57a681aae8c644eb08cd9166fa2fdd2709583866 Mon Sep 17 00:00:00 2001 From: bkaiserinfosec <49665796+bkaiserinfosec@users.noreply.github.com> Date: Sat, 30 Dec 2023 00:04:00 -0800 Subject: [PATCH 03/21] Feature/fix toxi (#443) * Update tox.ini * fix unit test failures --- src/vr/templates/vulns/all_vulnerabilities_filtered.html | 4 ---- src/vr/vulns/web/findings.py | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/vr/templates/vulns/all_vulnerabilities_filtered.html b/src/vr/templates/vulns/all_vulnerabilities_filtered.html index 22bfd116..f67b34cb 100644 --- a/src/vr/templates/vulns/all_vulnerabilities_filtered.html +++ b/src/vr/templates/vulns/all_vulnerabilities_filtered.html @@ -51,11 +51,7 @@

Filter - - {% include "vulns/csv_upload_modal.html" %} - - {% include "vulns/csv_upload_explanation_modal.html" %} diff --git a/src/vr/vulns/web/findings.py b/src/vr/vulns/web/findings.py index 41a34307..8c9938c8 100644 --- a/src/vr/vulns/web/findings.py +++ b/src/vr/vulns/web/findings.py @@ -768,7 +768,7 @@ def finding(appid, id): else: finding_accuracy = 'N/A' referrer = request.referrer - if 'all_app_vulns_filtered/' in referrer: + if referrer and 'all_app_vulns_filtered/' in referrer: nav_bar = 'Application' else: nav_bar = 'Component' From b3d741cb7da844ed83cc6d73e33f44acb550097a Mon Sep 17 00:00:00 2001 From: bkaiserinfosec <49665796+bkaiserinfosec@users.noreply.github.com> Date: Sat, 30 Dec 2023 00:33:34 -0800 Subject: [PATCH 04/21] Feature/fix toxi (#445) * Update tox.ini * fix unit test failures * Update web_testing.py --- ci_cd/unit_tests/web_testing.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ci_cd/unit_tests/web_testing.py b/ci_cd/unit_tests/web_testing.py index 126b4d45..fbe6e2f5 100644 --- a/ci_cd/unit_tests/web_testing.py +++ b/ci_cd/unit_tests/web_testing.py @@ -1632,7 +1632,9 @@ def test_edit_application_post(self): 'regulations': 1, } response = self._post_test_handler(route, data_dict) - assert response.status_code == 200 + match = _three_o_two_handler(response.headers, f"/edit_application/{app.ID}") + assert response.status_code == 302 + assert match def test_contacts_get(self): app = BusinessApplications.query.filter_by(ApplicationName=TEST_APP_NAME).first() From f62e0d15427b42649066bc7da6ac2120b17b24f5 Mon Sep 17 00:00:00 2001 From: bkaiserinfosec <49665796+bkaiserinfosec@users.noreply.github.com> Date: Sat, 30 Dec 2023 19:10:15 -0800 Subject: [PATCH 05/21] Feature/fix toxi (#447) * Update tox.ini * fix unit test failures * Update web_testing.py * Update Jenkinsfile --- Jenkinsfile | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 981681a1..b4e59984 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -299,21 +299,7 @@ pipeline { post { always { script { - def reportProcessor = new PipelineReportProcessor(this) - reportProcessor.processReport('pipeline_stage_report.json') - - def reportFile = 'pipeline_stage_report.json' - archiveArtifacts artifacts: reportFile, allowEmptyArchive: true - - def stageConfig = jslReadYamlConfig('post') - def recipientEmails = stageConfig?.recipientEmails - def recipientTeamsChannels = stageConfig?.recipientTeamsChannels - - jslSendMicrosoftTeamsPipelineReportMessage(recipientTeamsChannels) - jslSendMicrosoftTeamsMessage(recipientTeamsChannels) - jslSendPipelineStageReportEmail(recipientEmails) - jslSendSecurityReportEmail(recipientEmails) - jslSendPipelineReport() + jslPipelineReporter() } } } From 5c40b881a418ac78b4df7b8a94b5d22d1c61aea5 Mon Sep 17 00:00:00 2001 From: bkaiserinfosec <49665796+bkaiserinfosec@users.noreply.github.com> Date: Mon, 1 Jan 2024 11:06:57 -0800 Subject: [PATCH 06/21] Feature/fix toxi (#449) * Update tox.ini * fix unit test failures * Update web_testing.py * Update Jenkinsfile * add dockerImg map for Container scans --- flask_endpoints.csv | 262 +++++++++++------------ src/vr/api/vulns/vulnerabilities.py | 24 ++- src/vr/orchestration/web/dockerimages.py | 2 + 3 files changed, 150 insertions(+), 138 deletions(-) diff --git a/flask_endpoints.csv b/flask_endpoints.csv index 7ce7e5bc..8d5bb91e 100644 --- a/flask_endpoints.csv +++ b/flask_endpoints.csv @@ -1,156 +1,156 @@ Endpoint,Methods -/create_client,GET -/api/documentation,GET -/forgotpw,"GET, POST" -/resetpw//,"GET, POST" -/forgotun,"GET, POST" -/displayun//,"GET, POST" /,GET -/login,"GET, POST" -,GET -/check_if_mfa,POST -/logout,GET -/logout,GET -/messages,"GET, POST" -/suppress_msg,POST -/onboarding,GET -/onboarding_suppress,GET -/register,GET -/register_user/,GET -/register_user_submit,POST -/register_submit,POST -/qrcode,GET -/settings,GET -/unauth_403,GET -/users,"GET, POST" -/add_user_role,POST -/remove_user_role,POST -/remove_user_appview_role,POST -/remove_user,POST +/add_app_integration/,GET +/add_application,"GET, POST" +/add_application_environment/,"GET, POST" +/add_benchmark_attachment,POST +/add_benchmark_note,POST +/add_cicd_pipeline/,"GET, POST" +/add_cicd_pipeline_stage/,GET +/add_contact/,POST +/add_integration,"GET, POST" +/add_issue_dispo,POST +/add_issue_note,POST /add_new_user,POST -/edit_profile,"GET, POST" -/update_mfa_status,POST -/display_mfa_qr,GET -/mobile_sync,GET -/profile,GET -/mobile_qrcode,GET -/mfa_qrcode,GET -/api/oauth/authorize,"GET, POST" -/api/oauth/token,POST -/api/oauth/revoke,POST -/api/openapi.yaml,GET -/api/onboard_new_application,POST +/add_service_ticket/,POST +/add_user_role,POST +/all_app_integrations/,GET +/all_app_vulns_filtered///,"GET, POST" +/all_app_vulns_filtered////csv,"GET, POST" +/all_app_vulns_filtered////export,"GET, POST" +/all_application_benchmarks/,"GET, POST" +/all_application_environments/,GET +/all_application_metrics,GET +/all_applications,"GET, POST" +/all_applications_filtered//,"GET, POST" +/all_cheatsheets,GET +/all_cicd_pipelines/,GET +/all_dockerimages,"GET, POST" +/all_git_repos,GET +/all_integrations,GET +/all_pipeline_jobs,"GET, POST" +/all_pipelines,GET +/all_regulations,GET +/all_service_tickets,"GET, POST" +/all_vulnerabilities,"GET, POST" +/all_vulnerabilities/csv,"GET, POST" +/all_vulnerabilities/export,"GET, POST" +/all_vulnerabilities_filtered//,"GET, POST" +/all_vulnerabilities_filtered///csv,"GET, POST" +/all_vulnerabilities_filtered///export,"GET, POST" +/analyze,POST +/api/add_application_profile/,POST /api/add_loc,POST +/api/add_sg_results,POST +/api/add_vulnerabilities,POST +/api/check_security_scan_status/,GET +/api/closeout_security_scan/,POST +/api/delete_vulnerabilities,POST +/api/documentation,GET +/api/edit_vulnerabilities,POST /api/get_application_profile/,GET -/api/add_application_profile/,POST -/api/jenkins_webhook,POST /api/jenkins_pipeline_reporter,POST +/api/jenkins_webhook,POST +/api/oauth/authorize,"GET, POST" +/api/oauth/revoke,POST +/api/oauth/token,POST +/api/onboard_new_application,POST +/api/openapi.yaml,GET /api/parallel_security_scan,POST -/api/check_security_scan_status/,GET -/api/closeout_security_scan/,POST -/api/add_sg_results,POST -/api/vulnerabilities,GET /api/search_vulnerabilities,POST -/api/add_vulnerabilities,POST -/api/edit_vulnerabilities,POST -/api/delete_vulnerabilities,POST -/all_application_benchmarks/,"GET, POST" -/benchmark_assessments/,"GET, POST" -/application_benchmarks//,"GET, POST" -/assessment_results//,GET -/add_benchmark_note,POST -/delete_benchmark_note,POST -/add_benchmark_attachment,POST -/delete_benchmark_attachment,POST -/download_benchmark_attachment/,GET -/submit_risk_profile,POST -/all_applications,"GET, POST" -/all_applications_filtered//,"GET, POST" +/api/vulnerabilities,GET +/applevel_metrics/,GET /application///,GET -/application//export,GET /application//csv,GET -/add_application,"GET, POST" -/application_issues/,"GET, POST" -/delete_application/,GET +/application//export,GET +/application_benchmarks//,"GET, POST" /application_endpoints/,"GET, POST" -/add_integration,"GET, POST" -/all_integrations,GET -/validate_integration,POST -/add_app_integration/,GET -/submit_app_integration/,POST -/all_app_integrations/,GET -/remove_app_integration,POST -/all_regulations,GET -/edit_application/,"GET, POST" -/add_application_environment/,"GET, POST" -/all_application_environments/,GET -/remove_application_environment,POST -/edit_application_environment//,"GET, POST" -/add_cicd_pipeline/,"GET, POST" -/all_cicd_pipelines/,GET -/remove_cicd_pipeline,POST -/contacts/,GET -/add_contact/,POST -/delete_contact,POST -/all_pipelines,GET -/pipeline_generator/,GET -/analyze,POST -/submit,POST -/all_dockerimages,"GET, POST" -/dockerimages/,"GET, POST" -/all_pipeline_jobs,"GET, POST" -/pipeline_jobs/,"GET, POST" -/add_cicd_pipeline_stage/,GET -/get_cicd_pipeline_stage_data,POST -/validate_cicd_pipeline_stage/,POST +/application_issues/,"GET, POST" +/application_KPIs/,"GET, POST" +/application_profile/,GET +/assessment_results//,GET +/benchmark_assessments/,"GET, POST" /branches/,"GET, POST" -/all_cheatsheets,GET /cheatsheets/,GET -/all_git_repos,GET +/check_if_mfa,POST +/component_KPIs/,"GET, POST" /components/,"GET, POST" -/all_service_tickets,"GET, POST" -/issue//,GET -/add_service_ticket/,POST -/sourcecode_files/,"GET, POST" -/threat_modeler/,"GET, POST" -/threat_assessments/,"GET, POST" -/threat_assessment//,GET +/contacts/,GET +/create_client,GET /dashboard,GET +/delete_application/,GET +/delete_benchmark_attachment,POST +/delete_benchmark_note,POST +/delete_contact,POST +/delete_issue_note,POST /devopsscorecard/,"GET, POST" +/display_mfa_qr,GET +/displayun//,"GET, POST" +/dockerimages/,"GET, POST" +/download_benchmark_attachment/,GET +/edit_application/,"GET, POST" +/edit_application_environment//,"GET, POST" +/edit_profile,"GET, POST" +/filtered_findings///,"GET, POST" +/filtered_findings////csv,"GET, POST" +/filtered_findings////export,"GET, POST" +/finding//,GET +/finding///request_review,GET +/forgotpw,"GET, POST" +/forgotun,"GET, POST" +/get_cicd_pipeline_stage_data,POST +/global_KPIs,"GET, POST" +/issue//,GET +/login,"GET, POST" +/logout,GET +/logout,GET +/messages,"GET, POST" +/metrics/,GET +/mfa_qrcode,GET +/mobile_qrcode,GET +/mobile_sync,GET +/on_demand_testing,POST +/onboarding,GET +/onboarding_suppress,GET /open_findings/,"GET, POST" -/open_findings//export,"GET, POST" /open_findings//csv,"GET, POST" +/open_findings//export,"GET, POST" /open_findings_for_scan//,"GET, POST" -/open_findings_for_scan///export,"GET, POST" /open_findings_for_scan///csv,"GET, POST" -/finding///request_review,GET -/finding//,GET -/filtered_findings///,"GET, POST" -/filtered_findings////export,"GET, POST" -/filtered_findings////csv,"GET, POST" -/add_issue_dispo,POST -/add_issue_note,POST -/delete_issue_note,POST -/metrics/,GET -/all_application_metrics,GET -/applevel_metrics/,GET -/application_KPIs/,"GET, POST" -/component_KPIs/,"GET, POST" -/global_KPIs,"GET, POST" +/open_findings_for_scan///export,"GET, POST" +/pipeline_generator/,GET +/pipeline_jobs/,"GET, POST" +/profile,GET +/qrcode,GET +/register,GET +/register_submit,POST +/register_user/,GET +/register_user_submit,POST +/remove_app_integration,POST +/remove_application_environment,POST +/remove_cicd_pipeline,POST +/remove_user,POST +/remove_user_appview_role,POST +/remove_user_role,POST +/resetpw//,"GET, POST" /securitygatescorecard/,GET /securitygatesettings,GET +/settings,GET +/sourcecode_files/,"GET, POST" +/submit,POST +/submit_app_integration/,POST +/submit_risk_profile,POST +/suppress_msg,POST +/threat_assessment//,GET +/threat_assessments/,"GET, POST" +/threat_modeler/,"GET, POST" +/unauth_403,GET +/update_mfa_status,POST /update_securitygatesettings,POST -/vulnerability_scans/,"GET, POST" -/on_demand_testing,POST -/application_profile/,GET +/users,"GET, POST" +/validate_cicd_pipeline_stage/,POST +/validate_integration,POST /visual_pipeline/,GET /visual_vulnerabilities/,GET -/all_vulnerabilities,"GET, POST" -/all_vulnerabilities/export,"GET, POST" -/all_vulnerabilities/csv,"GET, POST" -/all_vulnerabilities_filtered//,"GET, POST" -/all_vulnerabilities_filtered///export,"GET, POST" -/all_vulnerabilities_filtered///csv,"GET, POST" -/all_app_vulns_filtered///,"GET, POST" -/all_app_vulns_filtered////export,"GET, POST" -/all_app_vulns_filtered////csv,"GET, POST" +/vulnerability_scans/,"GET, POST" +,GET diff --git a/src/vr/api/vulns/vulnerabilities.py b/src/vr/api/vulns/vulnerabilities.py index abb71663..7f0c000e 100644 --- a/src/vr/api/vulns/vulnerabilities.py +++ b/src/vr/api/vulns/vulnerabilities.py @@ -22,6 +22,7 @@ ERROR_RESP = "Error: Invalid API Request" + @api.route("/api/vulnerabilities") @require_oauth('read:vulnerabilities') def get_vulnerabilities(): @@ -93,12 +94,21 @@ def update_vulnerabilities_status(app_cmdb_id, scan_id, req_raw): if i.ID not in scans_to_check: scans_to_check.append(i.ID) scans_to_check = sorted(scans_to_check, reverse=True) - - previous_vulns = Vulnerabilities\ - .query\ - .join(VulnerabilityScans, VulnerabilityScans.ID==Vulnerabilities.ScanId)\ - .filter(text(f"(Vulnerabilities.Status NOT LIKE 'Closed-%' OR Vulnerabilities.Status='Closed-Mitigated') AND (Vulnerabilities.ApplicationId='{app_cmdb_id}') AND (Vulnerabilities.SourceType='{scan_type.split('CI/CD-')[1]}') AND (Vulnerabilities.InitialScanId!='{scan_id}')"))\ - .all() + if req_raw['scanType'] == 'Container': + if 'dockerImg' in req_raw: + previous_vulns = Vulnerabilities \ + .query \ + .join(VulnerabilityScans, VulnerabilityScans.ID == Vulnerabilities.ScanId) \ + .join(DockerImages, DockerImages.ID == Vulnerabilities.DockerImageId) \ + .filter(text( + f"(Vulnerabilities.Status NOT LIKE 'Closed-%' OR Vulnerabilities.Status='Closed-Mitigated') AND (Vulnerabilities.ApplicationId='{app_cmdb_id}') AND (Vulnerabilities.SourceType='{scan_type.split('CI/CD-')[1]}') AND (Vulnerabilities.InitialScanId!='{scan_id}') AND (DockerImages.ImageName=='{req_raw['dockerImg']}')")) \ + .all() + else: + previous_vulns = Vulnerabilities\ + .query\ + .join(VulnerabilityScans, VulnerabilityScans.ID==Vulnerabilities.ScanId)\ + .filter(text(f"(Vulnerabilities.Status NOT LIKE 'Closed-%' OR Vulnerabilities.Status='Closed-Mitigated') AND (Vulnerabilities.ApplicationId='{app_cmdb_id}') AND (Vulnerabilities.SourceType='{scan_type.split('CI/CD-')[1]}') AND (Vulnerabilities.InitialScanId!='{scan_id}')"))\ + .all() closed_cnt = 0 new_vulns = req_raw['findings'] @@ -107,7 +117,7 @@ def update_vulnerabilities_status(app_cmdb_id, scan_id, req_raw): prev_id_check = i.VulnerabilityID for j in new_vulns: new_id_check = j['b_VulnerabilityID'] if 'b_VulnerabilityID' in j else None - if prev_id_check == new_id_check: + if (prev_id_check == new_id_check) and (i.SourceType == j['SourceType']): found = True break if not found and i.Status != "Closed-Mitigated": diff --git a/src/vr/orchestration/web/dockerimages.py b/src/vr/orchestration/web/dockerimages.py index c38f76df..4afb87ce 100644 --- a/src/vr/orchestration/web/dockerimages.py +++ b/src/vr/orchestration/web/dockerimages.py @@ -18,6 +18,7 @@ LOGIN_URL = "admin.login" UNAUTH_URL = "403.html" SERVER_ERR_URL = "500.html" +VULN_STATUS_IS_NOT_CLOSED = "Vulnerabilities.Status NOT LIKE 'Closed-%' AND Vulnerabilities.Status NOT LIKE 'Open-RiskAccepted-%'" @orchestration.route("/all_dockerimages", methods=['GET', 'POST']) @@ -128,6 +129,7 @@ def dockerimages(appid): DockerImages.ID, DockerImages.AddDate, DockerImages.ImageName, DockerImages.ImageTag, DockerImages.ImageId, DockerImages.AppIdList, func.count(Vulnerabilities.VulnerabilityID).label('total_vulnerabilities') ).join(Vulnerabilities, Vulnerabilities.DockerImageId == DockerImages.ID) \ + .filter(text(VULN_STATUS_IS_NOT_CLOSED)) \ .filter(text(f"DockerImages.AppIdList LIKE '%{appid},%'")) \ .group_by(DockerImages.ID) \ .order_by(text(orderby)) \ From b8d2775262ae6ac137916bb244a635fa18ef7bb0 Mon Sep 17 00:00:00 2001 From: bkaiserinfosec <49665796+bkaiserinfosec@users.noreply.github.com> Date: Wed, 3 Jan 2024 20:36:17 -0800 Subject: [PATCH 07/21] Update Jenkinsfile (#452) --- Jenkinsfile | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index b4e59984..bb221109 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -3,8 +3,12 @@ pipeline { - agent any - + agent { + docker { + image 'securityuniversal/jenkins-pipeline-agent:latest' + args '--group-add 999' + } + } stages { stage('Initialize Config') { @@ -45,6 +49,11 @@ pipeline { } stage('Unit Testing') { + agent { + docker { + image 'securityuniversal/jenkins-python-agent:latest' + } + } when { expression { def config = jslReadYamlConfig('unitTesting') @@ -64,6 +73,11 @@ pipeline { } stage('Secret Scanning') { + agent { + docker { + image 'securityuniversal/jenkins-secret-agent:latest' + } + } when { expression { def config = jslReadYamlConfig('secretScanning') @@ -83,6 +97,11 @@ pipeline { } stage('Software Composition Analysis') { + agent { + docker { + image 'securityuniversal/jenkins-codetesting-agent:latest' + } + } when { expression { def config = jslReadYamlConfig('sca') @@ -106,6 +125,11 @@ pipeline { } stage('Static Application Security Testing') { + agent { + docker { + image 'securityuniversal/jenkins-codetesting-agent:latest' + } + } when { expression { def config = jslReadYamlConfig('sast') @@ -129,6 +153,12 @@ pipeline { } stage('Infrastructure-as-Code Security Testing') { + agent { + docker { + image 'securityuniversal/jenkins-iac-agent:latest' + args '--group-add 999' + } + } when { expression { def config = jslReadYamlConfig('iac') @@ -148,6 +178,12 @@ pipeline { } stage('Build Docker Service') { + agent { + docker { + image 'securityuniversal/jenkins-iac-agent:latest' + args '--group-add 999' + } + } when { expression { def config = jslReadYamlConfig('buildDocker') @@ -171,6 +207,12 @@ pipeline { } stage('Docker Container Scanning') { + agent { + docker { + image 'securityuniversal/jenkins-iac-agent:latest' + args '--group-add 999' + } + } when { expression { def config = jslReadYamlConfig('containerScan') @@ -195,6 +237,11 @@ pipeline { } stage('Release to Test') { + agent { + docker { + image 'securityuniversal/jenkins-deploy-agent:latest' + } + } when { expression { def config = jslReadYamlConfig('releaseToTest') @@ -266,6 +313,11 @@ pipeline { ////////// Deploy to Production ////////// stage('Deploy') { + agent { + docker { + image 'securityuniversal/jenkins-deploy-agent:latest' + } + } when { anyOf { // Condition for the PROD branch From 9e4030de31d47164737f216f7578d45fe04d7eb9 Mon Sep 17 00:00:00 2001 From: bkaiserinfosec <49665796+bkaiserinfosec@users.noreply.github.com> Date: Mon, 8 Jan 2024 07:53:01 -0800 Subject: [PATCH 08/21] Feature/jenkinsfile updates (#453) * Update Jenkinsfile * added scores and grades api endpoint --- src/vr/admin/routes/settings.py | 73 +++++- src/vr/api/__init__.py | 1 + src/vr/api/vulns/dora_extended.py | 378 +++++++++++++++++++++++++++ src/vr/db_models/setup.py | 6 +- src/vr/db_models/setup_2.py | 2 +- src/vr/templates/admin/settings.html | 97 ++++++- 6 files changed, 553 insertions(+), 4 deletions(-) create mode 100644 src/vr/api/vulns/dora_extended.py diff --git a/src/vr/admin/routes/settings.py b/src/vr/admin/routes/settings.py index ea761033..c366ce43 100644 --- a/src/vr/admin/routes/settings.py +++ b/src/vr/admin/routes/settings.py @@ -1,5 +1,7 @@ from flask import session, redirect, url_for, render_template from flask_login import login_required +from vr import db, app +import os # Start of Entity-specific Imports from vr.admin import admin from vr.admin.functions import _auth_user, check_menu_tour_init @@ -9,7 +11,7 @@ JENKINS_HOST, JENKINS_KEY, JENKINS_PROJECT, JENKINS_STAGING_PROJECT, JENKINS_TOKEN, SMTP_ADMIN_EMAIL, \ SMTP_HOST, SMTP_PASSWORD, SMTP_USER, SNOW_CLIENT_ID, SNOW_CLIENT_SECRET, SNOW_INSTANCE_NAME, SNOW_PASSWORD, \ SNOW_USERNAME, VERSION - +from flask_sqlalchemy import SQLAlchemy NAV = { 'CAT': { "name": "Settings", "url": "admin.admin_dashboard"} @@ -63,3 +65,72 @@ def settings(): } return render_template('admin/settings.html', user_roles=user_roles, NAV=NAV, user=user, settings=current_settings) + +@admin.route('/dangerous/delete_all', methods=['POST']) +def delete_all_data(): + NAV['curpage'] = {"name": "Settings"} + user, status, user_roles = _auth_user(session, 'No Role') + if status == 401: + return redirect(url_for('admin.login')) + elif status == 403: + return render_template('403.html', user=user, nav_cat={}, nav_subcat='', \ + nav_subsubcat='', nav_curpage={"name": "Unauthorized"}) + + try: + if ENV == 'test': + # Ensure all connections to the database are closed + db.session.close() + db.engine.dispose() + + # Path to the SQLite database file + db_path = "instance/" + app.config['SQLALCHEMY_DATABASE_URI'].replace('sqlite:///', '') + + # Delete the database file + if os.path.exists(db_path): + os.remove(db_path) + else: + print("The file does not exist") + else: + # Reflect the current database schema + db.reflect() + + # Retrieve all table names + table_names = db.engine.table_names() + + # Drop each table + for table_name in reversed(table_names): + db.engine.execute(f'DROP TABLE IF EXISTS {table_name} CASCADE') + + # Recreate all tables based on the current models + from vr.functions.mysql_db import connect_to_db + cur, db_obj = connect_to_db() + sql = '''CREATE TABLE "User" (id INTEGER NOT NULL, is_active BOOLEAN DEFAULT '1' NOT NULL, is_admin BOOLEAN DEFAULT '0' NOT NULL, is_security BOOLEAN DEFAULT '0' NOT NULL, username VARCHAR(100), password VARCHAR(255), auth_type VARCHAR(20), mfa_enabled BOOLEAN DEFAULT '0' NOT NULL, otp_secret VARCHAR(16), email VARCHAR(255) NOT NULL, email_confirmed_at DATETIME, first_name VARCHAR(100) DEFAULT '' NOT NULL, last_name VARCHAR(100) DEFAULT '' NOT NULL, jobtitle VARCHAR(100), dept VARCHAR(100), user_type VARCHAR(100), avatar_path VARCHAR(100), email_updates VARCHAR(1), app_updates VARCHAR(1), text_updates VARCHAR(1), registration_date DATETIME, loc_zipcode VARCHAR(20), loc_city VARCHAR(100), loc_state VARCHAR(50), about_me VARCHAR(2000), web_tz VARCHAR(100), phone_no VARCHAR(40), support_id VARCHAR(50), support_key VARCHAR(50), support_contact_id INTEGER, auth_token VARCHAR(300), onboarding_confirmed VARCHAR(1), PRIMARY KEY (id), UNIQUE (email))''' + cur.execute(sql) + db_obj.commit() + sql = 'CREATE TABLE "AppConfig" (id INTEGER NOT NULL, first_access BOOLEAN NOT NULL,PRIMARY KEY (id))' + cur.execute(sql) + db_obj.commit() + sql = 'CREATE TABLE "EntityPermissions" ("ID" INTEGER NOT NULL, "AddDate" DATETIME NOT NULL, "UserID" INTEGER, "EntityType" VARCHAR(100), "EntityID" VARCHAR(100), PRIMARY KEY ("ID"), FOREIGN KEY("UserID") REFERENCES "User" (id) ON DELETE CASCADE)' + cur.execute(sql) + db_obj.commit() + sql = 'CREATE TABLE "SourceCodeFile" ("ID" INTEGER NOT NULL, "AddDate" DATETIME, "GitRepoId" INTEGER, "FileName" VARCHAR(300), "FileLocation" VARCHAR(300), "FileType" VARCHAR(300), PRIMARY KEY ("ID"))' + cur.execute(sql) + db_obj.commit() + sql = 'CREATE TABLE "TmControls" ("ID" INTEGER NOT NULL, "AddDate" DATETIME NOT NULL, "Control" TEXT, "Type" VARCHAR(8), "Description" TEXT, "Lambda" VARCHAR(1), "Process" VARCHAR(1), "Server" VARCHAR(1), "Dataflow" VARCHAR(1), "Datastore" VARCHAR(1), "ExternalEntity" VARCHAR(1), PRIMARY KEY ("ID"))' + cur.execute(sql) + db_obj.commit() + sql = 'CREATE TABLE "UserRoleAssignments" (id INTEGER NOT NULL, user_id INTEGER, role_id INTEGER, PRIMARY KEY (id), FOREIGN KEY(user_id) REFERENCES "User" (id) ON DELETE CASCADE, FOREIGN KEY(role_id) REFERENCES "UserRoles" (id) ON DELETE CASCADE)' + cur.execute(sql) + db_obj.commit() + sql = 'CREATE TABLE "UserRoles" (id INTEGER NOT NULL, name VARCHAR(50), description VARCHAR(200), PRIMARY KEY (id), UNIQUE (name))' + cur.execute(sql) + db_obj.commit() + db_obj.close() + + + return "All tables dropped successfully", 200 + except Exception as e: + # Log the exception for debugging purposes + print(e) + db.session.rollback() + return "Error occurred during table deletion", 500 diff --git a/src/vr/api/__init__.py b/src/vr/api/__init__.py index 9c75fdb9..b6512480 100644 --- a/src/vr/api/__init__.py +++ b/src/vr/api/__init__.py @@ -10,5 +10,6 @@ from vr.api.vulns import vulnerabilities from vr.api.vulns import jenkins_webhook from vr.api.vulns import application_profiler +from vr.api.vulns import dora_extended from vr.api.integrations import servicenow diff --git a/src/vr/api/vulns/dora_extended.py b/src/vr/api/vulns/dora_extended.py new file mode 100644 index 00000000..1759a780 --- /dev/null +++ b/src/vr/api/vulns/dora_extended.py @@ -0,0 +1,378 @@ +import datetime +from vr import db, app +from flask import jsonify, request +from sqlalchemy import desc, text +from vr.api import api +from vr.admin.functions import db_connection_handler +from vr.admin.oauth2 import require_oauth +from authlib.integrations.flask_oauth2 import current_token +from vr.admin.auth_functions import verify_api_key, get_token_auth_header +from vr.functions.routing_functions import check_entity_permissions +from vr.assets.model.applicationprofiles import ApplicationProfiles, ApplicationProfilesSchema +from vr.assets.model.businessapplications import BusinessApplications +from vr.vulns.model.vulnerabilities import Vulnerabilities, MakeVulnerabilitiesSchema, VulnerabilitiesSchema +from vr.vulns.model.vulnerabilityscans import VulnerabilityScans +from vr.assessments.model.assessmentbenchmarkassessments import AssessmentBenchmarkAssessments +from vr.assessments.model.assessmentbenchmarkrules import AssessmentBenchmarkRules +from vr.assessments.model.assessmentbenchmarkruleaudits import AssessmentBenchmarkRuleAudits + + +ERROR_RESP = "Error: Invalid API Request" + +@api.route("/api/get_dora_grade/", methods=['POST', 'GET']) +@require_oauth('read:vulnerabilities') +def get_dora_grade(app_id): + token = current_token + auth, user_id, is_admin = verify_api_key(token) + response = jsonify({'response': ERROR_RESP}), 403 + if auth == 'valid': + permitted = check_entity_permissions(is_admin) + if permitted: + if request.method == 'POST': + form = request.get_json() + time_start = datetime.datetime.strptime(form['timeStart'], '%Y-%m-%d %H:%M:%S') + time_end = datetime.datetime.strptime(form['timeEnd'], '%Y-%m-%d %H:%M:%S') + else: + time_start = datetime.datetime.strptime('1990-01-01 12:00:00', '%Y-%m-%d %H:%M:%S') + time_end = datetime.datetime.utcnow() + time_dict = {'timeStart': time_start, 'timeEnd':time_end} + total_score = 0 + applicable_metrics = 0 + # calculate vulnerability resolution time + vr_score, total_score, applicable_metrics = calculate_vulnerability_resolution_time(time_dict, app_id, total_score, applicable_metrics) + # calculate frequency of security scans + scan_score, total_score, applicable_metrics = calculate_frequency_of_security_scans(time_dict, app_id, total_score, applicable_metrics) + # calculate mean time to detect (MTTD) security issues + all_vulns, detection_score, total_score, applicable_metrics = calculate_mean_time_to_detect(time_dict, app_id, total_score, applicable_metrics) + # calculate percentage of critical/high risk issues addressed + high_severity_score, total_score, applicable_metrics = calculate_percentage_of_high_risk_issues_addressed(all_vulns, total_score, applicable_metrics) + # calculate compliance with security standards + compliance_score, total_score, applicable_metrics = calculate_compliance_with_security_standards(time_dict, app_id, total_score, applicable_metrics) + # calculate risk profile adherence + risk_score, total_score, applicable_metrics = calculate_risk_profile_adherence(app_id, total_score, applicable_metrics) + + # calculate grade and final score + max_score, percent_score, grade = _calculate_grade(applicable_metrics, total_score) + + score = { + 'grade': grade, + 'total_score': total_score, + 'percent_score': (percent_score * 100), + 'max_score': max_score, + 'vulnerability_remediation_score': vr_score, + 'scan_frequency_score': scan_score, + 'time_to_detect_issues_score': detection_score, + 'critical_and_high_risk_mitigation_score': high_severity_score, + 'compliance_with_security_standards_score': compliance_score, + 'risk_profile_adherence_score': risk_score + } + response = jsonify(score), 200 + return response + + +def calculate_vulnerability_resolution_time(time_dict, app_id, total_score, applicable_metrics): + if '--' in app_id: + app_name = app_id.split('--')[0] + app_component = app_id.split('--')[1] + resolved_vulns = Vulnerabilities.query \ + .join(BusinessApplications, BusinessApplications.ID == Vulnerabilities.ApplicationId) \ + .filter(BusinessApplications.ApplicationName == app_name) \ + .filter(BusinessApplications.ApplicationAcronym == app_component) \ + .filter(Vulnerabilities.Status == 'Closed-Mitigated') \ + .filter(Vulnerabilities.MitigationDate >= time_dict['timeStart']) \ + .filter(Vulnerabilities.MitigationDate <= time_dict['timeEnd']) \ + .all() + else: + resolved_vulns = Vulnerabilities.query \ + .join(BusinessApplications, BusinessApplications.ID == Vulnerabilities.ApplicationId) \ + .filter(BusinessApplications.ApplicationName == app_id) \ + .filter(Vulnerabilities.Status == 'Closed-Mitigated') \ + .filter(Vulnerabilities.MitigationDate >= time_dict['timeStart']) \ + .filter(Vulnerabilities.MitigationDate <= time_dict['timeEnd']) \ + .all() + total_time = 0 + for i in resolved_vulns: + add_date = i.AddDate + resolve_date = i.MitigationDate + total = resolve_date - add_date + total_time += total.seconds / 60 / 60 + ave_resolved_hours = total_time / len(resolved_vulns) + vr_score = _calculate_dora_metric_score('resolved_vulns', ave_resolved_hours) + total_score += vr_score + applicable_metrics += 1 + return vr_score, total_score, applicable_metrics + + +def calculate_frequency_of_security_scans(time_dict, app_id, total_score, applicable_metrics): + if '--' in app_id: + app_name = app_id.split('--')[0] + app_component = app_id.split('--')[1] + all_scans = VulnerabilityScans.query \ + .join(BusinessApplications, BusinessApplications.ID == VulnerabilityScans.ApplicationId) \ + .filter(BusinessApplications.ApplicationName == app_name) \ + .filter(BusinessApplications.ApplicationAcronym == app_component) \ + .filter(VulnerabilityScans.ScanStartDate >= time_dict['timeStart']) \ + .filter(VulnerabilityScans.ScanStartDate <= time_dict['timeEnd']) \ + .all() + else: + all_scans = VulnerabilityScans.query \ + .join(BusinessApplications, BusinessApplications.ID == VulnerabilityScans.ApplicationId) \ + .filter(BusinessApplications.ApplicationName == app_id) \ + .filter(VulnerabilityScans.ScanStartDate >= time_dict['timeStart']) \ + .filter(VulnerabilityScans.ScanStartDate <= time_dict['timeEnd']) \ + .all() + if '--' in app_id: + app_name = app_id.split('--')[0] + app_component = app_id.split('--')[1] + reg_date = BusinessApplications\ + .query\ + .with_entities(BusinessApplications.RegDate)\ + .filter(BusinessApplications.ApplicationName == app_name) \ + .filter(BusinessApplications.ApplicationAcronym == app_component) \ + .first()[0] + else: + reg_date = BusinessApplications.query.with_entities(BusinessApplications.RegDate).filter( + BusinessApplications.ApplicationName == app_id).first()[0] + now = datetime.datetime.utcnow() + total_duration = (now - reg_date).days + unique_scan_dates = set() + for scan in all_scans: + unique_scan_dates.add(scan.ScanStartDate.date()) + unique_scan_count = len(unique_scan_dates) + if total_duration > 0: + frequency_of_scans = unique_scan_count / total_duration + else: + frequency_of_scans = 0 + scan_score = _calculate_dora_metric_score('scan_frequency', frequency_of_scans) + total_score += scan_score + applicable_metrics += 1 + return scan_score, total_score, applicable_metrics + + +def calculate_mean_time_to_detect(time_dict, app_id, total_score, applicable_metrics): + if '--' in app_id: + app_name = app_id.split('--')[0] + app_component = app_id.split('--')[1] + all_vulns = Vulnerabilities.query \ + .join(BusinessApplications, BusinessApplications.ID == Vulnerabilities.ApplicationId) \ + .filter(BusinessApplications.ApplicationName == app_name) \ + .filter(BusinessApplications.ApplicationAcronym == app_component) \ + .filter(Vulnerabilities.AddDate >= time_dict['timeStart']) \ + .filter(Vulnerabilities.AddDate <= time_dict['timeEnd']) \ + .all() + else: + all_vulns = Vulnerabilities.query \ + .join(BusinessApplications, BusinessApplications.ID == Vulnerabilities.ApplicationId) \ + .filter(BusinessApplications.ApplicationName == app_id) \ + .filter(Vulnerabilities.AddDate >= time_dict['timeStart']) \ + .filter(Vulnerabilities.AddDate <= time_dict['timeEnd']) \ + .all() + total_duration = 0 + for i in all_vulns: + detection_date = i.ReleaseDate + identification_date = i.AddDate + detection_time = detection_date - identification_date + total_duration += detection_time.seconds + if total_duration > 0: + detection_time_ave = total_duration / len(all_vulns) + else: + detection_time_ave = 0 + detection_score = _calculate_dora_metric_score('detection_time', detection_time_ave) + total_score += detection_score + applicable_metrics += 1 + return all_vulns, detection_score, total_score, applicable_metrics + + +def calculate_percentage_of_high_risk_issues_addressed(all_vulns, total_score, applicable_metrics): + total_issues = 0 + addressed_issues = 0 + for i in all_vulns: + if i.Severity == 'Critical' or i.Severity == 'High': + total_issues += 1 + if i.Status == 'Closed-Mitigated': + addressed_issues += 1 + if addressed_issues: + percent_addressed = (addressed_issues / total_issues) * 100 + else: + percent_addressed = 0 + high_severity_score = _calculate_dora_metric_score('high_severity', percent_addressed) + total_score += high_severity_score + applicable_metrics += 1 + return high_severity_score, total_score, applicable_metrics + + +def calculate_compliance_with_security_standards(time_dict, app_id, total_score, applicable_metrics): + if '--' in app_id: + app_name = app_id.split('--')[0] + app_component = app_id.split('--')[1] + latest_assessments = AssessmentBenchmarkAssessments.query \ + .join(BusinessApplications, BusinessApplications.ID == AssessmentBenchmarkAssessments.ApplicationID) \ + .filter(BusinessApplications.ApplicationName == app_name) \ + .filter(BusinessApplications.ApplicationAcronym == app_component) \ + .order_by(AssessmentBenchmarkAssessments.BenchmarkID, + desc(AssessmentBenchmarkAssessments.AddDate)) \ + .distinct(AssessmentBenchmarkAssessments.BenchmarkID) \ + .filter(AssessmentBenchmarkAssessments.AddDate >= time_dict['timeStart']) \ + .filter(AssessmentBenchmarkAssessments.AddDate <= time_dict['timeEnd']) \ + .all() + else: + latest_assessments = AssessmentBenchmarkAssessments.query \ + .join(BusinessApplications, BusinessApplications.ID == AssessmentBenchmarkAssessments.ApplicationID) \ + .filter(BusinessApplications.ApplicationName == app_id) \ + .order_by(AssessmentBenchmarkAssessments.BenchmarkID, + desc(AssessmentBenchmarkAssessments.AddDate)) \ + .distinct(AssessmentBenchmarkAssessments.BenchmarkID) \ + .filter(AssessmentBenchmarkAssessments.AddDate >= time_dict['timeStart']) \ + .filter(AssessmentBenchmarkAssessments.AddDate <= time_dict['timeEnd']) \ + .all() + all_rules = 0 + all_passed = 0 + for i in latest_assessments: + assessment_rules = AssessmentBenchmarkRules \ + .query \ + .filter(AssessmentBenchmarkRules.BenchmarkID == i.BenchmarkID) \ + .filter(text('AssessmentBenchmarkRules.ImplementationLevels LIKE "%1%"')) \ + .all() + assessment_rules_passed = AssessmentBenchmarkRuleAudits \ + .query \ + .filter(AssessmentBenchmarkRuleAudits.AssessmentID == i.ID) \ + .filter(text('AssessmentBenchmarkRuleAudits.PassingLevels LIKE "%1%"')) \ + .all() + all_rules += len(assessment_rules) + all_passed += len(assessment_rules_passed) + if all_passed > 0: + benchmark_pass_percent = all_passed / all_rules + else: + benchmark_pass_percent = 0 + compliance_score = _calculate_dora_metric_score('compliance', benchmark_pass_percent) + total_score += compliance_score + applicable_metrics += 1 + return compliance_score, total_score, applicable_metrics + + +def calculate_risk_profile_adherence(app_id, total_score, applicable_metrics): + if '--' in app_id: + app_name = app_id.split('--')[0] + app_component = app_id.split('--')[1] + score_query = BusinessApplications \ + .query \ + .with_entities(BusinessApplications.Criticality) \ + .filter(BusinessApplications.ApplicationName == app_name) \ + .filter(BusinessApplications.ApplicationAcronym == app_component) \ + .filter(text('BusinessApplications.Criticality LIKE "%(%"')) \ + .first() + else: + score_query = BusinessApplications \ + .query \ + .with_entities(BusinessApplications.Criticality) \ + .filter(BusinessApplications.ApplicationName == app_id) \ + .filter(text('BusinessApplications.Criticality LIKE "%(%"')) \ + .first() + if score_query is not None: + score = score_query.Criticality.split()[0] + else: + score = 0 + risk_score = _calculate_dora_metric_score('risk', score) + total_score += risk_score + applicable_metrics += 1 + return risk_score, total_score, applicable_metrics + + +def _calculate_grade(applicable_metrics, total_score): + max_score = applicable_metrics * 5 + percent_score = total_score / max_score + if percent_score >= 0.97: + grade = 'A+' + elif percent_score >= 0.93 and percent_score < 0.97: + grade = 'A' + elif percent_score >= 0.90 and percent_score < 0.93: + grade = 'A-' + elif percent_score >= 0.87 and percent_score < 0.90: + grade = 'B+' + elif percent_score >= 0.83 and percent_score < 0.87: + grade = 'B' + elif percent_score >= 0.80 and percent_score < 0.83: + grade = 'B-' + elif percent_score >= 0.77 and percent_score < 0.80: + grade = 'C+' + elif percent_score >= 0.73 and percent_score < 0.77: + grade = 'C' + elif percent_score >= 0.70 and percent_score < 0.73: + grade = 'C-' + elif percent_score >= 0.67 and percent_score < 0.70: + grade = 'D+' + elif percent_score >= 0.63 and percent_score < 0.67: + grade = 'D' + elif percent_score >= 0.60 and percent_score < 0.63: + grade = 'D-' + else: + grade = 'F' + return max_score, percent_score, grade + +def _calculate_dora_metric_score(metric_type, metric_data): + if metric_type == 'resolved_vulns': + if metric_data < 24: + points = 5 + elif metric_data >= 24 and metric_data < 72: + points = 4 + elif metric_data >= 72 and metric_data < 168: + points = 3 + elif metric_data: + points = 1 + else: + points = 0 + elif metric_type == 'scan_frequency': + if metric_data == 1: # means the scans occurred daily + points = 5 + elif metric_data > 0.1428571428571429: # means scans occurred at least weekly + points = 4 + elif metric_data > 0.07142857142857143: # means scans occurred at least monthly + points = 3 + elif metric_data: # means scans occurred less than monthly + points = 1 + else: # means no scans have be conducted + points = 0 + elif metric_type == 'detection_time': + if metric_data < 3600: # means less than 1 hour + points = 5 + elif metric_data < 21600: # means less than 6 hours + points = 4 + elif metric_data < 86400: # means less than 24 hours + points = 3 + elif metric_data: # means more than 24 hours + points = 1 + else: # means no scans have be conducted + points = 0 + elif metric_type == 'high_severity': + if metric_data > 95: + points = 5 + elif metric_data >= 80 and metric_data <= 95: + points = 4 + elif metric_data >= 60 and metric_data < 80: + points = 3 + elif metric_data: + points = 1 + else: # means no scans have be conducted + points = 0 + elif metric_type == 'compliance': + if metric_data > 95: + points = 5 + elif metric_data >= 80 and metric_data <= 95: + points = 4 + elif metric_data >= 60 and metric_data < 80: + points = 3 + elif metric_data: + points = 1 + else: # means no scans have be conducted + points = 0 + elif metric_type == 'risk': + if metric_data == 'low': + points = 5 + elif metric_data == 'medium': + points = 4 + elif metric_data == 'high': + points = 3 + else: # means no scans have be conducted + points = 0 + return points + diff --git a/src/vr/db_models/setup.py b/src/vr/db_models/setup.py index 31160bba..67adfc3b 100644 --- a/src/vr/db_models/setup.py +++ b/src/vr/db_models/setup.py @@ -34,7 +34,7 @@ def _init_db(db=None, app=None): class User(UserMixin, db.Model): __tablename__ = 'User' - extend_existing = True + __table_args__ = {'extend_existing': True} id = db.Column(db.Integer, primary_key=True) is_active = db.Column('is_active', db.Boolean(), nullable=False, server_default='1') is_admin = db.Column('is_admin', db.Boolean(), nullable=False, server_default='0') @@ -78,6 +78,7 @@ def __repr__(self): # Define the Role data-model class UserRoles(db.Model): __tablename__ = 'UserRoles' + __table_args__ = {'extend_existing': True} id = db.Column(db.Integer(), primary_key=True) name = db.Column(db.String(50), unique=True) description = db.Column(db.String(200)) @@ -87,6 +88,7 @@ class UserRoles(db.Model): # Define the UserRoles association table class UserRoleAssignments(db.Model): __tablename__ = 'UserRoleAssignments' + __table_args__ = {'extend_existing': True} id = db.Column(db.Integer(), primary_key=True) user_id = db.Column(db.Integer(), db.ForeignKey(USER_ID, ondelete='CASCADE')) role_id = db.Column(db.Integer(), db.ForeignKey('UserRoles.id', ondelete='CASCADE')) @@ -99,6 +101,7 @@ class UserRoleAssignments(db.Model): class EntityPermissions(db.Model): __tablename__ = 'EntityPermissions' + __table_args__ = {'extend_existing': True} ID = db.Column(db.Integer, primary_key=True) AddDate = db.Column(db.DateTime, index=True, default=datetime.utcnow, nullable=False) UserID = db.Column(db.Integer, db.ForeignKey(USER_ID, ondelete='CASCADE')) @@ -111,6 +114,7 @@ class EntityPermissions(db.Model): class AppConfig(db.Model): __tablename__ = 'AppConfig' + __table_args__ = {'extend_existing': True} id = db.Column(db.Integer, primary_key=True) first_access = db.Column(db.Boolean, nullable=False, default=True) diff --git a/src/vr/db_models/setup_2.py b/src/vr/db_models/setup_2.py index 605d54ab..d47ba210 100644 --- a/src/vr/db_models/setup_2.py +++ b/src/vr/db_models/setup_2.py @@ -47,7 +47,7 @@ class Technologies(db.Model): UniqueIDType = db.Column(db.String(20)) Description = db.Column(db.String(200)) RegComplete = db.Column(db.String(1)) - RegDate = db.Column(db.DateTime, index=True, default=datetime.utcnow, nullable=False) + RegDate = db.Column(db.DateTime, default=datetime.utcnow, nullable=False) Technologies() diff --git a/src/vr/templates/admin/settings.html b/src/vr/templates/admin/settings.html index b1d00a7a..06a4bee5 100644 --- a/src/vr/templates/admin/settings.html +++ b/src/vr/templates/admin/settings.html @@ -1,7 +1,48 @@ {% extends 'base_auth.html' %} {% block app_content %} + + + + {{ super() }} @@ -14,7 +55,61 @@

Application Settings

From fb5d50f2c373191b9f6288c61aa5ec222f4b02d5 Mon Sep 17 00:00:00 2001 From: bkaiserinfosec <49665796+bkaiserinfosec@users.noreply.github.com> Date: Mon, 8 Jan 2024 08:11:48 -0800 Subject: [PATCH 09/21] Feature/jenkinsfile updates (#455) * Update Jenkinsfile * added scores and grades api endpoint * Update Jenkinsfile --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index bb221109..7d21f73e 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -51,7 +51,7 @@ pipeline { stage('Unit Testing') { agent { docker { - image 'securityuniversal/jenkins-python-agent:latest' + image 'securityuniversal/jenkins:latest' } } when { From 22fc7571dc96690bc060d156429e30a1d8a819d2 Mon Sep 17 00:00:00 2001 From: bkaiserinfosec <49665796+bkaiserinfosec@users.noreply.github.com> Date: Mon, 8 Jan 2024 13:26:18 -0800 Subject: [PATCH 10/21] Feature/jenkinsfile updates (#457) * Update Jenkinsfile * added scores and grades api endpoint * Update Jenkinsfile * Update Jenkinsfile --- Jenkinsfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 7d21f73e..1fffa348 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -99,7 +99,7 @@ pipeline { stage('Software Composition Analysis') { agent { docker { - image 'securityuniversal/jenkins-codetesting-agent:latest' + image 'securityuniversal/jenkins:latest' } } when { @@ -127,7 +127,7 @@ pipeline { stage('Static Application Security Testing') { agent { docker { - image 'securityuniversal/jenkins-codetesting-agent:latest' + image 'securityuniversal/jenkins:latest' } } when { From 48869b85b94bc0b142bd039944cf979fe789bff8 Mon Sep 17 00:00:00 2001 From: bkaiserinfosec <49665796+bkaiserinfosec@users.noreply.github.com> Date: Mon, 8 Jan 2024 14:36:05 -0800 Subject: [PATCH 11/21] Feature/jenkinsfile updates (#459) * Update Jenkinsfile * added scores and grades api endpoint * Update Jenkinsfile * Update Jenkinsfile * Update pipeline-config.yaml --- pipeline-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pipeline-config.yaml b/pipeline-config.yaml index 9d98c47f..68f8f7cf 100644 --- a/pipeline-config.yaml +++ b/pipeline-config.yaml @@ -23,7 +23,7 @@ stages: - Python - Javascript sast: - enabled: true + enabled: false branches: - release codeLanguages: From b88f33e01e91cb761d98b04519d69cd1399d44c9 Mon Sep 17 00:00:00 2001 From: bkaiserinfosec <49665796+bkaiserinfosec@users.noreply.github.com> Date: Mon, 8 Jan 2024 15:07:07 -0800 Subject: [PATCH 12/21] Feature/jenkinsfile updates (#461) * Update Jenkinsfile * added scores and grades api endpoint * Update Jenkinsfile * Update Jenkinsfile * Update pipeline-config.yaml * Update pipeline-config.yaml --- pipeline-config.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pipeline-config.yaml b/pipeline-config.yaml index 68f8f7cf..2b33b743 100644 --- a/pipeline-config.yaml +++ b/pipeline-config.yaml @@ -9,14 +9,14 @@ stages: branches: - release unitTesting: - enabled: true + enabled: false branches: [] secretScanning: enabled: true branches: - release sca: - enabled: true + enabled: false branches: - release codeLanguages: @@ -37,19 +37,19 @@ stages: branches: - release containerScan: - enabled: true + enabled: false branches: - release containerName: secusphere containerTag: latest releaseToTest: - enabled: true + enabled: false branches: - release serviceName: secusphere containerTag: latest testRelease: - enabled: true + enabled: false branches: - release targetUrl: 'http://192.168.0.68:5010' From 3058cc8623e3fb3578035d300765d8ffc54d6a44 Mon Sep 17 00:00:00 2001 From: bkaiserinfosec <49665796+bkaiserinfosec@users.noreply.github.com> Date: Mon, 8 Jan 2024 15:13:50 -0800 Subject: [PATCH 13/21] Feature/jenkinsfile updates (#463) * Update Jenkinsfile * added scores and grades api endpoint * Update Jenkinsfile * Update Jenkinsfile * Update pipeline-config.yaml * Update pipeline-config.yaml * Update pipeline-config.yaml --- pipeline-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pipeline-config.yaml b/pipeline-config.yaml index 2b33b743..c54451b7 100644 --- a/pipeline-config.yaml +++ b/pipeline-config.yaml @@ -56,7 +56,7 @@ stages: dastTestType: full apiTargetUrl: 'http://192.168.0.68:5010/api/openapi.yaml' securityQualityGate: - enabled: true + enabled: false branches: - release deploy: From eae9cfd046a1800d8d80fe8e2f4edabc68687900 Mon Sep 17 00:00:00 2001 From: bkaiserinfosec <49665796+bkaiserinfosec@users.noreply.github.com> Date: Mon, 8 Jan 2024 15:25:23 -0800 Subject: [PATCH 14/21] Feature/jenkinsfile updates (#465) * Update Jenkinsfile * added scores and grades api endpoint * Update Jenkinsfile * Update Jenkinsfile * Update pipeline-config.yaml * Update pipeline-config.yaml * Update pipeline-config.yaml * Update Jenkinsfile --- Jenkinsfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Jenkinsfile b/Jenkinsfile index 1fffa348..a0e0cd5d 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -316,6 +316,7 @@ pipeline { agent { docker { image 'securityuniversal/jenkins-deploy-agent:latest' + args '--group-add 999' } } when { From b1d358668fdd463e8262ee93eb88ed6649fcb98e Mon Sep 17 00:00:00 2001 From: bkaiserinfosec <49665796+bkaiserinfosec@users.noreply.github.com> Date: Wed, 10 Jan 2024 09:59:29 -0800 Subject: [PATCH 15/21] Feature/jenkinsfile updates (#467) * Update Jenkinsfile * added scores and grades api endpoint * Update Jenkinsfile * Update Jenkinsfile * Update pipeline-config.yaml * Update pipeline-config.yaml * Update pipeline-config.yaml * Update Jenkinsfile * Update sgglobalthresholds.py --- src/vr/vulns/model/sgglobalthresholds.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vr/vulns/model/sgglobalthresholds.py b/src/vr/vulns/model/sgglobalthresholds.py index 0309bae3..09a2d3f1 100644 --- a/src/vr/vulns/model/sgglobalthresholds.py +++ b/src/vr/vulns/model/sgglobalthresholds.py @@ -8,7 +8,7 @@ class SgGlobalThresholds(db.Model): __tablename__ = 'SgGlobalThresholds' __table_args__ = {'extend_existing': True} ID = db.Column(db.Integer, primary_key=True) - Name = db.Column(db.String) + Name = db.Column(db.String(100)) AddDate = db.Column(db.DateTime) ThreshScaLow = db.Column(db.Integer) ThreshScaMedium = db.Column(db.Integer) From a688f721349a8cc8c330319f434c74ce6b0cbd69 Mon Sep 17 00:00:00 2001 From: bkaiserinfosec <49665796+bkaiserinfosec@users.noreply.github.com> Date: Wed, 10 Jan 2024 10:21:14 -0800 Subject: [PATCH 16/21] Feature/jenkinsfile updates (#469) * Update Jenkinsfile * added scores and grades api endpoint * Update Jenkinsfile * Update Jenkinsfile * Update pipeline-config.yaml * Update pipeline-config.yaml * Update pipeline-config.yaml * Update Jenkinsfile * Update sgglobalthresholds.py * Update initial_setup.py --- src/vr/functions/initial_setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vr/functions/initial_setup.py b/src/vr/functions/initial_setup.py index abc1228d..1132f9c9 100644 --- a/src/vr/functions/initial_setup.py +++ b/src/vr/functions/initial_setup.py @@ -217,7 +217,7 @@ def setup_core_db_tables(ENV): if ENV == 'test': sql = 'INSERT INTO SgGlobalThresholds (Name, AddDate, ThreshScaLow, ThreshScaMedium, ThreshScaHigh, ThreshScaCritical, ThreshContainerLow, ThreshContainerMedium, ThreshContainerHigh, ThreshContainerCritical, ThreshDastLow, ThreshDastMedium, ThreshDastHigh, ThreshDastCritical, ThreshDastApiLow, ThreshDastApiMedium, ThreshDastApiHigh, ThreshDastApiCritical, ThreshInfrastructureLow, ThreshInfrastructureMedium, ThreshInfrastructureHigh, ThreshInfrastructureCritical, ThreshSastLow, ThreshSastMedium, ThreshSastHigh, ThreshSastCritical, ThreshIacLow, ThreshIacMedium, ThreshIacHigh, ThreshIacCritical, ThreshSecretsLow, ThreshSecretsMedium, ThreshSecretsHigh, ThreshSecretsCritical) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)' else: - sql = 'INSERT INTO SgGlobalThresholds (Name, AddDate, ThreshScaLow, ThreshScaMedium, ThreshScaHigh, ThreshScaCritical, ThreshContainerLow, ThreshContainerMedium, ThreshContainerHigh, ThreshContainerCritical, ThreshDastLow, ThreshDastMedium, ThreshDastHigh, ThreshDastCritical, ThreshDastApiLow, ThreshDastApiMedium, ThreshDastApiHigh, ThreshDastApiCritical, ThreshInfrastructureLow, ThreshInfrastructureMedium, ThreshInfrastructureHigh, ThreshInfrastructureCritical, ThreshSastLow, ThreshSastMedium, ThreshSastHigh, ThreshSastCritical, ThreshIacLow, ThreshIacMedium, ThreshIacHigh, ThreshIacCritical, ThreshSecretsLow, ThreshSecretsMedium, ThreshSecretsHigh, ThreshSecretsCritical) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)' + sql = 'INSERT INTO SgGlobalThresholds (Name, AddDate, ThreshScaLow, ThreshScaMedium, ThreshScaHigh, ThreshScaCritical, ThreshContainerLow, ThreshContainerMedium, ThreshContainerHigh, ThreshContainerCritical, ThreshDastLow, ThreshDastMedium, ThreshDastHigh, ThreshDastCritical, ThreshDastApiLow, ThreshDastApiMedium, ThreshDastApiHigh, ThreshDastApiCritical, ThreshInfrastructureLow, ThreshInfrastructureMedium, ThreshInfrastructureHigh, ThreshInfrastructureCritical, ThreshSastLow, ThreshSastMedium, ThreshSastHigh, ThreshSastCritical, ThreshIacLow, ThreshIacMedium, ThreshIacHigh, ThreshIacCritical, ThreshSecretsLow, ThreshSecretsMedium, ThreshSecretsHigh, ThreshSecretsCritical) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)' args = ("General", now, None,None,4,0,None,None,2,0,None,None,0,2,None,None,0,2,None,None,0,2,None,None,0,2,None,None,0,2,None,None,0,2) cur.execute(sql, args) db.commit() From d0edd8f43198c3e36fe21e092a87b05a5679668a Mon Sep 17 00:00:00 2001 From: bkaiserinfosec <49665796+bkaiserinfosec@users.noreply.github.com> Date: Fri, 12 Jan 2024 20:34:28 -0800 Subject: [PATCH 17/21] Update Jenkinsfile --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index a0e0cd5d..d2593530 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -326,7 +326,7 @@ pipeline { // Condition for a Test-* branch expression { // Split the branch name by '/' and check if the last segment starts with 'Test-' - env.BRANCH_NAME.split('/').last().startsWith('Test') + env.BRANCH_NAME.split('/').last().startsWith('staging') } } } From 6bc2607e607869e15e8ed4e2814f5428b1a7ccc1 Mon Sep 17 00:00:00 2001 From: bkaiserinfosec <49665796+bkaiserinfosec@users.noreply.github.com> Date: Fri, 12 Jan 2024 22:06:35 -0800 Subject: [PATCH 18/21] Update pipeline-config.yaml --- pipeline-config.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/pipeline-config.yaml b/pipeline-config.yaml index c54451b7..2267ddc6 100644 --- a/pipeline-config.yaml +++ b/pipeline-config.yaml @@ -75,6 +75,7 @@ stages: azure.azTenantId: 'azTenantId' serviceCredentials: {} serviceSetStrings: + app.env: test app.extUrl: "192.168.0.150" app.db.prodDbUriRef: "PROD-DB-URI" app.smtp.host: "smtp.sendgrid.net:587" From 4e2bc4af7db96e100b2dfa52480a626b9046cabb Mon Sep 17 00:00:00 2001 From: bkaiserinfosec <49665796+bkaiserinfosec@users.noreply.github.com> Date: Fri, 12 Jan 2024 22:22:47 -0800 Subject: [PATCH 19/21] Update values.yaml --- ci_cd/helm/secusphere/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci_cd/helm/secusphere/values.yaml b/ci_cd/helm/secusphere/values.yaml index 8f2bcf7d..abba5342 100644 --- a/ci_cd/helm/secusphere/values.yaml +++ b/ci_cd/helm/secusphere/values.yaml @@ -3,7 +3,7 @@ # Declare variables to be passed into your templates. environment: prod appName: "secusphere" -appDomain: "acme.com" +appDomain: "securityuniversal.com" tlsSecretName: su-wildcard-tls From fba2f2bcd1453922682cc605c3e0387e43d12dfe Mon Sep 17 00:00:00 2001 From: bkaiserinfosec <49665796+bkaiserinfosec@users.noreply.github.com> Date: Fri, 12 Jan 2024 23:10:34 -0800 Subject: [PATCH 20/21] Update values.yaml --- ci_cd/helm/su-secrets/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci_cd/helm/su-secrets/values.yaml b/ci_cd/helm/su-secrets/values.yaml index 3bba9d33..97c59f40 100644 --- a/ci_cd/helm/su-secrets/values.yaml +++ b/ci_cd/helm/su-secrets/values.yaml @@ -8,6 +8,6 @@ azure: tls: enabled: true - name: "dynamic" + name: "su-wildcard-tls" crt: "dynamic" key: "dynamic" From 1afe638391d6c3bc1dfc221969f56873103e502f Mon Sep 17 00:00:00 2001 From: bkaiserinfosec <49665796+bkaiserinfosec@users.noreply.github.com> Date: Tue, 16 Jan 2024 20:24:16 -0800 Subject: [PATCH 21/21] Feature/jenkinsfile updates (#471) * Update Jenkinsfile * added scores and grades api endpoint * Update Jenkinsfile * Update Jenkinsfile * Update pipeline-config.yaml * Update pipeline-config.yaml * Update pipeline-config.yaml * Update Jenkinsfile * Update sgglobalthresholds.py * Update initial_setup.py * add conditions for jenkins and snow integrations --- src/config_engine.py | 130 +++++++++++++++++++------------- src/settings.py | 2 + src/vr/templates/base_auth.html | 1 + 3 files changed, 79 insertions(+), 54 deletions(-) diff --git a/src/config_engine.py b/src/config_engine.py index 0168cb9a..07400d06 100644 --- a/src/config_engine.py +++ b/src/config_engine.py @@ -9,7 +9,7 @@ SET_APP_EXT_URL from settings import SET_PROD_DB_URI_REF, SET_SMTP_PW_REF, SET_JENKINS_KEY_REF, SET_JENKINS_USER_REF, SET_JENKINS_TOKEN_REF from settings import SET_PROD_DB_URI, SET_SMTP_PW, SET_JENKINS_KEY, SET_JENKINS_USER, \ - SET_JENKINS_HOST, SET_JENKINS_PROJECT, SET_JENKINS_TOKEN, SET_JENKINS_STAGING_PROJECT + SET_JENKINS_HOST, SET_JENKINS_PROJECT, SET_JENKINS_TOKEN, SET_JENKINS_STAGING_PROJECT, SET_JENKINS_ENABLED, SET_SNOW_ENABLED from settings import SET_AZAD_CLIENT_ID, SET_AZAD_CLIENT_SECRET, SET_AZAD_AUTHORITY from settings import SET_SNOW_INSTANCE_NAME, SET_SNOW_CLIENT_ID, SET_SNOW_CLIENT_SECRET, SET_SNOW_USERNAME, SET_SNOW_PASSWORD, SET_SNOW_CLIENT_SECRET_REF, SET_SNOW_PASSWORD_REF @@ -205,65 +205,87 @@ def delete_cert(self, secret_name): ## ## GitHub to Jenkins Webhook ## -if ENV == 'prod': - if os.getenv('JENKINS_USER'): - JENKINS_USER = KeyVaultManager().get_secret(os.getenv('JENKINS_USER')) - else: - JENKINS_USER = KeyVaultManager().get_secret(SET_JENKINS_USER_REF) - if os.getenv('JENKINS_KEY'): - JENKINS_KEY = KeyVaultManager().get_secret(os.getenv('JENKINS_KEY')) - else: - JENKINS_KEY = KeyVaultManager().get_secret(SET_JENKINS_KEY_REF) - if os.getenv('JENKINS_TOKEN'): - JENKINS_TOKEN = KeyVaultManager().get_secret(os.getenv('JENKINS_TOKEN')) - else: - JENKINS_TOKEN = KeyVaultManager().get_secret(SET_JENKINS_TOKEN_REF) +if os.getenv('JENKINS_ENABLED'): + JENKINS_ENABLED = os.getenv('JENKINS_ENABLED') else: - JENKINS_USER = SET_JENKINS_USER - JENKINS_KEY = SET_JENKINS_KEY - JENKINS_TOKEN = SET_JENKINS_TOKEN + JENKINS_ENABLED = SET_JENKINS_ENABLED +if JENKINS_ENABLED == 'yes': + if ENV == 'prod': + if os.getenv('JENKINS_USER'): + JENKINS_USER = KeyVaultManager().get_secret(os.getenv('JENKINS_USER')) + else: + JENKINS_USER = KeyVaultManager().get_secret(SET_JENKINS_USER_REF) + if os.getenv('JENKINS_KEY'): + JENKINS_KEY = KeyVaultManager().get_secret(os.getenv('JENKINS_KEY')) + else: + JENKINS_KEY = KeyVaultManager().get_secret(SET_JENKINS_KEY_REF) + if os.getenv('JENKINS_TOKEN'): + JENKINS_TOKEN = KeyVaultManager().get_secret(os.getenv('JENKINS_TOKEN')) + else: + JENKINS_TOKEN = KeyVaultManager().get_secret(SET_JENKINS_TOKEN_REF) + else: + JENKINS_USER = SET_JENKINS_USER + JENKINS_KEY = SET_JENKINS_KEY + JENKINS_TOKEN = SET_JENKINS_TOKEN -if os.getenv('JENKINS_PROJECT'): - JENKINS_PROJECT = os.getenv('JENKINS_PROJECT') -else: - JENKINS_PROJECT = SET_JENKINS_PROJECT + if os.getenv('JENKINS_PROJECT'): + JENKINS_PROJECT = os.getenv('JENKINS_PROJECT') + else: + JENKINS_PROJECT = SET_JENKINS_PROJECT -if os.getenv('JENKINS_HOST'): - JENKINS_HOST = os.getenv('JENKINS_HOST') -else: - JENKINS_HOST = SET_JENKINS_HOST + if os.getenv('JENKINS_HOST'): + JENKINS_HOST = os.getenv('JENKINS_HOST') + else: + JENKINS_HOST = SET_JENKINS_HOST -if os.getenv('JENKINS_STAGING_PROJECT'): - JENKINS_STAGING_PROJECT = os.getenv('JENKINS_STAGING_PROJECT') + if os.getenv('JENKINS_STAGING_PROJECT'): + JENKINS_STAGING_PROJECT = os.getenv('JENKINS_STAGING_PROJECT') + else: + JENKINS_STAGING_PROJECT = SET_JENKINS_STAGING_PROJECT else: - JENKINS_STAGING_PROJECT = SET_JENKINS_STAGING_PROJECT - + JENKINS_USER = "" + JENKINS_KEY = "" + JENKINS_TOKEN = "" + JENKINS_PROJECT = "" + JENKINS_HOST = "" + JENKINS_STAGING_PROJECT = "" ## ServiceNOW Integration -if ENV == 'prod': - if os.getenv('SNOW_PASSWORD'): - SNOW_PASSWORD = KeyVaultManager().get_secret(os.getenv('SNOW_PASSWORD')) - else: - SNOW_PASSWORD = KeyVaultManager().get_secret(SET_SNOW_PASSWORD_REF) - if os.getenv('SNOW_CLIENT_SECRET'): - SNOW_CLIENT_SECRET = KeyVaultManager().get_secret(os.getenv('SNOW_CLIENT_SECRET')) - else: - SNOW_CLIENT_SECRET = KeyVaultManager().get_secret(SET_SNOW_CLIENT_SECRET_REF) - if os.getenv('SNOW_INSTANCE_NAME'): - SNOW_INSTANCE_NAME = KeyVaultManager().get_secret(os.getenv('SNOW_INSTANCE_NAME')) - else: - SNOW_INSTANCE_NAME = KeyVaultManager().get_secret(SET_SNOW_INSTANCE_NAME) - if os.getenv('SNOW_CLIENT_ID'): - SNOW_CLIENT_ID = KeyVaultManager().get_secret(os.getenv('SNOW_CLIENT_ID')) - else: - SNOW_CLIENT_ID = KeyVaultManager().get_secret(SET_SNOW_CLIENT_ID) - if os.getenv('SNOW_USERNAME'): - SNOW_USERNAME = KeyVaultManager().get_secret(os.getenv('SNOW_USERNAME')) +if os.getenv('SNOW_ENABLED'): + SNOW_ENABLED = os.getenv('SNOW_ENABLED') +else: + SNOW_ENABLED = SET_SNOW_ENABLED +if SNOW_ENABLED == 'yes': + if ENV == 'prod': + if os.getenv('SNOW_PASSWORD'): + SNOW_PASSWORD = KeyVaultManager().get_secret(os.getenv('SNOW_PASSWORD')) + else: + SNOW_PASSWORD = KeyVaultManager().get_secret(SET_SNOW_PASSWORD_REF) + if os.getenv('SNOW_CLIENT_SECRET'): + SNOW_CLIENT_SECRET = KeyVaultManager().get_secret(os.getenv('SNOW_CLIENT_SECRET')) + else: + SNOW_CLIENT_SECRET = KeyVaultManager().get_secret(SET_SNOW_CLIENT_SECRET_REF) + if os.getenv('SNOW_INSTANCE_NAME'): + SNOW_INSTANCE_NAME = os.getenv('SNOW_INSTANCE_NAME') + else: + SNOW_INSTANCE_NAME = SET_SNOW_INSTANCE_NAME + if os.getenv('SNOW_CLIENT_ID'): + SNOW_CLIENT_ID = os.getenv('SNOW_CLIENT_ID') + else: + SNOW_CLIENT_ID = SET_SNOW_CLIENT_ID + if os.getenv('SNOW_USERNAME'): + SNOW_USERNAME = os.getenv('SNOW_USERNAME') + else: + SNOW_USERNAME = SET_SNOW_USERNAME else: - SNOW_USERNAME = KeyVaultManager().get_secret(SET_SNOW_USERNAME) + SNOW_PASSWORD = SET_SNOW_PASSWORD + SNOW_CLIENT_SECRET = SET_SNOW_CLIENT_SECRET + SNOW_INSTANCE_NAME = SET_SNOW_INSTANCE_NAME + SNOW_CLIENT_ID = SET_SNOW_CLIENT_ID + SNOW_USERNAME = SET_SNOW_USERNAME else: - SNOW_PASSWORD = SET_SNOW_PASSWORD - SNOW_CLIENT_SECRET = SET_SNOW_CLIENT_SECRET - SNOW_INSTANCE_NAME = SET_SNOW_INSTANCE_NAME - SNOW_CLIENT_ID = SET_SNOW_CLIENT_ID - SNOW_USERNAME = SET_SNOW_USERNAME + SNOW_PASSWORD = "" + SNOW_CLIENT_SECRET = "" + SNOW_INSTANCE_NAME = "" + SNOW_CLIENT_ID = "" + SNOW_USERNAME = "" diff --git a/src/settings.py b/src/settings.py index 7273b90b..a893a2f0 100644 --- a/src/settings.py +++ b/src/settings.py @@ -39,6 +39,7 @@ ## ## Jenkins Webhook Settings (Optional) ## +SET_JENKINS_ENABLED = 'no' SET_JENKINS_KEY_REF = 'JENKINS-KEY' SET_JENKINS_USER_REF = 'JENKINS-USER' SET_JENKINS_TOKEN_REF = 'JENKINS-TOKEN' @@ -51,6 +52,7 @@ SET_JENKINS_TOKEN = 'changeme' ## ServiceNOW Settings +SET_SNOW_ENABLED = 'no' SET_SNOW_INSTANCE_NAME = 'dev124268' SET_SNOW_CLIENT_ID = '1ab21bf476013110e1ce39e1f368c2fa' SET_SNOW_CLIENT_SECRET_REF = 'SNOW-SECRET' diff --git a/src/vr/templates/base_auth.html b/src/vr/templates/base_auth.html index 5886557d..df697bc2 100644 --- a/src/vr/templates/base_auth.html +++ b/src/vr/templates/base_auth.html @@ -15,6 +15,7 @@ +