use axum::body::Body;
use axum::http::header::CONTENT_TYPE;
use axum::http::{HeaderValue, StatusCode};
use axum::response::Response;
use lean_ctx::core::model_catalog::{self, CatalogModel, MODEL_ID_PREFIX, ModelCatalog};
use lean_ctx::core::policy::RoutingPolicyRules;
use super::{PreparedProxyRequest, ProxyPrimitive, admission};
use crate::admitted::{GatewayRefusal, REASON_CODES_HEADER, REFUSAL_HEADER};
pub(super) const CN_DIRECT_OPT_IN_REQUIRED: &str = "cn_direct_opt_in_required";
const MODEL_ORIGIN_BLOCKED: &str = "destination.model_origin_blocked";
const HOST_COUNTRY_BLOCKED: &str = "destination.host_country_blocked";
const HOST_UNKNOWN: &str = "destination.host_unknown";
const CATALOG_UNAVAILABLE: &str = "destination.model_catalog_unavailable";
const POLICY_UNAVAILABLE: &str = "policy.origin_rules_unavailable";
const ORIGIN_GATE_REFUSED: &str = "model origin gate refused request";
const SUBSCRIPTION_PROVIDER_ID: &str = "leanctx";
#[derive(Debug, Clone, Copy)]
pub(super) struct Destination<'a> {
pub base: &'a str,
pub model: Option<&'a str>,
pub registry_id: Option<&'a str>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(super) enum Refusal {
CnDirectOptIn {
host: String,
vendor: String,
voided: bool,
},
Withheld(&'static str),
Unavailable(&'static str),
}
pub(super) fn decide(
catalog: &ModelCatalog,
rules: &RoutingPolicyRules,
local_opt_in: bool,
dest: Destination<'_>,
) -> Result<(), Refusal> {
let host = host_of(dest.base).ok_or(Refusal::Withheld(HOST_UNKNOWN))?;
if let Some(direct) = catalog.direct_vendor(&host) {
if rules.host_blocked(&direct.host_country) {
return Err(Refusal::Withheld(HOST_COUNTRY_BLOCKED));
}
let mut origins = catalog
.models
.iter()
.filter(|m| m.vendor == direct.vendor)
.map(|m| m.origin_country.as_str())
.peekable();
let origin_blocked = if origins.peek().is_none() {
rules.origin_blocked(&direct.host_country)
} else {
origins.any(|c| rules.origin_blocked(c))
};
if origin_blocked {
return Err(Refusal::Withheld(MODEL_ORIGIN_BLOCKED));
}
if direct.host_country == "CN" {
let voided = rules.vendor_direct_cn == Some(false);
if !local_opt_in || voided {
return Err(Refusal::CnDirectOptIn {
host,
vendor: direct.vendor.clone(),
voided: local_opt_in && voided,
});
}
}
}
let subscription_route = dest.registry_id == Some(SUBSCRIPTION_PROVIDER_ID);
if let Some(model) = dest
.model
.and_then(|m| catalog_model(catalog, m, subscription_route))
{
if rules.origin_blocked(&model.origin_country) {
return Err(Refusal::Withheld(MODEL_ORIGIN_BLOCKED));
}
if subscription_route
&& model
.hosts
.iter()
.all(|h| rules.host_blocked(&h.host_country))
{
return Err(Refusal::Withheld(HOST_COUNTRY_BLOCKED));
}
}
Ok(())
}
fn catalog_model<'c>(
catalog: &'c ModelCatalog,
model: &str,
subscription_route: bool,
) -> Option<&'c CatalogModel> {
catalog.model(model).or_else(|| {
(subscription_route && !model.starts_with(MODEL_ID_PREFIX))
.then(|| catalog.model(&format!("{MODEL_ID_PREFIX}{model}")))
.flatten()
})
}
fn host_of(base: &str) -> Option<String> {
let uri = base.parse::<axum::http::Uri>().ok()?;
let host = uri
.host()?
.trim_matches(|c| c == '[' || c == ']')
.trim_end_matches('.');
(!host.is_empty()).then(|| host.to_ascii_lowercase())
}
pub(super) fn admit(
dest: Destination<'_>,
provider_label: &str,
original_bytes: usize,
trace_id: &str,
) -> Option<PreparedProxyRequest> {
let verdict = match model_catalog::bundled() {
None => Err(Refusal::Unavailable(CATALOG_UNAVAILABLE)),
Some(catalog) => match lean_ctx::core::policy::runtime::active() {
Some(policy) if !policy.content_valid => Err(Refusal::Unavailable(POLICY_UNAVAILABLE)),
policy => {
let rules = policy
.as_ref()
.map(|p| p.resolved.routing.clone())
.unwrap_or_default();
let opt_in = lean_ctx::core::config::Config::load()
.proxy
.allows_vendor_direct_cn();
decide(catalog, &rules, opt_in, dest)
}
},
};
let refusal = verdict.err()?;
let response = match &refusal {
Refusal::CnDirectOptIn {
host,
vendor,
voided,
} => {
tracing::warn!(
"lean-ctx proxy: {host} is {vendor}'s own CN-hosted API (403 {CN_DIRECT_OPT_IN_REQUIRED})"
);
cn_direct_response(provider_label, host, vendor, *voided)
}
Refusal::Withheld(code) => {
let refusal = GatewayRefusal::withheld(code);
tracing::warn!("lean-ctx proxy: {}", refusal.message());
return Some(admission::refused(
&refusal,
provider_label,
original_bytes,
trace_id,
));
}
Refusal::Unavailable(code) => {
let refusal = GatewayRefusal::unavailable(code);
tracing::warn!("lean-ctx proxy: {}", refusal.message());
return Some(admission::refused(
&refusal,
provider_label,
original_bytes,
trace_id,
));
}
};
Some(PreparedProxyRequest::Terminal(Box::new(
ProxyPrimitive::Policy {
response,
original_tokens: original_bytes / 4,
trace_id: trace_id.to_owned(),
reason: ORIGIN_GATE_REFUSED,
},
)))
}
fn cn_direct_response(provider_label: &str, host: &str, vendor: &str, voided: bool) -> Response {
let how = if voided {
"your organization's policy forbids vendor-direct CN APIs (vendor_direct_cn = false), \
so the local opt-in does not apply"
} else {
"allow it with `[proxy] allow_vendor_direct_cn = true` in config.toml"
};
let message = format!(
"request not forwarded: {host} is {vendor}'s own China-hosted API; {how} \
({CN_DIRECT_OPT_IN_REQUIRED}). This is not a login problem; logging in again does not help"
);
let detail = serde_json::json!({
"refusal": "context_gateway",
"reason_codes": [CN_DIRECT_OPT_IN_REQUIRED],
"vendor": vendor,
"host": host,
"voided_by_policy": voided,
});
let body = match provider_label {
"Anthropic" | "Bedrock" | "Copilot" => serde_json::json!({
"type": "error",
"error": { "type": "permission_error", "message": message },
"lean_ctx": detail,
}),
"Gemini" => serde_json::json!({
"error": { "code": 403, "message": message, "status": "PERMISSION_DENIED" },
"lean_ctx": detail,
}),
_ => serde_json::json!({
"error": {
"message": message,
"type": "permission_error",
"param": null,
"code": CN_DIRECT_OPT_IN_REQUIRED,
},
"lean_ctx": detail,
}),
};
let mut response = Response::new(Body::from(body.to_string()));
*response.status_mut() = StatusCode::FORBIDDEN;
let headers = response.headers_mut();
headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
headers.insert(REFUSAL_HEADER, HeaderValue::from_static("context_gateway"));
headers.insert(
REASON_CODES_HEADER,
HeaderValue::from_static(CN_DIRECT_OPT_IN_REQUIRED),
);
response
}
#[cfg(test)]
mod tests {
use super::*;
fn rules(
origins: &[&str],
hosts: &[&str],
vendor_direct_cn: Option<bool>,
) -> RoutingPolicyRules {
RoutingPolicyRules {
blocked_model_origins: origins.iter().map(|s| (*s).to_owned()).collect(),
blocked_host_countries: hosts.iter().map(|s| (*s).to_owned()).collect(),
vendor_direct_cn,
..RoutingPolicyRules::default()
}
}
fn dest<'a>(base: &'a str, model: &'a str, registry_id: Option<&'a str>) -> Destination<'a> {
Destination {
base,
model: Some(model),
registry_id,
}
}
#[test]
fn vendor_direct_cn_needs_the_local_opt_in_and_org_false_voids_it() {
let catalog = model_catalog::bundled().expect("bundled catalog");
let direct = dest("https://API.Z.ai./api/paas/v4", "glm-5", Some("zai"));
let refused = |voided| {
Err(Refusal::CnDirectOptIn {
host: "api.z.ai".to_owned(),
vendor: "Z.ai (Zhipu)".to_owned(),
voided,
})
};
let none = RoutingPolicyRules::default();
assert_eq!(decide(catalog, &none, false, direct), refused(false));
assert_eq!(decide(catalog, &none, true, direct), Ok(()));
assert_eq!(
decide(catalog, &rules(&[], &[], Some(true)), false, direct),
refused(false),
"an org true never replaces the local opt-in"
);
assert_eq!(
decide(catalog, &rules(&[], &[], Some(false)), true, direct),
refused(true)
);
}
#[test]
fn origin_and_host_rules_cover_every_route() {
let catalog = model_catalog::bundled().expect("bundled catalog");
let none = RoutingPolicyRules::default();
let subscription = dest(
"https://models.hive.example",
"glm-5.3-flash",
Some("leanctx"),
);
let own = dest(
"https://openrouter.ai/api",
"leanctx/glm-5.3-flash",
Some("openrouter"),
);
assert_eq!(decide(catalog, &none, false, subscription), Ok(()));
let cn_origin = rules(&["CN"], &[], None);
for d in [subscription, own] {
assert_eq!(
decide(catalog, &cn_origin, false, d),
Err(Refusal::Withheld(MODEL_ORIGIN_BLOCKED))
);
}
let bare_elsewhere = dest(
"https://openrouter.ai/api",
"glm-5.3-flash",
Some("openrouter"),
);
assert_eq!(decide(catalog, &cn_origin, false, bare_elsewhere), Ok(()));
assert_eq!(
decide(catalog, &rules(&[], &["US"], None), false, subscription),
Err(Refusal::Withheld(HOST_COUNTRY_BLOCKED))
);
let direct = dest(
"https://api.deepseek.com/v1",
"deepseek-chat",
Some("deepseek"),
);
assert_eq!(
decide(catalog, &rules(&[], &["CN"], None), true, direct),
Err(Refusal::Withheld(HOST_COUNTRY_BLOCKED))
);
assert_eq!(
decide(catalog, &cn_origin, true, direct),
Err(Refusal::Withheld(MODEL_ORIGIN_BLOCKED))
);
assert_eq!(
decide(catalog, &none, true, dest("not a url", "m", None)),
Err(Refusal::Withheld(HOST_UNKNOWN))
);
}
}