Skip to content

Releases: WebSummoner/websummoner

Release list

1.0.0

Choose a tag to compare

@GhaziTriki GhaziTriki released this 03 Sep 03:06

🧙 websummoner 1.0.0

The hub itself: receives WebDriver requests, summons a browser into a Docker container for each session and proxies the session to it. Everything below is a change to this repository's code since the fork from Aerokube Selenoid (last upstream commit 17 December 2024); the release story across all projects is in the announcement.

⚠️ Breaking

  • Go module path is github.com/websummoner/websummoner; the binary is websummoner and the image websummoner/websummoner.
  • The Docker image's entrypoint reads /etc/websummoner/browsers.json and writes video to /opt/websummoner/video. Update the two mount targets, or pass your own -conf and -video-output-dir.
  • -video-recorder-image defaults to websummoner/video-recorder:latest-release.
  • For opera, yandex and brave sessions the hub replaces goog:chromeOptions with its own binary and arguments (see Session handling); clients cannot pass Chromium flags for those three browsers. Chrome and Edge are untouched.

🤝 Compatibility kept, permanently

  • selenoid:options is still merged; the new websummoner:options block wins when both are present.
  • X-Selenoid-No-Wait and X-Selenoid-File are accepted alongside X-WebSummoner-No-Wait and X-WebSummoner-File.
  • The /wd/hub/session/<id>/aerokube/... vendor path is accepted alongside /websummoner/....

