Upload using uploads.github.com if enabled for that repository

This commit is contained in:
Robert 2021-11-29 12:16:20 +00:00
parent 3bf14e85d8
commit 460d053698
6 changed files with 139 additions and 32 deletions

30
lib/database-upload.js generated
View file

@ -42,11 +42,13 @@ async function uploadDatabases(repositoryNwo, config, apiDetails, logger) {
return; return;
} }
const client = (0, api_client_1.getApiClient)(apiDetails); const client = (0, api_client_1.getApiClient)(apiDetails);
let useUploadDomain;
try { try {
await client.request("GET /repos/:owner/:repo/code-scanning/codeql/databases", { const response = await client.request("GET /repos/:owner/:repo/code-scanning/codeql/databases", {
owner: repositoryNwo.owner, owner: repositoryNwo.owner,
repo: repositoryNwo.repo, repo: repositoryNwo.repo,
}); });
useUploadDomain = response.data["uploads_domain_enabled"];
} }
catch (e) { catch (e) {
if (util.isHTTPError(e) && e.status === 404) { if (util.isHTTPError(e) && e.status === 404) {
@ -63,12 +65,26 @@ async function uploadDatabases(repositoryNwo, config, apiDetails, logger) {
// Upload the database bundle // Upload the database bundle
const payload = fs.readFileSync(await (0, util_1.bundleDb)(config, language, codeql)); const payload = fs.readFileSync(await (0, util_1.bundleDb)(config, language, codeql));
try { try {
await client.request(`PUT /repos/:owner/:repo/code-scanning/codeql/databases/:language`, { if (useUploadDomain) {
owner: repositoryNwo.owner, await client.request(`POST https://uploads.github.com/repos/:owner/:repo/code-scanning/codeql/databases/:language?name=:name`, {
repo: repositoryNwo.repo, owner: repositoryNwo.owner,
language, repo: repositoryNwo.repo,
data: payload, language,
}); name: `${language}-database`,
data: payload,
headers: {
authorization: `token ${apiDetails.auth}`,
},
});
}
else {
await client.request(`PUT /repos/:owner/:repo/code-scanning/codeql/databases/:language`, {
owner: repositoryNwo.owner,
repo: repositoryNwo.repo,
language,
data: payload,
});
}
logger.debug(`Successfully uploaded database for ${language}`); logger.debug(`Successfully uploaded database for ${language}`);
} }
catch (e) { catch (e) {

View file

@ -1 +1 @@
{"version":3,"file":"database-upload.js","sourceRoot":"","sources":["../src/database-upload.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAAA,uCAAyB;AAEzB,4DAA8C;AAC9C,6CAA8D;AAC9D,qCAAqC;AAIrC,6CAA+B;AAC/B,iCAAkC;AAE3B,KAAK,UAAU,eAAe,CACnC,aAA4B,EAC5B,MAAc,EACd,UAA4B,EAC5B,MAAc;IAEd,IAAI,WAAW,CAAC,gBAAgB,CAAC,iBAAiB,CAAC,KAAK,MAAM,EAAE;QAC9D,MAAM,CAAC,KAAK,CAAC,wDAAwD,CAAC,CAAC;QACvE,OAAO;KACR;IAED,iDAAiD;IACjD,IAAI,MAAM,CAAC,aAAa,CAAC,IAAI,KAAK,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE;QAC3D,MAAM,CAAC,KAAK,CAAC,kDAAkD,CAAC,CAAC;QACjE,OAAO;KACR;IAED,IAAI,CAAC,CAAC,MAAM,WAAW,CAAC,wBAAwB,EAAE,CAAC,EAAE;QACnD,4EAA4E;QAC5E,MAAM,CAAC,KAAK,CAAC,gDAAgD,CAAC,CAAC;QAC/D,OAAO;KACR;IAED,MAAM,MAAM,GAAG,IAAA,yBAAY,EAAC,UAAU,CAAC,CAAC;IACxC,IAAI;QACF,MAAM,MAAM,CAAC,OAAO,CAClB,wDAAwD,EACxD;YACE,KAAK,EAAE,aAAa,CAAC,KAAK;YAC1B,IAAI,EAAE,aAAa,CAAC,IAAI;SACzB,CACF,CAAC;KACH;IAAC,OAAO,CAAC,EAAE;QACV,IAAI,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,GAAG,EAAE;YAC3C,MAAM,CAAC,KAAK,CACV,kEAAkE,CACnE,CAAC;SACH;aAAM;YACL,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YACf,MAAM,CAAC,IAAI,CAAC,kDAAkD,CAAC,EAAE,CAAC,CAAC;SACpE;QACD,OAAO;KACR;IAED,MAAM,MAAM,GAAG,MAAM,IAAA,kBAAS,EAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACjD,KAAK,MAAM,QAAQ,IAAI,MAAM,CAAC,SAAS,EAAE;QACvC,6BAA6B;QAC7B,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,MAAM,IAAA,eAAQ,EAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;QAC1E,IAAI;YACF,MAAM,MAAM,CAAC,OAAO,CAClB,kEAAkE,EAClE;gBACE,KAAK,EAAE,aAAa,CAAC,KAAK;gBAC1B,IAAI,EAAE,aAAa,CAAC,IAAI;gBACxB,QAAQ;gBACR,IAAI,EAAE,OAAO;aACd,CACF,CAAC;YACF,MAAM,CAAC,KAAK,CAAC,sCAAsC,QAAQ,EAAE,CAAC,CAAC;SAChE;QAAC,OAAO,CAAC,EAAE;YACV,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YACf,4CAA4C;YAC5C,MAAM,CAAC,OAAO,CAAC,iCAAiC,QAAQ,KAAK,CAAC,EAAE,CAAC,CAAC;SACnE;KACF;AACH,CAAC;AAjED,0CAiEC"} {"version":3,"file":"database-upload.js","sourceRoot":"","sources":["../src/database-upload.ts"],"names":[],"mappings":"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"}

View file

@ -81,19 +81,29 @@ function getRecordingLogger(messages) {
endGroup: () => undefined, endGroup: () => undefined,
}; };
} }
function mockHttpRequests(optInStatusCode, databaseUploadStatusCode) { function mockHttpRequests(optInStatusCode, useUploadDomain, databaseUploadStatusCode) {
// Passing an auth token is required, so we just use a dummy value // Passing an auth token is required, so we just use a dummy value
const client = github.getOctokit("123"); const client = github.getOctokit("123");
const requestSpy = sinon.stub(client, "request"); const requestSpy = sinon.stub(client, "request");
const optInSpy = requestSpy.withArgs("GET /repos/:owner/:repo/code-scanning/codeql/databases"); const optInSpy = requestSpy.withArgs("GET /repos/:owner/:repo/code-scanning/codeql/databases");
if (optInStatusCode < 300) { if (optInStatusCode < 300) {
optInSpy.resolves(undefined); optInSpy.resolves({
status: optInStatusCode,
data: {
useUploadDomain,
},
headers: {},
url: "GET /repos/:owner/:repo/code-scanning/codeql/databases",
});
} }
else { else {
optInSpy.throws(new util_1.HTTPError("some error message", optInStatusCode)); optInSpy.throws(new util_1.HTTPError("some error message", optInStatusCode));
} }
if (databaseUploadStatusCode !== undefined) { if (databaseUploadStatusCode !== undefined) {
const databaseUploadSpy = requestSpy.withArgs("PUT /repos/:owner/:repo/code-scanning/codeql/databases/:language"); const url = useUploadDomain
? "POST https://uploads.github.com/repos/:owner/:repo/code-scanning/codeql/databases/:language?name=:name"
: "PUT /repos/:owner/:repo/code-scanning/codeql/databases/:language";
const databaseUploadSpy = requestSpy.withArgs(url);
if (databaseUploadStatusCode < 300) { if (databaseUploadStatusCode < 300) {
databaseUploadSpy.resolves(undefined); databaseUploadSpy.resolves(undefined);
} }
@ -213,7 +223,7 @@ function mockHttpRequests(optInStatusCode, databaseUploadStatusCode) {
.withArgs("upload-database") .withArgs("upload-database")
.returns("true"); .returns("true");
sinon.stub(actionsUtil, "isAnalyzingDefaultBranch").resolves(true); sinon.stub(actionsUtil, "isAnalyzingDefaultBranch").resolves(true);
mockHttpRequests(204, 500); mockHttpRequests(200, false, 500);
(0, codeql_1.setCodeQL)({ (0, codeql_1.setCodeQL)({
async databaseBundle(_, outputFilePath) { async databaseBundle(_, outputFilePath) {
fs.writeFileSync(outputFilePath, ""); fs.writeFileSync(outputFilePath, "");
@ -226,7 +236,7 @@ function mockHttpRequests(optInStatusCode, databaseUploadStatusCode) {
"Failed to upload database for javascript: Error: some error message") !== undefined); "Failed to upload database for javascript: Error: some error message") !== undefined);
}); });
}); });
(0, ava_1.default)("Successfully uploading a database", async (t) => { (0, ava_1.default)("Successfully uploading a database to api.github.com", async (t) => {
await (0, util_1.withTmpDir)(async (tmpDir) => { await (0, util_1.withTmpDir)(async (tmpDir) => {
(0, testing_utils_1.setupActionsVars)(tmpDir, tmpDir); (0, testing_utils_1.setupActionsVars)(tmpDir, tmpDir);
sinon sinon
@ -234,7 +244,27 @@ function mockHttpRequests(optInStatusCode, databaseUploadStatusCode) {
.withArgs("upload-database") .withArgs("upload-database")
.returns("true"); .returns("true");
sinon.stub(actionsUtil, "isAnalyzingDefaultBranch").resolves(true); sinon.stub(actionsUtil, "isAnalyzingDefaultBranch").resolves(true);
mockHttpRequests(204, 201); mockHttpRequests(200, false, 201);
(0, codeql_1.setCodeQL)({
async databaseBundle(_, outputFilePath) {
fs.writeFileSync(outputFilePath, "");
},
});
const loggedMessages = [];
await (0, database_upload_1.uploadDatabases)(testRepoName, getTestConfig(tmpDir), testApiDetails, getRecordingLogger(loggedMessages));
t.assert(loggedMessages.find((v) => v.type === "debug" &&
v.message === "Successfully uploaded database for javascript") !== undefined);
});
});
(0, ava_1.default)("Successfully uploading a database to uploads.github.com", async (t) => {
await (0, util_1.withTmpDir)(async (tmpDir) => {
(0, testing_utils_1.setupActionsVars)(tmpDir, tmpDir);
sinon
.stub(actionsUtil, "getRequiredInput")
.withArgs("upload-database")
.returns("true");
sinon.stub(actionsUtil, "isAnalyzingDefaultBranch").resolves(true);
mockHttpRequests(200, true, 201);
(0, codeql_1.setCodeQL)({ (0, codeql_1.setCodeQL)({
async databaseBundle(_, outputFilePath) { async databaseBundle(_, outputFilePath) {
fs.writeFileSync(outputFilePath, ""); fs.writeFileSync(outputFilePath, "");

File diff suppressed because one or more lines are too long

View file

@ -82,6 +82,7 @@ function getRecordingLogger(messages: LoggedMessage[]): Logger {
function mockHttpRequests( function mockHttpRequests(
optInStatusCode: number, optInStatusCode: number,
useUploadDomain?: boolean,
databaseUploadStatusCode?: number databaseUploadStatusCode?: number
) { ) {
// Passing an auth token is required, so we just use a dummy value // Passing an auth token is required, so we just use a dummy value
@ -93,15 +94,23 @@ function mockHttpRequests(
"GET /repos/:owner/:repo/code-scanning/codeql/databases" "GET /repos/:owner/:repo/code-scanning/codeql/databases"
); );
if (optInStatusCode < 300) { if (optInStatusCode < 300) {
optInSpy.resolves(undefined); optInSpy.resolves({
status: optInStatusCode,
data: {
useUploadDomain,
},
headers: {},
url: "GET /repos/:owner/:repo/code-scanning/codeql/databases",
});
} else { } else {
optInSpy.throws(new HTTPError("some error message", optInStatusCode)); optInSpy.throws(new HTTPError("some error message", optInStatusCode));
} }
if (databaseUploadStatusCode !== undefined) { if (databaseUploadStatusCode !== undefined) {
const databaseUploadSpy = requestSpy.withArgs( const url = useUploadDomain
"PUT /repos/:owner/:repo/code-scanning/codeql/databases/:language" ? "POST https://uploads.github.com/repos/:owner/:repo/code-scanning/codeql/databases/:language?name=:name"
); : "PUT /repos/:owner/:repo/code-scanning/codeql/databases/:language";
const databaseUploadSpy = requestSpy.withArgs(url);
if (databaseUploadStatusCode < 300) { if (databaseUploadStatusCode < 300) {
databaseUploadSpy.resolves(undefined); databaseUploadSpy.resolves(undefined);
} else { } else {
@ -303,7 +312,7 @@ test("Don't crash if uploading a database fails", async (t) => {
.returns("true"); .returns("true");
sinon.stub(actionsUtil, "isAnalyzingDefaultBranch").resolves(true); sinon.stub(actionsUtil, "isAnalyzingDefaultBranch").resolves(true);
mockHttpRequests(204, 500); mockHttpRequests(200, false, 500);
setCodeQL({ setCodeQL({
async databaseBundle(_: string, outputFilePath: string) { async databaseBundle(_: string, outputFilePath: string) {
@ -329,7 +338,7 @@ test("Don't crash if uploading a database fails", async (t) => {
}); });
}); });
test("Successfully uploading a database", async (t) => { test("Successfully uploading a database to api.github.com", async (t) => {
await withTmpDir(async (tmpDir) => { await withTmpDir(async (tmpDir) => {
setupActionsVars(tmpDir, tmpDir); setupActionsVars(tmpDir, tmpDir);
sinon sinon
@ -338,7 +347,41 @@ test("Successfully uploading a database", async (t) => {
.returns("true"); .returns("true");
sinon.stub(actionsUtil, "isAnalyzingDefaultBranch").resolves(true); sinon.stub(actionsUtil, "isAnalyzingDefaultBranch").resolves(true);
mockHttpRequests(204, 201); mockHttpRequests(200, false, 201);
setCodeQL({
async databaseBundle(_: string, outputFilePath: string) {
fs.writeFileSync(outputFilePath, "");
},
});
const loggedMessages = [] as LoggedMessage[];
await uploadDatabases(
testRepoName,
getTestConfig(tmpDir),
testApiDetails,
getRecordingLogger(loggedMessages)
);
t.assert(
loggedMessages.find(
(v) =>
v.type === "debug" &&
v.message === "Successfully uploaded database for javascript"
) !== undefined
);
});
});
test("Successfully uploading a database to uploads.github.com", async (t) => {
await withTmpDir(async (tmpDir) => {
setupActionsVars(tmpDir, tmpDir);
sinon
.stub(actionsUtil, "getRequiredInput")
.withArgs("upload-database")
.returns("true");
sinon.stub(actionsUtil, "isAnalyzingDefaultBranch").resolves(true);
mockHttpRequests(200, true, 201);
setCodeQL({ setCodeQL({
async databaseBundle(_: string, outputFilePath: string) { async databaseBundle(_: string, outputFilePath: string) {

View file

@ -33,14 +33,16 @@ export async function uploadDatabases(
} }
const client = getApiClient(apiDetails); const client = getApiClient(apiDetails);
let useUploadDomain: boolean;
try { try {
await client.request( const response = await client.request(
"GET /repos/:owner/:repo/code-scanning/codeql/databases", "GET /repos/:owner/:repo/code-scanning/codeql/databases",
{ {
owner: repositoryNwo.owner, owner: repositoryNwo.owner,
repo: repositoryNwo.repo, repo: repositoryNwo.repo,
} }
); );
useUploadDomain = response.data["uploads_domain_enabled"];
} catch (e) { } catch (e) {
if (util.isHTTPError(e) && e.status === 404) { if (util.isHTTPError(e) && e.status === 404) {
logger.debug( logger.debug(
@ -58,15 +60,31 @@ export async function uploadDatabases(
// Upload the database bundle // Upload the database bundle
const payload = fs.readFileSync(await bundleDb(config, language, codeql)); const payload = fs.readFileSync(await bundleDb(config, language, codeql));
try { try {
await client.request( if (useUploadDomain) {
`PUT /repos/:owner/:repo/code-scanning/codeql/databases/:language`, await client.request(
{ `POST https://uploads.github.com/repos/:owner/:repo/code-scanning/codeql/databases/:language?name=:name`,
owner: repositoryNwo.owner, {
repo: repositoryNwo.repo, owner: repositoryNwo.owner,
language, repo: repositoryNwo.repo,
data: payload, language,
} name: `${language}-database`,
); data: payload,
headers: {
authorization: `token ${apiDetails.auth}`,
},
}
);
} else {
await client.request(
`PUT /repos/:owner/:repo/code-scanning/codeql/databases/:language`,
{
owner: repositoryNwo.owner,
repo: repositoryNwo.repo,
language,
data: payload,
}
);
}
logger.debug(`Successfully uploaded database for ${language}`); logger.debug(`Successfully uploaded database for ${language}`);
} catch (e) { } catch (e) {
console.log(e); console.log(e);