cargo fmt
This commit is contained in:
@@ -53,9 +53,7 @@ pub enum ResolveError {
|
||||
MalformedRef(String),
|
||||
#[error("model.ref points to unknown provider `{0}`")]
|
||||
UnknownProvider(String),
|
||||
#[error(
|
||||
"model.ref omitted; manifest must specify scheme, model_id, and auth (missing: {0})"
|
||||
)]
|
||||
#[error("model.ref omitted; manifest must specify scheme, model_id, and auth (missing: {0})")]
|
||||
InlineMissing(&'static str),
|
||||
}
|
||||
|
||||
@@ -259,8 +257,8 @@ pub fn resolve_with_catalogs(
|
||||
models: &[ModelEntry],
|
||||
) -> Result<ModelConfig, ResolveError> {
|
||||
if let Some(ref_str) = &manifest.ref_ {
|
||||
let (provider_id, ref_model_id) = split_ref(ref_str)
|
||||
.ok_or_else(|| ResolveError::MalformedRef(ref_str.clone()))?;
|
||||
let (provider_id, ref_model_id) =
|
||||
split_ref(ref_str).ok_or_else(|| ResolveError::MalformedRef(ref_str.clone()))?;
|
||||
let provider = providers
|
||||
.iter()
|
||||
.find(|p| p.id == provider_id)
|
||||
@@ -371,10 +369,7 @@ mod tests {
|
||||
let cfg = resolve_with_catalogs(&manifest, &providers, &models).unwrap();
|
||||
assert_eq!(cfg.scheme, SchemeKind::Anthropic);
|
||||
assert_eq!(cfg.model_id, "claude-sonnet-4-6");
|
||||
assert_eq!(
|
||||
cfg.base_url.as_deref(),
|
||||
Some("https://api.anthropic.com")
|
||||
);
|
||||
assert_eq!(cfg.base_url.as_deref(), Some("https://api.anthropic.com"));
|
||||
match cfg.auth {
|
||||
AuthRef::ApiKey { env, file } => {
|
||||
assert_eq!(env.as_deref(), Some("INSOMNIA_API_KEY_ANTHROPIC"));
|
||||
@@ -382,7 +377,10 @@ mod tests {
|
||||
}
|
||||
_ => panic!("expected ApiKey auth from provider hint"),
|
||||
}
|
||||
assert!(cfg.capability.is_some(), "should fall back to provider.default_capability");
|
||||
assert!(
|
||||
cfg.capability.is_some(),
|
||||
"should fall back to provider.default_capability"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -44,7 +44,9 @@ impl AuthSnapshot {
|
||||
let refresh_token = tokens
|
||||
.get("refresh_token")
|
||||
.and_then(Value::as_str)
|
||||
.ok_or_else(|| CodexAuthError::MalformedAuthJson("missing tokens.refresh_token".into()))?
|
||||
.ok_or_else(|| {
|
||||
CodexAuthError::MalformedAuthJson("missing tokens.refresh_token".into())
|
||||
})?
|
||||
.to_string();
|
||||
|
||||
let id_token = tokens
|
||||
@@ -58,9 +60,7 @@ impl AuthSnapshot {
|
||||
.get("account_id")
|
||||
.and_then(Value::as_str)
|
||||
.map(str::to_string)
|
||||
.or_else(|| {
|
||||
super::jwt::parse_chatgpt_claims(&id_token).and_then(|c| c.account_id)
|
||||
})
|
||||
.or_else(|| super::jwt::parse_chatgpt_claims(&id_token).and_then(|c| c.account_id))
|
||||
.ok_or_else(|| {
|
||||
CodexAuthError::MalformedAuthJson(
|
||||
"missing account_id in both tokens and id_token claims".into(),
|
||||
@@ -131,7 +131,10 @@ pub async fn persist_refreshed(
|
||||
}
|
||||
raw.as_object_mut()
|
||||
.ok_or_else(|| CodexAuthError::MalformedAuthJson("auth.json not an object".into()))?
|
||||
.insert("last_refresh".into(), Value::String(Utc::now().to_rfc3339()));
|
||||
.insert(
|
||||
"last_refresh".into(),
|
||||
Value::String(Utc::now().to_rfc3339()),
|
||||
);
|
||||
|
||||
write_atomic(path, raw)?;
|
||||
AuthSnapshot::from_value(raw.clone())
|
||||
@@ -139,9 +142,8 @@ pub async fn persist_refreshed(
|
||||
|
||||
fn write_atomic(path: &Path, value: &Value) -> Result<(), CodexAuthError> {
|
||||
if let Some(parent) = path.parent() {
|
||||
std::fs::create_dir_all(parent).map_err(|e| {
|
||||
CodexAuthError::Io(format!("create_dir_all {}: {e}", parent.display()))
|
||||
})?;
|
||||
std::fs::create_dir_all(parent)
|
||||
.map_err(|e| CodexAuthError::Io(format!("create_dir_all {}: {e}", parent.display())))?;
|
||||
}
|
||||
let json = serde_json::to_vec_pretty(value)
|
||||
.map_err(|e| CodexAuthError::Io(format!("serialize: {e}")))?;
|
||||
@@ -203,7 +205,10 @@ mod tests {
|
||||
assert_eq!(snap.account_id, "acc-1");
|
||||
assert!(snap.last_refresh.is_some());
|
||||
// 未知フィールドが raw に保持されている
|
||||
assert_eq!(snap.raw.get("OPENAI_API_KEY").and_then(Value::as_str), Some("sk-extra"));
|
||||
assert_eq!(
|
||||
snap.raw.get("OPENAI_API_KEY").and_then(Value::as_str),
|
||||
Some("sk-extra")
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -238,7 +243,10 @@ mod tests {
|
||||
"agent_identity":{"workspace_id":"w","agent_runtime_id":"r","agent_private_key":"k","registered_at":"x"}
|
||||
}"#,
|
||||
);
|
||||
let updated = persist_refreshed(&path, None, Some("new-acc".into()), Some("new-ref".into())).await.unwrap();
|
||||
let updated =
|
||||
persist_refreshed(&path, None, Some("new-acc".into()), Some("new-ref".into()))
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(updated.access_token, "new-acc");
|
||||
assert_eq!(updated.refresh_token, "new-ref");
|
||||
// 未知フィールド agent_identity が保たれる
|
||||
@@ -258,7 +266,9 @@ mod tests {
|
||||
);
|
||||
// 既存ファイルを 644 に変えてから persist → 600 に直るか
|
||||
std::fs::set_permissions(&path, std::fs::Permissions::from_mode(0o644)).unwrap();
|
||||
persist_refreshed(&path, None, Some("a2".into()), None).await.unwrap();
|
||||
persist_refreshed(&path, None, Some("a2".into()), None)
|
||||
.await
|
||||
.unwrap();
|
||||
let mode = std::fs::metadata(&path).unwrap().permissions().mode() & 0o777;
|
||||
assert_eq!(mode, 0o600);
|
||||
}
|
||||
|
||||
@@ -23,10 +23,7 @@ use std::sync::Arc;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use chrono::{Duration, Utc};
|
||||
use llm_worker::llm_client::{
|
||||
ClientError,
|
||||
auth::AuthProvider,
|
||||
};
|
||||
use llm_worker::llm_client::{ClientError, auth::AuthProvider};
|
||||
use reqwest::header::{HeaderName, HeaderValue};
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
@@ -66,8 +63,8 @@ impl CodexAuthProvider {
|
||||
let codex_home = if let Ok(p) = std::env::var("CODEX_HOME") {
|
||||
PathBuf::from(p)
|
||||
} else {
|
||||
let home = std::env::var("HOME")
|
||||
.map_err(|_| ClientError::Config("HOME not set".into()))?;
|
||||
let home =
|
||||
std::env::var("HOME").map_err(|_| ClientError::Config("HOME not set".into()))?;
|
||||
PathBuf::from(home).join(".codex")
|
||||
};
|
||||
Ok(Self::new(codex_home))
|
||||
@@ -142,7 +139,9 @@ impl CodexAuthProvider {
|
||||
Ok(new_snap)
|
||||
}
|
||||
|
||||
fn build_headers(snap: &AuthSnapshot) -> Result<Vec<(HeaderName, HeaderValue)>, CodexAuthError> {
|
||||
fn build_headers(
|
||||
snap: &AuthSnapshot,
|
||||
) -> Result<Vec<(HeaderName, HeaderValue)>, CodexAuthError> {
|
||||
let mut out = Vec::with_capacity(5);
|
||||
|
||||
let auth_val = HeaderValue::from_str(&format!("Bearer {}", snap.access_token))
|
||||
@@ -151,10 +150,7 @@ impl CodexAuthProvider {
|
||||
|
||||
let acc_val = HeaderValue::from_str(&snap.account_id)
|
||||
.map_err(|e| CodexAuthError::InvalidHeader(format!("ChatGPT-Account-Id: {e}")))?;
|
||||
out.push((
|
||||
HeaderName::from_static("chatgpt-account-id"),
|
||||
acc_val,
|
||||
));
|
||||
out.push((HeaderName::from_static("chatgpt-account-id"), acc_val));
|
||||
|
||||
// Cloudflare WAF は ChatGPT backend アクセス元を `originator` /
|
||||
// `User-Agent` で識別する。Codex CLI が送る固定値を流用しないと
|
||||
@@ -186,7 +182,10 @@ impl CodexAuthProvider {
|
||||
#[async_trait]
|
||||
impl AuthProvider for CodexAuthProvider {
|
||||
async fn headers(&self) -> Result<Vec<(HeaderName, HeaderValue)>, ClientError> {
|
||||
let snap = self.ensure_fresh().await.map_err(CodexAuthError::to_client_error)?;
|
||||
let snap = self
|
||||
.ensure_fresh()
|
||||
.await
|
||||
.map_err(CodexAuthError::to_client_error)?;
|
||||
Self::build_headers(&snap).map_err(CodexAuthError::to_client_error)
|
||||
}
|
||||
}
|
||||
@@ -247,7 +246,10 @@ mod tests {
|
||||
let provider = CodexAuthProvider::new(dir.path().to_path_buf());
|
||||
|
||||
let headers = provider.headers().await.unwrap();
|
||||
let names: Vec<_> = headers.iter().map(|(n, _)| n.as_str().to_string()).collect();
|
||||
let names: Vec<_> = headers
|
||||
.iter()
|
||||
.map(|(n, _)| n.as_str().to_string())
|
||||
.collect();
|
||||
assert!(names.contains(&"authorization".to_string()));
|
||||
assert!(names.contains(&"chatgpt-account-id".to_string()));
|
||||
assert!(!names.contains(&"x-openai-fedramp".to_string()));
|
||||
@@ -276,7 +278,12 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn refreshes_when_expired_and_persists() {
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let path = write_auth(dir.path(), Utc::now().timestamp() - 60, false, "old-refresh");
|
||||
let path = write_auth(
|
||||
dir.path(),
|
||||
Utc::now().timestamp() - 60,
|
||||
false,
|
||||
"old-refresh",
|
||||
);
|
||||
|
||||
// refresh エンドポイントを mock。新しい JWT (将来 exp) を返す
|
||||
let server = MockServer::start().await;
|
||||
@@ -315,7 +322,12 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn permanent_refresh_failure_surfaces_login_message() {
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
write_auth(dir.path(), Utc::now().timestamp() - 60, false, "bad-refresh");
|
||||
write_auth(
|
||||
dir.path(),
|
||||
Utc::now().timestamp() - 60,
|
||||
false,
|
||||
"bad-refresh",
|
||||
);
|
||||
|
||||
let server = MockServer::start().await;
|
||||
Mock::given(method("POST"))
|
||||
|
||||
@@ -97,7 +97,10 @@ fn extract_error_code(body: &str) -> Option<String> {
|
||||
return Some(s.to_string());
|
||||
}
|
||||
}
|
||||
value.get("code").and_then(|v| v.as_str()).map(str::to_string)
|
||||
value
|
||||
.get("code")
|
||||
.and_then(|v| v.as_str())
|
||||
.map(str::to_string)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -58,10 +58,7 @@ pub enum ProviderError {
|
||||
/// 1. `AuthRef::ApiKey { env, .. }` で env が指定されていればその変数を参照
|
||||
/// 2. そうでなければ scheme 既定の環境変数 (`SchemeKind::default_env_var`)
|
||||
/// 3. それでも無ければ `file` を読む(絶対パスのみ)
|
||||
fn resolve_auth(
|
||||
scheme: SchemeKind,
|
||||
auth: &AuthRef,
|
||||
) -> Result<ResolvedAuth, ProviderError> {
|
||||
fn resolve_auth(scheme: SchemeKind, auth: &AuthRef) -> Result<ResolvedAuth, ProviderError> {
|
||||
match auth {
|
||||
AuthRef::None => Ok(ResolvedAuth::None),
|
||||
AuthRef::ApiKey { env, file } => {
|
||||
@@ -161,9 +158,7 @@ pub fn build_client(manifest: &ModelManifest) -> Result<Box<dyn LlmClient>, Prov
|
||||
/// `ModelManifest` から既に `catalog::resolve_model_manifest` を通した
|
||||
/// ケース(factory / spawn 経路でカタログ引きを 1 回だけにしたい等)で
|
||||
/// 使う。
|
||||
pub fn build_client_from_config(
|
||||
config: &ModelConfig,
|
||||
) -> Result<Box<dyn LlmClient>, ProviderError> {
|
||||
pub fn build_client_from_config(config: &ModelConfig) -> Result<Box<dyn LlmClient>, ProviderError> {
|
||||
build_from_config(config)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user