Reads an SBOM in any of the eight formats that write_sbom() writes, made
by sbom or by any other tool, into an <sbom> object. It can then be
inspected with sbom_components(), compared with sbom_diff(), or written
again in any format.
Arguments
- path
Path of the SBOM file.
- format
NULLto detect the format from the content, or one of theformatvalues ofsbom_formats()other than"csv", which the file must then be.
Value
An <sbom> object. Its metadata$inputs holds path. When the
file is not an SBOM in a format sbom reads, the error has class
sbom_read_error.
Details
read_sbom() reads CycloneDX JSON and XML (1.4 to 1.7), SPDX 2.2 and 2.3
as JSON, YAML, XML or tag-value, SPDX 3.0.1 JSON-LD, and SWID tags
(ISO/IEC 19770-2:2015). It detects the format from the file's content, not
from its name, so the file can be named anything. Reading SPDX YAML needs
the yaml package. SPDX YAML nested more than 200 levels deep, or holding
more than one YAML document, is a read error found before the file is
parsed. A crafted SPDX YAML file can still take tens of seconds to refuse.
Each component or package the document lists becomes a component (SPDX
files and snippets do not), the one the document describes becomes the
root, and each dependency between two components becomes a relationship.
A component is optional when the document says so, or when every
dependency on it is optional. The document's own notes follow a first note
that names the file and its format. An element without an id takes its
purl as its ref, then name@version, then component-<n>. The ecosystem
is the purl type, and "unknown" without a purl. URLs are kept as sbom
keeps its own: without credentials, query string or fragment, and never a
local path or a file: URL, and so are the URLs in a purl's qualifiers,
such as repository_url. Each control character of a value (C0 but tab
and newline, DEL and C1) is replaced with a space, and so are tab and
newline in names, versions, refs and purls, which are then trimmed.
The OSV advisory listings the document holds, as sbom and R Observatory
write them, are read too, for sbom_advisories(): CycloneDX
vulnerabilities whose source is OSV and that hold no analysis; SPDX 2
advisory references (category SECURITY in SPDX 2.3, OTHER in 2.2)
whose locator is an osv.dev vulnerability page and whose comment says, in
sbom's words, that OSV lists the package that holds it at its version,
naming no other id; and SPDX 3
security_Vulnerability elements whose securityOther identifier points
to osv.dev, with their hasAssociatedVulnerability relationships. Each
names the components it affects, at their versions. Other vulnerability
entries, such as another tool's vulnerabilities and VEX statements, are
not OSV advisory listings: they are not read, since every format sbom
writes says that OSV lists each advisory for the version. Nor is an entry
read for a component it states something else about: a CycloneDX
affects target with versions none of which has status affected for
the component's version, or for no version or range, and an SPDX 3
association beside a VEX relationship of the same vulnerability that
involves the same component. An advisory is
kept only when its id is an OSV id and it names a component of the
document that has a version. The <sbom>'s advisory status is
"listed" when the document lists an advisory, or says in R
Observatory's words that it lists those OSV gives, and "not-requested"
otherwise.
Some values cannot come back from every format:
| Format | Not read back |
| All | sbom's own ecosystems (local, git, repository, r, base-r), DESCRIPTION dependency fields and asserted overrides; CPE identifiers; vulnerability entries that are not OSV advisory listings, such as VEX statements; checksums other than MD5, SHA-1, SHA-256, SHA-384, SHA-512 and SHA3; URLs that are not valid IRI references, local paths, and purl qualifiers whose value is a local path; licenses of other SPDX documents (DocumentRef-), kept only as written |
| CycloneDX | license comments and package file names; a root's maintainer may be the organization in metadata.manufacture, which SPDX then writes as a person; the versions that fix an advisory, and the upstream record each rating comes from |
| SPDX 2 | refs (SPDX ids replace them, so sbom_diff() matches components it identifies by ref only partly), supplier URLs, the license as written, evidence, minimum versions, system requirements and Bioconductor releases; maintainers that are not persons; the descriptions and publication dates that sbom writes in comments; the texts of extracted licenses (hasExtractedLicensingInfos), so a document written again says that the text is not included; whether a supplier is a person, so a Person: supplier is written again as an Organization:; an advisory's summary, publication date, source URL, CVE ids and ratings. SPDX 2.2 has no primary purpose, so every package is a library; SPDX 2.3 gives R the type application. SPDX 2.2 cannot carry SHA3 checksums, so they are left out |
| SPDX 3 | refs, as in SPDX 2; supplier URLs, the license as written, license comments, evidence, minimum versions, package file names, system requirements and Bioconductor releases; maintainers that are not persons; which component holds another; the descriptions that sbom writes in comments; the versions that fix an advisory, and its ratings |
| SWID | refs of code compiled into a package, which gets no link; for the root, license expressions and comments, checksums, descriptions, publication dates, DOIs, evidence and Bioconductor releases; for the other components, everything but the name, version, purl, minimum version and whether it is optional; relationships other than the root's; advisories, which a tag has no place for. A tag creator with a real regid is the organization, any other is an author, except sbom itself |
Issues
The <sbom> records what could not be read as issues (sbom_issues()):
read-files-skipped(info): the document lists SPDX files or snippets, which are not components.read-duplicate-id(warning): elements share an id, so the later ones get the suffix-2,-3and so on.read-relationships-skipped(info): relationships of types sbom does not model.read-dangling-relationships(warning): relationships that name elements the document does not define.read-several-roots(info): the document describes more than one component, and the first in id order is the root.read-no-root(warning): the document describes no component, so a placeholder root with the ref"document"is added.read-values-dropped(info): values that sbom's formats cannot carry were not kept: URLs that are not valid IRI references, local paths (purl qualifiers among them), checksums of other algorithms or lengths, DOIs that cannot form a URL, and CPE identifiers.read-advisories-dropped(info): vulnerability entries (CycloneDX vulnerabilities, SPDX 2 advisory references, SPDX 3 vulnerabilities) that were not read, each counted once: those that are not OSV advisory listings, such as VEX statements and other sources' vulnerabilities, those whose id is not an OSV id, and those that name no component of the document that has a version; and the components that an entry otherwise read was not read for, since it gives them version statuses or VEX statements that are not listings. An entry that is a listing of none of the components it names is not an OSV advisory listing.read-control-characters(info): values held control characters, which were replaced with spaces.
When the document has no timestamp, or one that is not ISO 8601, the time
in the SOURCE_DATE_EPOCH environment variable is used when it is set, and
otherwise the time it was read, and a note says so.
See also
validate_sbom() to check an SBOM file against its schema and the
NTIA minimum elements.
Examples
x <- sbom_package(system.file("DESCRIPTION", package = "sbom"), system = FALSE)
path <- file.path(tempdir(), "sbom.cdx.json")
write_sbom(x, path)
y <- read_sbom(path)
y
#> <sbom> sbom 0.1.0
#> Components: 19
#> Relationships: 28
#> Issues: 0
#> Advisories: not requested.
sbom_components(y)[, c("ref", "name", "version", "license_spdx")]
#> ref
#> 1 R
#> 2 R/methods
#> 3 R/utils
#> 4 local/sbom
#> 5 pkg:cran/cli@3.6.6?repository_url=https://packagemanager.posit.co/cran/__linux__/resolute/latest
#> 6 pkg:cran/curl@8.1.0?repository_url=https://packagemanager.posit.co/cran/__linux__/resolute/latest
#> 7 pkg:cran/htmltools@0.5.9?repository_url=https://packagemanager.posit.co/cran/__linux__/resolute/latest
#> 8 pkg:cran/jsonlite@2.0.0?repository_url=https://packagemanager.posit.co/cran/__linux__/resolute/latest
#> 9 pkg:cran/jsonvalidate@1.5.0?repository_url=https://packagemanager.posit.co/cran/__linux__/resolute/latest
#> 10 pkg:cran/knitr@1.52?repository_url=https://packagemanager.posit.co/cran/__linux__/resolute/latest
#> 11 pkg:cran/pak@0.11.2?repository_url=https://packagemanager.posit.co/cran/__linux__/resolute/latest
#> 12 pkg:cran/quarto@1.5.1?repository_url=https://packagemanager.posit.co/cran/__linux__/resolute/latest
#> 13 pkg:cran/renv@1.3.1?repository_url=https://packagemanager.posit.co/cran/__linux__/resolute/latest
#> 14 pkg:cran/rlang@1.3.0?repository_url=https://packagemanager.posit.co/cran/__linux__/resolute/latest
#> 15 pkg:cran/rmarkdown@2.32?repository_url=https://packagemanager.posit.co/cran/__linux__/resolute/latest
#> 16 pkg:cran/testthat@3.3.2?repository_url=https://packagemanager.posit.co/cran/__linux__/resolute/latest
#> 17 pkg:cran/withr@3.0.3?repository_url=https://packagemanager.posit.co/cran/__linux__/resolute/latest
#> 18 pkg:cran/xml2@1.6.0?repository_url=https://packagemanager.posit.co/cran/__linux__/resolute/latest
#> 19 pkg:cran/yaml@2.3.12?repository_url=https://packagemanager.posit.co/cran/__linux__/resolute/latest
#> name version license_spdx
#> 1 R 4.6.2 GPL-2.0-only OR GPL-3.0-only
#> 2 methods 4.6.2 <NA>
#> 3 utils 4.6.2 <NA>
#> 4 sbom 0.1.0 MIT
#> 5 cli 3.6.6 MIT
#> 6 curl 8.1.0 MIT
#> 7 htmltools 0.5.9 GPL-2.0-only OR GPL-3.0-only
#> 8 jsonlite 2.0.0 MIT
#> 9 jsonvalidate 1.5.0 MIT
#> 10 knitr 1.52 GPL-2.0-only OR GPL-3.0-only
#> 11 pak 0.11.2 GPL-3.0-only
#> 12 quarto 1.5.1 MIT
#> 13 renv 1.3.1 MIT
#> 14 rlang 1.3.0 MIT
#> 15 rmarkdown 2.32 MIT
#> 16 testthat 3.3.2 MIT
#> 17 withr 3.0.3 MIT
#> 18 xml2 1.6.0 MIT
#> 19 yaml 2.3.12 BSD-3-Clause