mirror of
https://github.com/block/buzz.git
synced 2026-10-27 12:40:30 +00:00
Huddle audio was embedded in the v0 desktop client, forcing other clients to duplicate its protocol and codec behavior. This extracts `buzz-audio-client` so v1 can depend on a pinned library revision without building the v0 application. The crate owns the bounded v2 audio handshake, roster parsing, wire format, Opus sender, and per-peer NetEQ jitter buffer. The v0 human and agent senders use it, and the desktop retains room admission, identity/signing, TLS policy, device routing, mute, and teardown. Receive decoding preserves v1's support for 120 ms Opus packets. No relay protocol changes, speech models, or model downloads are included. Docker builder stages include CMake because cargo-chef compiles the workspace dependency graph. Dependency security: Opus 0.4 replaces the unmaintained `audiopus_sys` backend with `opusic-sys`. NetEQ is pinned exactly to 0.8.3 because its published Rust sources never reference its declared ringbuf dependency. RUSTSEC-2026-0293 is documented as unreachable for this audited source, and a wrapper restriction rejects every other consumer of vulnerable ringbuf versions. Independent review confirmed the scope; re-audit/remove the exception when changing NetEQ. NetEQ 0.9.1 still declares ringbuf 0.3, so a version bump alone does not remove it. Local `cargo deny check` passes with this constrained exception. Validation: - All 21 shared-crate tests pass, including real loopback WebSocket authentication/cancellation, real Opus-to-NetEQ playback, malformed input, and 120 ms decoding. These tests are included in `just test-unit`. - Shared-crate, root workspace, and desktop Tauri Clippy pass; `just desktop-tauri-check` passes. - The desktop Tauri test workspace passes; native two-person listening/device checks remain separate. - All mandatory push checks pass at `d06bac5dc`, including the complete Rust unit gate and desktop workspace checks. Existing agent timing and relay log-capture tests failed under concurrent load, passed separately, and passed in the full serial test run; no tests or hooks were skipped. - One test-only fixture change allows cold Perl startup before the escaped-process test's inner timeout (2 seconds instead of 300 ms). Its independent 5-second watchdog, 300-second surviving pipe writer, and all assertions remain intact. All eight process-helper tests pass; independent review confirmed this still tests bounded drain completion. - Dependency inspection confirms the library brings in no desktop application, Tauri, identity store, relay server, or speech-model crates. - Independent source review found no correctness blockers. Draft: a native two-person call, mute/leave/cancellation, and microphone/speaker switching still need a runtime tryout and human review. Full `just ci` was stopped during the unrelated mobile toolchain download because of disk pressure; it is not a passing gate. Consumer integration is tracked in block/buzz-app#489. --------- Signed-off-by: kenny lopez <klopez4212@gmail.com>
188 lines
9.0 KiB
Docker
188 lines
9.0 KiB
Docker
# syntax=docker/dockerfile:1.7
|
|
#
|
|
# Public Buzz relay image — published as ghcr.io/block/buzz:<tag>.
|
|
#
|
|
# Builds the `buzz-relay` binary (Rust 1.95) and the `buzz-web` static bundle
|
|
# (pnpm + vite), then assembles them into a small debian-slim runtime with
|
|
# `git` available (the relay shells out to git for repo hydrate / receive-pack
|
|
# / upload-pack — see crates/buzz-relay/src/api/git).
|
|
#
|
|
# Multi-arch is handled by running this same Dockerfile on native amd64 and
|
|
# native arm64 runners (see .github/workflows/docker.yml). The Dockerfile
|
|
# itself is platform-agnostic; do not add --platform pins.
|
|
|
|
ARG RUST_VERSION=1.95
|
|
ARG NODE_VERSION=24
|
|
ARG DEBIAN_VERSION=bookworm
|
|
|
|
# Optional extra CA bundle for builds behind a TLS-intercepting corporate proxy
|
|
# (e.g. a Cloudflare/Zscaler gateway that re-signs TLS). Empty by default, so
|
|
# public CI builds are unaffected. Point it at a PEM file in the build context:
|
|
# docker build --build-arg EXTRA_CA_CERTS=path/to/proxy-ca.pem ...
|
|
# Consumed by the network-touching stages below (cargo + pnpm).
|
|
ARG EXTRA_CA_CERTS=
|
|
|
|
# Optional npm registry for builds where the public registry is unreachable or
|
|
# policy-blocked (e.g. a corporate mirror / Artifactory). Empty default = public
|
|
# npmjs, so public CI builds are unaffected. Consumed by the web-builder stage.
|
|
ARG NPM_REGISTRY=
|
|
|
|
# ─── Stage 1: cargo-chef base ───────────────────────────────────────────────
|
|
FROM rust:${RUST_VERSION}-${DEBIAN_VERSION} AS chef
|
|
# Trust an optional corporate-proxy CA before any network fetch (no-op if unset).
|
|
ARG EXTRA_CA_CERTS
|
|
COPY --chmod=0644 ${EXTRA_CA_CERTS:-Dockerfile} /tmp/extra-ca/src
|
|
RUN if [ -n "${EXTRA_CA_CERTS}" ]; then \
|
|
cp /tmp/extra-ca/src /usr/local/share/ca-certificates/extra-proxy-ca.crt \
|
|
&& update-ca-certificates \
|
|
&& echo "CARGO_HTTP_CAINFO=/etc/ssl/certs/ca-certificates.crt" >> /etc/environment; \
|
|
fi
|
|
ENV CARGO_HTTP_CAINFO=/etc/ssl/certs/ca-certificates.crt
|
|
RUN cargo install cargo-chef --locked --version 0.1.71
|
|
WORKDIR /build
|
|
|
|
# ─── Stage 2: plan dependency graph ─────────────────────────────────────────
|
|
# Only the manifests are needed to compute the recipe; this layer rebuilds
|
|
# only when Cargo.{toml,lock} or crate manifests change, not on every source
|
|
# edit.
|
|
FROM chef AS planner
|
|
COPY . .
|
|
RUN cargo chef prepare --recipe-path recipe.json
|
|
|
|
# ─── Stage 3: cook dependencies, then build the binary ──────────────────────
|
|
FROM chef AS builder
|
|
RUN apt-get update \
|
|
&& apt-get install -y --no-install-recommends \
|
|
build-essential \
|
|
cmake \
|
|
pkg-config \
|
|
libssl-dev \
|
|
ca-certificates \
|
|
git \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
# Keep enough DWARF for native profilers to resolve optimized code to source
|
|
# locations. The normal runtime strips it below; runtime-debug retains it.
|
|
ENV CARGO_PROFILE_RELEASE_DEBUG=line-tables-only
|
|
COPY --from=planner /build/recipe.json recipe.json
|
|
# Cook the full workspace recipe — relay deps include workspace siblings, so
|
|
# scoping to -p buzz-relay misses transitive deps and re-builds them later.
|
|
RUN cargo chef cook --release --recipe-path recipe.json
|
|
COPY . .
|
|
# Compile immutable artifact identity into the relay. Defaults preserve local
|
|
# and third-party builds that do not run in provenance-aware CI.
|
|
ARG BUZZ_SOURCE_SHA=unknown
|
|
ARG BUZZ_BUILD_ID=local
|
|
ARG BUZZ_BUILD_URL=unknown
|
|
ENV BUZZ_SOURCE_SHA=${BUZZ_SOURCE_SHA} \
|
|
BUZZ_BUILD_ID=${BUZZ_BUILD_ID} \
|
|
BUZZ_BUILD_URL=${BUZZ_BUILD_URL}
|
|
RUN cargo build --release --locked -p buzz-relay --bin buzz-relay \
|
|
-p buzz-admin --bin buzz-admin \
|
|
-p buzz-pair-relay --bin buzz-pair-relay
|
|
|
|
# Derive the normal release binaries from the same optimized ELF files as the
|
|
# debug image so the two variants cannot drift at code-generation time.
|
|
FROM builder AS stripped-binaries
|
|
RUN strip target/release/buzz-relay \
|
|
&& strip target/release/buzz-admin \
|
|
&& strip target/release/buzz-pair-relay
|
|
|
|
# ─── Stage 4: web bundle (pnpm + vite) ──────────────────────────────────────
|
|
# Independent of the Rust layers so a CSS change doesn't bust Rust cache and
|
|
# vice versa.
|
|
FROM node:${NODE_VERSION}-${DEBIAN_VERSION}-slim AS web-builder
|
|
WORKDIR /build
|
|
# Trust an optional corporate-proxy CA so corepack + pnpm can fetch over an
|
|
# intercepting TLS gateway (no-op if EXTRA_CA_CERTS is unset).
|
|
ARG EXTRA_CA_CERTS
|
|
COPY --chmod=0644 ${EXTRA_CA_CERTS:-Dockerfile} /tmp/extra-ca/src
|
|
RUN if [ -n "${EXTRA_CA_CERTS}" ]; then \
|
|
apt-get update && apt-get install -y --no-install-recommends ca-certificates \
|
|
&& cp /tmp/extra-ca/src /usr/local/share/ca-certificates/extra-proxy-ca.crt \
|
|
&& update-ca-certificates \
|
|
&& rm -rf /var/lib/apt/lists/*; \
|
|
fi
|
|
ENV NODE_EXTRA_CA_CERTS=/etc/ssl/certs/ca-certificates.crt
|
|
# Point npm + corepack at an optional mirror (no-op when NPM_REGISTRY is unset).
|
|
# corepack reads COREPACK_NPM_REGISTRY to fetch the pinned pnpm; pnpm/npm read
|
|
# the .npmrc registry for dependency installs.
|
|
ARG NPM_REGISTRY
|
|
ENV COREPACK_NPM_REGISTRY=${NPM_REGISTRY}
|
|
# When using a mirror, disable corepack's npmjs signature check: the mirror
|
|
# republishes tarballs without the public registry's provenance signatures, so
|
|
# strict verification fails ("No compatible signature found"). Only relaxed on
|
|
# the mirror path — public builds (NPM_REGISTRY unset) keep strict verification.
|
|
RUN if [ -n "${NPM_REGISTRY}" ]; then \
|
|
echo "registry=${NPM_REGISTRY}" > /build/.npmrc \
|
|
&& echo "COREPACK_INTEGRITY_KEYS=0" >> /etc/environment; \
|
|
fi
|
|
ENV COREPACK_INTEGRITY_KEYS=${NPM_REGISTRY:+0}
|
|
RUN corepack enable
|
|
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
|
|
COPY patches/ patches/
|
|
COPY web/package.json web/
|
|
COPY admin-web/package.json admin-web/
|
|
RUN pnpm install --frozen-lockfile --filter buzz-web --filter buzz-admin-web
|
|
COPY web/ web/
|
|
COPY admin-web/ admin-web/
|
|
RUN pnpm -C web build && pnpm -C admin-web build
|
|
|
|
# ─── Stage 5: shared runtime ────────────────────────────────────────────────
|
|
FROM debian:${DEBIAN_VERSION}-slim AS runtime-base
|
|
|
|
# OCI annotations: required for GHCR to auto-link the image to this repo and
|
|
# inherit its visibility. org.opencontainers.image.source is the load-bearing
|
|
# one — without it GHCR keeps the image private even when the repo is public.
|
|
LABEL org.opencontainers.image.title="Buzz" \
|
|
org.opencontainers.image.description="WebSocket relay server for the Buzz communications platform" \
|
|
org.opencontainers.image.source="https://github.com/block/buzz" \
|
|
org.opencontainers.image.url="https://github.com/block/buzz" \
|
|
org.opencontainers.image.documentation="https://github.com/block/buzz#readme" \
|
|
org.opencontainers.image.licenses="Apache-2.0"
|
|
|
|
RUN apt-get update \
|
|
&& apt-get install -y --no-install-recommends \
|
|
ca-certificates \
|
|
curl \
|
|
git \
|
|
openssl \
|
|
&& rm -rf /var/lib/apt/lists/* \
|
|
&& groupadd --system --gid 1000 buzz \
|
|
&& useradd --system --uid 1000 --gid 1000 --home-dir /var/lib/buzz \
|
|
--create-home --shell /usr/sbin/nologin buzz
|
|
|
|
COPY --from=web-builder /build/web/dist /srv/buzz/web
|
|
COPY --from=web-builder /build/admin-web/dist /srv/buzz/admin-web
|
|
|
|
# The invite landing page is always served from the bundled web UI. Repository
|
|
# browser routes require the separate BUZZ_SERVE_GIT_WEB_GUI=true opt-in. The
|
|
# admin bundle is inert until BUZZ_ADMIN_HOST is configured.
|
|
ENV BUZZ_WEB_DIR=/srv/buzz/web \
|
|
BUZZ_ADMIN_WEB_DIR=/srv/buzz/admin-web
|
|
|
|
# 3000: app (WS + REST) · 8080: /_liveness, /_readiness · 9102: /metrics
|
|
EXPOSE 3000 8080 9102
|
|
|
|
# deploy/compose mounts a volume here; pre-created so it inherits buzz:buzz.
|
|
RUN mkdir -p /data/git && chown buzz:buzz /data/git
|
|
|
|
USER buzz:buzz
|
|
WORKDIR /var/lib/buzz
|
|
|
|
ENTRYPOINT ["/usr/local/bin/buzz-relay"]
|
|
|
|
# Optimized binaries with line-table debug information for native profiling.
|
|
# Published under debug-* tags; runtime behavior otherwise matches the normal
|
|
# image exactly.
|
|
FROM runtime-base AS runtime-debug
|
|
COPY --from=builder /build/target/release/buzz-relay /usr/local/bin/buzz-relay
|
|
COPY --from=builder /build/target/release/buzz-admin /usr/local/bin/buzz-admin
|
|
COPY --from=builder /build/target/release/buzz-pair-relay /usr/local/bin/buzz-pair-relay
|
|
|
|
# Keep the stripped runtime as the final/default Dockerfile target so existing
|
|
# `docker build .` callers and release tags retain their current behavior.
|
|
FROM runtime-base AS runtime
|
|
COPY --from=stripped-binaries /build/target/release/buzz-relay /usr/local/bin/buzz-relay
|
|
COPY --from=stripped-binaries /build/target/release/buzz-admin /usr/local/bin/buzz-admin
|
|
COPY --from=stripped-binaries /build/target/release/buzz-pair-relay /usr/local/bin/buzz-pair-relay
|