-
Notifications
You must be signed in to change notification settings - Fork 5
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
Environment Variable for Authentication Token Refactor #75
base: main
Are you sure you want to change the base?
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -3,6 +3,7 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
use std::cell::{Ref, RefCell}; | ||||||||||||||||||||||||||||||||||||||||||||||||||
use std::collections::{BTreeMap, BTreeSet}; | ||||||||||||||||||||||||||||||||||||||||||||||||||
use std::env::VarError; | ||||||||||||||||||||||||||||||||||||||||||||||||||
use std::path::{Path, PathBuf}; | ||||||||||||||||||||||||||||||||||||||||||||||||||
use std::rc::Rc; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -60,20 +61,21 @@ impl State { | |||||||||||||||||||||||||||||||||||||||||||||||||
pub async fn authentication_token( | ||||||||||||||||||||||||||||||||||||||||||||||||||
&self, | ||||||||||||||||||||||||||||||||||||||||||||||||||
token_path: Option<&str>, | ||||||||||||||||||||||||||||||||||||||||||||||||||
env_vars: &EnvVars, | ||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This kind of muddies the waters on what At least from my reading, Seems to me the logic around getting what the canonical token is should be something like: let env = EnvVars::read();
let state = State::load();
// Determine the canonical auth token
// Having the env var set is higher priority than the on-disk
let auth_token = if let Some(env_token) = env.authentication_token() {
env_token
} else if let Some(state_token) = state.authentication_token() {
state_token
}
println!("The token is {}", auth_token); There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree, this is muddying for sure. This has an issue that the user will have to do this (call EnvVars and State) at the call site. Are you suggesting that a separate module for Authentication token that can do this for the user? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess what I'm saying is having a If I'm using Similarly, if I am using tldr: The |
||||||||||||||||||||||||||||||||||||||||||||||||||
) -> Option<AuthenticationToken> { | ||||||||||||||||||||||||||||||||||||||||||||||||||
match token_path { | ||||||||||||||||||||||||||||||||||||||||||||||||||
Some(token_path) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||
let token_path = std::path::Path::new(token_path); | ||||||||||||||||||||||||||||||||||||||||||||||||||
if token_path.exists() { | ||||||||||||||||||||||||||||||||||||||||||||||||||
match tokio::fs::read_to_string(token_path).await { | ||||||||||||||||||||||||||||||||||||||||||||||||||
Ok(token) => Some(AuthenticationToken(token.to_string().trim().into())), | ||||||||||||||||||||||||||||||||||||||||||||||||||
Err(_) => self.authentication_token_inner(), | ||||||||||||||||||||||||||||||||||||||||||||||||||
Err(_) => self.authentication_token_inner(env_vars), | ||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||||||||||||||||||||||
self.authentication_token_inner() | ||||||||||||||||||||||||||||||||||||||||||||||||||
self.authentication_token_inner(env_vars) | ||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||
None => self.authentication_token_inner(), | ||||||||||||||||||||||||||||||||||||||||||||||||||
None => self.authentication_token_inner(env_vars), | ||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -82,10 +84,10 @@ impl State { | |||||||||||||||||||||||||||||||||||||||||||||||||
/// Attempts to read from: | ||||||||||||||||||||||||||||||||||||||||||||||||||
/// 1. The `CRITICALUP_TOKEN_ENV_VAR_NAME` environment | ||||||||||||||||||||||||||||||||||||||||||||||||||
/// 2. The state | ||||||||||||||||||||||||||||||||||||||||||||||||||
fn authentication_token_inner(&self) -> Option<AuthenticationToken> { | ||||||||||||||||||||||||||||||||||||||||||||||||||
match std::env::var(CRITICALUP_TOKEN_ENV_VAR_NAME) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
Ok(token_from_env) => Some(AuthenticationToken(token_from_env)), | ||||||||||||||||||||||||||||||||||||||||||||||||||
Err(_) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||
fn authentication_token_inner(&self, env_vars: &EnvVars) -> Option<AuthenticationToken> { | ||||||||||||||||||||||||||||||||||||||||||||||||||
match &env_vars.criticalup_token { | ||||||||||||||||||||||||||||||||||||||||||||||||||
Some(token) => Some(AuthenticationToken(token.to_string())), | ||||||||||||||||||||||||||||||||||||||||||||||||||
None => { | ||||||||||||||||||||||||||||||||||||||||||||||||||
let borrowed = self.inner.borrow(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
borrowed.repr.authentication_token.clone() | ||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -374,6 +376,34 @@ impl StateInstallation { | |||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
#[derive(Default)] | ||||||||||||||||||||||||||||||||||||||||||||||||||
amanjeev marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||||||
pub struct EnvVars { | ||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
criticalup/crates/criticalup-core/src/config/paths.rs Lines 12 to 21 in 2363ed2
Specifically here: criticalup/crates/criticalup-core/src/config/paths.rs Lines 57 to 63 in 2363ed2
As well as: criticalup/crates/criticalup-core/src/config/paths.rs Lines 69 to 75 in 2363ed2
This makes me wonder if There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes it makes sense to me to include these in EnvVars. |
||||||||||||||||||||||||||||||||||||||||||||||||||
criticalup_token: Option<String>, | ||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
impl EnvVars { | ||||||||||||||||||||||||||||||||||||||||||||||||||
pub async fn read() -> Result<Self, Error> { | ||||||||||||||||||||||||||||||||||||||||||||||||||
let mut env_vars = EnvVars::default(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
match std::env::var(CRITICALUP_TOKEN_ENV_VAR_NAME) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
Ok(value) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||
if !value.is_empty() { | ||||||||||||||||||||||||||||||||||||||||||||||||||
env_vars.criticalup_token = Some(value); | ||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||
Err(var_err) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||
if let VarError::NotUnicode(err) = var_err { | ||||||||||||||||||||||||||||||||||||||||||||||||||
return Err(Error::EnvVarNotUtf8 { | ||||||||||||||||||||||||||||||||||||||||||||||||||
name: CRITICALUP_TOKEN_ENV_VAR_NAME.to_string(), | ||||||||||||||||||||||||||||||||||||||||||||||||||
kind: VarError::NotUnicode(err), | ||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
Ok(env_vars) | ||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
#[derive(Clone, Serialize, Deserialize)] | ||||||||||||||||||||||||||||||||||||||||||||||||||
#[cfg_attr(test, derive(PartialEq, Eq))] | ||||||||||||||||||||||||||||||||||||||||||||||||||
pub struct AuthenticationToken(String); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -419,6 +449,7 @@ impl std::fmt::Debug for AuthenticationToken { | |||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
#[cfg(test)] | ||||||||||||||||||||||||||||||||||||||||||||||||||
mod tests { | ||||||||||||||||||||||||||||||||||||||||||||||||||
use crate::state::EnvVars; | ||||||||||||||||||||||||||||||||||||||||||||||||||
use crate::test_utils::TestEnvironment; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
use super::*; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -431,6 +462,10 @@ mod tests { | |||||||||||||||||||||||||||||||||||||||||||||||||
}} | ||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
const ENV_VARS: EnvVars = EnvVars { | ||||||||||||||||||||||||||||||||||||||||||||||||||
criticalup_token: None, | ||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
#[tokio::test] | ||||||||||||||||||||||||||||||||||||||||||||||||||
async fn test_load_state_without_existing_file() { | ||||||||||||||||||||||||||||||||||||||||||||||||||
let test = TestEnvironment::prepare().await; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -460,7 +495,7 @@ mod tests { | |||||||||||||||||||||||||||||||||||||||||||||||||
let state = State::load(test_env.config()).await.unwrap(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
assert_eq!( | ||||||||||||||||||||||||||||||||||||||||||||||||||
Some(AuthenticationToken("hello".into())), | ||||||||||||||||||||||||||||||||||||||||||||||||||
state.authentication_token(None).await | ||||||||||||||||||||||||||||||||||||||||||||||||||
state.authentication_token(None, &ENV_VARS).await | ||||||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -751,7 +786,7 @@ mod tests { | |||||||||||||||||||||||||||||||||||||||||||||||||
state.set_authentication_token(None); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
// Make sure the state file has authentication token as None. | ||||||||||||||||||||||||||||||||||||||||||||||||||
assert_eq!(state.authentication_token(None).await, None); | ||||||||||||||||||||||||||||||||||||||||||||||||||
assert_eq!(state.authentication_token(None, &ENV_VARS).await, None); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
let file_token_content = "my-awesome-token-from-file"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
let token_name = "CRITICALUP_TOKEN"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -763,7 +798,10 @@ mod tests { | |||||||||||||||||||||||||||||||||||||||||||||||||
std::fs::write(secrets_dir.join(token_name), file_token_content).unwrap(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
let token = test_env | ||||||||||||||||||||||||||||||||||||||||||||||||||
.state() | ||||||||||||||||||||||||||||||||||||||||||||||||||
.authentication_token(Some(secrets_dir.join(token_name).to_str().unwrap())) | ||||||||||||||||||||||||||||||||||||||||||||||||||
.authentication_token( | ||||||||||||||||||||||||||||||||||||||||||||||||||
Some(secrets_dir.join(token_name).to_str().unwrap()), | ||||||||||||||||||||||||||||||||||||||||||||||||||
&ENV_VARS, | ||||||||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||||||||
.await; | ||||||||||||||||||||||||||||||||||||||||||||||||||
assert_eq!(Some(AuthenticationToken(file_token_content.into())), token) | ||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -774,12 +812,12 @@ mod tests { | |||||||||||||||||||||||||||||||||||||||||||||||||
let state = test_env.state(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
state.set_authentication_token(None); | ||||||||||||||||||||||||||||||||||||||||||||||||||
assert_eq!(None, state.authentication_token(None).await); | ||||||||||||||||||||||||||||||||||||||||||||||||||
assert_eq!(None, state.authentication_token(None, &ENV_VARS).await); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
state.set_authentication_token(Some(AuthenticationToken("hello world".into()))); | ||||||||||||||||||||||||||||||||||||||||||||||||||
assert_eq!( | ||||||||||||||||||||||||||||||||||||||||||||||||||
Some(AuthenticationToken("hello world".into())), | ||||||||||||||||||||||||||||||||||||||||||||||||||
state.authentication_token(None).await | ||||||||||||||||||||||||||||||||||||||||||||||||||
state.authentication_token(None, &ENV_VARS).await | ||||||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -794,7 +832,10 @@ mod tests { | |||||||||||||||||||||||||||||||||||||||||||||||||
test_env.state().persist().await.unwrap(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
let new_state = State::load(test_env.config()).await.unwrap(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
assert_eq!(Some(token), new_state.authentication_token(None).await); | ||||||||||||||||||||||||||||||||||||||||||||||||||
assert_eq!( | ||||||||||||||||||||||||||||||||||||||||||||||||||
Some(token), | ||||||||||||||||||||||||||||||||||||||||||||||||||
new_state.authentication_token(None, &ENV_VARS).await | ||||||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
#[tokio::test] | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -1009,4 +1050,41 @@ mod tests { | |||||||||||||||||||||||||||||||||||||||||||||||||
unused_installations | ||||||||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
#[tokio::test] | ||||||||||||||||||||||||||||||||||||||||||||||||||
async fn test_set_authn_token_env_var() { | ||||||||||||||||||||||||||||||||||||||||||||||||||
amanjeev marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||||||
let test_env = TestEnvironment::with().state().prepare().await; | ||||||||||||||||||||||||||||||||||||||||||||||||||
let state = test_env.state(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
let token = "my_awesome_token".to_string(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
let env_vars = EnvVars { | ||||||||||||||||||||||||||||||||||||||||||||||||||
criticalup_token: Some(token.clone()), | ||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
state.set_authentication_token(None); | ||||||||||||||||||||||||||||||||||||||||||||||||||
assert_eq!( | ||||||||||||||||||||||||||||||||||||||||||||||||||
Some(AuthenticationToken(token)), | ||||||||||||||||||||||||||||||||||||||||||||||||||
state.authentication_token(None, &env_vars).await | ||||||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
let env_vars = EnvVars { | ||||||||||||||||||||||||||||||||||||||||||||||||||
criticalup_token: None, | ||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||
assert_eq!(None, state.authentication_token(None, &env_vars).await); | ||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
#[tokio::test] | ||||||||||||||||||||||||||||||||||||||||||||||||||
async fn test_read_env_var() { | ||||||||||||||||||||||||||||||||||||||||||||||||||
std::env::set_var(CRITICALUP_TOKEN_ENV_VAR_NAME, "HoustonWeHaveAToken!"); | ||||||||||||||||||||||||||||||||||||||||||||||||||
let ev = EnvVars::read().await.unwrap(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
assert_eq!( | ||||||||||||||||||||||||||||||||||||||||||||||||||
ev.criticalup_token, | ||||||||||||||||||||||||||||||||||||||||||||||||||
Some("HoustonWeHaveAToken!".to_string()) | ||||||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
std::env::remove_var(CRITICALUP_TOKEN_ENV_VAR_NAME); | ||||||||||||||||||||||||||||||||||||||||||||||||||
let ev = EnvVars::read().await.unwrap(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
assert_eq!(ev.criticalup_token, None); | ||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||
} |
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.
Noted elsewhere but this is the only usage of the token file path in our codebase, it creates some very confusing logic and perhaps we should refactor it out and have
EnvVars
intelligently detect if it's inside docker and look at/run/secrets
when it's being built.