-
Notifications
You must be signed in to change notification settings - Fork 54
Support configuration env variable replacement #385
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
We want to support environment variable replacement in the configuration similarly to how it is done in llama-stack. Example use case / motivation: The config, which since 3f7ed75 can contain a password to a database, requires users to move their entire config to a Kubernetes secret, as it now contains sensitive information, rather than a configmap. If instead we supported environment variable replacement, users could keep their config in a configmap and just set the password in a secret as k8s allows you to load secret values as environment variables in pods. Since users of lightspeed-stack are already familiar with the syntax for environment variable replacement from llama-stack, we can use the same function from llama-stack to handle this.
WalkthroughAdds environment variable substitution during configuration loading by invoking replace_env_vars on the YAML-loaded config dict within AppConfig.load_configuration. No changes to public interfaces or other behavior. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant AppConfig
participant YAMLLoader
participant EnvSubst as replace_env_vars
participant Model as Configuration
User->>AppConfig: load_configuration(path)
AppConfig->>YAMLLoader: load YAML
YAMLLoader-->>AppConfig: config_dict
AppConfig->>EnvSubst: replace_env_vars(config_dict)
EnvSubst-->>AppConfig: config_dict (resolved)
AppConfig->>Model: instantiate(Configuration, dict)
Model-->>AppConfig: configuration instance
AppConfig-->>User: AppConfig with resolved config
Estimated code review effort🎯 2 (Simple) | ⏱️ ~7 minutes Poem
✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/configuration.py (1)
6-9: llama-stack dependency pinned—confirm replace_env_vars API stability
- pyproject.toml (lines 28–29) declares and pins
- llama-stack==0.2.17
- llama-stack-client==0.2.17
- src/configuration.py
- line 8:
from llama_stack.core.stack import replace_env_vars- line 46: uses
replace_env_vars(config_dict)Ensure that
replace_env_varsis part of llama-stack’s stable, public API. If it isn’t guaranteed to remain stable, introduce a thin wrapper in this repo to isolate future upstream changes.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/configuration.py(3 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: build-pr
- GitHub Check: e2e_tests
| """Load configuration from YAML file.""" | ||
| with open(filename, encoding="utf-8") as fin: | ||
| config_dict = yaml.safe_load(fin) | ||
| config_dict = replace_env_vars(config_dict) | ||
| logger.info("Loaded configuration: %s", config_dict) | ||
| self.init_from_dict(config_dict) | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Stop logging full configuration (secrets leak) and harden env-var substitution handling.
Now that secrets can come from env vars, logging the entire config at info level risks leaking credentials. Also, yaml.safe_load can return None on empty files; passing that into replace_env_vars will likely error.
- Do not log the full configuration.
- Handle None from yaml.safe_load.
- Add defensive error handling around replace_env_vars to fail fast with a clear message.
Apply this diff:
with open(filename, encoding="utf-8") as fin:
- config_dict = yaml.safe_load(fin)
- config_dict = replace_env_vars(config_dict)
- logger.info("Loaded configuration: %s", config_dict)
+ config_dict = yaml.safe_load(fin) or {}
+ try:
+ config_dict = replace_env_vars(config_dict)
+ except Exception as e:
+ logger.error("Failed to apply environment variable substitution: %s", e)
+ raise
+ # Avoid logging secrets; log only the top-level sections/keys.
+ logger.info("Loaded configuration sections: %s", list(config_dict.keys()))
self.init_from_dict(config_dict)Optional follow-ups I can help with:
- Add unit tests covering nested env-var replacement, missing variables behavior, and type casting to ensure values still validate against Configuration. Want me to draft these?
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| """Load configuration from YAML file.""" | |
| with open(filename, encoding="utf-8") as fin: | |
| config_dict = yaml.safe_load(fin) | |
| config_dict = replace_env_vars(config_dict) | |
| logger.info("Loaded configuration: %s", config_dict) | |
| self.init_from_dict(config_dict) | |
| """Load configuration from YAML file.""" | |
| with open(filename, encoding="utf-8") as fin: | |
| config_dict = yaml.safe_load(fin) or {} | |
| try: | |
| config_dict = replace_env_vars(config_dict) | |
| except Exception as e: | |
| logger.error("Failed to apply environment variable substitution: %s", e) | |
| raise | |
| # Avoid logging secrets; log only the top-level sections/keys. | |
| logger.info("Loaded configuration sections: %s", list(config_dict.keys())) | |
| self.init_from_dict(config_dict) |
🤖 Prompt for AI Agents
In src/configuration.py around lines 43 to 49, stop logging the entire
configuration (to avoid leaking secrets), handle yaml.safe_load possibly
returning None, and add defensive error handling around replace_env_vars to fail
fast with a clear message; specifically, treat a None result from safe_load as
an empty dict (or raise a clear error), wrap the call to replace_env_vars in a
try/except that catches exceptions and raises/ logs a concise ValueError with
context (but do not include config contents or secret values), and replace the
info-level log of the full config with a non-sensitive message (e.g.,
"configuration loaded" or a debug log of a sanitized summary) before calling
self.init_from_dict.
maorfr
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/lgtm
tisnik
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
We want to support environment variable replacement in the configuration similarly to how it is done in llama-stack.
Example use case / motivation:
The config, which since 3f7ed75 can contain a password to a database, requires users to move their entire config to a Kubernetes secret, as it now contains sensitive information, rather than a configmap. If instead we supported environment variable replacement, users could keep their config in a configmap and just set the password in a secret as k8s allows you to load secret values as environment variables in pods.
Since users of lightspeed-stack are already familiar with the syntax for environment variable replacement from llama-stack, we can use the same function from llama-stack to handle this.
Description
Type of change
Related Tickets & Documents
Checklist before requesting a review
Testing
Checked that it works. Since it's a borrowed function, testing seems unnecessary
Summary by CodeRabbit