mirror of
https://github.com/tdurieux/anonymous_github.git
synced 2026-11-14 00:07:00 +01:00
Merge pull request #925 from tdurieux/fix/unavailable-submodule-commit
fix: keep repositories readable with invalid submodule commits
This commit is contained in:
2 files changed
+44
No files matched your search
@@ -58,7 +58,17 @@ export async function expandSubmodules(files: IFile[], data: GitHubBaseData,
|
||||
await waitForTokenGate("");
|
||||
const child = await octokit("").git.getTree({
|
||||
owner: repository.organization, repo: repository.repoName, tree_sha: mount.sha, recursive: "1",
|
||||
}).catch((error: unknown) => {
|
||||
const upstream = error as { status?: number; response?: { data?: { message?: string } } };
|
||||
// GitHub also uses 422 for a gitlink whose pinned object is missing.
|
||||
// Only classify this child-tree response, not arbitrary validation errors.
|
||||
if (upstream.status === 422 && /^Invalid object requested\. SHA must identify a commit or a tree\b/.test(upstream.response?.data?.message || "")) {
|
||||
mount.submodule = "unavailable";
|
||||
return null;
|
||||
}
|
||||
throw error;
|
||||
});
|
||||
if (!child) continue;
|
||||
if (child.data.truncated || child.data.tree.length > budget.remaining) { mount.submodule = "limit"; continue; }
|
||||
const entries = child.data.tree;
|
||||
if (entries.some(entry => !safeRepositoryPath(entry.path))) { mount.submodule = "unsupported"; continue; }
|
||||
|
||||
@@ -138,6 +138,40 @@ describe("public GitHub submodules", function () {
|
||||
expect(calls).to.have.length(1);
|
||||
});
|
||||
|
||||
it("keeps parent files when a child gitlink points to an invalid Git object", async () => {
|
||||
const error = Object.assign(new Error("invalid object"), { status: 422, response: { data: {
|
||||
message: "Invalid object requested. SHA must identify a commit or a tree.",
|
||||
} } });
|
||||
api([], { error });
|
||||
const source = new GitHubStream(parent);
|
||||
source.getGHTree = async () => ({ tree: [
|
||||
{ path: "vendor/dependency", type: "commit", mode: "160000", sha },
|
||||
{ path: "README.md", type: "blob", sha: blob, size: 5 },
|
||||
] });
|
||||
const files = await source.getFiles();
|
||||
expect(files.find(file => file.name === "dependency").submodule).to.equal("unavailable");
|
||||
expect(files.find(file => file.name === "dependency").upstream).not.to.exist;
|
||||
expect(files.find(file => file.name === "README.md").sha).to.equal(blob);
|
||||
});
|
||||
|
||||
it("does not suppress invalid-object errors from parent metadata", async () => {
|
||||
const error = Object.assign(new Error("invalid parent"), { status: 422, response: { data: {
|
||||
message: "Invalid object requested. SHA must identify a commit or a tree.",
|
||||
} } });
|
||||
stub(utils, "octokit", () => ({ repos: { getContent: async () => { throw error; } } }));
|
||||
let caught; try { await expandSubmodules([mount()], parent); } catch (err) { caught = err; }
|
||||
expect(caught).to.equal(error);
|
||||
});
|
||||
|
||||
for (const [status, message] of [[422, "Validation Failed"], [422, ""], [429, "rate limited"], [500, "server error"]]) {
|
||||
it(`preserves child failure ${status}: ${message}`, async () => {
|
||||
const error = Object.assign(new Error(message), { status, response: { data: { message } } });
|
||||
api([], { error });
|
||||
let caught; try { await expandSubmodules([mount()], parent); } catch (err) { caught = err; }
|
||||
expect(caught).to.equal(error);
|
||||
});
|
||||
}
|
||||
|
||||
it("does not persist transient failures as permanently missing dependencies", async () => {
|
||||
const error = Object.assign(new Error("rate limited"), { status: 403 }); api([], { error });
|
||||
let caught; try { await expandSubmodules([mount()], parent); } catch (err) { caught = err; }
|
||||
|
||||
Reference in new issue
Block a user