ryerraguntla commented on code in PR #4043: URL: https://github.com/apache/iggy/pull/4043#discussion_r4020498006
########## gateways/kafka/src/bridge/config.rs: ########## @@ -0,0 +1,345 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use std::path::Path; + +use secrecy::SecretString; +use tracing::warn; + +use crate::bridge::error::BridgeError; +use crate::bridge::topic_map::{TopicMapping, validate_identifier_name}; + +const DEFAULT_IGGY_ADDR: &str = "127.0.0.1:8090"; +/// Matches `DEFAULT_ROOT_USERNAME` (`core/server/src/boot/credentials.rs`) - the root user's +/// username is always `iggy` regardless of how its password was provisioned, so defaulting this +/// one field is safe. The password is a different story - see why there is no +/// `DEFAULT_IGGY_PASSWORD` at [`IggyBridgeConfig::from_env`]. +const DEFAULT_IGGY_USERNAME: &str = "iggy"; + +/// Connection + topic-mapping config for [`IggyBridge`](crate::bridge::iggy_bridge::IggyBridge). +/// +/// `Debug` is safe to derive: `password` is `SecretString`, which redacts on `Debug` by design +/// (`secrecy` crate) - never add a plain `String` credential field here without the same +/// treatment (see `connector-pr-review` blocker B1 in the connectors subsystem for why). +#[derive(Debug, Clone)] +pub struct IggyBridgeConfig { + pub address: String, + pub username: String, + pub password: SecretString, + pub topic_mapping: TopicMapping, +} + +impl IggyBridgeConfig { + /// The complete set of `IGGY_KAFKA_*` vars this module reads. `main.rs`'s + /// `reject_unknown_kafka_env_vars` checks this list *and* its own separate + /// `KNOWN_KAFKA_ENV_VARS`, not one merged copy - a var added only here is already + /// recognized there with no corresponding edit needed, and vice versa. A var this module + /// reads still has to be listed *somewhere* the guard checks, or a typo silently no-ops + /// instead of surfacing (`IGGY_KAFKA_` is a `DELEGATED_ENV_VAR_PREFIXES` entry in + /// `core/configs`, so the central provider's own typo-detection doesn't cover this namespace + /// either). + pub const KNOWN_ENV_VARS: &'static [&'static str] = &[ + "IGGY_KAFKA_IGGY_ADDR", + "IGGY_KAFKA_IGGY_USERNAME", + "IGGY_KAFKA_IGGY_PASSWORD", + "IGGY_KAFKA_IGGY_STREAM", + "IGGY_KAFKA_TOPIC_MAP_PATH", + ]; + + /// Builds config from `IGGY_KAFKA_*` env vars, defaulting to the Iggy server's own + /// out-of-the-box address and root username. + /// + /// `IGGY_KAFKA_IGGY_PASSWORD` has no default and must be set explicitly. `iggy-server` only + /// provisions the well-known `iggy`/`iggy` root credentials when started with + /// `--with-default-root-credentials` (`args.rs`, itself documented "INSECURE - FOR DEVELOPMENT + /// ONLY!"); without that flag it generates a random password (`boot/credentials.rs`) that no + /// constant here could ever guess. Defaulting the password to `"iggy"` would make this bridge + /// silently authenticate as root, with the credential in no config file and no log, on any + /// server that does happen to run dev-flagged - the failure mode of getting it wrong is a + /// loud, immediate auth rejection instead. + /// + /// `IGGY_KAFKA_IGGY_STREAM` and `IGGY_KAFKA_TOPIC_MAP_PATH` both influence the mapping's + /// default stream; when both are set, the TOML file's own `default_stream` wins and + /// `IGGY_KAFKA_IGGY_STREAM` is ignored entirely for the topics it covers (a TOML file is a + /// complete mapping document, not an overlay) - a `warn!` fires so that isn't silently + /// mysterious to whoever set the env var expecting it to matter. + /// + /// # Errors + /// + /// Returns [`BridgeError::InvalidConfig`] if `IGGY_KAFKA_IGGY_PASSWORD` is unset or empty, if + /// `IGGY_KAFKA_IGGY_USERNAME` is set but empty, or if `IGGY_KAFKA_TOPIC_MAP_PATH` is set but + /// the file is missing or fails to parse. + pub fn from_env() -> Result<Self, BridgeError> { + let address = + std::env::var("IGGY_KAFKA_IGGY_ADDR").unwrap_or_else(|_| DEFAULT_IGGY_ADDR.to_string()); + let username = std::env::var("IGGY_KAFKA_IGGY_USERNAME") + .unwrap_or_else(|_| DEFAULT_IGGY_USERNAME.to_string()); + // set-but-empty (`VAR=""`) is `Ok("")` from `env::var`, not `Err` - distinct from unset, + // and unchecked here would otherwise pass both cleanly through to a login attempt neither + // could ever satisfy. + if username.is_empty() { + return Err(BridgeError::InvalidConfig( + "IGGY_KAFKA_IGGY_USERNAME must not be empty".to_string(), + )); + } + let password = std::env::var("IGGY_KAFKA_IGGY_PASSWORD").map_err(|_| { + BridgeError::InvalidConfig( + "IGGY_KAFKA_IGGY_PASSWORD must be set - iggy-server generates a random root \ + password unless started with --with-default-root-credentials, so there is no \ + safe default to fall back to" + .to_string(), + ) + })?; + if password.is_empty() { + return Err(BridgeError::InvalidConfig( + "IGGY_KAFKA_IGGY_PASSWORD must not be empty".to_string(), + )); + } + let stream_env = std::env::var("IGGY_KAFKA_IGGY_STREAM").ok(); + // TopicMapping::new (below, on the no-file branch) validates default_stream too now, so + // removing this check wouldn't let an invalid value through uncaught - but its own message + // would say "topic mapping's default_stream", not IGGY_KAFKA_IGGY_STREAM, leaving whoever + // reads the error to work out which env var that phrase actually refers to. Checked here + // first so the message names the var an operator can actually go fix. + if let Some(ref stream) = stream_env { Review Comment: Moved IGGY_KAFKA_IGGY_STREAM validation into the no-file branch only. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
