guacenc, from guacamole-server, converts .guac recordings to video and is
what MP4 downloads (#241) run. Stop passing --disable-guacenc in
build-deb.sh, the release workflow, install.sh, the Dockerfile and
dev.sh, and ship /opt/rustguac/bin/guacenc in the .deb (debian/rules),
the Docker runtime image and the release tarball (install-release.sh
installs it when present). It needs only the ffmpeg libraries guacd is
already built and shipped with, so no new dependencies.
configure leaves guacenc out quietly when an ffmpeg library is missing,
like the protocols, so check-guacd-plugins.sh now also fails the build
when guacenc was not built.
The release workflow built guacd for the .deb without --with-spice and
without libspice-client-glib-2.0-dev, so every .deb from v1.9.0 to
v1.11.0 lacked SPICE and Proxmox consoles failed with "Support for
protocol spice is not installed". Docker and install.sh were fine.
guacd's configure leaves out a protocol whose library is missing even
when asked for it, which is why nothing failed. scripts/check-guacd-plugins.sh
now fails the build unless rdp, ssh, vnc and spice were all built; it
runs after make install in release.yml, build-deb.sh, install.sh and the
Dockerfile.
Also:
- --disable-kubernetes, not --without-kubernetes, which configure ignored,
so every build shipped an unused Kubernetes plugin
- the Dockerfile's trailing || true covered the whole guacd build, so a
failed compile still produced an image; it now covers only the
optional FreeRDP plugin copy it was meant for
A browser test harness under tests/e2e: serve.mjs serves the real static
tree over HTTP and lib/api.mjs answers /api/* from a small fixture address
book, recording every request the page makes, so the shipped pages run
against data the test controls without Vault, guacd or a session. CI gains
an e2e job that installs Chromium and runs the suite.
The first spec pins #252: at 1710px the connections, recordings and reports
tables fit inside the viewport and nothing scrolls sideways.
(cherry picked from commit 4ae28efec0)
tests/*.mjs pin browser-client behaviour (hardware H.264 fallback,
monitor pointer, coalesced drags, and now the #251 framebuffer fit) but
nothing ran them. The check job installs Debian's nodejs (20.x on
trixie) and runs each; they need no browser and no npm packages.
CI ran fmt, clippy, build and audit but never `cargo test`, so none of the
310 tests had ever run on a pull request. That included the regression
tests written specifically to guard past incidents: the recording rotation
that deleted in-progress files, and the credential-variable folder scan
that hid subfolder-granted entries from operators. Both could have been
reintroduced without CI noticing.
Runs the debug profile rather than --release on purpose. debug_assertions
and integer overflow checks are compiled in there and switched off in a
release build, and the wire-protocol parser is where an overflow would
otherwise pass silently.
Noted by @joshsol1 on #230.
- Bump pin 2980cf0 -> 6719b20d in Dockerfile, install.sh, release.yml,
docs/installation.md. -Werror verified clean on the new base (the
GUACAMOLE-2221 pin reason no longer applies).
- Drop patch 006 (terminal OSC-consume): upstreamed as GUACAMOLE-2213
(guac_terminal_unknown_osc).
- Rebase patch 004 (H.264 display worker) onto the refactored libguac
display internals: the queued-H.264-frame free moved into the deferred
guac_display_free_removed_layers path.
- Patches 001/002/003/005/007 unchanged (apply clean on new base).
Local build green under -Werror (guacd + rdp/ssh/vnc). H.264 passthrough
still needs runtime verification on an xrdp+x264 target.
Security audit (v1.6.1 cycle) findings:
- Shadow tokens: each use now writes a shadow_used entry to
token_audit_log with the connecting IP. Prior behaviour audited
only the mint, so a leaked token could be replayed within its
10-minute TTL with no observable record.
- OIDC groups claim: bound per-name length to 256 bytes (UTF-8
boundary preserved) and array size to 64. A misconfigured or
compromised IdP could previously bloat the seen_groups table
unbounded.
- .cargo/audit.toml formalises the rsa (RUSTSEC-2023-0071) and
rustls-pemfile (RUSTSEC-2025-0134) advisory ignores with
rationale, replacing the inline --ignore flag in CI. New
advisories on those crates will still surface.
Small defence-in-depth: WebSocket Origin/Host compare is now
case-insensitive (DNS is canonical) — previously exact-match.
Test harness grows from 150 to 215 tests:
- Pure-function regression coverage: OIDC groups cap, shadow-token
validation matrix (owner/shadow/invalid/expired/IDOR), Vault
path traversal, VDI username sanitization, recording-name
hardening, JPEG magic bytes, Guacamole protocol parser
adversarial cases (overflow length, UTF-8 split, malformed
frames, buffer cap, streaming boundaries), Origin/Host matcher.
- Async + in-memory state: SessionManager test helper bypassing
disk/browser, owner/shadow validation end-to-end, mint prunes
expired, shadow is session-scoped (IDOR guard), disconnect_viewer
saturating decrement, seen_groups DB bounds, rate-limit layer
burst -> 429 (proves tower_governor is actually applied).
Behaviour-preserving refactors to support testing:
check_share_token_match (from validate_share_token),
is_jpeg_magic (from thumbnail PUT), origin_host_matches (from
ws_handler CSWSH check).
Docker pipeline
- Multi-arch build on ubuntu-latest with QEMU was the long pole of
the release pipeline (arm64 took 30–60 min vs ~5 min for the
native-arm .deb job). Split into three jobs:
- build-docker-amd64 on ubuntu-latest
- build-docker-arm64 on ubuntu-24.04-arm (same native runner the
arm64 .deb build uses)
- build-docker-manifest combines them with
`docker buildx imagetools create` into the consumer-facing
`sol1/rustguac:VER` and `:latest` multi-arch manifest lists.
- Consumer-facing tags are unchanged — `docker pull
sol1/rustguac:latest` still auto-picks the right arch. The per-arch
intermediate tags (`:VER-amd64`, `:VER-arm64`) appear as byproducts
on Docker Hub but aren't required.
- The release job now depends on build-docker-manifest instead of
the removed build-docker.
Dependency refresh (closes 5 low-severity Dependabot alerts)
- `cargo update` at root and in fuzz/:
- rustls-webpki: fuzz/ was 0.103.x < 0.103.12 → now 0.103.12
(main lock was already there from v1.5.5)
- rand 0.9.x: < 0.9.3 → 0.9.4 (GHSA-cq8v-f236-94qc: unsound with
a custom logger inside rand::rng())
- rand 0.10.0 → 0.10.1 (same GHSA)
- We don't hook loggers into rand so the unsoundness never triggered
in practice, but getting to clean alerts is worth a lockfile bump.
Upstream GUACAMOLE-2221 introduced -Werror=maybe-uninitialized failure.
Pin all build paths (CI, Dockerfile, install.sh) to last known-good commit.
Update guacd version deliberately, not on every upstream push.