Skip to content

Implements the concept of trusted project#303

Open
arcanis wants to merge 3 commits into
mainfrom
mael/switch-trust
Open

Implements the concept of trusted project#303
arcanis wants to merge 3 commits into
mainfrom
mael/switch-trust

Conversation

@arcanis
Copy link
Copy Markdown
Member

@arcanis arcanis commented May 19, 2026

This diff implements the concept of trusted projects. When a project install would run a unsecure command, we now first check whether Yarn Switch trusts the root project folder. If it doesn't, we first prompt the user for confirmation that the folder should be trusted.

The intent of that PR is not to protect a trusted project against malicious postinstalls - that's what other settings like enableScripts or npmMinimalAgeGate are for. Instead we're trying here to solve the case where you'd run a yarn install on an untrusted project you downloaded in such a way that you'd end up executing arbitrary code. While not common amongst every user maintainers regularly do that when testing repros, and maintainers are very valuable targets.


Note

High Risk
High risk because it changes when and whether install/build scripts are allowed to execute, adding new interactive prompting and CI-specific trust defaults that can affect automation and security posture.

Overview
Adds a per-project trust model to Yarn Switch and gates install-script execution on it. A new switch trust command (--check/--set true|false|null) persists trust state per project folder and is used by zpm before running scripts, prompting interactively when trust is unknown and erroring when untrusted.

Trust state is now stored alongside link data via a new FolderConfig format, exposed in switch cache output, and treated as implicitly trusted on CI unless explicitly untrusted. CI workflows/actions are updated to allow tests to run against a provided locally built yarn-switch binary, and new acceptance tests cover the trust command and script gating behavior.

Reviewed by Cursor Bugbot for commit 7f2ebf4. Bugbot is set up for automated code reviews on this repo. Configure here.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 19, 2026

⏱️ Benchmark Results

gatsby install-full-cold

Metric Base Head Difference
Mean 4.383s 4.315s -1.53% ✅
Median 4.384s 4.329s -1.25% ✅
Min 4.299s 4.146s
Max 4.483s 4.410s
Std Dev 0.043s 0.059s
📊 Raw benchmark data (gatsby install-full-cold)

Base times: 4.377s, 4.429s, 4.483s, 4.387s, 4.345s, 4.384s, 4.441s, 4.330s, 4.365s, 4.299s, 4.350s, 4.330s, 4.403s, 4.341s, 4.429s, 4.310s, 4.385s, 4.417s, 4.371s, 4.332s, 4.438s, 4.413s, 4.386s, 4.406s, 4.368s, 4.401s, 4.355s, 4.422s, 4.422s, 4.356s

Head times: 4.410s, 4.385s, 4.281s, 4.336s, 4.295s, 4.294s, 4.354s, 4.324s, 4.399s, 4.355s, 4.212s, 4.146s, 4.338s, 4.276s, 4.331s, 4.164s, 4.295s, 4.319s, 4.328s, 4.319s, 4.331s, 4.333s, 4.355s, 4.337s, 4.342s, 4.260s, 4.312s, 4.353s, 4.318s, 4.362s


gatsby install-cache-only

Metric Base Head Difference
Mean 1.274s 1.272s -0.15% ✅
Median 1.271s 1.271s -0.05% ✅
Min 1.245s 1.251s
Max 1.308s 1.307s
Std Dev 0.014s 0.014s
📊 Raw benchmark data (gatsby install-cache-only)

Base times: 1.285s, 1.260s, 1.259s, 1.270s, 1.284s, 1.265s, 1.281s, 1.277s, 1.279s, 1.245s, 1.295s, 1.268s, 1.276s, 1.278s, 1.300s, 1.260s, 1.308s, 1.292s, 1.263s, 1.283s, 1.275s, 1.283s, 1.269s, 1.271s, 1.261s, 1.266s, 1.265s, 1.272s, 1.254s, 1.261s

Head times: 1.280s, 1.265s, 1.267s, 1.275s, 1.265s, 1.264s, 1.274s, 1.283s, 1.265s, 1.251s, 1.263s, 1.275s, 1.252s, 1.307s, 1.288s, 1.284s, 1.262s, 1.277s, 1.261s, 1.257s, 1.251s, 1.277s, 1.260s, 1.292s, 1.257s, 1.261s, 1.296s, 1.277s, 1.282s, 1.280s


gatsby install-cache-and-lock (warm, with lockfile)

Metric Base Head Difference
Mean 0.343s 0.344s +0.30% ⚠️
Median 0.343s 0.343s -0.12% ✅
Min 0.336s 0.336s
Max 0.348s 0.372s
Std Dev 0.003s 0.008s
📊 Raw benchmark data (gatsby install-cache-and-lock (warm, with lockfile))

Base times: 0.343s, 0.338s, 0.342s, 0.346s, 0.343s, 0.347s, 0.341s, 0.340s, 0.343s, 0.344s, 0.336s, 0.341s, 0.347s, 0.340s, 0.343s, 0.346s, 0.342s, 0.347s, 0.345s, 0.345s, 0.343s, 0.343s, 0.343s, 0.345s, 0.342s, 0.344s, 0.343s, 0.348s, 0.345s, 0.346s

Head times: 0.343s, 0.344s, 0.343s, 0.338s, 0.340s, 0.343s, 0.342s, 0.347s, 0.343s, 0.346s, 0.344s, 0.344s, 0.343s, 0.353s, 0.341s, 0.361s, 0.372s, 0.344s, 0.338s, 0.336s, 0.336s, 0.336s, 0.339s, 0.344s, 0.339s, 0.367s, 0.340s, 0.342s, 0.339s, 0.342s

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Redundant subprocess spawning while holding the lock
    • Moved project trust persistence into the prompt-only branch so cached trust results do not spawn redundant subprocesses while holding the mutex.

Create PR

Or push these changes by commenting:

@cursor push 28c8352090
Preview (28c8352090)
diff --git a/packages/zpm/src/script.rs b/packages/zpm/src/script.rs
--- a/packages/zpm/src/script.rs
+++ b/packages/zpm/src/script.rs
@@ -653,14 +653,14 @@
                 let trusted
                     = Self::prompt_project_trust(project_cwd).await?;
 
+                Self::set_project_trust(&switch_path, project_cwd, trusted).await?;
+
                 *prompt_result = Some(trusted);
 
                 trusted
             },
         };
 
-        Self::set_project_trust(&switch_path, project_cwd, trusted).await?;
-
         match trusted {
             true => Ok(()),
             false => Err(Error::ProjectNotTrusted(project_cwd.clone())),

You can send follow-ups to the cloud agent here.

Reviewed by Cursor Bugbot for commit e46e07c. Configure here.

},
};

Self::set_project_trust(&switch_path, project_cwd, trusted).await?;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Redundant subprocess spawning while holding the lock

Low Severity

When concurrent build scripts all call check_project_trust before the first one persists trust, they all queue on the TRUST_PROMPT_RESULT lock. After the first task prompts and persists, subsequent tasks read the cached Some(trusted) value but still unconditionally call set_project_trust (line 662), spawning a redundant subprocess while holding the mutex. This serializes all pending scripts through unnecessary subprocess calls. The set_project_trust call could be limited to the None branch where the prompt actually happens, since the first caller already persists trust.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit e46e07c. Configure here.

@arcanis
Copy link
Copy Markdown
Member Author

arcanis commented May 21, 2026

@cursor push 28c8352

@cursor
Copy link
Copy Markdown

cursor Bot commented May 21, 2026

The push command requires write access to the repository.

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.

1 participant