Skip to content
This repository was archived by the owner on Jul 28, 2025. It is now read-only.

Configurable keyring backends#278

Merged
calvinrp merged 3 commits intobytecodealliance:mainfrom
dfoxfranke:feature/pluggable-keyring
May 13, 2024
Merged

Configurable keyring backends#278
calvinrp merged 3 commits intobytecodealliance:mainfrom
dfoxfranke:feature/pluggable-keyring

Conversation

@dfoxfranke
Copy link
Contributor

@dfoxfranke dfoxfranke commented May 10, 2024

Makes keyring backends user-selectable, as discussed in #271 (comment).

  • Refactor client::keyring functions into a Keyring struct which can be instantiated with a backend selection.
  • Add a config option to control what backend is used.
  • Improve error reporting when the secret-service backend isn't working.
  • Add a flat-file backend that stores keys in plaintext alongside the config file.

This refactors `warg_client::keyring` to make everything a method
of a `Keyring` struct which can support multiple `CredentialBuilder`s.
Currently, all CLI commands still just use the system default
everywhere, but next, a config option can be added to customize it.
@dfoxfranke dfoxfranke force-pushed the feature/pluggable-keyring branch from 8a7570a to 01e3d40 Compare May 10, 2024 17:34
Create a `KeyringError` type providing structured information about
what went wrong. In the case of a platform error when using the
secret-service backend, provide a tip on how to remedy it.
@dfoxfranke
Copy link
Contributor Author

I'm marking this ready for review. The flat-file backend isn't implemented yet, but I think there's now enough in this PR to constitute an improvement for users, so it's suitable for merging.

@dfoxfranke dfoxfranke marked this pull request as ready for review May 13, 2024 17:07
Copy link
Collaborator

@lann lann left a comment

Choose a reason for hiding this comment

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

Code lgtm; cc @calvinrp who has worked on keyring more recently

pub type Result<T, E = KeyringError> = std::result::Result<T, E>;

impl Keyring {
#[cfg(target_os = "linux")]
Copy link
Collaborator

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I didn't think it worth pulling in the dependency just to use it in this one place where it barely provides any simplification. But if it gets pulled in later for wider use then, yes, this should be refactored.

if let Some(ref backend) = config.keyring_backend {
Self::new(backend.as_str())
} else {
Self::new(Self::SUPPORTED_BACKENDS[0])
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
Self::new(Self::SUPPORTED_BACKENDS[0])
Self::new(Self::DEFAULT_BACKEND)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Calvin already merged, so I'll fix this in my next PR.

pub const DEFAULT_BACKEND: &'static str = Self::SUPPORTED_BACKENDS[0];

/// Returns a human-readable description of a keyring backend.
pub fn describe_backend(backend: &str) -> &'static str {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Would it be difficult to make backend an enum?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I considered this but decided it would create more problems than it would solve. The set of supported backends is platform-dependent, so there would be a distinction between the enumeration of all understood backend identifiers, and the subset of those which are supported on the user's platform. So there would be a design trade-off between:

  1. Defining two separate enums, one which covers all backends and one which covers those which are supported on the platform.
  2. Defining only the supported enum, and needing a bunch of conditional attributes every time you want to match on it.
  3. Defining only the all-backends enum, and putting an is_supported(&self) -> bool method on it.

Then we have to decide how exactly we want our Serialize and Deserialize implementations to work and which type they should use, and probably put custom error reporting into this traits to not be too cryptic if the user copies a configuration file from one system to another where the backend isn't supported. Altogether it didn't seem worth it, so I just kept this stringly typed.

@calvinrp
Copy link
Collaborator

Thank you! This looks great.

@calvinrp calvinrp self-requested a review May 13, 2024 18:24
@calvinrp calvinrp merged commit c941934 into bytecodealliance:main May 13, 2024
calvinrp pushed a commit that referenced this pull request May 15, 2024
This adds support for storing warg credentials as flat files in the warg
config directory, following up on #278.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants