Skip to content

Commit 7459bff

Browse files
committed
sbom: add new fixup command as a merge replacement
newer grype no longer merges components, and also preserves syft:location:0:path accross formats, so we no longer need the input json to associate vulns with packages. Keep the old command for now to make the transition easier.
1 parent c7d0333 commit 7459bff

File tree

1 file changed

+58
-1
lines changed

1 file changed

+58
-1
lines changed

msys2_devtools/sbom.py

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,12 @@ def generate_components(value) -> list[Component]:
4242

4343
purls: list[PackageURL] = []
4444
cpes: list[str] = []
45-
properties = [Property(name="msys2:pkgbase", value=pkgbase)]
45+
properties = [
46+
Property(name="msys2:pkgbase", value=pkgbase),
47+
# syft:location:0:path gets preserved by grype in all output formats,
48+
# so we can use it as a way to identify the package later
49+
Property(name="syft:location:0:path", value=pkgbase),
50+
]
4651

4752
if "extra" in value and "references" in value["extra"]:
4853
pkgextra = extra_to_pkgextra_entry(value["extra"])
@@ -212,6 +217,41 @@ def get_component_key(component: Component) -> str:
212217
file.write(serialized_json)
213218

214219

220+
def handle_fixup_command(args) -> None:
221+
"""Adjust the target SBOM by rewriting component properties and
222+
adding unaffected versions from a grype json file."""
223+
224+
logging.basicConfig(level="INFO")
225+
226+
with open(args.target_sbom, "r", encoding="utf-8") as h:
227+
target_bom: Bom = Bom.from_json(json.loads(h.read()))
228+
229+
if args.grype_json is not None:
230+
with open(args.grype_json, "r", encoding="utf-8") as h:
231+
grype_data = json.loads(h.read())
232+
include_unaffected_from_grype(grype_data, target_bom)
233+
234+
for component in target_bom.components:
235+
value = None
236+
existing_prop = None
237+
for prop in component.properties:
238+
if prop.name == "syft:location:0:path":
239+
value = prop.value
240+
elif prop.name == "msys2:pkgbase":
241+
existing_prop = prop
242+
243+
if value is not None:
244+
if existing_prop is not None:
245+
existing_prop.value = value
246+
else:
247+
component.properties.add(Property(name="msys2:pkgbase", value=value))
248+
249+
my_json_outputter: 'JsonOutputter' = JsonV1Dot5(target_bom)
250+
serialized_json = my_json_outputter.output_as_string(indent=2)
251+
with open(args.target_sbom, 'w', encoding="utf-8") as file:
252+
file.write(serialized_json)
253+
254+
215255
def add_merge_subcommand(subparsers) -> None:
216256
parser = subparsers.add_parser(
217257
"merge",
@@ -228,12 +268,29 @@ def add_merge_subcommand(subparsers) -> None:
228268
parser.set_defaults(func=handle_merge_command)
229269

230270

271+
def add_fixup_subcommand(subparsers) -> None:
272+
parser = subparsers.add_parser(
273+
"fixup",
274+
description="Adjust the target SBOM by rewriting component properties and "
275+
"adding unaffected versions from a grype json file",
276+
allow_abbrev=False
277+
)
278+
parser.add_argument("target_sbom", help="The target SBOM to change")
279+
parser.add_argument(
280+
"--grype-json",
281+
help="Include additional info from a grype json file, like fixed versions",
282+
default=None
283+
)
284+
parser.set_defaults(func=handle_fixup_command)
285+
286+
231287
def main(argv: list[str]) -> None:
232288
parser = argparse.ArgumentParser(description="SBOM tools", allow_abbrev=False)
233289
subparsers = parser.add_subparsers(dest="command", required=True)
234290

235291
add_create_subcommand(subparsers)
236292
add_merge_subcommand(subparsers)
293+
add_fixup_subcommand(subparsers)
237294

238295
args = parser.parse_args(argv[1:])
239296
args.func(args)

0 commit comments

Comments
 (0)