Skip to content

feat(socket): admin socket settings page and runtime config for the socket server - #722

Merged
roncodes merged 4 commits into
release/v0.7.70from
feature/socket-admin-settings
Oct 15, 2026
Merged

roncodes merged 4 commits into
release/v0.7.70from
feature/socket-admin-settings

Conversation

@roncodes

@roncodes roncodes commented Oct 15, 2026 •

Copy link
Copy Markdown
Member

What

Admins can now manage socket authentication from Admin → Configure → Socket, and the socket server applies the changes at runtime without a restart.

Socket server (socket/)

  • Config polling. When SOCKETCLUSTER_AUTH_KEY is set, the server polls the API's signed GET int/v1/socket/config every SOCKETCLUSTER_CONFIG_POLL_SECONDS (default 30; 0 disables). Requests are signed with the authorize key and time out after 2 s. SOCKETCLUSTER_CONFIG_URL defaults to the authorize URL with /authorize replaced by /config. Without a key there is no polling and the server uses its environment only, as before.
  • Applied at runtime: enabled, mode (including allowClientPublish = mode !== 'enforce') and origins. A null mode or origins falls back to the socket server's own environment value. The environment is the starting config. When the API is unreachable, times out or answers with something malformed, the last good config stays in force.
  • The key is passed to SocketCluster whenever one is set, so tokens verify even while auth is off and switching on needs no restart. Behaviour is gated by the runtime mode. With a key, /publish and /stats also work while auth is off. That way the API can publish over HTTP as soon as its own switch flips, before the next poll.
  • Entering enforce at runtime disconnects every socket once (close code 4100). Clients reconnect after their usual reconnect delay, and subscriptions made under looser auth go through the authorizer again.
  • /stats additions:
    • config: {enabled, mode, origins, source: env|api, last_sync_at, last_sync_error};
    • denials: the top 50 {client, prefix, reason, count, last_at}. The prefix is the channel up to its first ., or other. Rows are capped and never contain tokens, subjects, company ids or full channel names.
  • Helm exposes socketcluster.configUrl / configPollSeconds. docker-compose needs nothing new, since the default derives from the authorize URL.

Which SocketCluster 17 settings can change live: allowClientPublish, origins and _allowAllOrigins are plain AGServer fields, read on every inbound #publish and every handshake, so setting them on the running server works. Origin changes only affect new handshakes; open connections are not re-checked.

Console (console/)

  • The Configure → Socket page now has three panels:
    • Status: whether the socket server is reachable, the effective switch and mode with Console setting / Environment badges, whether the key is configured, connections, what the server runs and its last config sync, and out-of-sync / sync-error notices.
    • Denials: a table of the aggregated denials.
    • Settings form: every field has a "Use environment" option (sent as null). Saving into enforce asks for confirmation, and key_missing gets its own message.
  • The page explains that the key stays in the environment and how to rotate it.
  • XSS fix: the test console rendered event content (channel data and refusal reasons from the network) with html-safe. It is now escaped text.

Why

Before this, switching socket auth on or changing its mode or origins meant editing env on the API and the socket server and restarting both. This lets an admin roll out log and then enforce from the console and see what would be denied first.

Related

Tests

  • socket/test/: unit tests for the config URL/interval, runtime config, poller (signing, failures, timeout, no overlap) and denials aggregation. Real-server integration tests cover:
    • a poll applies changes;
    • an unreachable API keeps the last good config;
    • no key means no polling;
    • enabling at runtime starts verifying and authorizing;
    • switching to enforce blocks client publish;
    • an origins change applies to new handshakes;
    • /stats denials contain no tokens or ids.
  • console/tests/integration/components/configure/socket-test.js: covers every branch of the page component and the XSS fix.

…ls on /stats

With SOCKETCLUSTER_AUTH_KEY set, the socket server polls the API's signed
GET int/v1/socket/config (SOCKETCLUSTER_CONFIG_URL, default derived from the
authorize URL; SOCKETCLUSTER_CONFIG_POLL_SECONDS, default 30, 0 disables) and
applies enabled, mode, client publish and origins at runtime. The environment
is the starting value and the last good remote config survives an unreachable
API. The key is now passed to SocketCluster whenever present, so switching auth
on needs no restart; entering enforce at runtime disconnects sockets once so
their subscriptions are re-authorized. /stats gains config and aggregated
denials (no tokens or ids). Helm exposes the two new env vars.
Rebuilds Admin > Configure > Socket on the new int/v1/settings/socket
endpoints: socket server status (reachable, effective switch and mode with
their sources, key configured, connections, last config sync, out-of-sync and
sync-error notices), the aggregated denials table, and a settings form where
each field can be left to the environment (null). Saving into enforce asks for
confirmation first; key_missing gets its own message. The key stays
environment-only and the page says how to rotate it.

Fixes an XSS in the test console: event content (channel data and refusal
reasons from the network) was rendered with html-safe and is now escaped.
@codecov

codecov Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (cfcb4f0) to head (7d7536f).
⚠️ Report is 1 commits behind head on release/v0.7.70.

Additional details and impacted files

Impacted file tree graph

@@                 Coverage Diff                 @@
##             release/v0.7.70      #722   +/-   ##
===================================================
  Coverage             100.00%   100.00%           
  Complexity                38        38           
===================================================
  Files                    196       196           
  Lines                   4028      4092   +64     
===================================================
+ Hits                    4028      4092   +64     
Flag Coverage Δ
api 100.00% <ø> (ø)
console 100.00% <100.00%> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
console/app/components/configure/socket.js 100.00% <100.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@roncodes
roncodes merged commit d5c9898 into release/v0.7.70 Oct 15, 2026
6 checks passed
@roncodes
roncodes deleted the feature/socket-admin-settings branch October 15, 2026 08:42
roncodes added a commit that referenced this pull request Oct 16, 2026
* chore(release): v0.7.70

* feat(socket): admin socket settings page and runtime config for the socket server (#722)

* feat(socket): poll the API for runtime socket config and report denials on /stats

With SOCKETCLUSTER_AUTH_KEY set, the socket server polls the API's signed
GET int/v1/socket/config (SOCKETCLUSTER_CONFIG_URL, default derived from the
authorize URL; SOCKETCLUSTER_CONFIG_POLL_SECONDS, default 30, 0 disables) and
applies enabled, mode, client publish and origins at runtime. The environment
is the starting value and the last good remote config survives an unreachable
API. The key is now passed to SocketCluster whenever present, so switching auth
on needs no restart; entering enforce at runtime disconnects sockets once so
their subscriptions are re-authorized. /stats gains config and aggregated
denials (no tokens or ids). Helm exposes the two new env vars.

* feat(console): admin socket settings page

Rebuilds Admin > Configure > Socket on the new int/v1/settings/socket
endpoints: socket server status (reachable, effective switch and mode with
their sources, key configured, connections, last config sync, out-of-sync and
sync-error notices), the aggregated denials table, and a settings form where
each field can be left to the environment (null). Saving into enforce asks for
confirmation first; key_missing gets its own message. The key stays
environment-only and the page says how to rotate it.

Fixes an XSS in the test console: event content (channel data and refusal
reasons from the network) was rendered with html-safe and is now escaped.

* test(console): match prettier wrapping in the socket settings test

* test(console): Toggle renders a disabled state as an empty data-disabled attribute

* docs(release): v0.7.70 notes cover every PR in the release branch

* ci: retrigger the checks that the Actions billing lock refused to start

* release: v0.7.70 upgrades to the published components

core-api 1.6.71, fleetops 0.6.73, storefront 0.4.26 and registry-bridge 0.1.11 in
composer.json, package.json, the lock files, the pnpm release-age exclusions and
the submodule pointers. RELEASE.md already names these versions.

* release: v0.7.70 ships storefront 0.4.27

The storefront hotfix (fleetbase/storefront#159: customer notes reach QPay orders
and lead the order panel; network orders open without reloading the list) replaces
0.4.26 in composer.json, package.json, the lock files, the pnpm release-age
exclusion and the submodule pointer. RELEASE.md covers it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant