
























@@ -789,33 +789,76 @@ describe("session history HTTP endpoints", () => {
789789});
790790expect(wsHistory.ok).toBe(false);
791791expect(wsHistory.error?.message).toBe("missing scope: operator.read");
792+} finally {
793+ws.close();
794+await server.close();
795+envSnapshot.restore();
796+}
797+});
792798799+test("allows HTTP session history reads with shared-secret bearer auth and default scopes", async () => {
800+await seedSession({ text: "bearer allowed history" });
801+802+const started = await startServerWithClient("test-gateway-token-1234567890");
803+const { server, ws, port, envSnapshot } = started;
804+try {
793805const httpHistory = await fetch(
794806`http://127.0.0.1:${port}/sessions/${encodeURIComponent("agent:main:main")}/history?limit=1`,
807+{
808+headers: AUTH_HEADER,
809+},
810+);
811+expect(httpHistory.status).toBe(200);
812+const body = await httpHistory.json();
813+expect(body.sessionKey).toBe("agent:main:main");
814+expect(body.messages?.[0]?.content?.[0]?.text).toBe("bearer allowed history");
815+} finally {
816+ws.close();
817+await server.close();
818+envSnapshot.restore();
819+}
820+});
821+822+test("maintains HTTP SSE streams with shared-secret bearer auth across transcript updates", async () => {
823+const { storePath } = await seedSession({ text: "bearer allowed history" });
824+825+const started = await startServerWithClient("test-gateway-token-1234567890");
826+const { server, ws, port, envSnapshot } = started;
827+try {
828+const res = await fetch(
829+`http://127.0.0.1:${port}/sessions/${encodeURIComponent("agent:main:main")}/history`,
795830{
796831headers: {
797832 ...AUTH_HEADER,
798-"x-openclaw-scopes": "operator.approvals",
833+Accept: "text/event-stream",
799834},
800835},
801836);
802-expect(httpHistory.status).toBe(403);
803-expectErrorResponse(await httpHistory.json(), {
804-type: "forbidden",
805-message: "missing scope: operator.read",
837+expect(res.status).toBe(200);
838+const reader = res.body?.getReader();
839+expect(reader).toBeDefined();
840+const stream = { reader: reader!, streamState: { buffer: "" } };
841+842+await expectHistoryEventTexts(stream, ["bearer allowed history"]);
843+844+const appended = await appendAssistantMessageToSessionTranscript({
845+sessionKey: "agent:main:main",
846+text: "bearer sse update",
847+ storePath,
806848});
849+expect(appended.ok).toBe(true);
807850808-const httpHistoryWithoutScopes = await fetch(
809-`http://127.0.0.1:${port}/sessions/${encodeURIComponent("agent:main:main")}/history?limit=1`,
810-{
811-headers: AUTH_HEADER,
812-},
813-);
814-expect(httpHistoryWithoutScopes.status).toBe(403);
815-expectErrorResponse(await httpHistoryWithoutScopes.json(), {
816-type: "forbidden",
817-message: "missing scope: operator.read",
851+if (!appended.ok) {
852+throw new Error(`append failed: ${appended.reason}`);
853+}
854+855+await expectMessageEventMatch(stream, {
856+text: "bearer sse update",
857+seq: 2,
858+id: appended.messageId,
818859});
860+861+await stream.reader.cancel();
819862} finally {
820863ws.close();
821864await server.close();
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。