- 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.