Files
frigate/.github/workflows/ci.yml
T
Josh HawkinsandGitHub ca851a9238 Miscellaneous Fixes (#24914)
* strip intel media driver on install

The manually built iHD_drv_video.so was installed with full debug info, making it 513 MB in the image instead of 41 MB stripped. Installing with install/strip removes about 240 MB from the compressed amd64 image.

* remove rjsf 6.11.0 dependabot hold

The hold covered the GenAI form refilling the saved model after a provider switch. That was a GenAIModelWidget bug that rjsf 6.11 exposed, and it was fixed with the 6.11.1 bump in #24901, so no rjsf version needs holding.

* strip intel media driver after install

install/strip skipped iHD_drv_video.so because media-driver installs it with install(PROGRAMS), not as a target. Strip it directly instead.

* bump dev docs version in header

* attest published images with github build provenance

Published images carried unsigned BuildKit provenance, so nothing tied an image digest to the commit it was built from. Each published image (the default multi-arch build and the six variants) now gets an actions/attest provenance attestation pushed to GHCR, verifiable with gh attestation verify. Release tags are skopeo copies with the same digest, so they're covered too. Storage records are off because they require an org-owned repo.
2026-11-09 06:44:48 -07:00

692 lines
31 KiB
YAML

name: CI
on:
workflow_dispatch:
push:
branches:
- dev
- master
paths-ignore:
- "docs/**"
# only run the latest commit to avoid cache overwrites
concurrency:
group: ${{ github.ref }}
cancel-in-progress: true
env:
PYTHON_VERSION: 3.11
jobs:
amd64_build:
runs-on: ubuntu-22.04
name: AMD64 Build
steps:
- name: Check out code
uses: actions/checkout@v7
with:
persist-credentials: false
- name: Set up QEMU and Buildx
id: setup
uses: ./.github/actions/setup
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push amd64 standard build
uses: docker/build-push-action@v7
with:
context: .
file: docker/main/Dockerfile
push: true
platforms: linux/amd64
target: frigate
tags: ${{ steps.setup.outputs.image-name }}-amd64
cache-from: type=registry,ref=${{ steps.setup.outputs.cache-name }}-amd64
cache-to: type=registry,ref=${{ steps.setup.outputs.cache-name }}-amd64,mode=max
smoke_test:
runs-on: ubuntu-22.04
name: AMD64 Smoke Test
needs:
- amd64_build
steps:
- name: Check out code
uses: actions/checkout@v7
with:
persist-credentials: false
- name: Set up QEMU and Buildx
id: setup
uses: ./.github/actions/setup
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Start container
run: |
mkdir -p /tmp/frigate-config /tmp/frigate-media
printf 'mqtt:\n enabled: false\ncameras: {}\n' > /tmp/frigate-config/config.yml
# simulate a root-era install: root-owned 0600 jwt secret pre-exists
docker run --rm -v /tmp/frigate-config:/config --entrypoint bash \
${{ steps.setup.outputs.image-name }}-amd64 \
-c "python3 -c 'import secrets; open(\"/config/.jwt_secret\",\"w\").write(secrets.token_hex(64))' && chmod 600 /config/.jwt_secret && chown 0:0 /config/.jwt_secret"
docker run -d --name frigate --shm-size 256m \
-v /tmp/frigate-config:/config \
-v /tmp/frigate-media:/media/frigate \
--mount type=tmpfs,target=/tmp/cache,tmpfs-size=100000000 \
-p 5000:5000 -p 8971:8971 \
${{ steps.setup.outputs.image-name }}-amd64
- name: Wait for API
run: |
for i in $(seq 1 60); do
curl -fs http://127.0.0.1:5000/api/version && exit 0
sleep 5
done
echo "API never came up"; docker logs frigate; exit 1
- name: Assert security headers and permissions
run: |
headers=$(curl -ksI https://127.0.0.1:8971/)
echo "$headers"
echo "$headers" | grep -qi "x-content-type-options: nosniff"
echo "$headers" | grep -qi "referrer-policy: strict-origin-when-cross-origin"
# server_tokens off: Server header must not include a version.
# written as an if rather than "! grep", because bash exempts a
# negated command from set -e and the assertion would never fail
if echo "$headers" | grep -qiE "^server: nginx/[0-9]"; then
echo "Server header leaks the nginx version; server_tokens is not off"
exit 1
fi
# Frigate never ships frame-ancestors: HA's Webpage card and iframe
# panels frame it cross-origin and it would break them silently
if echo "$headers" | grep -qi "frame-ancestors"; then
echo "response carries frame-ancestors, which breaks cross-origin iframe embedding"
exit 1
fi
# -t as root would chown the live cache and temp dirs to the `user`
# directive user; stdout discarded because -t reopens the config's
# /dev/stdout logs and the docker exec pipe is root-owned
docker exec frigate /command/s6-setuidgid frigate bash -c '/usr/local/nginx/sbin/nginx -e stderr -t -c /tmp/nginx/conf/nginx.conf >/dev/null'
docker exec frigate stat -c %a /config/tls/privkey.pem | grep -qx 600
docker exec frigate stat -c %a /dev/shm/go2rtc.yaml | grep -qx 640
- name: Assert services run as non-root
run: |
ps_out=$(docker exec frigate ps -eo user=,comm=)
echo "$ps_out"
assert_nonroot() {
# the process must exist AND no instance of it may run as root
echo "$ps_out" | grep -qw "$1" || { echo "$1 is not running"; exit 1; }
if echo "$ps_out" | grep -w "$1" | grep -q '^root'; then
echo "$1 is running as root"; exit 1
fi
}
assert_nonroot python3
assert_nonroot go2rtc
assert_nonroot nginx
# root-era jwt secret must have been captured by the sweep and the
# auth stack must be functional: wrong creds => clean 401, not 500
docker exec frigate stat -c %u /config/.jwt_secret | grep -qx "$(docker exec frigate id -u frigate)"
code=$(curl -s -o /dev/null -w '%{http_code}' -X POST http://127.0.0.1:5000/api/login \
-H 'content-type: application/json' -d '{"user":"admin","password":"definitely-wrong"}')
[ "$code" = "401" ] || { echo "login endpoint returned $code"; exit 1; }
# a root nginx -t above would have chowned the runtime dirs to root
owners=$(docker exec frigate stat -c %U /tmp/nginx /dev/shm/nginx_cache)
echo "$owners"
if echo "$owners" | grep -qvx frigate; then
echo "nginx runtime dirs are not owned by frigate"; exit 1
fi
# runtime user can write recordings storage
docker exec frigate /command/s6-setuidgid frigate touch /media/frigate/.write-probe
docker exec frigate rm /media/frigate/.write-probe
# tmpfs mount per the docs: arrives root-owned, holds the ZMQ IPC sockets
docker exec frigate /command/s6-setuidgid frigate touch /tmp/cache/.write-probe
docker exec frigate rm /tmp/cache/.write-probe
# models are baked in as root and archive members can carry root-only modes
docker exec frigate /command/s6-setuidgid frigate sh -c '
for f in /cpu_model.tflite /edgetpu_model.tflite /cpu_audio_model.tflite \
/labelmap.txt /audio-labelmap.txt /openvino-model/*; do
[ -e "$f" ] || continue
test -r "$f" || { echo "$f is not readable by the runtime user"; exit 1; }
done'
- name: Assert device access grants
run: |
# a fake accelerator node created after boot, then the oneshot re-run.
# /command is on PATH only for s6-supervised services, and the
# with-contenv shebang resolves its execline helpers through PATH
docker exec frigate mknod /dev/apex_9 c 120 99
docker exec frigate sh -c 'export PATH=/command:$PATH; exec /etc/s6-overlay/s6-rc.d/init-devices/run'
acl=$(docker exec frigate getfacl -p /dev/apex_9)
echo "$acl"
echo "$acl" | grep -q "user:frigate:rw-"
echo "$acl" | grep -q "user:go2rtc:rw-"
# the usb tree gets recursive grants plus a default ACL that
# newly created nodes inherit (the Coral re-enumeration path)
docker exec frigate sh -c 'mkdir -p /dev/bus/usb/001 && mknod /dev/bus/usb/001/002 c 189 1'
docker exec frigate sh -c 'export PATH=/command:$PATH; exec /etc/s6-overlay/s6-rc.d/init-devices/run'
docker exec frigate getfacl -p /dev/bus/usb/001 | grep -q "user:frigate:rwx"
docker exec frigate sh -c 'mknod /dev/bus/usb/001/099 c 189 98 && chmod 664 /dev/bus/usb/001/099'
inherited=$(docker exec frigate getfacl -p /dev/bus/usb/001/099)
echo "$inherited"
echo "$inherited" | grep -q "user:frigate:rw-"
# getfacl prints granted perms even when the mask clamps them to
# nothing, with a trailing "#effective:" comment; a clamped ACL must
# fail this assertion, not sneak past it. The check is scoped to the
# runtime users because the inherited group:: entry is always clamped
# on a non-directory, so an unscoped grep could never pass.
if echo "$inherited" | grep -E "^user:(frigate|go2rtc):" | grep -q "effective"; then
echo "inherited ACL is mask-clamped and grants no real access"; exit 1
fi
# hardware that is absent must stay silent: the literal table entries
# are not globs, so nullglob does not drop them and only an existence
# check keeps them from warning on every boot
out=$(docker exec frigate sh -c 'export PATH=/command:$PATH; exec /etc/s6-overlay/s6-rc.d/init-devices/run')
echo "$out"
if echo "$out" | grep -q "WARN"; then
echo "grant warned about device nodes that do not exist"; exit 1
fi
- name: Assert escape hatch restores root
run: |
mkdir -p /tmp/frigate-config-root
printf 'mqtt:\n enabled: false\ncameras: {}\n' > /tmp/frigate-config-root/config.yml
# pre-seed so the absence check proves the rm -f, not a vacuous pass
echo "2:1000:1000" > /tmp/frigate-config-root/.permissions_version
docker run -d --name frigate-root --shm-size 256m \
-e FRIGATE_RUN_AS_ROOT=true \
-v /tmp/frigate-config-root:/config \
${{ steps.setup.outputs.image-name }}-amd64
up=0
for i in $(seq 1 60); do
docker exec frigate-root curl -fs http://127.0.0.1:5000/api/version && up=1 && break
sleep 5
done
if [ "$up" -ne 1 ]; then echo "escape hatch container never healthy"; docker logs frigate-root; exit 1; fi
ps_out=$(docker exec frigate-root ps -eo user=,comm=)
echo "$ps_out"
echo "$ps_out" | grep -w python3 | grep -q '^root'
echo "$ps_out" | grep -w go2rtc | grep -q '^root'
echo "$ps_out" | grep -w nginx | grep -q '^root'
# an if, not ! test: bash exempts negated commands from set -e
if docker exec frigate-root test -f /config/.permissions_version; then
echo "escape hatch did not delete the sweep sentinel"; exit 1
fi
docker rm -f frigate-root
- name: Assert granular root services
run: |
mkdir -p /tmp/frigate-config-granular /tmp/frigate-media-granular
printf 'mqtt:\n enabled: false\ncameras: {}\n' > /tmp/frigate-config-granular/config.yml
docker run -d --name frigate-granular --shm-size 256m \
-e FRIGATE_ROOT_SERVICES=frigate \
-v /tmp/frigate-config-granular:/config \
-v /tmp/frigate-media-granular:/media/frigate \
${{ steps.setup.outputs.image-name }}-amd64
up=0
for i in $(seq 1 60); do
docker exec frigate-granular curl -fs http://127.0.0.1:5000/api/version && up=1 && break
sleep 5
done
if [ "$up" -ne 1 ]; then echo "granular container never became healthy"; docker logs frigate-granular; exit 1; fi
ps_out=$(docker exec frigate-granular ps -eo user=,comm=)
echo "$ps_out"
# the listed service runs as root
echo "$ps_out" | grep -w python3 | grep -q '^root'
# unlisted services still drop; ifs because set -e exempts negated commands
if echo "$ps_out" | grep -w go2rtc | grep -q '^root'; then
echo "go2rtc is unexpectedly running as root"; exit 1
fi
if echo "$ps_out" | grep -w nginx | grep -q '^root'; then
echo "nginx is unexpectedly running as root"; exit 1
fi
# the sweep still ran and the sentinel records the mode
docker exec frigate-granular cat /config/.permissions_version | grep -qx "2:1000:1000:frigate"
# the root frigate process chowns the db it creates (first-boot immediacy)
docker exec frigate-granular stat -c %u /config/frigate.db | grep -qx 1000
# plant a root-owned straggler; the per-boot sweep must reclaim it on restart
docker exec frigate-granular sh -c 'mkdir -p /media/frigate/clips && touch /media/frigate/clips/straggler.webp'
docker restart frigate-granular
up=0
for i in $(seq 1 60); do
docker exec frigate-granular curl -fs http://127.0.0.1:5000/api/version && up=1 && break
sleep 5
done
if [ "$up" -ne 1 ]; then echo "granular container never came back after restart"; docker logs frigate-granular; exit 1; fi
docker exec frigate-granular stat -c %u /media/frigate/clips/straggler.webp | grep -qx 1000
docker rm -f frigate-granular
- name: Assert unknown root service fails fast
run: |
mkdir -p /tmp/frigate-config-badsvc
printf 'mqtt:\n enabled: false\ncameras: {}\n' > /tmp/frigate-config-badsvc/config.yml
docker run -d --name frigate-badsvc --shm-size 256m \
-e FRIGATE_ROOT_SERVICES=frigatee \
-v /tmp/frigate-config-badsvc:/config \
${{ steps.setup.outputs.image-name }}-amd64
found=0
for i in $(seq 1 12); do
if docker logs frigate-badsvc 2>&1 | grep -q "unknown service 'frigatee'"; then found=1; break; fi
sleep 5
done
if [ "$found" -ne 1 ]; then
echo "no fail-fast error for an unknown service name"; docker logs frigate-badsvc; exit 1
fi
# the failed oneshot blocks startup through the dependency chain
if docker exec frigate-badsvc curl -fs http://127.0.0.1:5000/api/version; then
echo "container came up despite an invalid FRIGATE_ROOT_SERVICES"; exit 1
fi
docker rm -f frigate-badsvc
- name: Assert PUID/PGID remapping
run: |
mkdir -p /tmp/frigate-config-puid /tmp/frigate-media-puid
printf 'mqtt:\n enabled: false\ncameras: {}\n' > /tmp/frigate-config-puid/config.yml
docker run -d --name frigate-puid --shm-size 256m \
-e PUID=1500 -e PGID=1500 \
-v /tmp/frigate-config-puid:/config \
-v /tmp/frigate-media-puid:/media/frigate \
${{ steps.setup.outputs.image-name }}-amd64
up=0
for i in $(seq 1 60); do
docker exec frigate-puid curl -fs http://127.0.0.1:5000/api/version && up=1 && break
sleep 5
done
if [ "$up" -ne 1 ]; then echo "PUID container never became healthy"; docker logs frigate-puid; exit 1; fi
docker exec frigate-puid id -u frigate | grep -qx 1500
docker exec frigate-puid id -g frigate | grep -qx 1500
docker exec frigate-puid cat /config/.permissions_version | grep -qx "2:1500:1500"
# second boot must skip the sweep (sentinel hit). Poll rather than
# sleep: the string can only come from the second boot (the first
# had no sentinel), so grepping the full log is unambiguous.
docker restart frigate-puid
ok=0
for i in $(seq 1 30); do
docker logs frigate-puid 2>&1 | grep -q "already applied" && ok=1 && break
sleep 2
done
if [ "$ok" -ne 1 ]; then echo "sentinel skip never logged"; docker logs frigate-puid; exit 1; fi
docker rm -f frigate-puid
- name: Assert read-only rootfs with --user works
run: |
mkdir -p /tmp/frigate-config-ro /tmp/frigate-media-ro
printf 'mqtt:\n enabled: false\ncameras: {}\n' > /tmp/frigate-config-ro/config.yml
sudo chown -R 1000:1000 /tmp/frigate-config-ro /tmp/frigate-media-ro
# /run must allow exec: S6_READ_ONLY_ROOT has s6 copy its service
# scripts there and run them, and --tmpfs defaults to noexec
docker run -d --name frigate-ro --shm-size 256m \
--read-only --tmpfs /tmp:rw,size=1g --tmpfs /run:exec,nosuid,nodev,mode=0755,uid=1000,gid=1000 \
--user 1000:1000 \
--security-opt no-new-privileges:true \
-v /tmp/frigate-config-ro:/config \
-v /tmp/frigate-media-ro:/media/frigate \
${{ steps.setup.outputs.image-name }}-amd64
up=0
for i in $(seq 1 60); do
docker exec frigate-ro curl -fs http://127.0.0.1:5000/api/version && up=1 && break
sleep 5
done
if [ "$up" -ne 1 ]; then echo "read-only container never healthy"; docker logs frigate-ro; exit 1; fi
# an if, not "! grep": bash exempts a negated command from set -e and
# the assertion would never fail
if docker logs frigate-ro 2>&1 | grep -i "read-only file system"; then
echo "a service tried to write to the read-only rootfs"; exit 1
fi
# the self-signed cert has to land in /config, the only writable path
docker exec frigate-ro test -f /config/tls/privkey.pem
# and nginx must serve it, which is what proves the templated cert path
docker exec frigate-ro curl -ksSI https://127.0.0.1:8971/ >/dev/null
# logging must work via the s6-log fallback (no logutil-service as non-root)
docker exec frigate-ro test -s /dev/shm/logs/frigate/current
# runtime user can write recordings storage
docker exec frigate-ro touch /media/frigate/.write-probe
docker exec frigate-ro rm /media/frigate/.write-probe
docker rm -f frigate-ro
- name: Assert PUID with read-only fails fast with clear error
run: |
docker run -d --name frigate-ro-puid --shm-size 256m \
--read-only --tmpfs /tmp:rw,size=1g --tmpfs /run:exec,nosuid,nodev,mode=0755 \
-e PUID=1500 -e PGID=1500 \
-v /tmp/frigate-config-ro:/config \
${{ steps.setup.outputs.image-name }}-amd64
found=0
for i in $(seq 1 12); do
if docker logs frigate-ro-puid 2>&1 | grep -q "not compatible with read_only"; then found=1; break; fi
sleep 5
done
if [ "$found" -ne 1 ]; then
echo "no fail-fast error for PUID with a read-only rootfs"; docker logs frigate-ro-puid; exit 1
fi
docker rm -f frigate-ro-puid
- name: Assert EXTRA_GROUPS with read-only fails fast with clear error
run: |
docker run -d --name frigate-ro-groups --shm-size 256m \
--read-only --tmpfs /tmp:rw,size=1g --tmpfs /run:exec,nosuid,nodev,mode=0755 \
-e EXTRA_GROUPS=44 \
-v /tmp/frigate-config-ro:/config \
-v /tmp/frigate-media-ro:/media/frigate \
${{ steps.setup.outputs.image-name }}-amd64
found=0
for i in $(seq 1 12); do
if docker logs frigate-ro-groups 2>&1 | grep -q "EXTRA_GROUPS needs a writable /etc"; then found=1; break; fi
sleep 5
done
if [ "$found" -ne 1 ]; then
echo "no fail-fast error for EXTRA_GROUPS with a read-only rootfs"; docker logs frigate-ro-groups; exit 1
fi
docker rm -f frigate-ro-groups
- name: Assert read-only rootfs in the default mode works
run: |
mkdir -p /tmp/frigate-config-rod /tmp/frigate-media-rod
printf 'mqtt:\n enabled: false\ncameras: {}\n' > /tmp/frigate-config-rod/config.yml
docker run -d --name frigate-rod --shm-size 256m \
--read-only --tmpfs /tmp:rw,size=1g --tmpfs /run:exec,nosuid,nodev,mode=0755 \
--security-opt no-new-privileges:true \
-v /tmp/frigate-config-rod:/config \
-v /tmp/frigate-media-rod:/media/frigate \
${{ steps.setup.outputs.image-name }}-amd64
up=0
for i in $(seq 1 60); do
docker exec frigate-rod curl -fs http://127.0.0.1:5000/api/version && up=1 && break
sleep 5
done
if [ "$up" -ne 1 ]; then echo "read-only default-mode container never healthy"; docker logs frigate-rod; exit 1; fi
if docker logs frigate-rod 2>&1 | grep -i "read-only file system"; then
echo "a service tried to write to the read-only rootfs"; exit 1
fi
# the point of this mode over docker's user:: the drop still happens
# and go2rtc still gets its own separate user
ps_out=$(docker exec frigate-rod ps -eo user=,comm=)
echo "$ps_out"
for svc in python3 nginx; do
if echo "$ps_out" | grep -w "$svc" | grep -q '^root'; then
echo "$svc is running as root"; exit 1
fi
done
echo "$ps_out" | grep -w go2rtc | grep -q '^go2rtc'
# the ownership sweep still ran and recorded itself in /config
docker exec frigate-rod cat /config/.permissions_version | grep -qx "2:1000:1000"
# setfacl under a read-only rootfs, which nothing else covers:
# init-devices exits early under --user, so that path is never reached
docker exec frigate-rod mknod /dev/apex_9 c 120 99
docker exec frigate-rod sh -c 'export PATH=/command:$PATH; exec /etc/s6-overlay/s6-rc.d/init-devices/run'
docker exec frigate-rod getfacl -p /dev/apex_9 | grep -q "user:frigate:rw-"
docker rm -f frigate-rod
- name: "Assert switching that install to user: still starts"
run: |
# the config dir above now holds a go2rtc-owned go2rtc_homekit.yml,
# which user: keeps readable but not writable (no supplementary groups)
docker run -d --name frigate-rod-user --shm-size 256m \
--read-only --tmpfs /tmp:rw,size=1g --tmpfs /run:exec,nosuid,nodev,mode=0755,uid=1000,gid=1000 \
--user 1000:1000 \
-v /tmp/frigate-config-rod:/config \
-v /tmp/frigate-media-rod:/media/frigate \
${{ steps.setup.outputs.image-name }}-amd64
up=0
for i in $(seq 1 60); do
docker exec frigate-rod-user curl -fs http://127.0.0.1:5000/api/version && up=1 && break
sleep 5
done
if [ "$up" -ne 1 ]; then echo "container did not survive the switch to user:"; docker logs frigate-rod-user; exit 1; fi
docker logs frigate-rod-user 2>&1 | grep -q "HomeKit pairing changes will not persist"
docker rm -f frigate-rod-user
- name: Teardown
if: always()
run: docker rm -f frigate || true
arm64_build:
runs-on: ubuntu-22.04-arm
permissions:
contents: read
packages: write
attestations: write
id-token: write
name: ARM Build
steps:
- name: Check out code
uses: actions/checkout@v7
with:
persist-credentials: false
- name: Set up QEMU and Buildx
id: setup
uses: ./.github/actions/setup
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push arm64 standard build
id: standard-arm64
uses: docker/build-push-action@v7
with:
context: .
file: docker/main/Dockerfile
push: true
platforms: linux/arm64
target: frigate
tags: |
${{ steps.setup.outputs.image-name }}-standard-arm64
cache-from: type=registry,ref=${{ steps.setup.outputs.cache-name }}-arm64
- name: Attest arm64 standard build
uses: actions/attest@v4
with:
subject-name: ${{ steps.setup.outputs.image-repo }}
subject-digest: ${{ steps.standard-arm64.outputs.digest }}
push-to-registry: true
create-storage-record: false
- name: Build and push RPi build
uses: docker/bake-action@v7
with:
source: .
push: true
targets: rpi
files: docker/rpi/rpi.hcl
set: |
rpi.tags=${{ steps.setup.outputs.image-name }}-rpi
*.cache-from=type=registry,ref=${{ steps.setup.outputs.cache-name }}-arm64
*.cache-to=type=registry,ref=${{ steps.setup.outputs.cache-name }}-arm64,mode=max
jetson_jp6_build:
runs-on: ubuntu-22.04-arm
permissions:
contents: read
packages: write
attestations: write
id-token: write
name: Jetson Jetpack 6
steps:
- name: Check out code
uses: actions/checkout@v7
with:
persist-credentials: false
- name: Set up QEMU and Buildx
id: setup
uses: ./.github/actions/setup
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push TensorRT (Jetson, Jetpack 6)
id: tensorrt-jp6
env:
ARCH: arm64
BASE_IMAGE: nvcr.io/nvidia/tensorrt:23.12-py3-igpu
SLIM_BASE: nvcr.io/nvidia/tensorrt:23.12-py3-igpu
TRT_BASE: nvcr.io/nvidia/tensorrt:23.12-py3-igpu
uses: docker/bake-action@v7
with:
source: .
push: true
targets: tensorrt
files: docker/tensorrt/trt.hcl
set: |
tensorrt.tags=${{ steps.setup.outputs.image-name }}-tensorrt-jp6
*.cache-from=type=registry,ref=${{ steps.setup.outputs.cache-name }}-jp6
*.cache-to=type=registry,ref=${{ steps.setup.outputs.cache-name }}-jp6,mode=max
- name: Attest TensorRT (Jetson, Jetpack 6)
uses: actions/attest@v4
with:
subject-name: ${{ steps.setup.outputs.image-repo }}
subject-digest: ${{ fromJSON(steps.tensorrt-jp6.outputs.metadata)['tensorrt']['containerimage.digest'] }}
push-to-registry: true
create-storage-record: false
amd64_extra_builds:
runs-on: ubuntu-22.04
permissions:
contents: read
packages: write
attestations: write
id-token: write
name: AMD64 Extra Build
needs:
- amd64_build
steps:
- name: Check out code
uses: actions/checkout@v7
with:
persist-credentials: false
- name: Set up QEMU and Buildx
id: setup
uses: ./.github/actions/setup
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push TensorRT (x86 GPU)
id: tensorrt
env:
COMPUTE_LEVEL: "50 60 70 80 90"
uses: docker/bake-action@v7
with:
source: .
push: true
targets: tensorrt
files: docker/tensorrt/trt.hcl
set: |
tensorrt.tags=${{ steps.setup.outputs.image-name }}-tensorrt
*.cache-from=type=registry,ref=${{ steps.setup.outputs.cache-name }}-tensorrt
*.cache-to=type=registry,ref=${{ steps.setup.outputs.cache-name }}-tensorrt,mode=max
- name: Attest TensorRT (x86 GPU)
uses: actions/attest@v4
with:
subject-name: ${{ steps.setup.outputs.image-repo }}
subject-digest: ${{ fromJSON(steps.tensorrt.outputs.metadata)['tensorrt']['containerimage.digest'] }}
push-to-registry: true
create-storage-record: false
- name: AMD/ROCm general build
id: rocm
env:
HSA_OVERRIDE: 0
uses: docker/bake-action@v7
with:
source: .
push: true
targets: rocm
files: docker/rocm/rocm.hcl
set: |
rocm.tags=${{ steps.setup.outputs.image-name }}-rocm
*.cache-to=type=registry,ref=${{ steps.setup.outputs.cache-name }}-rocm,mode=max
*.cache-from=type=registry,ref=${{ steps.setup.outputs.cache-name }}-rocm
- name: Attest AMD/ROCm general build
uses: actions/attest@v4
with:
subject-name: ${{ steps.setup.outputs.image-repo }}
subject-digest: ${{ fromJSON(steps.rocm.outputs.metadata)['rocm']['containerimage.digest'] }}
push-to-registry: true
create-storage-record: false
arm64_extra_builds:
runs-on: ubuntu-22.04-arm
permissions:
contents: read
packages: write
attestations: write
id-token: write
name: ARM Extra Build
needs:
- arm64_build
steps:
- name: Check out code
uses: actions/checkout@v7
with:
persist-credentials: false
- name: Set up QEMU and Buildx
id: setup
uses: ./.github/actions/setup
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push Rockchip build
id: rk
uses: docker/bake-action@v7
with:
source: .
push: true
targets: rk
files: docker/rockchip/rk.hcl
set: |
rk.tags=${{ steps.setup.outputs.image-name }}-rk
*.cache-from=type=gha
- name: Attest Rockchip build
uses: actions/attest@v4
with:
subject-name: ${{ steps.setup.outputs.image-repo }}
subject-digest: ${{ fromJSON(steps.rk.outputs.metadata)['rk']['containerimage.digest'] }}
push-to-registry: true
create-storage-record: false
synaptics_build:
runs-on: ubuntu-22.04-arm
permissions:
contents: read
packages: write
attestations: write
id-token: write
name: Synaptics Build
needs:
- arm64_build
steps:
- name: Check out code
uses: actions/checkout@v7
with:
persist-credentials: false
- name: Set up QEMU and Buildx
id: setup
uses: ./.github/actions/setup
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push Synaptics build
id: synaptics
uses: docker/bake-action@v7
with:
source: .
push: true
targets: synaptics
files: docker/synaptics/synaptics.hcl
set: |
synaptics.tags=${{ steps.setup.outputs.image-name }}-synaptics
*.cache-from=type=gha
- name: Attest Synaptics build
uses: actions/attest@v4
with:
subject-name: ${{ steps.setup.outputs.image-repo }}
subject-digest: ${{ fromJSON(steps.synaptics.outputs.metadata)['synaptics']['containerimage.digest'] }}
push-to-registry: true
create-storage-record: false
# The majority of users running arm64 are rpi users, so the rpi
# build should be the primary arm64 image
assemble_default_build:
runs-on: ubuntu-22.04
permissions:
contents: read
packages: write
attestations: write
id-token: write
name: Assemble and push default build
needs:
- amd64_build
- arm64_build
steps:
- id: lowercaseRepo
uses: ASzc/change-string-case-action@v8
with:
string: ${{ github.repository }}
- name: Log in to the Container registry
uses: docker/login-action@8aa5831fb8d48d8f76594c7ddde61ae58019f550
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Create short sha
run: echo "SHORT_SHA=${GITHUB_SHA::7}" >> $GITHUB_ENV
- uses: int128/docker-manifest-create-action@v2
id: manifest
with:
tags: ghcr.io/${{ steps.lowercaseRepo.outputs.lowercase }}:${{ env.SHORT_SHA }}
sources: |
ghcr.io/${{ steps.lowercaseRepo.outputs.lowercase }}:${{ env.SHORT_SHA }}-amd64
ghcr.io/${{ steps.lowercaseRepo.outputs.lowercase }}:${{ env.SHORT_SHA }}-rpi
- name: Attest default build
uses: actions/attest@v4
with:
subject-name: ghcr.io/${{ steps.lowercaseRepo.outputs.lowercase }}
subject-digest: ${{ steps.manifest.outputs.digest }}
push-to-registry: true
create-storage-record: false