mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-04-29 12:11:09 +00:00
feat(permissions): add permission system and rename folder trust command
This commit is contained in:
parent
407a66c959
commit
eeb4d85785
33 changed files with 3295 additions and 205 deletions
|
|
@ -68,6 +68,7 @@ import { ideContextStore } from '../ide/ideContext.js';
|
|||
import { InputFormat, OutputFormat } from '../output/types.js';
|
||||
import { PromptRegistry } from '../prompts/prompt-registry.js';
|
||||
import { SkillManager } from '../skills/skill-manager.js';
|
||||
import { PermissionManager } from '../permissions/permission-manager.js';
|
||||
import { SubagentManager } from '../subagents/subagent-manager.js';
|
||||
import type { SubagentConfig } from '../subagents/types.js';
|
||||
import {
|
||||
|
|
@ -289,9 +290,18 @@ export interface ConfigParameters {
|
|||
debugMode: boolean;
|
||||
includePartialMessages?: boolean;
|
||||
question?: string;
|
||||
/** @deprecated Use `permissions.allow` instead. Migrated automatically. */
|
||||
coreTools?: string[];
|
||||
/** @deprecated Use `permissions.allow` instead. Migrated automatically. */
|
||||
allowedTools?: string[];
|
||||
/** @deprecated Use `permissions.deny` instead. Migrated automatically. */
|
||||
excludeTools?: string[];
|
||||
/** Merged permission rules from all sources (settings + CLI args). */
|
||||
permissions?: {
|
||||
allow?: string[];
|
||||
ask?: string[];
|
||||
deny?: string[];
|
||||
};
|
||||
toolDiscoveryCommand?: string;
|
||||
toolCallCommand?: string;
|
||||
mcpServerCommand?: string;
|
||||
|
|
@ -420,6 +430,7 @@ export class Config {
|
|||
private subagentManager!: SubagentManager;
|
||||
private extensionManager!: ExtensionManager;
|
||||
private skillManager: SkillManager | null = null;
|
||||
private permissionManager: PermissionManager | null = null;
|
||||
private fileSystemService: FileSystemService;
|
||||
private contentGeneratorConfig!: ContentGeneratorConfig;
|
||||
private contentGeneratorConfigSources: ContentGeneratorConfigSources = {};
|
||||
|
|
@ -439,6 +450,9 @@ export class Config {
|
|||
private readonly coreTools: string[] | undefined;
|
||||
private readonly allowedTools: string[] | undefined;
|
||||
private readonly excludeTools: string[] | undefined;
|
||||
private readonly permissionsAllow: string[] | undefined;
|
||||
private readonly permissionsAsk: string[] | undefined;
|
||||
private readonly permissionsDeny: string[] | undefined;
|
||||
private readonly toolDiscoveryCommand: string | undefined;
|
||||
private readonly toolCallCommand: string | undefined;
|
||||
private readonly mcpServerCommand: string | undefined;
|
||||
|
|
@ -544,6 +558,9 @@ export class Config {
|
|||
this.coreTools = params.coreTools;
|
||||
this.allowedTools = params.allowedTools;
|
||||
this.excludeTools = params.excludeTools;
|
||||
this.permissionsAllow = params.permissions?.allow;
|
||||
this.permissionsAsk = params.permissions?.ask;
|
||||
this.permissionsDeny = params.permissions?.deny;
|
||||
this.toolDiscoveryCommand = params.toolDiscoveryCommand;
|
||||
this.toolCallCommand = params.toolCallCommand;
|
||||
this.mcpServerCommand = params.mcpServerCommand;
|
||||
|
|
@ -701,6 +718,10 @@ export class Config {
|
|||
await this.skillManager.startWatching();
|
||||
this.debugLogger.debug('Skill manager initialized');
|
||||
|
||||
this.permissionManager = new PermissionManager(this);
|
||||
this.permissionManager.initialize();
|
||||
this.debugLogger.debug('Permission manager initialized');
|
||||
|
||||
// Load session subagents if they were provided before initialization
|
||||
if (this.sessionSubagents.length > 0) {
|
||||
this.subagentManager.loadSessionSubagents(this.sessionSubagents);
|
||||
|
|
@ -1073,6 +1094,10 @@ export class Config {
|
|||
return this.targetDir;
|
||||
}
|
||||
|
||||
getCwd(): string {
|
||||
return this.targetDir;
|
||||
}
|
||||
|
||||
getWorkspaceContext(): WorkspaceContext {
|
||||
return this.workspaceContext;
|
||||
}
|
||||
|
|
@ -1115,18 +1140,69 @@ export class Config {
|
|||
return this.question;
|
||||
}
|
||||
|
||||
/** @deprecated Use getPermissionsAllow() instead. */
|
||||
getCoreTools(): string[] | undefined {
|
||||
return this.coreTools;
|
||||
}
|
||||
|
||||
/** @deprecated Use getPermissionsAllow() instead. */
|
||||
getAllowedTools(): string[] | undefined {
|
||||
return this.allowedTools;
|
||||
}
|
||||
|
||||
/** @deprecated Use getPermissionsDeny() instead. */
|
||||
getExcludeTools(): string[] | undefined {
|
||||
return this.excludeTools;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the merged allow-rules for PermissionManager.
|
||||
*
|
||||
* This merges all sources so that PermissionManager receives a single,
|
||||
* authoritative list:
|
||||
* - settings.permissions.allow (persistent rules from all scopes)
|
||||
* - coreTools param (SDK / argv allowlist mode: only these tools run)
|
||||
* - allowedTools param (SDK / argv auto-approve list)
|
||||
*
|
||||
* CLI callers (loadCliConfig) already pre-merge argv into permissionsAllow
|
||||
* before constructing Config, so those fields will be empty for CLI usage.
|
||||
* SDK callers construct Config directly and rely on coreTools/allowedTools.
|
||||
*/
|
||||
getPermissionsAllow(): string[] | undefined {
|
||||
const base = this.permissionsAllow ?? [];
|
||||
const sdkAllow = [...(this.coreTools ?? []), ...(this.allowedTools ?? [])];
|
||||
if (sdkAllow.length === 0) return base.length > 0 ? base : undefined;
|
||||
const merged = [...base];
|
||||
for (const t of sdkAllow) {
|
||||
if (t && !merged.includes(t)) merged.push(t);
|
||||
}
|
||||
return merged;
|
||||
}
|
||||
|
||||
getPermissionsAsk(): string[] | undefined {
|
||||
return this.permissionsAsk;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the merged deny-rules for PermissionManager.
|
||||
*
|
||||
* Merges:
|
||||
* - settings.permissions.deny (persistent rules from all scopes)
|
||||
* - excludeTools param (SDK / argv blocklist)
|
||||
*
|
||||
* CLI callers pre-merge argv.excludeTools into permissionsDeny.
|
||||
*/
|
||||
getPermissionsDeny(): string[] | undefined {
|
||||
const base = this.permissionsDeny ?? [];
|
||||
const sdkDeny = this.excludeTools ?? [];
|
||||
if (sdkDeny.length === 0) return base.length > 0 ? base : undefined;
|
||||
const merged = [...base];
|
||||
for (const t of sdkDeny) {
|
||||
if (t && !merged.includes(t)) merged.push(t);
|
||||
}
|
||||
return merged;
|
||||
}
|
||||
|
||||
getToolDiscoveryCommand(): string | undefined {
|
||||
return this.toolDiscoveryCommand;
|
||||
}
|
||||
|
|
@ -1642,6 +1718,10 @@ export class Config {
|
|||
return this.skillManager;
|
||||
}
|
||||
|
||||
getPermissionManager(): PermissionManager | null {
|
||||
return this.permissionManager;
|
||||
}
|
||||
|
||||
async createToolRegistry(
|
||||
sendSdkMcpMessage?: SendSdkMcpMessage,
|
||||
): Promise<ToolRegistry> {
|
||||
|
|
@ -1669,7 +1749,20 @@ export class Config {
|
|||
return;
|
||||
}
|
||||
|
||||
if (isToolEnabled(toolName, coreToolsConfig, excludeToolsConfig)) {
|
||||
// Two-layer check: legacy coreTools/excludeTools whitelist + PM deny rules.
|
||||
// Legacy isToolEnabled() preserves the whitelist semantic where coreTools
|
||||
// acts as a strict allowlist (only listed tools are registered).
|
||||
// PM.isToolEnabled() handles deny rules from the new permissions system.
|
||||
const legacyEnabled = isToolEnabled(
|
||||
toolName,
|
||||
coreToolsConfig,
|
||||
excludeToolsConfig,
|
||||
);
|
||||
const pmEnabled = this.permissionManager
|
||||
? this.permissionManager.isToolEnabled(toolName)
|
||||
: true; // Should never reach here after initialize(), but safe default.
|
||||
|
||||
if (legacyEnabled && pmEnabled) {
|
||||
try {
|
||||
registry.registerTool(new ToolClass(...args));
|
||||
} catch (error) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue