diff --git a/lib/entry-points.js b/lib/entry-points.js index 7ff11d2666..adafe10b88 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -182119,7 +182119,7 @@ function combineQueries(logger2, config, augmentationProperties) { } return result; } -function generateCodeScanningConfig(logger2, originalUserInput, augmentationProperties) { +function generateCodeScanningConfig(logger2, originalUserInput, augmentationProperties, languages) { const augmentedConfig = cloneObject(originalUserInput); augmentedConfig.queries = combineQueries( logger2, @@ -182141,8 +182141,8 @@ function generateCodeScanningConfig(logger2, originalUserInput, augmentationProp } else if (!augmentedConfig.packs) { augmentedConfig.packs = augmentationProperties.packsInput; } else { - const language = Object.keys(augmentedConfig.packs)[0]; - augmentedConfig.packs[language] = augmentedConfig.packs[language].concat(augmentationProperties.packsInput); + const language = languages[0]; + augmentedConfig.packs[language] = (augmentedConfig.packs[language] ?? []).concat(augmentationProperties.packsInput); } } else { augmentedConfig.packs = augmentationProperties.packsInput; @@ -183061,7 +183061,8 @@ async function initActionState({ const computedConfig = generateCodeScanningConfig( logger2, userConfig, - augmentationProperties + augmentationProperties, + languages ); return { version: getActionVersion(), diff --git a/src/codeql.test.ts b/src/codeql.test.ts index d39b9a60d5..bd13697f97 100644 --- a/src/codeql.test.ts +++ b/src/codeql.test.ts @@ -668,6 +668,7 @@ const injectedConfigMacro = makeMacro({ new RecordingLogger(), thisStubConfig.originalUserInput, augmentationProperties, + thisStubConfig.languages, ); await codeqlObject.databaseInitCluster( @@ -737,6 +738,54 @@ injectedConfigMacro.serial( }, ); +const additivePackConfigurations: Array> = [ + { + javascript: ["acme/javascript-queries"], + python: ["acme/python-queries"], + }, + { + python: ["acme/python-queries"], + javascript: ["acme/javascript-queries"], + }, + { javascript: ["acme/javascript-queries"] }, + { javascript: ["acme/javascript-queries"], python: [] }, + {}, +]; +for (const packs of additivePackConfigurations) { + injectedConfigMacro.serial( + `additive packs target the analyzed language in ${JSON.stringify(packs)}`, + { + ...defaultAugmentationProperties, + packsInputCombines: true, + packsInput: ["acme/python-extra"], + }, + { + languages: [BuiltInLanguage.python], + originalUserInput: { packs }, + }, + { + packs: { + ...packs, + python: [...(packs.python || []), "acme/python-extra"], + }, + }, + ); +} + +injectedConfigMacro.serial( + "additive packs preserve an existing array", + { + ...defaultAugmentationProperties, + packsInputCombines: true, + packsInput: ["acme/python-extra"], + }, + { + languages: [BuiltInLanguage.python], + originalUserInput: { packs: ["acme/python-queries"] }, + }, + { packs: ["acme/python-queries", "acme/python-extra"] }, +); + injectedConfigMacro.serial( "injected packs from input with existing packs overrides", { diff --git a/src/config-utils.test.ts b/src/config-utils.test.ts index b66d4a797e..5e79ecbac7 100644 --- a/src/config-utils.test.ts +++ b/src/config-utils.test.ts @@ -622,6 +622,47 @@ test.serial( }, ); +test.serial( + "additive packs use the job language with a shared config file", + async (t) => { + await withTmpDir(async (tempDir) => { + setupActionsVars(tempDir, tempDir); + const userConfig: UserConfig = { + packs: { + javascript: ["acme/javascript-queries"], + python: ["acme/python-queries"], + }, + }; + const codeql = createStubCodeQL({ + async resolveLanguages() { + return { + extractors: { python: [{ extractor_root: "" }] }, + }; + }, + }); + const config = await configUtils.initConfig( + initAllState(), + createTestInitConfigInputs({ + languagesInput: "python", + packsInput: "+acme/python-extra", + configFile: createConfigFile(yaml.dump(userConfig), tempDir), + tempDir, + codeql, + workspacePath: tempDir, + }), + ); + + t.deepEqual(config.computedConfig, { + packs: { + javascript: ["acme/javascript-queries"], + python: ["acme/python-queries", "acme/python-extra"], + }, + }); + t.deepEqual(config.originalUserInput, userConfig); + }); + }, +); + test.serial("API client used when reading remote config", async (t) => { return await withTmpDir(async (tempDir) => { const codeql = createStubCodeQL({ diff --git a/src/config-utils.ts b/src/config-utils.ts index b59149e47f..0ea52e5158 100644 --- a/src/config-utils.ts +++ b/src/config-utils.ts @@ -437,6 +437,7 @@ export async function initActionState( logger, userConfig, augmentationProperties, + languages, ); return { diff --git a/src/config/db-config.ts b/src/config/db-config.ts index 91a97db4ec..24dc1f73c4 100644 --- a/src/config/db-config.ts +++ b/src/config/db-config.ts @@ -588,6 +588,7 @@ export function generateCodeScanningConfig( logger: Logger, originalUserInput: UserConfig, augmentationProperties: AugmentationProperties, + languages: Language[], ): UserConfig { // make a copy so we can modify it const augmentedConfig = cloneObject(originalUserInput); @@ -616,12 +617,10 @@ export function generateCodeScanningConfig( } else if (!augmentedConfig.packs) { augmentedConfig.packs = augmentationProperties.packsInput; } else { - // At this point, we know there is only one language. - // If there were more than one language, an error would already have been thrown. - const language = Object.keys(augmentedConfig.packs)[0]; - augmentedConfig.packs[language] = augmentedConfig.packs[ - language - ].concat(augmentationProperties.packsInput); + const language = languages[0]; + augmentedConfig.packs[language] = ( + augmentedConfig.packs[language] ?? [] + ).concat(augmentationProperties.packsInput); } } else { augmentedConfig.packs = augmentationProperties.packsInput; diff --git a/tests/multi-language-repo/.github/codeql/codeql-config-packaging3.yml b/tests/multi-language-repo/.github/codeql/codeql-config-packaging3.yml index 2a75653212..83374f6679 100644 --- a/tests/multi-language-repo/.github/codeql/codeql-config-packaging3.yml +++ b/tests/multi-language-repo/.github/codeql/codeql-config-packaging3.yml @@ -2,6 +2,8 @@ name: Pack testing in the CodeQL Action disable-default-queries: true packs: + ruby: + - codeql/ruby-queries javascript: - codeql-testing/codeql-pack2 - codeql-testing/codeql-pack3:other-query.ql diff --git a/unreleased-change-notes/fix-pack-language-merge.md b/unreleased-change-notes/fix-pack-language-merge.md new file mode 100644 index 0000000000..a740cf6b1e --- /dev/null +++ b/unreleased-change-notes/fix-pack-language-merge.md @@ -0,0 +1 @@ +- Fixed additive `packs` inputs being applied to the wrong language when a shared configuration file lists packs for multiple languages.