|
1 | 1 | import { describe, expect, it } from "vitest"; |
2 | 2 | import { |
| 3 | +GITHUB_ERROR_BODY_MAX_BYTES, |
3 | 4 | dependencyGuardCommentHeadSha, |
4 | 5 | dependencyFieldChanges, |
5 | 6 | dependencyOverrideExpectedSha, |
6 | 7 | findDependencyOverrideCommand, |
7 | 8 | findDependencyOverrideCommandAsync, |
| 9 | +githubApi, |
8 | 10 | isDependencyGuardAuthorizedForHead, |
9 | 11 | isDependencyFile, |
10 | 12 | isDependencyManifest, |
11 | 13 | isPackageLockfile, |
| 14 | +readBoundedGitHubErrorText, |
12 | 15 | renderAuthorizedDependencyComment, |
13 | 16 | renderBlockedDependencyComment, |
14 | 17 | renderClearedDependencyGuardComment, |
@@ -269,4 +272,54 @@ describe("dependency guard script", () => {
|
269 | 272 | expect(sanitizeDisplayValue("abc\u0000def")).toBe("abc?def"); |
270 | 273 | expect(sanitizeDisplayValue("x".repeat(300))).toHaveLength(240); |
271 | 274 | }); |
| 275 | + |
| 276 | +it("bounds GitHub error bodies by content-length", async () => { |
| 277 | +const response = new Response("ignored", { |
| 278 | +headers: { "content-length": String(GITHUB_ERROR_BODY_MAX_BYTES + 1) }, |
| 279 | +}); |
| 280 | + |
| 281 | +await expect(readBoundedGitHubErrorText(response)).rejects.toThrow( |
| 282 | +`GitHub error response body exceeded ${GITHUB_ERROR_BODY_MAX_BYTES} bytes`, |
| 283 | +); |
| 284 | +}); |
| 285 | + |
| 286 | +it("bounds GitHub error bodies by streamed bytes", async () => { |
| 287 | +const response = new Response( |
| 288 | +new ReadableStream({ |
| 289 | +start(controller) { |
| 290 | +controller.enqueue(new Uint8Array(GITHUB_ERROR_BODY_MAX_BYTES + 1)); |
| 291 | +controller.close(); |
| 292 | +}, |
| 293 | +}), |
| 294 | +); |
| 295 | + |
| 296 | +await expect(readBoundedGitHubErrorText(response)).rejects.toThrow( |
| 297 | +`GitHub error response body exceeded ${GITHUB_ERROR_BODY_MAX_BYTES} bytes`, |
| 298 | +); |
| 299 | +}); |
| 300 | + |
| 301 | +it("preserves GitHub status when an error body exceeds the cap", async () => { |
| 302 | +const originalFetch = globalThis.fetch; |
| 303 | +globalThis.fetch = (() => |
| 304 | +Promise.resolve( |
| 305 | +new Response( |
| 306 | +new ReadableStream({ |
| 307 | +start(controller) { |
| 308 | +controller.enqueue(new Uint8Array(GITHUB_ERROR_BODY_MAX_BYTES + 1)); |
| 309 | +controller.close(); |
| 310 | +}, |
| 311 | +}), |
| 312 | +{ status: 403, statusText: "Forbidden" }, |
| 313 | +), |
| 314 | +)) as typeof fetch; |
| 315 | + |
| 316 | +try { |
| 317 | +await expect(githubApi("token").request("/repos/openclaw/openclaw")).rejects.toMatchObject({ |
| 318 | +message: `403 Forbidden: GitHub error response body exceeded ${GITHUB_ERROR_BODY_MAX_BYTES} bytes`, |
| 319 | +status: 403, |
| 320 | +}); |
| 321 | +} finally { |
| 322 | +globalThis.fetch = originalFetch; |
| 323 | +} |
| 324 | +}); |
272 | 325 | }); |