Merge pull request #4023 from github/mbg/ff/remove-new-remote-file-addresses-ff

Promote `NewRemoteFileAddresses` FF
This commit is contained in:
Michael B. Gale
2026-07-21 11:25:34 +00:00
committed by GitHub
9 changed files with 25 additions and 112 deletions

View File

@@ -96,7 +96,6 @@ jobs:
CODEQL_PROXY_HOST: ${{ steps.proxy.outputs.proxy_host }} CODEQL_PROXY_HOST: ${{ steps.proxy.outputs.proxy_host }}
CODEQL_PROXY_PORT: ${{ steps.proxy.outputs.proxy_port }} CODEQL_PROXY_PORT: ${{ steps.proxy.outputs.proxy_port }}
CODEQL_PROXY_CA_CERTIFICATE: ${{ steps.proxy.outputs.proxy_ca_certificate }} CODEQL_PROXY_CA_CERTIFICATE: ${{ steps.proxy.outputs.proxy_ca_certificate }}
CODEQL_ACTION_NEW_REMOTE_FILE_ADDRESSES: 'true'
with: with:
languages: java languages: java
tools: ${{ steps.prepare-test.outputs.tools-url }} tools: ${{ steps.prepare-test.outputs.tools-url }}

29
lib/entry-points.js generated
View File

@@ -146795,11 +146795,6 @@ var featureConfig = {
envVar: "CODEQL_ACTION_JAVA_NETWORK_DEBUGGING", envVar: "CODEQL_ACTION_JAVA_NETWORK_DEBUGGING",
minimumVersion: void 0 minimumVersion: void 0
}, },
["new_remote_file_addresses" /* NewRemoteFileAddresses */]: {
defaultValue: false,
envVar: "CODEQL_ACTION_NEW_REMOTE_FILE_ADDRESSES",
minimumVersion: void 0
},
["overlay_analysis" /* OverlayAnalysis */]: { ["overlay_analysis" /* OverlayAnalysis */]: {
defaultValue: false, defaultValue: false,
envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS", envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS",
@@ -147862,11 +147857,6 @@ function getInvalidConfigFileMessage(configFile, messages) {
const andMore = messages.length > 10 ? `, and ${messages.length - 10} more.` : "."; const andMore = messages.length > 10 ? `, and ${messages.length - 10} more.` : ".";
return `The configuration file "${configFile}" is invalid: ${messages.slice(0, 10).join(", ")}${andMore}`; return `The configuration file "${configFile}" is invalid: ${messages.slice(0, 10).join(", ")}${andMore}`;
} }
function getConfigFileRepoOldFormatInvalidMessage(configFile) {
let error3 = `The configuration file "${configFile}" is not a supported remote file reference.`;
error3 += " Expected format <owner>/<repository>/<file-path>@<ref>";
return error3;
}
function getConfigFileRepoFormatInvalidMessage(configFile) { function getConfigFileRepoFormatInvalidMessage(configFile) {
let error3 = `The configuration file "${configFile}" is not a supported remote file reference.`; let error3 = `The configuration file "${configFile}" is not a supported remote file reference.`;
error3 += " Expected format [<owner>/]<repository>[@<ref>][:<file-path>]"; error3 += " Expected format [<owner>/]<repository>[@<ref>][:<file-path>]";
@@ -148379,14 +148369,6 @@ async function parseRemoteFileAddress(actionState, configFile) {
if (oldFormatAddressResult.isSuccess()) { if (oldFormatAddressResult.isSuccess()) {
return oldFormatAddressResult.value; return oldFormatAddressResult.value;
} }
const allowNewFormat = await actionState.features.getValue(
"new_remote_file_addresses" /* NewRemoteFileAddresses */
);
if (!allowNewFormat) {
throw new ConfigurationError(
getConfigFileRepoOldFormatInvalidMessage(configFile)
);
}
const newFormatAddressResult = parseNewRemoteFileAddress( const newFormatAddressResult = parseNewRemoteFileAddress(
actionState.env, actionState.env,
configFile configFile
@@ -149299,10 +149281,7 @@ async function downloadCacheWithTime(codeQL, languages, logger) {
return { trapCaches, trapCacheDownloadTime }; return { trapCaches, trapCacheDownloadTime };
} }
async function loadUserConfig(actionState, configFile, workspacePath, apiDetails, tempDir) { async function loadUserConfig(actionState, configFile, workspacePath, apiDetails, tempDir) {
const allowNewFormat = await actionState.features.getValue( if (isLocal(configFile)) {
"new_remote_file_addresses" /* NewRemoteFileAddresses */
);
if (isLocal(configFile, allowNewFormat)) {
if (configFile !== userConfigFromActionPath(tempDir)) { if (configFile !== userConfigFromActionPath(tempDir)) {
configFile = path10.resolve(workspacePath, configFile); configFile = path10.resolve(workspacePath, configFile);
if (!(configFile + path10.sep).startsWith(workspacePath + path10.sep)) { if (!(configFile + path10.sep).startsWith(workspacePath + path10.sep)) {
@@ -149316,7 +149295,7 @@ async function loadUserConfig(actionState, configFile, workspacePath, apiDetails
); );
return getLocalConfig(actionState.logger, configFile, validateConfig); return getLocalConfig(actionState.logger, configFile, validateConfig);
} else { } else {
if (allowNewFormat && isExplicitRemotePath(configFile)) { if (isExplicitRemotePath(configFile)) {
configFile = configFile.substring(REMOTE_PATH_PREFIX.length); configFile = configFile.substring(REMOTE_PATH_PREFIX.length);
} }
return await getRemoteConfig(actionState, configFile, apiDetails); return await getRemoteConfig(actionState, configFile, apiDetails);
@@ -149787,11 +149766,11 @@ function isExplicitRemotePath(configPath) {
function containsAtRef(configPath) { function containsAtRef(configPath) {
return configPath.includes("@"); return configPath.includes("@");
} }
function isLocal(configPath, allowNewFormat) { function isLocal(configPath) {
if (isExplicitLocalPath(configPath)) { if (isExplicitLocalPath(configPath)) {
return true; return true;
} }
if (allowNewFormat && isExplicitRemotePath(configPath)) { if (isExplicitRemotePath(configPath)) {
return false; return false;
} }
return !containsAtRef(configPath); return !containsAtRef(configPath);

View File

@@ -48,7 +48,6 @@ steps:
CODEQL_PROXY_HOST: ${{ steps.proxy.outputs.proxy_host }} CODEQL_PROXY_HOST: ${{ steps.proxy.outputs.proxy_host }}
CODEQL_PROXY_PORT: ${{ steps.proxy.outputs.proxy_port }} CODEQL_PROXY_PORT: ${{ steps.proxy.outputs.proxy_port }}
CODEQL_PROXY_CA_CERTIFICATE: ${{ steps.proxy.outputs.proxy_ca_certificate }} CODEQL_PROXY_CA_CERTIFICATE: ${{ steps.proxy.outputs.proxy_ca_certificate }}
CODEQL_ACTION_NEW_REMOTE_FILE_ADDRESSES: "true"
with: with:
languages: java languages: java
tools: ${{ steps.prepare-test.outputs.tools-url }} tools: ${{ steps.prepare-test.outputs.tools-url }}

View File

@@ -2607,9 +2607,7 @@ test.serial(
const getRemoteConfig = sinon.stub(file, "getRemoteConfig").resolves({}); const getRemoteConfig = sinon.stub(file, "getRemoteConfig").resolves({});
// Construct the basic test target. // Construct the basic test target.
const target = callee(configUtils.loadUserConfig) const target = callee(configUtils.loadUserConfig).withDefaultActionsEnv();
.withDefaultActionsEnv()
.withFeatures([Feature.NewRemoteFileAddresses]);
// Utility function to assert that `targetWithArgs` has identified // Utility function to assert that `targetWithArgs` has identified
// the input as a remote file address. // the input as a remote file address.

View File

@@ -489,11 +489,7 @@ export async function loadUserConfig(
apiDetails: api.GitHubApiCombinedDetails, apiDetails: api.GitHubApiCombinedDetails,
tempDir: string, tempDir: string,
): Promise<UserConfig> { ): Promise<UserConfig> {
const allowNewFormat = await actionState.features.getValue( if (isLocal(configFile)) {
Feature.NewRemoteFileAddresses,
);
if (isLocal(configFile, allowNewFormat)) {
if (configFile !== userConfigFromActionPath(tempDir)) { if (configFile !== userConfigFromActionPath(tempDir)) {
// If the config file is not generated by the Action, it should be relative to the workspace. // If the config file is not generated by the Action, it should be relative to the workspace.
configFile = path.resolve(workspacePath, configFile); configFile = path.resolve(workspacePath, configFile);
@@ -512,7 +508,7 @@ export async function loadUserConfig(
// Drop the explicit prefix if it is present. Since `REMOTE_PATH_PREFIX` is chosen // Drop the explicit prefix if it is present. Since `REMOTE_PATH_PREFIX` is chosen
// to not conflict with permissible characters in "owner" or "repo" components, // to not conflict with permissible characters in "owner" or "repo" components,
// this does not risk removing valid parts of either component by accident. // this does not risk removing valid parts of either component by accident.
if (allowNewFormat && isExplicitRemotePath(configFile)) { if (isExplicitRemotePath(configFile)) {
configFile = configFile.substring(REMOTE_PATH_PREFIX.length); configFile = configFile.substring(REMOTE_PATH_PREFIX.length);
} }
return await getRemoteConfig(actionState, configFile, apiDetails); return await getRemoteConfig(actionState, configFile, apiDetails);
@@ -1326,7 +1322,7 @@ function containsAtRef(configPath: string): boolean {
* @param configPath The path to test. * @param configPath The path to test.
* @returns True if it is local, or false otherwise. * @returns True if it is local, or false otherwise.
*/ */
function isLocal(configPath: string, allowNewFormat: boolean): boolean { function isLocal(configPath: string): boolean {
// If the path starts with `LOCAL_PATH_PREFIX`, it is explicitly local. // If the path starts with `LOCAL_PATH_PREFIX`, it is explicitly local.
// This allows local paths that would otherwise contain '@' // This allows local paths that would otherwise contain '@'
// to be used with a `LOCAL_PATH_PREFIX` prefix. // to be used with a `LOCAL_PATH_PREFIX` prefix.
@@ -1335,7 +1331,7 @@ function isLocal(configPath: string, allowNewFormat: boolean): boolean {
} }
// If the path starts with `REMOTE_PATH_PREFIX`, it is explicitly remote. // If the path starts with `REMOTE_PATH_PREFIX`, it is explicitly remote.
// This allows users to resolve ambiguity by specifying `REMOTE_PATH_PREFIX`. // This allows users to resolve ambiguity by specifying `REMOTE_PATH_PREFIX`.
if (allowNewFormat && isExplicitRemotePath(configPath)) { if (isExplicitRemotePath(configPath)) {
return false; return false;
} }

View File

@@ -108,7 +108,7 @@ test.serial("getRemoteConfig uses proxy when it is supposed to", async (t) => {
// Should use it when the FF is enabled and the environment variables are set. // Should use it when the FF is enabled and the environment variables are set.
await target await target
.withFeatures([Feature.ProxyApiRequests, Feature.NewRemoteFileAddresses]) .withFeatures([Feature.ProxyApiRequests])
.withEnv((env) => { .withEnv((env) => {
env.set(RegistryProxyVars.PROXY_HOST, "localhost"); env.set(RegistryProxyVars.PROXY_HOST, "localhost");
env.set(RegistryProxyVars.PROXY_PORT, "1234"); env.set(RegistryProxyVars.PROXY_PORT, "1234");
@@ -118,7 +118,6 @@ test.serial("getRemoteConfig uses proxy when it is supposed to", async (t) => {
// But not when the FF is not enabled. // But not when the FF is not enabled.
await target await target
.withFeatures([Feature.NewRemoteFileAddresses])
.withEnv((env) => { .withEnv((env) => {
env.set(RegistryProxyVars.PROXY_HOST, "localhost"); env.set(RegistryProxyVars.PROXY_HOST, "localhost");
env.set(RegistryProxyVars.PROXY_PORT, "1234"); env.set(RegistryProxyVars.PROXY_PORT, "1234");
@@ -128,7 +127,7 @@ test.serial("getRemoteConfig uses proxy when it is supposed to", async (t) => {
// And not when the environment variables aren't set. // And not when the environment variables aren't set.
await target await target
.withFeatures([Feature.ProxyApiRequests, Feature.NewRemoteFileAddresses]) .withFeatures([Feature.ProxyApiRequests])
.notLogs(t, "Using private registry proxy at 'http://localhost:1234'") .notLogs(t, "Using private registry proxy at 'http://localhost:1234'")
.throws(t, { message: errorMessage }); .throws(t, { message: errorMessage });
}); });

View File

@@ -2,8 +2,6 @@ import test from "ava";
import sinon from "sinon"; import sinon from "sinon";
import { ActionsEnvVars } from "../environment"; import { ActionsEnvVars } from "../environment";
import * as errors from "../error-messages";
import { Feature } from "../feature-flags";
import { callee } from "../testing-utils"; import { callee } from "../testing-utils";
import { ConfigurationError } from "../util"; import { ConfigurationError } from "../util";
@@ -75,15 +73,7 @@ test("parseRemoteFileAddress accepts full remote addresses", async (t) => {
for (const newFormatInput of newFormatInputs) { for (const newFormatInput of newFormatInputs) {
const targetWithArgs = target.withArgs(newFormatInput.input); const targetWithArgs = target.withArgs(newFormatInput.input);
// Should fail when the FF is not enabled. await targetWithArgs.passes(t.deepEqual, newFormatInput.expected);
await targetWithArgs
.withFeatures([])
.throws(t, { instanceOf: ConfigurationError });
// And pass when the FF is enabled.
await targetWithArgs
.withFeatures([Feature.NewRemoteFileAddresses])
.passes(t.deepEqual, newFormatInput.expected);
} }
}); });
@@ -138,15 +128,7 @@ test("parseRemoteFileAddress accepts remote address without an owner", async (t)
for (const testCase of testCases) { for (const testCase of testCases) {
const targetWithArgs = target.withArgs(testCase.input); const targetWithArgs = target.withArgs(testCase.input);
// Should fail when the FF is not enabled. await targetWithArgs.passes(t.deepEqual, testCase.expected);
await targetWithArgs
.withFeatures([])
.throws(t, { instanceOf: ConfigurationError });
// And pass when the FF is enabled.
await targetWithArgs
.withFeatures([Feature.NewRemoteFileAddresses])
.passes(t.deepEqual, testCase.expected);
} }
}); });
@@ -160,9 +142,7 @@ test("parseRemoteFileAddress throws for invalid `GITHUB_REPOSITORY`", async (t)
sinon.define(env, "getRequired", getRequired); sinon.define(env, "getRequired", getRequired);
}); });
await target await target.throws(t, { instanceOf: Error });
.withFeatures([Feature.NewRemoteFileAddresses])
.throws(t, { instanceOf: Error });
t.assert(getRequired.calledOnceWith(ActionsEnvVars.GITHUB_REPOSITORY)); t.assert(getRequired.calledOnceWith(ActionsEnvVars.GITHUB_REPOSITORY));
}); });
@@ -194,31 +174,19 @@ test("parseRemoteFileAddress accepts remote address without a path", async (t) =
for (const testCase of testCases) { for (const testCase of testCases) {
const targetWithArgs = target.withArgs(testCase.input); const targetWithArgs = target.withArgs(testCase.input);
// Should fail when the FF is not enabled. await targetWithArgs.passes(t.deepEqual, testCase.expected);
await targetWithArgs
.withFeatures([])
.throws(t, { instanceOf: ConfigurationError });
// And pass when the FF is enabled.
await targetWithArgs
.withFeatures([Feature.NewRemoteFileAddresses])
.passes(t.deepEqual, testCase.expected);
} }
}); });
test("parseRemoteFileAddress accepts remote address without a ref", async (t) => { test("parseRemoteFileAddress accepts remote address without a ref", async (t) => {
const target = callee(parseRemoteFileAddress).withArgs("owner/repo:path"); const target = callee(parseRemoteFileAddress).withArgs("owner/repo:path");
// Should only accept the input if the FF is enabled. await target.passes(t.deepEqual, {
await target.withFeatures([]).throws(t); owner: "owner",
await target repo: "repo",
.withFeatures([Feature.NewRemoteFileAddresses]) path: "path",
.passes(t.deepEqual, { ref: DEFAULT_CONFIG_FILE_REF,
owner: "owner", } satisfies RemoteFileAddress);
repo: "repo",
path: "path",
ref: DEFAULT_CONFIG_FILE_REF,
} satisfies RemoteFileAddress);
}); });
test("parseRemoteFileAddress rejects invalid values", async (t) => { test("parseRemoteFileAddress rejects invalid values", async (t) => {
@@ -251,18 +219,11 @@ test("parseRemoteFileAddress rejects invalid values", async (t) => {
for (const testInput of testInputs) { for (const testInput of testInputs) {
const targetWithArgs = target.withArgs(testInput); const targetWithArgs = target.withArgs(testInput);
// Should throw both when the new format is and isn't accepted. await targetWithArgs.throws(t, {
await targetWithArgs.withFeatures([]).throws(t, { // When the new format is accepted, there are some more specific
// errors in some cases. It is sufficient for us to check that
// an exception is thrown.
instanceOf: ConfigurationError, instanceOf: ConfigurationError,
message: errors.getConfigFileRepoOldFormatInvalidMessage(testInput),
}); });
await targetWithArgs
.withFeatures([Feature.NewRemoteFileAddresses])
.throws(t, {
// When the new format is accepted, there are some more specific
// errors in some cases. It is sufficient for us to check that
// an exception is thrown.
instanceOf: ConfigurationError,
});
} }
}); });

View File

@@ -1,7 +1,6 @@
import { ActionState } from "../action-common"; import { ActionState } from "../action-common";
import { ActionsEnvVars, ReadOnlyEnv } from "../environment"; import { ActionsEnvVars, ReadOnlyEnv } from "../environment";
import * as errorMessages from "../error-messages"; import * as errorMessages from "../error-messages";
import { Feature } from "../feature-flags";
import { ConfigurationError, Failure, Result, Success } from "../util"; import { ConfigurationError, Failure, Result, Success } from "../util";
/** Represents remote file addresses. */ /** Represents remote file addresses. */
@@ -126,16 +125,6 @@ export async function parseRemoteFileAddress(
return oldFormatAddressResult.value; return oldFormatAddressResult.value;
} }
// If the FF for the new format is not enabled, throw the old format error.
const allowNewFormat = await actionState.features.getValue(
Feature.NewRemoteFileAddresses,
);
if (!allowNewFormat) {
throw new ConfigurationError(
errorMessages.getConfigFileRepoOldFormatInvalidMessage(configFile),
);
}
// retrieve the various parts of the config location, and ensure they're present // retrieve the various parts of the config location, and ensure they're present
const newFormatAddressResult = parseNewRemoteFileAddress( const newFormatAddressResult = parseNewRemoteFileAddress(
actionState.env, actionState.env,

View File

@@ -94,8 +94,6 @@ export enum Feature {
ForceNightly = "force_nightly", ForceNightly = "force_nightly",
IgnoreGeneratedFiles = "ignore_generated_files", IgnoreGeneratedFiles = "ignore_generated_files",
JavaNetworkDebugging = "java_network_debugging", JavaNetworkDebugging = "java_network_debugging",
/** Allow the new remote file address format. */
NewRemoteFileAddresses = "new_remote_file_addresses",
OverlayAnalysis = "overlay_analysis", OverlayAnalysis = "overlay_analysis",
OverlayAnalysisCodeScanningCpp = "overlay_analysis_code_scanning_cpp", OverlayAnalysisCodeScanningCpp = "overlay_analysis_code_scanning_cpp",
OverlayAnalysisCodeScanningCsharp = "overlay_analysis_code_scanning_csharp", OverlayAnalysisCodeScanningCsharp = "overlay_analysis_code_scanning_csharp",
@@ -266,11 +264,6 @@ export const featureConfig = {
envVar: "CODEQL_ACTION_JAVA_NETWORK_DEBUGGING", envVar: "CODEQL_ACTION_JAVA_NETWORK_DEBUGGING",
minimumVersion: undefined, minimumVersion: undefined,
}, },
[Feature.NewRemoteFileAddresses]: {
defaultValue: false,
envVar: "CODEQL_ACTION_NEW_REMOTE_FILE_ADDRESSES",
minimumVersion: undefined,
},
[Feature.OverlayAnalysis]: { [Feature.OverlayAnalysis]: {
defaultValue: false, defaultValue: false,
envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS", envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS",