Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 46 additions & 11 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -19,30 +19,65 @@ FRIGATE_SHM_SIZE=256mb
FRIGATE_RTSP_USER=admin
FRIGATE_RTSP_PASSWORD=changeme

# Allow go2rtc `exec:` sources — needed only if you use GPU-enhanced "<cam>_hq"
# transcode streams (see frigate/config.yml). Off by default (security); fine to
# enable on a private LAN/tailnet box where the go2rtc config is yours.
GO2RTC_ALLOW_ARBITRARY_EXEC=true
# Allow go2rtc `exec:` sources. OFF by default, and the dashboard works fully
# without it. Turn it on ONLY for the optional GPU-enhanced "<cam>_hq" streams you
# write yourself in frigate/config.yml (see the commented example there).
# SECURITY: while this is true, anyone who can reach go2rtc's API (port 1984 on
# the host) can run commands inside the Frigate container. Keep 1984 off any
# untrusted network (firewall it, or use compose.bridge.yml which binds it to
# localhost). See SECURITY.md.
GO2RTC_ALLOW_ARBITRARY_EXEC=false

# ---- Windows / bridge networking ONLY --------------------------------------
# This machine's LAN IP, used for the go2rtc WebRTC candidate. Ignored on
# host-networking hosts (Unraid/Pi).
# This machine's LAN IP, used for the go2rtc WebRTC candidate (referenced in
# frigate/config.yml). Ignored on host-networking hosts (Unraid/Pi).
FRIGATE_HOST_LAN_IP=192.168.1.10

# ---- Control dashboard -----------------------------------------------------
DASHBOARD_IMAGE=tinkerview:latest
# Optional shared bearer token gating the dashboard API + ntfy action buttons.
# Empty = open on the tailnet (Tailscale is the perimeter). When set, open the
# dashboard once as http://<host>:8088/?token=YOURTOKEN — the browser stores it and
# uses it for the API + WebSocket thereafter.
# Shared bearer token gating the dashboard API + ntfy action buttons. SET ONE:
# with it empty, anyone who can reach port 8088 has full control (the dashboard
# logs a warning at startup). Generate one: openssl rand -hex 24
# (install.sh does this for you.) When set, open the dashboard once as
# http://<host>:8088/?token=<your token>; the browser stores it and uses it for
# the API + WebSocket thereafter.
DASHBOARD_TOKEN=
# Docker access for container health/restart — the docker-socket-proxy endpoint.
DOCKER_HOST=tcp://127.0.0.1:2375
# (Named DASHBOARD_DOCKER_HOST so it cannot collide with the DOCKER_HOST your shell or
# `podman compose` sets for the compose tool itself. The dashboard sees it as DOCKER_HOST.)
DASHBOARD_DOCKER_HOST=tcp://127.0.0.1:2375
# 0 (default) = read-only container health view; the Restart button is disabled.
# 1 = the dashboard may restart containers. The proxy cannot restrict POST to
# "restart" only, so 1 is root-equivalent for anything that can reach 127.0.0.1:2375
# (loopback only). Opt in only if you want the button. See SECURITY.md.
DOCKERPROXY_POST=0
# Host path of the container engine's API socket, mounted into docker-socket-proxy.
# Leave it unset on Docker. Rootless podman: install.sh sets it to your user socket,
# for example /run/user/1000/podman/podman.sock.
# DOCKER_SOCKET_PATH=/var/run/docker.sock
# Address the dashboard listens on (default ":8088" = all interfaces). Bind to a
# single IP (e.g. your tailnet or LAN address) to narrow it.
# DASHBOARD_LISTEN=:8088

# ---- MQTT (Mosquitto) ------------------------------------------------------
# By default the broker is published on 127.0.0.1 only. For Home Assistant on
# another machine use compose.mqtt-lan.yml (password-protected, port 1884);
# this limits which interface that port binds to (default: all).
# MQTT_LAN_BIND=0.0.0.0

# ---- ntfy (push notifications) ---------------------------------------------
NTFY_IMAGE=binwiederhier/ntfy:v2.11.0
NTFY_BASE_URL=http://127.0.0.1:8092
# ntfy relays a content-free poll request (a hash of the topic, no message) to ntfy.sh so
# iOS gets instant push. Uncomment with an empty value to switch that off (Android is
# unaffected; iOS notifications then arrive late or not at all).
# NTFY_UPSTREAM_BASE_URL=
# Publish token the dashboard uses (create it in ntfy after first start).
NTFY_TOKEN=

