Skip to content

fix(frontend): stop a payload string masquerading as undefined in raw view - #8045

Open
yhabib wants to merge 4 commits into
mainfrom
fix/undefined-token-replacement
Open

fix(frontend): stop a payload string masquerading as undefined in raw view#8045
yhabib wants to merge 4 commits into
mainfrom
fix/undefined-token-replacement

Conversation

@yhabib

@yhabib yhabib commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Motivation

stringifyJson marked a missing value by writing the sentinel string "__UNDEFINED__", then replacing every occurrence of that exact text with the bare word undefined after serialization. A proposal payload string equal to __UNDEFINED__ matched the same replace, so it rendered as undefined in the raw view, the tree view, and the copy text, even though the value was set. A payload string that ended in __UNDEFINED__ right after a quote garbled the rest of the display.

Changes

  • Replaced the sentinel-and-replace approach with a small recursive walker that writes the word undefined directly when a value is undefined, and delegates every other value to JSON.stringify. A payload string that reads __UNDEFINED__ now shows as that plain quoted string, like any other string.
  • Fixed stringifyJson to serialize an array hole as undefined instead of skipping it: the array branch used Array.from in place of .map, which skips holes and left them as holes in the output.
  • Added an e2e spec that submits a proposal with __UNDEFINED__ as the payload text and checks all three surfaces (tree view, raw view, copy button).
  • Added unit tests covering the sentinel string in a value and in a key, a string that starts with a quote and the sentinel, layout parity with JSON.stringify, and the array-hole case.
  • Added a changelog entry under Security.

Tests

  • npm run check: PASS.
  • CI=true npm run test: PASS, 672 test files, 5917 passed, 9 skipped.
  • ./scripts/check-relative-imports: PASS.
  • e2e (./scripts/e2e-tests): not run here, no local replica available in this environment. The new spec was reviewed and approved without a live run; someone with a working replica should run it before merge.

Todos

stringifyJson wrote the sentinel "__UNDEFINED__" for an undefined value,
then replaced every occurrence of that quoted token in the serialized text
with the bare word undefined. The replacement did not tell the sentinel
from payload data. A proposal payload string that read __UNDEFINED__ showed
as undefined, and a quote in front of it garbled the rest of the output.

stringifyJson now walks the value itself. It writes the word undefined only
for a value that is undefined, and it hands every leaf and every key to
JSON.stringify. The layout, the escaping and the mapped values (Principal,
bigint, hash, Promise, ArrayBuffer, function, symbol) stay the same.
The spec submits a proposal whose Motion text is the string __UNDEFINED__,
then reads the three surfaces that show a payload: the tree view, the raw
view and the copy button. Each surface must show the plain quoted string.

The spec is NOT RUN on this machine. The local replica comes up empty with
no NNS canisters, and no snsdemo snapshot archive is available to reinstall.
Array.prototype.map skips an array hole, so stringifyJson wrote [1,,3] for a
sparse array. That text is not valid JSON, and the absent value did not show.

Array.from visits every index and reads a hole as undefined. That is the text
stringifyJson wrote before this branch.

Two readability points from the review are in this commit too. The JSDoc now
reads as one block, and the space after a key colon is a const.
@yhabib
yhabib requested a review from a team as a code owner September 4, 2026 16:23
@zeropath-ai

zeropath-ai Bot commented Sep 4, 2026

Copy link
Copy Markdown

No security or compliance issues detected. Reviewed everything up to f909c2c.

Security Overview
Detected Code Changes
Change Type Relevant files
Enhancement ► frontend/src/lib/utils/utils.ts
    Transform and serialize values for JSON output with updated mapping rules
► frontend/src/tests/lib/utils/utils.spec.ts
    Add tests for UNDEFINED handling and serialization behavior
► frontend/src/tests/lib/components/common/JsonPreview.spec.ts
    Update tests to account for UNDEFINED rendering in raw/tree views
► frontend/src/tests/lib/components/proposal-detail/ProposalProposerActionsEntry.spec.ts
    Add test for copying string "UNDEFINED" payload
► frontend/src/tests/page-objects/ProposalProposerActionsEntry.page-object.ts
    Add copy button page-object accessor
Bug Fix ► frontend/src/tests/e2e/proposal-payload-undefined-token.spec.ts
    Add end-to-end test ensuring payload "UNDEFINED" is rendered correctly in various views
Other relevant categories ► CHANGELOG-Nns-Dapp-unreleased.md
    Update changelog with new behavior for undefined-like strings

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

stringifyJson’s new jsonGap helper can throw for non-finite indentation values and one updated JSDoc comment is inaccurate, so the implementation/docs should be corrected before merge.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR fixes stringifyJson so proposal payload strings that equal the previous undefined sentinel ("__UNDEFINED__") render as ordinary strings (instead of being rewritten to undefined) across the JSON tree view, raw view, and copy-to-clipboard text.

Changes:

  • Replaced the sentinel+regex-replace strategy in stringifyJson with a recursive serializer that writes undefined only for actual undefined values and delegates all other leaf serialization to JSON.stringify.
  • Added unit and e2e coverage for the "__UNDEFINED__" payload case (including copy button behavior) and for sparse-array holes.
  • Added a security changelog entry describing the rendering fix.
File summaries
File Description
frontend/src/lib/utils/utils.ts Reworks stringifyJson to avoid sentinel collisions and preserve undefined/array holes explicitly.
frontend/src/tests/lib/utils/utils.spec.ts Adds unit tests covering sentinel-string rendering, layout parity, array holes, and circulars.
frontend/src/tests/lib/components/common/JsonPreview.spec.ts Adds raw/tree view assertions for the "__UNDEFINED__" string case.
frontend/src/tests/lib/components/proposal-detail/ProposalProposerActionsEntry.spec.ts Adds a unit test verifying copy-to-clipboard preserves "__UNDEFINED__".
frontend/src/tests/page-objects/ProposalProposerActionsEntry.page-object.ts Adds a page-object accessor for the copy button.
frontend/src/tests/e2e/proposal-payload-undefined-token.spec.ts Adds an e2e regression test validating all three surfaces (tree/raw/copy).
CHANGELOG-Nns-Dapp-unreleased.md Documents the fix under Security.
Review details
  • Files reviewed: 7/7 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread frontend/src/lib/utils/utils.ts Outdated
Comment thread frontend/src/lib/utils/utils.ts Outdated
Math.floor(NaN) fed a RangeError into " ".repeat. Clamp NaN to 0, the
same value JSON.stringify uses. Also fix the BigInt devMode JSDoc, which
named the wrong output format.

Copilot review on PR 8045.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approved

The serialization fix is well-scoped and is backed by targeted unit/component/e2e regression tests, with only a minor documentation nit noted.

Review details

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

frontend/src/tests/e2e/proposal-payload-undefined-token.spec.ts:138

  • The comment says the raw view is valid JSON, but RawJson renders via stringifyJson which can output bare undefined (not valid JSON) for actual undefined values (see JsonPreview.spec.ts expecting {"test": undefined}). This test only guarantees JSON validity for this specific payload (no undefined values), so the comment should be scoped to that to avoid misleading future readers.
  • Files reviewed: 7/7 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants