142 lines
7.1 KiB
Plaintext
142 lines
7.1 KiB
Plaintext
# workshop configuration template.
|
|
#
|
|
# Copy to /opt/smart-home/workshop/workshop.env on the container host, fill in, and
|
|
# chmod 600 it. Same never-commit handling as every other *.env here.
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Auth — required. Fails closed (rejects every request) while empty.
|
|
# openssl rand -hex 32
|
|
# ---------------------------------------------------------------------------
|
|
WORKSHOP_TOKEN=
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Storage. THE SPLIT THAT MATTERS: the database is the index, the workspace is the
|
|
# filing cabinet. Queryable state (projects, parts, decisions) goes in SQLite;
|
|
# artefacts (datasheets, generated diagrams, photos, notes you want to open from a
|
|
# laptop) are ordinary files under the workspace, which is exported read-write over
|
|
# SMB. See docs/workshop-assistant.md.
|
|
#
|
|
# The workspace is the ONE writable share in this stack — the photo gallery share is
|
|
# deliberately read-only — so it gets its own volume and its own SMB account. Nothing
|
|
# on the host ever executes anything found in it.
|
|
# ---------------------------------------------------------------------------
|
|
WORKSHOP_DB_PATH=/data/workshop.db
|
|
WORKSHOP_WORKSPACE_DIR=/workspace
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Run behaviour
|
|
# ---------------------------------------------------------------------------
|
|
# 8098 is identity_web — see CoreSystemConfig.json's ports block, which the validator
|
|
# checks for duplicates.
|
|
WORKSHOP_PORT=8102
|
|
LOG_LEVEL=INFO
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Knowledge store — the second database, and the one that is NEVER pruned.
|
|
#
|
|
# workshop.db is a record of WORK (projects, decisions, the log). This is a record of
|
|
# WHAT IS TRUE: standing instructions about how you work, facts and specs by keyword,
|
|
# what was learned about a project, and the hardware inventory. Every other store in
|
|
# this stack has a retention window because stale observations are worse than none;
|
|
# this one is the opposite — the whole point is that you tell it once. There is no
|
|
# cutoff and no cleanup pass, by design.
|
|
# ---------------------------------------------------------------------------
|
|
WORKSHOP_KNOWLEDGE_DB_PATH=/data/workshop-knowledge.db
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Gitea (optional; repo creation is refused while unset).
|
|
#
|
|
# Lets a project be given a git repository. The service CREATES repos and reports
|
|
# them — it never pushes, commits or clones, and it has no delete path at all, even
|
|
# though the token technically permits one.
|
|
#
|
|
# The token: Gitea → Settings → Applications → Generate New Token, scope
|
|
# `write:repository` (plus `write:user` if GITEA_OWNER is left empty so repos are made
|
|
# under the token's own account).
|
|
#
|
|
# STRONGLY PREFERRED: a dedicated Gitea user ("workshop-bot") with access to ONE
|
|
# organisation, named in GITEA_OWNER — rather than a token on your own account, which
|
|
# can reach everything you own. The blast radius of a leaked env file is then one org
|
|
# of generated repos.
|
|
# ---------------------------------------------------------------------------
|
|
GITEA_URL=
|
|
GITEA_TOKEN=
|
|
GITEA_OWNER=
|
|
# Generated repos are private unless this is explicitly "false".
|
|
GITEA_PRIVATE_REPOS=true
|
|
GITEA_TIMEOUT=15
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Git. The assistant commits and pushes unattended; it NEVER rewrites history.
|
|
#
|
|
# Allowed: commit, push, branch, tag, merge — everything that ADDS to history, because
|
|
# the worst case is a bad commit you revert.
|
|
# Never, by any path: force-push, rebase, amend, reset --hard, filter-branch,
|
|
# filter-repo, branch/tag deletion, reflog expiry, gc --prune. Rewriting has no undo.
|
|
#
|
|
# That refusal lives in git_ops.py, but the real enforcement is Gitea BRANCH
|
|
# PROTECTION, applied automatically when a repo is created (enable_force_push: false,
|
|
# enable_delete: false). Client-side refusal is a policy; branch protection is a
|
|
# control. Check the create-repo response's `repo.protection.applied` — do not assume
|
|
# it is on because the repo exists.
|
|
#
|
|
# When history genuinely has to be scrubbed (a committed API token), POST
|
|
# /projects/<slug>/scrub-request returns the commands to run BY HAND from the repo on
|
|
# the SMB share. The manual step is the safety mechanism; automating it would remove
|
|
# the only thing making it safe.
|
|
#
|
|
# The working tree is code/ inside the project workspace — never the workspace root —
|
|
# so no git operation can reach the datasheets and photos beside it.
|
|
# ---------------------------------------------------------------------------
|
|
WORKSHOP_GIT_AUTHOR_NAME=workshop assistant
|
|
WORKSHOP_GIT_AUTHOR_EMAIL=workshop@localhost
|
|
WORKSHOP_GIT_BRANCH=main
|
|
WORKSHOP_GIT_TIMEOUT=120
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Infrastructure health — CheckMK + every OPNsense firewall, polled here.
|
|
#
|
|
# WHY HERE AND NOT IN digest-engine: the digest runs four times a day, and "is the NAS
|
|
# disk failing right now" is not a question with a six-hour answer. This service is
|
|
# always on, so it polls and keeps ~30 days of samples; digest-engine reads THIS over
|
|
# HTTP (its ENABLE_INFRA_HEALTH_INGEST). One poller, two consumers — and the digest
|
|
# gets "critical since Tuesday" instead of a snapshot it can't compare to anything.
|
|
#
|
|
# READ-ONLY, and not by promise: the CheckMK user should have the Guest role, which
|
|
# cannot acknowledge, downtime or reschedule. From OPNsense this reads exactly one
|
|
# endpoint (GET /api/ids/service/status — is Suricata running); the alert query stays
|
|
# in digest-engine, which already does the paging properly.
|
|
#
|
|
# OPNSENSE_JSON is written by tools/config-export.py from the `opnsense` LIST in
|
|
# CoreSystemConfig.json — every firewall carries its own name, and that name reaches
|
|
# the digest and the display, so "the IDS is running" can never stand in for two
|
|
# firewalls of which one is down.
|
|
# ---------------------------------------------------------------------------
|
|
CHECKMK_BASE_URL=
|
|
CHECKMK_SITE=cmk
|
|
CHECKMK_USERNAME=
|
|
CHECKMK_SECRET=
|
|
CHECKMK_ONLY_PROBLEMS=true
|
|
CHECKMK_MAX_ROWS=200
|
|
OPNSENSE_JSON=
|
|
WORKSHOP_HEALTH_INTERVAL_SECONDS=300
|
|
WORKSHOP_HEALTH_TIMEOUT=20
|
|
WORKSHOP_HEALTH_RETENTION_DAYS=30
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Network cameras the workshop display may show.
|
|
#
|
|
# The USB webcams in this project are fixed-purpose (a kitchen item held to a lens, a
|
|
# doorway) and their angles are useless for anything else — so what the workshop shows
|
|
# is the NETWORK cameras, via the go2rtc/Frigate this stack already runs.
|
|
#
|
|
# Format: name:stream_id[,name:stream_id...] where stream_id is the camera's name in
|
|
# go2rtc. The frontend builds a WebRTC/MSE URL from it; nothing here proxies video,
|
|
# because putting a Python HTTP server in the path of an H.264 stream is how you turn
|
|
# a working camera into a stuttering one.
|
|
# ---------------------------------------------------------------------------
|
|
WORKSHOP_CAMERAS=
|
|
# Base URL of go2rtc's own web API, reachable from the BROWSER (not from this
|
|
# container) — the kiosk connects to it directly.
|
|
GO2RTC_URL=
|