Skip to content

feat(ci): add a full SBOM - app deps, OTP/Elixir runtime, container OS packages - #54

Merged
bougyman merged 3 commits into
mainfrom
issue-53
Aug 10, 2026
Merged

feat(ci): add a full SBOM - app deps, OTP/Elixir runtime, container OS packages#54
bougyman merged 3 commits into
mainfrom
issue-53

Conversation

@bougyman

@bougyman bougyman commented Aug 10, 2026

Copy link
Copy Markdown
Member

Summary

Closes #53.

mix.lock has exact versions + checksums for the Hex dependency tree, but it's not a real SBOM - wrong format (Erlang-term syntax, not SPDX/CycloneDX), no license data, and doesn't cover the OTP/ERTS runtime Burrito bundles into each binary or the Alpine packages baked into the container image.

Two real SBOMs, kept as separate files since a container SBOM has no use to anyone not using the container:

  • App + Hex deps + Erlang/OTP + Elixir runtime, via erlef/mix_sbom (verified: includes the OTP standard library apps - kernel/stdlib/crypto/ssl/etc - and Elixir at the exact pinned version by default, no manual merge needed). Generated in the burrito job, attached to the release as sbom.cdx.json in the same atomic gh release create call that creates the release.
  • Container OS packages (Alpine/apk), via aquasecurity/trivy-action (--format cyclonedx). Generated in the container job, which runs after the release is already published (and thus immutable, Releases ship with zero assets - GitHub's Immutable Releases locks them before the build finishes #18) - published as a workflow artifact, not a release asset, since it genuinely can't be attached to the already-locked release.

Test plan

  • mix test - 182 passed
  • mix format --check-formatted - clean
  • Ran mix sbom.cyclonedx for real locally and inspected the actual output - confirmed it includes elixir at our exact pinned version (1.20.3) plus the OTP standard library apps, alongside all real Hex deps (67 components total)
  • Verified aquasecurity/trivy-action's format input passes straight through to Trivy's own CLI (checked entrypoint.sh directly - only sarif/github are special-cased, cyclonedx isn't)
  • Confirmed the exact local image tag ci/build_image.sh produces (linear-cli-ex:<tag>, no registry prefix) so Trivy scans the right reference
  • Both edited workflow/doc files validated (ruby -ryaml, asciidoctor -o /dev/null)
  • Next real release should show both new steps succeed, sbom.cdx.json attached to the release, and a container-sbom workflow artifact on the container job

🤖 Generated with Claude Code

…S packages

mix.lock has exact versions + checksums for the Hex dependency tree,
but it's not a real SBOM - wrong format (Erlang-term syntax, not SPDX/
CycloneDX), no license data, and doesn't cover the OTP/ERTS runtime
Burrito bundles into each binary or the Alpine packages baked into the
container image.

Two real SBOMs, kept as separate files since a container SBOM has no
use to anyone not using the container:

- App + Hex deps + Erlang/OTP + Elixir runtime, via erlef/mix_sbom
  (verified: includes the OTP standard library apps - kernel/stdlib/
  crypto/ssl/etc - and Elixir at the exact pinned version by default,
  no manual merge needed). Generated in the burrito job, attached to
  the release as sbom.cdx.json in the same atomic `gh release create`
  call that creates the release.
- Container OS packages (Alpine/apk), via aquasecurity/trivy-action
  (--format cyclonedx). Generated in the container job, which runs
  after the release is already published (and thus immutable, #18) -
  published as a workflow artifact, not a release asset, since it
  genuinely can't be attached to the already-locked release.

Closes #53.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings August 10, 2026 13:14

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds automated generation and publishing of Software Bill of Materials (SBOM) outputs as part of the release pipeline, covering both application/runtime dependencies and container OS packages, and documents the new artifacts for users.

Changes:

  • Generate an app/runtime CycloneDX SBOM during the Burrito release job and upload it with the GitHub release assets.
  • Generate a separate CycloneDX SBOM for container OS packages via Trivy and upload it as a workflow artifact.
  • Document the SBOM outputs in the README and add the SBOM tooling dependency to the app.

Reviewed changes

Copilot reviewed 3 out of 4 changed files in this pull request and generated 2 comments.

File Description
Readme.adoc Documents the new SBOM outputs and where they are published.
app/mix.exs Adds the :sbom dependency for local/dev SBOM generation.
app/mix.lock Locks new transitive deps introduced by :sbom.
.github/workflows/main.yaml Implements app SBOM generation/upload in the release job and container SBOM generation/upload in the container job.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread app/mix.exs Outdated
Comment thread .github/workflows/main.yaml
Two review findings on #54:

- `~> 0.8` doesn't allow 0.10.0 (Elixir's ~> pins the second segment
  tight for pre-1.0 versions), but mix.lock already resolved to
  0.10.0 - the exact version already tested. Widened to `~> 0.10`
  rather than downgrading.
- erlef/mix_sbom has no output-filename input (verified directly in
  the action's own script: it always writes to
  $RUNNER_TEMP/$RANDOM.cdx.json, exposed via sbom-path). gh release
  create uses a file's own basename as the actual download filename -
  the `#label` syntax only sets a cosmetic display label, not the
  filename - so without an explicit rename, the Readme's documented
  .../download/sbom.cdx.json URL would 404. Added a rename step.
@bougyman
bougyman merged commit e296fdd into main Aug 10, 2026
2 checks passed
@bougyman
bougyman deleted the issue-53 branch August 10, 2026 14:12
bougyman pushed a commit that referenced this pull request Aug 10, 2026
🤖 I have created a release *beep* *boop*
---


##
[0.8.3](v0.8.2...v0.8.3)
(2026-08-10)


### Features

* **ci:** add a full SBOM - app deps, OTP/Elixir runtime, container OS
packages ([#54](#54))
([e296fdd](e296fdd))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).
This was referenced Aug 11, 2026
bougyman pushed a commit that referenced this pull request Aug 11, 2026
🤖 I have created a release *beep* *boop*
---


##
[1.0.0](v1.0.0...v1.0.0)
(2026-08-11)


### ⚠ BREAKING CHANGES

* graduate to 1.0.0 - disable pre-major version bumping
([#70](#70))
* **cd:** parallelize Burrito target builds and fix Trivy/Podman image
scanning ([#68](#68))
* **ci:** rename release.yaml to main.yaml, workflow name to "main"
([#38](#38))
* add Readme/LICENSE, feat: wire up the issue list --project picker
([#12](#12))

### Features

* add mix githooks.install to activate the repo's git hooks
([#51](#51))
([9b35472](9b35472))
* **api:** add LinearCli.Api GraphQL client (Phase 1)
([723f3f6](723f3f6))
* **ci:** add a full SBOM - app deps, OTP/Elixir runtime, container OS
packages ([#54](#54))
([e296fdd](e296fdd))
* **cli:** add favorite teams/projects, filtering list views by them
([#61](#61))
([6c858d9](6c858d9))
* **cli:** add issue create/develop/pr/take/update write commands (Phase
6)
([1649618](1649618))
* **cli:** add profiles - default team/project stored in local SQLite
([#57](#57))
([554e336](554e336))
* **cli:** add project update - post a status update to a project
([#43](#43))
([30dc6dc](30dc6dc))
* **cli:** make version respect --output json
([#33](#33))
([b160aad](b160aad))
* **cli:** resolve bare issue numbers via active profile, favorited
teams, or a team prompt
([#65](#65))
([8b183da](8b183da))
* **cli:** support Ruby's short subcommand aliases
([#15](#15))
([9fca6b5](9fca6b5))
* initial commit with ash submodule
([c2ceafb](c2ceafb))
* **linear:** add Ash domain resources for
Issue/Project/Team/User/Label/WorkflowState/Comment (Phase 2)
([e2a27f3](e2a27f3))
* **oban:** add scheduled monthly project rollover (Phase 7)
([11afb43](11afb43))
* phase 4 from initial plan -&gt; complete
([012866e](012866e))
* phase 8 - packaging, releasing, and CI
([#1](#1))
([905c238](905c238))
* scaffold Elixir port and enforce conventional commits
([a4d03a0](a4d03a0))


### Bug Fixes

* **ci:** consolidate the release pipeline into one workflow/DAG
([ba821bb](ba821bb))
* **ci:** create releases as drafts so assets survive Immutable Releases
([#19](#19))
([8572623](8572623))
* **ci:** package release binaries with the wrapper scripts
([#24](#24))
([5fb24a4](5fb24a4))
* **ci:** rebuild the release pipeline to stop the version-bump runaway
loop ([#30](#30))
([c311fd4](c311fd4))
* **ci:** relabel the release PR as tagged after we tag it ourselves
([ab1408e](ab1408e))
* **ci:** skip commit-subject validation in the post-merge pipeline
([#41](#41))
([3d00a85](3d00a85))
* **cli:** reject unrecognized flags instead of treating them as issue
ids ([#2](#2))
([#4](#4))
([e697ff6](e697ff6))
* **deps:** update ash to a non-vulnerable version
([#63](#63))
([b838e2a](b838e2a))


### Performance Improvements

* **linear:** fan out find-by-ids and per-team project fetches (Phase 5)
([fb00153](fb00153))


### Documentation

* add Readme/LICENSE, feat: wire up the issue list --project picker
([#12](#12))
([eb42c69](eb42c69))


### Miscellaneous Chores

* **ci:** rename release.yaml to main.yaml, workflow name to "main"
([#38](#38))
([2581a40](2581a40))
* graduate to 1.0.0 - disable pre-major version bumping
([#70](#70))
([87a65ae](87a65ae))


### Continuous Integration

* **cd:** parallelize Burrito target builds and fix Trivy/Podman image
scanning ([#68](#68))
([5cc829a](5cc829a))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add a full SBOM: app deps, Erlang/OTP + Elixir runtime, and container OS packages

2 participants