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)