Skip to content

Reencode non-ASCII strings in BEP command line and metadata events - #30665

Open
oscarthecat wants to merge 3 commits into
bazelbuild:masterfrom
oscarthecat:fix/bep-command-line-non-ascii
Open

Reencode non-ASCII strings in BEP command line and metadata events#30665
oscarthecat wants to merge 3 commits into
bazelbuild:masterfrom
oscarthecat:fix/bep-command-line-non-ascii

Conversation

@oscarthecat

Copy link
Copy Markdown

Bazel stores strings internally as raw bytes in Latin-1 Strings, while protobuf string fields are Unicode. CommandLineEvent and BuildMetadataEvent wrote internal strings into the BEP protos without reencoding them, so any non-ASCII option value, residue entry or build metadata value ended up double encoded in the BEP.

For example, with a UTF-8 environment variable GITLAB_USER_NAME=王芳兵, the canonical command line reported --client_env=GITLAB_USER_NAME=çè³åµ, and --build_metadata=USER=王芳兵 was mangled the same way. Consumers of the BEP that display these values, such as BuildBuddy, show the mojibake.

Route these values through StringEncoding.internalToUnicode(), as is already done for other proto fields, e.g. in BuildLanguageInfoItem. ASCII values are unaffected. WorkspaceStatus values were already correct, since the workspace status output is decoded as UTF-8 when it is parsed.

Description

Motivation

Build API Changes

No

Checklist

  • I have added tests for the new use cases (if any).
  • I have updated the documentation (if applicable).

Release Notes

RELNOTES: None

@google-cla

google-cla Bot commented Aug 11, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@github-actions github-actions Bot added team-Rules-Server Issues for serverside rules included with Bazel awaiting-review PR is awaiting review from an assigned reviewer labels Aug 11, 2026

@fmeum fmeum left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The WorkspaceStatus entries being encoded correctly here is actually concerning though as other parts of the system assume that everything is in the internal encoding. If you know where they are being parsed, could you make sure they are retained in internal encoding there and only converted back to Unicode when forming the BES proto?

@oscarthecat
oscarthecat requested a review from a team as a code owner August 11, 2026 11:45
@oscarthecat
oscarthecat requested review from gregestren and removed request for a team August 11, 2026 11:45
@oscarthecat

Copy link
Copy Markdown
Author

Thanks, that was a good catch — and it turned out to be more than a convention issue.

BazelWorkspaceStatusModule decoded the command output as UTF-8, which made those entries the only Unicode strings in the status maps; everything else (BUILD_USER, BUILD_HOST, embed_label) is an internal string. printStatusMap then reencoded the values as UTF-8 when writing the status files — but WorkspaceStatusAction#parseValues reads those files with readContentAsLatin1 (WorkspaceStatusAction.java:130), i.e. it expects the internal encoding. So the writer and the reader disagreed, which also affects stamping via BuildInfoFileWriteAction.java:103.

Changes:

  • BazelWorkspaceStatusModule.java:122 — decode the command output as Latin-1, so it stays in the internal encoding like the other entries.
  • BazelWorkspaceStatusModule.java:161 — write the status files without reencoding. The files still contain the exact bytes the command emitted, but the values now round-trip through parseValues unchanged.
  • BuildInfoEvent.java — convert to Unicode where the BES proto is formed, which is the only place that needs it.

Added test_non_ascii_status_value to workspace_status_test.sh, which asserts both halves: the raw bytes in stable-status.txt and the reencoded value in the BEP.

@oscarthecat
oscarthecat force-pushed the fix/bep-command-line-non-ascii branch from ed2f768 to b5fa902 Compare August 11, 2026 12:35
}
return stdoutStream.toString(UTF_8);
// Keep the output as an internal string, i.e. raw bytes in a Latin-1 String, so that it
// matches the encoding of the other entries in the status maps and of the bytes written

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Just say that this uses Bazel's internal string encoding and reference StringEncoding.

.collect(joining("\n"));
s += "\n";
return s.getBytes(StandardCharsets.UTF_8);
// The map values are internal strings, i.e. raw bytes in a Latin-1 String, so write them out

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Same as above

Bazel keeps strings internally as raw bytes in Latin-1 `String`s, whereas
protobuf `string` fields hold Unicode. `CommandLineEvent` and
`BuildMetadataEvent` wrote internal strings into the BEP protos as is, so a
non-ASCII option value, residue entry or build metadata value came out double
encoded.

Route these values through `StringEncoding#internalToUnicode`, as is already
done for other proto fields, e.g. in `BuildLanguageInfoItem`. ASCII values are
unaffected.

The values are the ones a consumer of the BEP is most likely to display: an
invocation started with a non-ASCII `--build_metadata`, `--client_env` or
target pattern showed mojibake in the UI rather than what the user had passed
in, and there was no way to recover the original bytes from the stream.
The workspace status command output was decoded as UTF-8, which made its
entries the only Unicode strings in the status maps, and it was reencoded as
UTF-8 on the way into the status files. `WorkspaceStatusAction#parseValues`
reads those files as Latin-1, so a non-ASCII value did not survive the round
trip and reached `BuildInfoFileWriteAction` mangled.

Decode the output as Latin-1 so that it stays in the internal encoding like
every other entry, and write the status files without reencoding. The files
still hold the exact bytes the command emitted. Convert to Unicode in
`BuildInfoEvent`, where the BEP proto is formed and it is actually needed.
@oscarthecat
oscarthecat force-pushed the fix/bep-command-line-non-ascii branch from b5fa902 to 847a9be Compare August 11, 2026 13:11
Rather than restating how the internal encoding represents bytes, name it and
point at `StringEncoding`, which documents it.
@oscarthecat

Copy link
Copy Markdown
Author

Done, thanks — comments now just name the internal string encoding and point at StringEncoding.

Pushed as a separate commit (9a6bdb6) so the change is easy to see. Also applied the same simplification to the comment in CommandLineEventTest, which had the same problem.

CI is green and the CLA check is sorted out. Happy to squash or adjust anything else.

@fmeum fmeum left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@fmeum

fmeum commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

@bazel-io fork 9.3.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awaiting-review PR is awaiting review from an assigned reviewer community-reviewed Reviewed by a trusted community contributor team-Rules-Server Issues for serverside rules included with Bazel

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants