Commit Graph
11 Commits
Author SHA1 Message Date
Logan Cusano 28266b4441 Pin the op25 container to a Python major version
CI / lint (push) Successful in 6s
Build op25 / build (push) Successful in 21s
CI / test (push) Successful in 38s
`python:slim-trixie` carried no version at all, so a rebuild could move the
interpreter across a major release without anything in the repo changing. That
is not hypothetical here: app/models.py referenced IcecastConfig about 85 lines
before its definition and ran only because trixie currently ships Python 3.14,
where PEP 649 defers annotation evaluation. On 3.13 it was a hard NameError.
The ordering was fixed on 2026-08-16; the unpinned base outlived it.

Pinned to 3.14-slim rather than 3.14-slim-trixie so it matches drb-edge-node,
which was already on 3.14-slim. Patch releases still float, which is what we
want for security updates -- only the major version is nailed down.

Every other Dockerfile in both repos already pinned a major version
(python:3.12-slim, python:3.14-slim, node:20-slim, debian:bookworm-slim), so
this was the only genuinely unpinned base image, despite server-26#11 claiming
none of them were pinned.

Closes logan/server-26#11 (filed against the wrong repo -- the file lives in
the client repo).
2026-08-20 03:01:38 -04:00
Logan CusanoandClaude Opus 5 9d86304b8a Revert the CI full-fetch workaround and drop unreachable workflows
CI / lint (push) Failing after 17s
CI / test (push) Successful in 49s
Build op25 / build (push) Successful in 1h29m25s
Shallow clones were never a Gitea packing bug. An intruder had set
uploadpack.packObjectsHook in Gitea's HOME gitconfig, pointing at a
non-executable dropper, so every upload-pack died mid-pack. That hook is
gone and --depth=1 clones are verified working, so fetch-depth: 0 buys
nothing but slower CI. See INCIDENT-2026-08-11.md.

op25-container/.gitea/workflows/* never ran: Gitea only executes
workflows under .gitea/workflows at the repo root, and op25-container is
a subdirectory of this repo, not a repo of its own. The live OP25 image
build is .gitea/workflows/build-op25.yml.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-16 13:00:02 -04:00
Logan CusanoandClaude Opus 5 a61a7b2c31 Bind OP25 control API and terminal to loopback by default
Both :8001 (FastAPI control API) and :8081 (OP25's HTTP terminal) listened on
0.0.0.0 with no authentication, on a container that is privileged with /dev
mounted and network_mode: host. Nodes get deployed to third-party sites, so
that exposed start/stop/retune to anyone on the host's LAN.

All three containers share the host network namespace, so edge-node still
reaches both over 127.0.0.1 unchanged. OP25_DEBUG_EXPOSE=true restores the
old 0.0.0.0 binding and logs a loud warning; it is off by default.

Confirmed against boatbod/op25 gr310 that the terminal's http:<host>:<port>
string is honoured as a real bind address (http_server.py splits it and hands
the host to create_server), so no flag was invented.

Also reorder models.py so IcecastConfig precedes ConfigGenerator, which
annotates a field with it. That only worked because python:slim-trixie is
currently Python 3.14, where PEP 649 defers annotation evaluation; on 3.13 or
earlier the same file is a hard NameError at import.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-16 09:33:25 -04:00
Logan CusanoandClaude Opus 5 7c4a3f2f20 Make PulseAudio readiness mean a live connection, clear stale socket state
The pulse_socket named volume survives container recreation, so after a
compose recreate the previous container's /run/pulse/pid and native
socket were still present. PulseAudio read the stale pid file, decided a
daemon was already running, and refused to start:

    E: [pulseaudio] pid.c: Daemon already running.

The entrypoint still reported "PulseAudio socket ready" because it only
checked that the socket file existed - and a stale one did. Capture then
failed in a restart loop against a dead daemon.

Readiness in both the op25 entrypoint and drb-edge-node now means a
pactl probe actually succeeds. Stale pid/socket are removed only when
that probe fails, so a live daemon's socket is never deleted.

pulseaudio-utils was missing from the edge-node image (only libpulse0
was installed), so no pactl binary existed there at all - added.

Capture exits are now classified: a missing source logs at ERROR and
names the configured PULSE_SOURCE, rather than looking identical to
"daemon not up yet". Retrying forever against a wrong source name is how
the April PulseAudio failure stayed hidden.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-04 22:10:28 -04:00
Logan 16f6e0de95 audio fixes attempt
CI / lint (push) Failing after 6s
CI / test (push) Successful in 19s
Build edge-node / build (push) Successful in 7m54s
Build op25 / build (push) Successful in 1h25m50s
2026-05-23 14:59:48 -04:00
Logan d0e4734cf9 Linting + touches
CI / lint (push) Successful in 8s
Build edge-node / build (push) Failing after 22s
Build icecast / build (push) Failing after 23s
CI / test (push) Successful in 23s
Build op25 / build (push) Failing after 16s
2026-04-21 00:56:50 -04:00
Logan 4e41df9f95 updates 2026-04-12 03:34:11 -04:00
Logan 33cad7ed24 updates 2026-04-12 03:05:48 -04:00
Logan fb86d79930 File Change
op25-container/system.pa	New PulseAudio config: auth-anonymous=1 so the edge-node can connect without group membership
op25-container/Dockerfile	Copies system.pa into /etc/pulse/system.pa
drb-edge-node/Dockerfile	Added libpulse0 — ffmpeg needs this runtime library to use -f pulse
drb-edge-node/app/internal/call_recorder.py	Switched recording from Icecast (burst-buffer overlap) to PulseAudio monitor (zero-delay, exact call boundaries)
2026-04-11 21:16:32 -04:00
Logan 7de55f9885 changes 2026-04-06 00:23:33 -04:00
Logan 1a9c92b6db Initial commit — DRB client (edge node) stack
Includes edge-node (FastAPI/MQTT/Discord voice), op25-container (SDR decoder),
and icecast (audio streaming).
2026-04-05 19:01:51 -04:00