-
-
Notifications
You must be signed in to change notification settings - Fork 6
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
feat: environment variable interpolation #30
base: main
Are you sure you want to change the base?
feat: environment variable interpolation #30
Conversation
Codecov ReportAttention: Patch coverage is
|
src/app/mod.rs
Outdated
pub port: Option<u16>, | ||
#[serde(deserialize_with = "deserialize_optional_env_var")] |
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.
This is a first attempt at getting variable interpolation working. It does work, but it's breaking optional config values. I keep getting the following error:
Error: radarr: missing field `uri` at line 2 column 3
This occurs with any other optional config value, like ssl_cert_paths
as well.
I'm having trouble figuring out where that's coming from or how to make the values actually optional again 😅 @Dark-Alex-17, any ideas? It doesn't seem to be coming from the validate() function, so it seems like something is using the config values before they're validated?
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.
Aside from breaking optional values, I'm not sure if there's a less verbose way to generalize deserializing the various types of config values (String
, Option<String>
, and Option<u16>
).
For now, I had to make separate deserializers for each, but I wonder if there's a way to generalize them, without doing something icky and just treating them all as String
or Option<String>
🤔
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.
I have something working that might address these concerns. Mind if I push to your branch?
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.
In short though:
-
To address the concern about security, I created a regex to remove all non-essential characters (including whitespace) from all variable values, not just those interpolated from environment variables. When I tested this, even valid Rust code was rendered unreadable and unusable so I can confirm it does pretty good mitigation of any code injection attacks
-
To address the issue of not being able to start with empty optional values, I added
#[serde(default, ...)]
to theOption
fields which allows Serde to construct the defaultNone
value when it loads from the YAML file and when there's no value for the corresponding field. -
I tried writing a macro to simplify the need for dedicated deserializers for
Option
fields but alas, even after all my tinkering and Googling, what you've come up with truly is the best way to achieve this. -
And I also added a new crate,I actually just put this in a separate commit toveil
, so that debugging is easier; It allows you to derive theDebug
trait on a struct but mark which fields you want redacted on output. So, I naturally redacted theapi_token
field. Then I simply added a new line tomain.rs
that debugs the config that was loaded to help with debugging issues both here, and in the future.main
to make life better for all. -
I also added a few tests to make sure it was working the way I wanted. The only other tests that would need to be written are for the
Option
deserializers. -
I also tested this out with YAML fields that have multiple environment variables and it worked perfectly; e.g.
radarr.uri: http://${RADARR_HOST}:${RADARR_PORT}/something
What are your thoughts?
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.
To address the concern about security, I created a regex to remove all non-essential characters (including whitespace) from all variable values, not just those interpolated from environment variables. When I tested this, even valid Rust code was rendered unreadable and unusable so I can confirm it does pretty good mitigation of any code injection attacks
That's a very interesting and defensive approach. I like it!
To address the issue of not being able to start with empty optional values, I added #[serde(default, ...)] ...
🙌 TIL about serde default
. Great find! That was way simpler than I thought it might be.
I tried writing a macro to simplify the need for dedicated deserializers for Option fields but alas, even after all my tinkering and Googling, what you've come up with truly is the best way to achieve this.
That's a relief 😌 I had no idea how else to make that nicer and haven't delved into macros yet. lol.
I also tested this out with YAML fields that have multiple environment variables and it worked perfectly; e.g. radarr.uri: http://${RADARR_HOST}:${RADARR_PORT}/something
Good thinking. Combining the vars didn't occur to me. I'm glad it works.
I also added a few tests to make sure it was working the way I wanted. The only other tests that would need to be written are for the Option deserializers.
I'll take a look at these next.
Thanks for your help!
7ce5c5a
to
8d450de
Compare
Sorry about the main branch thing. Not entirely sure what's going on right now since it's working locally and that supposed missing |
No worries. I'm pretty sure I'm just having git skill issues somewhere. lol. |
Hey, I've been there. Even as a pro, there's a reason the initial commit for Git literally calls it the, "information manager from hell", along with this explanation:
So. You're in good company 😁 |
Allow
${VAR_INTERPOLATION}
in config file. Addresses #23.Example