diff --git a/lib/init-action.js b/lib/init-action.js index 0ea051433..6579713b3 100644 --- a/lib/init-action.js +++ b/lib/init-action.js @@ -88056,7 +88056,7 @@ function generateCodeScanningConfig(logger, originalUserInput, augmentationPrope } return augmentedConfig; } -function parseUserConfig(pathInput, contents) { +function parseUserConfig(logger, pathInput, contents) { try { const schema2 = ( // eslint-disable-next-line @typescript-eslint/no-require-imports @@ -88065,10 +88065,13 @@ function parseUserConfig(pathInput, contents) { const doc = load(contents); const result = new jsonschema.Validator().validate(doc, schema2); if (result.errors.length > 0) { + for (const error2 of result.errors) { + logger.error(error2.stack); + } throw new ConfigurationError( getInvalidConfigFileMessage( pathInput, - `The configuration file contained ${result.errors.length} error(s)` + `There are ${result.errors.length} error(s)` ) ); } @@ -89284,7 +89287,7 @@ async function downloadCacheWithTime(trapCachingEnabled, codeQL, languages, logg } return { trapCaches, trapCacheDownloadTime }; } -async function loadUserConfig(configFile, workspacePath, apiDetails, tempDir) { +async function loadUserConfig(logger, configFile, workspacePath, apiDetails, tempDir) { if (isLocal(configFile)) { if (configFile !== userConfigFromActionPath(tempDir)) { configFile = path11.resolve(workspacePath, configFile); @@ -89294,9 +89297,9 @@ async function loadUserConfig(configFile, workspacePath, apiDetails, tempDir) { ); } } - return getLocalConfig(configFile); + return getLocalConfig(logger, configFile); } else { - return await getRemoteConfig(configFile, apiDetails); + return await getRemoteConfig(logger, configFile, apiDetails); } } var OVERLAY_ANALYSIS_FEATURES = { @@ -89443,6 +89446,7 @@ async function initConfig(inputs) { } else { logger.debug(`Using configuration file: ${inputs.configFile}`); userConfig = await loadUserConfig( + logger, inputs.configFile, inputs.workspacePath, inputs.apiDetails, @@ -89508,15 +89512,19 @@ function isLocal(configPath) { } return configPath.indexOf("@") === -1; } -function getLocalConfig(configFile) { +function getLocalConfig(logger, configFile) { if (!fs9.existsSync(configFile)) { throw new ConfigurationError( getConfigFileDoesNotExistErrorMessage(configFile) ); } - return parseUserConfig(configFile, fs9.readFileSync(configFile, "utf-8")); + return parseUserConfig( + logger, + configFile, + fs9.readFileSync(configFile, "utf-8") + ); } -async function getRemoteConfig(configFile, apiDetails) { +async function getRemoteConfig(logger, configFile, apiDetails) { const format = new RegExp( "(?[^/]+)/(?[^/]+)/(?[^@]+)@(?.*)" ); @@ -89545,6 +89553,7 @@ async function getRemoteConfig(configFile, apiDetails) { ); } return parseUserConfig( + logger, configFile, Buffer.from(fileContents, "base64").toString("binary") ); diff --git a/src/config-utils.ts b/src/config-utils.ts index 1c0346340..121eae324 100644 --- a/src/config-utils.ts +++ b/src/config-utils.ts @@ -526,6 +526,7 @@ async function downloadCacheWithTime( } async function loadUserConfig( + logger: Logger, configFile: string, workspacePath: string, apiDetails: api.GitHubApiCombinedDetails, @@ -542,9 +543,9 @@ async function loadUserConfig( ); } } - return getLocalConfig(configFile); + return getLocalConfig(logger, configFile); } else { - return await getRemoteConfig(configFile, apiDetails); + return await getRemoteConfig(logger, configFile, apiDetails); } } @@ -801,6 +802,7 @@ export async function initConfig(inputs: InitConfigInputs): Promise { } else { logger.debug(`Using configuration file: ${inputs.configFile}`); userConfig = await loadUserConfig( + logger, inputs.configFile, inputs.workspacePath, inputs.apiDetails, @@ -898,7 +900,7 @@ function isLocal(configPath: string): boolean { return configPath.indexOf("@") === -1; } -function getLocalConfig(configFile: string): UserConfig { +function getLocalConfig(logger: Logger, configFile: string): UserConfig { // Error if the file does not exist if (!fs.existsSync(configFile)) { throw new ConfigurationError( @@ -906,10 +908,15 @@ function getLocalConfig(configFile: string): UserConfig { ); } - return parseUserConfig(configFile, fs.readFileSync(configFile, "utf-8")); + return parseUserConfig( + logger, + configFile, + fs.readFileSync(configFile, "utf-8"), + ); } async function getRemoteConfig( + logger: Logger, configFile: string, apiDetails: api.GitHubApiCombinedDetails, ): Promise { @@ -948,6 +955,7 @@ async function getRemoteConfig( } return parseUserConfig( + logger, configFile, Buffer.from(fileContents, "base64").toString("binary"), ); diff --git a/src/config/db-config.test.ts b/src/config/db-config.test.ts index 1308dbb4e..f6f73b311 100644 --- a/src/config/db-config.test.ts +++ b/src/config/db-config.test.ts @@ -2,6 +2,12 @@ import test, { ExecutionContext } from "ava"; import { RepositoryProperties } from "../feature-flags/properties"; import { KnownLanguage, Language } from "../languages"; +import { getRunnerLogger } from "../logging"; +import { + checkExpectedLogMessages, + getRecordingLogger, + LoggedMessage, +} from "../testing-utils"; import { ConfigurationError, prettyPrintPack } from "../util"; import * as dbConfig from "./db-config"; @@ -394,6 +400,7 @@ test( test("parseUserConfig - successfully parses valid YAML", (t) => { const result = dbConfig.parseUserConfig( + getRunnerLogger(true), "test", ` paths-ignore: @@ -418,6 +425,7 @@ test("parseUserConfig - throws a ConfigurationError if the file is not valid YAM t.throws( () => dbConfig.parseUserConfig( + getRunnerLogger(true), "test", ` paths-ignore: @@ -431,3 +439,27 @@ test("parseUserConfig - throws a ConfigurationError if the file is not valid YAM }, ); }); + +test("parseUserConfig - throws a ConfigurationError if validation fails", (t) => { + const loggedMessages: LoggedMessage[] = []; + const logger = getRecordingLogger(loggedMessages); + + t.throws( + () => + dbConfig.parseUserConfig( + logger, + "test", + ` + paths-ignore: + - "some/path" + queries: true + `, + ), + { + instanceOf: ConfigurationError, + }, + ); + + const expectedMessages = ["instance.queries is not of a type(s) array"]; + checkExpectedLogMessages(t, loggedMessages, expectedMessages); +}); diff --git a/src/config/db-config.ts b/src/config/db-config.ts index 3d7a8f471..b20c4fbee 100644 --- a/src/config/db-config.ts +++ b/src/config/db-config.ts @@ -480,12 +480,14 @@ export function generateCodeScanningConfig( /** * Attempts to parse `contents` into a `UserConfig` value. * + * @param logger The logger to use. * @param pathInput The path to the file where `contents` was obtained from, for use in error messages. * @param contents The string contents of a YAML file to try and parse as a `UserConfig`. * @returns The `UserConfig` corresponding to `contents`, if parsing was successful. * @throws A `ConfigurationError` if parsing failed. */ export function parseUserConfig( + logger: Logger, pathInput: string, contents: string, ): UserConfig { @@ -498,10 +500,13 @@ export function parseUserConfig( const result = new jsonschema.Validator().validate(doc, schema); if (result.errors.length > 0) { + for (const error of result.errors) { + logger.error(error.stack); + } throw new ConfigurationError( errorMessages.getInvalidConfigFileMessage( pathInput, - `The configuration file contained ${result.errors.length} error(s)`, + `There are ${result.errors.length} error(s)`, ), ); }