mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-09-14 14:41:21 -04:00
* Create frigate and go2rtc runtime users in the image * Add single fix-ownership helper for volume permission migration * Add init-usermod oneshot for PUID and PGID remapping * Chown newly created runtime directories to the frigate user * Run sentinel-guarded ownership sweep during prepare * Add host-side volume permission migration script * Guard log directory ownership for user-mode startup * Fall back to plain s6-log when running without root * Assert PUID remapping and sweep sentinel in CI smoke test * Skip the ownership sweep in the devcontainer * Pin FRIGATE_RUN_AS_ROOT in ownership tests * Do not record the sweep as complete when a chown failed * Validate PUID and PGID in the migration script * Treat a failed ownership scan as an incomplete sweep * Reject PUID and PGID of 0 during remapping * Handle symlinks, dry runs, and sentinel write failures in the sweep * Treat an absent sweep root as an incomplete sweep
310 lines
11 KiB
YAML
310 lines
11 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@v6
|
|
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@v6
|
|
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
|
|
printf 'mqtt:\n enabled: false\ncameras: {}\n' > /tmp/frigate-config/config.yml
|
|
docker run -d --name frigate --shm-size 256m \
|
|
-v /tmp/frigate-config:/config \
|
|
-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
|
|
docker exec frigate /usr/local/nginx/sbin/nginx -t
|
|
docker exec frigate stat -c %a /etc/letsencrypt/live/frigate/privkey.pem | grep -qx 600
|
|
docker exec frigate stat -c %a /dev/shm/go2rtc.yaml | grep -qx 640
|
|
- name: Assert PUID/PGID remapping
|
|
run: |
|
|
mkdir -p /tmp/frigate-config-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 \
|
|
${{ 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 "1: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: Teardown
|
|
if: always()
|
|
run: docker rm -f frigate || true
|
|
arm64_build:
|
|
runs-on: ubuntu-22.04-arm
|
|
name: ARM Build
|
|
steps:
|
|
- name: Check out code
|
|
uses: actions/checkout@v6
|
|
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
|
|
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: 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
|
|
name: Jetson Jetpack 6
|
|
steps:
|
|
- name: Check out code
|
|
uses: actions/checkout@v6
|
|
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)
|
|
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
|
|
amd64_extra_builds:
|
|
runs-on: ubuntu-22.04
|
|
name: AMD64 Extra Build
|
|
needs:
|
|
- amd64_build
|
|
steps:
|
|
- name: Check out code
|
|
uses: actions/checkout@v6
|
|
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)
|
|
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: AMD/ROCm general build
|
|
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
|
|
arm64_extra_builds:
|
|
runs-on: ubuntu-22.04-arm
|
|
name: ARM Extra Build
|
|
needs:
|
|
- arm64_build
|
|
steps:
|
|
- name: Check out code
|
|
uses: actions/checkout@v6
|
|
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
|
|
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
|
|
synaptics_build:
|
|
runs-on: ubuntu-22.04-arm
|
|
name: Synaptics Build
|
|
needs:
|
|
- arm64_build
|
|
steps:
|
|
- name: Check out code
|
|
uses: actions/checkout@v6
|
|
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
|
|
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
|
|
# 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
|
|
name: Assemble and push default build
|
|
needs:
|
|
- amd64_build
|
|
- arm64_build
|
|
steps:
|
|
- id: lowercaseRepo
|
|
uses: ASzc/change-string-case-action@v6
|
|
with:
|
|
string: ${{ github.repository }}
|
|
- name: Log in to the Container registry
|
|
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1
|
|
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
|
|
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
|