Use GHEC-DR URL in Octokit instance

This commit is contained in:
Koen Vlaswinkel
2024-04-24 14:23:14 +02:00
parent 9a14896a4e
commit c2ddd680c1
6 changed files with 44 additions and 14 deletions

View File

@@ -3,6 +3,7 @@ import type { Octokit } from "@octokit/rest";
import type { Credentials } from "../authentication"; import type { Credentials } from "../authentication";
import { AppOctokit } from "../octokit"; import { AppOctokit } from "../octokit";
import { hasGhecDrUri } from "../../config"; import { hasGhecDrUri } from "../../config";
import { getOctokitBaseUrl } from "./octokit";
// We need 'repo' scope for triggering workflows, 'gist' scope for exporting results to Gist, // We need 'repo' scope for triggering workflows, 'gist' scope for exporting results to Gist,
// and 'read:packages' for reading private CodeQL packages. // and 'read:packages' for reading private CodeQL packages.
@@ -15,24 +16,18 @@ const SCOPES = ["repo", "gist", "read:packages"];
*/ */
export class VSCodeCredentials implements Credentials { export class VSCodeCredentials implements Credentials {
/** /**
* A specific octokit to return, otherwise a new authenticated octokit will be created when needed. * Creates or returns an instance of Octokit. The returned instance should
*/ * not be stored and reused, as it may become out-of-date with the current
private octokit: Octokit | undefined; * authentication session.
/**
* Creates or returns an instance of Octokit.
* *
* @returns An instance of Octokit. * @returns An instance of Octokit.
*/ */
async getOctokit(): Promise<Octokit> { async getOctokit(): Promise<Octokit> {
if (this.octokit) {
return this.octokit;
}
const accessToken = await this.getAccessToken(); const accessToken = await this.getAccessToken();
return new AppOctokit({ return new AppOctokit({
auth: accessToken, auth: accessToken,
baseUrl: getOctokitBaseUrl(),
}); });
} }

View File

@@ -0,0 +1,15 @@
import { getGitHubInstanceApiUrl } from "../../config";
/**
* Returns the Octokit base URL to use based on the GitHub instance URL.
*
* This is necessary because the Octokit base URL should not have a trailing
* slash, but this is included by default in a URL.
*/
export function getOctokitBaseUrl(): string {
let apiUrl = getGitHubInstanceApiUrl().toString();
if (apiUrl.endsWith("/")) {
apiUrl = apiUrl.slice(0, -1);
}
return apiUrl;
}

View File

@@ -127,6 +127,7 @@ export function hasGhecDrUri(): boolean {
* The URI for GitHub.com. * The URI for GitHub.com.
*/ */
export const GITHUB_URL = new URL("https://github.com"); export const GITHUB_URL = new URL("https://github.com");
export const GITHUB_API_URL = new URL("https://api.github.com");
/** /**
* If the GitHub Enterprise URI is set to something that looks like GHEC-DR, return it. * If the GitHub Enterprise URI is set to something that looks like GHEC-DR, return it.
@@ -148,6 +149,16 @@ export function getGitHubInstanceUrl(): URL {
return GITHUB_URL; return GITHUB_URL;
} }
export function getGitHubInstanceApiUrl(): URL {
const ghecDrUri = getGhecDrUri();
if (ghecDrUri) {
const url = new URL(ghecDrUri.toString());
url.hostname = `api.${url.hostname}`;
return url;
}
return GITHUB_API_URL;
}
const ROOT_SETTING = new Setting("codeQL"); const ROOT_SETTING = new Setting("codeQL");
// Telemetry configuration // Telemetry configuration

View File

@@ -7,6 +7,7 @@ import { AppOctokit } from "../common/octokit";
import type { ProgressCallback } from "../common/vscode/progress"; import type { ProgressCallback } from "../common/vscode/progress";
import { UserCancellationException } from "../common/vscode/progress"; import { UserCancellationException } from "../common/vscode/progress";
import type { EndpointDefaults } from "@octokit/types"; import type { EndpointDefaults } from "@octokit/types";
import { getOctokitBaseUrl } from "../common/vscode/octokit";
export async function getCodeSearchRepositories( export async function getCodeSearchRepositories(
query: string, query: string,
@@ -54,6 +55,7 @@ async function provideOctokitWithThrottling(
const octokit = new MyOctokit({ const octokit = new MyOctokit({
auth, auth,
baseUrl: getOctokitBaseUrl(),
throttle: { throttle: {
onRateLimit: (retryAfter: number, options: EndpointDefaults): boolean => { onRateLimit: (retryAfter: number, options: EndpointDefaults): boolean => {
void logger.log( void logger.log(

View File

@@ -30,6 +30,7 @@ import {
allowHttp, allowHttp,
downloadTimeout, downloadTimeout,
getGitHubInstanceUrl, getGitHubInstanceUrl,
hasGhecDrUri,
isCanary, isCanary,
} from "../config"; } from "../config";
import { showAndLogInformationMessage } from "../common/logging"; import { showAndLogInformationMessage } from "../common/logging";
@@ -151,9 +152,10 @@ export class DatabaseFetcher {
maxStep: 2, maxStep: 2,
}); });
const instanceUrl = getGitHubInstanceUrl();
const options: InputBoxOptions = { const options: InputBoxOptions = {
title: title: `Enter a GitHub repository URL or "name with owner" (e.g. https://github.com/github/codeql or github/codeql)`,
'Enter a GitHub repository URL or "name with owner" (e.g. https://github.com/github/codeql or github/codeql)',
placeHolder: "https://github.com/<owner>/<repo> or <owner>/<repo>", placeHolder: "https://github.com/<owner>/<repo> or <owner>/<repo>",
ignoreFocusOut: true, ignoreFocusOut: true,
}; };
@@ -187,7 +189,8 @@ export class DatabaseFetcher {
throw new Error(`Invalid GitHub repository: ${githubRepo}`); throw new Error(`Invalid GitHub repository: ${githubRepo}`);
} }
const credentials = isCanary() ? this.app.credentials : undefined; const credentials =
isCanary() || hasGhecDrUri() ? this.app.credentials : undefined;
const octokit = credentials const octokit = credentials
? await credentials.getOctokit() ? await credentials.getOctokit()

View File

@@ -3,6 +3,7 @@ import type { Octokit } from "@octokit/rest";
import type { RestEndpointMethodTypes } from "@octokit/plugin-rest-endpoint-methods"; import type { RestEndpointMethodTypes } from "@octokit/plugin-rest-endpoint-methods";
import { showNeverAskAgainDialog } from "../../common/vscode/dialog"; import { showNeverAskAgainDialog } from "../../common/vscode/dialog";
import type { GitHubDatabaseConfig } from "../../config"; import type { GitHubDatabaseConfig } from "../../config";
import { hasGhecDrUri } from "../../config";
import type { Credentials } from "../../common/authentication"; import type { Credentials } from "../../common/authentication";
import { AppOctokit } from "../../common/octokit"; import { AppOctokit } from "../../common/octokit";
import type { ProgressCallback } from "../../common/vscode/progress"; import type { ProgressCallback } from "../../common/vscode/progress";
@@ -67,7 +68,10 @@ export async function listDatabases(
credentials: Credentials, credentials: Credentials,
config: GitHubDatabaseConfig, config: GitHubDatabaseConfig,
): Promise<ListDatabasesResult | undefined> { ): Promise<ListDatabasesResult | undefined> {
const hasAccessToken = !!(await credentials.getExistingAccessToken()); // On GHEC-DR, unauthenticated requests will enver work, so we should always ask
// for authentication.
const hasAccessToken =
!!(await credentials.getExistingAccessToken()) || hasGhecDrUri();
let octokit = hasAccessToken let octokit = hasAccessToken
? await credentials.getOctokit() ? await credentials.getOctokit()