Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pick up CycloneDX BOM components from metadata as well #3092

Merged

Conversation

dervoeti
Copy link
Contributor

@dervoeti dervoeti commented Aug 2, 2024

I'm building a docker image containing multiple Java applications. For those applications, I generate CycloneDX SBOMs at build time using cyclonedx-maven-plugin, which are placed in the docker image alongside the applications.

cyclonedx-maven-plugin stores the application component itself (e.g. my-java-app@1.2.3) inside the .metadata.component attribute of the SBOM. It does not provide it again in the .components attribute of the SBOM. This seems to be correct.
When I scan the image using Syft, the sbom-cataloger picks up the SBOMs of the Java applications, but it does not recognize the component in .metadata.component. So the main component and its direct dependency relations to sub-components are lost in the SBOM Syft produces for the image.

This PR fixes that by collecting .metadata.component as a package as well, additionally to .components. I tested this for my use case and it provided the expected result.

I'm not an expert on CycloneDX or Syft, so I have no idea whether this is an idiomatic way of implementing it or it has any side effects, hence I made this a draft PR. As mentioned, it works fine for my use case.

Signed-off-by: dervoeti <lukas.voetmand@stackable.tech>
@kzantow
Copy link
Contributor

kzantow commented Aug 2, 2024

Hey @dervoeti , this looks like a good change but I'd mention two things:

  • we'd definitely like to see some tests for this, maybe using handcrafted cyclonedx objects
  • the metadata.component is output by syft itself to hold certain types of information, so we need to be sure to only include this as a package when it's determined not to be the type of metadata syft uses to recreate the source object

Signed-off-by: dervoeti <lukas.voetmand@stackable.tech>
@dervoeti dervoeti force-pushed the fix/cyclonedx-bom-components-from-metadata branch from 25348c4 to 671684e Compare August 2, 2024 15:50
Signed-off-by: dervoeti <lukas.voetmand@stackable.tech>
@dervoeti dervoeti force-pushed the fix/cyclonedx-bom-components-from-metadata branch from 4f91340 to 390fc91 Compare August 5, 2024 20:14
@dervoeti
Copy link
Contributor Author

dervoeti commented Aug 5, 2024

Thanks for the quick reply! I added an integration test with a handcrafted CycloneDX SBOM.

Regarding the Syft generated .metadata.component, I think the question is how to determine this. Do you think it's sufficient to check .metadata.tools.components for the presence of an entry with .name == 'syft'? As an alternative, a property for the component (in .metadata.component.properties) could be introduced as a hint that this .metadata.component was generated by Syft.

@kzantow
Copy link
Contributor

kzantow commented Aug 5, 2024

Hi @dervoeti , Syft outputs appropriate component types for the metadata.component: container and file.

For example:

    "component": {
      "bom-ref": "5cb25b1aaa91f815",
      "type": "container",
      "name": "alpine",
      "version": "sha256:844cde635b9cfad87b1fbe17d0659615264eaac1d00dda8320cba71d218421bb"
    }

or

    "component": {
      "bom-ref": "67aed86799793a90",
      "type": "file",
      "name": "/home/downloads"
    }

I think this should could probably check for the CycloneDX component type being only those appropriate to create packages. My feeling looking at the list is, this would include: application, framework, and library... maybe platform. What do you think?

@kzantow
Copy link
Contributor

kzantow commented Aug 5, 2024

It looks like when Syft constructs the source object it is explicitly checking for container and file: https://github.com/anchore/syft/blob/main/syft/format/internal/cyclonedxutil/helpers/decoder.go#L232 and there is still some uncertainty when a file is found. For now, we could probably omit the file, but this probably would be good to create a file in the file section when it is determined not to be the "source" type of a file. Sorry I don't have an exact answer here. For your use case you could probably ignore files in this PR.

…type

Signed-off-by: dervoeti <lukas.voetmand@stackable.tech>
@dervoeti
Copy link
Contributor Author

dervoeti commented Aug 5, 2024

Yeah I think your list sounds reasonable, I implemented it that way now 🙂 For my use case only application and library are really relevant, but framework and platform make sense too.

@dervoeti dervoeti marked this pull request as ready for review August 5, 2024 21:07
kzantow
kzantow previously requested changes Aug 5, 2024
@@ -39,11 +39,32 @@ func ToSyftModel(bom *cyclonedx.BOM) (*sbom.SBOM, error) {
}

func collectBomPackages(bom *cyclonedx.BOM, s *sbom.SBOM, idMap map[string]interface{}) error {
if bom.Components == nil {
components := []cyclonedx.Component{}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this change could be simplified to just adding this block:

	if bom.Metadata.Component != nil
		collectPackages(bom.Metadata.Component, s, idMap)
	}

... and in the collectPackages, we should be recursively adding sub-components, and checking for the type being one of the right types, which it looks like it's doing already

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I should have looked at exactly what the code was doing there before sending you down a path to implement an unnecessary thing 🤦

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No worries, I also didn't see the logic was already present. Good thing you spotted it, I refactored it, the change is much simpler now 👍

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I may have missed suggesting a bom.Metadata != nil bit

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah right, fixed

Signed-off-by: dervoeti <lukas.voetmand@stackable.tech>
Signed-off-by: dervoeti <lukas.voetmand@stackable.tech>
@dervoeti dervoeti requested a review from kzantow August 7, 2024 19:08
Copy link
Contributor

@kzantow kzantow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the contribution, @dervoeti !

@kzantow kzantow merged commit 3161e18 into anchore:main Aug 12, 2024
11 checks passed
@kzantow kzantow added the bug Something isn't working label Aug 12, 2024
@dervoeti dervoeti deleted the fix/cyclonedx-bom-components-from-metadata branch August 13, 2024 18:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants