Skip to content

fix(cli): skip redundant settings writes and preserve trailing newlines#26282

Closed
cocosheng-g wants to merge 1 commit intomainfrom
issue-18934-pr
Closed

fix(cli): skip redundant settings writes and preserve trailing newlines#26282
cocosheng-g wants to merge 1 commit intomainfrom
issue-18934-pr

Conversation

@cocosheng-g
Copy link
Copy Markdown
Contributor

Summary

Prevent unnecessary rewrites of settings.json and preserve formatting (like single-line arrays and trailing newlines) even when internal migrations occur.

Details

  • Implemented a deepEqual utility to compare JSON structures ignoring comment-json metadata (Symbol keys).
  • Added logic to updateSettingsFilePreservingFormat to skip fs.writeFileSync if logical content is unchanged.
  • Ensured trailing newlines are detected and preserved from the original file.
  • Added comprehensive unit tests in commentJson.test.ts for formatting preservation, newline handling, and redundant write avoidance.

Related Issues

Fixes #18934

How to Validate

  1. Create a formatted .gemini/settings.json with a single-line array and trailing newline:
    printf '{\n "context": {\n "fileName": ["A.md", "B.md"]\n }\n}\n' > .gemini/settings.json
  2. Run gemini --help (or any command that loads settings).
  3. Verify the file content and formatting are unchanged: cat .gemini/settings.json.
  4. Run unit tests: npm test packages/cli/src/utils/commentJson.test.ts.

Pre-Merge Checklist

  • Added/updated tests (if needed)
  • Validated on required platforms/methods:
    • MacOS
      • npm run

This change prevents settings.json from being mangled when logical content hasn't changed, preserving user formatting like single-line arrays and trailing newlines.

Fixes #18934
@cocosheng-g cocosheng-g requested a review from a team as a code owner April 30, 2026 19:58
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request optimizes the CLI settings management by preventing unnecessary file system operations when settings are already up to date. It also improves the robustness of the settings update process by ensuring that existing file formatting, specifically trailing newlines, is preserved during the write process.

Highlights

  • Redundant Write Prevention: Implemented a deep equality check to compare the current settings file content with proposed updates, skipping file system writes if no logical changes are detected.
  • Formatting Preservation: Enhanced the settings update logic to detect and maintain trailing newlines, ensuring file formatting remains consistent after internal migrations.
  • Testing: Added comprehensive unit tests to verify that writes are skipped when unnecessary and that trailing newline behavior is correctly preserved or applied.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@github-actions
Copy link
Copy Markdown

Size Change: +1.24 kB (0%)

Total Size: 33.9 MB

Filename Size Change
./bundle/chunk-DMRZKV22.js 0 B -19.5 kB (removed) 🏆
./bundle/chunk-OJMSRFXR.js 0 B -3.8 kB (removed) 🏆
./bundle/chunk-SNQWZR2D.js 0 B -12.6 kB (removed) 🏆
./bundle/chunk-SYCCFH64.js 0 B -49.2 kB (removed) 🏆
./bundle/chunk-TRCB3AJA.js 0 B -14.7 MB (removed) 🏆
./bundle/chunk-XF4IIA5L.js 0 B -656 kB (removed) 🏆
./bundle/chunk-YLZ5BY3A.js 0 B -3.43 kB (removed) 🏆
./bundle/chunk-ZXQZIXPZ.js 0 B -2.72 MB (removed) 🏆
./bundle/core-WK6DOSUE.js 0 B -48.2 kB (removed) 🏆
./bundle/devtoolsService-3XHDXPPU.js 0 B -28 kB (removed) 🏆
./bundle/gemini-RS5RPJB7.js 0 B -580 kB (removed) 🏆
./bundle/interactiveCli-4ZGOMUTP.js 0 B -1.32 MB (removed) 🏆
./bundle/liteRtServerManager-54ME5SHT.js 0 B -2.11 kB (removed) 🏆
./bundle/oauth2-provider-44V43547.js 0 B -9.16 kB (removed) 🏆
./bundle/chunk-DCD76IKN.js 19.5 kB +19.5 kB (new file) 🆕
./bundle/chunk-FRREUWHP.js 3.8 kB +3.8 kB (new file) 🆕
./bundle/chunk-H4ZYYRXG.js 12.6 kB +12.6 kB (new file) 🆕
./bundle/chunk-OZJMCY6U.js 14.7 MB +14.7 MB (new file) 🆕
./bundle/chunk-URFAUOLT.js 2.72 MB +2.72 MB (new file) 🆕
./bundle/chunk-YH3BR4BH.js 657 kB +657 kB (new file) 🆕
./bundle/chunk-YYGVAHFC.js 3.43 kB +3.43 kB (new file) 🆕
./bundle/chunk-Z3QDPOAF.js 49.2 kB +49.2 kB (new file) 🆕
./bundle/core-QUVGN7BQ.js 48.2 kB +48.2 kB (new file) 🆕
./bundle/devtoolsService-FYHRZU6D.js 28 kB +28 kB (new file) 🆕
./bundle/gemini-EJYXWNDZ.js 580 kB +580 kB (new file) 🆕
./bundle/interactiveCli-YWN2TTUN.js 1.32 MB +1.32 MB (new file) 🆕
./bundle/liteRtServerManager-M6RFMO6L.js 2.11 kB +2.11 kB (new file) 🆕
./bundle/oauth2-provider-AHJF4L6L.js 9.16 kB +9.16 kB (new file) 🆕
ℹ️ View Unchanged
Filename Size Change
./bundle/bundled/third_party/index.js 8 MB 0 B
./bundle/chunk-34MYV7JD.js 2.45 kB 0 B
./bundle/chunk-5AUYMPVF.js 858 B 0 B
./bundle/chunk-5PS3AYFU.js 1.18 kB 0 B
./bundle/chunk-664ZODQF.js 124 kB 0 B
./bundle/chunk-DAHVX5MI.js 206 kB 0 B
./bundle/chunk-IUUIT4SU.js 56.5 kB 0 B
./bundle/chunk-OQX7GVID.js 1.97 MB 0 B
./bundle/chunk-RJTRUG2J.js 39.8 kB 0 B
./bundle/cleanup-IOAG5Z5R.js 0 B -932 B (removed) 🏆
./bundle/devtools-36NN55EP.js 696 kB 0 B
./bundle/dist-T73EYRDX.js 356 B 0 B
./bundle/events-XB7DADIJ.js 418 B 0 B
./bundle/examples/hooks/scripts/on-start.js 188 B 0 B
./bundle/examples/mcp-server/example.js 1.43 kB 0 B
./bundle/gemini.js 5.14 kB 0 B
./bundle/getMachineId-bsd-TXG52NKR.js 1.55 kB 0 B
./bundle/getMachineId-darwin-7OE4DDZ6.js 1.55 kB 0 B
./bundle/getMachineId-linux-SHIFKOOX.js 1.34 kB 0 B
./bundle/getMachineId-unsupported-5U5DOEYY.js 1.06 kB 0 B
./bundle/getMachineId-win-6KLLGOI4.js 1.72 kB 0 B
./bundle/memoryDiscovery-QEUOLE5X.js 980 B 0 B
./bundle/multipart-parser-KPBZEGQU.js 11.7 kB 0 B
./bundle/node_modules/@google/gemini-cli-devtools/dist/client/main.js 222 kB 0 B
./bundle/node_modules/@google/gemini-cli-devtools/dist/src/_client-assets.js 229 kB 0 B
./bundle/node_modules/@google/gemini-cli-devtools/dist/src/index.js 13.4 kB 0 B
./bundle/node_modules/@google/gemini-cli-devtools/dist/src/types.js 132 B 0 B
./bundle/sandbox-macos-permissive-open.sb 890 B 0 B
./bundle/sandbox-macos-permissive-proxied.sb 1.31 kB 0 B
./bundle/sandbox-macos-restrictive-open.sb 3.36 kB 0 B
./bundle/sandbox-macos-restrictive-proxied.sb 3.56 kB 0 B
./bundle/sandbox-macos-strict-open.sb 4.82 kB 0 B
./bundle/sandbox-macos-strict-proxied.sb 5.02 kB 0 B
./bundle/src-QVCVGIUX.js 47 kB 0 B
./bundle/start-AIEY3IH5.js 0 B -652 B (removed) 🏆
./bundle/tree-sitter-7U6MW5PS.js 274 kB 0 B
./bundle/tree-sitter-bash-34ZGLXVX.js 1.84 MB 0 B
./bundle/cleanup-5DOHOKBO.js 932 B +932 B (new file) 🆕
./bundle/start-NGYQIRK2.js 652 B +652 B (new file) 🆕

compressed-size-action

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces logic to skip unnecessary file writes in updateSettingsFilePreservingFormat by performing a deep equality check on the logical content. It also improves trailing newline handling for settings files and adds comprehensive tests for these scenarios. A security concern was raised regarding potential prototype pollution in the update application logic, along with a suggestion to use a more robust method for stripping metadata during content comparison.

}

// First, check if logical content would change using the clean parse
const updatedClean = applyUpdates(structuredClone(cleanParsed), updates);
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.

security-high high

The call to applyUpdates on line 52 introduces a Prototype Pollution vulnerability. The helper function applyKeyDiff (used by applyUpdates) does not validate or skip sensitive keys like __proto__, constructor, or prototype. This new call path expands the attack surface, potentially leading to Denial of Service (DoS) or Remote Code Execution (RCE) if Object.prototype is modified. To remediate this, applyKeyDiff (line 170) should be updated to explicitly skip these sensitive keys.

Additionally, the current implementation uses JSON.parse(stripJsonComments(...)) for content comparison, which is stricter than comment-json and could cause errors with valid (but lenient) JSON (e.g., trailing commas). For more robust comparison, consider using structuredClone on the comment-json parsed object, as it naturally strips Symbols, providing a clean object without parsing errors.

Bojun-Vvibe added a commit to Bojun-Vvibe/oss-contributions that referenced this pull request May 1, 2026
- google-gemini/gemini-cli#26284 merge-after-nits: voice-mode wave animation, must remove duplicate ternary arm before merge

- google-gemini/gemini-cli#26282 merge-after-nits (CLOSED, design-of-record): clean-parse equality + trailing-newline preservation for settings.json

- docs: append drip-236 block to reviews/INDEX.md
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.

settings.json is rewritten with different formatting even when logical content hasn't changed

1 participant