Compare commits

...

2 Commits

Author SHA1 Message Date
Michael B. Gale 9e9e5714ab Replace meta variable for $kind if FF is enabled 2026-07-28 14:29:41 +01:00
Michael B. Gale 91fbc53f6a Add RemoteAddressAnalysisMetaVar feature 2026-07-28 14:04:38 +01:00
6 changed files with 155 additions and 9 deletions
+31 -3
View File
@@ -146993,6 +146993,11 @@ var featureConfig = {
envVar: "CODEQL_ACTION_PROXY_API_REQUESTS",
minimumVersion: void 0
},
["remote_address_analysis_meta_var" /* RemoteAddressAnalysisMetaVar */]: {
defaultValue: false,
envVar: "CODEQL_ACTION_REMOTE_ADDRESS_ANALYSIS_META_VAR",
minimumVersion: void 0
},
["skip_file_coverage_on_prs" /* SkipFileCoverageOnPrs */]: {
defaultValue: false,
envVar: "CODEQL_ACTION_SKIP_FILE_COVERAGE_ON_PRS",
@@ -148524,7 +148529,23 @@ async function getConfigFileInput({
}
return void 0;
}
async function getRemoteConfig(actionState, configFile, apiDetails) {
function replaceMetaVars(configFileAddress, analysisKind) {
return configFileAddress.replaceAll("$kind", analysisKind);
}
async function getRemoteConfig(actionState, analysisKinds, configFile, apiDetails) {
const supportMetaVar = await actionState.features.getValue(
"remote_address_analysis_meta_var" /* RemoteAddressAnalysisMetaVar */
);
if (supportMetaVar && analysisKinds.length === 1) {
configFile = replaceMetaVars(configFile, analysisKinds[0]);
actionState.logger.debug(
`Remote file address after replacing meta variables: ${configFile}`
);
} else if (supportMetaVar) {
actionState.logger.warning(
`Ignoring '${"remote_address_analysis_meta_var" /* RemoteAddressAnalysisMetaVar */}' feature, because multiple analysis kinds are enabled.`
);
}
const address = await parseRemoteFileAddress(actionState, configFile);
const shouldProxyRequest = await actionState.features.getValue(
"proxy_api_requests" /* ProxyApiRequests */
@@ -149386,7 +149407,7 @@ async function downloadCacheWithTime(codeQL, languages, logger) {
const trapCacheDownloadTime = import_perf_hooks.performance.now() - start;
return { trapCaches, trapCacheDownloadTime };
}
async function loadUserConfig(actionState, configFile, workspacePath, apiDetails, tempDir) {
async function loadUserConfig(actionState, analysisKinds, configFile, workspacePath, apiDetails, tempDir) {
if (isLocal(configFile)) {
if (configFile !== userConfigFromActionPath(tempDir)) {
configFile = path10.resolve(workspacePath, configFile);
@@ -149404,7 +149425,12 @@ async function loadUserConfig(actionState, configFile, workspacePath, apiDetails
if (isExplicitRemotePath(configFile)) {
configFile = configFile.substring(REMOTE_PATH_PREFIX.length);
}
return await getRemoteConfig(actionState, configFile, apiDetails);
return await getRemoteConfig(
actionState,
analysisKinds,
configFile,
apiDetails
);
}
}
var OVERLAY_ANALYSIS_FEATURES = {
@@ -149706,6 +149732,7 @@ async function determineUserConfig(action, tempDir, inputs) {
);
const fromConfigFile = await loadUserConfig(
action,
inputs.analysisKinds,
inputs.configFile,
inputs.workspacePath,
inputs.apiDetails,
@@ -149742,6 +149769,7 @@ async function determineUserConfig(action, tempDir, inputs) {
action.logger.debug(`Using configuration file: ${inputs.configFile}`);
return await loadUserConfig(
action,
inputs.analysisKinds,
inputs.configFile,
inputs.workspacePath,
inputs.apiDetails,
+13 -4
View File
@@ -2544,6 +2544,7 @@ test("loadUserConfig - loads local configuration files", async (t) => {
) =>
configUtils.loadUserConfig(
actionState,
[AnalysisKind.CodeScanning],
filePath,
workspaceDir,
SAMPLE_DOTCOM_API_DETAILS,
@@ -2587,12 +2588,19 @@ test.serial("loadUserConfig - loads remote configuration files", async (t) => {
const remoteAddress = "owner/repo/file@ref";
await callee(configUtils.loadUserConfig)
.withArgs(remoteAddress, tmpDir, SAMPLE_DOTCOM_API_DETAILS, tmpDir)
.withArgs(
[AnalysisKind.CodeScanning],
remoteAddress,
tmpDir,
SAMPLE_DOTCOM_API_DETAILS,
tmpDir,
)
.passes(t.deepEqual, {});
t.true(
getRemoteConfig.calledOnceWithExactly(
sinon.match.any,
[AnalysisKind.CodeScanning],
remoteAddress,
SAMPLE_DOTCOM_API_DETAILS,
),
@@ -2626,9 +2634,9 @@ test.serial(
// match our expectations. We break it down like this to get
// more useful test output.
const args = getRemoteConfig.getCalls()[0].args;
t.is(args.length, 3);
t.deepEqual(args[1], address);
t.deepEqual(args[2], SAMPLE_DOTCOM_API_DETAILS);
t.is(args.length, 4);
t.deepEqual(args[2], address);
t.deepEqual(args[3], SAMPLE_DOTCOM_API_DETAILS);
};
// Utility function to assert that `targetWithArgs` has not identified
@@ -2665,6 +2673,7 @@ test.serial(
// Prepare the test call to `loadUserConfig`.
const targetWithArgs = target.withArgs(
[AnalysisKind.CodeScanning],
address,
tmpDir,
SAMPLE_DOTCOM_API_DETAILS,
+9 -1
View File
@@ -484,6 +484,7 @@ async function downloadCacheWithTime(
*/
export async function loadUserConfig(
actionState: ActionState<["Logger", "Env", "FeatureFlags"]>,
analysisKinds: AnalysisKind[],
configFile: string,
workspacePath: string,
apiDetails: api.GitHubApiCombinedDetails,
@@ -511,7 +512,12 @@ export async function loadUserConfig(
if (isExplicitRemotePath(configFile)) {
configFile = configFile.substring(REMOTE_PATH_PREFIX.length);
}
return await getRemoteConfig(actionState, configFile, apiDetails);
return await getRemoteConfig(
actionState,
analysisKinds,
configFile,
apiDetails,
);
}
}
@@ -1071,6 +1077,7 @@ export async function determineUserConfig(
);
const fromConfigFile = await loadUserConfig(
action,
inputs.analysisKinds,
inputs.configFile,
inputs.workspacePath,
inputs.apiDetails,
@@ -1118,6 +1125,7 @@ export async function determineUserConfig(
action.logger.debug(`Using configuration file: ${inputs.configFile}`);
return await loadUserConfig(
action,
inputs.analysisKinds,
inputs.configFile,
inputs.workspacePath,
inputs.apiDetails,
+71 -1
View File
@@ -13,6 +13,7 @@ import {
setupTests,
} from "../testing-utils";
import type { UserConfig } from "./db-config";
import { getConfigFileInput, getRemoteConfig } from "./file";
setupTests(test);
@@ -137,7 +138,11 @@ test.serial("getRemoteConfig uses proxy when it is supposed to", async (t) => {
const target = callee(getRemoteConfig)
.withDefaultActionsEnv()
.withArgs("file.yml", SAMPLE_DOTCOM_API_DETAILS);
.withArgs(
[AnalysisKind.CodeScanning],
"file.yml",
SAMPLE_DOTCOM_API_DETAILS,
);
// Should use it when the FF is enabled and the environment variables are set.
await target
@@ -164,3 +169,68 @@ test.serial("getRemoteConfig uses proxy when it is supposed to", async (t) => {
.notLogs(t, "Using private registry proxy at 'http://localhost:1234'")
.throws(t, { message: errorMessage });
});
test.serial("getRemoteConfig replaces meta variables", async (t) => {
const client = github.getOctokit("123");
const response = {
data: {
content: Buffer.from("disable-default-queries: false").toString("base64"),
},
};
sinon.stub(client.rest.repos, "getContent").callsFake((params) => {
if (params?.path.endsWith("$kind.yml")) {
throw new Error(`Unexpected request path: ${params.path}`);
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return response as any;
});
sinon
.stub(api, "getApiClientWithExternalAuth")
.callsFake((_details, _proxy) => {
return client;
});
const target = callee(getRemoteConfig)
.withDefaultActionsEnv()
.withArgs(
[AnalysisKind.CodeScanning],
"owner/repo:file-$kind.yml",
SAMPLE_DOTCOM_API_DETAILS,
);
// Should replace the meta variable if the FF is enabled.
await target
.withFeatures([Feature.RemoteAddressAnalysisMetaVar])
.logs(
t,
"Remote file address after replacing meta variables: owner/repo:file-code-scanning.yml",
)
.passes(t.deepEqual, {
"disable-default-queries": false,
} satisfies UserConfig);
// But not if the FF is off.
await target.throws(t, {
instanceOf: Error,
message: "Unexpected request path: file-$kind.yml",
});
// Or if there are multiple analysis kinds.
await callee(getRemoteConfig)
.withDefaultActionsEnv()
.withArgs(
[AnalysisKind.CodeScanning, AnalysisKind.CodeQuality],
"owner/repo:file-$kind.yml",
SAMPLE_DOTCOM_API_DETAILS,
)
.withFeatures([Feature.RemoteAddressAnalysisMetaVar])
.logs(
t,
`Ignoring '${Feature.RemoteAddressAnalysisMetaVar}' feature, because multiple analysis kinds are enabled.`,
)
.throws(t, {
instanceOf: Error,
message: "Unexpected request path: file-$kind.yml",
});
});
+24
View File
@@ -80,6 +80,14 @@ export async function getConfigFileInput(
return undefined;
}
/** Replaces supported meta variables in `configFileAddress`. */
export function replaceMetaVars(
configFileAddress: string,
analysisKind: AnalysisKind,
): string {
return configFileAddress.replaceAll("$kind", analysisKind);
}
/**
* Attempts to fetch a `UserConfig` from a remote `address`.
*
@@ -91,9 +99,25 @@ export async function getConfigFileInput(
*/
export async function getRemoteConfig(
actionState: ActionState<["Logger", "Env", "FeatureFlags"]>,
analysisKinds: AnalysisKind[],
configFile: string,
apiDetails: api.GitHubApiCombinedDetails,
): Promise<UserConfig> {
const supportMetaVar = await actionState.features.getValue(
Feature.RemoteAddressAnalysisMetaVar,
);
if (supportMetaVar && analysisKinds.length === 1) {
configFile = replaceMetaVars(configFile, analysisKinds[0]);
actionState.logger.debug(
`Remote file address after replacing meta variables: ${configFile}`,
);
} else if (supportMetaVar) {
actionState.logger.warning(
`Ignoring '${Feature.RemoteAddressAnalysisMetaVar}' feature, because multiple analysis kinds are enabled.`,
);
}
const address = await parseRemoteFileAddress(actionState, configFile);
const shouldProxyRequest = await actionState.features.getValue(
+7
View File
@@ -137,6 +137,8 @@ export enum Feature {
QaTelemetryEnabled = "qa_telemetry_enabled",
/** Routes (some) API requests through the registry proxy. */
ProxyApiRequests = "proxy_api_requests",
/** Adds support for an analysis kind meta variable in remote addresses. */
RemoteAddressAnalysisMetaVar = "remote_address_analysis_meta_var",
/** Note that this currently only disables baseline file coverage information. */
SkipFileCoverageOnPrs = "skip_file_coverage_on_prs",
StartProxyUseFeaturesRelease = "start_proxy_use_features_release",
@@ -385,6 +387,11 @@ export const featureConfig = {
envVar: "CODEQL_ACTION_PROXY_API_REQUESTS",
minimumVersion: undefined,
},
[Feature.RemoteAddressAnalysisMetaVar]: {
defaultValue: false,
envVar: "CODEQL_ACTION_REMOTE_ADDRESS_ANALYSIS_META_VAR",
minimumVersion: undefined,
},
[Feature.SkipFileCoverageOnPrs]: {
defaultValue: false,
envVar: "CODEQL_ACTION_SKIP_FILE_COVERAGE_ON_PRS",