Skip to content

OCPBUGS-74140: Prevent Chinese characters from rendering as unicode escape sequences in alert messages#16156

Open
sg00dwin wants to merge 2 commits intoopenshift:mainfrom
sg00dwin:OCPBUGS-74140-create-project-chinese-characters
Open

OCPBUGS-74140: Prevent Chinese characters from rendering as unicode escape sequences in alert messages#16156
sg00dwin wants to merge 2 commits intoopenshift:mainfrom
sg00dwin:OCPBUGS-74140-create-project-chinese-characters

Conversation

@sg00dwin
Copy link
Member

@sg00dwin sg00dwin commented Mar 16, 2026

The K8s API server escapes certain Unicode characters (PUA, CJK Extension I) using Go-style sequences (\uXXXX, \UXXXXXXXX) in validation error messages. These were displayed as literal text instead of actual characters.

  • Fix K8s API error messages displaying Go-style Unicode escape sequences (\ue00f, \U0002ebf0) as literal
    text instead of actual characters
  • Add unescapeGoUnicode utility to convert escape sequences back to Unicode characters in validateStatus

Assisted by: Claude Code

After
Screenshot 2026-03-16 at 3 50 19 PM

Before
Screenshot 2026-03-16 at 4 50 45 PM

Summary by CodeRabbit

  • Bug Fixes

    • Improved error message display by properly handling Unicode escape sequences.
  • Tests

    • Expanded test coverage for Unicode escape sequence handling in various scenarios.

@openshift-ci-robot openshift-ci-robot added jira/severity-critical Referenced Jira bug's severity is critical for the branch this PR is targeting. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. labels Mar 16, 2026
@openshift-ci-robot
Copy link
Contributor

@sg00dwin: This pull request references Jira Issue OCPBUGS-74140, which is invalid:

  • expected the bug to target only the "4.22.0" version, but multiple target versions were set

Comment /jira refresh to re-evaluate validity if changes to the Jira bug are made, or edit the title of this pull request to link to a different bug.

The bug has been updated to refer to the pull request using the external bug tracker.

Details

In response to this:

The K8s API server escapes certain Unicode characters (PUA, CJK Extension I) using Go-style sequences (\uXXXX, \UXXXXXXXX) in validation error messages. These were displayed as literal text instead of actual characters.

  • Fix K8s API error messages displaying Go-style Unicode escape sequences (\ue00f, \U0002ebf0) as literal
    text instead of actual characters
  • Add unescapeGoUnicode utility to convert escape sequences back to Unicode characters in validateStatus

Assisted by: Claude Code

After
Screenshot 2026-03-16 at 3 50 19 PM

Before
Screenshot 2026-03-16 at 4 50 45 PM

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci-robot openshift-ci-robot added the jira/invalid-bug Indicates that a referenced Jira bug is invalid for the branch this PR is targeting. label Mar 16, 2026
@openshift-ci openshift-ci bot requested review from Leo6Leo and rhamilto March 16, 2026 20:59
@openshift-ci openshift-ci bot added the component/sdk Related to console-plugin-sdk label Mar 16, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 16, 2026

📝 Walkthrough

Walkthrough

This pull request introduces Unicode escape handling for error messages in the console fetch utilities. A new unescapeGoUnicode function is added to convert Go-style Unicode escape sequences (\uXXXX for standard escapes and \UXXXXXXXX for supplementary plane escapes) into their actual character representations. The function is integrated into the error handling path so that error reason strings are unescaped before being passed to HttpError. Additionally, the validateStatus function signature is expanded to accept method and retry parameters, enabling conditional logic based on HTTP method and retry capability. Test coverage is expanded with dedicated test cases validating the unescaping behavior across various Unicode escape patterns and mixed content scenarios.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
📝 Coding Plan
  • Generate coding plan for human review comments

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

CodeRabbit can scan for known vulnerabilities in your dependencies using OSV Scanner.

OSV Scanner will automatically detect and report security vulnerabilities in your project's dependencies. No additional configuration is required.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
frontend/packages/console-dynamic-plugin-sdk/src/utils/fetch/__tests__/console-fetch.spec.ts (1)

5-23: Add a malformed-escape regression test for parser safety.

Nice happy-path coverage. Please add one case for invalid/out-of-range escapes (e.g. \\UFFFFFFFF) to lock in fail-open behavior and prevent future regressions.

✅ Suggested test case
 describe('unescapeGoUnicode', () => {
+  it('should not throw on malformed or out-of-range Go unicode escapes', () => {
+    expect(() => unescapeGoUnicode('\\UFFFFFFFF')).not.toThrow();
+    expect(unescapeGoUnicode('\\UFFFFFFFF')).toBe('\\UFFFFFFFF');
+  });
+
   it('should unescape 4-digit Go unicode escapes', () => {
     expect(unescapeGoUnicode('\\ue00f')).toBe('\ue00f');
     expect(unescapeGoUnicode('\\ue4c8')).toBe('\ue4c8');
   });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@frontend/packages/console-dynamic-plugin-sdk/src/utils/fetch/__tests__/console-fetch.spec.ts`
around lines 5 - 23, Add a regression test in the unescapeGoUnicode suite to
assert malformed/out-of-range escapes are preserved (fail-open). In the test
file console-fetch.spec.ts near the other cases for unescapeGoUnicode, add an it
block that calls unescapeGoUnicode with an invalid escape like '\\UFFFFFFFF'
(and optionally other malformed examples) and expects the original input string
to be returned unchanged; reference the unescapeGoUnicode function to locate
where to add this test.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@frontend/packages/console-dynamic-plugin-sdk/src/utils/fetch/console-fetch-utils.ts`:
- Line 229: The 403 JSON error branch still passes raw json.message into the
HttpError, so escaped Unicode can leak; update the 403 handling to call
unescapeGoUnicode(json.message) before constructing the HttpError (same as the
other branch that throws new HttpError(unescapeGoUnicode(reason), ...)). Locate
the 403 response branch in console-fetch-utils.ts and replace the raw
json.message usage with unescapeGoUnicode(json.message) when creating the
HttpError so both error paths behave consistently.
- Around line 153-156: The unescapeGoUnicode function can throw RangeError when
String.fromCodePoint is given out-of-range values; update the replacer callbacks
in unescapeGoUnicode to parse the hex, check that the code point is a finite
integer within 0..0x10FFFF (and for \uXXXX also within 0..0xFFFF), and only call
String.fromCodePoint for valid values; if validation fails (NaN or
out-of-range), return the original matched escape sequence (the full match) so
the function fails gracefully instead of throwing.

---

Nitpick comments:
In
`@frontend/packages/console-dynamic-plugin-sdk/src/utils/fetch/__tests__/console-fetch.spec.ts`:
- Around line 5-23: Add a regression test in the unescapeGoUnicode suite to
assert malformed/out-of-range escapes are preserved (fail-open). In the test
file console-fetch.spec.ts near the other cases for unescapeGoUnicode, add an it
block that calls unescapeGoUnicode with an invalid escape like '\\UFFFFFFFF'
(and optionally other malformed examples) and expects the original input string
to be returned unchanged; reference the unescapeGoUnicode function to locate
where to add this test.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: f0190f24-f1fd-4a05-ab5b-6299ab48b1bb

📥 Commits

Reviewing files that changed from the base of the PR and between 092f737 and 28a1ea5.

📒 Files selected for processing (2)
  • frontend/packages/console-dynamic-plugin-sdk/src/utils/fetch/__tests__/console-fetch.spec.ts
  • frontend/packages/console-dynamic-plugin-sdk/src/utils/fetch/console-fetch-utils.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (1)
**

⚙️ CodeRabbit configuration file

-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.

Files:

  • frontend/packages/console-dynamic-plugin-sdk/src/utils/fetch/__tests__/console-fetch.spec.ts
  • frontend/packages/console-dynamic-plugin-sdk/src/utils/fetch/console-fetch-utils.ts
🧬 Code graph analysis (1)
frontend/packages/console-dynamic-plugin-sdk/src/utils/fetch/__tests__/console-fetch.spec.ts (1)
frontend/packages/console-dynamic-plugin-sdk/src/utils/fetch/console-fetch-utils.ts (1)
  • unescapeGoUnicode (153-156)

Comment on lines +153 to +156
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)));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="$(fd 'console-fetch-utils\.ts$' | head -n1)"
echo "Inspecting $FILE"
sed -n '149,170p' "$FILE"
echo
echo "Searching for guard patterns near unescapeGoUnicode:"
rg -n -C2 'unescapeGoUnicode|fromCodePoint|0x10ffff|try\s*\{|catch\s*\(' "$FILE"

Repository: openshift/console

Length of output: 1618


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="frontend/packages/console-dynamic-plugin-sdk/src/utils/fetch/console-fetch-utils.ts"
echo "Inspecting 403 error branch (lines 190-210):"
sed -n '190,210p' "$FILE"

Repository: openshift/console

Length of output: 696


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="frontend/packages/console-dynamic-plugin-sdk/src/utils/fetch/console-fetch-utils.ts"

echo "=== All uses of unescapeGoUnicode in file ==="
rg -n 'unescapeGoUnicode' "$FILE"

echo -e "\n=== Full error handling flow (lines 160-240) to understand all paths ==="
sed -n '160,240p' "$FILE" | head -80

Repository: openshift/console

Length of output: 2412


Harden unescapeGoUnicode to prevent throwing on invalid Unicode code points.

String.fromCodePoint throws RangeError for out-of-range values (> 0x10FFFF). If a malformed \UXXXXXXXX escape sequence appears in an API error message, this will propagate as an uncaught exception instead of being caught by normal error handling, resulting in a degraded user experience. Validate the code point range and fail gracefully by returning the original escape sequence.

Proposed fix
+const decodeGoUnicodeEscape = (raw: string, hex: string): string => {
+  const codePoint = Number.parseInt(hex, 16);
+  if (!Number.isFinite(codePoint) || codePoint < 0 || codePoint > 0x10ffff) {
+    return raw;
+  }
+  try {
+    return String.fromCodePoint(codePoint);
+  } catch {
+    return raw;
+  }
+};
+
 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)));
+    .replace(/\\U([0-9a-fA-F]{8})/g, (raw, hex) => decodeGoUnicodeEscape(raw, hex))
+    .replace(/\\u([0-9a-fA-F]{4})/g, (raw, hex) => decodeGoUnicodeEscape(raw, hex));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
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)));
const decodeGoUnicodeEscape = (raw: string, hex: string): string => {
const codePoint = Number.parseInt(hex, 16);
if (!Number.isFinite(codePoint) || codePoint < 0 || codePoint > 0x10ffff) {
return raw;
}
try {
return String.fromCodePoint(codePoint);
} catch {
return raw;
}
};
export const unescapeGoUnicode = (str: string): string =>
str
.replace(/\\U([0-9a-fA-F]{8})/g, (raw, hex) => decodeGoUnicodeEscape(raw, hex))
.replace(/\\u([0-9a-fA-F]{4})/g, (raw, hex) => decodeGoUnicodeEscape(raw, hex));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@frontend/packages/console-dynamic-plugin-sdk/src/utils/fetch/console-fetch-utils.ts`
around lines 153 - 156, The unescapeGoUnicode function can throw RangeError when
String.fromCodePoint is given out-of-range values; update the replacer callbacks
in unescapeGoUnicode to parse the hex, check that the code point is a finite
integer within 0..0x10FFFF (and for \uXXXX also within 0..0xFFFF), and only call
String.fromCodePoint for valid values; if validation fails (NaN or
out-of-range), return the original matched escape sequence (the full match) so
the function fails gracefully instead of throwing.

}

throw new HttpError(reason, response.status, response, json);
throw new HttpError(unescapeGoUnicode(reason), response.status, response, json);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Apply unescape consistently in the 403 JSON error path as well.

Right now unescaping is only applied in this branch; the 403 branch still uses raw json.message, so escaped Unicode can still leak to users there.

💡 Proposed fix
   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,
       );
     });
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@frontend/packages/console-dynamic-plugin-sdk/src/utils/fetch/console-fetch-utils.ts`
at line 229, The 403 JSON error branch still passes raw json.message into the
HttpError, so escaped Unicode can leak; update the 403 handling to call
unescapeGoUnicode(json.message) before constructing the HttpError (same as the
other branch that throws new HttpError(unescapeGoUnicode(reason), ...)). Locate
the 403 response branch in console-fetch-utils.ts and replace the raw
json.message usage with unescapeGoUnicode(json.message) when creating the
HttpError so both error paths behave consistently.

}

throw new HttpError(reason, response.status, response, json);
throw new HttpError(unescapeGoUnicode(reason), response.status, response, json);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fix was applied here but not to the existing 403 handler above (line 194). Could Unicode escapes also appear in 403 json.message responses? If so, should we apply the same treatment there for consistency?

*/
export const unescapeGoUnicode = (str: string): string =>
str
.replace(/\\U([0-9a-fA-F]{8})/g, (_, hex) => String.fromCodePoint(parseInt(hex, 16)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if the API returns a malformed escape like \UFFFFFFFF? String.fromCodePoint() throws a RangeError for code points above 0x10FFFF. Should we add bounds checking to fail gracefully?

0x2ebf0,
)}${String.fromCodePoint(0x2ebf1)}`;
expect(unescapeGoUnicode(input)).toBe(expected);
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add a test case for invalid/out-of-range escape sequences to ensure the function doesn't throw unexpectedly?

@sg00dwin
Copy link
Member Author

@cajieh Thank you for the review. I pushed updates addressing the comments.

@openshift-ci
Copy link
Contributor

openshift-ci bot commented Mar 17, 2026

@sg00dwin: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/e2e-gcp-console 7e34460 link true /test e2e-gcp-console

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

@cajieh
Copy link
Contributor

cajieh commented Mar 17, 2026

/lgtm

@openshift-ci openshift-ci bot added the lgtm Indicates that a PR is ready to be merged. label Mar 17, 2026
@openshift-ci
Copy link
Contributor

openshift-ci bot commented Mar 17, 2026

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: cajieh, sg00dwin

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci openshift-ci bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Mar 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. component/sdk Related to console-plugin-sdk jira/invalid-bug Indicates that a referenced Jira bug is invalid for the branch this PR is targeting. jira/severity-critical Referenced Jira bug's severity is critical for the branch this PR is targeting. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. lgtm Indicates that a PR is ready to be merged.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants