fix(ci): stabilize cross-platform workflow checks

This commit is contained in:
zhefox
2026-07-29 21:55:43 +08:00
parent 37df5b93b1
commit f8000012f7
40 changed files with 251 additions and 139 deletions
@@ -383,7 +383,7 @@ async fn gateway_executes_codex_search_with_responses_permission_and_search_cont
.header(TRACE_ID_HEADER, "trace-search-1")
.json(&json!({
"id": "session-search-1",
"model": "gpt-5.6-sol-ultra-fast",
"model": "gpt-5.6-sol-ultra",
"reasoning": {"effort": "low", "summary": "auto"},
"input": "find current OpenAI documentation",
"commands": {
@@ -2133,7 +2133,7 @@ fn admin_provider_oauth_dispatch_batch_mod_stays_thin() {
"pub(super) fn apply_admin_provider_oauth_batch_import_hints(",
"pub(super) async fn extract_admin_provider_oauth_batch_error_detail(",
"pub(super) fn build_admin_provider_oauth_batch_import_response(",
"pub(super) fn build_admin_provider_oauth_batch_task_state(",
"pub(in super::super) fn build_admin_provider_oauth_batch_task_state(",
] {
assert!(
batch_parse.contains(pattern),
@@ -4994,6 +4994,8 @@ fn retired_api_format_occurrences_are_whitelisted() {
"crates/aether-data/runtime/src/lifecycle/migrate/tests.rs",
"crates/aether-usage/runtime/src/report.rs",
"frontend/src/api/endpoints/types/__tests__/api-format.spec.ts",
"frontend/src/views/admin/module-management/modelDirectivesConfig.ts",
"frontend/src/views/admin/module-management/__tests__/modelDirectivesConfig.spec.ts",
];
let allowed = allowed_paths
.into_iter()
@@ -1750,7 +1750,8 @@ fn usage_repositories_are_owned_by_contracts_and_driver_adapters() {
}
let mysql_facade =
read_workspace_file("crates/aether-data/runtime/src/repository/usage/mysql.rs");
assert!(mysql_facade.contains("aether_data_mysql::MysqlUsageStorage"));
assert!(mysql_facade.contains("use aether_data_mysql::"));
assert!(mysql_facade.contains("MysqlUsageStorage"));
for forbidden in ["sqlx::query", "FROM `usage`", "INSERT INTO `usage`"] {
assert!(
!mysql_facade.contains(forbidden),
@@ -332,7 +332,8 @@ fn testkit_gateway_harness_is_opt_in() {
"aether-gateway = { workspace = true, features = [\"testkit\"], optional = true }"
));
let testkit_lib = read_workspace_file("crates/aether-testing/testkit/src/lib.rs");
let testkit_lib =
read_workspace_file("crates/aether-testing/testkit/src/lib.rs").replace("\r\n", "\n");
for module in ["execution_runtime", "gateway", "tunnel"] {
assert!(
testkit_lib.contains(&format!("#[cfg(feature = \"gateway\")]\nmod {module};")),
@@ -2828,12 +2828,14 @@ async fn gateway_handles_admin_keys_grouped_by_format_locally_with_trusted_admin
.expect("Agent Identity auth config should encrypt"),
);
let mut codex_provider = sample_provider("provider-codex", "codex", 30);
codex_provider.provider_type = "codex".to_string();
let provider_catalog_repository = Arc::new(SummaryNullingProviderCatalogReadRepository::seed(
vec![
sample_provider("provider-openai", "openai", 10),
sample_provider("provider-claude", "claude", 20)
.with_transport_fields(false, false, true, None, None, None, None, None, None),
sample_provider("provider-codex", "codex", 30),
codex_provider,
],
vec![
sample_endpoint(
@@ -474,12 +474,19 @@ async fn gateway_auto_removes_codex_key_when_quota_proves_oauth_invalid() {
"stale-access-token",
);
key.auth_type = "oauth".to_string();
key.expires_at_unix_secs = Some(1);
key.expires_at_unix_secs = Some(4_102_444_800);
key.oauth_invalid_at_unix_secs = Some(1);
key.oauth_invalid_reason = Some(
"[REFRESH_FAILED] Token 续期失败 (401): refresh_token 无效、已过期或已撤销,请重新登录授权"
.to_string(),
);
key.encrypted_auth_config = Some(
encrypt_python_fernet_plaintext(
DEVELOPMENT_ENCRYPTION_KEY,
r#"{"provider_type":"codex","refresh_token":"invalid-refresh-token","expires_at":4102444800}"#,
)
.expect("auth config should encrypt"),
);
let provider_catalog_repository = Arc::new(InMemoryProviderCatalogReadRepository::seed(
vec![provider],
@@ -521,7 +528,7 @@ async fn gateway_auto_removes_codex_key_when_quota_proves_oauth_invalid() {
let payload: serde_json::Value = response.json().await.expect("json body should parse");
assert_eq!(payload["success"], 0);
assert_eq!(payload["failed"], 1);
assert_eq!(payload["auto_removed"], 1);
assert_eq!(payload["auto_removed"], 1, "payload={payload}");
assert_eq!(payload["results"][0]["status"], "auth_invalid");
assert_eq!(payload["results"][0]["auto_removed"], true);
@@ -152,25 +152,33 @@ fn sample_kiro_device_access_token_without_email() -> String {
}
fn sample_codex_access_token_with_profile_email(email: &str, account_id: &str) -> String {
sample_codex_access_token_with_profile_email_and_expiry(email, account_id, Some(2_000_000_000))
}
fn sample_codex_access_token_with_profile_email_and_expiry(
email: &str,
account_id: &str,
expires_at: Option<u64>,
) -> String {
use base64::Engine as _;
let header =
base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(r#"{"alg":"none","typ":"JWT"}"#);
let payload = base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(
json!({
"iss": "https://auth.openai.com",
"aud": ["https://api.openai.com/v1"],
"exp": 2_000_000_000u64,
"https://api.openai.com/profile": {
"email": email,
"email_verified": true,
},
"https://api.openai.com/auth": {
"chatgpt_account_id": account_id,
},
})
.to_string(),
);
let mut claims = json!({
"iss": "https://auth.openai.com",
"aud": ["https://api.openai.com/v1"],
"https://api.openai.com/profile": {
"email": email,
"email_verified": true,
},
"https://api.openai.com/auth": {
"chatgpt_account_id": account_id,
},
});
if let Some(expires_at) = expires_at {
claims["exp"] = json!(expires_at);
}
let payload = base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(claims.to_string());
format!("{header}.{payload}.sig")
}
@@ -4352,6 +4360,11 @@ fn gateway_imports_codex_access_token_with_payload_expires_at_when_token_has_no_
}
async fn gateway_imports_codex_access_token_with_payload_expires_at_when_token_has_no_exp_impl() {
let access_token = sample_codex_access_token_with_profile_email_and_expiry(
"[email protected]",
"acct-opaque-123",
None,
);
let mut provider = sample_provider("provider-codex", "codex", 10);
provider.provider_type = "codex".to_string();
let endpoint = sample_endpoint(
@@ -4387,7 +4400,7 @@ async fn gateway_imports_codex_access_token_with_payload_expires_at_when_token_h
.header(TRUSTED_ADMIN_USER_ROLE_HEADER, "admin")
.header(TRUSTED_ADMIN_SESSION_ID_HEADER, "session-123")
.json(&json!({
"access_token": "opaque-codex-access-token",
"access_token": access_token,
"expiresAt": 2_100_000_000u64,
"name": "temporary-codex-opaque-access-token",
}))
@@ -7763,14 +7776,14 @@ async fn gateway_consecutive_manual_oauth_refresh_uses_rotated_refresh_token_imp
}
#[test]
fn gateway_concurrent_manual_oauth_refresh_uses_rotated_refresh_token_after_lock_wait() {
fn gateway_concurrent_manual_oauth_refresh_reuses_winner_after_lock_wait() {
run_admin_oauth_test(
"gateway_concurrent_manual_oauth_refresh_uses_rotated_refresh_token_after_lock_wait",
gateway_concurrent_manual_oauth_refresh_uses_rotated_refresh_token_after_lock_wait_impl,
"gateway_concurrent_manual_oauth_refresh_reuses_winner_after_lock_wait",
gateway_concurrent_manual_oauth_refresh_reuses_winner_after_lock_wait_impl,
);
}
async fn gateway_concurrent_manual_oauth_refresh_uses_rotated_refresh_token_after_lock_wait_impl() {
async fn gateway_concurrent_manual_oauth_refresh_reuses_winner_after_lock_wait_impl() {
let refresh_request_bodies = Arc::new(Mutex::new(Vec::<String>::new()));
let refresh_request_bodies_clone = Arc::clone(&refresh_request_bodies);
let execution_runtime = Router::new().route(
@@ -7963,17 +7976,12 @@ async fn gateway_concurrent_manual_oauth_refresh_uses_rotated_refresh_token_afte
.lock()
.expect("mutex should lock")
.clone();
assert_eq!(bodies.len(), 2);
assert_eq!(bodies.len(), 1);
assert!(
bodies[0].contains("refresh_token=old-codex-refresh-token"),
"unexpected first refresh body: {}",
bodies[0]
);
assert!(
bodies[1].contains("refresh_token=rotated-codex-refresh-token"),
"unexpected second refresh body: {}",
bodies[1]
);
let stored_key = provider_catalog_repository
.list_keys_by_ids(&["key-codex-oauth-concurrent-refresh".to_string()])
@@ -7992,10 +8000,7 @@ async fn gateway_concurrent_manual_oauth_refresh_uses_rotated_refresh_token_afte
.expect("auth config should decrypt");
let auth_config: serde_json::Value =
serde_json::from_str(&decrypted_auth_config).expect("auth config should parse");
assert_eq!(
auth_config["refresh_token"],
"rotated-codex-refresh-token-2"
);
assert_eq!(auth_config["refresh_token"], "rotated-codex-refresh-token");
gateway_handle.abort();
execution_runtime_handle.abort();
@@ -4,6 +4,7 @@ use std::sync::Arc;
use aether_contracts::{ExecutionPlan, ExecutionResult, ResponseBody};
use aether_crypto::DEVELOPMENT_ENCRYPTION_KEY;
use aether_data::repository::candidate_selection::InMemoryMinimalCandidateSelectionReadRepository;
use base64::Engine as _;
use http::StatusCode;
use serde_json::json;
@@ -634,7 +635,17 @@ fn assert_native_gemini_embedding_execution_plan(plan: &ExecutionPlan) {
Some("gemini-embedding-2-preview")
);
assert!(!plan.stream);
let body = plan.body.json_body.as_ref().expect("json request body");
assert!(plan.body.json_body.is_none());
let body_bytes = base64::engine::general_purpose::STANDARD
.decode(
plan.body
.body_bytes_b64
.as_deref()
.expect("original request body bytes"),
)
.expect("request body should decode");
let body: serde_json::Value =
serde_json::from_slice(&body_bytes).expect("request body should parse");
assert_eq!(body["content"]["parts"][0]["text"], "hello");
assert!(body.get("input").is_none());
assert!(body.get("messages").is_none());