mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-26 20:09:32 +00:00
fix(qa): measure chunked credential payload bytes
This commit is contained in:
@@ -165,6 +165,45 @@ describe("credential lease runtime", () => {
|
||||
expect(chunkRequest.leaseToken).toBe("lease-chunked");
|
||||
});
|
||||
|
||||
it("validates chunked convex payload length as utf8 bytes", async () => {
|
||||
const serialized = JSON.stringify({
|
||||
groupId: "-100123",
|
||||
driverToken: "driv\u00e9r",
|
||||
sutToken: "sut",
|
||||
});
|
||||
const fetchImpl = vi
|
||||
.fn<typeof fetch>()
|
||||
.mockResolvedValueOnce(
|
||||
jsonResponse({
|
||||
status: "ok",
|
||||
credentialId: "cred-utf8",
|
||||
leaseToken: "lease-utf8",
|
||||
payload: {
|
||||
__openclawQaCredentialPayloadChunksV1: true,
|
||||
byteLength: Buffer.byteLength(serialized, "utf8"),
|
||||
chunkCount: 1,
|
||||
},
|
||||
}),
|
||||
)
|
||||
.mockResolvedValueOnce(jsonResponse({ status: "ok", data: serialized }));
|
||||
|
||||
const lease = await acquireQaCredentialLease({
|
||||
kind: "telegram",
|
||||
source: "convex",
|
||||
role: "ci",
|
||||
env: {
|
||||
OPENCLAW_QA_CONVEX_SITE_URL: "https://qa-cred.example.convex.site",
|
||||
OPENCLAW_QA_CONVEX_SECRET_CI: "ci-secret",
|
||||
},
|
||||
fetchImpl,
|
||||
resolveEnvPayload: () => ({ groupId: "-1", driverToken: "unused", sutToken: "unused" }),
|
||||
parsePayload: (payload) =>
|
||||
payload as { groupId: string; driverToken: string; sutToken: string },
|
||||
});
|
||||
|
||||
expect(lease.payload.driverToken).toBe("driv\u00e9r");
|
||||
});
|
||||
|
||||
it("defaults convex credential role to maintainer outside CI", async () => {
|
||||
const fetchImpl = vi.fn<typeof fetch>().mockResolvedValueOnce(
|
||||
jsonResponse({
|
||||
|
||||
@@ -328,7 +328,7 @@ async function resolveConvexCredentialPayload(params: {
|
||||
chunks.push(parsed.data);
|
||||
}
|
||||
const serialized = chunks.join("");
|
||||
if (serialized.length !== marker.byteLength) {
|
||||
if (Buffer.byteLength(serialized, "utf8") !== marker.byteLength) {
|
||||
throw new Error("Chunked credential payload length mismatch.");
|
||||
}
|
||||
return JSON.parse(serialized) as unknown;
|
||||
|
||||
@@ -324,7 +324,7 @@ async function hydratePayloadFromLease(params: {
|
||||
const credentialId = requireString(params.acquired, "credentialId");
|
||||
const leaseToken = requireString(params.acquired, "leaseToken");
|
||||
const chunks: string[] = [];
|
||||
let serializedLength = 0;
|
||||
let serializedBytes = 0;
|
||||
for (let index = 0; index < marker.chunkCount; index += 1) {
|
||||
const chunk = await postBroker({
|
||||
action: "payload-chunk",
|
||||
@@ -340,14 +340,14 @@ async function hydratePayloadFromLease(params: {
|
||||
},
|
||||
});
|
||||
const data = requireString(chunk, "data");
|
||||
serializedLength += data.length;
|
||||
if (serializedLength > marker.byteLength) {
|
||||
serializedBytes += Buffer.byteLength(data, "utf8");
|
||||
if (serializedBytes > marker.byteLength) {
|
||||
throw new Error("Chunked payload exceeded declared byteLength.");
|
||||
}
|
||||
chunks.push(data);
|
||||
}
|
||||
const serialized = chunks.join("");
|
||||
if (serializedLength !== marker.byteLength) {
|
||||
if (serializedBytes !== marker.byteLength) {
|
||||
throw new Error("Chunked payload length mismatch.");
|
||||
}
|
||||
return parseTelegramUserQaCredentialPayload(JSON.parse(serialized));
|
||||
@@ -640,4 +640,4 @@ if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href)
|
||||
await main();
|
||||
}
|
||||
|
||||
export { optionalPositiveInteger, parseChunkedPayloadMarker };
|
||||
export { hydratePayloadFromLease, optionalPositiveInteger, parseChunkedPayloadMarker };
|
||||
|
||||
@@ -4,7 +4,7 @@ import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "no
|
||||
import { readFile } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import path, { win32 } from "node:path";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { fetchJsonWithTimeout, runCommand } from "../../scripts/e2e/telegram-user-credential-io.ts";
|
||||
import {
|
||||
expandHome,
|
||||
@@ -75,6 +75,8 @@ async function waitForExit(
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
vi.unstubAllGlobals();
|
||||
for (const dir of tempDirs.splice(0)) {
|
||||
rmSync(dir, { force: true, recursive: true });
|
||||
}
|
||||
@@ -178,6 +180,64 @@ describe("telegram user credential IO", () => {
|
||||
).toThrow("Chunked payload marker exceeds 67108864 bytes.");
|
||||
});
|
||||
|
||||
it("hydrates chunked lease payloads using utf8 byte lengths", async () => {
|
||||
const credentialModule = (await import(
|
||||
`${new URL("../../scripts/e2e/telegram-user-credential.ts", import.meta.url).href}?case=utf8-chunk-${Date.now()}`
|
||||
)) as {
|
||||
hydratePayloadFromLease(params: {
|
||||
acquired: Record<string, unknown>;
|
||||
ownerId: string;
|
||||
siteUrl: string;
|
||||
token: string;
|
||||
}): Promise<Record<string, unknown>>;
|
||||
};
|
||||
const sha256 = "a".repeat(64);
|
||||
const serialized = JSON.stringify({
|
||||
groupId: "-100123",
|
||||
sutToken: "sut-token",
|
||||
testerUserId: "8709353529",
|
||||
testerUsername: "OpenClawTestUser",
|
||||
telegramApiId: "123456",
|
||||
telegramApiHash: "api-hash-\u00e9",
|
||||
tdlibDatabaseEncryptionKey: "db-key",
|
||||
tdlibArchiveBase64: "tdlib-archive",
|
||||
tdlibArchiveSha256: sha256,
|
||||
desktopTdataArchiveBase64: "desktop-archive",
|
||||
desktopTdataArchiveSha256: sha256,
|
||||
});
|
||||
const fetchMock = vi.fn<typeof fetch>(
|
||||
async () =>
|
||||
new Response(JSON.stringify({ status: "ok", data: serialized }), {
|
||||
status: 200,
|
||||
headers: { "content-type": "application/json" },
|
||||
}),
|
||||
);
|
||||
vi.stubGlobal("fetch", fetchMock);
|
||||
|
||||
const payload = await credentialModule.hydratePayloadFromLease({
|
||||
acquired: {
|
||||
credentialId: "cred-utf8",
|
||||
leaseToken: "lease-utf8",
|
||||
payload: {
|
||||
[CHUNKED_PAYLOAD_MARKER]: true,
|
||||
byteLength: Buffer.byteLength(serialized, "utf8"),
|
||||
chunkCount: 1,
|
||||
},
|
||||
},
|
||||
ownerId: "owner-utf8",
|
||||
siteUrl: "https://qa.example.invalid",
|
||||
token: "ci-secret",
|
||||
});
|
||||
|
||||
expect(payload.telegramApiHash).toBe("api-hash-\u00e9");
|
||||
expect(fetchMock).toHaveBeenCalledWith(
|
||||
"https://qa.example.invalid/qa-credentials/v1/payload-chunk",
|
||||
expect.objectContaining({
|
||||
body: expect.stringContaining('"credentialId":"cred-utf8"'),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("rejects loose numeric credential limits instead of parsing prefixes", async () => {
|
||||
const credentialModule = (await import(
|
||||
`${new URL("../../scripts/e2e/telegram-user-credential.ts", import.meta.url).href}?case=limits-${Date.now()}`
|
||||
|
||||
Reference in New Issue
Block a user