Skip to content

fix(extensions): preserve symlinks in extension source path while enforcing folder trust - #20867

Merged
galdawave merged 9 commits into
mainfrom
galzahavi/fix/symlink-folder-trust
Mar 5, 2026
Merged

galdawave merged 9 commits into
mainfrom
galzahavi/fix/symlink-folder-trust

Conversation

@galdawave

Copy link
Copy Markdown
Contributor

Summary

This PR fixes a bug where extension installation and linking resolved symlinks to their real disk locations. This was breaking the use of stable symlinks by replacing them with ephemeral real paths in the extension metadata.

Details

  • Path Stability: Modified install.ts and extension-manager.ts to use path.resolve() for the installMetadata.source instead of getRealPath(). This ensures symlinks are preserved in the extension's configuration.
  • Maintained Security: Folder trust verification and storage in trustedFolders.json still utilize the real path. This ensures that spoofing protection is maintained (swapping a symlink to a new location will still trigger a trust prompt).
  • Copy Reliability: Updated the ExtensionManager to use the real path for localSourcePath during the copy phase of local installations, preventing ENOTDIR errors when copying from a symlink.

Related Issues

Fixes the issue reported regarding symlink resolution.

How to Validate

  1. Run new unit tests:
    npm test -w @google/gemini-cli -- src/config/extension-manager-symlink.test.ts
  2. Run integration tests:
    npm run test:integration:sandbox:none -- symlink-install.test.ts

Pre-Merge Checklist

  • Updated relevant documentation and README (if needed)
  • Added/updated tests (if needed)
  • Noted breaking changes (if any)
  • Validated on required platforms/methods:
    • MacOS
      • npm run
      • npx
      • Docker
      • Podman
      • Seatbelt
    • Windows
      • npm run
      • npx
      • Docker
    • Linux
      • npm run
      • npx
      • Docker

@galdawave
galdawave requested a review from a team as a code owner March 2, 2026 18:50
@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 addresses a bug where the CLI's extension installation process would resolve symlinks to their physical disk locations, leading to unstable extension metadata. The changes ensure that symlinks are preserved in the extension's stored source path, while simultaneously maintaining robust security by performing folder trust checks against the real path. Additionally, it improves the reliability of local extension copying by using the real path for the source during the copy operation.

Highlights

  • Symlink Preservation: Modified extension installation logic to store the absolute path (preserving symlinks) in installMetadata.source instead of resolving to the real disk path.
  • Security Maintained: Folder trust verification continues to use the real path of the extension, ensuring security against symlink spoofing.
  • Copy Reliability: Updated the ExtensionManager to use the real path for the source during local extension copying, preventing ENOTDIR errors.
  • New Unit Tests: Added dedicated unit tests to validate the correct handling and preservation of symlinks during extension installation and trust checks.
Changelog
  • packages/cli/src/commands/extensions/install.ts
    • Imported the path module.
    • Changed how installMetadata.source is set, using path.resolve() to preserve symlinks instead of getRealPath().
    • Adjusted folder trust discovery and storage to use the realPath for security checks and absolutePath for user prompts.
  • packages/cli/src/config/extension-manager-symlink.test.ts
    • Added a new test file to verify symlink preservation in installMetadata.source and correct interaction with folder trust logic.
  • packages/cli/src/config/extension-manager.ts
    • Removed the getRealPath() call when assigning to installMetadata.source to preserve symlinks.
    • Added getRealPath() when determining localSourcePath for copying, ensuring reliable file operations.
Activity
  • The pull request was created to fix a bug related to symlink resolution during extension installation.
  • New unit tests were added to validate the fix.
  • The author has validated the changes on MacOS using npm run and Seatbelt.
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.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

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

github-actions Bot commented Mar 2, 2026 •

Copy link
Copy Markdown

Size Change: +150 B (0%)

Total Size: 26 MB

