mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-05 01:20:21 +00:00
Fix/telegram writeback admin scope gate (#54561)
* fix(telegram): require operator.admin for legacy target writeback persistence * Address claude feedback * Update extensions/telegram/src/target-writeback.ts Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Remove stray brace * Add updated docs * Add missing test file, address codex concerns * Fix test formatting error * Address comments, fix tests --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
This commit is contained in:
@@ -130,6 +130,7 @@ type ChannelHandlerParams = {
|
||||
forceDocument?: boolean;
|
||||
silent?: boolean;
|
||||
mediaLocalRoots?: readonly string[];
|
||||
gatewayClientScopes?: readonly string[];
|
||||
};
|
||||
|
||||
// Channel docking: outbound delivery delegates to plugin.outbound adapters.
|
||||
@@ -250,6 +251,7 @@ function createChannelOutboundContextBase(
|
||||
deps: params.deps,
|
||||
silent: params.silent,
|
||||
mediaLocalRoots: params.mediaLocalRoots,
|
||||
gatewayClientScopes: params.gatewayClientScopes,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -275,6 +277,7 @@ type DeliverOutboundPayloadsCoreParams = {
|
||||
session?: OutboundSessionContext;
|
||||
mirror?: DeliveryMirror;
|
||||
silent?: boolean;
|
||||
gatewayClientScopes?: readonly string[];
|
||||
};
|
||||
|
||||
function collectPayloadMediaSources(payloads: ReplyPayload[]): string[] {
|
||||
@@ -508,6 +511,7 @@ export async function deliverOutboundPayloads(
|
||||
forceDocument: params.forceDocument,
|
||||
silent: params.silent,
|
||||
mirror: params.mirror,
|
||||
gatewayClientScopes: params.gatewayClientScopes,
|
||||
}).catch(() => null); // Best-effort — don't block delivery if queue write fails.
|
||||
|
||||
// Wrap onError to detect partial failures under bestEffort mode.
|
||||
@@ -576,6 +580,7 @@ async function deliverOutboundPayloadsCore(
|
||||
forceDocument: params.forceDocument,
|
||||
silent: params.silent,
|
||||
mediaLocalRoots,
|
||||
gatewayClientScopes: params.gatewayClientScopes,
|
||||
});
|
||||
const configuredTextLimit = handler.chunker
|
||||
? resolveTextChunkLimit(cfg, channel, accountId, {
|
||||
|
||||
@@ -75,6 +75,7 @@ function buildRecoveryDeliverParams(entry: QueuedDelivery, cfg: OpenClawConfig)
|
||||
forceDocument: entry.forceDocument,
|
||||
silent: entry.silent,
|
||||
mirror: entry.mirror,
|
||||
gatewayClientScopes: entry.gatewayClientScopes,
|
||||
skipQueue: true, // Prevent re-enqueueing during recovery.
|
||||
} satisfies Parameters<DeliverFn>[0];
|
||||
}
|
||||
|
||||
@@ -26,6 +26,8 @@ export type QueuedDeliveryPayload = {
|
||||
forceDocument?: boolean;
|
||||
silent?: boolean;
|
||||
mirror?: OutboundMirror;
|
||||
/** Gateway caller scopes at enqueue time, preserved for recovery replay. */
|
||||
gatewayClientScopes?: readonly string[];
|
||||
};
|
||||
|
||||
export interface QueuedDelivery extends QueuedDeliveryPayload {
|
||||
@@ -142,6 +144,7 @@ export async function enqueueDelivery(
|
||||
forceDocument: params.forceDocument,
|
||||
silent: params.silent,
|
||||
mirror: params.mirror,
|
||||
gatewayClientScopes: params.gatewayClientScopes,
|
||||
retryCount: 0,
|
||||
});
|
||||
return id;
|
||||
|
||||
@@ -125,6 +125,7 @@ describe("delivery-queue recovery", () => {
|
||||
bestEffort: true,
|
||||
gifPlayback: true,
|
||||
silent: true,
|
||||
gatewayClientScopes: ["operator.write"],
|
||||
mirror: {
|
||||
sessionKey: "agent:main:main",
|
||||
text: "a",
|
||||
@@ -142,6 +143,7 @@ describe("delivery-queue recovery", () => {
|
||||
bestEffort: true,
|
||||
gifPlayback: true,
|
||||
silent: true,
|
||||
gatewayClientScopes: ["operator.write"],
|
||||
mirror: {
|
||||
sessionKey: "agent:main:main",
|
||||
text: "a",
|
||||
|
||||
@@ -23,6 +23,7 @@ describe("delivery-queue storage", () => {
|
||||
bestEffort: true,
|
||||
gifPlayback: true,
|
||||
silent: true,
|
||||
gatewayClientScopes: ["operator.write"],
|
||||
mirror: {
|
||||
sessionKey: "agent:main:main",
|
||||
text: "hello",
|
||||
@@ -45,6 +46,7 @@ describe("delivery-queue storage", () => {
|
||||
bestEffort: true,
|
||||
gifPlayback: true,
|
||||
silent: true,
|
||||
gatewayClientScopes: ["operator.write"],
|
||||
mirror: {
|
||||
sessionKey: "agent:main:main",
|
||||
text: "hello",
|
||||
@@ -157,6 +159,21 @@ describe("delivery-queue storage", () => {
|
||||
expect(await loadPendingDeliveries(tmpDir())).toHaveLength(2);
|
||||
});
|
||||
|
||||
it("persists gateway caller scopes for replay", async () => {
|
||||
const id = await enqueueDelivery(
|
||||
{
|
||||
channel: "telegram",
|
||||
to: "2",
|
||||
payloads: [{ text: "b" }],
|
||||
gatewayClientScopes: ["operator.write"],
|
||||
},
|
||||
tmpDir(),
|
||||
);
|
||||
|
||||
const entry = readQueuedEntry(tmpDir(), id);
|
||||
expect(entry.gatewayClientScopes).toEqual(["operator.write"]);
|
||||
});
|
||||
|
||||
it("backfills lastAttemptAt for legacy retry entries during load", async () => {
|
||||
const id = await enqueueDelivery(
|
||||
{ channel: "whatsapp", to: "+1", payloads: [{ text: "legacy" }] },
|
||||
|
||||
Reference in New Issue
Block a user