From 1e79c8cebb5faf725b05896afcc5755ed500e158 Mon Sep 17 00:00:00 2001 From: bkaiserinfosec <49665796+bkaiserinfosec@users.noreply.github.com> Date: Wed, 3 Jan 2024 20:33:59 -0800 Subject: [PATCH 01/17] Update Jenkinsfile --- 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 da05aedfe8f4922f79fdda30830f544ebd341c64 Mon Sep 17 00:00:00 2001 From: bkaiserinfosec <49665796+bkaiserinfosec@users.noreply.github.com> Date: Mon, 8 Jan 2024 07:50:15 -0800 Subject: [PATCH 02/17] 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 d5d2e521c2d81ca7e00f627d3c8e488b51dea5c5 Mon Sep 17 00:00:00 2001 From: bkaiserinfosec <49665796+bkaiserinfosec@users.noreply.github.com> Date: Mon, 8 Jan 2024 08:08:57 -0800 Subject: [PATCH 03/17] 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 1c686dccfc79ec824f336d8cb1f7291a42a982d7 Mon Sep 17 00:00:00 2001 From: bkaiserinfosec <49665796+bkaiserinfosec@users.noreply.github.com> Date: Mon, 8 Jan 2024 13:23:42 -0800 Subject: [PATCH 04/17] 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 a0b457d0eaba46005ba4007fd19f467db25e76d6 Mon Sep 17 00:00:00 2001 From: bkaiserinfosec <49665796+bkaiserinfosec@users.noreply.github.com> Date: Mon, 8 Jan 2024 14:33:05 -0800 Subject: [PATCH 05/17] 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 2a883c725c426585415cb923cc6979fae7a72661 Mon Sep 17 00:00:00 2001 From: bkaiserinfosec <49665796+bkaiserinfosec@users.noreply.github.com> Date: Mon, 8 Jan 2024 15:04:27 -0800 Subject: [PATCH 06/17] 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 aee46ec5d0408f9df5b107fa1ab28042ecef045b Mon Sep 17 00:00:00 2001 From: bkaiserinfosec <49665796+bkaiserinfosec@users.noreply.github.com> Date: Mon, 8 Jan 2024 15:11:00 -0800 Subject: [PATCH 07/17] 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 339c255078c76db2c363e4fbc1d18d8beeeaf8cc Mon Sep 17 00:00:00 2001 From: bkaiserinfosec <49665796+bkaiserinfosec@users.noreply.github.com> Date: Mon, 8 Jan 2024 15:22:53 -0800 Subject: [PATCH 08/17] 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 96a156020fa3c7710958ac25b86fbea90cade3b0 Mon Sep 17 00:00:00 2001 From: bkaiserinfosec <49665796+bkaiserinfosec@users.noreply.github.com> Date: Wed, 10 Jan 2024 09:56:50 -0800 Subject: [PATCH 09/17] 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 607c8d09badd5473e82e47f57e8e426f170b7b13 Mon Sep 17 00:00:00 2001 From: bkaiserinfosec <49665796+bkaiserinfosec@users.noreply.github.com> Date: Wed, 10 Jan 2024 10:18:35 -0800 Subject: [PATCH 10/17] 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 9fb5c666116e664809d1c8a3b81e4f0aff04e161 Mon Sep 17 00:00:00 2001 From: bkaiserinfosec <49665796+bkaiserinfosec@users.noreply.github.com> Date: Tue, 16 Jan 2024 20:18:36 -0800 Subject: [PATCH 11/17] 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 @@ + From 273ddde35d4b37cfdfbdb6f0f2bc8b85f6d711b8 Mon Sep 17 00:00:00 2001 From: bkaiserinfosec <49665796+bkaiserinfosec@users.noreply.github.com> Date: Mon, 26 Feb 2024 16:39:21 -0800 Subject: [PATCH 12/17] add settings for Jenkins --- Jenkinsfile | 2 ++ src/vr/__init__.py | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index a0e0cd5d..9f3098ff 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -342,6 +342,8 @@ pipeline { 'secretsSetStrings': stageConfig?.secretsSetStrings, 'serviceCredentials': stageConfig?.serviceCredentials, 'serviceSetStrings': stageConfig?.serviceSetStrings, + 'dockerReg': 'secunicontainerregistry.azurecr.io', + 'imgPullSecret': 'acrCreds' ]) } diff --git a/src/vr/__init__.py b/src/vr/__init__.py index b74f78d5..e1bc03cf 100644 --- a/src/vr/__init__.py +++ b/src/vr/__init__.py @@ -2,7 +2,7 @@ import requests from config_engine import ENV, PROD_DB_URI, AUTH_TYPE, APP_EXT_URL, LDAP_HOST, LDAP_PORT, LDAP_BASE_DN, \ LDAP_USER_DN, LDAP_GROUP_DN, LDAP_USER_RDN_ATTR, LDAP_USER_LOGIN_ATTR, LDAP_BIND_USER_DN, LDAP_BIND_USER_PASSWORD, \ - AZAD_CLIENT_ID, AZAD_CLIENT_SECRET, AZAD_AUTHORITY, JENKINS_USER + AZAD_CLIENT_ID, AZAD_CLIENT_SECRET, AZAD_AUTHORITY, JENKINS_USER, JENKINS_ENABLED from flask import Flask from flask_bootstrap import Bootstrap from flask_login import LoginManager @@ -448,4 +448,5 @@ def get_jenkins_data(): # Call the Jobs Here # train_model_every_six_hours() -get_jenkins_data_every_hour() +if JENKINS_ENABLED == 'yes': + get_jenkins_data_every_hour() From 1280738197ad6308d2c17b111727a13f6e3fcbeb Mon Sep 17 00:00:00 2001 From: bkaiserinfosec <49665796+bkaiserinfosec@users.noreply.github.com> Date: Mon, 26 Feb 2024 17:13:46 -0800 Subject: [PATCH 13/17] Update Jenkinsfile --- Jenkinsfile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 9f3098ff..117c0a1b 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -199,7 +199,8 @@ pipeline { jslStageWrapper('Build Docker Service') { script { jslBuildDocker([ - 'serviceName': env.appName + 'serviceName': env.appName, + 'dockerReg': 'secunicontainerregistry.azurecr.io' ]) } } @@ -230,7 +231,7 @@ pipeline { def stageConfig = jslReadYamlConfig('containerScan') def containerName = stageConfig?.containerName def containerTag = stageConfig?.containerTag - jslContainerSecurityScanning(containerName, containerTag) + jslContainerSecurityScanning(containerName, containerTag, 'secunicontainerregistry.azurecr.io') } } } From 75db5d037dcbb9efea3c40bd4142789a1c948ee3 Mon Sep 17 00:00:00 2001 From: bkaiserinfosec <49665796+bkaiserinfosec@users.noreply.github.com> Date: Tue, 27 Feb 2024 20:17:21 -0800 Subject: [PATCH 14/17] 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 c54451b7..2b33b743 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: false + enabled: true branches: - release deploy: From 5f9eb28819414b58ca0d4f77a9dbd9f6596dd1a2 Mon Sep 17 00:00:00 2001 From: bkaiserinfosec <49665796+bkaiserinfosec@users.noreply.github.com> Date: Tue, 27 Feb 2024 20:50:28 -0800 Subject: [PATCH 15/17] Update Jenkinsfile --- Jenkinsfile | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 117c0a1b..95b031d2 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -75,7 +75,7 @@ pipeline { stage('Secret Scanning') { agent { docker { - image 'securityuniversal/jenkins-secret-agent:latest' + image 'securityuniversal/jenkins-sectesting-agent:latest' } } when { @@ -99,7 +99,7 @@ pipeline { stage('Software Composition Analysis') { agent { docker { - image 'securityuniversal/jenkins:latest' + image 'securityuniversal/jenkins-sectesting-agent:latest' } } when { @@ -127,7 +127,7 @@ pipeline { stage('Static Application Security Testing') { agent { docker { - image 'securityuniversal/jenkins:latest' + image 'securityuniversal/jenkins-sectesting-agent:latest' } } when { @@ -155,7 +155,7 @@ pipeline { stage('Infrastructure-as-Code Security Testing') { agent { docker { - image 'securityuniversal/jenkins-iac-agent:latest' + image 'securityuniversal/jenkins-sectesting-agent:latest' args '--group-add 999' } } @@ -210,7 +210,7 @@ pipeline { stage('Docker Container Scanning') { agent { docker { - image 'securityuniversal/jenkins-iac-agent:latest' + image 'securityuniversal/jenkins-sectesting-agent:latest' args '--group-add 999' } } @@ -294,6 +294,12 @@ pipeline { ////////// Quality Gate ////////// stage("Quality Gate - Security") { + agent { + docker { + image 'securityuniversal/jenkins-sectesting-agent:latest' + args '--group-add 999' + } + } when { expression { def config = jslReadYamlConfig('securityQualityGate') From 7301c44b72b48ab1cab0165ab157b556a6f6e7b0 Mon Sep 17 00:00:00 2001 From: bkaiserinfosec <49665796+bkaiserinfosec@users.noreply.github.com> Date: Tue, 27 Feb 2024 22:02:06 -0800 Subject: [PATCH 16/17] jenkins testing --- Jenkinsfile | 2 +- pipeline-config.yaml | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 281ac45d..a2d43df6 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -51,7 +51,7 @@ pipeline { stage('Unit Testing') { agent { docker { - image 'securityuniversal/jenkins:latest' + image 'securityuniversal/jenkins-python-agent:latest' } } when { diff --git a/pipeline-config.yaml b/pipeline-config.yaml index 55659e84..93ec1421 100644 --- a/pipeline-config.yaml +++ b/pipeline-config.yaml @@ -9,21 +9,21 @@ stages: branches: - release unitTesting: - enabled: false + enabled: true branches: [] secretScanning: enabled: true branches: - release sca: - enabled: false + enabled: true branches: - release codeLanguages: - Python - Javascript sast: - enabled: false + enabled: true branches: - release codeLanguages: @@ -37,19 +37,19 @@ stages: 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' From f75ce71458cf5eb1729f290b88d2e08f88534eef Mon Sep 17 00:00:00 2001 From: bkaiserinfosec <49665796+bkaiserinfosec@users.noreply.github.com> Date: Sat, 9 Mar 2024 11:25:04 -0800 Subject: [PATCH 17/17] Update vulnerabilities.py --- src/vr/api/vulns/vulnerabilities.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vr/api/vulns/vulnerabilities.py b/src/vr/api/vulns/vulnerabilities.py index 7f0c000e..68360c8b 100644 --- a/src/vr/api/vulns/vulnerabilities.py +++ b/src/vr/api/vulns/vulnerabilities.py @@ -132,7 +132,7 @@ def update_vulnerabilities_status(app_cmdb_id, scan_id, req_raw): def add_vulns_background_process(req_raw): now = datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S") app_name = req_raw['appName'] - git_url = req_raw['giturl'] + git_url = req_raw['gitUrl'] git_branch = req_raw['branch'] findings = req_raw['findings'] scan_type = req_raw['scanType']