F3: Kimi inference pipeline + full grok cloud-surface excision
Sampler / inference (PRD F3):
- kimi_compat.rs: single adaptation point for the Kimi chat/completions
dialect (thinking-field mapping, model_id stripping, empty-content
tool-call message fix, stream_options.include_usage), with kimi-cli
source citations
- Rate-limit handling reworked for Kimi/Moonshot semantics; UA kigi/{version}
- /models replaces the xAI models-v2 endpoint everywhere; idle model
refresh carries X-Msh-* device headers only (X-XAI-Token-Auth and
x-grok-client-mode/CLIENT_MODE_HEADER machinery deleted)
Cloud-surface excision (PRD §5, zero-egress):
- remote/ conversations lane, cli-chat-proxy-types crate, prod/ dir,
share command, credit bar: deleted (single local session lane;
paginate() replaces merge_and_paginate)
- Subscription/tier gate stack deleted end-to-end: AppView
gate/tier/team/ZDR fields, app/subscription.rs watch loop,
dispatch/billing.rs paywall + SuperGrok upsell, free-usage-exhausted
chain, tier-restricted commands, GateInfo, RemoteSettings gate fields,
SettingsUpdateNotification gate fields
- /privacy + coding-data-sharing setting deleted (backed by a dead xAI
RPC; Kigi is zero-egress — nothing to share or retain remotely)
Auth UX correctness (user-reported):
- Device-flow fixtures now mirror the live Kimi payload shape
(https://www.kimi.com/code/authorize_device?user_code=..., verified
against auth.kimi.com); the fabricated auth.kimi.com/device?code=...
URLs are gone
- open_browser_detached is a no-op under cfg(test): unit tests drove
wiremock fixture URLs into the real browser (root cause of the
"garbage mock link" ABCD-1234 tabs)
- Welcome/pager-minimal rebrand: Grok Build -> Kigi, grok.com ->
kimi.com, "Sign in to Grok" -> "Sign in to Kimi"
This commit is contained in:
@@ -56,19 +56,19 @@ fn matches_trusted_base_url(candidate: &str, trusted_base: &str) -> bool {
|
||||
/// True for subscription coding-API URLs (the compiled production endpoint;
|
||||
/// deliberately NOT the env-overridable [`kigi_env::coding_api_base_url`] so a
|
||||
/// runtime override can't widen this trust set).
|
||||
pub fn is_cli_chat_proxy_url(url: &str) -> bool {
|
||||
pub fn is_production_coding_api_url(url: &str) -> bool {
|
||||
matches_trusted_base_url(url, kigi_env::PRODUCTION_ENDPOINTS.coding_api_base_url)
|
||||
}
|
||||
/// True for URLs the idle model-metadata refresh may re-fetch from: the
|
||||
/// *effective* subscription coding endpoint (the `KIGI_CODE_BASE_URL`
|
||||
/// override when set, else the compiled production endpoint), plus loopback
|
||||
/// hosts (local dev proxies and test mocks). Unlike [`is_cli_chat_proxy_url`]
|
||||
/// hosts (local dev proxies and test mocks). Unlike [`is_production_coding_api_url`]
|
||||
/// this honours the env override and loopback, so use it only to gate traffic
|
||||
/// that already flows to the session's configured base URL (the refresh
|
||||
/// re-fetches from the same host the session samples against); it must never
|
||||
/// widen a security trust set.
|
||||
pub fn is_effective_coding_endpoint_url(url: &str) -> bool {
|
||||
if is_cli_chat_proxy_url(url) {
|
||||
if is_production_coding_api_url(url) {
|
||||
return true;
|
||||
}
|
||||
if matches_trusted_base_url(url, &kigi_env::coding_api_base_url()) {
|
||||
@@ -83,18 +83,11 @@ pub fn is_effective_coding_endpoint_url(url: &str) -> bool {
|
||||
None => false,
|
||||
})
|
||||
}
|
||||
/// True for first-party xAI endpoints (`*.x.ai`, cli-chat-proxy, and optional
|
||||
/// non-production first-party hosts when that feature is enabled).
|
||||
/// `disable_api_key_auth` refuses keys only for these; other hosts are BYOK and
|
||||
/// exempt. Safe against invalid URLs and suffix attacks (`evil-x.ai.example`).
|
||||
pub fn is_first_party_xai_url(url: &str) -> bool {
|
||||
if is_cli_chat_proxy_url(url) {
|
||||
return true;
|
||||
}
|
||||
reqwest::Url::parse(url)
|
||||
.ok()
|
||||
.and_then(|u| u.host_str().map(|h| h.to_owned()))
|
||||
.is_some_and(|host| host == "x.ai" || host.ends_with(".x.ai"))
|
||||
/// True for first-party endpoints: the Kimi subscription coding API. The
|
||||
/// session-token 401-refresh gate only refreshes against these; other hosts
|
||||
/// are BYOK and exempt. Safe against invalid URLs and suffix attacks.
|
||||
pub fn is_first_party_url(url: &str) -> bool {
|
||||
is_production_coding_api_url(url)
|
||||
}
|
||||
/// Truncate a string to at most `max_chars` characters.
|
||||
/// Slices at char boundaries so multi-byte UTF-8 never panics.
|
||||
@@ -229,18 +222,18 @@ pub fn is_grok_process(pid: u32) -> bool {
|
||||
mod tests {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn test_is_cli_chat_proxy_url_accepts_proxy_subpath() {
|
||||
assert!(is_cli_chat_proxy_url(
|
||||
fn test_is_production_coding_api_url_accepts_proxy_subpath() {
|
||||
assert!(is_production_coding_api_url(
|
||||
"https://api.kimi.com/coding/v1/chat/completions"
|
||||
));
|
||||
}
|
||||
#[test]
|
||||
fn test_is_cli_chat_proxy_url_rejects_public_api() {
|
||||
assert!(!is_cli_chat_proxy_url("https://api.x.ai/v1"));
|
||||
fn test_is_production_coding_api_url_rejects_public_api() {
|
||||
assert!(!is_production_coding_api_url("https://api.x.ai/v1"));
|
||||
}
|
||||
#[test]
|
||||
fn test_is_cli_chat_proxy_url_rejects_spoofed_hostname() {
|
||||
assert!(!is_cli_chat_proxy_url(
|
||||
fn test_is_production_coding_api_url_rejects_spoofed_hostname() {
|
||||
assert!(!is_production_coding_api_url(
|
||||
"https://api.kimi.com.evil.example/coding/v1"
|
||||
));
|
||||
}
|
||||
@@ -261,31 +254,22 @@ mod tests {
|
||||
));
|
||||
}
|
||||
#[test]
|
||||
fn test_is_cli_chat_proxy_url_rejects_v11_prefix_confusion() {
|
||||
assert!(!is_cli_chat_proxy_url(
|
||||
fn test_is_production_coding_api_url_rejects_v11_prefix_confusion() {
|
||||
assert!(!is_production_coding_api_url(
|
||||
"https://api.kimi.com/coding/v11/chat/completions"
|
||||
));
|
||||
}
|
||||
#[test]
|
||||
fn test_is_first_party_xai_url() {
|
||||
assert!(is_first_party_xai_url("https://api.x.ai/v1"));
|
||||
assert!(is_first_party_xai_url(
|
||||
"https://api.x.ai/v1/chat/completions"
|
||||
));
|
||||
assert!(is_first_party_xai_url("https://x.ai"));
|
||||
assert!(is_first_party_xai_url(
|
||||
fn test_is_first_party_url() {
|
||||
assert!(is_first_party_url(
|
||||
"https://api.kimi.com/coding/v1/chat/completions"
|
||||
));
|
||||
assert!(!is_first_party_xai_url("https://api.openai.com/v1"));
|
||||
assert!(!is_first_party_xai_url("https://api.anthropic.com/v1"));
|
||||
assert!(!is_first_party_xai_url(
|
||||
"https://generativelanguage.googleapis.com"
|
||||
));
|
||||
assert!(!is_first_party_xai_url("https://api.x.ai.evil.example/v1"));
|
||||
assert!(!is_first_party_xai_url("https://evil-x.ai.attacker.com/v1"));
|
||||
assert!(!is_first_party_xai_url("https://prefixx.ai/v1"));
|
||||
assert!(!is_first_party_xai_url("not-a-url"));
|
||||
assert!(!is_first_party_xai_url(""));
|
||||
assert!(!is_first_party_url("https://api.x.ai/v1"));
|
||||
assert!(!is_first_party_url("https://api.openai.com/v1"));
|
||||
assert!(!is_first_party_url("https://api.anthropic.com/v1"));
|
||||
assert!(!is_first_party_url("https://api.kimi.com.evil.example/v1"));
|
||||
assert!(!is_first_party_url("not-a-url"));
|
||||
assert!(!is_first_party_url(""));
|
||||
}
|
||||
#[test]
|
||||
fn test_truncate() {
|
||||
|
||||
Reference in New Issue
Block a user