Add security hardening, Ghidra, recreate skill, checkpoints, shells, web search and themes
- Sandbox (bubblewrap) for non-admin shell/git, MCP per-user rights, hard budgets and quotas, login rate limiting, audit log and backups - Ghidra headless decompilation (ARM64 natives built from source), binary_info tool, clean room / deep workflow per session - Recreate skill and commands for analysing and re-building old software - File checkpoints with rewind/restore, background shells (bash_output, kill_shell) - web_search tool (DuckDuckGo, SearXNG, Brave, Tavily) - In-app dialogs and toasts instead of browser dialogs - 15 base themes (trilium-themes palettes plus Nord, VS Code, GitHub, Catppuccin, One, Dracula, Rose Pine, Everforest, Kanagawa) with light/dark/auto switcher and license notes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
fab9add5d5
commit
5b569b6835
108 files changed
+6785
-279
No files matched your search
@@ -21,6 +21,38 @@ pub struct Config {
|
||||
pub craft: CraftConfig,
|
||||
pub auth: AuthConfig,
|
||||
pub images: ImagesConfig,
|
||||
pub sandbox: SandboxConfig,
|
||||
pub search: SearchConfig,
|
||||
}
|
||||
|
||||
/// Web search for the web_search tool.
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
#[serde(default)]
|
||||
pub struct SearchConfig {
|
||||
/// "duckduckgo" (no key), "searxng", "brave" or "tavily".
|
||||
pub provider: String,
|
||||
/// SearXNG base URL.
|
||||
pub url: String,
|
||||
pub api_key: String,
|
||||
}
|
||||
|
||||
impl Default for SearchConfig {
|
||||
fn default() -> Self {
|
||||
Self { provider: "duckduckgo".into(), url: String::new(), api_key: String::new() }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
#[serde(default)]
|
||||
pub struct SandboxConfig {
|
||||
/// "auto": sandbox shell/git of non-admin users, "always": everybody, "off": nobody.
|
||||
pub mode: String,
|
||||
}
|
||||
|
||||
impl Default for SandboxConfig {
|
||||
fn default() -> Self {
|
||||
Self { mode: "auto".into() }
|
||||
}
|
||||
}
|
||||
|
||||
/// Image generation via fal.ai.
|
||||
@@ -152,6 +184,8 @@ pub struct ServerConfig {
|
||||
pub monthly_budget: f64,
|
||||
/// Warn when this share of a budget is used (0.0–1.0).
|
||||
pub budget_warning: f64,
|
||||
/// "warn" (default) or "block": refuse new model requests once a budget is used up.
|
||||
pub budget_action: String,
|
||||
}
|
||||
|
||||
impl Default for ServerConfig {
|
||||
@@ -168,6 +202,7 @@ impl Default for ServerConfig {
|
||||
mcp_direct_limit: 15,
|
||||
monthly_budget: 0.0,
|
||||
budget_warning: 0.8,
|
||||
budget_action: "warn".into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -292,6 +327,20 @@ pub struct McpConfig {
|
||||
/// "auto" (default), "always" or "on_demand": how the server's tools reach the model.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub load: Option<String>,
|
||||
/// Who may use this server besides admins: usernames or "*" for everybody.
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub users: Vec<String>,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
/// Whether a session owner may use an MCP server (no owner = legacy/admin).
|
||||
pub fn mcp_allowed(&self, server: &str, user: Option<&crate::store::User>) -> bool {
|
||||
match user {
|
||||
None => true,
|
||||
Some(u) if u.is_admin() => true,
|
||||
Some(u) => self.mcp.get(server).is_some_and(|m| m.users.iter().any(|x| x == "*" || x.eq_ignore_ascii_case(&u.username))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq)]
|
||||
@@ -533,6 +582,9 @@ pub fn redacted_json(cfg: &Config) -> serde_json::Value {
|
||||
if let Some(t) = v.pointer_mut("/images/admin_key") {
|
||||
mask(t);
|
||||
}
|
||||
if let Some(t) = v.pointer_mut("/search/api_key") {
|
||||
mask(t);
|
||||
}
|
||||
v
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user