From 4aecc1d92f2ab7cee25e083d045e7862b54b7b2d Mon Sep 17 00:00:00 2001 From: tdurieux Date: Sun, 6 Sep 2026 09:19:23 +0200 Subject: [PATCH] fix: fetch complete content for truncated Gist files --- src/core/Gist.ts | 25 ++++++++++++++++++------- test/production-regressions.test.js | 13 +++++++++++++ 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/core/Gist.ts b/src/core/Gist.ts index ea19a88..945d112 100644 --- a/src/core/Gist.ts +++ b/src/core/Gist.ts @@ -83,14 +83,25 @@ export default class Gist { }), ]); - const files = Object.values(gistInfo.data.files || {}) + const files = await Promise.all(Object.values(gistInfo.data.files || {}) .filter((f): f is NonNullable => !!f) - .map((f) => ({ - filename: f.filename || "", - content: f.content || "", - language: f.language || undefined, - size: f.size || 0, - type: f.type || undefined, + .map(async (f) => { + let content = (f as typeof f & { encoding?: string }).encoding === "base64" + ? Buffer.from(f.content || "", "base64").toString("utf8") + : f.content || ""; + if (f.truncated) { + if (!f.raw_url) throw new Error("Truncated gist file has no raw URL"); + const raw = await oct.request("GET {url}", { url: f.raw_url, request: { parseSuccessResponseBody: false } }); + if (typeof raw.data !== "string") throw new Error("Invalid raw gist response"); + content = raw.data; + } + return { + filename: f.filename || "", + content, + language: f.language || undefined, + size: f.size || 0, + type: f.type || undefined, + }; })); const commentsMapped = comments.map((comment) => ({ diff --git a/test/production-regressions.test.js b/test/production-regressions.test.js index 0cd8cc8..ac056c7 100644 --- a/test/production-regressions.test.js +++ b/test/production-regressions.test.js @@ -162,6 +162,19 @@ describe("production regressions", function () { expect(handled).to.equal(failure); }); } + + it("fetches complete truncated gist content", async function () { + const Gist = require("../src/core/Gist").default; + const model = new (require("../src/core/model/anonymizedGists/anonymizedGists.model").default)({ source: { gistId: "123" } }); + const gist = new Gist(model); gist.getToken = async () => "private-token"; + stub(gh, "octokit", token => { + expect(token).to.equal("private-token"); + return { rest: { gists: { get: async () => ({ data: { files: { file: { filename: "file", content: "prefix", truncated: true, raw_url: "https://gist.githubusercontent.com/raw", size: 20 } } } }) } }, + paginate: async () => [], request: async (route, { url }) => { expect(url).to.include("gist.githubusercontent.com"); return { data: "complete gist content" }; } }; + }); + await gist.download(); + expect(gist.toJSON().gist.files[0].content).to.equal("complete gist content"); + }); it("checks GitHub authorization before returning shared cached metadata", async function () { const CachedRepoModel = require("../src/core/model/repositories/repositories.model").default; stub(db, "isConnected", true);