fix(merge): align security contracts with latest main

This commit is contained in:
elky
2026-09-05 01:31:21 +08:00
parent 0e3bd7eff4
commit 9ff4d73d5c
8 changed files with 25 additions and 38 deletions
@@ -426,11 +426,11 @@ mod tests {
assert!(candidate.finished_at_unix_ms.is_some()); assert!(candidate.finished_at_unix_ms.is_some());
} }
/// The guard holds no request body, so its settlement write must describe the /// The guard holds no request body, and the persistence boundary intentionally
/// capture rather than deny it: a typed `none` capture state would clear the /// rejects request/response capture material. A dropped-attempt settlement
/// stored request body instead of leaving it alone. /// must not re-introduce an inline body or a caller-controlled body reference.
#[tokio::test] #[tokio::test]
async fn settling_a_dropped_attempt_leaves_the_captured_request_body_alone() { async fn settling_a_dropped_attempt_does_not_reintroduce_request_body_capture() {
let usage_repository = Arc::new(InMemoryUsageReadRepository::default()); let usage_repository = Arc::new(InMemoryUsageReadRepository::default());
let request_candidate_repository = Arc::new(InMemoryRequestCandidateRepository::default()); let request_candidate_repository = Arc::new(InMemoryRequestCandidateRepository::default());
let state = test_state(&usage_repository, &request_candidate_repository); let state = test_state(&usage_repository, &request_candidate_repository);
@@ -444,7 +444,8 @@ mod tests {
candidate_started_unix_ms, candidate_started_unix_ms,
) )
.await; .await;
// Stand in for a write that already captured this request's body. // This deliberately supplies capture material to prove that the usage
// persistence boundary strips it before either lifecycle write stores it.
let captured_body = json!({"stream": true, "service_tier": "priority"}); let captured_body = json!({"stream": true, "service_tier": "priority"});
let mut capture = build_pending_usage_record( let mut capture = build_pending_usage_record(
&plan, &plan,
@@ -478,11 +479,9 @@ mod tests {
) )
.await .await
.expect("cancelled usage should be recorded"); .expect("cancelled usage should be recorded");
assert_eq!(usage.provider_request_body, Some(captured_body)); assert_eq!(usage.provider_request_body, None);
assert_ne!( assert_eq!(usage.provider_request_body_ref, None);
usage.provider_request_body_state, assert_eq!(usage.provider_request_body_state, None);
Some(UsageBodyCaptureState::None)
);
} }
#[tokio::test] #[tokio::test]
@@ -16,8 +16,9 @@ use aether_contracts::ProxySnapshot;
use aether_data_contracts::repository::provider_catalog::{ use aether_data_contracts::repository::provider_catalog::{
StoredProviderCatalogEndpoint, StoredProviderCatalogKey, StoredProviderCatalogProvider, StoredProviderCatalogEndpoint, StoredProviderCatalogKey, StoredProviderCatalogProvider,
}; };
use aether_provider_pool::build_antigravity_pool_quota_request; use aether_provider_pool::{
use aether_provider_pool::build_antigravity_pool_quota_summary_request; build_antigravity_pool_quota_request, build_antigravity_pool_quota_summary_request,
};
use serde_json::json; use serde_json::json;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::time::{SystemTime, UNIX_EPOCH}; use std::time::{SystemTime, UNIX_EPOCH};
@@ -46,6 +46,11 @@ fn provider_oauth_service_for_template(
let adapter = AntigravityProviderOAuthAdapter::default() let adapter = AntigravityProviderOAuthAdapter::default()
.with_token_url_override(token_url) .with_token_url_override(token_url)
.with_user_info_url_override(antigravity_user_info_url); .with_user_info_url_override(antigravity_user_info_url);
#[cfg(test)]
let adapter = adapter.with_oauth_credentials_for_tests(
"gateway-test-antigravity-client-id",
"gateway-test-antigravity-client-secret",
);
return Ok(ProviderOAuthService::new().with_adapter(Arc::new(adapter))); return Ok(ProviderOAuthService::new().with_adapter(Arc::new(adapter)));
} }
GenericProviderOAuthAdapter::for_provider_type(template.provider_type) GenericProviderOAuthAdapter::for_provider_type(template.provider_type)
@@ -4000,13 +4000,16 @@ async fn gateway_names_new_antigravity_oauth_account_from_google_userinfo_email_
.with_encryption_key_for_tests(DEVELOPMENT_ENCRYPTION_KEY), .with_encryption_key_for_tests(DEVELOPMENT_ENCRYPTION_KEY),
) )
.with_provider_oauth_state_entry_for_tests( .with_provider_oauth_state_entry_for_tests(
"nonce-antigravity-123", "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
json!({ json!({
"nonce": "nonce-antigravity-123", "nonce": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
"key_id": "", "key_id": "",
"provider_id": "provider-antigravity", "provider_id": "provider-antigravity",
"provider_type": "antigravity", "provider_type": "antigravity",
"pkce_verifier": "verifier-antigravity-123", "pkce_verifier": "verifier-antigravity-123",
"initiated_by_user_id": "admin-user-123",
"initiated_by_session_id": "session-123",
"created_at": aether_admin::provider::state::current_unix_secs(),
}), }),
) )
.with_provider_oauth_token_url_for_tests( .with_provider_oauth_token_url_for_tests(
@@ -4029,7 +4032,7 @@ async fn gateway_names_new_antigravity_oauth_account_from_google_userinfo_email_
.header(TRUSTED_ADMIN_USER_ROLE_HEADER, "admin") .header(TRUSTED_ADMIN_USER_ROLE_HEADER, "admin")
.header(TRUSTED_ADMIN_SESSION_ID_HEADER, "session-123") .header(TRUSTED_ADMIN_SESSION_ID_HEADER, "session-123")
.json(&json!({ .json(&json!({
"callback_url": "http://localhost:51121/oauth2callback?code=antigravity-code-123&state=nonce-antigravity-123" "callback_url": "http://localhost:51121/oauth2callback?code=antigravity-code-123&state=cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
})) }))
.send() .send()
.await .await
@@ -4062,14 +4065,7 @@ async fn gateway_names_new_antigravity_oauth_account_from_google_userinfo_email_
.expect("created key should load"); .expect("created key should load");
let persisted = persisted_keys.first().expect("created key should exist"); let persisted = persisted_keys.first().expect("created key should exist");
assert_eq!(persisted.name, "[email protected]"); assert_eq!(persisted.name, "[email protected]");
let decrypted_auth_config = decrypt_python_fernet_ciphertext( let decrypted_auth_config = decrypt_persisted_provider_auth_config(persisted);
DEVELOPMENT_ENCRYPTION_KEY,
persisted
.encrypted_auth_config
.as_deref()
.expect("auth config should be stored"),
)
.expect("auth config should decrypt");
let auth_config: Value = let auth_config: Value =
serde_json::from_str(&decrypted_auth_config).expect("auth config json should parse"); serde_json::from_str(&decrypted_auth_config).expect("auth config json should parse");
assert_eq!(auth_config["email"], "[email protected]"); assert_eq!(auth_config["email"], "[email protected]");
@@ -47,8 +47,6 @@ use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use tokio::sync::oneshot; use tokio::sync::oneshot;
use wreq::ws::message::Message as WreqWsMessage; use wreq::ws::message::Message as WreqWsMessage;
use crate::data::GatewayDataState;
fn codex_models_snapshot( fn codex_models_snapshot(
api_key_id: &str, api_key_id: &str,
user_id: &str, user_id: &str,
-12
View File
@@ -289,18 +289,6 @@ fn tunnel_attachment_key(node_id: &str) -> String {
format!("tunnel.attachments.{node_id}") format!("tunnel.attachments.{node_id}")
} }
fn system_default_affinity_cache_key(api_key_id: &str, api_format: &str, model: &str) -> String {
let scope = aether_scheduler_core::SchedulerAffinityScope::new("system-default", Some(1));
aether_scheduler_core::build_scheduler_affinity_cache_key_for_api_key_id_with_client_session_and_scope(
api_key_id,
api_format,
model,
None,
Some(&scope),
)
.expect("system-default affinity cache key should build")
}
fn sample_tunnel_proxy_node(node_id: &str, tunnel_generation: &str) -> StoredProxyNode { fn sample_tunnel_proxy_node(node_id: &str, tunnel_generation: &str) -> StoredProxyNode {
StoredProxyNode::new( StoredProxyNode::new(
node_id.to_string(), node_id.to_string(),
@@ -122,6 +122,7 @@ define_candidate_diagnostic_categories!(
"invalid_request_error", "invalid_request_error",
"kiro_web_search_mcp_unavailable", "kiro_web_search_mcp_unavailable",
"local_stream_candidate_watchdog_timeout", "local_stream_candidate_watchdog_timeout",
"local_stream_attempt_cancelled",
"local_sync_attempt_aborted", "local_sync_attempt_aborted",
"local_sync_attempt_cancelled", "local_sync_attempt_cancelled",
"not_found_error", "not_found_error",
@@ -31,7 +31,6 @@ impl AntigravityProviderOAuthAdapter {
/// Supply deterministic OAuth client credentials for tests without /// Supply deterministic OAuth client credentials for tests without
/// requiring a process-wide environment variable. Production callers /// requiring a process-wide environment variable. Production callers
/// continue to resolve the secret from the configured environment. /// continue to resolve the secret from the configured environment.
#[cfg(test)]
#[doc(hidden)] #[doc(hidden)]
pub fn with_oauth_credentials_for_tests( pub fn with_oauth_credentials_for_tests(
mut self, mut self,