Package Version Inventories

Automatically collect package versions for your repositories, or upload SBOM files for your repositories and services.

Overview

Package version inventories are automatically collected by OpsLevel for git forge integrations (e.g. Git Integrations), unless they are disabled on the integration. These inventories enable you to quickly and easily to create Package Version Checks to validate package version usage. This helps to ensure all code in your organization is vulnerability-free and not out of support.

📘

Scheduled Processing

Package version information is collected once per day. When you update packages or package versions for a repository, you may need to wait up to 24h to see your updates reflected in OpsLevel.

For manual uploads of SBOMs (described below), we will process at most one uploaded SBOM per day, per-attached-resource (either Service or Repository). If additional files for a resource have been uploaded, but not processed, we schedule processing the freshest uploaded file at approximately 12:45am UTC.

Managing Automated Collection

You can manage automated package version collection on your git forge integration configuration pages.

Automated Collection Language Support

The automated collection of packages relies on Syft to collect information about the attached repository. This tool supports a very wide range of package managers and languages. Refer to the Syft documentation for more information on supported package managers and languages.

Manual SBOM uploads

Note: If you enable the "Manual SBOM Upload" feature toggle, automatic package version generation will be disabled, so your manually uploaded files are not overwritten.

Instead of using automatically generated package versions, you have the option of manually uploading software bills of materials (SBOM) files to OpsLevel. SBOMs serve as lists of software packages that are being used by your services and/or repositories. Currently both the CycloneDX JSON v1.5 and the CycloneDX JSON v1.6 SBOM formats are supported.

📘

Additional Requirements

The bare CycloneDX specification is relatively vague about certain fields and their usage. For this reason, OpsLevel places the following additional constraints on SBOMs uploaded to it:

  1. The Package URL (PURL) field of component elements is required.
  2. If the intention is to address software packages using their namespaces, those namespaces must be part of the component elements' name field value. The tools we evaluated automatically do this for languages where it makes sense (e.g. go).

API Endpoint

To upload a software bill of materials, send a POST request to the following URL:

https://app.opslevel.com/upload/documents/sbom/<resource_id>

<resource_id> can either be the ID of the service or of the repository to which you want to attach the software bill of materials to, e.g. Z2lkOi8vb3BzbGV2ZWwvU2VydmljZS8yNDg. You can retrieve the resource ID with our GraphQL API.

Mapping

Software bill of materials files can be attached to services or to repositories in OpsLevel. Some organizations rely on monorepos that hold dozens of services, some of which are even bundled into a co-located images. Other organizations rely on multiple repositories that roll up into a single image at release time.

In order to accommodate various release strategies, OpsLevel allows uploading software bills of materials to either repositories or to services, and shows packages from a linked repository on the service associated with it.

Where to upload

If you are unsure of whether to attach the software bill of materials to the service or the repository, consider following these guidelines:

  • If the repository hosts only one service, or if the repository hosts more than one service and the generated software bill of materials does not relate to one of those services specifically (e.g. because it is shared by multiple services within the repository), attach the software bill of materials to the repository.
  • If you have access to service-level software bills of materials for multiple services inside a repository hosting more than one service, attach the software bill of materials to the service.
  • If you're generating a software bill of materials for a build of a service that contains code from two or more repositories, attach the software bill of materials to the service.

Request Headers

Set the Content-Type HTTP request header to application/json.

Additionally, the upload request must be authenticated using an API token (see the "Create an API Token" section of our GraphQL API documentation).

Set the Authorization header to Bearer <api_token> (e.g. Bearer ABfFuAsAHou3XzyVW8nmeNqK86FAZCG3OHmK).

Request Body

The HTTP request body of the upload request should conform to the CycloneDX JSON Standard in version 1.5or in version 1.6. Various tools exist to generate software bills of materials in this format, e.g. syft.

An example body could look like the following:

{
    "$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
    "bomFormat": "CycloneDX",
    "specVersion": "1.5",
    "serialNumber": "urn:uuid:3c1ed074-6751-46f7-9eb3-5279bb5c6495",
    "version": 1,
    "metadata": {
        "timestamp": "2023-12-20T08:34:16-06:00",
        "tools": [
            {
                "vendor": "anchore",  
                "name": "syft",
                "version": "0.98.0"
            }
        ],
        "component": {
            "bom-ref": "08329a07b4eb8eac",
            "type": "file",
            "name": "./"
        }
    },
    "components": [
        {
            "bom-ref": "pkg:gem/[email protected]?package-id=fdf94e8c0de5bf8d",
            "type": "library",
            "name": "zeitwerk",
            "version": "2.6.12",
            "cpe": "cpe:2.3:a:ruby-lang:zeitwerk:2.6.12:*:*:*:*:*:*:*",
            "purl": "pkg:gem/[email protected]",
            "properties": [
                {
                    "name": "syft:package:foundBy",
                    "value": "ruby-gemfile-cataloger"
                },
                {
                    "name": "syft:package:language",
                    "value": "ruby"
                },
                {
                    "name": "syft:package:type",
                    "value": "gem"
                },
                {
                    "name": "syft:cpe23",
                    "value": "cpe:2.3:a:ruby_lang:zeitwerk:2.6.12:*:*:*:*:*:*:*"
                },
                {
                    "name": "syft:cpe23",
                    "value": "cpe:2.3:a:zeitwerk:zeitwerk:2.6.12:*:*:*:*:*:*:*"
                },
                {
                    "name": "syft:cpe23",
                    "value": "cpe:2.3:a:ruby:zeitwerk:2.6.12:*:*:*:*:*:*:*"
                },
                {
                    "name": "syft:location:0:path",
                    "value": "/Gemfile.lock"
                }
            ]
        },
        {
            "bom-ref": "pkg:npm/[email protected]?package-id=9ac1a725ce574216",
            "type": "library",
            "name": "zenscroll",
            "version": "4.0.2",
            "licenses": [
                {
                    "license": {
                        "id": "Unlicense"
                    }
                }
            ],
            "cpe": "cpe:2.3:a:zenscroll:zenscroll:4.0.2:*:*:*:*:*:*:*",
            "purl": "pkg:npm/[email protected]",
            "properties": [
                {
                    "name": "syft:package:foundBy",
                    "value": "javascript-lock-cataloger"
                },
                {
                    "name": "syft:package:language",
                    "value": "javascript"
                },
                {
                    "name": "syft:package:type",
                    "value": "npm"
                },
                {
                    "name": "syft:location:0:path",
                    "value": "/yarn.lock"
                }
            ]
        }
    ]
}

Submitting the Request

Submitting the request successfully should result in an HTTP response status code of 202/accepted and the following body:

{
    "status": "OK"
}

An invalid request will produce an HTTP response status code other than 202/accepted, with a body like the following:

{
    "errors": [
        "value at `/sbom/$schema` is not one of: [\"http://cyclonedx.org/schema/bom-1.5.schema.json\"]"
    ]
}

Uploading additional software bills of materials for a particular resource (repository or service) will replace the previous SBOM. We support up to one current SBOM per service and up to one per repository.

User Interface

Once you uploaded a software bill of materials, its contents will be visible within our application on either the service page, or on the repository page, depending on what the SBOM was attached to.

Service Software Bills of Materials

Navigate to Catalog > Services > Service of Interest > Dependencies > Packages.

A table like the one below will display all the software packages that we detected the service is using. This table shows both software packages stemming from software bills of materials attached directly to the service, as well as from software bills of materials attached to the repository that the service is hosted in - indicated by the "Uploaded To" column.

Repository Software Bill of Materials

Navigate to Catalog > Repositories > Repository of Interest.

A table like the one below will display all the software packages that we detected the repository is using. This table shows only the software packages stemming from software bills of materials attached directly to the repository.


What’s Next

Create some package version checks for your services!