diff --git a/lib/entry-points.js b/lib/entry-points.js index 7ff11d2666..9ce56766da 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -182321,7 +182321,7 @@ async function getRemoteConfig(actionState, configFile, apiDetails) { return parseUserConfig( actionState.logger, configFile, - Buffer.from(fileContents, "base64").toString("binary"), + Buffer.from(fileContents, "base64").toString("utf8"), validateConfig ); } diff --git a/src/config/file.test.ts b/src/config/file.test.ts index 0833ad3d06..21c97235a6 100644 --- a/src/config/file.test.ts +++ b/src/config/file.test.ts @@ -108,6 +108,67 @@ test("getConfigFileInput ignores repository property value when FF is off", asyn .passes(t.is, undefined); }); +for (const { name, contents } of [ + ...["Security", "Sécurité", "日本語", "🛡️"].map((configName) => ({ + name: configName, + contents: `name: ${configName} +paths: + - "src/${configName}" +paths-ignore: + - "generated/${configName}" +`, + })), + { + name: "Café", + contents: `name: "Caf\\u00e9" +paths: + - "src/Caf\\u00e9" +paths-ignore: + - "generated/Caf\\u00e9" +`, + }, +]) { + test.serial( + `getRemoteConfig preserves UTF-8 configuration: ${name}`, + async (t) => { + const configFile = "octo-org/codeql-config/config.yml@main"; + const config = { + name, + paths: [`src/${name}`], + "paths-ignore": [`generated/${name}`], + }; + const client = github.getOctokit("123"); + const response = { + data: { + content: Buffer.from(contents, "utf8").toString("base64"), + encoding: "base64", + }, + }; + const getContent = sinon + .stub(client.rest.repos, "getContent") + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + .resolves(response as any); + sinon.stub(api, "getApiClientWithExternalAuth").returns(client); + + for (const features of [[], [Feature.ValidateDbConfig]]) { + await callee(getRemoteConfig) + .withFeatures(features) + .withArgs(configFile, SAMPLE_DOTCOM_API_DETAILS) + .passes(t.deepEqual, config); + } + + t.assert( + getContent.alwaysCalledWithExactly({ + owner: "octo-org", + repo: "codeql-config", + path: "config.yml", + ref: "main", + }), + ); + }, + ); +} + test.serial("getRemoteConfig uses proxy when it is supposed to", async (t) => { const client = github.getOctokit("123"); const response = { diff --git a/src/config/file.ts b/src/config/file.ts index be0e415a38..a4a69ac2b9 100644 --- a/src/config/file.ts +++ b/src/config/file.ts @@ -131,7 +131,7 @@ export async function getRemoteConfig( return parseUserConfig( actionState.logger, configFile, - Buffer.from(fileContents, "base64").toString("binary"), + Buffer.from(fileContents, "base64").toString("utf8"), validateConfig, ); } diff --git a/unreleased-change-notes/fix-remote-config-utf8.md b/unreleased-change-notes/fix-remote-config-utf8.md new file mode 100644 index 0000000000..e267f3f254 --- /dev/null +++ b/unreleased-change-notes/fix-remote-config-utf8.md @@ -0,0 +1 @@ +- Fixed remote configuration files corrupting Unicode names and paths or failing to parse when they contain non-ASCII characters.