fix(gateway): land #28428 from @l0cka
Landed from contributor PR #28428 by @l0cka. Co-authored-by: Daniel Alkurdi <danielalkurdi@gmail.com>
This commit is contained in:
@@ -78,12 +78,15 @@ describe("auditGatewayServiceConfig", () => {
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(
|
||||
audit.issues.some((issue) => issue.code === SERVICE_AUDIT_CODES.gatewayTokenEmbedded),
|
||||
).toBe(true);
|
||||
expect(
|
||||
audit.issues.some((issue) => issue.code === SERVICE_AUDIT_CODES.gatewayTokenMismatch),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("does not flag gateway token mismatch when service token matches config token", async () => {
|
||||
it("flags embedded service token even when it matches config token", async () => {
|
||||
const audit = await auditGatewayServiceConfig({
|
||||
env: { HOME: "/tmp" },
|
||||
platform: "linux",
|
||||
@@ -96,6 +99,29 @@ describe("auditGatewayServiceConfig", () => {
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(
|
||||
audit.issues.some((issue) => issue.code === SERVICE_AUDIT_CODES.gatewayTokenEmbedded),
|
||||
).toBe(true);
|
||||
expect(
|
||||
audit.issues.some((issue) => issue.code === SERVICE_AUDIT_CODES.gatewayTokenMismatch),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it("does not flag token issues when service token is not embedded", async () => {
|
||||
const audit = await auditGatewayServiceConfig({
|
||||
env: { HOME: "/tmp" },
|
||||
platform: "linux",
|
||||
expectedGatewayToken: "new-token",
|
||||
command: {
|
||||
programArguments: ["/usr/bin/node", "gateway"],
|
||||
environment: {
|
||||
PATH: "/usr/local/bin:/usr/bin:/bin",
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(
|
||||
audit.issues.some((issue) => issue.code === SERVICE_AUDIT_CODES.gatewayTokenEmbedded),
|
||||
).toBe(false);
|
||||
expect(
|
||||
audit.issues.some((issue) => issue.code === SERVICE_AUDIT_CODES.gatewayTokenMismatch),
|
||||
).toBe(false);
|
||||
@@ -143,10 +169,9 @@ describe("checkTokenDrift", () => {
|
||||
expect(result?.message).toContain("differs from service token");
|
||||
});
|
||||
|
||||
it("detects drift when config has token but service has no token", () => {
|
||||
it("returns null when config has token but service has no token", () => {
|
||||
const result = checkTokenDrift({ serviceToken: undefined, configToken: "new-token" });
|
||||
expect(result).not.toBeNull();
|
||||
expect(result?.code).toBe(SERVICE_AUDIT_CODES.gatewayTokenDrift);
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
|
||||
it("returns null when service has token but config does not", () => {
|
||||
|
||||
@@ -35,6 +35,7 @@ export const SERVICE_AUDIT_CODES = {
|
||||
gatewayPathMissing: "gateway-path-missing",
|
||||
gatewayPathMissingDirs: "gateway-path-missing-dirs",
|
||||
gatewayPathNonMinimal: "gateway-path-nonminimal",
|
||||
gatewayTokenEmbedded: "gateway-token-embedded",
|
||||
gatewayTokenMismatch: "gateway-token-mismatch",
|
||||
gatewayRuntimeBun: "gateway-runtime-bun",
|
||||
gatewayRuntimeNodeVersionManager: "gateway-runtime-node-version-manager",
|
||||
@@ -208,19 +209,25 @@ function auditGatewayToken(
|
||||
issues: ServiceConfigIssue[],
|
||||
expectedGatewayToken?: string,
|
||||
) {
|
||||
const expectedToken = expectedGatewayToken?.trim();
|
||||
if (!expectedToken) {
|
||||
const serviceToken = command?.environment?.OPENCLAW_GATEWAY_TOKEN?.trim();
|
||||
if (!serviceToken) {
|
||||
return;
|
||||
}
|
||||
const serviceToken = command?.environment?.OPENCLAW_GATEWAY_TOKEN?.trim();
|
||||
if (serviceToken === expectedToken) {
|
||||
issues.push({
|
||||
code: SERVICE_AUDIT_CODES.gatewayTokenEmbedded,
|
||||
message: "Gateway service embeds OPENCLAW_GATEWAY_TOKEN and should be reinstalled.",
|
||||
detail: "Run `openclaw gateway install --force` to remove embedded service token.",
|
||||
level: "recommended",
|
||||
});
|
||||
const expectedToken = expectedGatewayToken?.trim();
|
||||
if (!expectedToken || serviceToken === expectedToken) {
|
||||
return;
|
||||
}
|
||||
issues.push({
|
||||
code: SERVICE_AUDIT_CODES.gatewayTokenMismatch,
|
||||
message:
|
||||
"Gateway service OPENCLAW_GATEWAY_TOKEN does not match gateway.auth.token in openclaw.json",
|
||||
detail: serviceToken ? "service token is stale" : "service token is missing",
|
||||
detail: "service token is stale",
|
||||
level: "recommended",
|
||||
});
|
||||
}
|
||||
@@ -360,21 +367,15 @@ export function checkTokenDrift(params: {
|
||||
serviceToken: string | undefined;
|
||||
configToken: string | undefined;
|
||||
}): ServiceConfigIssue | null {
|
||||
const { serviceToken, configToken } = params;
|
||||
const serviceToken = params.serviceToken?.trim() || undefined;
|
||||
const configToken = params.configToken?.trim() || undefined;
|
||||
|
||||
// Normalise both tokens before comparing: service-file parsers (systemd,
|
||||
// launchd) can return values with trailing newlines or whitespace that
|
||||
// cause a false-positive mismatch against the config value.
|
||||
const normService = serviceToken?.trim() || undefined;
|
||||
const normConfig = configToken?.trim() || undefined;
|
||||
|
||||
// No drift if both are undefined/empty
|
||||
if (!normService && !normConfig) {
|
||||
// Tokenless service units are canonical; no drift to report.
|
||||
if (!serviceToken) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Drift: config has token, service has different or no token
|
||||
if (normConfig && normService !== normConfig) {
|
||||
if (configToken && serviceToken !== configToken) {
|
||||
return {
|
||||
code: SERVICE_AUDIT_CODES.gatewayTokenDrift,
|
||||
message:
|
||||
|
||||
@@ -264,7 +264,6 @@ describe("buildServiceEnvironment", () => {
|
||||
const env = buildServiceEnvironment({
|
||||
env: { HOME: "/home/user" },
|
||||
port: 18789,
|
||||
token: "secret",
|
||||
});
|
||||
expect(env.HOME).toBe("/home/user");
|
||||
if (process.platform === "win32") {
|
||||
@@ -273,7 +272,7 @@ describe("buildServiceEnvironment", () => {
|
||||
expect(env.PATH).toContain("/usr/bin");
|
||||
}
|
||||
expect(env.OPENCLAW_GATEWAY_PORT).toBe("18789");
|
||||
expect(env.OPENCLAW_GATEWAY_TOKEN).toBe("secret");
|
||||
expect(env.OPENCLAW_GATEWAY_TOKEN).toBeUndefined();
|
||||
expect(env.OPENCLAW_SERVICE_MARKER).toBe("openclaw");
|
||||
expect(env.OPENCLAW_SERVICE_KIND).toBe("gateway");
|
||||
expect(typeof env.OPENCLAW_SERVICE_VERSION).toBe("string");
|
||||
|
||||
@@ -245,11 +245,10 @@ export function buildMinimalServicePath(options: BuildServicePathOptions = {}):
|
||||
export function buildServiceEnvironment(params: {
|
||||
env: Record<string, string | undefined>;
|
||||
port: number;
|
||||
token?: string;
|
||||
launchdLabel?: string;
|
||||
platform?: NodeJS.Platform;
|
||||
}): Record<string, string | undefined> {
|
||||
const { env, port, token, launchdLabel } = params;
|
||||
const { env, port, launchdLabel } = params;
|
||||
const platform = params.platform ?? process.platform;
|
||||
const sharedEnv = resolveSharedServiceEnvironmentFields(env, platform);
|
||||
const profile = env.OPENCLAW_PROFILE;
|
||||
@@ -260,7 +259,6 @@ export function buildServiceEnvironment(params: {
|
||||
...buildCommonServiceEnvironment(env, sharedEnv),
|
||||
OPENCLAW_PROFILE: profile,
|
||||
OPENCLAW_GATEWAY_PORT: String(port),
|
||||
OPENCLAW_GATEWAY_TOKEN: token,
|
||||
OPENCLAW_LAUNCHD_LABEL: resolvedLaunchdLabel,
|
||||
OPENCLAW_SYSTEMD_UNIT: systemdUnit,
|
||||
OPENCLAW_WINDOWS_TASK_NAME: resolveGatewayWindowsTaskName(profile),
|
||||
|
||||
Reference in New Issue
Block a user