fix(qqbot): preserve framework command authorization (#77453)

* fix(qqbot): preserve framework command authorization

* Add changelog entry for PR #77453
This commit is contained in:
Devin Robison
2026-05-04 12:38:51 -06:00
committed by GitHub
parent dff437a1cb
commit edddb07f20
3 changed files with 57 additions and 1 deletions

View File

@@ -207,6 +207,7 @@ Docs: https://docs.openclaw.ai
- TUI: replace the stale-response watchdog notice with plain user-facing copy so stalled replies no longer surface backend or streaming internals. (#77120) Thanks @davemorin.
- Security/Windows: validate `SystemRoot`/`WINDIR` env values through the Windows install-root validator and add them to the dangerous-host-env policy when resolving `icacls.exe`/`whoami.exe` for `openclaw security audit`, so workspace `.env` overrides and bare command names cannot redirect Windows ACL helpers to attacker-controlled binaries. (#74458) Thanks @mmaps.
- Security/Windows: pin Windows registry-probe `reg.exe` resolution to the canonical Windows install root in install-root probing, so `SystemRoot`/`WINDIR` env overrides cannot redirect registry queries during Windows host detection. (#74454) Thanks @mmaps.
- QQBot: preserve the framework command authorization decision when converting framework command contexts into engine slash command contexts, so downstream slash handlers see `commandAuthorized` matching the channel's resolved `isAuthorizedSender` instead of a hardcoded `true`. (#77453) Thanks @drobison00.
## 2026.5.3-1

View File

@@ -0,0 +1,55 @@
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-types";
import type { PluginCommandContext } from "openclaw/plugin-sdk/plugin-entry";
import { describe, expect, it } from "vitest";
import { buildFrameworkSlashContext } from "./framework-context-adapter.js";
function createCommandContext(isAuthorizedSender: boolean): PluginCommandContext {
return {
senderId: "SENDER_OPENID",
channel: "qqbot",
isAuthorizedSender,
args: "on",
commandBody: "/bot-streaming on",
config: {} as OpenClawConfig,
from: "qqbot:c2c:SENDER_OPENID",
requestConversationBinding: async () => undefined,
detachConversationBinding: async () => ({ removed: false }),
getCurrentConversationBinding: async () => null,
} as unknown as PluginCommandContext;
}
describe("buildFrameworkSlashContext", () => {
it("preserves the framework authorization decision in the slash context", () => {
const authorized = buildFrameworkSlashContext({
ctx: createCommandContext(true),
account: {
accountId: "default",
enabled: true,
appId: "app",
clientSecret: "secret",
secretSource: "config",
markdownSupport: true,
config: {},
},
from: { msgType: "c2c", targetType: "c2c", targetId: "SENDER_OPENID" },
commandName: "bot-streaming",
});
const unauthorized = buildFrameworkSlashContext({
ctx: createCommandContext(false),
account: {
accountId: "default",
enabled: true,
appId: "app",
clientSecret: "secret",
secretSource: "config",
markdownSupport: true,
config: {},
},
from: { msgType: "c2c", targetType: "c2c", targetId: "SENDER_OPENID" },
commandName: "bot-streaming",
});
expect(authorized.commandAuthorized).toBe(true);
expect(unauthorized.commandAuthorized).toBe(false);
});
});

View File

@@ -54,7 +54,7 @@ export function buildFrameworkSlashContext({
accountId: account.accountId,
appId: account.appId,
accountConfig: account.config as unknown as Record<string, unknown>,
commandAuthorized: true,
commandAuthorized: ctx.isAuthorizedSender,
queueSnapshot: { ...DEFAULT_QUEUE_SNAPSHOT },
};
}