ℹ️ View Unchanged
Filename Size Change
./bundle/gemini.js 25.5 MB +150 B (0%)
./bundle/node_modules/@google/gemini-cli-devtools/dist/client/main.js 221 kB 0 B
./bundle/node_modules/@google/gemini-cli-devtools/dist/src/_client-assets.js 227 kB 0 B
./bundle/node_modules/@google/gemini-cli-devtools/dist/src/index.js 11.5 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

compressed-size-action

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request correctly addresses a bug with symlink handling during extension installation. However, this change introduces security risks. Specifically, the allowedExtensions security policy can now be bypassed using symlinks (high severity). Additionally, the extension loader fails to re-verify the trust of the target directory when following a symlink during load. While this could allow the execution of untrusted code, it is considered low-risk as it requires an attacker to have write access to the user's extension directory.

Comment thread packages/cli/src/config/extension-manager.ts
@galdawave
galdawave force-pushed the galzahavi/fix/symlink-folder-trust branch from cfd40ae to a80f16c Compare March 2, 2026 19:20
@gemini-cli gemini-cli Bot added the status/need-issue Pull requests that need to have an associated issue. label Mar 2, 2026
Comment thread packages/cli/src/config/extension-manager-symlink.test.ts Outdated
@scidomino

Copy link
Copy Markdown
Collaborator

The core logic looks solid and correctly addresses the metadata path stability issue without compromising security checks (the gemini-code-assist bot's security warning is a false positive).

However, I noticed one small cross-platform issue in the new test that needs a quick fix:

packages/cli/src/config/extension-manager-symlink.test.ts

fs.symlinkSync(extensionDir, symlinkDir);

On Windows, Node.js defaults the symlink type to 'file'. Because extensionDir is a directory, this will cause the test to fail for Windows developers.

Could you update this to explicitly pass 'dir' as the third argument?

fs.symlinkSync(extensionDir, symlinkDir, 'dir');

On Windows, Node.js defaults fs.symlinkSync type to 'file'. Explicitly
passing 'dir' ensures that directory symlinks are created correctly,
fixing potential test failures for Windows developers.
@galdawave

Copy link
Copy Markdown
Contributor Author

The core logic looks solid and correctly addresses the metadata path stability issue without compromising security checks (the gemini-code-assist bot's security warning is a false positive).

However, I noticed one small cross-platform issue in the new test that needs a quick fix:

packages/cli/src/config/extension-manager-symlink.test.ts

fs.symlinkSync(extensionDir, symlinkDir);

On Windows, Node.js defaults the symlink type to 'file'. Because extensionDir is a directory, this will cause the test to fail for Windows developers.

Could you update this to explicitly pass 'dir' as the third argument?

fs.symlinkSync(extensionDir, symlinkDir, 'dir');

Done

@galdawave
galdawave enabled auto-merge March 4, 2026 22:25
@galdawave
galdawave added this pull request to the merge queue Mar 5, 2026
Merged via the queue into main with commit 3481032 Mar 5, 2026
27 checks passed
@galdawave
galdawave deleted the galzahavi/fix/symlink-folder-trust branch March 5, 2026 00:22
struckoff pushed a commit to struckoff/gemini-cli that referenced this pull request Mar 6, 2026
kunal-10-cloud pushed a commit to kunal-10-cloud/gemini-cli that referenced this pull request Mar 12, 2026
liamhelmer pushed a commit to badal-io/gemini-cli that referenced this pull request Mar 12, 2026
yashodipmore pushed a commit to yashodipmore/geemi-cli that referenced this pull request Mar 21, 2026
SUNDRAM07 pushed a commit to SUNDRAM07/gemini-cli that referenced this pull request Mar 30, 2026
warrenzhu25 pushed a commit to warrenzhu25/gemini-cli that referenced this pull request Apr 9, 2026
cocosheng-g pushed a commit that referenced this pull request May 6, 2026
@sripasg sripasg added the size/m A medium sized PR label Jun 2, 2026
software-0ficial pushed a commit to software-0ficial/gemini-cli that referenced this pull request Jul 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/m A medium sized PR status/need-issue Pull requests that need to have an associated issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants