Check what the config input sets instead of exempting dynamic workflows

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Henry Mercer
2026-10-01 17:59:47 +01:00
parent 1bb99cb5c7
commit a6cd2a544a
6 changed files with 108 additions and 31 deletions

21
lib/entry-points.js generated
View File

@@ -149268,6 +149268,22 @@ var DEFAULT_SETUP_CONFIG_SCHEMA = {
object(DEFAULT_SETUP_SCHEMA)
)
};
function matchesDefaultSetupConfigSchema(contents) {
let config;
try {
config = load(contents);
} catch (error3) {
if (error3 instanceof YAMLException) {
return false;
}
throw error3;
}
if (!isObject(config)) {
return false;
}
const result = checkSchema(DEFAULT_SETUP_CONFIG_SCHEMA, config);
return result.valid && result.unknownKeys.length === 0;
}
function mergeDefaultSetupAndUserConfigs(logger, fromConfigInput, fromConfigFile) {
logger.debug(
"Combining configuration files from 'config' and 'config-file' inputs"
@@ -151614,7 +151630,7 @@ function getOtherLanguagePacksReason(inputs) {
if (inputs.configFile !== void 0) {
return `the configuration file '${inputs.configFile}' may use queries that need library packs for other languages`;
}
if (inputs.configInput !== void 0 && !inputs.isDynamicWorkflow) {
if (inputs.configInput !== void 0 && !matchesDefaultSetupConfigSchema(inputs.configInput)) {
return "the 'config' input may use queries that need library packs for other languages";
}
const query = findNonBuiltInQuery(
@@ -162399,8 +162415,7 @@ async function run3(actionState) {
configFile,
configInput,
queriesInput,
extraQueriesProperty: repositoryProperties["github-codeql-extra-queries" /* EXTRA_QUERIES */],
isDynamicWorkflow: isDynamicWorkflow(actionState.env)
extraQueriesProperty: repositoryProperties["github-codeql-extra-queries" /* EXTRA_QUERIES */]
});
const useOverlayAwareDefaultCliVersion = analysisKinds?.length === 1 && analysisKinds[0] === "code-scanning" /* CodeScanning */;
const initCodeQLResult = await initCodeQL(

View File

@@ -625,3 +625,43 @@ test("mergeDefaultSetupAndUserConfigs - warns about invalid keys from Default Se
`Invalid keys in Default Setup configuration: ${expectedInvalidKeys}`,
]);
});
test("matchesDefaultSetupConfigSchema - returns true for configurations that only use Default Setup properties", (t) => {
for (const contents of [
[
"default-setup:",
" org:",
" model-packs: [ github/immutable-actions-list@0.0.1 ]",
"threat-models: [ ]",
].join("\n"),
"threat-models: [ local ]",
"{}",
]) {
t.true(dbConfig.matchesDefaultSetupConfigSchema(contents), contents);
}
});
test("matchesDefaultSetupConfigSchema - returns false for configurations that use other properties", (t) => {
for (const contents of [
"queries: [ { uses: ./queries/show_ifs.ql } ]",
"paths-ignore: [ tests ]",
"default-setup: { org: { model-packs: [], queries: [] } }",
]) {
t.false(dbConfig.matchesDefaultSetupConfigSchema(contents), contents);
}
});
test("matchesDefaultSetupConfigSchema - returns false for invalid Default Setup properties", (t) => {
for (const contents of [
"threat-models: local",
"default-setup: { org: { model-packs: [ 1 ] } }",
]) {
t.false(dbConfig.matchesDefaultSetupConfigSchema(contents), contents);
}
});
test("matchesDefaultSetupConfigSchema - returns false for contents that aren't a YAML object", (t) => {
for (const contents of ["threat-models: [", "- threat-models", "local", ""]) {
t.false(dbConfig.matchesDefaultSetupConfigSchema(contents), contents);
}
});

View File

@@ -94,6 +94,28 @@ const DEFAULT_SETUP_CONFIG_SCHEMA = {
),
} as const satisfies json.Schema;
/**
* Returns whether `contents` is a YAML mapping that only sets the properties that Default Setup
* uses, which are threat models and model packs, to valid values. Returns `false` otherwise,
* including if `contents` isn't valid YAML.
*/
export function matchesDefaultSetupConfigSchema(contents: string): boolean {
let config: unknown;
try {
config = yaml.load(contents);
} catch (error) {
if (error instanceof yaml.YAMLException) {
return false;
}
throw error;
}
if (!json.isObject(config)) {
return false;
}
const result = json.checkSchema(DEFAULT_SETUP_CONFIG_SCHEMA, config);
return result.valid && result.unknownKeys.length === 0;
}
/**
* Merges supported properties from two configuration files. This is intended only for
* use with merging the `config` input provided by Default Setup with a potentially

View File

@@ -13,7 +13,6 @@ import {
getOptionalInput,
getRequiredInput,
getTemporaryDirectory,
isDynamicWorkflow,
persistInputs,
} from "./actions-util";
import { AnalysisKind, getAnalysisKinds } from "./analyses";
@@ -315,7 +314,6 @@ async function run(
queriesInput,
extraQueriesProperty:
repositoryProperties[RepositoryPropertyName.EXTRA_QUERIES],
isDynamicWorkflow: isDynamicWorkflow(actionState.env),
});
const useOverlayAwareDefaultCliVersion =
analysisKinds?.length === 1 &&

View File

@@ -199,7 +199,6 @@ const NO_QUERY_CONFIG: QueryConfigInputs = {
configInput: undefined,
queriesInput: undefined,
extraQueriesProperty: undefined,
isDynamicWorkflow: false,
};
test("getOtherLanguagePacksReason returns undefined when no queries are configured", (t) => {
@@ -224,33 +223,34 @@ test("getOtherLanguagePacksReason returns undefined for built-in query suites",
}
});
test("getOtherLanguagePacksReason returns undefined for the config input in a dynamic workflow", (t) => {
test("getOtherLanguagePacksReason returns undefined for a config input that only uses default setup properties", (t) => {
t.is(
getOtherLanguagePacksReason({
...NO_QUERY_CONFIG,
configInput: "threat-models: [ local ]",
isDynamicWorkflow: true,
// The shape of the `config` input that default setup passes.
configInput: [
"default-setup:",
" org:",
" model-packs: [ github/immutable-actions-list@0.0.1 ]",
"threat-models: [ ]",
].join("\n"),
}),
undefined,
);
});
test("getOtherLanguagePacksReason explains a configuration file, including in a dynamic workflow", (t) => {
// Default setup can get a configuration file from a repository property.
for (const isDynamicWorkflow of [false, true]) {
t.is(
getOtherLanguagePacksReason({
...NO_QUERY_CONFIG,
configFile: "./.github/codeql/codeql-config.yml",
isDynamicWorkflow,
}),
"the configuration file './.github/codeql/codeql-config.yml' may use queries that need " +
"library packs for other languages",
);
}
test("getOtherLanguagePacksReason explains a configuration file", (t) => {
t.is(
getOtherLanguagePacksReason({
...NO_QUERY_CONFIG,
configFile: "./.github/codeql/codeql-config.yml",
}),
"the configuration file './.github/codeql/codeql-config.yml' may use queries that need " +
"library packs for other languages",
);
});
test("getOtherLanguagePacksReason explains the config input outside a dynamic workflow", (t) => {
test("getOtherLanguagePacksReason explains a config input that uses other properties", (t) => {
t.is(
getOtherLanguagePacksReason({
...NO_QUERY_CONFIG,

View File

@@ -4,6 +4,7 @@ import { ActionState } from "./action-common";
import { isGitHubHostedRunner } from "./actions-util";
import {
defaultSuites,
matchesDefaultSetupConfigSchema,
parseExtraQueriesProperty,
parseQueriesInput,
QuerySpec,
@@ -48,8 +49,6 @@ export interface QueryConfigInputs {
queriesInput: string | undefined;
/** The `github-codeql-extra-queries` repository property. */
extraQueriesProperty: string | undefined;
/** Whether the Action is running in a dynamic workflow, such as default setup. */
isDynamicWorkflow: boolean;
}
/**
@@ -58,8 +57,9 @@ export interface QueryConfigInputs {
* queries that these inputs add are built-in query suites. The `packs` input doesn't matter, since
* query packs are downloaded together with their dependencies.
*
* The configuration isn't loaded until CodeQL is set up, so any configuration file or `config`
* input is assumed to configure such queries, except for the `config` input in dynamic workflows.
* Any configuration file is assumed to configure such queries, since reading it may need file or API
* access. The `config` input is only assumed to if it sets anything other than valid threat models
* and model packs, which are the properties that default setup uses.
*
* @throws A `ConfigurationError` if the `queries` input or the `github-codeql-extra-queries`
* repository property is a '+' with no queries after it, unless an input that's checked earlier
@@ -75,10 +75,12 @@ export function getOtherLanguagePacksReason(
);
}
// The `config` input can configure queries in the same way as a configuration file. We assume
// that dynamic workflows, which GitHub manages, don't use it to add queries. For example, default
// setup only uses it for threat models and model packs.
if (inputs.configInput !== undefined && !inputs.isDynamicWorkflow) {
// The `config` input can configure queries in the same way as a configuration file. Default
// setup only uses it for threat models and model packs, neither of which adds queries.
if (
inputs.configInput !== undefined &&
!matchesDefaultSetupConfigSchema(inputs.configInput)
) {
return "the 'config' input may use queries that need library packs for other languages";
}