From 264b74f399c525e2b21e197614ff2a3c40526797 Mon Sep 17 00:00:00 2001 From: Daniel Furnivall Date: Mon, 27 Nov 2023 13:03:27 +0000 Subject: [PATCH 01/34] add v4 audit implementation - testing --- .../uk/gov/hmcts/pipeline/yarn/yarnv4audit.py | 161 ++++++++++++++++++ src/uk/gov/hmcts/contino/YarnBuilder.groovy | 88 ++++++++-- 2 files changed, 234 insertions(+), 15 deletions(-) create mode 100644 resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py diff --git a/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py b/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py new file mode 100644 index 0000000000..5ad93443b3 --- /dev/null +++ b/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py @@ -0,0 +1,161 @@ +import json +from dataclasses import dataclass, asdict +import subprocess +import os + +@dataclass +class Vulnerability: + name: str + id: str + severity: str + vulnerable_versions: str + issue: str + url: str + tree_versions: list[str] + dependents: list[str] + + def to_json(self): + return asdict(self) + + def format_vulnerability(self) -> str: + return ( + f"├─ {self.name}\n" + f"│ ├─ ID: {self.id if self.id is not None else 'N/A'}\n" + f"│ ├─ URL: {self.url if self.url is not None else 'N/A'}\n" + f"│ ├─ Issue: {self.issue if self.issue is not None else 'N/A'}\n" + f"│ ├─ Severity: {self.severity if self.severity is not None else 'N/A'}\n" + f"│ ├─ Vulnerable Versions: {self.vulnerable_versions if self.vulnerable_versions is not None else 'N/A'}\n" + f"│ ├─ Tree Versions: {', '.join(self.tree_versions) if self.tree_versions else 'N/A'}\n" + f"│ └─ Dependents: {', '.join(self.dependents) if self.dependents else 'N/A'}" + ) + + def __eq__(self, other): + if isinstance(other, Vulnerability): + return self.id == other.id + # Compare based on id only - allows us to handle situations + # where the other text of the vulnerability changes over time + return False + +def run_audit_command(): + command = ['yarn', 'npm', 'audit', '--recursive', '--environment', 'production', '--json'] + result = subprocess.run(command, capture_output=True, text=True) + # if any errors, print them and exit + if result.stderr != '': + print("Error running command `yarn npm audit --recursive --environment production --json` - Please raise a request in #platops-help. Error: ", repr(result.stderr)) + exit(1) + else: + return result.stdout, result.returncode + +def validate_audit_response(response, exit_code): + if exit_code == 0: + print("No vulnerabilities found, nice work!") + exit(0) + list_of_issues = split_and_strip_json_blocks(response) + print("Found", len(list_of_issues), "vulnerabilities") + if check_json_keys(list_of_issues): + vulnerabilities = build_list_of_issues(list_of_issues) + return vulnerabilities + else: + print("Error parsing JSON returned from audit endpoint - please raise a request in #platops-help") + exit(1) + +def split_and_strip_json_blocks(json_block): + stripped_response = json_block.strip() + list_of_issues = stripped_response.split('\n') + return list_of_issues + +def check_yarn_audit_known_issues(): + if os.path.exists('yarn-audit-known-issues'): + print("Found yarn-audit-known-issues file - checking for suppressed vulnerabilities") + with open('yarn-audit-known-issues') as f: + known_issues_file_content = f.read() + known_issues_stripped = split_and_strip_json_blocks(known_issues_file_content) + if check_json_keys(known_issues_stripped): + known_issues_list = build_list_of_issues(known_issues_stripped) + return known_issues_list + else : + print("Error parsing JSON in your yarn-audit-known-issues file - delete the file and use the following command:") + print("`yarn npm audit --recursive --environment production --json > yarn-audit-known-issues`") + exit(1) + else: + return [] + +def check_json_keys(json_blocks): + try: + for block in json_blocks: + data = json.loads(block) + # Check if both 'value' and 'children' keys are in the JSON block (yarn v4 schema) + if "value" not in data or "children" not in data: + return False + return True + except json.JSONDecodeError: + return False + +def combine_suppressions_and_vulnerabilities(suppressions, vulnerabilities): + # comparison logic is based on the ID of the vulnerability - if the ID is the same, we assume it's the same + # vulnerability + unsuppressed_vulnerabilities = [item for item in vulnerabilities if item not in suppressions] + unneeded_suppressions = [item for item in suppressions if item not in vulnerabilities] + suppressed_active_vulnerabilities = [item for item in vulnerabilities if item in suppressions] + return unsuppressed_vulnerabilities, unneeded_suppressions, suppressed_active_vulnerabilities + + +def build_list_of_issues(json_blocks): + """ + Creates a list of Vulnerability objects from a list of JSON blocks. + Each JSON block is parsed once and then used to construct a Vulnerability object. + + :param json_blocks: A list of JSON strings. + :return: A list of Vulnerability objects. + """ + vulnerabilities = [] + for block in json_blocks: + parsed_data = json.loads(block) + vuln = Vulnerability( + name=parsed_data.get('value'), + id=parsed_data.get('children', {}).get('ID'), + issue=parsed_data.get('children', {}).get('Issue'), + url=parsed_data.get('children', {}).get('URL'), + severity=parsed_data.get('children', {}).get('Severity'), + vulnerable_versions=parsed_data.get('children', {}).get('Vulnerable Versions'), + tree_versions=parsed_data.get('children', {}).get('Tree Versions', []), + dependents=parsed_data.get('children', {}).get('Dependents', []) + ) + vulnerabilities.append(vuln) + return vulnerabilities + +def print_vulnerabilities(vulnerabilities): + print("Found", len(vulnerabilities), "active vulnerabilities, please fix these before pushing again.") + for vulnerability in vulnerabilities: + print(vulnerability.format_vulnerability()) + +def print_suppressions(suppressions): + print("Found", len(suppressions), "unnecessary suppression(s), please check these are still needed." + "If not, please remove them from your yarn-audit-known-issues file") + for suppression in suppressions: + print(suppression.format_vulnerability()) + +def decide_what_to_print(unsuppressed_vulnerabilities, unneeded_suppressions): + if len(unsuppressed_vulnerabilities) == 0 and len(unneeded_suppressions) == 0: + print("All vulnerabilities are suppressed and there are no unneeded_suppressions - no action required, nice work!") + return + if len(unsuppressed_vulnerabilities) > 0: + print_vulnerabilities(unsuppressed_vulnerabilities) + return + if len(unneeded_suppressions) > 0: + print_suppressions(unneeded_suppressions) + +def build_parent_json_for_cosmosDB(vulnerabilities, suppressions): + if os.environ.get('ci') != 'True': + print("Not running in CI, skipping parent JSON block") + parent_block = {"suppressed_vulnerabilities": [s.to_json() for s in suppressions], + "unsuppressed_vulnerabilities": [v.to_json() for v in vulnerabilities]} + with open("audit-v4-cosmosdb-output", "w") as file: + file.write(json.dumps(parent_block, indent=2)) + +audit_output, return_code = run_audit_command() +vulnerabilities = validate_audit_response(audit_output, return_code) +suppressions = check_yarn_audit_known_issues() +unsuppressed_vulnerabilities, unneeded_suppressions, suppressed_active_vulnerabilities = combine_suppressions_and_vulnerabilities(suppressions, vulnerabilities) +decide_what_to_print(unsuppressed_vulnerabilities, unneeded_suppressions) +build_parent_json_for_cosmosDB(unsuppressed_vulnerabilities, suppressed_active_vulnerabilities) diff --git a/src/uk/gov/hmcts/contino/YarnBuilder.groovy b/src/uk/gov/hmcts/contino/YarnBuilder.groovy index e4f2594458..a57f8f602d 100644 --- a/src/uk/gov/hmcts/contino/YarnBuilder.groovy +++ b/src/uk/gov/hmcts/contino/YarnBuilder.groovy @@ -123,9 +123,41 @@ class YarnBuilder extends AbstractBuilder { } } + def yarnVersionCheck() { + steps.sh """ + grep '"packageManager":' package.json | cut -d '"' -f 4 > yarn_version + """ + + def versionString = steps.readFile(yarn_version) + def parts = versionString.split("\\.") + def major = parts.size() > 0 ? parts[0].toInteger() : 0 + def minor = parts.size() > 1 ? parts[1].toInteger() : 0 + def patch = parts.size() > 2 ? parts[2].toInteger() : 0 + + if (major < 3) { + println "Version is less than 3.0.0. This needs updating as we only support 3.0.x upwards." + return '<3' + } else if (major == 3) { + println "v3 detected - continuing" + return 'v3' + } else if (major == 4) { + if (minor == 0 && patch == 0) { + println "v4.0.0 detected. You will need to upgrade yarn to at least v4.0.1, as 4.0.0 has an unsupported audit format." + return 'v4.0.0' +// todo - handle exit code here + } + } else { + println "Version is greater than 4.0.0. Using the updated configuration for yarn npm audit." + return 'v4+' + } + } + def securityCheck() { - try { - steps.sh """ + + version = yarnVersionCheck() + if (version == 'v3') { + try { + steps.sh """ set +ex export NVM_DIR='/home/jenkinsssh/.nvm' # TODO get home from variable . /opt/nvm/nvm.sh || true @@ -133,30 +165,56 @@ class YarnBuilder extends AbstractBuilder { set -ex """ - corepackEnable() - steps.writeFile(file: 'yarn-audit-with-suppressions.sh', text: steps.libraryResource('uk/gov/hmcts/pipeline/yarn/yarn-audit-with-suppressions.sh')) - steps.writeFile(file: 'prettyPrintAudit.sh', text: steps.libraryResource('uk/gov/hmcts/pipeline/yarn/prettyPrintAudit.sh')) + corepackEnable() + steps.writeFile(file: 'yarn-audit-with-suppressions.sh', text: steps.libraryResource('uk/gov/hmcts/pipeline/yarn/yarn-audit-with-suppressions.sh')) + steps.writeFile(file: 'prettyPrintAudit.sh', text: steps.libraryResource('uk/gov/hmcts/pipeline/yarn/prettyPrintAudit.sh')) - steps.sh """ + steps.sh """ export PATH=\$HOME/.local/bin:\$PATH chmod +x yarn-audit-with-suppressions.sh ./yarn-audit-with-suppressions.sh """ - } finally { - steps.sh """ + } finally { + steps.sh """ cat yarn-audit-result | jq -c '. | {type: "auditSummary", data: .metadata}' > yarn-audit-issues-result-summary cat yarn-audit-result | jq -cr '.advisories| to_entries[] | {"type": "auditAdvisory", "data": { "advisory": .value }}' >> yarn-audit-issues-advisories cat yarn-audit-issues-result-summary yarn-audit-issues-advisories > yarn-audit-issues-result """ - String issues = steps.readFile('yarn-audit-issues-result') - String knownIssues = null - if (steps.fileExists(CVE_KNOWN_ISSUES_FILE_PATH)) { - knownIssues = steps.readFile(CVE_KNOWN_ISSUES_FILE_PATH) + String issues = steps.readFile('yarn-audit-issues-result') + String knownIssues = null + if (steps.fileExists(CVE_KNOWN_ISSUES_FILE_PATH)) { + knownIssues = steps.readFile(CVE_KNOWN_ISSUES_FILE_PATH) + } + def cveReport = prepareCVEReport(issues, knownIssues) + new CVEPublisher(steps) + .publishCVEReport('node', cveReport) } - def cveReport = prepareCVEReport(issues, knownIssues) - new CVEPublisher(steps) - .publishCVEReport('node', cveReport) } + else if (version == 'v4.0.0') { + steps.println("Unsupported version, please upgrade to 4.0.1 or higher") +// todo : handle + } + else if (version == '<3') { + steps.println("Version too low") +// todo : handle + + } + else if (version == 'v4+') { + securityCheckYarnV4() + } + } + + def securityCheckYarnV4() { + steps.writeFile(file: 'yarnv4audit.py', text: steps.libraryResource('uk/gov/hmcts/pipeline/yarn/yarnv4audit.py')) + + steps.sh """ + export PATH=\$HOME/.local/bin:\$PATH + chmod +x yarnv4audit.py + ./yarnv4audit.py + """ + steps.sh """ + cat audit-v4-cosmosdb-output + """ } @Override From bb0b82d7f1bd9273a811fd2d602763fe30f6f1c5 Mon Sep 17 00:00:00 2001 From: Daniel Furnivall Date: Mon, 27 Nov 2023 13:21:19 +0000 Subject: [PATCH 02/34] fix some shell --- .../uk/gov/hmcts/pipeline/yarn/yarnv4audit.py | 161 ++++++++++++++++++ src/uk/gov/hmcts/contino/YarnBuilder.groovy | 6 +- 2 files changed, 165 insertions(+), 2 deletions(-) diff --git a/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py b/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py index 5ad93443b3..6a9642cf35 100644 --- a/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py +++ b/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py @@ -100,6 +100,159 @@ def combine_suppressions_and_vulnerabilities(suppressions, vulnerabilities): return unsuppressed_vulnerabilities, unneeded_suppressions, suppressed_active_vulnerabilities +def build_list_of_issues(json_blocks): + """ + Creates a list of Vulnerability objects from a list of JSON blocks. + Each JSON block is parsed once and then used to construct a Vulnerability object. + + :param json_blocks: A list of JSON strings. + :return: A list of Vulnerability objects. + """ + vulnerabilities = [] + for block in json_blocks: + parsed_data = json.loads(block) + vuln = Vulnerability( + name=parsed_data.get('value'), + id=parsed_data.get('children', {}).get('ID'), + issue=parsed_data.get('children', {}).get('Issue'), + url=parsed_data.get('children', {}).get('URL'), + severity=parsed_data.get('children', {}).get('Severity'), + vulnerable_versions=parsed_data.get('children', {}).get('Vulnerable Versions'), + tree_versions=parsed_data.get('children', {}).get('Tree Versions', []), + dependents=parsed_data.get('children', {}).get('Dependents', []) + ) + vulnerabilities.append(vuln) + return vulnerabilities + +def print_vulnerabilities(vulnerabilities): + print("Found", len(vulnerabilities), "active vulnerabilities, please fix these before pushing again.") + for vulnerability in vulnerabilities: + print(vulnerability.format_vulnerability()) + +def print_suppressions(suppressions): + print("Found", len(suppressions), "unnecessary suppression(s), please check these are still needed." + "If not, please remove them from your yarn-audit-known-issues file") + for suppression in suppressions: + print(suppression.format_vulnerability()) + +def decide_what_to_print(unsuppressed_vulnerabilities, unneeded_suppressions): + if len(unsuppressed_vulnerabilities) == 0 and len(unneeded_suppressions) == 0: + print("All vulnerabilities are suppressed and there are no unneeded_suppressions - no action required, nice work!") + return + if len(unsuppressed_vulnerabilities) > 0: + print_vulnerabilities(unsuppressed_vulnerabilities) + return + if len(unneeded_suppressions) > 0: + print_suppressions(unneeded_suppressions) + +def build_parent_json_for_cosmosDB(vulnerabilities, suppressions): + if os.environ.get('ci') != 'True': + print("Not running in CI, skipping parent JSON block") + parent_block = {"suppressed_vulnerabilities": [s.to_json() for s in suppressions], + "unsuppressed_vulnerabilities": [v.to_json() for v in vulnerabilities]} + with open("audit-v4-cosmosdb-output", "w") as file: + file.write(json.dumps(parent_block, indent=2))import json +from dataclasses import dataclass, asdict +import subprocess +import os + +@dataclass +class Vulnerability: + name: str + id: str + severity: str + vulnerable_versions: str + issue: str + url: str + tree_versions: list[str] + dependents: list[str] + + def to_json(self): + return asdict(self) + + def format_vulnerability(self) -> str: + return ( + f"├─ {self.name}\n" + f"│ ├─ ID: {self.id if self.id is not None else 'N/A'}\n" + f"│ ├─ URL: {self.url if self.url is not None else 'N/A'}\n" + f"│ ├─ Issue: {self.issue if self.issue is not None else 'N/A'}\n" + f"│ ├─ Severity: {self.severity if self.severity is not None else 'N/A'}\n" + f"│ ├─ Vulnerable Versions: {self.vulnerable_versions if self.vulnerable_versions is not None else 'N/A'}\n" + f"│ ├─ Tree Versions: {', '.join(self.tree_versions) if self.tree_versions else 'N/A'}\n" + f"│ └─ Dependents: {', '.join(self.dependents) if self.dependents else 'N/A'}" + ) + + def __eq__(self, other): + if isinstance(other, Vulnerability): + return self.id == other.id + # Compare based on id only - allows us to handle situations + # where the other text of the vulnerability changes over time + return False + +def run_audit_command(): + command = ['yarn', 'npm', 'audit', '--recursive', '--environment', 'production', '--json'] + result = subprocess.run(command, capture_output=True, text=True) + # if any errors, print them and exit + if result.stderr != '': + print("Error running command `yarn npm audit --recursive --environment production --json` - Please raise a request in #platops-help. Error: ", repr(result.stderr)) + exit(1) + else: + return result.stdout, result.returncode + +def validate_audit_response(response, exit_code): + if exit_code == 0: + print("No vulnerabilities found, nice work!") + exit(0) + list_of_issues = split_and_strip_json_blocks(response) + print("Found", len(list_of_issues), "vulnerabilities") + if check_json_keys(list_of_issues): + vulnerabilities = build_list_of_issues(list_of_issues) + return vulnerabilities + else: + print("Error parsing JSON returned from audit endpoint - please raise a request in #platops-help") + exit(1) + +def split_and_strip_json_blocks(json_block): + stripped_response = json_block.strip() + list_of_issues = stripped_response.split('\n') + return list_of_issues + +def check_yarn_audit_known_issues(): + if os.path.exists('yarn-audit-known-issues'): + print("Found yarn-audit-known-issues file - checking for suppressed vulnerabilities") + with open('yarn-audit-known-issues') as f: + known_issues_file_content = f.read() + known_issues_stripped = split_and_strip_json_blocks(known_issues_file_content) + if check_json_keys(known_issues_stripped): + known_issues_list = build_list_of_issues(known_issues_stripped) + return known_issues_list + else : + print("Error parsing JSON in your yarn-audit-known-issues file - delete the file and use the following command:") + print("`yarn npm audit --recursive --environment production --json > yarn-audit-known-issues`") + exit(1) + else: + return [] + +def check_json_keys(json_blocks): + try: + for block in json_blocks: + data = json.loads(block) + # Check if both 'value' and 'children' keys are in the JSON block (yarn v4 schema) + if "value" not in data or "children" not in data: + return False + return True + except json.JSONDecodeError: + return False + +def combine_suppressions_and_vulnerabilities(suppressions, vulnerabilities): + # comparison logic is based on the ID of the vulnerability - if the ID is the same, we assume it's the same + # vulnerability + unsuppressed_vulnerabilities = [item for item in vulnerabilities if item not in suppressions] + unneeded_suppressions = [item for item in suppressions if item not in vulnerabilities] + suppressed_active_vulnerabilities = [item for item in vulnerabilities if item in suppressions] + return unsuppressed_vulnerabilities, unneeded_suppressions, suppressed_active_vulnerabilities + + def build_list_of_issues(json_blocks): """ Creates a list of Vulnerability objects from a list of JSON blocks. @@ -159,3 +312,11 @@ def build_parent_json_for_cosmosDB(vulnerabilities, suppressions): unsuppressed_vulnerabilities, unneeded_suppressions, suppressed_active_vulnerabilities = combine_suppressions_and_vulnerabilities(suppressions, vulnerabilities) decide_what_to_print(unsuppressed_vulnerabilities, unneeded_suppressions) build_parent_json_for_cosmosDB(unsuppressed_vulnerabilities, suppressed_active_vulnerabilities) + + +audit_output, return_code = run_audit_command() +vulnerabilities = validate_audit_response(audit_output, return_code) +suppressions = check_yarn_audit_known_issues() +unsuppressed_vulnerabilities, unneeded_suppressions, suppressed_active_vulnerabilities = combine_suppressions_and_vulnerabilities(suppressions, vulnerabilities) +decide_what_to_print(unsuppressed_vulnerabilities, unneeded_suppressions) +build_parent_json_for_cosmosDB(unsuppressed_vulnerabilities, suppressed_active_vulnerabilities) diff --git a/src/uk/gov/hmcts/contino/YarnBuilder.groovy b/src/uk/gov/hmcts/contino/YarnBuilder.groovy index a57f8f602d..bf184d3e4a 100644 --- a/src/uk/gov/hmcts/contino/YarnBuilder.groovy +++ b/src/uk/gov/hmcts/contino/YarnBuilder.groovy @@ -125,10 +125,12 @@ class YarnBuilder extends AbstractBuilder { def yarnVersionCheck() { steps.sh """ - grep '"packageManager":' package.json | cut -d '"' -f 4 > yarn_version + jq -r '.packageManager' package.json | sed 's/yarn@//' > yarn_version """ - def versionString = steps.readFile(yarn_version) + + + def versionString = steps.readFile('yarn_version') def parts = versionString.split("\\.") def major = parts.size() > 0 ? parts[0].toInteger() : 0 def minor = parts.size() > 1 ? parts[1].toInteger() : 0 From 8550a984d389e35dc73683f7c305502330da2089 Mon Sep 17 00:00:00 2001 From: Daniel Furnivall Date: Mon, 27 Nov 2023 13:25:07 +0000 Subject: [PATCH 03/34] fix some shell --- src/uk/gov/hmcts/contino/YarnBuilder.groovy | 1 + 1 file changed, 1 insertion(+) diff --git a/src/uk/gov/hmcts/contino/YarnBuilder.groovy b/src/uk/gov/hmcts/contino/YarnBuilder.groovy index bf184d3e4a..43a56bf902 100644 --- a/src/uk/gov/hmcts/contino/YarnBuilder.groovy +++ b/src/uk/gov/hmcts/contino/YarnBuilder.groovy @@ -131,6 +131,7 @@ class YarnBuilder extends AbstractBuilder { def versionString = steps.readFile('yarn_version') + steps.println(versionString) def parts = versionString.split("\\.") def major = parts.size() > 0 ? parts[0].toInteger() : 0 def minor = parts.size() > 1 ? parts[1].toInteger() : 0 From 7313986e2a83746ac8ca079840e95e557e2ceb3c Mon Sep 17 00:00:00 2001 From: Daniel Furnivall Date: Mon, 27 Nov 2023 13:43:07 +0000 Subject: [PATCH 04/34] more fixes --- src/uk/gov/hmcts/contino/YarnBuilder.groovy | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/uk/gov/hmcts/contino/YarnBuilder.groovy b/src/uk/gov/hmcts/contino/YarnBuilder.groovy index 43a56bf902..2e2c675a98 100644 --- a/src/uk/gov/hmcts/contino/YarnBuilder.groovy +++ b/src/uk/gov/hmcts/contino/YarnBuilder.groovy @@ -128,8 +128,6 @@ class YarnBuilder extends AbstractBuilder { jq -r '.packageManager' package.json | sed 's/yarn@//' > yarn_version """ - - def versionString = steps.readFile('yarn_version') steps.println(versionString) def parts = versionString.split("\\.") @@ -138,19 +136,19 @@ class YarnBuilder extends AbstractBuilder { def patch = parts.size() > 2 ? parts[2].toInteger() : 0 if (major < 3) { - println "Version is less than 3.0.0. This needs updating as we only support 3.0.x upwards." + steps.println("Version is less than 3.0.0. This needs updating as we only support 3.0.x upwards.") return '<3' } else if (major == 3) { - println "v3 detected - continuing" + steps.println("v3 detected - continuing") return 'v3' } else if (major == 4) { if (minor == 0 && patch == 0) { - println "v4.0.0 detected. You will need to upgrade yarn to at least v4.0.1, as 4.0.0 has an unsupported audit format." + steps.println("v4.0.0 detected. You will need to upgrade yarn to at least v4.0.1, as 4.0.0 has an unsupported audit format.") return 'v4.0.0' // todo - handle exit code here } } else { - println "Version is greater than 4.0.0. Using the updated configuration for yarn npm audit." + steps.println("Version is greater than 4.0.0. Using the updated configuration for yarn npm audit.") return 'v4+' } } @@ -158,6 +156,8 @@ class YarnBuilder extends AbstractBuilder { def securityCheck() { version = yarnVersionCheck() + steps.println("escaped version check") + steps.println(version) if (version == 'v3') { try { steps.sh """ From cbc661f7b2d43a7094229223f2097265a2cd676e Mon Sep 17 00:00:00 2001 From: Daniel Furnivall Date: Mon, 27 Nov 2023 13:47:25 +0000 Subject: [PATCH 05/34] more fixes --- src/uk/gov/hmcts/contino/YarnBuilder.groovy | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/uk/gov/hmcts/contino/YarnBuilder.groovy b/src/uk/gov/hmcts/contino/YarnBuilder.groovy index 2e2c675a98..a3b03db5a0 100644 --- a/src/uk/gov/hmcts/contino/YarnBuilder.groovy +++ b/src/uk/gov/hmcts/contino/YarnBuilder.groovy @@ -134,7 +134,9 @@ class YarnBuilder extends AbstractBuilder { def major = parts.size() > 0 ? parts[0].toInteger() : 0 def minor = parts.size() > 1 ? parts[1].toInteger() : 0 def patch = parts.size() > 2 ? parts[2].toInteger() : 0 - + steps.println(major) + steps.println(minor) + steps.println(patch) if (major < 3) { steps.println("Version is less than 3.0.0. This needs updating as we only support 3.0.x upwards.") return '<3' From 08a078295375a0adcbf57a7cc76681431d6dfffe Mon Sep 17 00:00:00 2001 From: Daniel Furnivall Date: Mon, 27 Nov 2023 13:51:36 +0000 Subject: [PATCH 06/34] try block --- src/uk/gov/hmcts/contino/YarnBuilder.groovy | 52 ++++++++++++--------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/src/uk/gov/hmcts/contino/YarnBuilder.groovy b/src/uk/gov/hmcts/contino/YarnBuilder.groovy index a3b03db5a0..53eec0a818 100644 --- a/src/uk/gov/hmcts/contino/YarnBuilder.groovy +++ b/src/uk/gov/hmcts/contino/YarnBuilder.groovy @@ -124,35 +124,41 @@ class YarnBuilder extends AbstractBuilder { } def yarnVersionCheck() { - steps.sh """ + try { + steps.sh """ jq -r '.packageManager' package.json | sed 's/yarn@//' > yarn_version """ - def versionString = steps.readFile('yarn_version') - steps.println(versionString) - def parts = versionString.split("\\.") - def major = parts.size() > 0 ? parts[0].toInteger() : 0 - def minor = parts.size() > 1 ? parts[1].toInteger() : 0 - def patch = parts.size() > 2 ? parts[2].toInteger() : 0 - steps.println(major) - steps.println(minor) - steps.println(patch) - if (major < 3) { - steps.println("Version is less than 3.0.0. This needs updating as we only support 3.0.x upwards.") - return '<3' - } else if (major == 3) { - steps.println("v3 detected - continuing") - return 'v3' - } else if (major == 4) { - if (minor == 0 && patch == 0) { - steps.println("v4.0.0 detected. You will need to upgrade yarn to at least v4.0.1, as 4.0.0 has an unsupported audit format.") - return 'v4.0.0' + def versionString = steps.readFile('yarn_version') + steps.println(versionString) + def parts = versionString.split("\\.") + def major = parts.size() > 0 ? parts[0].toInteger() : 0 + def minor = parts.size() > 1 ? parts[1].toInteger() : 0 + def patch = parts.size() > 2 ? parts[2].toInteger() : 0 + steps.println(major) + steps.println(minor) + steps.println(patch) + if (major < 3) { + steps.println("Version is less than 3.0.0. This needs updating as we only support 3.0.x upwards.") + return '<3' + } else if (major == 3) { + steps.println("v3 detected - continuing") + return 'v3' + } else if (major == 4) { + if (minor == 0 && patch == 0) { + steps.println("v4.0.0 detected. You will need to upgrade yarn to at least v4.0.1, as 4.0.0 has an unsupported audit format.") + return 'v4.0.0' // todo - handle exit code here + } + } else { + steps.println("Version is greater than 4.0.0. Using the updated configuration for yarn npm audit.") + return 'v4+' } - } else { - steps.println("Version is greater than 4.0.0. Using the updated configuration for yarn npm audit.") - return 'v4+' } + catch(Exception e) { + localSteps.echo "Error running version check {e.getMessage()}" + } + } def securityCheck() { From 8d9b80986c221b9be48b30e0fa4d7704e712b3bc Mon Sep 17 00:00:00 2001 From: Daniel Furnivall Date: Mon, 27 Nov 2023 14:01:02 +0000 Subject: [PATCH 07/34] def on version --- src/uk/gov/hmcts/contino/YarnBuilder.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uk/gov/hmcts/contino/YarnBuilder.groovy b/src/uk/gov/hmcts/contino/YarnBuilder.groovy index 53eec0a818..e76b591b4a 100644 --- a/src/uk/gov/hmcts/contino/YarnBuilder.groovy +++ b/src/uk/gov/hmcts/contino/YarnBuilder.groovy @@ -163,7 +163,7 @@ class YarnBuilder extends AbstractBuilder { def securityCheck() { - version = yarnVersionCheck() + def version = yarnVersionCheck() steps.println("escaped version check") steps.println(version) if (version == 'v3') { From 22546df445bdbe991b9825f215baac7f82b04066 Mon Sep 17 00:00:00 2001 From: Daniel Furnivall Date: Mon, 27 Nov 2023 14:22:41 +0000 Subject: [PATCH 08/34] commit --- src/uk/gov/hmcts/contino/YarnBuilder.groovy | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/uk/gov/hmcts/contino/YarnBuilder.groovy b/src/uk/gov/hmcts/contino/YarnBuilder.groovy index e76b591b4a..f924e07766 100644 --- a/src/uk/gov/hmcts/contino/YarnBuilder.groovy +++ b/src/uk/gov/hmcts/contino/YarnBuilder.groovy @@ -135,9 +135,6 @@ class YarnBuilder extends AbstractBuilder { def major = parts.size() > 0 ? parts[0].toInteger() : 0 def minor = parts.size() > 1 ? parts[1].toInteger() : 0 def patch = parts.size() > 2 ? parts[2].toInteger() : 0 - steps.println(major) - steps.println(minor) - steps.println(patch) if (major < 3) { steps.println("Version is less than 3.0.0. This needs updating as we only support 3.0.x upwards.") return '<3' @@ -156,8 +153,9 @@ class YarnBuilder extends AbstractBuilder { } } catch(Exception e) { - localSteps.echo "Error running version check {e.getMessage()}" + steps.echo "Error running version check {e.getMessage()}" } + return "didn't get through if block" } From 0c776da09e76693e8f1f088022c24b7a65837978 Mon Sep 17 00:00:00 2001 From: Daniel Furnivall Date: Mon, 27 Nov 2023 15:57:45 +0000 Subject: [PATCH 09/34] commit --- src/uk/gov/hmcts/contino/YarnBuilder.groovy | 1 + 1 file changed, 1 insertion(+) diff --git a/src/uk/gov/hmcts/contino/YarnBuilder.groovy b/src/uk/gov/hmcts/contino/YarnBuilder.groovy index f924e07766..715cc27164 100644 --- a/src/uk/gov/hmcts/contino/YarnBuilder.groovy +++ b/src/uk/gov/hmcts/contino/YarnBuilder.groovy @@ -135,6 +135,7 @@ class YarnBuilder extends AbstractBuilder { def major = parts.size() > 0 ? parts[0].toInteger() : 0 def minor = parts.size() > 1 ? parts[1].toInteger() : 0 def patch = parts.size() > 2 ? parts[2].toInteger() : 0 + steps.println(major.getClass()) if (major < 3) { steps.println("Version is less than 3.0.0. This needs updating as we only support 3.0.x upwards.") return '<3' From 0fa9aed21d1bd084f56d4085c5cd5645768a1f17 Mon Sep 17 00:00:00 2001 From: Daniel Furnivall Date: Mon, 27 Nov 2023 16:04:04 +0000 Subject: [PATCH 10/34] switch quote type --- src/uk/gov/hmcts/contino/YarnBuilder.groovy | 25 ++++++++++++--------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/uk/gov/hmcts/contino/YarnBuilder.groovy b/src/uk/gov/hmcts/contino/YarnBuilder.groovy index 715cc27164..5cebc2ade2 100644 --- a/src/uk/gov/hmcts/contino/YarnBuilder.groovy +++ b/src/uk/gov/hmcts/contino/YarnBuilder.groovy @@ -138,19 +138,22 @@ class YarnBuilder extends AbstractBuilder { steps.println(major.getClass()) if (major < 3) { steps.println("Version is less than 3.0.0. This needs updating as we only support 3.0.x upwards.") - return '<3' - } else if (major == 3) { - steps.println("v3 detected - continuing") - return 'v3' - } else if (major == 4) { - if (minor == 0 && patch == 0) { - steps.println("v4.0.0 detected. You will need to upgrade yarn to at least v4.0.1, as 4.0.0 has an unsupported audit format.") - return 'v4.0.0' + return "<3" + } else { + if (major == 3) { + steps.println("v3 detected - continuing") + return "v3" + } + if (major == 4) { + if (minor == 0 && patch == 0) { + steps.println("v4.0.0 detected. You will need to upgrade yarn to at least v4.0.1, as 4.0.0 has an unsupported audit format.") + return "v4.0.0" // todo - handle exit code here + } + } else { + steps.println("Version is greater than 4.0.0. Using the updated configuration for yarn npm audit.") + return "v4+" } - } else { - steps.println("Version is greater than 4.0.0. Using the updated configuration for yarn npm audit.") - return 'v4+' } } catch(Exception e) { From fd8de07aff45840fe2fc21650c6f964ef66beac2 Mon Sep 17 00:00:00 2001 From: Daniel Furnivall Date: Mon, 27 Nov 2023 16:09:23 +0000 Subject: [PATCH 11/34] man i'm dumb --- src/uk/gov/hmcts/contino/YarnBuilder.groovy | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/uk/gov/hmcts/contino/YarnBuilder.groovy b/src/uk/gov/hmcts/contino/YarnBuilder.groovy index 5cebc2ade2..144e3d4018 100644 --- a/src/uk/gov/hmcts/contino/YarnBuilder.groovy +++ b/src/uk/gov/hmcts/contino/YarnBuilder.groovy @@ -135,22 +135,24 @@ class YarnBuilder extends AbstractBuilder { def major = parts.size() > 0 ? parts[0].toInteger() : 0 def minor = parts.size() > 1 ? parts[1].toInteger() : 0 def patch = parts.size() > 2 ? parts[2].toInteger() : 0 - steps.println(major.getClass()) + steps.println(major.getClass() + minor.getClass() + patch.getClass()) if (major < 3) { steps.println("Version is less than 3.0.0. This needs updating as we only support 3.0.x upwards.") return "<3" - } else { - if (major == 3) { + } + + if (major == 3) { steps.println("v3 detected - continuing") return "v3" } - if (major == 4) { + if (major == 4) { if (minor == 0 && patch == 0) { steps.println("v4.0.0 detected. You will need to upgrade yarn to at least v4.0.1, as 4.0.0 has an unsupported audit format.") return "v4.0.0" // todo - handle exit code here } - } else { + } + else { steps.println("Version is greater than 4.0.0. Using the updated configuration for yarn npm audit.") return "v4+" } From 8a1909e669550cfe3275c274d9f568301c879ff1 Mon Sep 17 00:00:00 2001 From: Daniel Furnivall Date: Mon, 27 Nov 2023 16:10:24 +0000 Subject: [PATCH 12/34] dumb error --- src/uk/gov/hmcts/contino/YarnBuilder.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uk/gov/hmcts/contino/YarnBuilder.groovy b/src/uk/gov/hmcts/contino/YarnBuilder.groovy index 144e3d4018..f9b4200179 100644 --- a/src/uk/gov/hmcts/contino/YarnBuilder.groovy +++ b/src/uk/gov/hmcts/contino/YarnBuilder.groovy @@ -157,7 +157,7 @@ class YarnBuilder extends AbstractBuilder { return "v4+" } } - } + catch(Exception e) { steps.echo "Error running version check {e.getMessage()}" } From dca51db5d6110a8c5e7f6d17d8b675c2fdad0bd9 Mon Sep 17 00:00:00 2001 From: Daniel Furnivall Date: Mon, 27 Nov 2023 16:22:49 +0000 Subject: [PATCH 13/34] better catch block --- src/uk/gov/hmcts/contino/YarnBuilder.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uk/gov/hmcts/contino/YarnBuilder.groovy b/src/uk/gov/hmcts/contino/YarnBuilder.groovy index f9b4200179..a9d5e5b6ae 100644 --- a/src/uk/gov/hmcts/contino/YarnBuilder.groovy +++ b/src/uk/gov/hmcts/contino/YarnBuilder.groovy @@ -159,7 +159,7 @@ class YarnBuilder extends AbstractBuilder { } catch(Exception e) { - steps.echo "Error running version check {e.getMessage()}" + steps.echo e.getMessage() } return "didn't get through if block" From 065cdd34d318df8500c585e36ae576de19685157 Mon Sep 17 00:00:00 2001 From: Daniel Furnivall Date: Mon, 27 Nov 2023 16:27:21 +0000 Subject: [PATCH 14/34] attempt to find this bloody exception --- src/uk/gov/hmcts/contino/YarnBuilder.groovy | 1 - 1 file changed, 1 deletion(-) diff --git a/src/uk/gov/hmcts/contino/YarnBuilder.groovy b/src/uk/gov/hmcts/contino/YarnBuilder.groovy index a9d5e5b6ae..22f12db844 100644 --- a/src/uk/gov/hmcts/contino/YarnBuilder.groovy +++ b/src/uk/gov/hmcts/contino/YarnBuilder.groovy @@ -135,7 +135,6 @@ class YarnBuilder extends AbstractBuilder { def major = parts.size() > 0 ? parts[0].toInteger() : 0 def minor = parts.size() > 1 ? parts[1].toInteger() : 0 def patch = parts.size() > 2 ? parts[2].toInteger() : 0 - steps.println(major.getClass() + minor.getClass() + patch.getClass()) if (major < 3) { steps.println("Version is less than 3.0.0. This needs updating as we only support 3.0.x upwards.") return "<3" From 0aab964f83cb12bd07a56c889c6e80f1f812f67e Mon Sep 17 00:00:00 2001 From: Daniel Furnivall Date: Mon, 27 Nov 2023 16:31:50 +0000 Subject: [PATCH 15/34] attempt to find this bloody exception --- src/uk/gov/hmcts/contino/YarnBuilder.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uk/gov/hmcts/contino/YarnBuilder.groovy b/src/uk/gov/hmcts/contino/YarnBuilder.groovy index 22f12db844..ff45954408 100644 --- a/src/uk/gov/hmcts/contino/YarnBuilder.groovy +++ b/src/uk/gov/hmcts/contino/YarnBuilder.groovy @@ -160,7 +160,7 @@ class YarnBuilder extends AbstractBuilder { catch(Exception e) { steps.echo e.getMessage() } - return "didn't get through if block" + return major.toString() } From e826fee12b9ea048b051a81b25c34138680063e5 Mon Sep 17 00:00:00 2001 From: Daniel Furnivall Date: Mon, 27 Nov 2023 16:40:32 +0000 Subject: [PATCH 16/34] help --- src/uk/gov/hmcts/contino/YarnBuilder.groovy | 54 +++++++++++---------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/src/uk/gov/hmcts/contino/YarnBuilder.groovy b/src/uk/gov/hmcts/contino/YarnBuilder.groovy index ff45954408..4ccaffa4fc 100644 --- a/src/uk/gov/hmcts/contino/YarnBuilder.groovy +++ b/src/uk/gov/hmcts/contino/YarnBuilder.groovy @@ -124,46 +124,48 @@ class YarnBuilder extends AbstractBuilder { } def yarnVersionCheck() { + def major = 0 + def minor = 0 + def patch = 0 + try { steps.sh """ - jq -r '.packageManager' package.json | sed 's/yarn@//' > yarn_version - """ + jq -r '.packageManager' package.json | sed 's/yarn@//' > yarn_version + """ - def versionString = steps.readFile('yarn_version') + def versionString = steps.readFile('yarn_version').trim() steps.println(versionString) + def parts = versionString.split("\\.") - def major = parts.size() > 0 ? parts[0].toInteger() : 0 - def minor = parts.size() > 1 ? parts[1].toInteger() : 0 - def patch = parts.size() > 2 ? parts[2].toInteger() : 0 + major = parts.size() > 0 ? parts[0].toInteger() : major + minor = parts.size() > 1 ? parts[1].toInteger() : minor + patch = parts.size() > 2 ? parts[2].toInteger() : patch + if (major < 3) { steps.println("Version is less than 3.0.0. This needs updating as we only support 3.0.x upwards.") return "<3" - } - - if (major == 3) { - steps.println("v3 detected - continuing") - return "v3" - } - if (major == 4) { - if (minor == 0 && patch == 0) { - steps.println("v4.0.0 detected. You will need to upgrade yarn to at least v4.0.1, as 4.0.0 has an unsupported audit format.") - return "v4.0.0" -// todo - handle exit code here - } - } - else { - steps.println("Version is greater than 4.0.0. Using the updated configuration for yarn npm audit.") - return "v4+" + } else if (major == 3) { + steps.println("v3 detected - continuing") + return "v3" + } else if (major == 4) { + if (minor == 0 && patch == 0) { + steps.println("v4.0.0 detected. You will need to upgrade yarn to at least v4.0.1, as 4.0.0 has an unsupported audit format.") + return "v4.0.0" + } else { + steps.println("Version is v4.0.1 or higher.") + return "v4.0.1+" } + } else { + steps.println("Version is greater than 4.0.0. Using the updated configuration for yarn npm audit.") + return "v4+" } - - catch(Exception e) { + } catch (Exception e) { steps.echo e.getMessage() + return "error" } - return major.toString() - } + def securityCheck() { def version = yarnVersionCheck() From c3c1d2e596a773541a1937cb278acdc9a67bd15c Mon Sep 17 00:00:00 2001 From: Daniel Furnivall Date: Mon, 27 Nov 2023 16:43:41 +0000 Subject: [PATCH 17/34] should maybe reach the python now? --- src/uk/gov/hmcts/contino/YarnBuilder.groovy | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/uk/gov/hmcts/contino/YarnBuilder.groovy b/src/uk/gov/hmcts/contino/YarnBuilder.groovy index 4ccaffa4fc..6ccf619131 100644 --- a/src/uk/gov/hmcts/contino/YarnBuilder.groovy +++ b/src/uk/gov/hmcts/contino/YarnBuilder.groovy @@ -215,22 +215,26 @@ class YarnBuilder extends AbstractBuilder { // todo : handle } - else if (version == 'v4+') { + else if (version == 'v4.0.1+') { securityCheckYarnV4() } } def securityCheckYarnV4() { steps.writeFile(file: 'yarnv4audit.py', text: steps.libraryResource('uk/gov/hmcts/pipeline/yarn/yarnv4audit.py')) - - steps.sh """ + try { + steps.sh """ export PATH=\$HOME/.local/bin:\$PATH chmod +x yarnv4audit.py ./yarnv4audit.py """ - steps.sh """ + steps.sh """ cat audit-v4-cosmosdb-output """ + } + catch(Exception e) { + steps.println(e) + } } @Override From fedfe98c5a1a80fc8b8e28bdae72ce6255cbb1ff Mon Sep 17 00:00:00 2001 From: Daniel Furnivall Date: Mon, 27 Nov 2023 16:46:29 +0000 Subject: [PATCH 18/34] no i'm still dumb --- src/uk/gov/hmcts/contino/YarnBuilder.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uk/gov/hmcts/contino/YarnBuilder.groovy b/src/uk/gov/hmcts/contino/YarnBuilder.groovy index 6ccf619131..c035de0a0f 100644 --- a/src/uk/gov/hmcts/contino/YarnBuilder.groovy +++ b/src/uk/gov/hmcts/contino/YarnBuilder.groovy @@ -226,7 +226,7 @@ class YarnBuilder extends AbstractBuilder { steps.sh """ export PATH=\$HOME/.local/bin:\$PATH chmod +x yarnv4audit.py - ./yarnv4audit.py + python3 yarnv4audit.py """ steps.sh """ cat audit-v4-cosmosdb-output From 3627844190d5ae9967a8bae60575f95c6968bbb8 Mon Sep 17 00:00:00 2001 From: Daniel Furnivall Date: Mon, 27 Nov 2023 16:49:55 +0000 Subject: [PATCH 19/34] attempt with python instead of python3 --- src/uk/gov/hmcts/contino/YarnBuilder.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uk/gov/hmcts/contino/YarnBuilder.groovy b/src/uk/gov/hmcts/contino/YarnBuilder.groovy index c035de0a0f..f95217b86a 100644 --- a/src/uk/gov/hmcts/contino/YarnBuilder.groovy +++ b/src/uk/gov/hmcts/contino/YarnBuilder.groovy @@ -226,7 +226,7 @@ class YarnBuilder extends AbstractBuilder { steps.sh """ export PATH=\$HOME/.local/bin:\$PATH chmod +x yarnv4audit.py - python3 yarnv4audit.py + python yarnv4audit.py """ steps.sh """ cat audit-v4-cosmosdb-output From d65a7381bf5aeea279c9075318054df170f9aca6 Mon Sep 17 00:00:00 2001 From: Daniel Furnivall Date: Mon, 27 Nov 2023 17:19:39 +0000 Subject: [PATCH 20/34] never mind i'm dumb as a rock --- resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py b/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py index 6a9642cf35..bd0e2fddb4 100644 --- a/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py +++ b/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py @@ -151,7 +151,7 @@ def build_parent_json_for_cosmosDB(vulnerabilities, suppressions): parent_block = {"suppressed_vulnerabilities": [s.to_json() for s in suppressions], "unsuppressed_vulnerabilities": [v.to_json() for v in vulnerabilities]} with open("audit-v4-cosmosdb-output", "w") as file: - file.write(json.dumps(parent_block, indent=2))import json + file.write(json.dumps(parent_block, indent=2)) from dataclasses import dataclass, asdict import subprocess import os From 8164712a3732ab9a0a328bdac69908d1f10af0cf Mon Sep 17 00:00:00 2001 From: Daniel Furnivall Date: Mon, 27 Nov 2023 17:31:15 +0000 Subject: [PATCH 21/34] python3 --- src/uk/gov/hmcts/contino/YarnBuilder.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uk/gov/hmcts/contino/YarnBuilder.groovy b/src/uk/gov/hmcts/contino/YarnBuilder.groovy index f95217b86a..c035de0a0f 100644 --- a/src/uk/gov/hmcts/contino/YarnBuilder.groovy +++ b/src/uk/gov/hmcts/contino/YarnBuilder.groovy @@ -226,7 +226,7 @@ class YarnBuilder extends AbstractBuilder { steps.sh """ export PATH=\$HOME/.local/bin:\$PATH chmod +x yarnv4audit.py - python yarnv4audit.py + python3 yarnv4audit.py """ steps.sh """ cat audit-v4-cosmosdb-output From b42563ab0ba00a55b2b1a15295b8d0dab56a7128 Mon Sep 17 00:00:00 2001 From: Daniel Furnivall Date: Mon, 27 Nov 2023 17:35:39 +0000 Subject: [PATCH 22/34] i am so spectacularly dumb --- .../uk/gov/hmcts/pipeline/yarn/yarnv4audit.py | 161 ------------------ src/uk/gov/hmcts/contino/YarnBuilder.groovy | 1 + 2 files changed, 1 insertion(+), 161 deletions(-) diff --git a/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py b/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py index bd0e2fddb4..5ad93443b3 100644 --- a/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py +++ b/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py @@ -152,167 +152,6 @@ def build_parent_json_for_cosmosDB(vulnerabilities, suppressions): "unsuppressed_vulnerabilities": [v.to_json() for v in vulnerabilities]} with open("audit-v4-cosmosdb-output", "w") as file: file.write(json.dumps(parent_block, indent=2)) -from dataclasses import dataclass, asdict -import subprocess -import os - -@dataclass -class Vulnerability: - name: str - id: str - severity: str - vulnerable_versions: str - issue: str - url: str - tree_versions: list[str] - dependents: list[str] - - def to_json(self): - return asdict(self) - - def format_vulnerability(self) -> str: - return ( - f"├─ {self.name}\n" - f"│ ├─ ID: {self.id if self.id is not None else 'N/A'}\n" - f"│ ├─ URL: {self.url if self.url is not None else 'N/A'}\n" - f"│ ├─ Issue: {self.issue if self.issue is not None else 'N/A'}\n" - f"│ ├─ Severity: {self.severity if self.severity is not None else 'N/A'}\n" - f"│ ├─ Vulnerable Versions: {self.vulnerable_versions if self.vulnerable_versions is not None else 'N/A'}\n" - f"│ ├─ Tree Versions: {', '.join(self.tree_versions) if self.tree_versions else 'N/A'}\n" - f"│ └─ Dependents: {', '.join(self.dependents) if self.dependents else 'N/A'}" - ) - - def __eq__(self, other): - if isinstance(other, Vulnerability): - return self.id == other.id - # Compare based on id only - allows us to handle situations - # where the other text of the vulnerability changes over time - return False - -def run_audit_command(): - command = ['yarn', 'npm', 'audit', '--recursive', '--environment', 'production', '--json'] - result = subprocess.run(command, capture_output=True, text=True) - # if any errors, print them and exit - if result.stderr != '': - print("Error running command `yarn npm audit --recursive --environment production --json` - Please raise a request in #platops-help. Error: ", repr(result.stderr)) - exit(1) - else: - return result.stdout, result.returncode - -def validate_audit_response(response, exit_code): - if exit_code == 0: - print("No vulnerabilities found, nice work!") - exit(0) - list_of_issues = split_and_strip_json_blocks(response) - print("Found", len(list_of_issues), "vulnerabilities") - if check_json_keys(list_of_issues): - vulnerabilities = build_list_of_issues(list_of_issues) - return vulnerabilities - else: - print("Error parsing JSON returned from audit endpoint - please raise a request in #platops-help") - exit(1) - -def split_and_strip_json_blocks(json_block): - stripped_response = json_block.strip() - list_of_issues = stripped_response.split('\n') - return list_of_issues - -def check_yarn_audit_known_issues(): - if os.path.exists('yarn-audit-known-issues'): - print("Found yarn-audit-known-issues file - checking for suppressed vulnerabilities") - with open('yarn-audit-known-issues') as f: - known_issues_file_content = f.read() - known_issues_stripped = split_and_strip_json_blocks(known_issues_file_content) - if check_json_keys(known_issues_stripped): - known_issues_list = build_list_of_issues(known_issues_stripped) - return known_issues_list - else : - print("Error parsing JSON in your yarn-audit-known-issues file - delete the file and use the following command:") - print("`yarn npm audit --recursive --environment production --json > yarn-audit-known-issues`") - exit(1) - else: - return [] - -def check_json_keys(json_blocks): - try: - for block in json_blocks: - data = json.loads(block) - # Check if both 'value' and 'children' keys are in the JSON block (yarn v4 schema) - if "value" not in data or "children" not in data: - return False - return True - except json.JSONDecodeError: - return False - -def combine_suppressions_and_vulnerabilities(suppressions, vulnerabilities): - # comparison logic is based on the ID of the vulnerability - if the ID is the same, we assume it's the same - # vulnerability - unsuppressed_vulnerabilities = [item for item in vulnerabilities if item not in suppressions] - unneeded_suppressions = [item for item in suppressions if item not in vulnerabilities] - suppressed_active_vulnerabilities = [item for item in vulnerabilities if item in suppressions] - return unsuppressed_vulnerabilities, unneeded_suppressions, suppressed_active_vulnerabilities - - -def build_list_of_issues(json_blocks): - """ - Creates a list of Vulnerability objects from a list of JSON blocks. - Each JSON block is parsed once and then used to construct a Vulnerability object. - - :param json_blocks: A list of JSON strings. - :return: A list of Vulnerability objects. - """ - vulnerabilities = [] - for block in json_blocks: - parsed_data = json.loads(block) - vuln = Vulnerability( - name=parsed_data.get('value'), - id=parsed_data.get('children', {}).get('ID'), - issue=parsed_data.get('children', {}).get('Issue'), - url=parsed_data.get('children', {}).get('URL'), - severity=parsed_data.get('children', {}).get('Severity'), - vulnerable_versions=parsed_data.get('children', {}).get('Vulnerable Versions'), - tree_versions=parsed_data.get('children', {}).get('Tree Versions', []), - dependents=parsed_data.get('children', {}).get('Dependents', []) - ) - vulnerabilities.append(vuln) - return vulnerabilities - -def print_vulnerabilities(vulnerabilities): - print("Found", len(vulnerabilities), "active vulnerabilities, please fix these before pushing again.") - for vulnerability in vulnerabilities: - print(vulnerability.format_vulnerability()) - -def print_suppressions(suppressions): - print("Found", len(suppressions), "unnecessary suppression(s), please check these are still needed." - "If not, please remove them from your yarn-audit-known-issues file") - for suppression in suppressions: - print(suppression.format_vulnerability()) - -def decide_what_to_print(unsuppressed_vulnerabilities, unneeded_suppressions): - if len(unsuppressed_vulnerabilities) == 0 and len(unneeded_suppressions) == 0: - print("All vulnerabilities are suppressed and there are no unneeded_suppressions - no action required, nice work!") - return - if len(unsuppressed_vulnerabilities) > 0: - print_vulnerabilities(unsuppressed_vulnerabilities) - return - if len(unneeded_suppressions) > 0: - print_suppressions(unneeded_suppressions) - -def build_parent_json_for_cosmosDB(vulnerabilities, suppressions): - if os.environ.get('ci') != 'True': - print("Not running in CI, skipping parent JSON block") - parent_block = {"suppressed_vulnerabilities": [s.to_json() for s in suppressions], - "unsuppressed_vulnerabilities": [v.to_json() for v in vulnerabilities]} - with open("audit-v4-cosmosdb-output", "w") as file: - file.write(json.dumps(parent_block, indent=2)) - -audit_output, return_code = run_audit_command() -vulnerabilities = validate_audit_response(audit_output, return_code) -suppressions = check_yarn_audit_known_issues() -unsuppressed_vulnerabilities, unneeded_suppressions, suppressed_active_vulnerabilities = combine_suppressions_and_vulnerabilities(suppressions, vulnerabilities) -decide_what_to_print(unsuppressed_vulnerabilities, unneeded_suppressions) -build_parent_json_for_cosmosDB(unsuppressed_vulnerabilities, suppressed_active_vulnerabilities) - audit_output, return_code = run_audit_command() vulnerabilities = validate_audit_response(audit_output, return_code) diff --git a/src/uk/gov/hmcts/contino/YarnBuilder.groovy b/src/uk/gov/hmcts/contino/YarnBuilder.groovy index c035de0a0f..d981b93fda 100644 --- a/src/uk/gov/hmcts/contino/YarnBuilder.groovy +++ b/src/uk/gov/hmcts/contino/YarnBuilder.groovy @@ -226,6 +226,7 @@ class YarnBuilder extends AbstractBuilder { steps.sh """ export PATH=\$HOME/.local/bin:\$PATH chmod +x yarnv4audit.py + python3 --version python3 yarnv4audit.py """ steps.sh """ From d45a8b1f7933d0fa9185ca57c239b60afbfa9ee6 Mon Sep 17 00:00:00 2001 From: Daniel Furnivall Date: Mon, 27 Nov 2023 17:43:19 +0000 Subject: [PATCH 23/34] 3.8/9 change for typing module --- resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py b/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py index 5ad93443b3..e57fabf4a4 100644 --- a/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py +++ b/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py @@ -2,6 +2,7 @@ from dataclasses import dataclass, asdict import subprocess import os +import typing @dataclass class Vulnerability: @@ -11,8 +12,8 @@ class Vulnerability: vulnerable_versions: str issue: str url: str - tree_versions: list[str] - dependents: list[str] + tree_versions: List[str] + dependents: List[str] def to_json(self): return asdict(self) From 39481ab2801b3f992464d9a84ba21a41d9c86902 Mon Sep 17 00:00:00 2001 From: Daniel Furnivall Date: Mon, 27 Nov 2023 17:45:48 +0000 Subject: [PATCH 24/34] one more beep --- resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py b/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py index e57fabf4a4..a8ce9ad1ae 100644 --- a/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py +++ b/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py @@ -2,7 +2,7 @@ from dataclasses import dataclass, asdict import subprocess import os -import typing +from typing import List @dataclass class Vulnerability: From 0f151177823fccf17cff54574388d75d8cb40db3 Mon Sep 17 00:00:00 2001 From: Daniel Furnivall Date: Mon, 27 Nov 2023 18:07:27 +0000 Subject: [PATCH 25/34] from typing import List --- resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py b/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py index a8ce9ad1ae..508e757f2a 100644 --- a/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py +++ b/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py @@ -7,7 +7,7 @@ @dataclass class Vulnerability: name: str - id: str + id: st severity: str vulnerable_versions: str issue: str From 3152566242ac48f306d0d170d59cc0967caf094e Mon Sep 17 00:00:00 2001 From: Daniel Furnivall Date: Mon, 27 Nov 2023 18:09:21 +0000 Subject: [PATCH 26/34] why is everything i'm doing so stupid --- resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py b/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py index 508e757f2a..a8ce9ad1ae 100644 --- a/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py +++ b/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py @@ -7,7 +7,7 @@ @dataclass class Vulnerability: name: str - id: st + id: str severity: str vulnerable_versions: str issue: str From 325e59a539d663b73af4387237daa2486887c1be Mon Sep 17 00:00:00 2001 From: Daniel Furnivall Date: Tue, 28 Nov 2023 11:20:29 +0000 Subject: [PATCH 27/34] 3.10 --- src/uk/gov/hmcts/contino/YarnBuilder.groovy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/uk/gov/hmcts/contino/YarnBuilder.groovy b/src/uk/gov/hmcts/contino/YarnBuilder.groovy index d981b93fda..5e4e2567e3 100644 --- a/src/uk/gov/hmcts/contino/YarnBuilder.groovy +++ b/src/uk/gov/hmcts/contino/YarnBuilder.groovy @@ -226,8 +226,8 @@ class YarnBuilder extends AbstractBuilder { steps.sh """ export PATH=\$HOME/.local/bin:\$PATH chmod +x yarnv4audit.py - python3 --version - python3 yarnv4audit.py + python3.10 --version + python3.10 yarnv4audit.py """ steps.sh """ cat audit-v4-cosmosdb-output From 02ea7d4d8c8f9614dfd4a123c2b4eaa6f07ec841 Mon Sep 17 00:00:00 2001 From: Daniel Furnivall Date: Fri, 1 Dec 2023 10:42:35 +0000 Subject: [PATCH 28/34] test infinity --- resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py b/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py index a8ce9ad1ae..5ad93443b3 100644 --- a/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py +++ b/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py @@ -2,7 +2,6 @@ from dataclasses import dataclass, asdict import subprocess import os -from typing import List @dataclass class Vulnerability: @@ -12,8 +11,8 @@ class Vulnerability: vulnerable_versions: str issue: str url: str - tree_versions: List[str] - dependents: List[str] + tree_versions: list[str] + dependents: list[str] def to_json(self): return asdict(self) From 035bf7b2dbb4e71cfd917b3ee1786c48434cf5cc Mon Sep 17 00:00:00 2001 From: Daniel Furnivall Date: Fri, 1 Dec 2023 10:44:08 +0000 Subject: [PATCH 29/34] exit code for fail --- resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py b/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py index 5ad93443b3..a596446e64 100644 --- a/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py +++ b/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py @@ -159,3 +159,5 @@ def build_parent_json_for_cosmosDB(vulnerabilities, suppressions): unsuppressed_vulnerabilities, unneeded_suppressions, suppressed_active_vulnerabilities = combine_suppressions_and_vulnerabilities(suppressions, vulnerabilities) decide_what_to_print(unsuppressed_vulnerabilities, unneeded_suppressions) build_parent_json_for_cosmosDB(unsuppressed_vulnerabilities, suppressed_active_vulnerabilities) +if len(unsuppressed_vulnerabilities) > 0: + exit(1) From 80abcbdcd56001517d430d6b2829af0d657e322c Mon Sep 17 00:00:00 2001 From: Daniel Furnivall Date: Tue, 5 Dec 2023 14:33:43 +0000 Subject: [PATCH 30/34] attempt to look at CI variable --- resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py | 3 ++- src/uk/gov/hmcts/contino/YarnBuilder.groovy | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py b/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py index a596446e64..171b8090d3 100644 --- a/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py +++ b/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py @@ -146,7 +146,8 @@ def decide_what_to_print(unsuppressed_vulnerabilities, unneeded_suppressions): print_suppressions(unneeded_suppressions) def build_parent_json_for_cosmosDB(vulnerabilities, suppressions): - if os.environ.get('ci') != 'True': + print(f'CI value: {os.environ.get("CI")}') + if os.environ.get('CI') != True: print("Not running in CI, skipping parent JSON block") parent_block = {"suppressed_vulnerabilities": [s.to_json() for s in suppressions], "unsuppressed_vulnerabilities": [v.to_json() for v in vulnerabilities]} diff --git a/src/uk/gov/hmcts/contino/YarnBuilder.groovy b/src/uk/gov/hmcts/contino/YarnBuilder.groovy index 5e4e2567e3..d981b93fda 100644 --- a/src/uk/gov/hmcts/contino/YarnBuilder.groovy +++ b/src/uk/gov/hmcts/contino/YarnBuilder.groovy @@ -226,8 +226,8 @@ class YarnBuilder extends AbstractBuilder { steps.sh """ export PATH=\$HOME/.local/bin:\$PATH chmod +x yarnv4audit.py - python3.10 --version - python3.10 yarnv4audit.py + python3 --version + python3 yarnv4audit.py """ steps.sh """ cat audit-v4-cosmosdb-output From 3a69909518b1f656fa9835caede4b7b6158b1318 Mon Sep 17 00:00:00 2001 From: Daniel Furnivall Date: Tue, 5 Dec 2023 14:52:04 +0000 Subject: [PATCH 31/34] 3.10 again --- src/uk/gov/hmcts/contino/YarnBuilder.groovy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/uk/gov/hmcts/contino/YarnBuilder.groovy b/src/uk/gov/hmcts/contino/YarnBuilder.groovy index d981b93fda..5e4e2567e3 100644 --- a/src/uk/gov/hmcts/contino/YarnBuilder.groovy +++ b/src/uk/gov/hmcts/contino/YarnBuilder.groovy @@ -226,8 +226,8 @@ class YarnBuilder extends AbstractBuilder { steps.sh """ export PATH=\$HOME/.local/bin:\$PATH chmod +x yarnv4audit.py - python3 --version - python3 yarnv4audit.py + python3.10 --version + python3.10 yarnv4audit.py """ steps.sh """ cat audit-v4-cosmosdb-output From b764d1f3204b33b07d2d587f4c7a207f077036cc Mon Sep 17 00:00:00 2001 From: Daniel Furnivall Date: Tue, 5 Dec 2023 15:28:57 +0000 Subject: [PATCH 32/34] removed errant try/catch blocks --- resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py | 3 +-- src/uk/gov/hmcts/contino/YarnBuilder.groovy | 5 ----- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py b/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py index 171b8090d3..925e332dc3 100644 --- a/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py +++ b/resources/uk/gov/hmcts/pipeline/yarn/yarnv4audit.py @@ -146,8 +146,7 @@ def decide_what_to_print(unsuppressed_vulnerabilities, unneeded_suppressions): print_suppressions(unneeded_suppressions) def build_parent_json_for_cosmosDB(vulnerabilities, suppressions): - print(f'CI value: {os.environ.get("CI")}') - if os.environ.get('CI') != True: + if os.environ.get('CI') != 'true': print("Not running in CI, skipping parent JSON block") parent_block = {"suppressed_vulnerabilities": [s.to_json() for s in suppressions], "unsuppressed_vulnerabilities": [v.to_json() for v in vulnerabilities]} diff --git a/src/uk/gov/hmcts/contino/YarnBuilder.groovy b/src/uk/gov/hmcts/contino/YarnBuilder.groovy index 5e4e2567e3..2e4f9268e8 100644 --- a/src/uk/gov/hmcts/contino/YarnBuilder.groovy +++ b/src/uk/gov/hmcts/contino/YarnBuilder.groovy @@ -222,7 +222,6 @@ class YarnBuilder extends AbstractBuilder { def securityCheckYarnV4() { steps.writeFile(file: 'yarnv4audit.py', text: steps.libraryResource('uk/gov/hmcts/pipeline/yarn/yarnv4audit.py')) - try { steps.sh """ export PATH=\$HOME/.local/bin:\$PATH chmod +x yarnv4audit.py @@ -233,10 +232,6 @@ class YarnBuilder extends AbstractBuilder { cat audit-v4-cosmosdb-output """ } - catch(Exception e) { - steps.println(e) - } - } @Override def techStackMaintenance() { From 9bc4d821c623abd32057a4f066a6f9afe51ff424 Mon Sep 17 00:00:00 2001 From: Daniel Furnivall Date: Tue, 5 Dec 2023 15:57:23 +0000 Subject: [PATCH 33/34] attempt to get cvereport --- src/uk/gov/hmcts/contino/YarnBuilder.groovy | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/uk/gov/hmcts/contino/YarnBuilder.groovy b/src/uk/gov/hmcts/contino/YarnBuilder.groovy index 2e4f9268e8..ddb632db74 100644 --- a/src/uk/gov/hmcts/contino/YarnBuilder.groovy +++ b/src/uk/gov/hmcts/contino/YarnBuilder.groovy @@ -228,9 +228,8 @@ class YarnBuilder extends AbstractBuilder { python3.10 --version python3.10 yarnv4audit.py """ - steps.sh """ - cat audit-v4-cosmosdb-output - """ + LinkedHashMap CVEReport = prepareCVEReportYarn4('audit-v4-cosmosdb-output') + this.steps.echo CVEReport.toString() } @Override @@ -250,6 +249,14 @@ class YarnBuilder extends AbstractBuilder { } } + def prepareCVEReportYarn4(String inputFilePath) { + String jsonString = new File(inputFilePath) + JsonSlurper slurper = new JsonSlurper() + LinkedHashMap parsedData = slurper.parseText(jsonString) + return parsedData + } + + def prepareCVEReport(String issues, String knownIssues) { def jsonSlurper = new JsonSlurper() From 6dd487e8871f4530a5b1f4b126e2dc0a21b8b9eb Mon Sep 17 00:00:00 2001 From: Daniel Furnivall Date: Tue, 5 Dec 2023 16:04:30 +0000 Subject: [PATCH 34/34] try/finally --- src/uk/gov/hmcts/contino/YarnBuilder.groovy | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/uk/gov/hmcts/contino/YarnBuilder.groovy b/src/uk/gov/hmcts/contino/YarnBuilder.groovy index ddb632db74..6c0a25e97c 100644 --- a/src/uk/gov/hmcts/contino/YarnBuilder.groovy +++ b/src/uk/gov/hmcts/contino/YarnBuilder.groovy @@ -169,8 +169,6 @@ class YarnBuilder extends AbstractBuilder { def securityCheck() { def version = yarnVersionCheck() - steps.println("escaped version check") - steps.println(version) if (version == 'v3') { try { steps.sh """ @@ -221,16 +219,20 @@ class YarnBuilder extends AbstractBuilder { } def securityCheckYarnV4() { - steps.writeFile(file: 'yarnv4audit.py', text: steps.libraryResource('uk/gov/hmcts/pipeline/yarn/yarnv4audit.py')) + try { + steps.writeFile(file: 'yarnv4audit.py', text: steps.libraryResource('uk/gov/hmcts/pipeline/yarn/yarnv4audit.py')) steps.sh """ export PATH=\$HOME/.local/bin:\$PATH chmod +x yarnv4audit.py python3.10 --version python3.10 yarnv4audit.py """ - LinkedHashMap CVEReport = prepareCVEReportYarn4('audit-v4-cosmosdb-output') - this.steps.echo CVEReport.toString() } + finally { + LinkedHashMap CVEReport = prepareCVEReportYarn4('audit-v4-cosmosdb-output') + this.steps.echo CVEReport.toString() + } + } @Override def techStackMaintenance() {