Use externalRepoAuth when getting a remote config

This allows users to specify a different token for retrieving the
codeql config from a different repository.

Fixes https://github.com/github/advanced-security-field/issues/185
This commit is contained in:
Andrew Eisenberg 2021-04-09 14:17:46 -07:00 committed by Andrew Eisenberg
parent 7f9fb10a74
commit 534192fa05
9 changed files with 194 additions and 19 deletions

94
src/api-client.test.ts Normal file
View file

@ -0,0 +1,94 @@
import * as githubUtils from "@actions/github/lib/utils";
import test, { ExecutionContext } from "ava";
import sinon from "sinon";
import { getApiClient } from "./api-client";
import { setupTests } from "./testing-utils";
setupTests(test);
let githubStub: sinon.SinonStub;
test.beforeEach(() => {
githubStub = sinon.stub(githubUtils, "GitHub");
});
test("Get the client API", async (t) => {
doTest(
t,
{
auth: "xyz",
externalRepoAuth: "abc",
url: "http://hucairz",
},
undefined,
{
auth: "token xyz",
baseUrl: "http://hucairz/api/v3",
userAgent: "CodeQL Action",
}
);
});
test("Get the client API external", async (t) => {
doTest(
t,
{
auth: "xyz",
externalRepoAuth: "abc",
url: "http://hucairz",
},
{ allowExternal: true },
{
auth: "token abc",
baseUrl: "http://hucairz/api/v3",
userAgent: "CodeQL Action",
}
);
});
test("Get the client API external not present", async (t) => {
doTest(
t,
{
auth: "xyz",
url: "http://hucairz",
},
{ allowExternal: true },
{
auth: "token xyz",
baseUrl: "http://hucairz/api/v3",
userAgent: "CodeQL Action",
}
);
});
test("Get the client API with github url", async (t) => {
doTest(
t,
{
auth: "xyz",
url: "https://github.com/some/invalid/url",
},
undefined,
{
auth: "token xyz",
baseUrl: "https://api.github.com",
userAgent: "CodeQL Action",
}
);
});
function doTest(
t: ExecutionContext<unknown>,
clientArgs: any,
clientOptions: any,
expected: any
) {
getApiClient(clientArgs, clientOptions);
const firstCallArgs = githubStub.args[0];
// log is a function, so we don't need to test for equality of it
delete firstCallArgs[0].log;
t.deepEqual(firstCallArgs, [expected]);
}

View file

@ -25,14 +25,17 @@ export interface GitHubApiExternalRepoDetails {
}
export const getApiClient = function (
apiDetails: GitHubApiDetails,
allowLocalRun = false
apiDetails: GitHubApiCombinedDetails,
{ allowLocalRun = false, allowExternal = false } = {}
) {
if (isLocalRun() && !allowLocalRun) {
throw new Error("Invalid API call in local run");
}
const auth =
(allowExternal && apiDetails.externalRepoAuth) || apiDetails.auth;
return new githubUtils.GitHub(
githubUtils.getOctokitOptions(apiDetails.auth, {
githubUtils.getOctokitOptions(auth, {
baseUrl: getApiUrl(apiDetails.url),
userAgent: "CodeQL Action",
log: consoleLogLevel({ level: "debug" }),
@ -63,5 +66,5 @@ export function getActionsApiClient(allowLocalRun = false) {
url: getRequiredEnvParam("GITHUB_SERVER_URL"),
};
return getApiClient(apiDetails, allowLocalRun);
return getApiClient(apiDetails, { allowLocalRun });
}

View file

@ -601,7 +601,7 @@ async function getLanguagesInRepo(
): Promise<Language[]> {
logger.debug(`GitHub repo ${repository.owner} ${repository.repo}`);
const response = await api
.getApiClient(apiDetails, true)
.getApiClient(apiDetails, { allowLocalRun: true })
.repos.listLanguages({
owner: repository.owner,
repo: repository.repo,
@ -1013,7 +1013,7 @@ function getLocalConfig(configFile: string, checkoutPath: string): UserConfig {
async function getRemoteConfig(
configFile: string,
apiDetails: api.GitHubApiDetails
apiDetails: api.GitHubApiCombinedDetails
): Promise<UserConfig> {
// retrieve the various parts of the config location, and ensure they're present
const format = new RegExp(
@ -1025,12 +1025,14 @@ async function getRemoteConfig(
throw new Error(getConfigFileRepoFormatInvalidMessage(configFile));
}
const response = await api.getApiClient(apiDetails, true).repos.getContent({
owner: pieces.groups.owner,
repo: pieces.groups.repo,
path: pieces.groups.path,
ref: pieces.groups.ref,
});
const response = await api
.getApiClient(apiDetails, { allowLocalRun: true, allowExternal: true })
.repos.getContent({
owner: pieces.groups.owner,
repo: pieces.groups.repo,
path: pieces.groups.path,
ref: pieces.groups.ref,
});
let fileContents: string;
if ("content" in response.data && response.data.content !== undefined) {