use std::time::Duration; use codex_aws_auth::AwsAccessKeys; use http::HeaderValue; use http::Method; use pretty_assertions::assert_eq; use super::*; async fn test_provider() -> AwsSigV4AuthProvider { let context = AwsAuthContext::load_with_access_keys( AwsAuthConfig { profile: None, region: Some("us-east-1".to_string()), service: "execute-api".to_string(), }, AwsAccessKeys { access_key_id: "test-access-key".to_string(), secret_access_key: "test-secret-key".to_string(), session_token: Some("test-session-token".to_string()), }, ) .await .expect("load fixture signing context"); AwsSigV4AuthProvider { context } } #[tokio::test] async fn signs_requests_without_changing_payload_or_metadata() { let provider = test_provider().await; let url = "https://executor.example.com/connect?environment_id=environment-1"; for mut request in [ Request::new(Method::GET, url.to_string()), Request::new(Method::POST, url.to_string()) .with_json(&serde_json::json!({"transport": "direct_jsonrpc_v1"})), Request::new(Method::POST, url.to_string()) .with_json(&serde_json::json!({"transport": "direct_jsonrpc_v1"})) .with_compression(RequestCompression::Zstd), ] { request .headers .insert("session_id", HeaderValue::from_static("session-1")); request .headers .insert("x-custom-header", HeaderValue::from_static("preserved")); request.timeout = Some(Duration::from_secs(3)); let method = request.method.clone(); let expected = request .prepare_body_for_send() .expect("prepare fixture body"); let signed = provider .apply_auth(request) .await .expect("sign fixture request"); assert_eq!(signed.method, method); assert_eq!(signed.url, url); assert_eq!(signed.timeout, Some(Duration::from_secs(3))); assert_eq!(signed.body, expected.body.clone().map(RequestBody::Raw)); assert_eq!(signed.compression, RequestCompression::None); for (name, value) in &expected.headers { assert_eq!(signed.headers.get(name), Some(value)); } assert_eq!(signed.headers["x-amz-security-token"], "test-session-token"); assert!(signed.headers.contains_key("x-amz-date")); let authorization = signed.headers[http::header::AUTHORIZATION] .to_str() .unwrap(); assert!(authorization.starts_with("AWS4-HMAC-SHA256 ")); assert!(authorization.contains("/us-east-1/execute-api/aws4_request")); assert_eq!(signed.prepare_body_for_send().unwrap().body, expected.body); } } #[tokio::test] async fn invalid_signing_request_is_a_permanent_auth_error() { let provider = test_provider().await; let error = provider .apply_auth(Request::new(Method::GET, "not a URL".to_string())) .await .expect_err("invalid URL should fail signing"); assert!(matches!(error, AuthError::Build(_))); } #[tokio::test] async fn invalid_signing_configuration_is_rejected() { let error = aws_sigv4_auth_provider(AwsAuthConfig { profile: None, region: Some("us-east-1".to_string()), service: " ".to_string(), }) .await .err() .expect("empty service should fail configuration"); assert!(matches!(error, AwsAuthError::EmptyService)); }