tiletopia/src-tauri/src/lib.rs
megaproxy 5b970f8b48 Hard-deny: PowerShell patterns + drift-proof the label list
Four new compiled-in hard-deny rules covering PowerShell + cmd.exe
catastrophic patterns (mirror of the POSIX 10):

- Remove-Item / del / rd / ri / rm / erase / rmdir targeting C:\
  or user home / appdata
- Format-Volume / Clear-Disk with any flag (= an invocation, not a
  Get-Help lookup)
- iwr | iex pipe form (PowerShell web-to-execute)
- iex (irm ...) parenthesized form

Universal application — no shell-aware scoping yet. PS cmdlet
identifiers are distinctive enough that bash false-positives are
vanishingly unlikely. Shell-aware policy scoping remains a known
follow-up.

Drift-proof the "Always blocked" label list: backend now exposes
hard_deny_rules() via a new mcp_hard_deny_labels Tauri command, and
PolicyTab loads it at mount instead of hardcoding the list. Avoids
the 11→15 manual sync that would have been needed (and that had
already drifted twice this week).

cargo test --lib: 138 passed; 0 failed (118 prior + 20 new fuzz
cases for rules 11-14; hard_deny_rules_count bumped 10 → 14).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 17:14:42 +01:00

76 lines
2.9 KiB
Rust

//! Library entry point. `main.rs` calls `run()`.
mod commands;
mod creds;
mod hosts;
mod mcp;
mod mcp_policy;
mod pty;
use std::sync::Arc;
use crate::mcp::{McpServerHandle, McpState, PendingActions};
use crate::pty::PtyManager;
pub fn run() {
let _ = tracing_subscriber::fmt()
.with_env_filter(
tracing_subscriber::EnvFilter::try_from_default_env()
.unwrap_or_else(|_| tracing_subscriber::EnvFilter::new("info")),
)
.with_writer(std::io::stderr)
.try_init();
// keyring-core 1.x requires explicit store registration before any
// Entry::new() call. We're Windows-only so the Credential Manager
// backend is the only choice. Failure here means SSH passwords won't
// be retrievable — log and continue (host configs still work without
// saved passwords; users just see the prompt and type it manually).
match windows_native_keyring_store::Store::new() {
Ok(store) => keyring_core::set_default_store(store),
Err(e) => tracing::warn!("keyring store init failed: {e}"),
}
// PtyManager and McpState are shared with the MCP server, so register
// them as Arc<T> rather than the plain T. Tauri commands access them
// via `tauri::State<'_, Arc<T>>` and deref / clone as needed.
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())
.plugin(tauri_plugin_opener::init())
.manage(ptys)
.manage(mcp_state)
.manage(McpServerHandle::default())
.manage(pending_actions)
.invoke_handler(tauri::generate_handler![
commands::list_distros,
commands::spawn_pane,
commands::write_to_pane,
commands::resize_pane,
commands::kill_pane,
commands::save_workspace,
commands::load_workspace,
commands::list_ssh_hosts,
commands::save_ssh_hosts,
commands::set_host_password,
commands::delete_host_password,
commands::has_host_password,
commands::mcp_start,
commands::mcp_stop,
commands::mcp_status,
commands::mcp_regenerate_token,
commands::mcp_update_state,
commands::mcp_action_reply,
commands::mcp_policy_load,
commands::mcp_policy_save,
commands::mcp_hard_deny_labels,
])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}