-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
workspace trust: v2 #15857
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
workspace trust: v2 #15857
Changes from 1 commit
974120d
08d49b4
fc68a0d
7fa938e
3a8cd62
34f8bd5
9832c24
2907085
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This reads well to me now 👍 |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,23 +1,133 @@ | ||||||
| # Workspace trust | ||||||
|
|
||||||
| Helix has a number of potentially dangerous features, namely LSP and ability to use local to workspace configurations. Those features can lead to unexpected code execution. To protect against code execution in dangerous contexts, Helix has a workspace trust protection, which will prevent these potentially dangerous features from running automatically. | ||||||
| Helix has two potentially dangerous features, both of which can execute | ||||||
| arbitrary code: | ||||||
|
|
||||||
| Helix will not trust any workspace by default. | ||||||
| - Language servers (LSP) | ||||||
| - Local workspace configuration (`.helix/config.toml`, `.helix/languages.toml`) | ||||||
|
|
||||||
| By default, it will prompt about trust when you open new file in a workspace where you didn't make a decision about trust yet. | ||||||
| To protect against malicious projects (a checked-out PR, a freshly cloned | ||||||
| repository, etc.) Helix gates them behind explicit per-workspace trust. | ||||||
| By default language servers and debug adapters still start automatically | ||||||
| (their binaries come from `$PATH`, not from the workspace), but loading | ||||||
| `.helix/config.toml` or `.helix/languages.toml` requires opting in. The | ||||||
| model is intentionally similar to [direnv](https://direnv.net/): you run | ||||||
| `:workspace-trust` once per workspace and Helix remembers across sessions. | ||||||
|
|
||||||
| If you decide not to trust a workspace and don't want to be prompted about trust every time you start a new session in it, you can exclude the workspace by choosing `Never` option in trust selection window. | ||||||
| ## Granting trust | ||||||
|
|
||||||
| You can always make current workspace trusted by running `:workspace-trust` command, and untrust it with `:workspace-untrust`. | ||||||
| When Helix opens a file inside a workspace it has never seen before, a | ||||||
| modal trust prompt asks: | ||||||
|
|
||||||
| Lists of trusted and excluded workspaces, delimited by newline characters, are stored in `~/.local/share/helix/trusted_workspaces` and `~/.local/share/helix/excluded_workspaces` correspondingly. | ||||||
| <!-- TODO: Windows paths --> | ||||||
| - **Trust** — allow the workspace permanently. | ||||||
| - **Never** — exclude the workspace; never prompt again. | ||||||
|
|
||||||
| # Configuration | ||||||
| `<Esc>` (or any other dismissal) caches "untrusted for this session" so | ||||||
| the prompt doesn't re-fire for every file you open in the workspace. The | ||||||
| next time you start Helix in that workspace, it'll prompt again. | ||||||
|
|
||||||
| You can return to the old behaviour of loading every local `.helix/config.toml` and `.helix/languages.toml` and starting LSP's without an explicit permission by setting following option: | ||||||
| A small `[⚠]` indicator appears in the bottom-right of the editor (next | ||||||
| to the macro-recording `[@]`) whenever the workspace is in restricted mode | ||||||
| *and* running `:workspace-trust` would change observable behavior — i.e. | ||||||
| when there's a local config to load or an LSP that would start. | ||||||
|
|
||||||
| You can also run `:workspace-trust` / `:workspace-untrust` / | ||||||
| `:workspace-exclude` directly from the typed command prompt. | ||||||
|
|
||||||
| ## Revoking trust | ||||||
|
|
||||||
| Run `:workspace-untrust` to revoke a workspace's trust grant. The next time | ||||||
| you open a file in that workspace, you're back to the untrusted hint. | ||||||
|
|
||||||
| ## Detecting changes after trust was granted | ||||||
|
|
||||||
| When you trust a workspace, Helix records a hash of every file under | ||||||
| `.helix/`. If those files change afterwards (a malicious checkout, an | ||||||
| inadvertent rebase, etc.) Helix detects the mismatch on the next open and | ||||||
| reports the workspace as *stale*: | ||||||
|
|
||||||
| ``` | ||||||
| Workspace `.helix/` config changed since `:workspace-trust`. Local config | ||||||
| not loaded. Run `:workspace-trust` to re-allow. | ||||||
| ``` | ||||||
|
|
||||||
| In the stale state, language servers continue to run (they use the | ||||||
| globally-configured binaries on `$PATH`, which are unchanged), but | ||||||
| `.helix/config.toml` and `.helix/languages.toml` are not loaded. Run | ||||||
| `:workspace-trust` again to re-pin the new hash. | ||||||
|
|
||||||
| ## Storage | ||||||
|
|
||||||
| Trust grants live in `data_dir()/workspace_trust/`, one small file per | ||||||
| workspace. The filename is the SHA-256 of the workspace's absolute path; | ||||||
| the contents look like: | ||||||
|
|
||||||
| ``` | ||||||
| path = /home/user/proj1 | ||||||
| hash = sha256:abc123... | ||||||
| excluded = false | ||||||
| ``` | ||||||
|
|
||||||
| - Linux, macOS: `~/.local/share/helix/workspace_trust/` | ||||||
| - Windows: `%AppData%\Roaming\helix\workspace_trust\` | ||||||
|
|
||||||
| The one-file-per-workspace shape is safe under multiple concurrent Helix | ||||||
| instances — different workspaces never write the same file. | ||||||
|
|
||||||
| ## Configuration | ||||||
|
|
||||||
| Two settings live under `[editor.workspace-trust]`: | ||||||
|
|
||||||
| | Key | Values | Default | Effect | | ||||||
| | --- | --- | --- | --- | | ||||||
| | `level` | `"none"`, `"servers"`, `"all"` | `"servers"` | What is auto-trusted in every workspace. See below. | | ||||||
| | `prompt` | `true`, `false` | `true` | Whether to surface the modal popup. The `[⚠]` indicator is shown regardless. | | ||||||
|
|
||||||
| ### Recommended setups | ||||||
|
|
||||||
| **Default: trust servers, prompt before loading workspace config.** | ||||||
|
|
||||||
| ```toml | ||||||
| [editor] | ||||||
| insecure = true | ||||||
| [editor.workspace-trust] | ||||||
| level = "servers" | ||||||
| prompt = true | ||||||
| ``` | ||||||
|
|
||||||
| Language servers and debug adapters start automatically in every | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
I think we need to manually kick off debug adapter servers, right? They're never started automatically iirc |
||||||
| workspace — their binaries come from `$PATH` and are not | ||||||
| workspace-controlled. The modal only appears when opening a file in a | ||||||
| workspace whose `.helix/config.toml` or `.helix/languages.toml` would | ||||||
| unlock something. Trust everything else with one keystroke per | ||||||
| workspace, deny with another. | ||||||
|
|
||||||
| **Maximum security: never prompt, trust each workspace by hand.** | ||||||
|
|
||||||
| ```toml | ||||||
| [editor.workspace-trust] | ||||||
| level = "none" | ||||||
| prompt = false | ||||||
| ``` | ||||||
|
|
||||||
| Nothing trusts implicitly: language servers, debug adapters, local | ||||||
| config, and git `Trust::Full` are all off until you run | ||||||
| `:workspace-trust`. The popup never appears; the `[⚠]` indicator in the | ||||||
| bottom-right is your only signal that the current workspace is | ||||||
| restricted. Suited to users who would rather grant trust as a | ||||||
| deliberate action than dismiss a dialog. | ||||||
|
|
||||||
| > [!WARNING] | ||||||
| > `level = "all"` is highly discouraged. It implicitly trusts every | ||||||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I still think
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah I think we can just replace |
||||||
| > workspace you open, which defeats the protection entirely: a | ||||||
| > checked-out PR with a malicious `.helix/config.toml` would get its | ||||||
| > configuration loaded and any language server it defines launched, with | ||||||
| > no prompt and no indicator. Only set this if you accept full | ||||||
| > responsibility for what's in every project directory you `cd` into. | ||||||
|
|
||||||
| ## Git trust | ||||||
|
|
||||||
| Workspace trust also gates how Helix opens git repositories. Untrusted | ||||||
| workspaces are opened in [gix](https://github.com/Byron/gitoxide)'s | ||||||
| `Trust::Reduced` mode, which disables risky configuration like | ||||||
| `core.fsmonitor`, `core.sshCommand`, `gpg.openpgp.program`, and similar | ||||||
| options that can execute arbitrary commands from `.git/config`. Trusted | ||||||
| workspaces use `Trust::Full`. | ||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a lot packed into the descriptions, I wonder if moving the details to the example section would be better?