refactor: rename JWT issuer foxhunt-api-gateway → foxhunt-api, drop compat aliases
- JWT issuer now foxhunt-api across all 16 files (services, tests, config, docker-compose) - Remove serde alias api_gateway_url from FxtConfig (no backwards compat) - Remove api_gateway CLI alias from e2e orchestrator - All services must deploy simultaneously for JWT validation to match Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -86,7 +86,7 @@ impl Default for BrokerConfig {
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct FxtConfig {
|
||||
/// Unified API URL (default: <https://api.fxhnt.ai>)
|
||||
#[serde(default = "default_api_url", alias = "api_gateway_url")]
|
||||
#[serde(default = "default_api_url")]
|
||||
pub api_url: String,
|
||||
|
||||
/// Log level (default: info)
|
||||
@@ -251,14 +251,6 @@ mod tests {
|
||||
assert_eq!(config.token_storage, "keyring");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_backwards_compat_alias() {
|
||||
// Old config files using api_gateway_url must still deserialize correctly.
|
||||
let toml_str = r#"api_gateway_url = "http://legacy:50051""#;
|
||||
let config: FxtConfig = toml::from_str(toml_str).unwrap();
|
||||
assert_eq!(config.api_url, "http://legacy:50051");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_config_with_broker_section() {
|
||||
let toml_str = r#"
|
||||
|
||||
@@ -49,7 +49,7 @@ impl Default for TestJwtConfig {
|
||||
Self {
|
||||
// Use same secret as API Gateway tests for compatibility
|
||||
secret: "test-secret-must-be-at-least-64-characters-long-for-security-validation-ok-1234567890".to_string(),
|
||||
issuer: "foxhunt-api-gateway".to_string(),
|
||||
issuer: "foxhunt-api".to_string(),
|
||||
audience: "foxhunt-services".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ pub struct TestJwtClaims {
|
||||
/// Not before timestamp (optional)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub nbf: Option<u64>,
|
||||
/// Issuer (should be "foxhunt-api-gateway")
|
||||
/// Issuer (should be "foxhunt-api")
|
||||
pub iss: String,
|
||||
/// Audience (should be "foxhunt-services")
|
||||
pub aud: String,
|
||||
@@ -93,7 +93,7 @@ impl Default for TestJwtConfig {
|
||||
.unwrap_or_else(|_| {
|
||||
"test-secret-must-be-at-least-64-characters-long-for-security-validation-ok-1234567890".to_string()
|
||||
}),
|
||||
issuer: "foxhunt-api-gateway".to_string(),
|
||||
issuer: "foxhunt-api".to_string(),
|
||||
audience: "foxhunt-services".to_string(),
|
||||
}
|
||||
}
|
||||
@@ -518,7 +518,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_jwt_config_default() {
|
||||
let config = TestJwtConfig::default();
|
||||
assert_eq!(config.issuer, "foxhunt-api-gateway");
|
||||
assert_eq!(config.issuer, "foxhunt-api");
|
||||
assert_eq!(config.audience, "foxhunt-services");
|
||||
assert!(
|
||||
config.secret.len() >= 64,
|
||||
|
||||
@@ -29,7 +29,7 @@ pub struct JwtConfig {
|
||||
)]
|
||||
pub jwt_secret: SecretString,
|
||||
|
||||
/// JWT issuer (e.g., "foxhunt-api-gateway")
|
||||
/// JWT issuer (e.g., "foxhunt-api")
|
||||
pub jwt_issuer: String,
|
||||
|
||||
/// JWT audience (e.g., "foxhunt-services")
|
||||
@@ -154,7 +154,7 @@ impl JwtConfig {
|
||||
///
|
||||
/// Reads from:
|
||||
/// - JWT_SECRET: Signing secret (minimum 64 characters)
|
||||
/// - JWT_ISSUER: Token issuer (default: "foxhunt-api-gateway")
|
||||
/// - JWT_ISSUER: Token issuer (default: "foxhunt-api")
|
||||
/// - JWT_AUDIENCE: Token audience (default: "foxhunt-services")
|
||||
fn load_from_env() -> Result<Self> {
|
||||
let jwt_secret = std::env::var("JWT_SECRET").context(
|
||||
@@ -162,7 +162,7 @@ impl JwtConfig {
|
||||
)?;
|
||||
|
||||
let jwt_issuer =
|
||||
std::env::var("JWT_ISSUER").unwrap_or_else(|_| "foxhunt-api-gateway".to_string());
|
||||
std::env::var("JWT_ISSUER").unwrap_or_else(|_| "foxhunt-api".to_string());
|
||||
|
||||
let jwt_audience =
|
||||
std::env::var("JWT_AUDIENCE").unwrap_or_else(|_| "foxhunt-services".to_string());
|
||||
@@ -286,7 +286,7 @@ mod tests {
|
||||
jwt_secret: SecretString::from(
|
||||
"JcqslC17wjp3hG/O1bHLwsVS7CfmfbJuXccnJ4XFJMeC3dhV1s46C4NhmDNCHK/o+7j7ok5uYJdqGcOU+NhBSA==".to_string()
|
||||
),
|
||||
jwt_issuer: "foxhunt-api-gateway".to_string(),
|
||||
jwt_issuer: "foxhunt-api".to_string(),
|
||||
jwt_audience: "foxhunt-services".to_string(),
|
||||
rotation_date: Some("2025-10-18".to_string()),
|
||||
};
|
||||
@@ -298,7 +298,7 @@ mod tests {
|
||||
fn test_jwt_config_validation_too_short() {
|
||||
let config = JwtConfig {
|
||||
jwt_secret: SecretString::from("short_secret_32chars_only!!!!!".to_string()),
|
||||
jwt_issuer: "foxhunt-api-gateway".to_string(),
|
||||
jwt_issuer: "foxhunt-api".to_string(),
|
||||
jwt_audience: "foxhunt-services".to_string(),
|
||||
rotation_date: None,
|
||||
};
|
||||
@@ -316,7 +316,7 @@ mod tests {
|
||||
let weak_secret = "a".repeat(70); // 70 chars but all same character
|
||||
let config = JwtConfig {
|
||||
jwt_secret: SecretString::from(weak_secret),
|
||||
jwt_issuer: "foxhunt-api-gateway".to_string(),
|
||||
jwt_issuer: "foxhunt-api".to_string(),
|
||||
jwt_audience: "foxhunt-services".to_string(),
|
||||
rotation_date: None,
|
||||
};
|
||||
@@ -329,7 +329,7 @@ mod tests {
|
||||
fn test_jwt_config_debug_redacts_secret() {
|
||||
let config = JwtConfig {
|
||||
jwt_secret: SecretString::from("test-secret-should-not-appear".to_string()),
|
||||
jwt_issuer: "foxhunt-api-gateway".to_string(),
|
||||
jwt_issuer: "foxhunt-api".to_string(),
|
||||
jwt_audience: "foxhunt-services".to_string(),
|
||||
rotation_date: None,
|
||||
};
|
||||
|
||||
@@ -199,7 +199,7 @@ services:
|
||||
- VAULT_ADDR=http://vault:8200
|
||||
- VAULT_TOKEN=foxhunt-dev-root
|
||||
- JWT_SECRET=${JWT_SECRET:-dev_secret_key_change_in_production}
|
||||
- JWT_ISSUER=foxhunt-api-gateway
|
||||
- JWT_ISSUER=foxhunt-api
|
||||
- JWT_AUDIENCE=foxhunt-services
|
||||
# TLS Configuration - Wave H1 mTLS implementation
|
||||
- TLS_ENABLED=${TLS_ENABLED:-false}
|
||||
@@ -255,7 +255,7 @@ services:
|
||||
- VAULT_ADDR=http://vault:8200
|
||||
- VAULT_TOKEN=foxhunt-dev-root
|
||||
- JWT_SECRET=${JWT_SECRET:-dev_secret_key_change_in_production}
|
||||
- JWT_ISSUER=foxhunt-api-gateway
|
||||
- JWT_ISSUER=foxhunt-api
|
||||
- JWT_AUDIENCE=foxhunt-services
|
||||
- BENZINGA_API_KEY=${BENZINGA_API_KEY:-demo_key_please_replace}
|
||||
# DBN Data Configuration - Wave 153 Real Data Integration
|
||||
@@ -313,7 +313,7 @@ services:
|
||||
- VAULT_ADDR=http://vault:8200
|
||||
- VAULT_TOKEN=foxhunt-dev-root
|
||||
- JWT_SECRET=${JWT_SECRET:-dev_secret_key_change_in_production}
|
||||
- JWT_ISSUER=foxhunt-api-gateway
|
||||
- JWT_ISSUER=foxhunt-api
|
||||
- JWT_AUDIENCE=foxhunt-services
|
||||
# GPU Configuration
|
||||
- NVIDIA_VISIBLE_DEVICES=all
|
||||
|
||||
@@ -52,7 +52,7 @@ fn generate_test_jwt() -> String {
|
||||
iat: now,
|
||||
exp: now + 3600,
|
||||
nbf: Some(now),
|
||||
iss: "foxhunt-api-gateway".to_string(),
|
||||
iss: "foxhunt-api".to_string(),
|
||||
aud: "foxhunt-services".to_string(),
|
||||
roles: vec!["trader".to_string()],
|
||||
permissions: vec!["trading.submit_order".to_string()],
|
||||
|
||||
@@ -103,7 +103,7 @@ impl JwtConfig {
|
||||
|
||||
Ok(Self {
|
||||
jwt_secret,
|
||||
jwt_issuer: "foxhunt-api-gateway".to_string(),
|
||||
jwt_issuer: "foxhunt-api".to_string(),
|
||||
jwt_audience: "foxhunt-services".to_string(),
|
||||
})
|
||||
}
|
||||
@@ -454,7 +454,7 @@ mod tests {
|
||||
.await
|
||||
.expect("Should create config with valid JWT_SECRET");
|
||||
|
||||
assert_eq!(config.jwt_issuer, "foxhunt-api-gateway");
|
||||
assert_eq!(config.jwt_issuer, "foxhunt-api");
|
||||
assert_eq!(config.jwt_audience, "foxhunt-services");
|
||||
assert!(config.jwt_secret.len() >= 64);
|
||||
|
||||
@@ -484,7 +484,7 @@ mod tests {
|
||||
match result {
|
||||
Ok(config) => {
|
||||
// Verify config was loaded successfully
|
||||
assert_eq!(config.jwt_issuer, "foxhunt-api-gateway");
|
||||
assert_eq!(config.jwt_issuer, "foxhunt-api");
|
||||
assert_eq!(config.jwt_audience, "foxhunt-services");
|
||||
assert!(config.jwt_secret.len() >= 64);
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ impl Default for TestJwtConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
secret: "test-secret-must-be-at-least-64-characters-long-for-security-validation-ok-1234567890".to_string(),
|
||||
issuer: "foxhunt-api-gateway".to_string(),
|
||||
issuer: "foxhunt-api".to_string(),
|
||||
audience: "foxhunt-services".to_string(),
|
||||
}
|
||||
}
|
||||
@@ -98,7 +98,7 @@ pub fn generate_invalid_signature_token(user_id: &str) -> Result<String> {
|
||||
iat: now,
|
||||
exp: now + 3600,
|
||||
nbf: Some(now), // Not before: valid from now
|
||||
iss: "foxhunt-api-gateway".to_string(),
|
||||
iss: "foxhunt-api".to_string(),
|
||||
aud: "foxhunt-services".to_string(),
|
||||
roles: vec!["trader".to_string()],
|
||||
permissions: vec!["api.access".to_string()],
|
||||
|
||||
@@ -94,7 +94,7 @@ fn create_valid_jwt_token() -> Result<String> {
|
||||
sub: "test_user_001".to_string(),
|
||||
exp: (Utc::now() + Duration::hours(1)).timestamp() as usize,
|
||||
iat: Utc::now().timestamp() as usize,
|
||||
iss: "foxhunt-api-gateway".to_string(),
|
||||
iss: "foxhunt-api".to_string(),
|
||||
aud: "foxhunt-trading".to_string(),
|
||||
roles: vec!["trader".to_string()],
|
||||
permissions: vec!["trade:submit".to_string(), "trade:cancel".to_string()],
|
||||
@@ -135,7 +135,7 @@ fn create_expired_jwt_token() -> Result<String> {
|
||||
sub: "test_user_002".to_string(),
|
||||
exp: (Utc::now() - Duration::hours(1)).timestamp() as usize, // Expired 1 hour ago
|
||||
iat: (Utc::now() - Duration::hours(2)).timestamp() as usize,
|
||||
iss: "foxhunt-api-gateway".to_string(),
|
||||
iss: "foxhunt-api".to_string(),
|
||||
aud: "foxhunt-trading".to_string(),
|
||||
roles: vec!["trader".to_string()],
|
||||
permissions: vec!["trade:submit".to_string()],
|
||||
@@ -408,7 +408,7 @@ async fn test_submit_order_insufficient_role_returns_permission_denied() -> Resu
|
||||
sub: "readonly_user".to_string(),
|
||||
exp: (Utc::now() + ChronoDuration::hours(1)).timestamp() as usize,
|
||||
iat: Utc::now().timestamp() as usize,
|
||||
iss: "foxhunt-api-gateway".to_string(),
|
||||
iss: "foxhunt-api".to_string(),
|
||||
aud: "foxhunt-trading".to_string(),
|
||||
roles: vec!["viewer".to_string()], // Read-only role
|
||||
permissions: vec!["read:orders".to_string()],
|
||||
|
||||
@@ -91,7 +91,7 @@ fn create_valid_jwt_token() -> Result<String> {
|
||||
sub: "test_user_001".to_string(),
|
||||
exp: (Utc::now() + Duration::hours(1)).timestamp() as usize,
|
||||
iat: Utc::now().timestamp() as usize,
|
||||
iss: "foxhunt-api-gateway".to_string(),
|
||||
iss: "foxhunt-api".to_string(),
|
||||
aud: "foxhunt-backtesting".to_string(),
|
||||
roles: vec!["trader".to_string()],
|
||||
permissions: vec!["backtest:run".to_string()],
|
||||
|
||||
@@ -82,7 +82,7 @@ fn create_valid_jwt_token() -> Result<String> {
|
||||
sub: "test_ml_user_001".to_string(),
|
||||
exp: (Utc::now() + Duration::hours(1)).timestamp() as usize,
|
||||
iat: Utc::now().timestamp() as usize,
|
||||
iss: "foxhunt-api-gateway".to_string(),
|
||||
iss: "foxhunt-api".to_string(),
|
||||
aud: "foxhunt-ml-training".to_string(),
|
||||
roles: vec!["ml_engineer".to_string()],
|
||||
permissions: vec!["ml:train".to_string(), "ml:manage".to_string()],
|
||||
|
||||
@@ -119,7 +119,7 @@ impl Default for AuthConfig {
|
||||
enable_jwt: false, // API Gateway handles JWT
|
||||
enable_api_keys: false, // API Gateway handles API keys
|
||||
enable_mtls: false, // API Gateway handles mTLS
|
||||
jwt_issuer: "foxhunt-api-gateway".to_string(),
|
||||
jwt_issuer: "foxhunt-api".to_string(),
|
||||
jwt_audience: "foxhunt-trading-service".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -699,7 +699,7 @@ fn parse_service_list(services_str: &str) -> Result<Vec<ServiceType>> {
|
||||
];
|
||||
break;
|
||||
},
|
||||
"api" | "api_gateway" | "gateway" => services.push(ServiceType::ApiGateway),
|
||||
"api" | "gateway" => services.push(ServiceType::ApiGateway),
|
||||
"trading" => services.push(ServiceType::TradingService),
|
||||
"backtesting" => services.push(ServiceType::BacktestingService),
|
||||
"ml_training" | "ml" => services.push(ServiceType::MLTrainingService),
|
||||
|
||||
@@ -112,7 +112,7 @@ impl E2ETestFramework {
|
||||
sub: "e2e_test_user".to_string(),
|
||||
exp: now + 3600, // 1 hour expiration
|
||||
iat: now,
|
||||
iss: "foxhunt-api-gateway".to_string(),
|
||||
iss: "foxhunt-api".to_string(),
|
||||
aud: "foxhunt-services".to_string(),
|
||||
jti: uuid::Uuid::new_v4().to_string(),
|
||||
roles: vec!["trader".to_string(), "admin".to_string()],
|
||||
|
||||
@@ -27,7 +27,7 @@ fn create_test_token() -> Result<String, Box<dyn std::error::Error>> {
|
||||
|
||||
let claims = Claims {
|
||||
sub: "test_user".to_string(),
|
||||
iss: "foxhunt-api-gateway".to_string(),
|
||||
iss: "foxhunt-api".to_string(),
|
||||
aud: "foxhunt-services".to_string(),
|
||||
iat: now,
|
||||
exp: now + 3600, // Valid for 1 hour
|
||||
@@ -77,7 +77,7 @@ async fn test_jwt_token_validation() {
|
||||
.map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?;
|
||||
|
||||
assert_eq!(token_data.claims.sub, "test_user");
|
||||
assert_eq!(token_data.claims.iss, "foxhunt-api-gateway");
|
||||
assert_eq!(token_data.claims.iss, "foxhunt-api");
|
||||
assert_eq!(token_data.claims.aud, "foxhunt-services");
|
||||
assert!(token_data.claims.roles.contains(&"trader".to_string()));
|
||||
|
||||
@@ -98,7 +98,7 @@ async fn test_jwt_token_expiration() {
|
||||
|
||||
let expired_claims = Claims {
|
||||
sub: "test_user".to_string(),
|
||||
iss: "foxhunt-api-gateway".to_string(),
|
||||
iss: "foxhunt-api".to_string(),
|
||||
aud: "foxhunt-services".to_string(),
|
||||
iat: now - 7200, // Issued 2 hours ago
|
||||
exp: now - 3600, // Expired 1 hour ago
|
||||
|
||||
@@ -265,7 +265,7 @@ pub fn create_test_jwt(config: TestAuthConfig) -> Result<String> {
|
||||
sub: config.user_id,
|
||||
iat: now.timestamp() as u64,
|
||||
exp: (now + config.expiry_duration).timestamp() as u64,
|
||||
iss: "foxhunt-api-gateway".to_string(), // MUST match API Gateway JwtConfig
|
||||
iss: "foxhunt-api".to_string(), // MUST match API Gateway JwtConfig
|
||||
aud: "foxhunt-services".to_string(), // MUST match API Gateway JwtConfig
|
||||
roles: config.roles,
|
||||
permissions: config.permissions,
|
||||
@@ -433,7 +433,7 @@ mod tests {
|
||||
use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation};
|
||||
let mut validation = Validation::new(Algorithm::HS256);
|
||||
validation.validate_exp = false; // Disable expiry check to decode
|
||||
validation.set_issuer(&["foxhunt-api-gateway"]);
|
||||
validation.set_issuer(&["foxhunt-api"]);
|
||||
validation.set_audience(&["foxhunt-services"]);
|
||||
|
||||
let jwt_secret = get_test_jwt_secret();
|
||||
|
||||
Reference in New Issue
Block a user