Examples
========

The following examples are based on common use-cases.

Generate
~~~~~~~~

Generation happens fully offline and can run against an arbitrary root directory.

Local System
^^^^^^^^^^^^

Generate a CycloneDX SBOM of the current system.

.. code-block:: bash

    debsbom --progress generate -t cdx -o sbom
    # output in sbom.cdx.json

Container Rootfs
^^^^^^^^^^^^^^^^

Create the SBOM of a Debian-based container (rootless).
The ``debsbom`` tool hereby is used from the host (e.g. from a Python venv).

Using `Podman <https://podman.io/>`__:

.. code-block:: bash

    CRT=$(podman create debian:trixie)
    CHROOT=$(podman unshare podman mount $CRT)
    podman unshare debsbom generate -t spdx --root $CHROOT

In CI-like environments, it is often more practical to use `skopeo <https://github.com/podman-container-tools/skopeo>`__
and `umoci <https://github.com/opencontainers/umoci>`__ instead:

.. code-block:: bash

    skopeo copy docker://debian:trixie oci:debian:trixie
    umoci raw unpack --rootless --image debian:trixie ./rootfs
    debsbom generate -t spdx --root ./rootfs

You can also scan a container export directly, without unpacking the complete root filesystem:

.. code-block:: bash

    CRT=$(podman create debian:trixie)
    podman export "$CRT" -o rootfs.tar
    debsbom generate -t spdx --root rootfs.tar

To avoid the temporary tar file as well, stream the uncompressed export through stdin:

.. code-block:: bash

    podman export "$CRT" | debsbom generate -t spdx --root -

Compressed tar files use their filename extension to select the decompressor. The supported
extensions are ``.bz2``, ``.gz``, ``.xz``, ``.zst``, and ``.lz4``. Compression cannot be
selected by filename when reading from stdin, so ``podman export`` should be piped directly.

From Package List
^^^^^^^^^^^^^^^^^

Create the SBOM from a package list. The so provided packages will still be enriched with any available data from the apt cache.

.. code-block:: bash

    echo "htop 3.4.1-5 amd64" | debsbom generate --from-pkglist
    # or in isar manifest format
    echo "json-c|0.16-2|libjson-c5:amd64|0.16-2" | debsbom generate --from-pkglist
    # or with PURLs
    echo "pkg:deb/debian/htop@3.4.1-5?arch=amd64" | debsbom generate --from-pkglist

It further is possible to inject a dpkg status file via stdin (e.g. if you only have that file).
The data is then also resolved from the apt-cache (if available), but this usually only makes sense if you don't have a
chroot and want to create the sbom just from the data in the file.

.. code-block:: bash

    cat path/to/dpkg/status | debsbom generate --from-pkglist

Please mind that only packages that are passed via the package list are included in the resulting SBOM. This leaves out any dependencies
that you might expect to see for a package. If you want to have these included you also need to explicitly pass them in the package list.

Download
~~~~~~~~

Lookup all packages on the ``snapshot.debian.org`` mirror and download all binary and source artifacts referenced in an SBOM:

.. code-block:: bash

    debsbom --progress \
        download --outdir downloads --sources --binaries sbom.cdx.json
    find downloads -mindepth 1 -maxdepth 1
    # downloads/.cache   <- debsbom metadata to map packages to artifacts
    # downloads/sources  <- files related to source packages (e.g. .dsc, .orig.tar)
    # downloads/binaries <- .deb files

It is also possible to download multiple packages by name, version and architecture:

.. code-block:: bash

    cat <<EOF | debsbom download --binaries --sources
    cpp 4:12.2.0-3 amd64
    guestfs-tools 1.52.3-1 source
    EOF

Alternatively, the download can be executed from the container image:

.. code-block:: bash

    echo "guestfs-tools 1.52.3-1 source" | \
    docker run -v$(pwd)/downloads:/mnt/downloads -i ghcr.io/siemens/debsbom:latest \
        debsbom download --outdir /mnt/downloads --sources

Merge Source Packages
~~~~~~~~~~~~~~~~~~~~~

Debian source packages consist of a ``.dsc`` file along with one or more related artifacts.
The :doc:`/commands/source-merge` takes care of merging all referenced artifacts of a debian source package into a single archive.
All referenced files have to be downloaded upfront, by using the :doc:`/commands/download`.

.. note::
    Internally, the ``dpkg-source`` command from the ``dpkg-dev`` package is used to perform the merge.

The following example merges all debian source packages referenced in the ``sbom.cdx.json``, applies the debian patches and compresses the new artifacts with ZStandard.

.. code-block:: bash

    debsbom --progress \
        source-merge \
            --compress zstd \
            --apply-patches \
            sbom.cdx.json

Repack Artifacts
~~~~~~~~~~~~~~~~

The :doc:`/commands/repack` is similar to the :doc:`/commands/source-merge` but performs additional steps to re-layout the downloaded artifacts and recreate the SBOM.
The following example generates a ``standard-bom-package`` source distribution archive.

.. code-block:: bash

    debsbom --progress repack \
        --dldir downloads \
        --outdir source-archive \
        --compress zstd \
        --apply-patches \
        --validate \
        sbom.cdx.json sbom.packed.cdx.json

It further is possible to only repack (and update in the SBOM) a subset of packages.
For that, provide both an SBOM, as well as a set of "to-be-processed" packages via stdin.

.. code-block:: bash

    echo "bash 5.2.37-2 source" | debsbom -v repack sbom-in.json sbom-out.json

Compare SBOMs
~~~~~~~~~~~~~

The SBOMs produced by ``debsbom`` can be further processed with existing tools – for example, the `CycloneDX CLI <https://github.com/CycloneDX/cyclonedx-cli>`_.
Comparing two SBOMs directly is outside the scope of ``debsbom``, but you can determine which components have changed by using a short snippet such as the one shown below.

Locate Changes
^^^^^^^^^^^^^^

.. code-block:: bash

    cyclonedx-cli diff --component-versions --output-format json \
        sbom.old.cdx.json sbom.cdx.json | \
    jq -r '.componentVersions[] | select(.added!=[] or .removed!=[]) | {"added": .added[0].purl, "removed": .removed[0].purl}'
    # {"added", "purl-a-1.1", "removed": "purl-a-1.0"}
    # {...}

A similar output can be generated by just using ``jq`` and ``diff``:

.. code-block:: bash

    diff --color \
        <(jq -r --sort-keys '.components[].purl' sbom.old.cdx.json) \
        <(jq -r --sort-keys '.components[].purl' sbom.cdx.json)

Identify new Components
^^^^^^^^^^^^^^^^^^^^^^^

Consider you only want to know the changed and added components, e.g. for license clearing.

.. code-block:: bash

    PURLS=$( \
        diff -U0 \
            <(jq -r --sort-keys '.components[].purl' sbom.old.cdx.json) \
            <(jq -r --sort-keys '.components[].purl' sbom.cdx.json) \
            | grep ^+pkg | sed 's/^+//' \
    )

The PURLs can be used as input to debsbom to download / merge components:

.. code-block:: bash

    echo "$PURLS" | debsbom download --sources --binaries

Once downloaded, it is possible to merge the source packages:

.. code-block:: bash

    echo "$PURLS" | debsbom source-merge --apply-patches

And the same list of packages can be repacked:

.. code-block:: bash

    echo "$PURLS" | debsbom repack \
        --apply-patches
        sbom.cdx.json \
        sbom.cdx.repacked.json

Delta SBOMs
~~~~~~~~~~~

The :doc:`/commands/delta` compares a base (reference) SBOM with a target (new) SBOM and produces
a new SBOM containing only the components present in the target. The typical use-case is identifying
newly added or changed components between two builds or releases.

Use ``debsbom delta`` when you only want to see changed or added components, e.g., to generate an
SBOM for license clearance.

.. code-block:: bash

   debsbom delta sbom.old.cdx.json sbom.cdx.json extras.cdx.json

You can also pass SBOMs via stdin, but you also have to pass the SBOM type in this case:

.. code-block:: bash

   cat sbom.old.spdx.json sbom.spdx.json | debsbom delta -t spdx - - -o -

Export as Graph
~~~~~~~~~~~~~~~

The :doc:`/commands/export` allows one to convert the SBOM into various graph representations.
These can be used as input to graph visualization and analysis tooling (like Gephi).

.. note::
    We recommend to use the SPDX format as input, as this describes inter package relations
    more precisely.

Convert the SPDX SBOM to GraphML:

.. code-block:: bash

    debsbom export sbom.spdx.json sbom-graph.graphml

Merging multiple SBOMs
~~~~~~~~~~~~~~~~~~~~~~

The :doc:`/commands/merge` merges multiple SBOMs hierarchically. The intended use-case is to
combine multiple SBOMs describing a Debian-based distribution. A good example is the rootfs
and the initrd of a Linux distribution.

Merge two SBOMs representing the above case:

.. code-block:: bash

    debsbom merge rootfs.spdx.json initrd.spdx.json -o merged.spdx.json

You can also pass SBOMs via stdin, but you also have to pass the SBOM type in this case:

.. code-block:: bash

    cat rootfs.spdx.json initrd.spdx.json | debsbom merge -t spdx -o merged.spdx.json -

Filter packages of an SBOM
~~~~~~~~~~~~~~~~~~~~~~~~~~

The :doc:`/commands/filter` filters selected packages in an SBOM.

You can filter to include only binary or source packages:

.. code-block:: bash

    debsbom filter --binaries sbom.spdx.json filtered.spdx.json
    debsbom filter --sources sbom.spdx.json filtered.spdx.json

You can also get the subgraph for a specific package:

.. code-block:: bash

    debsbom filter --package debsbom sbom.spdx.json package-filtered.spdx.json

Combining multiple filters are logically ``and``ed. The following would give you all source packages ``debsbom`` transitively depends on:

.. code-block:: bash

    debsbom filter --sources --package debsbom sbom.spdx.json package-source-filtered.spdx.json


License-Clearing Workflow
~~~~~~~~~~~~~~~~~~~~~~~~~

``debsbom`` can be used for license clearing. The license clearing workflow could look like this:

First, generate a CycloneDX SBOM of a rootfs:

.. code-block:: bash

    debsbom --progress generate -r path/to/the/rootfs -t cdx -o sbom
    # output in sbom.cdx.json

Use the generated SBOM to download all source packages:

.. code-block:: bash

    debsbom --progress download --outdir downloads --sources sbom.cdx.json
    # the downloaded files will be in downloads/sources/<archive>

You will notice that there is no single file for each source package. Instead there is multiple:
the .dsc file, an .orig.tar tarball, maybe some patches and more. ``debsbom`` provides an easy
way to combine them into a single tarball that can be used in most license clearing platforms:

.. code-block:: bash

    debsbom --progress source-merge --compress zstd --apply-patches sbom.cdx.json
    # merged and patched compressed tarballs are in downloads/sources/<archive>

Now there is a single compressed file for each source package.

.. note::
    If you only need to work on a smaller subset of packages you can pass a package list
    via stdin. See the above sections for concrete examples how to do that.

Alternatively you can use the :doc:`/commands/repack` to rewrite the SBOM and repack the downloaded
artifacts in a format-specific way:

.. code-block:: bash

    debsbom --progress repack \
        --format standard-bom-package \
        --dldir downloads \
        --compress zstd \
        --apply-patches \
        --validate \
        sbom.cdx.json sbom.packed.cdx.json

This step is very specific to the actual use-case you have. Right now the only available format
is ``standard-bom-package``, which created a directory structure and rewrites the SBOM to reference
all source packages directly in there. If you want to see more formats you can open an issue,
or even better, contribute it directly.

Vulnerability Analysis
~~~~~~~~~~~~~~~~~~~~~~

``debsbom`` can check a Debian SBOM for known vulnerabilities based on of the
`Debian Security Tracker <https://security-tracker.debian.org/tracker/>`_.
Reports can be generated in various formats, including OpenVEX and SARIF.

The following example demonstrates how to generate an OpenVEX report for all components in the
SBOM. The result can be used as input to other vulnerability analysis tooling that is not
capable of correctly handling components with patch versions.

.. code-block:: bash

    debsbom sec-scan \
        --update-db \
        --author "Test <test@example.com>" \
        --format vex \
        sbom.cdx.json \
    > result.vex

When scanning SBOMs of existing products, it is often necessary to evaluate the impact of a
vulnerability in the context of the overall system. For example, a vulnerability in a
component may not be exploitable because the vulnerable code path is not in use. To identify
who can make this assessment, you can emit the path from the vulnerable component to
the root component (similar to ``debsbom trace-path``) on a per-vulnerability basis:

.. code-block:: bash

    debsbom sec-scan \
        --format json \
        --with-paths-to-root \
        sbom.cdx.json \
    | jq | less
