Skip to content

Commit 339947b

Browse files
authored
Merge pull request #1276 from asklymenko/T9203-SBOM
T9203: refactor SBOM generation script
2 parents b84fb1a + 3a296d2 commit 339947b

1 file changed

Lines changed: 56 additions & 62 deletions

File tree

scripts/image-build/build-vyos-image

Lines changed: 56 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,58 @@ import tempfile
3636
class ImageBuildError(Exception):
3737
pass
3838

39+
# Parse email contact strings.
40+
def supplier_from_contact_string(raw):
41+
if not raw:
42+
return None
43+
m = re.match(r'^(?P<name>.*?)\s*[<\[](?P<contact>[^<>\[\]]+)[>\]]$', raw.strip())
44+
if m:
45+
name, contact = m.group('name').strip(), m.group('contact').strip()
46+
if name.lower() == 'none' or contact.lower() == 'none':
47+
return None
48+
supplier = {}
49+
if name:
50+
supplier['name'] = name
51+
if '@' in contact:
52+
supplier['contact'] = [{'email': contact}]
53+
return supplier or None
54+
if re.match(r'^[^\s@]+@[^\s@]+\.[^\s@]+$', raw.strip()):
55+
return {'contact': [{'email': raw.strip()}]}
56+
return {'name': raw.strip()}
57+
58+
def component_supplier(comp, vyos_supplier, go_authors_supplier):
59+
# Return the supplier field for CycloneDX components.
60+
61+
# Debian packages: the Maintainer field (component.publisher) is a real,
62+
# per-package supplier fact.
63+
supplier = supplier_from_contact_string(comp.get('publisher'))
64+
if supplier:
65+
return supplier
66+
67+
# Kernel modules: VyOS compiles every one itself for this exact kernel
68+
# build, so VyOS genuinely is the supplier of the binary - regardless of
69+
# who originally authored the driver source.
70+
found_by = next((p['value'] for p in comp.get('properties', [])
71+
if p.get('name') == 'syft:package:foundBy'), None)
72+
if found_by == 'linux-kernel-cataloger':
73+
return vyos_supplier
74+
75+
# Python packages: component.author (from the package's own METADATA) is
76+
# a real, per-package supplier fact. We install these packages unmodified.
77+
supplier = supplier_from_contact_string(comp.get('author'))
78+
if supplier:
79+
return supplier
80+
81+
# golang.org/x/* and the embedded Go stdlib: a verified official
82+
# supplier, every LICENSE file says "Copyright <year> The Go Authors".
83+
# Not extended to other Go modules (e.g. github.com/<org>/<repo>): unlike
84+
# this one prefix, there's no single verifiable fact covering all of them.
85+
name = comp.get('name', '')
86+
if name.startswith('golang.org/x/') or name == 'stdlib':
87+
return go_authors_supplier
88+
89+
return None
90+
3991
# argparse converts hyphens to underscores,
4092
# so for lookups in the original options hash we have to convert them back
4193
def field_to_option(s):
@@ -809,6 +861,8 @@ Pin-Priority: 600
809861

810862
vyos_author = {'name': 'VyOS maintainers and contributors', 'email': 'maintainers@vyos.io'}
811863
vyos_supplier = {'name': 'VyOS Networks', 'url': [build_defaults['website_url']]}
864+
go_authors_supplier = {'name': 'The Go Authors', 'url': ['https://go.dev']}
865+
812866
cdx['metadata']['authors'] = [vyos_author]
813867
cdx['metadata']['supplier'] = vyos_supplier
814868

@@ -818,72 +872,12 @@ Pin-Priority: 600
818872
cdx['metadata']['component']['type'] = 'operating-system'
819873
cdx['metadata']['component']['supplier'] = vyos_supplier
820874

821-
# Add the correct supplier field for Debian packages.
822-
publisher_re = re.compile(r'^(?P<name>.*?)\s*[<\[](?P<contact>[^<>\[\]]+)[>\]]$')
823-
email_re = re.compile(r'^[^\s@]+@[^\s@]+\.[^\s@]+$')
824-
for comp in cdx['components']:
825-
publisher = comp.get('publisher')
826-
if not publisher:
827-
continue
828-
m = publisher_re.match(publisher.strip())
829-
if m:
830-
name, contact = m.group('name').strip(), m.group('contact').strip()
831-
if name.lower() == 'none' or contact.lower() == 'none':
832-
continue
833-
supplier = {}
834-
if name:
835-
supplier['name'] = name
836-
if '@' in contact:
837-
supplier['contact'] = [{'email': contact}]
838-
elif email_re.match(publisher.strip()):
839-
supplier = {'contact': [{'email': publisher.strip()}]}
840-
else:
841-
supplier = {'name': publisher.strip()}
842-
if supplier:
843-
comp['supplier'] = supplier
844-
845-
# VyOS compiles every kernel module itself, so it's correct to list VyOS as the supplier for these modules.
875+
# Add the correct component.supplier field.
846876
for comp in cdx['components']:
847-
if comp.get('supplier'):
848-
continue
849-
found_by = next((p['value'] for p in comp.get('properties', [])
850-
if p.get('name') == 'syft:package:foundBy'), None)
851-
if found_by == 'linux-kernel-cataloger':
852-
comp['supplier'] = vyos_supplier
853-
854-
# Use the component.author value as the supplier for Python packages.
855-
for comp in cdx['components']:
856-
if comp.get('supplier'):
857-
continue
858-
author = comp.get('author')
859-
if not author:
860-
continue
861-
m = publisher_re.match(author.strip())
862-
if m:
863-
name, contact = m.group('name').strip(), m.group('contact').strip()
864-
if name.lower() == 'none' or contact.lower() == 'none':
865-
continue
866-
supplier = {}
867-
if name:
868-
supplier['name'] = name
869-
if '@' in contact:
870-
supplier['contact'] = [{'email': contact}]
871-
elif email_re.match(author.strip()):
872-
supplier = {'contact': [{'email': author.strip()}]}
873-
else:
874-
supplier = {'name': author.strip()}
877+
supplier = component_supplier(comp, vyos_supplier, go_authors_supplier)
875878
if supplier:
876879
comp['supplier'] = supplier
877880

878-
# Specify the supplier for golang.org/x/* modules and the embedded Go stdlib.
879-
go_authors_supplier = {'name': 'The Go Authors', 'url': ['https://go.dev']}
880-
for comp in cdx['components']:
881-
if comp.get('supplier'):
882-
continue
883-
name = comp.get('name', '')
884-
if name.startswith('golang.org/x/') or name == 'stdlib':
885-
comp['supplier'] = go_authors_supplier
886-
887881
with open(cdx_file, 'w') as f:
888882
json.dump(cdx, f)
889883

0 commit comments

Comments
 (0)