From 28a1ea5b1d9c402a89892c4585a9d5ad30b70dc3 Mon Sep 17 00:00:00 2001 From: Steve Goodwin Date: Mon, 16 Mar 2026 16:45:41 -0400 Subject: [PATCH 1/2] Fix Chinese characters rendering as escape codes in alert messages Assisted by Claude --- .../fetch/__tests__/console-fetch.spec.ts | 22 ++++++++++++++++++- .../src/utils/fetch/console-fetch-utils.ts | 11 +++++++++- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/frontend/packages/console-dynamic-plugin-sdk/src/utils/fetch/__tests__/console-fetch.spec.ts b/frontend/packages/console-dynamic-plugin-sdk/src/utils/fetch/__tests__/console-fetch.spec.ts index 12d298c40f6..53d0f0e0211 100644 --- a/frontend/packages/console-dynamic-plugin-sdk/src/utils/fetch/__tests__/console-fetch.spec.ts +++ b/frontend/packages/console-dynamic-plugin-sdk/src/utils/fetch/__tests__/console-fetch.spec.ts @@ -1,6 +1,26 @@ import { RetryError } from '../../error/http-error'; import { consoleFetch } from '../console-fetch'; -import { shouldLogout, validateStatus } from '../console-fetch-utils'; +import { shouldLogout, unescapeGoUnicode, validateStatus } from '../console-fetch-utils'; + +describe('unescapeGoUnicode', () => { + it('should unescape 4-digit Go unicode escapes', () => { + expect(unescapeGoUnicode('\\ue00f')).toBe('\ue00f'); + expect(unescapeGoUnicode('\\ue4c8')).toBe('\ue4c8'); + }); + + it('should unescape 8-digit Go unicode escapes for supplementary plane characters', () => { + expect(unescapeGoUnicode('\\U0002ebf0')).toBe(String.fromCodePoint(0x2ebf0)); + expect(unescapeGoUnicode('\\U0002ebf1')).toBe(String.fromCodePoint(0x2ebf1)); + }); + + it('should unescape mixed content with normal text and escapes', () => { + const input = 'a啊阿沸犯跃kg\\ue00f\\ue010\\ue011\\ue4c8丙乩h妖哪匸与f去\\U0002ebf0\\U0002ebf1'; + const expected = `a啊阿沸犯跃kg\ue00f\ue010\ue011\ue4c8丙乩h妖哪匸与f去${String.fromCodePoint( + 0x2ebf0, + )}${String.fromCodePoint(0x2ebf1)}`; + expect(unescapeGoUnicode(input)).toBe(expected); + }); +}); describe('consoleFetch', () => { const json = async () => ({ diff --git a/frontend/packages/console-dynamic-plugin-sdk/src/utils/fetch/console-fetch-utils.ts b/frontend/packages/console-dynamic-plugin-sdk/src/utils/fetch/console-fetch-utils.ts index fc3c5cfe5d7..3e4ffbca4b1 100644 --- a/frontend/packages/console-dynamic-plugin-sdk/src/utils/fetch/console-fetch-utils.ts +++ b/frontend/packages/console-dynamic-plugin-sdk/src/utils/fetch/console-fetch-utils.ts @@ -146,6 +146,15 @@ export const shouldLogout = (url: string): boolean => { return false; }; +/** + * Converts Go-style Unicode escape sequences (\uXXXX, \UXXXXXXXX) in K8s API error + * messages back to actual Unicode characters for proper display in the browser. + */ +export const unescapeGoUnicode = (str: string): string => + str + .replace(/\\U([0-9a-fA-F]{8})/g, (_, hex) => String.fromCodePoint(parseInt(hex, 16))) + .replace(/\\u([0-9a-fA-F]{4})/g, (_, hex) => String.fromCodePoint(parseInt(hex, 16))); + export const validateStatus = async ( response: Response, url: string, @@ -217,6 +226,6 @@ export const validateStatus = async ( reason = response.statusText; } - throw new HttpError(reason, response.status, response, json); + throw new HttpError(unescapeGoUnicode(reason), response.status, response, json); }); }; From 7e34460fdafae8134ac3e9c3e6dd597c74cd7729 Mon Sep 17 00:00:00 2001 From: Steve Goodwin Date: Tue, 17 Mar 2026 09:51:24 -0400 Subject: [PATCH 2/2] Address review comments --- .../src/utils/fetch/__tests__/console-fetch.spec.ts | 4 ++++ .../src/utils/fetch/console-fetch-utils.ts | 7 +++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/frontend/packages/console-dynamic-plugin-sdk/src/utils/fetch/__tests__/console-fetch.spec.ts b/frontend/packages/console-dynamic-plugin-sdk/src/utils/fetch/__tests__/console-fetch.spec.ts index 53d0f0e0211..0cea5359eb5 100644 --- a/frontend/packages/console-dynamic-plugin-sdk/src/utils/fetch/__tests__/console-fetch.spec.ts +++ b/frontend/packages/console-dynamic-plugin-sdk/src/utils/fetch/__tests__/console-fetch.spec.ts @@ -20,6 +20,10 @@ describe('unescapeGoUnicode', () => { )}${String.fromCodePoint(0x2ebf1)}`; expect(unescapeGoUnicode(input)).toBe(expected); }); + + it('should not throw on out-of-range 8-digit escape sequences', () => { + expect(unescapeGoUnicode('\\UFFFFFFFF')).toBe('\\UFFFFFFFF'); + }); }); describe('consoleFetch', () => { diff --git a/frontend/packages/console-dynamic-plugin-sdk/src/utils/fetch/console-fetch-utils.ts b/frontend/packages/console-dynamic-plugin-sdk/src/utils/fetch/console-fetch-utils.ts index 3e4ffbca4b1..52b9f3823c0 100644 --- a/frontend/packages/console-dynamic-plugin-sdk/src/utils/fetch/console-fetch-utils.ts +++ b/frontend/packages/console-dynamic-plugin-sdk/src/utils/fetch/console-fetch-utils.ts @@ -152,7 +152,10 @@ export const shouldLogout = (url: string): boolean => { */ export const unescapeGoUnicode = (str: string): string => str - .replace(/\\U([0-9a-fA-F]{8})/g, (_, hex) => String.fromCodePoint(parseInt(hex, 16))) + .replace(/\\U([0-9a-fA-F]{8})/g, (match, hex) => { + const codePoint = parseInt(hex, 16); + return codePoint <= 0x10ffff ? String.fromCodePoint(codePoint) : match; + }) .replace(/\\u([0-9a-fA-F]{4})/g, (_, hex) => String.fromCodePoint(parseInt(hex, 16))); export const validateStatus = async ( @@ -192,7 +195,7 @@ export const validateStatus = async ( if (response.status === 403) { return response.json().then((json) => { throw new HttpError( - json.message || 'Access denied due to cluster policy.', + unescapeGoUnicode(json.message || 'Access denied due to cluster policy.'), response.status, response, json,