Skip to content

Creates CycloneDX Software Bill of Materials (SBOM) from Go modules

License

Notifications You must be signed in to change notification settings

VinodAnandan/cyclonedx-gomod

 
 

Repository files navigation

cyclonedx-gomod

Build Status Go Report Card Latest GitHub release License Website Slack Invite Group Discussion Twitter

cyclonedx-gomod creates CycloneDX Software Bill of Materials (SBOM) from Go modules

Installation

Prebuilt binaries are available on the releases page.

From Source

go install github.com/CycloneDX/[email protected]

Building from source requires Go 1.16 or newer.

Compatibility

cyclonedx-gomod will produce BOMs for the latest version of the CycloneDX specification supported by cyclonedx-go, which currently is 1.2. You can use the CycloneDX CLI to convert between multiple BOM formats or specification versions.

Accuracy

Currently, SBOMs generated with cyclonedx-gomod are completely module-based.

What does this mean? Well, modules in Go can consist of multiple commands or applications. For example, k8s.io/minikube is a module, but it contains multiple commands. Each of these commands is eventually compiled into its own binary. Most likely, each command only depends on a subset of the dependencies defined in the module's go.mod.

Additionally, some dependencies may only be required when a given build constraint is in place. Build constraints can include the operating system (GOOS), the architecture (GOARCH) or build tags. As an example, github.com/Microsoft/go-winio provides Windows-specific functionality and won't be included in builds that target Linux or macOS.

cyclonedx-gomod describes the module, not commands or binaries. See also the discussion in #20.

We're in the process of adding support for generating command- or binary-specific SBOMs as well. Stay tuned!

Usage

Usage of cyclonedx-gomod:
  -json
        Output in JSON format
  -licenses
        Resolve module licenses
  -module string
        Path to Go module (default ".")
  -noserial
        Omit serial number
  -novprefix
        Omit "v" version prefix
  -output string
        Output path (default "-")
  -reproducible
        Make the SBOM reproducible by omitting dynamic content
  -serial string
        Serial number (default [random UUID])
  -std
        Include Go standard library as component and dependency of the module
  -test
        Include test dependencies
  -type string
        Type of the main component (default "application")
  -version
        Show version

Example

$ cyclonedx-gomod -licenses -std -output bom.xml

Checkout the examples directory for examples of BOMs generated by cyclonedx-gomod.

GitHub Actions 🤖

We made a GitHub Action to help integrate cyclonedx-gomod into existing CI/CD workflows!
You can find it on the GitHub marketplace: gh-gomod-generate-sbom

Docker 🐳

$ docker run -it --rm \
    -v "/path/to/mymodule:/mymodule" \
    -v "$(pwd):/out" \
    cyclonedx/cyclonedx-gomod -module /mymodule -output /out/bom.xml -licenses

Important Notes

Vendoring

Modules that use vendoring are, although in a limited manner, supported.
Limitations are as follows:

  • No hashes. Go doesn't copy all module files to vendor, only those that are required to build and test the main module. Because module checksums consider almost all files in a module's directory though, calculating accurate hashes from the vendor directory is not possible. As a consequence, BOMs for modules that use vendoring do not include component hashes.

Licenses

There is currently no standard way for developers to declare their module's license.
Detecting licenses based on files in a repository is a non-trivial task, which is why cyclonedx-gomod
uses go-license-detector to resolve module licenses.

While go-license-detector's license matching may be accurate most of the time, BOMs should state facts.
This is why license resolution is an opt-in feature (using the -licenses flag). If you are a vendor and legally required to provide 100% accurate BOMs, do not use this feature.

Hashes

cyclonedx-gomod uses the same hashing algorithm Go uses for its module authentication.
vikyd/go-checksum does a great job of explaining what exactly that entails. In essence, the hash you see in a BOM should be the same as in your go.sum file, just in a different format. This is because the CycloneDX specification enforces hashes to be provided in hex encoding, while Go uses base64 encoded values.

To verify a hash found in a BOM, do the following:

  1. Hex decode the value
  2. Base64 encode the value
  3. Prefix the value with h1:
  4. Compare with the expected module checksum

Example

Given the following component element in a BOM:

<component bom-ref="pkg:golang/github.com/google/[email protected]" type="library">
  <name>github.com/google/uuid</name>
  <version>v1.2.0</version>
  <scope>required</scope>
  <hashes>
    <hash alg="SHA-256">
      a8962d5e72515a6a5eee6ff75e5ca1aec2eb11446a1d1336931ce8c57ab2503b
    </hash>
  </hashes>
  <licenses>
    <license>
      <id>BSD-3-Clause</id>
      <url>https://spdx.org/licenses/BSD-3-Clause.html</url>
    </license>
  </licenses>
  <purl>pkg:golang/github.com/google/[email protected]</purl>
  <externalReferences>
    <reference type="vcs">
      <url>https://github.com/google/uuid</url>
    </reference>
  </externalReferences>
</component>

We take the hash, hex decode it, base64 encode the resulting bytes and prefix that with h1: (demonstrated here in a CyberChef recipe).

In this case, we end up with h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=.
In order to verify that this matches what we expect, we can query Go's checksum database for the component we're inspecting:

$ curl https://sum.golang.org/lookup/github.com/google/[email protected]
2580307
github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=

go.sum database tree
3935567
SapHtgdNCeF00Cx8kqztePV24kgzNg++Xovae42HAMw=

— sum.golang.org Az3grsm7Wm4CVNR1RHq9BFnu9jzcRlU2uw7lr0gfUWgO6+rqPNjT+fUTl9gH0NRTgdwW9nItuQSMbhSaLCsk8YeYSAs=

Line 2 of the response tells us that the checksum in our BOM matches that known to the checksum database.

Copyright & License

CycloneDX GoMod is Copyright (c) OWASP Foundation. All Rights Reserved.

Permission to modify and redistribute is granted under the terms of the Apache 2.0 license.
See the LICENSE file for the full license.

Contributing

Pull requests are welcome. But please read the CycloneDX contributing guidelines first.

It is generally expected that pull requests will include relevant tests. Tests are automatically run against all supported Go versions for every pull request.

Running Tests

Some tests make use of the CycloneDX CLI, e.g. to validate BOMs.
Make sure to download the CLI binary and make it available as cyclonedx in your $PATH.
See also Setup CycloneDX CLI in the workflow.

Integration tests additionally make use of the tar command, which may not be available in Windows environments.

About

Creates CycloneDX Software Bill of Materials (SBOM) from Go modules

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Go 98.5%
  • Makefile 1.2%
  • Dockerfile 0.3%