Skip to content

"WARN merging packages have with different pURLs" from the same package in multiple architectures #2422

@brians-neptune

Description

@brians-neptune

What happened:

I have an SBOM which includes components from Syft-generated SBOMs for containers of multiple architectures of the same distribution. This results in many warnings like this:

[0000]  WARN merging packages have with different pURLs: "abd9052a56926a5f"="pkg:deb/ubuntu/bash@5.1-6ubuntu1.1?arch=amd64&distro=ubuntu-22.04" vs "abd9052a56926a5f"="pkg:deb/ubuntu/bash@5.1-6ubuntu1.1?arch=arm64&distro=ubuntu-22.04"
[0000]  WARN merging packages have with different pURLs: "e6575b016bbfc860"="pkg:deb/ubuntu/dbus-user-session@1.12.20-2ubuntu4.1?arch=amd64&distro=ubuntu-22.04&upstream=dbus" vs "e6575b016bbfc860"="pkg:deb/ubuntu/dbus-user-session@1.12.20-2ubuntu4.1?arch=arm64&distro=ubuntu-22.04&u

Looking at the code in question, I suspect this might be fine because the relevant information for those packages should be the same, but I'm not sure.

What you expected to happen:

No warnings. I don't have any expectation as to whether these packages should be merged or not, but either way it shouldn't warn.

How to reproduce it (as minimally and precisely as possible):

Here's an SBOM you can use directly: merged.json
Run grype as grype sbom:merged.json --distro ubuntu:22.04 (no config file needed). This minimal example only produces a warning for bash.

If you want to recreate that SBOM, here are the steps:

Use a trivial Dockerfile:

FROM ubuntu:22.04

And create some simple Docker containers:

# Some Docker versions get confused about having the same base image for
# non-native platforms, so just tell them to always pull.
docker build --platform linux/amd64 . --tag tmp_grype_repro_amd64 --pull --no-cache
docker build --platform linux/arm64 . --tag tmp_grype_repro_arm64 --pull --no-cache

syft scan --output cyclonedx-json=amd64_sbom.json docker:tmp_grype_repro_amd64
syft scan --output cyclonedx-json=arm64_sbom.json docker:tmp_grype_repro_arm64

Then merge them using this script:

#!/usr/bin/env python3

import json

from cyclonedx.model.bom import Bom
from cyclonedx.model.component import Component, ComponentType
from cyclonedx.validation.json import JsonStrictValidator
from cyclonedx.output import (BaseOutput, OutputFormat, SchemaVersion,
                              make_outputter)

SCHEMA_VERSION = SchemaVersion.V1_6

def merge_in_bom(bom, to_merge, wrapper_component):
    bom.metadata.tools.components |= to_merge.metadata.tools.components
    bom.metadata.tools.services |= to_merge.metadata.tools.services
    bom.metadata.tools.tools |= to_merge.metadata.tools.tools
    bom.metadata.licenses |= to_merge.metadata.licenses
    bom.services |= to_merge.services
    bom.external_references |= to_merge.external_references
    bom.vulnerabilities |= to_merge.vulnerabilities
    for dependency in to_merge.dependencies:
        if dependency.ref == to_merge.metadata.component.bom_ref:
            continue
        bom.dependencies.add(dependency)
    if to_merge.definitions:
        if bom.definitions:
            bom.definitions |= to_merge.definitions
        else:
            bom.definitions = to_merge.definitions

    wrapper_component.components = to_merge.components
    bom.components.add(wrapper_component)
    return wrapper_component

def main():
    main_component = Component(
        type=ComponentType.APPLICATION,
        name='main_component',
    )

    bom = Bom()
    bom.metadata.component = main_component

    with open('amd64_sbom.json', 'r') as f:
        amd64_sbom = Bom.from_json(json.load(f))
    with open('arm64_sbom.json', 'r') as f:
        arm64_sbom = Bom.from_json(json.load(f))

    bom.register_dependency(main_component, [
        merge_in_bom(bom, amd64_sbom, Component(
            type=ComponentType.CONTAINER,
            name='amd64',
        )),
        merge_in_bom(bom, arm64_sbom, Component(
            type=ComponentType.CONTAINER,
            name='arm64',
        )),
    ])

    outputter: BaseOutput = make_outputter(bom=bom, output_format=OutputFormat.JSON, schema_version=SCHEMA_VERSION)
    json_string = outputter.output_as_string()

    json_validator = JsonStrictValidator(SCHEMA_VERSION)
    validation_errors = json_validator.validate_str(json_string)
    if validation_errors:
        print('Invalid SBOM produced', 'ValidationError:', repr(validation_errors), sep='\n', file=sys.stderr)
        sys.exit(1)
    with open('merged.json', 'w') as f:
        f.write(json_string)

if __name__ == '__main__':
    main()

Anything else we need to know?:

Environment:

  • Output of grype version: grype 0.87.0
  • OS (e.g: cat /etc/os-release or similar): Multiple Ubuntu 22.04 containers, both amd64 and arm64

Additional environment:

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    Status

    Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions