diff --git a/CHANGELOG.md b/CHANGELOG.md index a17b2bf66..56458aecc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ See the [releases page](https://github.com/github/codeql-action/releases) for th ## [UNRELEASED] -- Organizations can now create a custom repository property with the name `github-codeql-tools` to set the default CodeQL CLI tools value for their repositories. For more information, see [Managing custom properties for repositories in your organization](https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization), [Repository properties for Code Scanning](https://docs.github.com/en/code-security/concepts/code-scanning/repository-properties) and [Customizing your advanced setup for code scanning](https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning). +- Organizations can now create a custom repository property with the name `github-codeql-tools` to set the default CodeQL CLI tools value for dynamic workflows. If a workflow provides an explicit `tools:` input, that input takes precedence. For more information, see [Managing custom properties for repositories in your organization](https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization), [Repository properties for Code Scanning](https://docs.github.com/en/code-security/concepts/code-scanning/repository-properties) and [Customizing your advanced setup for code scanning](https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning). ## 4.36.0 - 22 May 2026 diff --git a/src/init-action.ts b/src/init-action.ts index 1d0e6c3c1..8d02aafe1 100644 --- a/src/init-action.ts +++ b/src/init-action.ts @@ -7,6 +7,7 @@ import * as semver from "semver"; import { v4 as uuidV4 } from "uuid"; import { + isDynamicWorkflow, FileCmdNotFoundError, getActionVersion, getFileType, @@ -297,9 +298,10 @@ async function run(startedAt: Date) { // Determine the effective tools input. // The explicit `tools` workflow input takes precedence. If none is provided, - // fall back to the 'github-codeql-tools' repository property (if set). + // fall back to the 'github-codeql-tools' repository property (if set) only for dynamic workflows. effectiveToolsInput = resolveToolsInput( getOptionalInput("tools"), + isDynamicWorkflow(), repositoryProperties, logger, ); diff --git a/src/resolve-tools-input.test.ts b/src/resolve-tools-input.test.ts index d281eb3d5..977199e0a 100644 --- a/src/resolve-tools-input.test.ts +++ b/src/resolve-tools-input.test.ts @@ -11,7 +11,7 @@ test("resolveToolsInput returns undefined when no tools input or repository prop const loggedMessages: LoggedMessage[] = []; const logger = getRecordingLogger(loggedMessages); - const result = resolveToolsInput(undefined, {}, logger); + const result = resolveToolsInput(undefined, true, {}, logger); t.is(result, undefined); t.is(loggedMessages.length, 0); @@ -21,7 +21,7 @@ test("resolveToolsInput returns workflow input when only workflow input is provi const loggedMessages: LoggedMessage[] = []; const logger = getRecordingLogger(loggedMessages); - const result = resolveToolsInput("latest", {}, logger); + const result = resolveToolsInput("latest", true, {}, logger); t.is(result, "latest"); t.is(loggedMessages.length, 1); @@ -38,7 +38,7 @@ test("resolveToolsInput returns repository property when only repository propert const repositoryProperties: RepositoryProperties = { [RepositoryPropertyName.TOOLS]: "toolcache", }; - const result = resolveToolsInput(undefined, repositoryProperties, logger); + const result = resolveToolsInput(undefined, true, repositoryProperties, logger); t.is(result, "toolcache"); t.is(loggedMessages.length, 1); @@ -55,7 +55,7 @@ test("resolveToolsInput prioritizes workflow input over repository property", (t const repositoryProperties: RepositoryProperties = { [RepositoryPropertyName.TOOLS]: "toolcache", }; - const result = resolveToolsInput("nightly", repositoryProperties, logger); + const result = resolveToolsInput("nightly", true, repositoryProperties, logger); t.is(result, "nightly"); t.is(loggedMessages.length, 1); @@ -72,7 +72,7 @@ test("resolveToolsInput treats empty string workflow input as not set", (t) => { const repositoryProperties: RepositoryProperties = { [RepositoryPropertyName.TOOLS]: "toolcache", }; - const result = resolveToolsInput("", repositoryProperties, logger); + const result = resolveToolsInput("", true, repositoryProperties, logger); t.is(result, "toolcache"); t.is(loggedMessages.length, 1); @@ -82,53 +82,6 @@ test("resolveToolsInput treats empty string workflow input as not set", (t) => { ); }); -test("resolveToolsInput returns workflow input with URL value", (t) => { - const loggedMessages: LoggedMessage[] = []; - const logger = getRecordingLogger(loggedMessages); - - const url = "https://example.com/codeql-bundle.tar.gz"; - const result = resolveToolsInput(url, {}, logger); - - t.is(result, url); - t.is(loggedMessages.length, 1); - t.is( - loggedMessages[0].message, - `Setting tools: ${url} based on workflow input.`, - ); -}); - -test("resolveToolsInput returns repository property with 'latest' value", (t) => { - const loggedMessages: LoggedMessage[] = []; - const logger = getRecordingLogger(loggedMessages); - - const repositoryProperties: RepositoryProperties = { - [RepositoryPropertyName.TOOLS]: "latest", - }; - const result = resolveToolsInput(undefined, repositoryProperties, logger); - - t.is(result, "latest"); - t.is( - loggedMessages[0].message, - "Setting tools: latest based on the 'github-codeql-tools' repository property.", - ); -}); - -test("resolveToolsInput returns repository property with specific version", (t) => { - const loggedMessages: LoggedMessage[] = []; - const logger = getRecordingLogger(loggedMessages); - - const repositoryProperties: RepositoryProperties = { - [RepositoryPropertyName.TOOLS]: "2.16.1", - }; - const result = resolveToolsInput(undefined, repositoryProperties, logger); - - t.is(result, "2.16.1"); - t.is( - loggedMessages[0].message, - "Setting tools: 2.16.1 based on the 'github-codeql-tools' repository property.", - ); -}); - test("resolveToolsInput returns undefined when repository property is undefined", (t) => { const loggedMessages: LoggedMessage[] = []; const logger = getRecordingLogger(loggedMessages); @@ -136,8 +89,27 @@ test("resolveToolsInput returns undefined when repository property is undefined" const repositoryProperties: RepositoryProperties = { [RepositoryPropertyName.TOOLS]: undefined, }; - const result = resolveToolsInput(undefined, repositoryProperties, logger); + const result = resolveToolsInput(undefined, true, repositoryProperties, logger); t.is(result, undefined); t.is(loggedMessages.length, 0); }); + +test("resolveToolsInput ignores repository property when fallback is disabled", (t) => { + const loggedMessages: LoggedMessage[] = []; + const logger = getRecordingLogger(loggedMessages); + + const repositoryProperties: RepositoryProperties = { + [RepositoryPropertyName.TOOLS]: "toolcache", + }; + const result = resolveToolsInput(undefined, false, repositoryProperties, logger); + + t.is(result, undefined); + t.is(loggedMessages.length, 1); + const fallbackDisabledMessage = String(loggedMessages[0].message); + t.true( + /Ignoring 'github-codeql-tools' repository property because it is only supported for (dynamic workflows|default setup)\./.test( + fallbackDisabledMessage, + ), + ); +}); diff --git a/src/resolve-tools-input.ts b/src/resolve-tools-input.ts index beff11a7c..6f4cbaddf 100644 --- a/src/resolve-tools-input.ts +++ b/src/resolve-tools-input.ts @@ -7,15 +7,17 @@ import { Logger } from "./logging"; /** * Resolves the effective tools input by combining the workflow input and repository properties. * The explicit `tools` workflow input takes precedence. If none is provided, - * falls back to the repository property (if set). + * falls back to the repository property (if set and enabled for this workflow). * * @param toolsWorkflowInput - The value of the `tools` workflow input, if provided. + * @param allowRepositoryPropertyFallback - Whether the repository property fallback is enabled. * @param repositoryProperties - The parsed repository properties. * @param logger - Logger for outputting resolution messages. * @returns The effective tools input value. */ export function resolveToolsInput( toolsWorkflowInput: string | undefined, + allowRepositoryPropertyFallback: boolean, repositoryProperties: RepositoryProperties, logger: Logger, ): string | undefined { @@ -26,6 +28,13 @@ export function resolveToolsInput( return toolsWorkflowInput; } + if (!allowRepositoryPropertyFallback) { + logger.info( + `No explicit tools input was provided. Ignoring '${RepositoryPropertyName.TOOLS}' repository property because it is only supported for dynamic workflows.`, + ); + return undefined; + } + const toolsPropertyValue = repositoryProperties[RepositoryPropertyName.TOOLS]; if (toolsPropertyValue) { logger.info( diff --git a/src/setup-codeql-action.ts b/src/setup-codeql-action.ts index f0a5c821c..ef30cebe8 100644 --- a/src/setup-codeql-action.ts +++ b/src/setup-codeql-action.ts @@ -2,6 +2,7 @@ import * as core from "@actions/core"; import { v4 as uuidV4 } from "uuid"; import { + isDynamicWorkflow, getActionVersion, getOptionalInput, getRequiredInput, @@ -156,9 +157,10 @@ async function run(startedAt: Date): Promise { // Determine the effective tools input. // The explicit `tools` workflow input takes precedence. If none is provided, - // fall back to the 'github-codeql-tools' repository property (if set). + // fall back to the 'github-codeql-tools' repository property (if set) only for dynamic workflows. effectiveToolsInput = resolveToolsInput( getOptionalInput("tools"), + isDynamicWorkflow(), repositoryProperties, logger, );