Skip to content

Commit 73e8a2f

Browse files
committed
Merge branch 'master' into mkumykov-multi-image
2 parents 7ee264e + 9cf116b commit 73e8a2f

12 files changed

+1569
-103
lines changed

examples/client/batch_generate_sbom.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22
Created on April 13, 2023
33
@author: kumykov
44
5+
##################### DISCLAIMER ##########################
6+
## This script was created for a specific purpose and ##
7+
## SHOULD NOT BE USED as a general purpose utility. ##
8+
## For general purpose utility use ##
9+
## /examples/client/generate_sbom.py ##
10+
###########################################################
11+
512
Copyright (C) 2023 Synopsys, Inc.
613
http://www.blackducksoftware.com/
714

examples/client/batch_update_project_phase.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,11 +100,11 @@ def process_csv_file(filename):
100100
project_phase_idx = None
101101
for row in csvreader:
102102
row_number = csvreader.line_num
103-
if not (project_name_idx and project_version_idx and project_phase_idx):
103+
if (project_name_idx == None and project_version_idx == None and project_phase_idx == None):
104104
project_name_idx = row.index(project_name_column)
105105
project_version_idx = row.index(project_version_column)
106106
project_phase_idx = row.index(project_phase_column)
107-
elif project_name_idx and project_version_idx and project_phase_idx:
107+
elif project_name_idx != None and project_version_idx != None and project_phase_idx != None:
108108
project_name = row[project_name_idx].strip() if project_name_idx < len(row) else ''
109109
version_name = row[project_version_idx].strip() if project_version_idx < len(row) else ''
110110
phase = row[project_phase_idx] if project_phase_idx < len(row) else ''
@@ -130,11 +130,11 @@ def process_excel_file(filename):
130130
row_number = 0
131131
for row in ws.values:
132132
row_number += 1
133-
if not (project_name_idx and project_version_idx and project_phase_idx):
133+
if (project_name_idx == None and project_version_idx == None and project_phase_idx == None):
134134
project_name_idx = row.index(project_name_column)
135135
project_version_idx = row.index(project_version_column)
136136
project_phase_idx = row.index(project_phase_column)
137-
elif project_name_idx and project_version_idx and project_phase_idx:
137+
elif project_name_idx != None and project_version_idx != None and project_phase_idx != None:
138138
project_name = row[project_name_idx] if project_name_idx < len(row) else ''
139139
version_name = row[project_version_idx] if project_version_idx < len(row) else ''
140140
phase = row[project_phase_idx] if project_phase_idx < len(row) else ''

examples/client/consolidated_file_report.py

Lines changed: 823 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
'''
2+
Created on October 12, 2023
3+
@author: kumykov
4+
5+
Copyright (C) 2023 Synopsys, Inc.
6+
http://www.synopsys.com/
7+
8+
Licensed to the Apache Software Foundation (ASF) under one
9+
or more contributor license agreements. See the NOTICE file
10+
distributed with this work for additional information
11+
regarding copyright ownership. The ASF licenses this file
12+
to you under the Apache License, Version 2.0 (the
13+
"License"); you may not use this file except in compliance
14+
with the License. You may obtain a copy of the License at
15+
16+
http://www.apache.org/licenses/LICENSE-2.0
17+
18+
Unless required by applicable law or agreed to in writing,
19+
software distributed under the License is distributed on an
20+
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21+
KIND, either express or implied. See the License for the
22+
specific language governing permissions and limitations
23+
under the License.
24+
25+
This script is provided as an example of populating custom field data
26+
based on BOM components crypto information.
27+
The goal is to enable policy functionality that would be triggered by
28+
cryptographic features of a component.
29+
30+
The script will analyze ciphers included in a component and will set
31+
a BOM Component custom field value to reflect that a known weakness is present.
32+
33+
Requirements
34+
35+
- python3 version 3.8 or newer recommended
36+
- the following packages are used by the script and should be installed
37+
prior to use:
38+
argparse
39+
blackduck
40+
logging
41+
sys
42+
json
43+
pprint
44+
- Blackduck instance
45+
- API token with sufficient privileges to perform project version phase
46+
change.
47+
48+
Install python packages with the following command:
49+
50+
pip3 install argparse blackduck logging sys json pprint
51+
52+
Using
53+
54+
Script expects a boolean custom field labeled "BadCrypto" on a BOM Component.
55+
A policy that is triggered by BadCrypto custom field value used to visualize
56+
results.
57+
58+
usage: crypto-to-custom.py [-h] -u BASE_URL -t TOKEN_FILE -pn PROJECT_NAME -vn VERSION_NAME [-nv] [--reset]
59+
60+
options:
61+
-h, --help show this help message and exit
62+
-u BASE_URL, --base-url BASE_URL
63+
Hub server URL e.g. https://your.blackduck.url
64+
-t TOKEN_FILE, --token-file TOKEN_FILE
65+
File containing access token
66+
-pn PROJECT_NAME, --project-name PROJECT_NAME
67+
Project Name
68+
-vn VERSION_NAME, --version-name VERSION_NAME
69+
Version Name
70+
-nv, --no-verify Disable TLS certificate verification
71+
--reset Undo the changes made by this script
72+
73+
74+
'''
75+
76+
import argparse
77+
from blackduck import Client
78+
from pprint import pprint
79+
import logging
80+
import sys
81+
import json
82+
83+
logging.basicConfig(format='%(asctime)s:%(levelname)s:%(message)s', stream=sys.stderr, level=logging.DEBUG)
84+
logging.getLogger("requests").setLevel(logging.INFO)
85+
logging.getLogger("urllib3").setLevel(logging.INFO)
86+
logging.getLogger("blackduck").setLevel(logging.INFO)
87+
88+
def find_project_by_name(project_name):
89+
params = {
90+
'q': [f"name:{project_name}"]
91+
}
92+
projects = [p for p in bd.get_resource('projects', params=params) if p['name'] == project_name]
93+
if len(projects) == 1:
94+
return projects[0]
95+
else:
96+
return None
97+
98+
def find_project_version_by_name(project, version_name):
99+
params = {
100+
'q': [f"versionName:{version_name}"]
101+
}
102+
versions = [v for v in bd.get_resource('versions', project, params=params) if v['versionName'] == version_name]
103+
if len(versions) == 1:
104+
return versions[0]
105+
else:
106+
return None
107+
108+
def parse_command_args():
109+
110+
parser = argparse.ArgumentParser("crypto-to-custom.py")
111+
parser.add_argument("-u", "--base-url", required=True, help="Hub server URL e.g. https://your.blackduck.url")
112+
parser.add_argument("-t", "--token-file", required=True, help="File containing access token")
113+
parser.add_argument("-pn", "--project-name", required=True, help="Project Name")
114+
parser.add_argument("-vn", "--version-name", required=True, help="Version Name")
115+
parser.add_argument("-nv", "--no-verify", action='store_false', help="Disable TLS certificate verification")
116+
parser.add_argument("--reset", action='store_true', help="Undo the changes made by this script")
117+
return parser.parse_args()
118+
119+
def set_custom_field(field, url, value):
120+
payload = {"fields": [{"customField": field['_meta']['href'],"values": value}]}
121+
headers = {"Accept": "application/vnd.blackducksoftware.bill-of-materials-6+json",
122+
"Content-Type": "application/vnd.blackducksoftware.bill-of-materials-6+json"}
123+
response = bd.session.put(url, data=json.dumps(payload), headers=headers)
124+
print(response)
125+
126+
def process_project_version(args):
127+
project = find_project_by_name(args.project_name)
128+
version = find_project_version_by_name(project, args.version_name)
129+
130+
components = bd.get_resource('components',version)
131+
for component in components:
132+
print (component['componentName'], component['componentVersionName'])
133+
custom_fields = bd.get_resource('custom-fields',component, items=False)
134+
custom_fields_url = custom_fields['_meta']['href']
135+
c = [x for x in custom_fields['items'] if x['label'] == 'BadCrypto'][0]
136+
resources = bd.list_resources(component)
137+
if 'crypto-algorithms' in resources.keys():
138+
crypto_algorithms = bd.get_resource('crypto-algorithms', component)
139+
for crypto in crypto_algorithms:
140+
if crypto['knownWeaknesses']:
141+
pprint('Has Weakness')
142+
value = ['true']
143+
if args.reset:
144+
value = []
145+
set_custom_field(c, custom_fields_url, value=value)
146+
break
147+
148+
def main():
149+
args = parse_command_args()
150+
with open(args.token_file, 'r') as tf:
151+
access_token = tf.readline().strip()
152+
global bd
153+
bd = Client(base_url=args.base_url, token=access_token, verify=args.no_verify, timeout=60.0, retries=4)
154+
155+
process_project_version(args)
156+
157+
if __name__ == "__main__":
158+
sys.exit(main())
159+

examples/client/deactivate_deep_licenses.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,27 @@
11
'''
2+
Created on June 4, 2023
3+
@author: kumykov
4+
5+
Copyright (C) 2023 Synopsys, Inc.
6+
http://www.blackducksoftware.com/
7+
8+
Licensed to the Apache Software Foundation (ASF) under one
9+
or more contributor license agreements. See the NOTICE file
10+
distributed with this work for additional information
11+
regarding copyright ownership. The ASF licenses this file
12+
to you under the Apache License, Version 2.0 (the
13+
"License"); you may not use this file except in compliance
14+
with the License. You may obtain a copy of the License at
15+
16+
http://www.apache.org/licenses/LICENSE-2.0
17+
18+
Unless required by applicable law or agreed to in writing,
19+
software distributed under the License is distributed on an
20+
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21+
KIND, either express or implied. See the License for the
22+
specific language governing permissions and limitations
23+
under the License.
24+
225
Purpose: Deactivates Deep Licenses that were detected by Deep License search
326
427
usage: deactivate_deep_licenses.py [-h] -u BASE_URL -t TOKEN_FILE -p PROJECT_NAME -pv VERSION_NAME [-mt MATCH_TYPE] [-nv] [--active]
@@ -96,4 +119,4 @@ def main():
96119

97120

98121
if __name__ == "__main__":
99-
sys.exit(main())
122+
sys.exit(main())

examples/client/generate_sbom.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,10 @@ class FailedReportDownload(Exception):
4545
parser.add_argument("token_file", help="containing access token")
4646
parser.add_argument("project_name")
4747
parser.add_argument("version_name")
48-
parser.add_argument("-z", "--zip_file_name", default="reports.zip")
49-
parser.add_argument("-t", "--type", type=str, nargs='?', default="SPDX_22", choices=["SPDX_22", "CYCLONEDX_13"], help="Choose the type of SBOM report")
48+
parser.add_argument("-t", "--type", type=str, nargs='?', default="SPDX_23", choices=["SPDX_22", "SPDX_23", "CYCLONEDX_13", "CYCLONEDX_14"], help="Choose the type of SBOM report")
5049
parser.add_argument('-r', '--retries', default=4, type=int, help="How many times to retry downloading the report, i.e. wait for the report to be generated")
51-
parser.add_argument('-s', '--sleep_time', default=5, type=int, help="The amount of time to sleep in-between (re-)tries to download the report")
50+
parser.add_argument('-s', '--sleep_seconds', default=60, type=int, help="The amount of time to sleep in-between (re-)tries to download the report")
51+
parser.add_argument('--include-subprojects', dest='include_subprojects', action='store_false', help="whether subprojects should be included")
5252
parser.add_argument('--no-verify', dest='verify', action='store_false', help="disable TLS certificate verification")
5353

5454
args = parser.parse_args()
@@ -75,8 +75,8 @@ def download_report(bd_client, location, filename, retries=args.retries):
7575
logging.error("Ruh-roh, not sure what happened here")
7676
else:
7777
logging.debug(f"Failed to retrieve report {report_id}, report status: {report_status}")
78-
logging.debug("Probably not ready yet, waiting 5 seconds then retrying...")
79-
time.sleep(args.sleep_time)
78+
logging.debug(f"Probably not ready yet, waiting {args.sleep_seconds} seconds then retrying...")
79+
time.sleep(args.sleep_seconds)
8080
retries -= 1
8181
download_report(bd_client, location, filename, retries)
8282
else:
@@ -105,16 +105,19 @@ def download_report(bd_client, location, filename, retries=args.retries):
105105

106106
post_data = {
107107
'reportFormat': "JSON",
108-
'reportType': 'SBOM',
109-
'sbomType': args.type,
108+
'sbomType': args.type,
109+
'includeSubprojects': args.include_subprojects
110110
}
111111
sbom_reports_url = version['_meta']['href'] + "/sbom-reports"
112112

113+
bd.session.headers["Content-Type"] = "application/vnd.blackducksoftware.report-4.json"
113114
r = bd.session.post(sbom_reports_url, json=post_data)
115+
if (r.status_code == 403):
116+
logging.debug("Authorization Error - Please ensure the token you are using has write permissions!")
114117
r.raise_for_status()
115118
location = r.headers.get('Location')
116119
assert location, "Hmm, this does not make sense. If we successfully created a report then there needs to be a location where we can get it from"
117120

118121
logging.debug(f"Created SBOM report of type {args.type} for project {args.project_name}, version {args.version_name} at location {location}")
119-
download_report(bd, location, args.zip_file_name)
122+
download_report(bd, location, f"{args.project_name}({args.version_name}).zip")
120123

0 commit comments

Comments
 (0)