MCP v2 PR-1: policy engine + audit log + Config/Audit/Policy panel tabs
Foundation for Claude-drives-the-workspace writes. Nothing wired end-to-end yet (App.tsx dispatcher comes next); this lands the machinery + UI. mcp_policy.rs (new) — three-tier allow/ask/deny policy with deny-first precedence and a compiled-in non-overridable hard-deny list (10 patterns covering rm -rf /, fork bombs, mkfs on device, dd to raw disk, /etc/passwd overwrite, curl|sh, chmod -R 777 /, etc.). Shell-operator-aware glob matcher mirroring Claude Code's Bash(*) syntax. Restrictive default — empty policy means every non-hard- denied call falls to Ask. Persisted to mcp-policy.json in app_config_dir. Includes a PolicyClassifier scaffold (no-op) for a future v2.1 LLM-classifier hook. 1152 lines incl. ~100 unit + fuzz tests covering the matchers and lookalike negatives. mcp.rs — TileService now holds AppHandle + Arc<PendingActions> (oneshot registry keyed by uuid). New async dispatch_action helper runs the policy check, emits "mcp://request" for the frontend to handle, awaits a oneshot reply (30s timeout), then emits "mcp:// audit" with the outcome regardless. set_label tool wired through this path as the demo for PR-1b's dispatcher. commands.rs / lib.rs — new Tauri commands mcp_action_reply, mcp_policy_load, mcp_policy_save; PendingActions registered as managed state. McpPanel.tsx — refactored into Config / Audit / Policy tabs. AuditTab listens on mcp://audit, keeps a 200-entry ring with ok/denied/failed chips. PolicyTab edits the allow/ask/deny buckets (stacked vertically — three columns overflowed the panel) and shows the hard-deny rules read-only at the bottom with "Cannot be disabled" badges. Themed scrollbar on mcp-body to match xterm panes. Caveat: set_label calls from Claude will currently time out — the App.tsx side that listens on mcp://request and replies via mcp_action_reply lands in PR-1b. Co-authored by Sonnet (policy engine, backend plumbing, panel UI) and Haiku (hard-deny fuzz test suite); integration + bug fixes here.
This commit is contained in:
parent
b14b450577
commit
464c576b79
11 changed files with 2512 additions and 144 deletions
|
|
@ -4,11 +4,12 @@ mod commands;
|
|||
mod creds;
|
||||
mod hosts;
|
||||
mod mcp;
|
||||
mod mcp_policy;
|
||||
mod pty;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::mcp::{McpServerHandle, McpState};
|
||||
use crate::mcp::{McpServerHandle, McpState, PendingActions};
|
||||
use crate::pty::PtyManager;
|
||||
|
||||
pub fn run() {
|
||||
|
|
@ -36,6 +37,9 @@ pub fn run() {
|
|||
let ptys: Arc<PtyManager> = Arc::new(PtyManager::new());
|
||||
let mcp_state: Arc<tokio::sync::RwLock<McpState>> =
|
||||
Arc::new(tokio::sync::RwLock::new(McpState::default()));
|
||||
// Pending action registry — separate managed state so mcp_action_reply can
|
||||
// grab it without needing to lock McpState or reach into TileService.
|
||||
let pending_actions: Arc<PendingActions> = Arc::new(PendingActions::default());
|
||||
|
||||
tauri::Builder::default()
|
||||
.plugin(tauri_plugin_clipboard_manager::init())
|
||||
|
|
@ -43,6 +47,7 @@ pub fn run() {
|
|||
.manage(ptys)
|
||||
.manage(mcp_state)
|
||||
.manage(McpServerHandle::default())
|
||||
.manage(pending_actions)
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
commands::list_distros,
|
||||
commands::spawn_pane,
|
||||
|
|
@ -61,6 +66,9 @@ pub fn run() {
|
|||
commands::mcp_status,
|
||||
commands::mcp_regenerate_token,
|
||||
commands::mcp_update_state,
|
||||
commands::mcp_action_reply,
|
||||
commands::mcp_policy_load,
|
||||
commands::mcp_policy_save,
|
||||
])
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue