Reject invalid deployment configuration early
This commit is contained in:
parent
2020dd4ed3
commit
0e351c3640
1 changed files with 543 additions and 55 deletions
|
|
@ -104,7 +104,7 @@ impl ApiApplicationConfig {
|
|||
let lease_ttl = env_duration("REMORA_LEASE_TTL_SECONDS", 30)?;
|
||||
let target = TargetStoreConfig::from_env().map_err(runtime_error)?;
|
||||
let vault = VaultConfig::from_env().map_err(runtime_error)?;
|
||||
Ok(Self {
|
||||
let config = Self {
|
||||
public_bind: env_parse("REMORA_PUBLIC_BIND", "0.0.0.0:8080")?,
|
||||
worker_bind: env_parse("REMORA_WORKER_BIND", "0.0.0.0:8443")?,
|
||||
management: ManagementConfig::from_env(crate::COMPONENT_NAME)?,
|
||||
|
|
@ -156,10 +156,54 @@ impl ApiApplicationConfig {
|
|||
private_key: PathBuf::from(required_env("REMORA_WORKER_TLS_KEY_FILE")?),
|
||||
client_ca: PathBuf::from(required_env("REMORA_WORKER_TLS_CLIENT_CA_FILE")?),
|
||||
},
|
||||
})
|
||||
};
|
||||
validate_api_limits(
|
||||
config.database_connections,
|
||||
&config.coordination,
|
||||
&config.attempt,
|
||||
&config.recovery,
|
||||
&config.public_api,
|
||||
)?;
|
||||
Ok(config)
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_api_limits(
|
||||
database_connections: u32,
|
||||
coordination: &StoreConfig,
|
||||
attempt: &AttemptConfig,
|
||||
recovery: &RecoveryConfig,
|
||||
public_api: &PublicApiConfig,
|
||||
) -> Result<(), RuntimeError> {
|
||||
if database_connections == 0
|
||||
|| coordination.global_limit == 0
|
||||
|| coordination.lease_ttl.is_zero()
|
||||
|| coordination.reserve_ttl.is_zero()
|
||||
|| coordination.progress_ttl.is_zero()
|
||||
|| attempt.max_attempts == 0
|
||||
|| recovery.retry_delay.is_zero()
|
||||
|| recovery.cleanup_claim_ttl.is_zero()
|
||||
|| recovery.batch_size == 0
|
||||
|| public_api.cursor_secret.is_empty()
|
||||
|| public_api.member_access_ttl.is_zero()
|
||||
|| public_api.event_retention.is_zero()
|
||||
|| public_api.event_poll_interval.is_zero()
|
||||
|| public_api.event_heartbeat_interval.is_zero()
|
||||
|| public_api.event_ticket_ttl.is_zero()
|
||||
|| public_api.event_ticket_ttl > Duration::from_secs(60)
|
||||
|| public_api.event_allowed_origins.is_empty()
|
||||
|| public_api
|
||||
.event_allowed_origins
|
||||
.iter()
|
||||
.any(|origin| origin.is_empty() || origin.trim() != origin)
|
||||
{
|
||||
return Err(RuntimeError::message(
|
||||
"API limits and timing must be positive and event ticket expiry must not exceed 60 seconds",
|
||||
));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl ApiApplication {
|
||||
#[must_use]
|
||||
pub fn new(config: ApiApplicationConfig) -> Self {
|
||||
|
|
@ -657,4 +701,33 @@ mod tests {
|
|||
"cannot read REMORA_CURSOR_SECRET_FILE: entity not found"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validates_api_limits_before_external_connections() {
|
||||
let coordination = StoreConfig {
|
||||
global_limit: 1,
|
||||
lease_ttl: Duration::from_secs(30),
|
||||
reserve_ttl: Duration::from_secs(30),
|
||||
progress_ttl: Duration::from_secs(60),
|
||||
cancel_ttl: None,
|
||||
};
|
||||
let attempt = AttemptConfig { max_attempts: 1 };
|
||||
let recovery = RecoveryConfig {
|
||||
retry_delay: Duration::from_secs(1),
|
||||
cleanup_claim_ttl: Duration::from_secs(30),
|
||||
batch_size: 1,
|
||||
};
|
||||
let mut public_api = PublicApiConfig {
|
||||
cursor_secret: vec![1; 32],
|
||||
member_access_ttl: Duration::from_secs(60),
|
||||
event_retention: Duration::from_secs(3600),
|
||||
event_poll_interval: Duration::from_millis(250),
|
||||
event_heartbeat_interval: Duration::from_secs(15),
|
||||
event_ticket_ttl: Duration::from_secs(30),
|
||||
event_allowed_origins: vec!["https://remora.example".into()],
|
||||
};
|
||||
assert!(validate_api_limits(1, &coordination, &attempt, &recovery, &public_api).is_ok());
|
||||
public_api.event_ticket_ttl = Duration::from_secs(61);
|
||||
assert!(validate_api_limits(1, &coordination, &attempt, &recovery, &public_api).is_err());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue