diff --git a/lib/entry-points.js b/lib/entry-points.js index 83c1d99b3..0901767d7 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -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( diff --git a/src/config/db-config.test.ts b/src/config/db-config.test.ts index 63d9d2ffe..ecf77194a 100644 --- a/src/config/db-config.test.ts +++ b/src/config/db-config.test.ts @@ -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); + } +}); diff --git a/src/config/db-config.ts b/src/config/db-config.ts index 4b1ed5479..38cc74ab2 100644 --- a/src/config/db-config.ts +++ b/src/config/db-config.ts @@ -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 diff --git a/src/init-action.ts b/src/init-action.ts index 311127024..e1ac5df5e 100644 --- a/src/init-action.ts +++ b/src/init-action.ts @@ -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 && diff --git a/src/per-language-bundles.test.ts b/src/per-language-bundles.test.ts index 63e01d0dc..c94b8d6db 100644 --- a/src/per-language-bundles.test.ts +++ b/src/per-language-bundles.test.ts @@ -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, diff --git a/src/per-language-bundles.ts b/src/per-language-bundles.ts index d85c3f892..371787901 100644 --- a/src/per-language-bundles.ts +++ b/src/per-language-bundles.ts @@ -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"; }