CRA Desk
Every generate step

Generating an SBOM for Elixir / Erlang (Mix)

The step below writes a CycloneDX JSON software bill of materials (SBOM) in your own pipeline. The CRA Desk scan reads that file and turns it into a Cyber Resilience Act (CRA) readiness report - it never generates one for you.

Add to mix.exs:

defp deps do
  [{:sbom, "~> 0.6", only: :dev, runtime: false}]
end

Run in CI:

mix deps.get
mix sbom.cyclonedx -f -o sbom.json
Produces:
sbom.json
Format:
CycloneDX JSON
Generator documentation

What the generator actually reads

mix.lock is the input, so the file describes the versions Mix resolved for the current project, Erlang dependencies included - but only once mix deps.get has run, because an empty lock produces an empty inventory rather than an error.

Versions and package URLs

Dependencies come out as pkg:hex purls matching OSV's Hex advisories and both Elixir and Erlang packages from Hex share that namespace - which is what makes a mixed BEAM project readable in one file. A dependency pulled from a git ref rather than from Hex has no purl of that kind and is counted as a gap.

The whole CI job

GitHub Actions

- uses: actions/checkout@v4
- run: mix deps.get
- run: mix sbom.cyclonedx -f -o sbom.json
- uses: mmalinowski/cradesk-action@v1
  with:
    sbom-path: sbom.json

GitLab CI/CD

generate-sbom:
  script:
    - mix deps.get
    - mix sbom.cyclonedx -f -o sbom.json

include:
  - component: gitlab.com/cradesk/scan/readiness@1
    inputs:
      sbom_path: sbom.json

Only the first step changes with your stack - the CRA Desk step after it is identical everywhere.

What goes wrong here

The default output is XML, so -f json is not optional here. The dependency is dev-only, which keeps it out of your release.

Repositories with more than one thing in them

An umbrella project is several applications behind one lock at the root. Generating from the umbrella root gives you the union; generating inside one child application gives that application's own dependencies. Pick whichever matches what you ship and keep the choice stable so two reports stay comparable.

What CRA Desk does with the result

Components from this build carry pkg:hex package URLs, which the watch matches against OSV's Hex advisories when the SBOM arrives and again as new advisories land. Matching runs on every plan; e-mail alerts and the full match list are what a paid plan adds.

A generator that runs is not the same as coverage. Components with no purl, no version, or from an ecosystem outside the ones we watch are counted as gaps in every report rather than reported as clean.

Other stacks