Skip to content
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

Fix random secret_provider #56

Merged
merged 6 commits into from
Jun 15, 2020
Merged

Fix random secret_provider #56

merged 6 commits into from
Jun 15, 2020

Conversation

sl4vr
Copy link
Contributor

@sl4vr sl4vr commented May 14, 2020

Resolves #54

  • Removed region from ssm to support same interface for all secret providers
  • Refactored get_secret filter to avoid using exceptions for flow control (partially)
  • Refactored and expanded tests
  • Fix random secret length mismatch bug

@sl4vr sl4vr requested a review from AFriemann May 14, 2020 07:51
@sl4vr sl4vr requested a review from a team as a code owner May 14, 2020 07:51
@sl4vr
Copy link
Contributor Author

sl4vr commented May 14, 2020

@AFriemann hopefully you don't mind if I could practice python on my spare time using k8t 😉

@AFriemann
Copy link
Member

@effect305 absolutely not

@sl4vr sl4vr force-pushed the random_provider_args_bugfix branch from a28383d to 817a093 Compare May 14, 2020 14:10
@sl4vr sl4vr added the wip label May 14, 2020
@sl4vr
Copy link
Contributor Author

sl4vr commented May 14, 2020

Awesome, I'll add tests to get_secret later then.

@sl4vr sl4vr force-pushed the random_provider_args_bugfix branch from 817a093 to 0608d20 Compare May 14, 2020 14:37
k8t/config.py Outdated
Comment on lines 29 to 30
def get_secrets(key: str, default: Any = None) -> Any:
return CONFIG.get("secrets", {}).get(key, default)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def get_secrets(key: str, default: Any = None) -> Any:
return CONFIG.get("secrets", {}).get(key, default)
def get_value(*args: str, default: Any = None) -> Any:
result = copy.deepcopy(CONFIG)
for arg in args:
if result is None:
break
result.get(arg)
return result if result is not None else default

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

my main issue is actually the function name, would also be fine with another suggestion

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My original idea was to have some sort of safe navigation function for config, which would also support lists. Like this:

def fetch(*keys):
    return dig(CONFIG, *keys)


def dig(target, *keys):
    if len(keys) > 0:
        key = keys[0]
    else:
        return target

    if isinstance(target, dict):
        return dig(target[key], *keys[1:]) if key in target else None
    if isinstance(target, list):
        return dig(target[key], *keys[1:]) if isinstance(key, int) and key < len(target) else None
    return None

But then I considered possibility of import only get_secrets to modules that need access to secrets section of config only and end up with get_secrets function as also a much simpler solution, at least for current config usages.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you insist to use kind of safe navigation function, I would suggest:

  • definitely remove default argument as nonintuitive and return None instead. So caller could handle it on his own:
region = config.get_value("secrets", "region") or DEFAULT_REGION
  • allow to navigate through lists, since yaml support them. But that's probably comes from ruby background, maybe it's redundant feature.
def get_value(*args: Union[str, int]) -> Any:
    result = CONFIG
    
    for arg in args:
        if isinstance(result, dict):
            result = result.get(arg)
        elif isinstance(result, list):
            try:
                result = result[arg]
            except (IndexError, TypeError):
                return None
        else:
            return None
    return result

Anyway while there's such limited config usage, I would stick to just get_secrets function with only 1 level of lookup as simplest option.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing the default makes sense, it could be confusing since you'd have to pass it as kwarg and defaults are probably handled on the module itself anyway.

The list navigation I think is unnecessary, would leave that to the caller to handle (you should be expecting a list if there is a list defined and most of the time you can't be sure about the item order anyway).

And no I definitely wouldn't insist on it; think i'd also be fine with a more clear name, it's just confusing to read get_secrets since it evokes the idea of actually getting the secret value, not configuration. How about we drop the get and just go with secrets since it reads better in context?

region = config.secrets("region") or DEFAULT_REGION

Copy link
Contributor Author

@sl4vr sl4vr May 15, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My idea of get_secrets was to provide same interface as get method of dict provides. Thus its name, it's kinda get method for secrets section of config, "get from secrets" in other words.

If it doesn't make much sense, tbh I would stick to get_value option, just without default, and maybe with better name.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I've just realized that get_secrets looks very similar to helper function itself. Maybe it's really better to go with get_value then.

@sl4vr
Copy link
Contributor Author

sl4vr commented May 19, 2020

@AFriemann There are still some things to decide about configuration access: type safety, default values (or doesn't suit there, because it overrides False), etc. So I've decided to use get for now as most native and simple way.

@sl4vr sl4vr removed the wip label May 19, 2020
@sl4vr sl4vr requested a review from AFriemann May 19, 2020 07:14
@sl4vr sl4vr force-pushed the random_provider_args_bugfix branch from b899c99 to 8b82d62 Compare May 19, 2020 07:55
Comment on lines +85 to +87
provider_name = config.CONFIG.get("secrets", {}).get("provider")
if not provider_name:
raise RuntimeError("Secrets provider not configured.")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could just go with an exception here

provider_name = None

try:
  provider_name = config.CONFIG['secrets']['provider'].lower()
except KeyError:
  raise RuntimeError("Secrets provider not configured.")

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it's just kinda artifact from previous implementation.

Copy link
Member

@AFriemann AFriemann left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's fine for now

@sl4vr sl4vr added the bug Something isn't working label Jun 13, 2020
@AFriemann AFriemann merged commit 0676020 into master Jun 15, 2020
@AFriemann AFriemann deleted the random_provider_args_bugfix branch June 15, 2020 12:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging this pull request may close these issues.

get_secret fails with random provider
2 participants