build-labels
This gem allows ...
build-labels simple-compose.yml | docker-compose build -f -
$ build-labels
Version: 0.0.85
Usage:
build-labels -c docker-compose.yml gitlab
cat docker-compose.yml | build-labels gitlab
build-labels gitlab < docker-compose.yml
Commands:
to_compose - Add labels to all build sections of docker-compose file
to_dockerfiles - Add ENVs to Dockerfiles from docker-compose file
gitlab - Use GitLab CI variables
github - Use GitHub CI variables
cache - Add cache section
print - Print labels to stdout
set_version - Add version tag from [docker_context]/.version file to image
Options:
-c, --compose COMPOSE_FILE Compose file
-e, --env FILE Load .build_info FILE
-n, --no-env Do not process env variables
--except FILTER
filter services
--cache-from CACHE FROM
type=[local,registry] ...
--cache-to CACHE TO
type=[local,registry] ...
--full-version
Push full version tag
-h, --help
https://rdoc.info/gems/build-labels https://rubydoc.info/gems/build-labels https://gemdocs.org/gems/build-labels
Installation
To install the gem
$ gem install build-labels
Filesystem checks
trivy-runner fs scans every local source directory declared as a service build.context in a Compose file. Mapping and shorthand build forms are supported, relative paths are resolved from the Compose file directory, and contexts shared by multiple services are scanned once. Services without a build are ignored. Remote and unresolved contexts fail before any scan starts.
The filesystem mode runs a local trivy executable and never invokes Docker. This is necessary because Docker resolves bind-mount source paths on the daemon host, not inside the current build container.
Dockerfile.build example
Based on the file-server build image, a complete build runner can prepare Bake input, build locally, run enabled tests and scans, and defer every push until validation passes:
FROM ruby:3.4.10-slim-bookworm AS base
RUN apt-get update && apt-get upgrade -y && apt-get install -y --no-install-recommends bash git jq
RUN gem install build-labels:0.0.85
RUN install-docker-static
RUN install-trivy-static
WORKDIR /build
COPY . .
CMD ["bash", "-e", "-o", "pipefail", "-c", "\
cd /build/docker; \
build-labels -n -c docker-compose.yml changed gitlab set_version to_dockerfiles to_compose | tee bake.yml; \
export OTEL_RESOURCE_ATTRIBUTES=\"service.name=docker-builder,pipeline.id=${CI_PIPELINE_ID:-},project.name=${CI_PROJECT_NAME:-}\"; \
export REGISTRY_HOST=\"${CI_REGISTRY_HOST:-}\" BUILDX_BAKE_ENTITLEMENTS_FS=0; \
grep -q '^services: {}$' bake.yml && exit 0; \
docker buildx bake -f bake.yml --set '*.output=type=docker' --sbom=false --provenance=false --metadata-file /tmp/bake-metadata.json; \
if [ \"${CI_BUILD_TARGET:-}\" = tests ]; then \
docker compose -f bake.yml down; \
docker compose -f bake.yml up --force-recreate --no-build --pull never --abort-on-container-failure; \
fi; \
if [ \"${CI_TRIVY_SCAN:-}\" = true ]; then \
trivy-runner fs -f bake.yml -- --scanners vuln,secret,misconfig --severity HIGH,CRITICAL --ignore-unfixed --include-dev-deps --exit-code 1; \
trivy-runner -f bake.yml --metadata-file /tmp/bake-metadata.json -- --severity HIGH,CRITICAL --ignore-unfixed --table-mode detailed; \
fi; \
[ -z \"${CI_SKIP_PUSH:-}\" ] || exit 0; \
docker compose -f bake.yml push; \
"]Build and run it with the Docker socket and the same named cache volume used by image mode. Pass the CI variables required by the selected build-labels commands through the caller's normal environment or --env-file:
docker build -f docker/Dockerfile.build -t build-runner .
docker run --rm \
-v /var/run/docker.sock:/var/run/docker.sock \
-v trivy-cache:/root/.cache/trivy \
-e CI_TRIVY_SCAN=true \
build-runnerCI_TRIVY_SCAN=true enables both filesystem and image scanning independently of CI_BUILD_TARGET=tests. Any build, test, or scan failure stops the shell before docker compose push; CI_SKIP_PUSH skips only the final publication step.
The file defaults to bake.yml. The cache directory defaults to TRIVY_CACHE_DIR, or /root/.cache/trivy when the variable is unset. Override it as a runner option before the separator when needed:
trivy-runner fs -f docker-compose.yml --cache-dir /cache/trivy -- \
--scanners vuln,secret,misconfig \
--severity HIGH,CRITICAL \
--ignore-unfixed \
--include-dev-depsAll options after -- are forwarded unchanged to each trivy fs process. The runner does not select scanners, severities, dependency policy, or a failure exit code. It streams Trivy output directly, stops after the first failed context, and returns Trivy's exit status. It does not install dependencies, run application builds/tests, or invoke package-manager audit commands.
Image vulnerability checks
trivy-runner scans locally built images using Docker/Buildx and a Trivy container; no local Trivy installation is needed. It requires the metadata file produced by the build:
docker buildx bake -f bake.yml --set '*.output=type=docker' --sbom=false --provenance=false --metadata-file /tmp/bake-metadata.json
trivy-runner -f bake.yml --metadata-file /tmp/bake-metadata.json --image-src docker -- --severity HIGH,CRITICALRun from the same directory and with the same environment as the build. Append Bake target/group names when scanning a subset. The file defaults to bake.yml; --metadata-file is required. This version supports Docker-local images with one platform per target.
The runner resolves tags with docker buildx bake --print, checks every selected tag against its build image ID, and scans each distinct image ID once. It checks the tags again after successful scans. Empty Compose service lists are skipped. Exit status is 0 on success and 1 on an invalid input, image mismatch, vulnerability-policy failure, or tool failure. Trivy's scan output is streamed to the terminal.
Use Trivy's native --severity HIGH,CRITICAL after -- to choose which severities are displayed and fail the scan. The runner supplies --exit-code 1 and does not add a severity filter; without one, Trivy uses its environment/configuration or its default of all severities. Unfixed findings are included unless filtered out.
Starting with 0.0.82, put native trivy image options after --:
trivy-runner -f bake.yml --metadata-file /tmp/bake-metadata.json -- --severity HIGH,CRITICAL --ignore-unfixed --no-progress--ignore-unfixed displays and fails on vulnerabilities only when a fixed version is available; --no-progress suppresses download progress bars. Put any Bake targets/groups before --. All following arguments are forwarded unchanged to every scan, after the runner's default Trivy options and before the image ID. Trivy handles option validation and repeated options; forwarded options can change scan behavior and failure policy. Paths refer to files inside the scanner container.
Each scan uses docker run --rm --pull always with the unpinned aquasec/trivy image, pulling the current latest image before starting. Set TRIVY_IMAGE to override the scanner image, including a digest-pinned reference. A pull failure stops the command. The container mounts /var/run/docker.sock from the Docker daemon host and uses the persistent named volume trivy-cache at TRIVY_CACHE_DIR (default /root/.cache/trivy). This requires the daemon's standard Unix socket; remote/rootless socket layouts are not automatically mapped. Use a trusted scanner image because socket access grants access to the Docker daemon.
Starting with 0.0.83, terminal output is enabled by default for colored Trivy tables in CI:
trivy-runner -f bake.yml --metadata-file /tmp/bake-metadata.json -- --severity HIGH,CRITICAL --ignore-unfixed --table-mode detailedThis allocates a terminal for the scanner container without interactive input. Add --no-tty before -- when capturing JSON or other machine-readable reports: a container terminal combines Trivy's stdout and stderr. Explicit --tty is also supported. Before each distinct image scan, a cyan banner lists its tags and image ID. After all scans and the final tag verification succeed, the runner prints a green Trivy checks passed. message. Both messages go to stderr, including in CI logs. Failed checks do not print the success message; empty selections print neither. Success means the configured scan policy passed; filtered findings may still exist.
Other TRIVY_* variables are forwarded to the container. Local configuration/ignore files and other environment variables are not automatically shared; file paths must exist inside the scanner image or its cache volume. An outer build container's cache bind mount is not used by the scanner's named volume.
Building, testing, publishing, and SBOM generation/signing are separate operations. Run this command before publication, and keep local image tags stable through the scan/push interval; the runner does not lock the shared Docker daemon.
Usage
Create the file simple-compose.yml which describes the images to build
version: '3.8'
services:
service-a:
image: service-a
build:
context: .
dockerfile: ./Dockerfile
ports:
- 8080
environment:
- hello
service-b:
image: service-a
build: .
service-c:
image: service-a
Then run in the current directory
$ build-labels -c simple-compose.yml gitlab
This will ...
---
version: '3.8'
services:
service-a:
image: service-a
build:
context: "."
dockerfile: "./Dockerfile"
labels:
- org.opencontainers.image.vendor=/
- org.opencontainers.image.authors=/
- org.opencontainers.image.revision=d17e5c66b8d101f9e54d68e1e8540279bbe25467
- org.opencontainers.image.ref.name=:master
- org.opencontainers.image.source=https://gitlab.com//dev1/reports
- org.opencontainers.image.documentation=https://gitlab.com//dev1/reports
- org.opencontainers.image.licenses=https://gitlab.com//dev1/reports
- org.opencontainers.image.url=https://gitlab.com//dev1/reports
- org.opencontainers.image.title=reports
- org.opencontainers.image.version=master
- com.gitlab.ci.user=/
- com.gitlab.ci.tagorbranch=master
- com.gitlab.ci.commiturl=https://gitlab.com//dev1/reports/commit/d17e5c66b8d101f9e54d68e1e8540279bbe25467
- com.gitlab.ci.mrurl=https://gitlab.com//dev1/reports/-/merge_requests/
- com.gitlab.ci.tag=:d17e5c66b8d101f9e54d68e1e8540279bbe25467
- com.gitlab.ci.commit_branch=master
- com.gitlab.ci.commit_short_sha=d17e5c66
- com.gitlab.ci.commit_timestamp=2022-11-15T17:21:59+03:00
- com.gitlab.ci.commit_message=update
- docker.service.name=service-a
- org.label-schema.url=https://gitlab.com//dev1/reports
- org.label-schema.vcs-url=https://gitlab.com//dev1/reports
- org.label-schema.version=master
- org.label-schema.vcs-ref=d17e5c66b8d101f9e54d68e1e8540279bbe25467
- org.label-schema.vendor=/
- org.label-schema.name=reports
- org.label-schema.usage=https://gitlab.com//dev1/reports
- org.label-schema.schema-version=1.0
service-b:
image: service-a
build:
context: "."
labels:
- org.opencontainers.image.vendor=/
- org.opencontainers.image.authors=/
- org.opencontainers.image.revision=d17e5c66b8d101f9e54d68e1e8540279bbe25467
- org.opencontainers.image.ref.name=:master
- org.opencontainers.image.source=https://gitlab.com//dev1/reports
- org.opencontainers.image.documentation=https://gitlab.com//dev1/reports
- org.opencontainers.image.licenses=https://gitlab.com//dev1/reports
- org.opencontainers.image.url=https://gitlab.com//dev1/reports
- org.opencontainers.image.title=reports
- org.opencontainers.image.version=master
- com.gitlab.ci.user=/
- com.gitlab.ci.tagorbranch=master
- com.gitlab.ci.commiturl=https://gitlab.com//dev1/reports/commit/d17e5c66b8d101f9e54d68e1e8540279bbe25467
- com.gitlab.ci.mrurl=https://gitlab.com//dev1/reports/-/merge_requests/
- com.gitlab.ci.tag=:d17e5c66b8d101f9e54d68e1e8540279bbe25467
- com.gitlab.ci.commit_branch=master
- com.gitlab.ci.commit_short_sha=d17e5c66
- com.gitlab.ci.commit_timestamp=2022-11-15T17:21:59+03:00
- com.gitlab.ci.commit_message=update
- docker.service.name=service-b
- org.label-schema.url=https://gitlab.com//dev1/reports
- org.label-schema.vcs-url=https://gitlab.com//dev1/reports
- org.label-schema.version=master
- org.label-schema.vcs-ref=d17e5c66b8d101f9e54d68e1e8540279bbe25467
- org.label-schema.vendor=/
- org.label-schema.name=reports
- org.label-schema.usage=https://gitlab.com//dev1/reports
- org.label-schema.schema-version=1.0