SBOM for R Package Repositories (renv + GitHub Actions)
sbom.RmdPurpose
This vignette documents how to configure an R package repository to generate a Software Bill of Materials (SBOM) as part of continuous integration (CI) using:
-
renvfor reproducible dependency locking (renv.lock) - GitHub Actions for CI
- Anchore SBOM Action (Syft-based) to generate an SBOM file (SPDX JSON by default)
-
reproducibleaito standardize configuration (use_sbom()) and to write additional environment metadata (write_sbom_env())
This workflow is designed to be:
- repeatable (same steps across repos)
-
auditable (SBOM bundle includes
renv.lock+ environment manifest) - scalable (multi-language projects can share the SBOM generation approach later)
What gets produced
On every pull request and on merges to main, the
workflow will generate an artifact bundle under:
artifacts/sbom/
Typically including:
-
sbom.spdx.json(SBOM generated by the Anchore action) -
<Package>_env_sha-<shortsha>.txt(environment manifest generated byreproducibleai) -
renv.lock(copied into the bundle to document the dependency lock)
Artifacts are uploaded with a target retention of 120 days, subject to GitHub org/repo policy.
Prerequisites
renv (required for SBOM)
SBOM generation in this workflow requires renv.lock.
If your repo does not yet use renv, initialize it from
the package root:
install.packages("renv")
renv::init()
Commit the resulting files:
renv.lockrenv/activate.R
Do not commit renv/library/.
Step-by-step: enable SBOM in an R package repo
From the package root (folder containing
DESCRIPTION):
1) Install reproducibleai and snapshot
Install reproducibleai using your standard method (for
your environment):
pak::pak("MVR-GIS/reproducibleai")
then:
renv::snapshot()
This ensures reproducibleai is recorded in
renv.lock so CI can restore it.
2) Scaffold SBOM workflow
Run once:
reproducibleai::use_sbom()
This will:
- write
.github/workflows/sbom-r.yml - add
/artifacts/to.gitignore - add
^artifacts$to.Rbuildignore
Commit these changes.
Troubleshooting
renv::restore() fails compiling packages (common with
sf stacks)
If your package depends on sf, terra,
units, xml2, etc., CI may fail due to missing
system libraries/headers on Ubuntu runners.
The default workflow written by use_sbom() installs a
baseline set of Ubuntu packages (GDAL/PROJ/GEOS/udunits, etc.), but you
may need to extend it depending on your dependency graph.
Look for errors like:
fatal error: ...: No such file or directoryconfigure: error: ... not found
Then add the corresponding Ubuntu apt-get package(s) to
the workflow.
Appendix: what write_sbom_env() records
The environment manifest includes:
- Package name + version (from
DESCRIPTION) - git SHA (from
GITHUB_SHAin CI when available) - timestamp (UTC)
- R version + platform details
- sha256 hash of
renv.lock
This provides a lightweight audit trail linking the SBOM file to the exact locked dependency specification used by the repository.