mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-07-26 11:49:16 +00:00
fix(console): send proxy tier headers for remote node console-token requests (#424)
The gateway's console-token fetch to remote nodes was missing the x-sencho-tier and x-sencho-variant headers. Without them, the remote's requireAdmiral guard fell back to its own local license (Community), rejecting the request with 403 and surfacing as a 502 "Connection error" in the browser. Additionally, the remote's WS upgrade handler for host-console checked only the local LicenseService instead of respecting proxy tier headers on console_session tokens. Both paths now propagate and honour proxy tier headers consistently.
This commit is contained in:
@@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
### Fixed
|
||||
|
||||
* **console:** fix remote node Host Console failing with "Connection error" / 502. The gateway's console-token request to the remote node was missing license tier headers, causing the remote's Admiral license gate to reject the request. Both the HTTP fetch and the WS upgrade handler now correctly propagate proxy tier headers for console_session tokens.
|
||||
* **auto-update:** resolve failure when executing auto-update policies on remote Distributed API nodes. Previously, the scheduler tried to access the remote Docker daemon directly, which is not supported. Now the update execution is proxied to the remote Sencho instance via HTTP, matching the existing Distributed API architecture.
|
||||
* **schedules:** auto-update policies no longer appear in the Scheduled Operations list. Each view now fetches only its relevant task type via server-side action filtering.
|
||||
|
||||
|
||||
+19
-3
@@ -2690,9 +2690,14 @@ server.on('upgrade', async (req, socket, head) => {
|
||||
let bearerTokenForProxy = node.api_token;
|
||||
if (isInteractiveConsolePath) {
|
||||
try {
|
||||
const ls = LicenseService.getInstance();
|
||||
const tokenRes = await fetch(`${node.api_url.replace(/\/$/, '')}/api/system/console-token`, {
|
||||
method: 'POST',
|
||||
headers: { 'Authorization': `Bearer ${node.api_token}` },
|
||||
headers: {
|
||||
'Authorization': `Bearer ${node.api_token}`,
|
||||
[PROXY_TIER_HEADER]: ls.getTier(),
|
||||
[PROXY_VARIANT_HEADER]: ls.getVariant() || '',
|
||||
},
|
||||
});
|
||||
if (tokenRes.ok) {
|
||||
const data = await tokenRes.json() as { token?: string };
|
||||
@@ -2759,9 +2764,20 @@ server.on('upgrade', async (req, socket, head) => {
|
||||
socket.destroy();
|
||||
return;
|
||||
}
|
||||
// Admiral license gate: host console requires Admiral (paid + team variant)
|
||||
// Admiral license gate: host console requires Admiral (paid + team variant).
|
||||
// For proxied connections (console_session tokens), trust the tier headers sent by the gateway;
|
||||
// for direct connections, check the local LicenseService.
|
||||
const isConsoleSession = decoded.scope === 'console_session';
|
||||
const consoleTierHeader = req.headers[PROXY_TIER_HEADER] as string | undefined;
|
||||
const consoleVariantHeader = req.headers[PROXY_VARIANT_HEADER] as string | undefined;
|
||||
const ls = LicenseService.getInstance();
|
||||
if (ls.getTier() !== 'paid' || ls.getVariant() !== 'admiral') {
|
||||
const consoleTier = (isConsoleSession && isLicenseTier(consoleTierHeader))
|
||||
? normalizeTier(consoleTierHeader)
|
||||
: ls.getTier();
|
||||
const consoleVariant = (isConsoleSession && consoleVariantHeader !== undefined && isLicenseVariant(consoleVariantHeader))
|
||||
? normalizeVariant(consoleVariantHeader)
|
||||
: ls.getVariant();
|
||||
if (consoleTier !== 'paid' || consoleVariant !== 'admiral') {
|
||||
socket.write('HTTP/1.1 403 Forbidden\r\n\r\n');
|
||||
socket.destroy();
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user