
























@@ -12,8 +12,16 @@ describe("sanitizeSystemRunParamsForForwarding", () => {
1212connId: "conn-1",
1313connect: {
1414scopes: ["operator.write", "operator.approvals"],
15+client: { id: "cli-1", mode: "cli" },
1516device: { id: "dev-1" },
16-client: { id: "cli-1" },
17+},
18+};
19+const trustedBackendClient = {
20+connId: "backend-conn",
21+connect: {
22+scopes: ["operator.write", "operator.approvals"],
23+client: { id: "gateway-client", mode: "backend" },
24+device: null,
1725},
1826};
1927@@ -45,6 +53,7 @@ describe("sanitizeSystemRunParamsForForwarding", () => {
4553requestedByConnId: "conn-1",
4654requestedByDeviceId: "dev-1",
4755requestedByClientId: "cli-1",
56+requestedByDeviceTokenAuth: false,
4857resolvedAtMs: now - 500,
4958decision: "allow-once",
5059resolvedBy: "operator",
@@ -361,6 +370,7 @@ describe("sanitizeSystemRunParamsForForwarding", () => {
361370record.requestedByConnId = "conn-1";
362371record.requestedByDeviceId = "dev-1";
363372record.requestedByClientId = "cli-1";
373+record.requestedByDeviceTokenAuth = false;
364374365375const decisionPromise = approvalManager.register(record, 60_000);
366376approvalManager.resolve(runId, "allow-once", "operator");
@@ -426,4 +436,113 @@ describe("sanitizeSystemRunParamsForForwarding", () => {
426436});
427437expectRejectedForwardingResult(result, "APPROVAL_NODE_MISMATCH", "not valid for this node");
428438});
439+440+test("accepts trusted backend replay for no-device approval after the request connection changes", () => {
441+const record = makeRecord("echo SAFE", ["echo", "SAFE"]);
442+record.requestedByConnId = "control-ui-conn";
443+record.requestedByDeviceId = null;
444+record.requestedByClientId = "openclaw-control-ui";
445+record.requestedByDeviceTokenAuth = false;
446+447+const result = sanitizeSystemRunParamsForForwarding({
448+rawParams: {
449+command: ["echo", "SAFE"],
450+rawCommand: "echo SAFE",
451+runId: "approval-1",
452+approved: true,
453+approvalDecision: "allow-once",
454+},
455+nodeId: "node-1",
456+client: trustedBackendClient,
457+execApprovalManager: manager(record),
458+nowMs: now,
459+});
460+461+expectAllowOnceForwardingResult(result);
462+});
463+464+test("rejects no-device approval replay from a backend client without approval scope", () => {
465+const record = makeRecord("echo SAFE", ["echo", "SAFE"]);
466+record.requestedByConnId = "control-ui-conn";
467+record.requestedByDeviceId = null;
468+record.requestedByClientId = "openclaw-control-ui";
469+record.requestedByDeviceTokenAuth = false;
470+471+const result = sanitizeSystemRunParamsForForwarding({
472+rawParams: {
473+command: ["echo", "SAFE"],
474+rawCommand: "echo SAFE",
475+runId: "approval-1",
476+approved: true,
477+approvalDecision: "allow-once",
478+},
479+nodeId: "node-1",
480+client: {
481+ ...trustedBackendClient,
482+connect: {
483+ ...trustedBackendClient.connect,
484+scopes: ["operator.write"],
485+},
486+},
487+execApprovalManager: manager(record),
488+nowMs: now,
489+});
490+491+expectRejectedForwardingResult(result, "APPROVAL_CLIENT_MISMATCH", "not valid for this client");
492+});
493+494+test("rejects no-device approval replay from a non-backend client on a different connection", () => {
495+const record = makeRecord("echo SAFE", ["echo", "SAFE"]);
496+record.requestedByConnId = "control-ui-conn";
497+record.requestedByDeviceId = null;
498+record.requestedByClientId = "openclaw-control-ui";
499+record.requestedByDeviceTokenAuth = false;
500+501+const result = sanitizeSystemRunParamsForForwarding({
502+rawParams: {
503+command: ["echo", "SAFE"],
504+rawCommand: "echo SAFE",
505+runId: "approval-1",
506+approved: true,
507+approvalDecision: "allow-once",
508+},
509+nodeId: "node-1",
510+client: {
511+connId: "other-control-ui-conn",
512+connect: {
513+scopes: ["operator.write", "operator.approvals"],
514+client: { id: "openclaw-control-ui", mode: "ui" },
515+device: null,
516+},
517+},
518+execApprovalManager: manager(record),
519+nowMs: now,
520+});
521+522+expectRejectedForwardingResult(result, "APPROVAL_CLIENT_MISMATCH", "not valid for this client");
523+});
524+525+test("rejects no-device approval replay when the original request used device-token auth", () => {
526+const record = makeRecord("echo SAFE", ["echo", "SAFE"]);
527+record.requestedByConnId = "control-ui-conn";
528+record.requestedByDeviceId = null;
529+record.requestedByClientId = "openclaw-control-ui";
530+record.requestedByDeviceTokenAuth = true;
531+532+const result = sanitizeSystemRunParamsForForwarding({
533+rawParams: {
534+command: ["echo", "SAFE"],
535+rawCommand: "echo SAFE",
536+runId: "approval-1",
537+approved: true,
538+approvalDecision: "allow-once",
539+},
540+nodeId: "node-1",
541+client: trustedBackendClient,
542+execApprovalManager: manager(record),
543+nowMs: now,
544+});
545+546+expectRejectedForwardingResult(result, "APPROVAL_CLIENT_MISMATCH", "not valid for this client");
547+});
429548});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。