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).
95 lines
2.8 KiB
Rust
95 lines
2.8 KiB
Rust
//! 401 attribution: callback hook + shared helpers for tool HTTP clients.
|
|
|
|
use std::sync::Arc;
|
|
|
|
/// Bearer prefix length shared across crate boundaries.
|
|
pub const SENT_BEARER_PREFIX_LEN: usize = 12;
|
|
|
|
/// Which tool endpoint produced the 401.
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub enum ToolConsumer {
|
|
WebSearch,
|
|
}
|
|
|
|
impl ToolConsumer {
|
|
pub fn as_str(self) -> &'static str {
|
|
match self {
|
|
Self::WebSearch => "WebSearch",
|
|
}
|
|
}
|
|
}
|
|
|
|
/// 401 attribution callback. Shell wires this to emit telemetry.
|
|
pub trait Auth401AttributionCallback: Send + Sync + std::fmt::Debug {
|
|
/// `sent_bearer_prefix` is truncated to [`SENT_BEARER_PREFIX_LEN`]
|
|
/// before crossing this boundary. `None` = no bearer was sent.
|
|
fn record_401(&self, consumer: ToolConsumer, sent_bearer_prefix: Option<&str>);
|
|
}
|
|
|
|
/// Shared, cheap-to-clone alias for the attribution callback.
|
|
pub type SharedAttributionCallback = Arc<dyn Auth401AttributionCallback>;
|
|
|
|
/// Record a 401 attribution event if a callback is wired. Truncates
|
|
/// the bearer to [`SENT_BEARER_PREFIX_LEN`] before crossing the
|
|
/// trait boundary.
|
|
pub(crate) fn emit_401(
|
|
callback: Option<&SharedAttributionCallback>,
|
|
consumer: ToolConsumer,
|
|
sent_bearer: Option<&str>,
|
|
) {
|
|
if let Some(cb) = callback {
|
|
let prefix = sent_bearer.map(|s| truncate_to_prefix(s.to_string()));
|
|
cb.record_401(consumer, prefix.as_deref());
|
|
}
|
|
}
|
|
|
|
/// Truncate a bearer string to the first [`SENT_BEARER_PREFIX_LEN`]
|
|
/// characters. Used by tool clients before passing the bearer across
|
|
/// the [`Auth401AttributionCallback`] boundary.
|
|
///
|
|
/// Bearer tokens are ASCII (per the `Authorization` header grammar)
|
|
/// so the byte index is always a char boundary; this function uses
|
|
/// `String::truncate` which would otherwise panic on a non-boundary
|
|
/// cut.
|
|
pub(crate) fn truncate_to_prefix(mut bearer: String) -> String {
|
|
bearer.truncate(SENT_BEARER_PREFIX_LEN.min(bearer.len()));
|
|
bearer
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn truncate_to_prefix_long_string_cuts_at_12() {
|
|
assert_eq!(
|
|
truncate_to_prefix("xai-key-aaaaaaaaaaaaaaaaaaa".to_string()),
|
|
"xai-key-aaaa"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn truncate_to_prefix_short_string_unchanged() {
|
|
assert_eq!(truncate_to_prefix("abc".to_string()), "abc");
|
|
}
|
|
|
|
#[test]
|
|
fn truncate_to_prefix_exact_12_unchanged() {
|
|
assert_eq!(
|
|
truncate_to_prefix("123456789012".to_string()),
|
|
"123456789012"
|
|
);
|
|
assert_eq!(truncate_to_prefix("123456789012".to_string()).len(), 12);
|
|
}
|
|
|
|
#[test]
|
|
fn truncate_to_prefix_empty_unchanged() {
|
|
assert_eq!(truncate_to_prefix(String::new()), "");
|
|
}
|
|
|
|
#[test]
|
|
fn tool_consumer_as_str_stable_identifiers() {
|
|
assert_eq!(ToolConsumer::WebSearch.as_str(), "WebSearch");
|
|
}
|
|
}
|