Travis CI jobs run on a virtual machine rather than inside a container of your choosing, so the integration is a plain docker run from the job with the docker service enabled.
Minimal example
language: minimal
services:
- docker
script:
- |
docker run --rm \
-v "$TRAVIS_BUILD_DIR:/workspace" \
-e TRAVIS -e TRAVIS_COMMIT -e TRAVIS_BRANCH \
-e TRAVIS_TAG -e TRAVIS_PULL_REQUEST_BRANCH \
-e LOCK_FILE=requirements.txt \
-e OUTPUT_FILE=sbom.cdx.json \
-e ENRICH=true \
-e UPLOAD=false \
ghcr.io/sbomify/sbomify-actionThe bare -e TRAVIS form forwards the variable’s value from the job into the container. That part matters: the job runs on the VM, and docker run passes nothing through unless you ask it to. Without those five the container sees no Travis environment at all, is treated as a local run, and records no repository details - see VCS information.
Uploading to sbomify
Define TOKEN as an encrypted environment variable in the repository settings, or with travis encrypt, and forward it the same way:
script:
- |
docker run --rm \
-v "$TRAVIS_BUILD_DIR:/workspace" \
-e TRAVIS -e TRAVIS_COMMIT -e TRAVIS_BRANCH \
-e TRAVIS_TAG -e TRAVIS_PULL_REQUEST_BRANCH \
-e TOKEN \
-e COMPONENT_ID=your-component-id \
-e LOCK_FILE=requirements.txt \
-e AUGMENT=true \
-e ENRICH=true \
ghcr.io/sbomify/sbomify-actionLeave “Display value in build log” off, and keep the variable out of pull request builds unless you need it there - Travis withholds encrypted variables from forked pull requests by default, which is the behaviour you want.
Travis CI does not support OIDC trusted publishing; that is currently GitHub-only.
Caching
Travis restores declared directories between builds, so point the tool caches at one of them and mount it into the container:
cache:
directories:
- $HOME/.sbomify-cache
script:
- |
docker run --rm \
-v "$TRAVIS_BUILD_DIR:/workspace" \
-v "$HOME/.sbomify-cache:/cache" \
-e TRAVIS -e TRAVIS_COMMIT -e TRAVIS_BRANCH \
-e TRAVIS_TAG -e TRAVIS_PULL_REQUEST_BRANCH \
-e SBOMIFY_CACHE_DIR=/cache/sbomify \
-e SYFT_CACHE_DIR=/cache/syft \
-e SBOMIFY_TOOL_CACHE=/cache/runtimes \
-e LOCK_FILE=poetry.lock \
-e ENRICH=true \
-e UPLOAD=false \
ghcr.io/sbomify/sbomify-actionForward GITHUB_TOKEN as well. License databases come from GitHub Releases whatever CI you are on, and unauthenticated requests are capped at 60 per hour per IP - when that limit is hit, enrichment degrades silently rather than failing. See license database rate limits.
Versioning
Use the tag when there is one and fall back to the commit:
script:
- |
docker run --rm \
-v "$TRAVIS_BUILD_DIR:/workspace" \
-e TRAVIS -e TRAVIS_COMMIT -e TRAVIS_BRANCH \
-e TRAVIS_TAG -e TRAVIS_PULL_REQUEST_BRANCH \
-e COMPONENT_NAME=my-app \
-e COMPONENT_VERSION="${TRAVIS_TAG:-$TRAVIS_COMMIT}" \
-e LOCK_FILE=requirements.txt \
ghcr.io/sbomify/sbomify-actionTo upload on tagged builds only, guard the stage with if: tag IS present.
VCS information
Repository URL, commit SHA and branch or tag are detected automatically. Detection landed after v26.8.0, so it is present on master and in any release tagged since.
| Field | Read from |
|---|---|
| Repository | The git checkout (git remote) |
| Commit | TRAVIS_COMMIT, falling back to the checkout |
| Branch or tag | TRAVIS_TAG, then TRAVIS_PULL_REQUEST_BRANCH, then TRAVIS_BRANCH |
Travis is the one platform here whose repository URL comes from the checkout rather than the vendor, and that is deliberate. Travis publishes only TRAVIS_REPO_SLUG, an owner/repo pair with no host attached, and it serves GitHub, Bitbucket, GitLab and Assembla projects alike. Turning that pair into a URL means guessing the forge, and a link that lands on the wrong host is worse than no link at all. The remote in the checkout says which host without guessing.
The commit and the ref come from the job because the checkout cannot answer them properly: Travis clones with --branch and then checks out the commit, leaving a detached HEAD that can name a tag and nothing else. TRAVIS_TAG comes first because on a tag build TRAVIS_BRANCH repeats the tag name rather than naming a branch. TRAVIS_PULL_REQUEST_BRANCH comes before TRAVIS_BRANCH because on a pull request build TRAVIS_BRANCH is the branch being merged into, while the source branch is the one this build actually built.
A commit link is added for github.com, gitlab.com and bitbucket.org, plus self-hosted GitHub and GitLab. Anything else gets the repository URL and the SHA without a link rather than a guessed one that 404s.
Two things have to be true
- The
.gitdirectory has to be inside the mount.-v "$TRAVIS_BUILD_DIR:/workspace"from the build directory gives you that; a mount of only your lockfile does not. Without a repository URL nothing is emitted, since Travis publishes none of its own to fall back on. - The Travis variables have to be forwarded. A
docker runwith no-e TRAVISis not recognisably a Travis job from inside the container, so it counts as a local run - where reading the checkout is opt-in and off by default. ForwardTRAVISat minimum; forwardTRAVIS_COMMIT,TRAVIS_BRANCH,TRAVIS_TAGandTRAVIS_PULL_REQUEST_BRANCHto get the ref the job was triggered for rather than whatever the detached HEAD can name.
Overriding
Set the fields in sbomify.json when you want something other than the remote recorded - an internal mirror rewritten to its public URL, for example:
{
"vcs_url": "https://github.com/my-org/my-repo",
"vcs_commit_sha": "abc123def456",
"vcs_ref": "main"
}sbomify.json wins over detection. Set AUGMENT=true when you are supplying other metadata alongside it. See augmentation.
Container images
The Docker daemon is already there once the docker service is enabled, so build the image first and point the action at it:
services:
- docker
script:
- docker build -t my-app:latest .
- |
docker run --rm \
-v "$TRAVIS_BUILD_DIR:/workspace" \
-v /var/run/docker.sock:/var/run/docker.sock \
-e TRAVIS -e TRAVIS_COMMIT -e TRAVIS_BRANCH \
-e TRAVIS_TAG -e TRAVIS_PULL_REQUEST_BRANCH \
-e DOCKER_IMAGE=my-app:latest \
-e OUTPUT_FILE=container-sbom.cdx.json \
-e ENRICH=true \
-e UPLOAD=false \
ghcr.io/sbomify/sbomify-actionMounting the Docker socket grants the container control of the host daemon. On a throwaway Travis VM that is a smaller concern than on a long-lived agent, but it is worth knowing.
Monorepos
-e WORKING_DIR=packages/my-app
-e LOCK_FILE=package-lock.jsonFor several components, use a build matrix with one COMPONENT_ID per entry.
Signing
Build provenance attestation is GitHub-specific. Use cosign, which runs anywhere.
Next steps
- Configuration reference - every option
- Augmentation - setting VCS details manually
- Advanced - caching, audit trail, troubleshooting