Skip to main content

SBOM

In this example you are going to create a sbomComponent blueprint that ingests all third party components in your sbom.json or sbom.xml file using a combination of Port's API and webhook functionality. You will then relate this blueprint to a sbomVulnerability blueprint, allowing you to map all the components affected by a security vulnerability.

To ingest the components and vulnerabilities to Port, a script that sends information about the SBOM file according to the webhook configuration is used.

Prerequisites

Create the following blueprint definition and webhook configuration:

SBOM component blueprint
{
"identifier": "sbomComponent",
"description": "This blueprint represents an SBOM component in our software catalog",
"title": "SBOM Component",
"icon": "Package",
"schema": {
"properties": {
"name": {
"title": "Name",
"type": "string"
},
"version": {
"title": "Version",
"type": "string"
},
"package_url": {
"title": "Package URL",
"type": "string"
},
"external_references": {
"title": "External References",
"type": "array"
},
"licenses": {
"title": "Licenses",
"type": "array"
},
"type": {
"title": "Type",
"type": "string",
"default": "library",
"enum": [
"application",
"framework",
"library",
"container",
"platform",
"operating-system",
"device",
"device-driver",
"firmware",
"file",
"data",
"machine-learning-model"
]
},
"software_product": {
"title": "Software Product",
"type": "string"
}
},
"required": []
},
"mirrorProperties": {},
"calculationProperties": {},
"relations": {}
}
SBOM vulnerability blueprint
{
"identifier": "sbomVulnerability",
"description": "This blueprint represents an SBOM vulnerability in our software catalog",
"title": "SBOM Vulnerability",
"icon": "Package",
"schema": {
"properties": {
"description": {
"title": "Description",
"type": "string"
},
"reference": {
"title": "BOM Reference",
"type": "string"
},
"recommendation": {
"title": "Recommendation",
"type": "string"
},
"ratings": {
"title": "Ratings",
"type": "array"
},
"source": {
"title": "Source",
"type": "string"
},
"published": {
"title": "Published On",
"type": "string",
"format": "date-time"
},
"state": {
"title": "State",
"type": "string",
"default": "exploitable",
"enum": [
"resolved",
"resolved_with_pedigree",
"exploitable",
"in_triage",
"false_positive",
"not_affected"
],
"enumColors": {
"resolved": "green",
"resolved_with_pedigree": "lightGray",
"exploitable": "red",
"in_triage": "yellow",
"false_positive": "purple",
"not_affected": "green"
}
}
},
"required": []
},
"mirrorProperties": {},
"calculationProperties": {},
"relations": {
"components": {
"title": "Components",
"target": "sbomComponent",
"required": false,
"many": true
}
}
}
SBOM webhook configuration
{
"identifier": "sbomMapper",
"title": "SBOM Mapper",
"description": "A webhook configuration to map SBOM components and vulnerabilities to Port",
"icon": "Package",
"mappings": [
{
"blueprint": "sbomComponent",
"itemsToParse": ".body.components",
"entity": {
"identifier": ".item.reference",
"title": ".item.name",
"properties": {
"version": ".item.version",
"package_url": ".item.purl",
"type": ".item.type",
"external_references": ".item.external_references",
"licenses": ".item.licenses",
"software_product": ".body.software_product + \"-\" + .body.software_version"
}
}
},
{
"blueprint": "sbomVulnerability",
"itemsToParse": ".body.vulnerabilities",
"entity": {
"identifier": ".item.id",
"title": ".item.id",
"properties": {
"description": ".item.description",
"reference": ".item.reference",
"recommendation": ".item.recommendation",
"ratings": ".item.ratings",
"source": ".item.source",
"published": ".item.published",
"state": ".item.state"
},
"relations": {
"components": ".item.affects"
}
}
}
],
"enabled": true,
"security": {}
}
note

This documentation uses the CycloneDX SBOM standard. For more information on the schema structure, you can look here

Working with Port's API and Bash script

Here are example snippets showing how to integrate Port's API and Webhook with your existing pipelines using Python and report SBOM entities from them:

Create the following Python script in your repository to create or update Port entities as part of your pipeline:

Python script for CycloneDX JSON
import requests
import json
import os

WEBHOOK_URL = os.environ['WEBHOOK_URL'] ## the value of the URL you receive after creating the Port webhook
PATH_TO_SBOM_JSON_FILE = os.environ['PATH_TO_SBOM_JSON_FILE']

def add_entity_to_port(entity_object):
"""A function to create the passed entity in Port using the webhook URL

Params
--------------
entity_object: dict
The entity to add in your Port catalog

Returns
--------------
response: dict
The response object after calling the webhook
"""
headers = {"Content-Type": "application/json"}
response = requests.post(WEBHOOK_URL, json=entity_object, headers=headers)
return response.json()


def extract_sbom_data(sbom_file):
"""This function takes an sbom file path, converts the "components" and "vulnerabilities" property into a
JSON array and it then sends this data to Port

Params
--------------
sbom_file: str
The path to the sbom file relative to the project's root folder

Returns
--------------
response: dict
The response object after calling the webhook
"""
with open(sbom_file, 'r') as file:
sbom_data = json.load(file)
software_information = sbom_data["metadata"]["component"]
software_product = software_information.get("name", "")
software_version = software_information.get("version", "")

components = []
vulnerabilities = []
for component in sbom_data.get("components", []):
component_data = {
"type": component.get("type", ""),
"reference": component.get("bom-ref", ""),
"name": component.get("name", ""),
"version": component.get("version", ""),
"purl": component.get("purl", ""),
"external_references": component.get("externalReferences", []),
"licenses": [license_data.get("license", "") for license_data in component.get("licenses", [])]
}
components.append(component_data)

for vulnerability in sbom_data.get("vulnerabilities", []):
vulnerability_data = {
"id": vulnerability.get("id"),
"description": vulnerability.get("description", ""),
"reference": vulnerability.get("bom-ref", ""),
"recommendation": vulnerability.get("recommendation", ""),
"state": vulnerability.get("analysis", {}).get("state"),
"ratings": vulnerability.get("ratings", []),
"source": vulnerability.get("source", {}).get("name"),
"affects": [bom_component.get("ref", "") for bom_component in vulnerability.get("affects", [])],
"published": vulnerability.get("published", "")
}
vulnerabilities.append(vulnerability_data)

entity_object = {
"components": components,
"vulnerabilities": vulnerabilities,
"software_product": software_product,
"software_version": software_version
}
webhook_response = add_entity_to_port(entity_object)
return webhook_response


# Example usage
response = extract_sbom_data(PATH_TO_SBOM_JSON_FILE)
print(response)