-
Notifications
You must be signed in to change notification settings - Fork 447
Feat/add workspace trust feature #4738
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
Open
MMhunter
wants to merge
10
commits into
main
Choose a base branch
from
feat/add-workspace-trust-feature
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 9 commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
a276714
fix: 修复原有 select 自动完成功能
MMhunter dba77b2
fix: 修复自动方法时补全多一个点
MMhunter 8e97342
Merge remote-tracking branch 'origin/main' into feat/fix-select-defau…
MMhunter 8e75fe5
feat: add workspace trust module for security clearance
MMhunter a3af3b5
feat: workspace trusted feature to core-browser
MMhunter bc63495
chore: restore yarn.lock
MMhunter 170eb33
fix: fix dep
MMhunter f136fdb
chore: better description
MMhunter 4950b33
feat: add command register awaiter
MMhunter 922f391
feat: fix theme stuck
MMhunter File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,142 @@ | ||
| # 工作区信任(受限模式)功能设计文档 | ||
|
|
||
| ## 概述 | ||
|
|
||
| 为 IDE 添加「工作区信任」机制,在首次打开项目时提示用户是否信任该项目目录。若用户选择「受限模式」,则 IDE 仅加载特定的安全插件,防止恶意脚本攻击。 | ||
|
|
||
| ## 背景 | ||
|
|
||
| 当前 IDE 打开项目时会自动加载并激活所有插件(extensions),包括第三方插件。如果项目目录来源不可信,其中的恶意插件脚本可能对用户的系统和数据造成威胁。VS Code 的「Workspace Trust」功能提供了类似的防护机制。 | ||
|
|
||
| ## 核心流程 | ||
|
|
||
| ``` | ||
| 用户打开项目目录 | ||
| │ | ||
| ├── 查询 globalStorage 中是否已记录该目录的信任状态 | ||
| │ │ | ||
| │ ├── 已记录 → 直接使用已有状态 | ||
| │ └── 未记录 → 弹出信任对话框 | ||
| │ │ | ||
| │ ├── 选择「信任」 → 记录为信任状态 | ||
| │ └── 选择「受限模式」 → 记录为受限状态 | ||
| │ | ||
| ├── 根据信任状态决定是否加载插件 | ||
| │ │ | ||
| │ ├── 信任 → 加载所有插件 | ||
| │ └── 受限 → 仅加载白名单插件 | ||
| │ | ||
| └── 根据信任状态更新 UI | ||
| │ | ||
| ├── 信任 → 正常 UI | ||
| └── 受限 → 状态栏显示「受限模式」标识 | ||
| ``` | ||
|
|
||
| ## 数据设计 | ||
|
|
||
| ### 存储方案 | ||
|
|
||
| 使用 `globalStorage`(全局持久化存储)记录每个目录的信任状态。 | ||
|
|
||
| 存储 key 格式:`workspace_trust_state:<workspace_path>` 存储 value:`"trusted"` | `"restricted"` | ||
|
|
||
| 例如: | ||
|
|
||
| ``` | ||
| workspace_trust_state:/Users/mahang/Workspace/ide/core = "trusted" | ||
| workspace_trust_state:/tmp/suspicious-project = "restricted" | ||
| ``` | ||
|
|
||
| ### 存储模块 | ||
|
|
||
| 使用 `STORAGE_NAMESPACE.GLOBAL_EXTENSIONS` 全局存储空间,以 key-value 形式持久化。 | ||
|
|
||
| ### 信任白名单插件 | ||
|
|
||
| 受限模式下仅允许加载以下插件(可通过配置扩展): | ||
|
|
||
| - `vscode.theme-defaults` - 默认主题 | ||
| - `vscode.typescript-language-features` - TypeScript 语言服务 | ||
| - `common-extension` - 通用扩展 | ||
|
|
||
| ## 模块设计 | ||
|
|
||
| ### 新增模块:`workspace-trust` | ||
|
|
||
| 在 `packages/workspace-trust/` 下创建新模块: | ||
|
|
||
| #### 文件结构 | ||
|
|
||
| ``` | ||
| packages/workspace-trust/ | ||
| ├── package.json | ||
| ├── src/ | ||
| │ ├── common/ | ||
| │ │ └── index.ts # 公共常量和类型定义 | ||
| │ └── browser/ | ||
| │ ├── index.ts # 模块入口,BrowserModule 定义 | ||
| │ ├── workspace-trust.service.ts # WorkspaceTrustService | ||
| │ ├── workspace-trust.contribution.ts # ClientAppContribution, 信任对话框 | ||
| │ └── workspace-trust-statusbar.contribution.ts # 状态栏「受限模式」标识 | ||
| ``` | ||
|
|
||
| #### `WorkspaceTrustService` 核心方法 | ||
|
|
||
| | 方法 | 说明 | | ||
| | --- | --- | | ||
| | `getTrustState(workspacePath: string): WorkspaceTrustState \| undefined` | 获取指定工作区路径的信任状态 | | ||
| | `setTrustState(workspacePath: string, state: WorkspaceTrustState): Promise<void>` | 设置并持久化信任状态 | | ||
| | `isRestricted(): boolean` | 当前工作区是否处于受限模式 | | ||
| | `showTrustDialog(): Promise<WorkspaceTrustState>` | 弹出信任选择对话框 | | ||
| | `ensureTrustDecided(): Promise<void>` | 确保当前工作区已有信任决定(如没有则弹窗) | | ||
| | `getAllowedExtensionIds(): string[]` | 受限模式下允许加载的插件 ID 白名单 | | ||
|
|
||
| #### `WorkspaceTrustContribution` | ||
|
|
||
| 实现 `ClientAppContribution` 接口: | ||
|
|
||
| - `initialize()`: 检查当前工作区的信任状态,如果未决定则弹出信任对话框 | ||
| - 此方法在 `ExtensionClientAppContribution.initialize()` 之前执行(通过模块依赖保证) | ||
|
|
||
| #### `WorkspaceTrustStatusbarContribution` | ||
|
|
||
| - 在受限模式下,于状态栏右侧显示「受限模式」标识 | ||
| - 点击可跳转到设置页面解除受限模式 | ||
|
|
||
| ## 集成点 | ||
|
|
||
| ### 1. 信任检查时机 | ||
|
|
||
| `WorkspaceTrustContribution.initialize()` 在 app 启动的 `initialize` 阶段执行。此时: | ||
|
|
||
| 1. 获取当前工作区路径(从 `AppConfig.workspaceDir`) | ||
| 2. 查询 globalStorage 中是否已有信任状态 | ||
| 3. 如果没有,弹出信任对话框,等待用户选择 | ||
| 4. 将用户的决定写入 globalStorage | ||
|
|
||
| ### 2. 插件过滤时机 | ||
|
|
||
| 修改 `ExtensionServiceImpl.initExtensionMetaData()`,在获取到所有插件元数据后: | ||
|
|
||
| 1. 检查 `WorkspaceTrustService.isRestricted()` | ||
| 2. 如果是受限模式,过滤 `extensionMetaDataArr`,仅保留白名单中的插件 | ||
|
|
||
| ### 3. 状态栏显示 | ||
|
|
||
| `WorkspaceTrustStatusbarContribution` 在 `onStart()` 阶段: | ||
|
|
||
| 1. 检查 `WorkspaceTrustService.isRestricted()` | ||
| 2. 如果是受限模式,在状态栏右侧添加「受限模式」元素 | ||
|
|
||
| ## 模块依赖 | ||
|
|
||
| ``` | ||
| workspace-trust → extension (依赖关系:workspace-trust 模块需要在 extension 之前初始化) | ||
| workspace-trust → workspace (获取工作区路径) | ||
| ``` | ||
|
|
||
| ## 后续扩展 | ||
|
|
||
| - 在设置页面添加「管理工作区信任」入口,允许用户修改已有工作区的信任状态 | ||
| - 支持更多类型的白名单插件配置 | ||
| - 受限模式下禁用终端、调试等可能存在安全风险的功能 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| /** | ||
| * Workspace trust state enum | ||
| */ | ||
| export enum WorkspaceTrustState { | ||
| /** User has not yet decided */ | ||
| Undecided = 'undecided', | ||
| /** User trusts this workspace - all extensions loaded */ | ||
| Trusted = 'trusted', | ||
| /** User chose restricted mode - only allowed extensions loaded */ | ||
| Restricted = 'restricted', | ||
| } | ||
|
|
||
| /** | ||
| * Storage key prefix for workspace trust state | ||
| */ | ||
| export const WORKSPACE_TRUST_STORAGE_KEY = 'workspace_trust_state'; | ||
|
|
||
| /** | ||
| * Service token for WorkspaceTrustService | ||
| */ | ||
| export const WorkspaceTrustServiceToken = Symbol('WorkspaceTrustService'); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| export { WorkspaceTrustService } from './workspace-trust.service'; | ||
| export { WorkspaceTrustContribution } from './workspace-trust.contribution'; | ||
| export { WorkspaceTrustStatusBarContribution } from './workspace-trust-statusbar.contribution'; | ||
| export { | ||
| WorkspaceTrustCommandContribution, | ||
| WORKSPACE_TRUST_EXIT_RESTRICTED_COMMAND, | ||
| } from './workspace-trust-command.contribution'; | ||
| export { WorkspaceTrustSettingsContribution } from './workspace-trust-settings.contribution'; | ||
| export { WorkspaceTrustState } from './common'; |
53 changes: 53 additions & 0 deletions
53
packages/core-browser/src/workspace-trust/workspace-trust-command.contribution.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| import { Autowired } from '@opensumi/di'; | ||
| import { CommandContribution, CommandRegistry, CommandService, MessageType, localize } from '@opensumi/ide-core-common'; | ||
| import { Domain } from '@opensumi/ide-core-common/lib/di-helper'; | ||
|
|
||
| import { IClientApp } from '../browser-module'; | ||
| import { ClientAppContribution } from '../common/common.define'; | ||
|
|
||
| import { WorkspaceTrustState } from './common'; | ||
| import { WorkspaceTrustService } from './workspace-trust.service'; | ||
|
|
||
| export const WORKSPACE_TRUST_EXIT_RESTRICTED_COMMAND = { | ||
| id: 'workspace.trust.exitRestricted', | ||
| label: localize('workspace.trust.exitRestricted.label', 'Exit Restricted Mode'), | ||
| }; | ||
|
|
||
| @Domain(CommandContribution, ClientAppContribution) | ||
| export class WorkspaceTrustCommandContribution implements CommandContribution, ClientAppContribution { | ||
| @Autowired(WorkspaceTrustService) | ||
| private readonly workspaceTrustService: WorkspaceTrustService; | ||
|
|
||
| @Autowired(IClientApp) | ||
| private readonly clientApp: IClientApp; | ||
|
|
||
| @Autowired(CommandService) | ||
| private readonly commandService: CommandService; | ||
|
|
||
| registerCommands(commands: CommandRegistry) { | ||
| commands.registerCommand(WORKSPACE_TRUST_EXIT_RESTRICTED_COMMAND, { | ||
| execute: async () => { | ||
| const okText = localize('workspace.trust.exitRestricted.confirm.ok', 'Trust and Reload'); | ||
| const cancelText = localize('workspace.trust.exitRestricted.cancel', 'Cancel'); | ||
|
|
||
| const msg = await this.commandService.executeCommand<string>('dialog.open', { | ||
| message: localize( | ||
| 'workspace.trust.exitRestricted.confirm.message', | ||
| 'Are you sure you want to trust the authors of the files in this workspace and exit Restricted Mode?', | ||
| ), | ||
| type: MessageType.Info, | ||
| buttons: [okText, cancelText], | ||
| }); | ||
|
|
||
| if (msg === okText) { | ||
| await this.workspaceTrustService.setTrustState(WorkspaceTrustState.Trusted); | ||
| this.clientApp.fireOnReload(true); | ||
| } | ||
| }, | ||
| }); | ||
| } | ||
|
|
||
| onStart() { | ||
| // no-op | ||
| } | ||
| } |
37 changes: 37 additions & 0 deletions
37
packages/core-browser/src/workspace-trust/workspace-trust-setting-panel.module.less
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| .workspaceTrustPanel { | ||
| padding: 12px 18px; | ||
|
|
||
| .description { | ||
| margin-bottom: 12px; | ||
| color: var(--foreground); | ||
| font-size: 13px; | ||
| line-height: 1.5; | ||
| } | ||
|
|
||
| .button { | ||
| padding: 6px 16px; | ||
| border: none; | ||
| border-radius: 4px; | ||
| cursor: pointer; | ||
| font-size: 13px; | ||
| color: #fff; | ||
| transition: opacity 0.15s; | ||
|
|
||
| &:hover:not(:disabled) { | ||
| opacity: 0.85; | ||
| } | ||
|
|
||
| &:disabled { | ||
| opacity: 0.5; | ||
| cursor: not-allowed; | ||
| } | ||
| } | ||
|
|
||
| .buttonTrust { | ||
| background-color: var(--button-background); | ||
| } | ||
|
|
||
| .buttonRestrict { | ||
| background-color: var(--button-background); | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
externalSearchBehavior 模式下仍执行内部过滤,和新语义不一致
Line 305 已启用“外部托管”语义,但 Line 484-507 仍会在输入时调用
filterOption。建议在 external 模式直接跳过内部过滤,避免契约偏差和额外开销。建议修复
Also applies to: 484-507
🤖 Prompt for AI Agents