DOCKERPROXY_IMAGE=tecnativa/docker-socket-proxy:0.3.0

# ---- Tailscale sidecar (compose.tailscale.yml, optional) -------------------
# Auth key from the Tailscale admin console (Settings > Keys). Without it the
# container prints a login URL in its logs instead.
# TS_AUTHKEY=
124 changes: 124 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# Continuous integration: Go (format, vet, race tests), frontend (typecheck,
# build), compose file validation, and a no-push build of the dashboard image.
name: ci

on:
push:
branches: [main]
pull_request:

# Cancel superseded runs on the same PR/branch; never cancel a run on main.
concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

permissions:
contents: read

jobs:
go:
runs-on: ubuntu-latest
defaults:
run:
working-directory: dashboard
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: dashboard/go.mod
cache-dependency-path: dashboard/go.sum

- name: gofmt
run: |
unformatted="$(gofmt -l .)"
if [ -n "$unformatted" ]; then
echo "These files need gofmt:"
echo "$unformatted"
exit 1
fi

- name: go.mod / go.sum are tidy
run: |
go mod tidy
git diff --exit-code -- go.mod go.sum

- name: go vet
run: go vet ./...

- name: go test -race
run: go test -race ./...

web:
runs-on: ubuntu-latest
defaults:
run:
working-directory: dashboard/web
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: 22
cache: npm
cache-dependency-path: dashboard/web/package-lock.json

- run: npm ci
- run: npm run typecheck
- run: npm run build

compose:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

# Every documented overlay combination must at least parse and interpolate.
- name: docker compose config
run: |
cp .env.example .env
for overlay in nvidia intel amd-rocm cpu pi bridge; do
echo "== $overlay"
docker compose -f docker-compose.yml -f "compose.${overlay}.yml" config --quiet
done
docker compose -f docker-compose.yml -f compose.cpu.yml -f compose.mqtt-lan.yml config --quiet
docker compose -f docker-compose.yml -f compose.intel.yml -f compose.coral.yml config --quiet
docker compose -f docker-compose.yml -f compose.cpu.yml -f compose.tailscale.yml config --quiet
docker compose -f docker-compose.yml -f compose.cpu.yml -f compose.selinux.yml config --quiet

shell:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

# shellcheck is preinstalled on GitHub's ubuntu runners.
- name: shellcheck install.sh
run: |
bash -n install.sh
shellcheck install.sh

image:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1

# Build only (no push). Release images are built by release.yml on v* tags.
- name: Build dashboard image
uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0
with:
context: ./dashboard
push: false
tags: tinkerview:ci
cache-from: type=gha
cache-to: type=gha,mode=max
27 changes: 19 additions & 8 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,36 @@ on:

permissions:
contents: read
packages: write

concurrency:
group: release-${{ github.ref }}
cancel-in-progress: false

jobs:
image:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write # push to ghcr.io
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

# QEMU lets the amd64 runner cross-build the arm64 (Pi) image.
- uses: docker/setup-qemu-action@v3
- uses: docker/setup-buildx-action@v3
- uses: docker/setup-qemu-action@99012661954931238ded8c8b007157a8430204e1 # v4.4.0
- uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1

- name: Log in to GHCR
uses: docker/login-action@v3
uses: docker/login-action@81c6f93d4bc991e510b342a00b419b3bb4efc5c6 # v4.7.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Image tags + labels
id: meta
uses: docker/metadata-action@v5
uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0
with:
# GHCR repository names must be lowercase.
images: ghcr.io/makerviking/tinkerview
Expand All @@ -41,11 +49,14 @@ jobs:
type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/v') }}

- name: Build + push (amd64 + arm64)
uses: docker/build-push-action@v6
uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0
with:
context: ./dashboard
platforms: linux/amd64,linux/arm64
push: true
# Only tag pushes publish. A manual run from a branch builds but does not push.
push: ${{ startsWith(github.ref, 'refs/tags/v') }}
provenance: true
sbom: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
Expand Down
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ dashboard/data/

# --- personal working notes + local dev scaffolding (contain real LAN IPs) ---
handoff.md
REVIEW-*.md
dashboard/dev/

# --- build artifacts ---
Expand All @@ -25,6 +26,11 @@ frigate/clips/
frigate/go2rtc_homekit.yml
frigate/backup_config.yaml
frigate/*.bak
frigate/*.bak.yml
frigate/*.pre-*.bak.*
*.bak
*.bak.yml
*.pre-*.bak.*

# --- recordings / media ---
storage/
Expand Down
Loading
Loading