M2 audit: excise managed connectors and xAI media-gen tools

Managed connectors (grok.com MCP admin) removed root-and-branch:
- The managed-MCP fetch/injection pipeline is gone, including the whole
  kigi-shell-session-support crate (managed-config fetch client, gateway
  tool catalog + dispatch, header injection, refresh task), reactive
  managed re-auth, mcp_doctor's grok.com-source discovery, and the
  [managed_mcps] config surface.
- TUI: the 'Managed by grok.com' section, connectors URL/deep-link,
  Action::OpenManagedConnectors, and session_team_id are gone. Local MCP
  management (list/toggle/add/remove/auth/tools) is fully intact.
- Kept as LOCAL policy: managed-settings.json MCP allow/deny enforcement,
  the multi-source local MCP merge, folder-trust gating. PluginOrigin
  Project/User labels kept (they tag locally discovered plugin dirs).

imagine/media-gen tools (xAI image/video generation) removed:
- image_gen, image_edit, video_gen, image_to_video, reference_to_video
  implementations, registrations, ToolKind/ToolInput/Output variants
  (serde-safe), config plumbing end to end, ZDR video machinery,
  /imagine + /imagine-video commands and guidance text, the bundled
  imagine skill (added to legacy cleanup so user installs delete it),
  and the media-gen render path.
- Kept: image INPUT (paste/attach, [Image #N] meta, pdf/image fetch,
  clipboard wrap), generic media-ref rendering, and the generic tool
  401-retry machinery (tests renamed, assertions unweakened).
- deploy_app stays: it is a permanently-disabled local stub deploying
  nowhere.

121 files changed, 8 deleted. Gates: workspace check/clippy 0/0, fmt,
deny ok; suites green (tools 2554, shell 4862, tui 6608, workspace
1042). Remaining grok.com strings live only in the auth-method ids and
changelog archives (§9/M3 sweep).
This commit is contained in:
2026-07-17 23:45:05 -04:00
parent fa75eb139a
commit 5e4e24db99
120 changed files with 301 additions and 11327 deletions
+3 -117
View File
@@ -474,62 +474,6 @@ impl SubagentsConfig {
result
}
}
/// Managed MCP connector fetching config (`[managed_mcps]` in config.toml).
///
/// See [`Self::resolve`] for full priority chain.
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
#[serde(default)]
pub struct ManagedMcpsConfig {
pub enabled: bool,
pub gateway_tools_enabled: bool,
}
impl Default for ManagedMcpsConfig {
fn default() -> Self {
Self {
enabled: true,
gateway_tools_enabled: false,
}
}
}
impl ManagedMcpsConfig {
/// Priority: env var > TOML > remote > default (enabled interactive, disabled headless).
pub fn resolve(
config: &toml::Value,
remote: Option<&crate::util::config::RemoteSettings>,
is_headless: bool,
) -> Self {
let mut result: Self = config
.get("managed_mcps")
.and_then(|v| v.clone().try_into().ok())
.unwrap_or(Self {
enabled: !is_headless,
gateway_tools_enabled: false,
});
let managed_mcps_table = config.get("managed_mcps").and_then(|v| v.as_table());
let has_local_enabled = managed_mcps_table.is_some_and(|t| t.contains_key("enabled"));
let resolved = crate::agent::config::resolve_enabled(
None,
"KIGI_MANAGED_MCPS_ENABLED",
result.enabled,
has_local_enabled,
remote.and_then(|r| r.managed_mcps_enabled),
!is_headless,
);
result.enabled = resolved.value;
let has_local_gateway_tools =
managed_mcps_table.is_some_and(|t| t.contains_key("gateway_tools_enabled"));
let gateway_resolved = crate::agent::config::resolve_enabled(
None,
"KIGI_MANAGED_MCP_GATEWAY_TOOLS_ENABLED",
result.gateway_tools_enabled,
has_local_gateway_tools,
remote.and_then(|r| r.managed_mcp_gateway_tools_enabled),
false,
);
result.gateway_tools_enabled = result.enabled && gateway_resolved.value;
result
}
}
/// Auxiliary model overrides under `[models]`.
#[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize)]
#[serde(default)]
@@ -656,8 +600,7 @@ impl ModelOverrideConfig {
///
/// ```toml
/// [tools]
/// disable_zdr_incompatible_tools = true
/// # [tools.zdr_video_output_s3] — see ZdrVideoOutputS3Config
/// respect_gitignore = true
/// ```
#[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize)]
#[serde(default)]
@@ -665,29 +608,12 @@ pub struct ToolsConfig {
/// When `true`, all tools (including `read_file`) filter gitignored
/// files. When `false` (default), each tool picks its own default.
pub respect_gitignore: bool,
/// Drop tools whose xAI API requires server-side artifact storage
/// (currently just `video_gen`). Intended for ZDR-bound teams via
/// `~/.kigi/managed_config.toml`. Defaults to `false`.
pub disable_zdr_incompatible_tools: bool,
/// Optional S3 bucket config for ZDR video output. When present (and
/// valid), video tools presign an upload URL and pass it to the API so
/// the generated video lands in a team-owned bucket instead of being
/// downloaded locally. Only effective when `disable_zdr_incompatible_tools`
/// is `true`. Populated from `[tools.zdr_video_output_s3]` in config.
pub zdr_video_output_s3:
Option<kigi_tools::implementations::grok_build::video_gen::ZdrVideoOutputS3Config>,
}
impl ToolsConfig {
/// Resolve the final tools config, in priority order:
/// 1. Env vars `KIGI_RESPECT_GITIGNORE` and
/// `KIGI_DISABLE_ZDR_INCOMPATIBLE_TOOLS` (`0`/`false` off,
/// `1`/`true` on).
/// 1. Env var `KIGI_RESPECT_GITIGNORE` (`0`/`false` off, `1`/`true` on).
/// 2. `[tools]` block from the merged effective config.
/// 3. Defaults (both `false`).
///
/// Fields are read individually so a malformed
/// `[tools.zdr_video_output_s3]` cannot wipe `disable_zdr_incompatible_tools`
/// (or any other tools flag) via whole-table deserialize failure.
/// 3. Default (`false`).
pub fn resolve(config: &toml::Value) -> Self {
let tools = config.get("tools");
let mut result = Self {
@@ -695,33 +621,6 @@ impl ToolsConfig {
.and_then(|t| t.get("respect_gitignore"))
.and_then(|v| v.as_bool())
.unwrap_or(false),
disable_zdr_incompatible_tools: tools
.and_then(|t| t.get("disable_zdr_incompatible_tools"))
.and_then(|v| v.as_bool())
.unwrap_or(false),
zdr_video_output_s3: tools
.and_then(|t| t.get("zdr_video_output_s3"))
.and_then(|s3_val| match s3_val
.clone()
.try_into::<
kigi_tools::implementations::grok_build::video_gen::ZdrVideoOutputS3Config,
>()
{
Ok(cfg) if cfg.is_valid() => Some(cfg),
Ok(_) => {
tracing::warn!(
"tools.zdr_video_output_s3 is present but incomplete; ignoring ZDR video output config"
);
None
}
Err(e) => {
tracing::warn!(
error = % e,
"tools.zdr_video_output_s3 failed to parse; ignoring ZDR video output config"
);
None
}
}),
};
match std::env::var("KIGI_RESPECT_GITIGNORE").as_deref() {
Ok("0") | Ok("false") => {
@@ -732,15 +631,6 @@ impl ToolsConfig {
}
_ => {}
}
match std::env::var("KIGI_DISABLE_ZDR_INCOMPATIBLE_TOOLS").as_deref() {
Ok("0") | Ok("false") => {
result.disable_zdr_incompatible_tools = false;
}
Ok("1") | Ok("true") => {
result.disable_zdr_incompatible_tools = true;
}
_ => {}
}
result
}
}
@@ -1009,9 +899,6 @@ fn apply_requirements_inner(
pin_feature!(tool_search);
pin_feature!(web_fetch);
pin_feature!(ask_user_question);
pin_requirement_only!(image_gen);
pin_requirement_only!(image_edit);
pin_feature!(video_gen);
pin_feature!(write_file);
pin_feature!(voice_mode);
pin_requirement_only!(remote_fetch);
@@ -1020,7 +907,6 @@ fn apply_requirements_inner(
enforce_opt!("cli", "show_tips", config.cli.show_tips);
enforce_val!("memory", "enabled", config.memory.enabled);
enforce_val!("subagents", "enabled", config.subagents.enabled);
enforce_val!("managed_mcps", "enabled", config.managed_mcps.enabled);
if let Some(val) = req_bool(req, "tools", "respect_gitignore") {
config
.requirements
+6 -247
View File
@@ -1201,154 +1201,6 @@ fn subagents_config_is_subagent_enabled_false_when_toggled_off() {
);
assert!(sa.is_subagent_enabled("explore"), "explore = true should return enabled");
}
fn with_managed_mcp_env<T>(
managed_mcps: Option<&str>,
gateway_tools: Option<&str>,
f: impl FnOnce() -> T,
) -> T {
static LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
let _guard = LOCK.lock().unwrap_or_else(|e| e.into_inner());
with_env_var_opt(
"KIGI_MANAGED_MCPS_ENABLED",
managed_mcps,
|| with_env_var_opt("KIGI_MANAGED_MCP_GATEWAY_TOOLS_ENABLED", gateway_tools, f),
)
}
#[test]
#[serial_test::serial]
fn managed_mcps_interactive_default_enabled() {
with_managed_mcp_env(
None,
None,
|| {
let empty = toml::Value::Table(toml::map::Map::new());
let cfg = ManagedMcpsConfig::resolve(&empty, None, false);
assert!(cfg.enabled);
},
);
}
#[test]
#[serial_test::serial]
fn managed_mcps_headless_default_disabled() {
with_managed_mcp_env(
None,
None,
|| {
let empty = toml::Value::Table(toml::map::Map::new());
let cfg = ManagedMcpsConfig::resolve(&empty, None, true);
assert!(! cfg.enabled);
},
);
}
#[test]
#[serial_test::serial]
fn managed_mcp_gateway_tools_default_disabled() {
with_managed_mcp_env(
None,
None,
|| {
let empty = toml::Value::Table(toml::map::Map::new());
let cfg = ManagedMcpsConfig::resolve(&empty, None, false);
assert!(! cfg.gateway_tools_enabled);
},
);
}
#[test]
#[serial_test::serial]
fn managed_mcp_gateway_tools_require_managed_master() {
with_managed_mcp_env(
None,
None,
|| {
let config: toml::Value = toml::from_str(
r#"
[managed_mcps]
gateway_tools_enabled = true
"#,
)
.unwrap();
let remote = crate::util::config::RemoteSettings {
managed_mcps_enabled: Some(false),
..Default::default()
};
let cfg = ManagedMcpsConfig::resolve(&config, Some(&remote), true);
assert!(! cfg.enabled);
assert!(! cfg.gateway_tools_enabled);
},
);
}
#[test]
#[serial_test::serial]
fn managed_mcp_gateway_tools_remote_enabled() {
with_managed_mcp_env(
None,
None,
|| {
let empty = toml::Value::Table(toml::map::Map::new());
let remote = crate::util::config::RemoteSettings {
managed_mcp_gateway_tools_enabled: Some(true),
..Default::default()
};
let cfg = ManagedMcpsConfig::resolve(&empty, Some(&remote), false);
assert!(cfg.gateway_tools_enabled);
},
);
}
#[test]
#[serial_test::serial]
fn managed_mcp_gateway_tools_env_overrides_remote() {
with_managed_mcp_env(
None,
Some("0"),
|| {
let empty = toml::Value::Table(toml::map::Map::new());
let remote = crate::util::config::RemoteSettings {
managed_mcp_gateway_tools_enabled: Some(true),
..Default::default()
};
let cfg = ManagedMcpsConfig::resolve(&empty, Some(&remote), false);
assert!(! cfg.gateway_tools_enabled);
},
);
}
#[test]
#[serial_test::serial]
fn managed_mcp_gateway_tools_env_on_overrides_remote_off() {
with_managed_mcp_env(
None,
Some("1"),
|| {
let empty = toml::Value::Table(toml::map::Map::new());
let remote = crate::util::config::RemoteSettings {
managed_mcp_gateway_tools_enabled: Some(false),
..Default::default()
};
let cfg = ManagedMcpsConfig::resolve(&empty, Some(&remote), false);
assert!(cfg.gateway_tools_enabled);
},
);
}
#[test]
#[serial_test::serial]
fn managed_mcp_gateway_tools_enabled_with_managed_master() {
with_managed_mcp_env(
None,
None,
|| {
let config: toml::Value = toml::from_str(
r#"
[managed_mcps]
enabled = true
gateway_tools_enabled = true
"#,
)
.unwrap();
let cfg = ManagedMcpsConfig::resolve(&config, None, false);
assert!(cfg.enabled);
assert!(cfg.gateway_tools_enabled);
},
);
}
fn with_model_overrides_env_full<T>(
ss: Option<&str>,
id: Option<&str>,
@@ -1777,28 +1629,16 @@ fn model_overrides_prompt_suggestion_blank_values_are_unset() {
},
);
}
/// Lock shared by every test that touches the env vars read by
/// `ToolsConfig::resolve`, so tests across both fields can't race.
/// Lock shared by every test that touches the env var read by
/// `ToolsConfig::resolve`, so tests can't race.
static TOOLS_ENV_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
/// Set both `ToolsConfig` env vars for the duration of `f`, then
/// restore. `None` clears the var.
fn with_tools_env<T>(
respect_gitignore: Option<&str>,
disable_zdr: Option<&str>,
f: impl FnOnce() -> T,
) -> T {
let _guard = TOOLS_ENV_LOCK.lock().unwrap_or_else(|e| e.into_inner());
with_env_var_opt(
"KIGI_RESPECT_GITIGNORE",
respect_gitignore,
|| with_env_var_opt("KIGI_DISABLE_ZDR_INCOMPATIBLE_TOOLS", disable_zdr, f),
)
}
fn without_grok_respect_gitignore<T>(f: impl FnOnce() -> T) -> T {
with_tools_env(None, None, f)
let _guard = TOOLS_ENV_LOCK.lock().unwrap_or_else(|e| e.into_inner());
with_env_var_opt("KIGI_RESPECT_GITIGNORE", None, f)
}
fn with_grok_respect_gitignore<T>(value: &str, f: impl FnOnce() -> T) -> T {
with_tools_env(Some(value), None, f)
let _guard = TOOLS_ENV_LOCK.lock().unwrap_or_else(|e| e.into_inner());
with_env_var_opt("KIGI_RESPECT_GITIGNORE", Some(value), f)
}
#[test]
fn tools_config_default_disabled() {
@@ -1858,87 +1698,6 @@ fn tools_config_env_false_overrides_toml_true() {
);
}
#[test]
fn zdr_incompatible_tools_env_overrides_toml_false() {
with_tools_env(
None,
Some("true"),
|| {
let config: toml::Value = toml::from_str(
"[tools]\ndisable_zdr_incompatible_tools = false",
)
.unwrap();
let tc = ToolsConfig::resolve(&config);
assert!(tc.disable_zdr_incompatible_tools, "env must override TOML");
},
);
}
#[test]
fn zdr_video_output_s3_deserializes_from_tools_block() {
let config: toml::Value = toml::from_str(
r#"
[tools]
disable_zdr_incompatible_tools = true
[tools.zdr_video_output_s3]
bucket = "team-videos"
endpoint = "https://s3.example.com"
region = "us-east-1"
[tools.zdr_video_output_s3.read_write]
access_key_id = "AKIA..."
secret_access_key = "secret"
"#,
)
.unwrap();
let tc = ToolsConfig::resolve(&config);
let s3 = tc.zdr_video_output_s3.expect("zdr_video_output_s3 should deserialize");
assert_eq!(s3.bucket, "team-videos");
assert!(s3.is_valid());
}
#[test]
fn incomplete_zdr_video_output_s3_is_ignored() {
without_grok_respect_gitignore(|| {
let config: toml::Value = toml::from_str(
r#"
[tools]
disable_zdr_incompatible_tools = true
[tools.zdr_video_output_s3]
bucket = "team-videos"
"#,
)
.unwrap();
let tc = ToolsConfig::resolve(&config);
assert!(tc.zdr_video_output_s3.is_none());
assert!(
tc.disable_zdr_incompatible_tools,
"incomplete zdr_video_output_s3 must not drop disable_zdr_incompatible_tools"
);
});
}
#[test]
fn malformed_zdr_video_output_s3_preserves_zdr_flag() {
without_grok_respect_gitignore(|| {
let config: toml::Value = toml::from_str(
r#"
[tools]
disable_zdr_incompatible_tools = true
respect_gitignore = true
[tools.zdr_video_output_s3]
bucket = "team-videos"
endpoint = "https://s3.example.com"
region = "us-east-1"
"#,
)
.unwrap();
let tc = ToolsConfig::resolve(&config);
assert!(tc.zdr_video_output_s3.is_none());
assert!(tc.disable_zdr_incompatible_tools);
assert!(tc.respect_gitignore);
});
}
#[test]
fn roles_parse_from_toml() {
let toml_str = r#"
[roles.researcher]