mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-07 11:01:24 +00:00
fix(cron): prevent isolated hook session-key double-prefixing (land #27333, @MaheshBhushan)
Co-authored-by: MaheshBhushan <mkoduri73@gmail.com>
This commit is contained in:
@@ -13,6 +13,7 @@ Docs: https://docs.openclaw.ai
|
|||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
|
|
||||||
|
- Cron/Hooks isolated routing: preserve canonical `agent:*` session keys in isolated runs so already-qualified keys are not double-prefixed (for example `agent:main:main` no longer becomes `agent:main:agent:main:main`). Landed from contributor PR #27333 by @MaheshBhushan. (#27289, #27282)
|
||||||
- Security/Plugin channel HTTP auth: normalize protected `/api/channels` path checks against canonicalized request paths (case + percent-decoding + slash normalization), and fail closed on malformed `%`-encoded channel prefixes so alternate-path variants cannot bypass gateway auth.
|
- Security/Plugin channel HTTP auth: normalize protected `/api/channels` path checks against canonicalized request paths (case + percent-decoding + slash normalization), and fail closed on malformed `%`-encoded channel prefixes so alternate-path variants cannot bypass gateway auth.
|
||||||
- Security/Exec approvals forwarding: prefer turn-source channel/account/thread metadata when resolving approval delivery targets so stale session routes do not misroute approval prompts.
|
- Security/Exec approvals forwarding: prefer turn-source channel/account/thread metadata when resolving approval delivery targets so stale session routes do not misroute approval prompts.
|
||||||
- Onboarding/Gateway: seed default Control UI `allowedOrigins` for non-loopback binds during onboarding (`localhost`/`127.0.0.1` plus custom bind host) so fresh non-loopback setups do not fail startup due to missing origin policy. (#26157) thanks @stakeswky.
|
- Onboarding/Gateway: seed default Control UI `allowedOrigins` for non-loopback binds during onboarding (`localhost`/`127.0.0.1` plus custom bind host) so fresh non-loopback setups do not fail startup due to missing origin policy. (#26157) thanks @stakeswky.
|
||||||
|
|||||||
28
src/cron/isolated-agent/run.session-key.test.ts
Normal file
28
src/cron/isolated-agent/run.session-key.test.ts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
import { resolveCronAgentSessionKey } from "./run.js";
|
||||||
|
|
||||||
|
describe("resolveCronAgentSessionKey", () => {
|
||||||
|
it("builds an agent-scoped key for legacy aliases", () => {
|
||||||
|
expect(resolveCronAgentSessionKey({ sessionKey: "main", agentId: "main" })).toBe(
|
||||||
|
"agent:main:main",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("preserves canonical agent keys instead of prefixing twice", () => {
|
||||||
|
expect(resolveCronAgentSessionKey({ sessionKey: "agent:main:main", agentId: "main" })).toBe(
|
||||||
|
"agent:main:main",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("normalizes canonical keys to lowercase before reuse", () => {
|
||||||
|
expect(
|
||||||
|
resolveCronAgentSessionKey({ sessionKey: "AGENT:Main:Hook:Webhook:42", agentId: "x" }),
|
||||||
|
).toBe("agent:main:hook:webhook:42");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("keeps hook keys scoped under the target agent", () => {
|
||||||
|
expect(resolveCronAgentSessionKey({ sessionKey: "hook:webhook:42", agentId: "main" })).toBe(
|
||||||
|
"agent:main:hook:webhook:42",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -40,7 +40,11 @@ import {
|
|||||||
import type { AgentDefaultsConfig } from "../../config/types.js";
|
import type { AgentDefaultsConfig } from "../../config/types.js";
|
||||||
import { registerAgentRunContext } from "../../infra/agent-events.js";
|
import { registerAgentRunContext } from "../../infra/agent-events.js";
|
||||||
import { logWarn } from "../../logger.js";
|
import { logWarn } from "../../logger.js";
|
||||||
import { buildAgentMainSessionKey, normalizeAgentId } from "../../routing/session-key.js";
|
import {
|
||||||
|
buildAgentMainSessionKey,
|
||||||
|
normalizeAgentId,
|
||||||
|
parseAgentSessionKey,
|
||||||
|
} from "../../routing/session-key.js";
|
||||||
import {
|
import {
|
||||||
buildSafeExternalPrompt,
|
buildSafeExternalPrompt,
|
||||||
detectSuspiciousPatterns,
|
detectSuspiciousPatterns,
|
||||||
@@ -142,10 +146,7 @@ export async function runCronIsolatedAgentTurn(params: {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const baseSessionKey = (params.sessionKey?.trim() || `cron:${params.job.id}`).trim();
|
const baseSessionKey = (params.sessionKey?.trim() || `cron:${params.job.id}`).trim();
|
||||||
const agentSessionKey = buildAgentMainSessionKey({
|
const agentSessionKey = resolveCronAgentSessionKey({ sessionKey: baseSessionKey, agentId });
|
||||||
agentId,
|
|
||||||
mainKey: baseSessionKey,
|
|
||||||
});
|
|
||||||
|
|
||||||
const workspaceDirRaw = resolveAgentWorkspaceDir(params.cfg, agentId);
|
const workspaceDirRaw = resolveAgentWorkspaceDir(params.cfg, agentId);
|
||||||
const agentDir = resolveAgentDir(params.cfg, agentId);
|
const agentDir = resolveAgentDir(params.cfg, agentId);
|
||||||
@@ -646,3 +647,18 @@ export async function runCronIsolatedAgentTurn(params: {
|
|||||||
|
|
||||||
return resolveRunOutcome({ delivered, deliveryAttempted });
|
return resolveRunOutcome({ delivered, deliveryAttempted });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function resolveCronAgentSessionKey(params: {
|
||||||
|
sessionKey: string;
|
||||||
|
agentId: string;
|
||||||
|
}): string {
|
||||||
|
const baseSessionKey = params.sessionKey.trim();
|
||||||
|
const normalizedBaseSessionKey = baseSessionKey.toLowerCase();
|
||||||
|
if (parseAgentSessionKey(normalizedBaseSessionKey)) {
|
||||||
|
return normalizedBaseSessionKey;
|
||||||
|
}
|
||||||
|
return buildAgentMainSessionKey({
|
||||||
|
agentId: params.agentId,
|
||||||
|
mainKey: baseSessionKey,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user