🔀 Session handling

  • A full queue with either no-wait header set answers 429 Too Many Requests instead of a generic 500 (RFC 6585; upstream issue aerokube#1203). Header presence is what matters, since GGR sends it with an empty value.
  • Deterministic version lookup in browsers.json: an exact key wins, otherwise the longest key the requested version is a prefix of. Upstream took the first prefix match in map order.
  • Vendor blocks and the legacy version routing hint are stripped before the request reaches the driver; modern drivers reject unknown capabilities (upstream issue aerokube#909).
  • adaptDriverCapabilities: sessions for opera, yandex and brave are forwarded as browserName: chrome with the right binary (/usr/bin/opera, /usr/bin/yandex-browser, /opt/brave.com/brave/brave-browser), --no-sandbox and a per-request --user-data-dir; Yandex gets --homepage=about:blank --no-first-run --no-default-browser-check; Opera gets goog:chromeOptions.w3c: true, because operadriver answers in JSONWP unless asked for W3C. Routing still happens on the real browser name, so a browser fix here applies to images built long before it.
  • JSONWP replies are wrapped into the W3C envelope; a JSONWP reply with a non-zero status is treated as an error rather than a session, and a reply without a sessionId returns a clear error instead of panicking.
  • se:cdp and se:cdpVersion are advertised only for Chromium browsers; advertising a CDP endpoint for Firefox or WebKit made clients fail their first WebSocket handshake.
  • A session that fails to start removes the temporary video and log files it had reserved.
  • The reverse proxy uses httputil.ProxyRequest.Rewrite and sets X-Forwarded-*; the Director API is gone.
  • Start-up returns errors instead of calling log.Fatal from three places, and signal channels are buffered, so shutdown drains the server, closes the Docker client and reports once.

📈 Observability

  • /metrics in Prometheus text format: websummoner_sessions_active, websummoner_sessions_limit, websummoner_queue_depth, websummoner_queue_pending, websummoner_browser_sessions{browser="…"}, and the counters websummoner_sessions_created_total, websummoner_sessions_failed_total, websummoner_sessions_timed_out_total, websummoner_sessions_deleted_total, websummoner_video_sessions_total, websummoner_vnc_sessions_total, websummoner_audio_sessions_total.
  • HEAD /ping answers 200; HEAD /status answers 200 when a slot is free and 503 when the hub is full. The old handlers served GET only, which broke Kubernetes probes and load-balancer checks.

📤 Files, video and audio

  • File upload for containerised browsers is served by the hub, on /session/<id>/file and on the /session/<id>/se/file path Selenium 4 actually sends (the old interception matched only the legacy four-fragment form, so it never fired). The hub unpacks the zip and places the file at /opt/websummoner/uploads/ inside the browser container by streaming a tar to tar -x running in the container, which honours tmpfs and volume mounts and leaves the file owned by the browser's user; images without tar fall back to the Docker copy API, and a test -f in the container confirms the file is visible before the path is handed to the driver. -enable-file-upload gates the feature as before.
  • enableAudio capability (default true) controls the audio track of recordings: ENABLE_AUDIO on the browser container, DISABLE_AUDIO=true on the recorder when off.
  • The W3C proxy capability is translated into http_proxy, https_proxy and no_proxy on the browser container for safari sessions, because WebKitWebDriver ignores the capability; localhost, 127.0.0.1 and ::1 are always excluded so the driver's own connection is never proxied.

🔒 Hardening

  • videoName and logName must be plain file names; anything with a path element is rejected with invalid argument. The video delete endpoint applies the same check.
  • Video and log output directories are created 0755; upstream created them 0644, which is not traversable.
  • The Docker client negotiates the API version again after the compatibility probe instead of staying pinned to the minimum the probe left behind.
  • SECURITY.md documents the reporting process and that anyone who can reach the hub can start containers.

📦 Dependencies

Was Now
Go 1.22 1.27
github.com/docker/docker v26.1.5 v28.5.2 (types.ContainerJSONcontainer.InspectResponse and friends)
github.com/docker/go-connections v0.5.0 v0.8.1
github.com/imdario/mergo v0.3.15 dario.cat/mergo v1.0.2
github.com/mafredri/cdp v0.34.1 v0.35.0
golang.org/x/net v0.25.0 v0.58.0
github.com/gorilla/websocket v1.5.1 v1.5.3
github.com/stretchr/testify v1.9.0 v1.12.1
github.com/aws/aws-sdk-go v1.53.5 v1.55.8
GGR config types github.com/aerokube/ggr github.com/websummoner/ggr

🏗️ Build, CI and supply chain

  • golangci-lint gates every push and pull request: errcheck, govet, staticcheck, ineffassign, misspell, unused and gofmt; the tree passes with the full set enabled.
  • govulncheck runs in CI with a narrow, documented allowlist (ci/govulncheck.sh): two Moby daemon-side advisories with no affected symbols and no fixed version. Anything else fails the build.
  • Release workflow: binaries for linux amd64/arm64, darwin amd64/arm64 and windows amd64/arm64/386, all CGO_ENABLED=0; the image built for linux/amd64 and linux/arm64; an SPDX SBOM generated with Syft and attached to the release; the image signed with cosign (keyless). Docker Hub login reads the password from stdin, the repository name is lower-cased, and the selenoid/hub tag is no longer pushed.
  • Test workflow with the race detector and coverage to Codecov and DeepSource; a lint workflow; a docs workflow; the stale-issue workflow on actions/stale v11; Dependabot weekly with grouped pull requests for Go modules, the Docker base image, GitHub Actions and the documentation site's npm packages.
  • AGENTS.md describes the workspace, the dockerised toolchain and the contribution rules; ci/docs.sh and the AsciiDoc pipeline are gone.

🧪 Tests

New test files cover driver mode end to end (driver_mode_test.go), the HEAD probes (health_test.go), graceful start and shutdown (run_test.go), the metrics format and counters (metrics_test.go), the queue's no-wait and 429 paths (protect/queue_test.go), capability adaptation, JSONWP wrapping, CDP advertising, safe file names and vendor-option stripping (safety_test.go, branches_test.go), plus unit tests for info and jsonerror. Coverage is reported for every package.

📚 Documentation

The AsciiDoc fragments under docs/ are replaced by docs-site/, an Astro Starlight site — 30 pages, full-text search, dark mode, an llms.txt export — deployed to GitHub Pages at websummoner.riadvice.com/websummoner by its own workflow, which also builds every pull request. New pages include Migrating from Selenoid, a source-checked comparison with Selenoid, Moon, Selenium Grid, Selenide, Playwright and Puppeteer, Browser images with per-browser behaviour, Image tags, Building browser images, Docker Compose, S3 upload and a FAQ. Analytics load only when a measurement id is configured, and then only after consent.


WebSummoner 1.0.0 · 📖 Documentation · 💬 Discussions

WebSummoner is developed and maintained by RIADVICE under Apache-2.0. It builds on Selenoid by Aerokube and Ivan Krutov, and on the original UI by Kirill Merkushev.