新增: AI工具授权目录总开关(信任所有目录)
- path_auth判定加bypass旁路:开启时白名单外目录免逐次询问直接放行 - 黑名单凭据目录保护不随开关放行(安全硬边界保留) - 设置页授权目录面板加开关(默认关,读取失败按关处理) - 对话区开启时常驻放行提示横幅防静默裸奔,中英i18n齐
This commit is contained in:
@@ -29,6 +29,10 @@
|
||||
@provider-switched="(name: string) => showToast(t('aiChat.providerSwitched', { model: name }), 'info')"
|
||||
/>
|
||||
|
||||
<!-- 「信任所有目录」放行横幅:开关开启期间常驻提示(设置-安全-AI 工具授权目录),
|
||||
提醒当前 AI 可直接访问任意非受保护目录;黑名单目录仍被拒绝 -->
|
||||
<div v-if="pathAuthBypass" class="ai-auth-bypass-banner">{{ $t('aiChat.pathAuthBypassBanner') }}</div>
|
||||
|
||||
<!-- 第四批抽离至 ai/MessageList.vue(消息列表 + 流式 Markdown 分块渲染 + 工具卡转发 +
|
||||
折叠归档段 + 滚动跟随/回底部,零行为变更,store/useMarkdown 单例共享) -->
|
||||
<MessageList
|
||||
@@ -161,6 +165,8 @@ const router = useRouter()
|
||||
// 关(false,兜底回退):挂 DirAuthDialog 独立弹窗老链路(useAiEvents AiDirAuthRequired case 走 pendingDirAuths)。
|
||||
const appSettings = useAppSettingsStore()
|
||||
const unifiedApproval = appSettings.useSetting<boolean>('df-ai-unified-approval', true)
|
||||
// 「信任所有目录」总开关(与设置页 AllowedDirsPanel 同一 KV):开启时对话区顶部常驻放行横幅
|
||||
const pathAuthBypass = appSettings.useSetting<boolean>('df-ai-path-auth-bypass', false)
|
||||
|
||||
// ── 空状态示例问题随 MessageList 子组件迁移(examplePrompts 数组在子组件内);
|
||||
// 父仅保留 sendExamplePrompt 转发(子 emit 'send-example-prompt' → 父委托 ChatInput.sendExamplePrompt)。──
|
||||
@@ -683,6 +689,16 @@ async function initContextEventListeners(): Promise<void> {
|
||||
TopBar.vue scoped 自持 + .ai-btn-icon* 抽 components.css 全局共享,
|
||||
原 AiChat scoped 不渗透子组件根,删此重复块零视觉变更) */
|
||||
|
||||
/* ── 「信任所有目录」放行横幅(开关开启期间常驻,warning 色系对齐 .ai-toast-warning) ── */
|
||||
.ai-auth-bypass-banner {
|
||||
padding: 5px 14px;
|
||||
background: var(--df-warning-bg);
|
||||
color: var(--df-warning);
|
||||
border-bottom: 0.5px solid color-mix(in srgb, var(--df-warning) 40%, transparent);
|
||||
font-size: 12px;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
/* ═══ Input ═══ */
|
||||
.ai-input-area {
|
||||
padding: 10px 14px;
|
||||
|
||||
@@ -8,6 +8,15 @@
|
||||
<!-- 说明 -->
|
||||
<p class="allowed-dirs-desc">{{ $t('settings.descAllowedDirs') }}</p>
|
||||
|
||||
<!-- 「信任所有目录」总开关:开启后白名单外路径不再逐次弹授权(后端黑名单仍硬拒)。
|
||||
走 appSettings KV(df-ai-path-auth-bypass),后端 process_tool_calls 每轮读取,改后即时生效。 -->
|
||||
<SettingRow :label="$t('settings.labelPathAuthBypass')" :desc="$t('settings.descPathAuthBypass')">
|
||||
<label class="toggle">
|
||||
<input type="checkbox" v-model="pathAuthBypass" />
|
||||
<span class="toggle-slider"></span>
|
||||
</label>
|
||||
</SettingRow>
|
||||
|
||||
<!-- 列表 -->
|
||||
<div v-if="loading" class="empty-hint">{{ $t('settings.allowedDirsLoading') }}</div>
|
||||
<template v-else>
|
||||
@@ -99,6 +108,9 @@ const newDir = ref('')
|
||||
const loading = ref(true)
|
||||
const saving = ref(false)
|
||||
|
||||
// 「信任所有目录」总开关(useSetting 双向绑 KV,写走 debounced 落库,后端每轮工具执行前读)
|
||||
const pathAuthBypass = appSettings.useSetting<boolean>('df-ai-path-auth-bypass', false)
|
||||
|
||||
async function load() {
|
||||
loading.value = true
|
||||
try {
|
||||
|
||||
@@ -189,6 +189,8 @@ export default {
|
||||
dirAuthFailed: 'Authorization failed: {msg}',
|
||||
// M5:path deny second confirmation (deny is irreversible — tool returns Err, loop continues without retry; asymmetry with approve, prevents mis-clicks)
|
||||
dirAuthDenyConfirm: 'Deny authorization? The tool will fail immediately and will not be retried this round.',
|
||||
// Persistent bypass banner shown at the top of the chat area while "trust all directories" is on
|
||||
pathAuthBypassBanner: 'Authorization bypassed: AI can access files directly',
|
||||
|
||||
// ── Input Augmentation layer: mention/skill injection feedback ──
|
||||
// search_files blind search denied by whitelist fallback (no auth dialog; prompt user to use @mention or absolute path)
|
||||
|
||||
@@ -192,6 +192,9 @@ export default {
|
||||
allowedDirsDup: 'This directory is already in the authorized list',
|
||||
allowedDirsAddFail: 'Failed to add authorized directory',
|
||||
allowedDirsRemoveFail: 'Failed to remove authorized directory',
|
||||
// "Trust all directories" master switch (Settings - Security - AI Tool Allowed Dirs panel)
|
||||
labelPathAuthBypass: 'Trust all directories',
|
||||
descPathAuthBypass: 'When enabled, AI can directly access any unprotected directory without per-access prompts; protected (blacklisted) directories such as credential folders are still denied.',
|
||||
|
||||
// ===== ScriptNode command execution safety =====
|
||||
panelScriptSafety: '🛡️ Command Execution Safety',
|
||||
|
||||
@@ -190,6 +190,8 @@ export default {
|
||||
dirAuthFailed: '授权失败:{msg}',
|
||||
// M5:path 类拒绝二次确认(拒绝不可逆——工具返 Err、loop 续跑不再重试,与 approve 不对称,防误点)
|
||||
dirAuthDenyConfirm: '确定拒绝授权吗?该工具将立即失败,且本轮不会重试。',
|
||||
// 「信任所有目录」总开关开启期间的常驻放行横幅(对话区顶部)
|
||||
pathAuthBypassBanner: '授权已放行:AI 可直接访问文件',
|
||||
|
||||
// ── Input Augmentation 层: mention/skill 注入反馈 ──
|
||||
// search_files 盲搜被白名单兜底拒绝(不应弹授权窗,直接友好提示用户改用 @引用或绝对路径)
|
||||
|
||||
@@ -191,6 +191,9 @@ export default {
|
||||
allowedDirsDup: '该目录已在授权列表中',
|
||||
allowedDirsAddFail: '添加授权目录失败',
|
||||
allowedDirsRemoveFail: '删除授权目录失败',
|
||||
// 「信任所有目录」总开关(设置-安全-AI 工具授权目录面板)
|
||||
labelPathAuthBypass: '信任所有目录',
|
||||
descPathAuthBypass: '开启后 AI 可直接访问任意非受保护目录,不再逐次询问;凭据等受保护目录(黑名单)仍被拒绝。',
|
||||
|
||||
// ===== ScriptNode 命令执行安全 =====
|
||||
panelScriptSafety: '🛡️ 命令执行安全',
|
||||
|
||||
Reference in New Issue
Block a user