Files
anonymous_github/test/gist-auth-errors.test.js
T
Thomas Durieux db966356ec fix: support gists through GitHub App login (#875)
* fix: prompt OAuth reconnection when gist credentials are rejected

* fix: support gist reads through GitHub App user grants

* test: adapt truncated gist regression to provider selection

* fix: address gist reconnect visibility and token renewal review

* fix: verify App authorization before revoking OAuth
2026-10-08 10:26:13 +01:00

60 lines
3.2 KiB
JavaScript

const { expect } = require("chai");
require("ts-node/register/transpile-only");
const github = require("../src/core/GitHubUtils");
const Gist = require("../src/core/Gist").default;
const Model = require("../src/core/model/anonymizedGists/anonymizedGists.model").default;
const { handleError } = require("../src/server/routes/route-utils");
describe("gist authentication errors", function () {
let original, gist, client;
beforeEach(function () {
original = github.octokit;
gist = new Gist(new Model({ source: { gistId: "example" }, gist: { files: [{ filename: "saved.txt", content: "saved" }] } }));
gist.getAccess = async () => ({ token: "rejected-token", connection: "oauth" });
client = { rest: { gists: { get: async () => ({ data: { files: {} } }) } }, paginate: async () => [], request: async () => ({ data: "raw" }) };
github.octokit = token => { expect(token).to.equal("rejected-token"); return client; };
});
afterEach(function () { github.octokit = original; });
for (const operation of ["metadata", "comments", "raw file"]) {
it("requests OAuth reconnection when GitHub rejects " + operation, async function () {
const failure = Object.assign(new Error("Bad credentials"), { status: 401 });
const reject = async () => { throw failure; };
if (operation === "metadata") client.rest.gists.get = reject;
if (operation === "comments") client.paginate = reject;
if (operation === "raw file") {
client.rest.gists.get = async () => ({ data: { files: { file: { filename: "large.txt", truncated: true, raw_url: "https://gist.githubusercontent.com/example/raw" } } } });
client.request = reject;
}
let error;
try { await gist.download(); } catch (caught) { error = caught; }
expect(error?.message).to.equal("github_oauth_required");
expect(error.cause).to.equal(failure);
let status, body;
handleError(error, { headersSent: false, status: value => { status = value; return { json: value => { body = value; } }; } });
expect(status).to.equal(403);
expect(body).to.deep.equal({ error: "github_oauth_required" });
expect(gist.model.gist.files[0].content).to.equal("saved");
});
}
for (const status of [403, 404, 429, 500]) {
it("preserves non-authentication GitHub errors: " + status, async function () {
const failure = Object.assign(new Error("Other GitHub failure"), { status });
client.rest.gists.get = async () => { throw failure; };
let error;
try { await gist.download(); } catch (caught) { error = caught; }
expect(error).to.equal(failure);
});
}
it("requests App reconnection when an App user token is rejected", async function () {
gist.getAccess = async () => ({ token: "rejected-token", connection: "github-app" });
client.rest.gists.get = async () => { throw Object.assign(new Error("Bad credentials"), { status: 401 }); };
let error;
try { await gist.download(); } catch (caught) { error = caught; }
expect(error?.message).to.equal("github_app_reconnect_required");
});
it("still downloads a gist when the credential is accepted", async function () {
await gist.download();
expect(gist.model.gist.files).to.have.length(0);
});
});