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

[SM-1129] Run command with secrets #621

Merged
merged 87 commits into from
Aug 16, 2024
Merged
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
07e1fe9
feat: add `bws run` command
tangowithfoxtrot Feb 20, 2024
391d6b1
Merge branch 'main' into run-command-with-secrets
tangowithfoxtrot Feb 21, 2024
bd75024
allow reading from stdin
tangowithfoxtrot Feb 21, 2024
48f3841
allow other shells
tangowithfoxtrot Feb 21, 2024
1e5d63a
print stdout+stderr as they happen
tangowithfoxtrot Feb 21, 2024
a52b989
inherit output instead of piping it manually
tangowithfoxtrot Feb 21, 2024
710ae61
return child process exit status
tangowithfoxtrot Feb 21, 2024
f3ad7f3
display warning about problematic key names
tangowithfoxtrot Feb 21, 2024
c7d29ad
add `--no-inherit-env` option
tangowithfoxtrot Feb 21, 2024
211d067
appease clippy 📎
tangowithfoxtrot Feb 21, 2024
26af620
fix: wrong default shell on Windows
tangowithfoxtrot Feb 22, 2024
0f4d996
fix: determine OS at runtime (not compile time)
tangowithfoxtrot Feb 23, 2024
7516a45
update warning message
tangowithfoxtrot Feb 23, 2024
a19e820
fix: run command hanging if no command was supplied; don't allow inte…
tangowithfoxtrot Feb 23, 2024
bafdaad
Merge branch 'main' into run-command-with-secrets
tangowithfoxtrot Feb 27, 2024
5fc71d3
Merge branch 'main' into run-command-with-secrets
tangowithfoxtrot Mar 18, 2024
6ad88b8
fix: panic on invalid shell
tangowithfoxtrot Mar 18, 2024
accc97e
`cargo fmt`
tangowithfoxtrot Mar 18, 2024
b78284b
fix: `clippy::nonminimal_bool`
tangowithfoxtrot Mar 18, 2024
c2ee84c
fix: `clippy::nonminimal_bool`
tangowithfoxtrot Apr 25, 2024
acbffe6
Merge remote-tracking branch 'origin/main' into run-command-with-secrets
tangowithfoxtrot Apr 25, 2024
9eb8e9f
update hermit-abi
tangowithfoxtrot Apr 29, 2024
4dfde95
use `expect` instead of `unwrap`
tangowithfoxtrot Apr 29, 2024
9fc608b
cargo fmt
tangowithfoxtrot Apr 29, 2024
1ab92be
Merge branch 'main' into run-command-with-secrets
tangowithfoxtrot Apr 29, 2024
ce96046
Update crates/bws/src/main.rs
tangowithfoxtrot May 28, 2024
8e51cf9
Update crates/bws/src/main.rs
tangowithfoxtrot May 28, 2024
68306b3
fmt
tangowithfoxtrot May 28, 2024
2e673b6
remove unused RunCommand
tangowithfoxtrot May 28, 2024
b6e676a
extract valid posix key detection so that it can be reused
tangowithfoxtrot May 29, 2024
65b5492
Merge branch 'main' into run-command-with-secrets
tangowithfoxtrot May 29, 2024
f483b30
Revert "Merge branch 'main' into run-command-with-secrets"
tangowithfoxtrot May 29, 2024
64c30c6
Merge branch 'main' into run-command-with-secrets
tangowithfoxtrot May 29, 2024
0e87279
move run command to cli.rs
tangowithfoxtrot May 29, 2024
606185c
re-add which to cargo
tangowithfoxtrot May 29, 2024
30da24c
cargo fmt
tangowithfoxtrot Jun 4, 2024
8cdf289
rm redundant child.wait
tangowithfoxtrot Jun 4, 2024
cd56439
fail if duplicate keynames
tangowithfoxtrot Jun 11, 2024
14fa8df
Merge branch 'main' into run-command-with-secrets
tangowithfoxtrot Jun 11, 2024
cb9903a
unset BWS_ACCESS_TOKEN in run command by default
tangowithfoxtrot Jun 11, 2024
9511ba2
feat: uuids-as-keynames
tangowithfoxtrot Jun 11, 2024
55c9e72
appease clippy
tangowithfoxtrot Jun 12, 2024
0c6128a
use `contains_key` instead of `entry`
tangowithfoxtrot Jun 12, 2024
09bdee7
Merge branch 'main' into run-command-with-secrets
tangowithfoxtrot Jun 21, 2024
9ae6078
refactor run command
tangowithfoxtrot Jun 21, 2024
4a4a8d8
`cargo fmt`
tangowithfoxtrot Jun 21, 2024
cb6f987
Merge branch 'main' into run-command-with-secrets
tangowithfoxtrot Jun 27, 2024
eb29e7d
Revert "Merge branch 'main' into run-command-with-secrets"
tangowithfoxtrot Jun 27, 2024
2da9ca9
unit tests for helper functions
tangowithfoxtrot Jun 27, 2024
deebd5d
Merge branch 'main' into run-command-with-secrets
tangowithfoxtrot Jun 27, 2024
2c5a279
import ClientSecretsExt
tangowithfoxtrot Jun 27, 2024
a836b65
use `std::io::IsTerminal` instead of `atty` crate
tangowithfoxtrot Jul 1, 2024
17a4d28
supress unused import warning in unit tests
tangowithfoxtrot Jul 1, 2024
14a9e50
fix: rm unneeded `which` as build dep
tangowithfoxtrot Jul 1, 2024
c93bf8f
fix: follow var name convention
tangowithfoxtrot Jul 1, 2024
5be08ed
fix: use documentation comments
tangowithfoxtrot Jul 1, 2024
e06e48f
Merge branch 'main' into run-command-with-secrets
tangowithfoxtrot Jul 1, 2024
3df1c6d
fix: formatting
tangowithfoxtrot Jul 2, 2024
68973d0
chore: upgrade which
tangowithfoxtrot Jul 2, 2024
83eb725
Merge branch 'main' into run-command-with-secrets
tangowithfoxtrot Jul 5, 2024
61b41fc
Merge branch 'main' into run-command-with-secrets
tangowithfoxtrot Jul 9, 2024
9f6a165
fix: rm redundant check for empty command
tangowithfoxtrot Jul 9, 2024
3080dac
feat: bail instead of exiting
tangowithfoxtrot Jul 9, 2024
23ab8f4
fix: provide default path for windows in edge-case where path isn't set
tangowithfoxtrot Jul 9, 2024
3fcd32c
fix: exit early if duplicates are detected
tangowithfoxtrot Jul 9, 2024
c7aad3f
chore: update lock file
tangowithfoxtrot Jul 9, 2024
eda00aa
fix: clippy; use `if let` instead of `match` for single pattern
tangowithfoxtrot Jul 10, 2024
9839b94
Merge branch 'main' into run-command-with-secrets
tangowithfoxtrot Jul 10, 2024
7362764
chore: formatting
tangowithfoxtrot Jul 11, 2024
f9629b8
fix: return error instead of exiting in run.rs
tangowithfoxtrot Jul 11, 2024
15b1114
Merge branch 'main' into run-command-with-secrets
tangowithfoxtrot Jul 11, 2024
4d4922f
Merge branch 'main' into run-command-with-secrets
tangowithfoxtrot Jul 15, 2024
1c6ffbc
Merge branch 'main' into run-command-with-secrets
tangowithfoxtrot Jul 16, 2024
75e3d8b
Update crates/bws/src/command/run.rs
tangowithfoxtrot Jul 16, 2024
e86aa2e
Update crates/bws/src/main.rs
tangowithfoxtrot Jul 16, 2024
b86d026
Update crates/bws/src/command/run.rs
tangowithfoxtrot Jul 16, 2024
f4c2598
Merge branch 'run-command-with-secrets' of https://github.com/bitward…
tangowithfoxtrot Jul 16, 2024
f9456b8
fix: add itertools dep to cargo
tangowithfoxtrot Jul 16, 2024
e31c689
chore: rm unused import
tangowithfoxtrot Jul 16, 2024
4a5aeb3
chore: update cargo lock file
tangowithfoxtrot Jul 16, 2024
5bdf99c
we don't need to handle invalid posix regex
tangowithfoxtrot Jul 16, 2024
f9c9946
refactor: remove unused enum
tangowithfoxtrot Jul 16, 2024
a75f53e
chore: `cargo fmt`
tangowithfoxtrot Jul 16, 2024
4770dbf
Merge branch 'main' into run-command-with-secrets
tangowithfoxtrot Jul 16, 2024
87fc76d
fix: Windows PowerShell crash when `--no-inherit-env` is passed
tangowithfoxtrot Aug 8, 2024
bc1a6ff
Merge branch 'main' into run-command-with-secrets
tangowithfoxtrot Aug 8, 2024
a0f78a3
Merge branch 'main' into run-command-with-secrets
tangowithfoxtrot Aug 15, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 37 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions crates/bws/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ repository.workspace = true
license-file.workspace = true

[dependencies]
atty = "0.2.14"
Hinton marked this conversation as resolved.
Show resolved Hide resolved
bat = { version = "0.24.0", features = [
"regex-onig",
], default-features = false }
Expand Down Expand Up @@ -43,6 +44,7 @@ thiserror = "1.0.57"
tokio = { version = "1.36.0", features = ["rt-multi-thread", "macros"] }
toml = "0.8.10"
uuid = { version = "1.7.0", features = ["serde"] }
which = "6.0.0"
Hinton marked this conversation as resolved.
Show resolved Hide resolved

[build-dependencies]
bitwarden-cli = { workspace = true }
Expand All @@ -51,6 +53,8 @@ clap_complete = "4.5.2"
clap_mangen = "0.2.20"
uuid = { version = "1.7.0" }

which = "6.0.0"
Hinton marked this conversation as resolved.
Show resolved Hide resolved

[dev-dependencies]
tempfile = "3.10.0"

Expand Down
23 changes: 23 additions & 0 deletions crates/bws/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,20 @@
#[command(subcommand)]
cmd: SecretCommand,
},
#[command(long_about = "Run a command with secrets injected")]
Run {
#[arg(help = "The command to run")]
command: Vec<String>,

Check warning on line 95 in crates/bws/src/cli.rs

View check run for this annotation

Codecov / codecov/patch

crates/bws/src/cli.rs#L95

Added line #L95 was not covered by tests
#[arg(long, help = "The shell to use")]
shell: Option<String>,
#[arg(
long,
help = "Don't inherit environment variables from the current shell"
)]
no_inherit_env: bool,

Check warning on line 102 in crates/bws/src/cli.rs

View check run for this annotation

Codecov / codecov/patch

crates/bws/src/cli.rs#L102

Added line #L102 was not covered by tests
#[arg(long, help = "The ID of the project to use")]
project_id: Option<Uuid>,
},
#[command(long_about = "Create a single item (deprecated)", hide(true))]
Create {
#[command(subcommand)]
Expand Down Expand Up @@ -226,3 +240,12 @@
Project { project_ids: Vec<Uuid> },
Secret { secret_ids: Vec<Uuid> },
}

#[derive(Subcommand, Debug)]
pub(crate) enum RunCommand {
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think we use this. Should we ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch. I think I missed this when refectoring the command at some point. Removed in f9c9946.

Command {
command: Vec<String>,

Check warning on line 247 in crates/bws/src/cli.rs

View check run for this annotation

Codecov / codecov/patch

crates/bws/src/cli.rs#L247

Added line #L247 was not covered by tests
project_id: Option<Uuid>,
shell: Option<String>,
},
}
103 changes: 102 additions & 1 deletion crates/bws/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::{path::PathBuf, process, str::FromStr};
use std::{io::Read, path::PathBuf, process, str::FromStr};

use atty::Stream;
use bitwarden::{
auth::{login::AccessTokenLoginRequest, AccessToken},
client::client_settings::ClientSettings,
Expand All @@ -25,6 +26,10 @@
mod config;
mod render;
mod state;
mod util;

use util::is_valid_posix_name;
use which::which;

use crate::{cli::*, render::serialize_response};

Expand Down Expand Up @@ -404,6 +409,102 @@
}
}

Commands::Run {
command,
shell,
no_inherit_env,
project_id,

Check warning on line 416 in crates/bws/src/main.rs

View check run for this annotation

Codecov / codecov/patch

crates/bws/src/main.rs#L413-L416

Added lines #L413 - L416 were not covered by tests
} => {
let shell = match std::env::consts::OS {
Copy link
Member

Choose a reason for hiding this comment

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

The process_command function is getting quite big already, do you mind splitting this to a separate function?

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. I can probably move this stuff out of here in a similar fashion to how it's being handled in #809.

"windows" => shell.unwrap_or_else(|| "powershell".to_string()),
_ => shell.unwrap_or_else(|| "sh".to_string()),

Check warning on line 420 in crates/bws/src/main.rs

View check run for this annotation

Codecov / codecov/patch

crates/bws/src/main.rs#L418-L420

Added lines #L418 - L420 were not covered by tests
};

if which(&shell).is_err() {
eprintln!("Error: shell '{}' not found", shell);
std::process::exit(1);
}

Check warning on line 426 in crates/bws/src/main.rs

View check run for this annotation

Codecov / codecov/patch

crates/bws/src/main.rs#L423-L426

Added lines #L423 - L426 were not covered by tests

let user_command = if command.is_empty() {
if atty::is(Stream::Stdin) {
dani-garcia marked this conversation as resolved.
Show resolved Hide resolved
eprintln!("{}", Cli::command().render_help().ansi());
std::process::exit(1);
}

let mut buffer = String::new();
std::io::stdin().read_to_string(&mut buffer)?;
buffer

Check warning on line 436 in crates/bws/src/main.rs

View check run for this annotation

Codecov / codecov/patch

crates/bws/src/main.rs#L428-L436

Added lines #L428 - L436 were not covered by tests
} else {
command.join(" ")

Check warning on line 438 in crates/bws/src/main.rs

View check run for this annotation

Codecov / codecov/patch

crates/bws/src/main.rs#L438

Added line #L438 was not covered by tests
};

if user_command.is_empty() {
let mut cmd = Cli::command();
eprintln!("{}", cmd.render_help().ansi());
std::process::exit(1);
}

Check warning on line 445 in crates/bws/src/main.rs

View check run for this annotation

Codecov / codecov/patch

crates/bws/src/main.rs#L441-L445

Added lines #L441 - L445 were not covered by tests

let res = if let Some(project_id) = project_id {
client
.secrets()
.list_by_project(&SecretIdentifiersByProjectRequest { project_id })
.await?

Check warning on line 451 in crates/bws/src/main.rs

View check run for this annotation

Codecov / codecov/patch

crates/bws/src/main.rs#L447-L451

Added lines #L447 - L451 were not covered by tests
} else {
client
.secrets()
.list(&SecretIdentifiersRequest { organization_id })
.await?

Check warning on line 456 in crates/bws/src/main.rs

View check run for this annotation

Codecov / codecov/patch

crates/bws/src/main.rs#L453-L456

Added lines #L453 - L456 were not covered by tests
};

let secret_ids = res.data.into_iter().map(|e| e.id).collect();
let secrets = client
.secrets()
.get_by_ids(SecretsGetRequest { ids: secret_ids })
.await?

Check warning on line 463 in crates/bws/src/main.rs

View check run for this annotation

Codecov / codecov/patch

crates/bws/src/main.rs#L459-L463

Added lines #L459 - L463 were not covered by tests
.data;

let environment = secrets
.into_iter()
.map(|s| (s.key, s.value))
.collect::<std::collections::HashMap<String, String>>();

Check warning on line 469 in crates/bws/src/main.rs

View check run for this annotation

Codecov / codecov/patch

crates/bws/src/main.rs#L466-L469

Added lines #L466 - L469 were not covered by tests

for key in environment.keys() {
if !is_valid_posix_name(key) {
Copy link
Contributor

Choose a reason for hiding this comment

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

will shell start with invalid environment variables ? don't we need to filter those out ?

Copy link
Contributor Author

@tangowithfoxtrot tangowithfoxtrot Jun 3, 2024

Choose a reason for hiding this comment

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

Great questions!

  1. Will this work with quoted args and multiline ?
bws run docker run --platform "linux/amd64" --rm --name "ubuntu-1" ubuntu echo 'hello'

bws run if [ "$ENV1" = "1234" ]; then
echo "hello";
fi

In the first case, I'd use an "end of arguments" (--) operator to construct a command like that to ensure that the shell is passing all of the arguments to our command: bws run -- docker run --platform "linux/amd64" --rm --name "ubuntu-1" ubuntu echo 'hello'.

In the case of the multi-line if statement, I'm not sure if there's a way for bws to handle that, as the first new-line passed to the shell would immediately attempt to execute bws run if [ "$ENV1" = "1234" ]; then on its own. I'm unsure if anything other than a shell builtin could trigger the interactive multiline input.

I wouldn't generally use the run command to execute more intircate ad-hoc shell commands like that (I'd put something like that in a script), but if you wanted to, you could wrap it in single-quotes to avoid having the shell executing or interpolating anything before it's passed to our command. Something like the following would work:

bws run -- 'if [ "$ENV1" = "1234" ]; then
echo "hello";
fi'
  1. Is creating the environment variables secrets with key good idea, since it is not guaranteed to be unique within one and across multiple projects and does not follow posix env format ?

I would prefer keeping the default behavior to use the key names, as it greatly improves usability and is in-line with CLIs that have similar functionality. Making UUIDs the default would require more effort for users to use the run command to replace things like local env files, where the environment variables wouldn't have a Bitwarden-generated secret UUID to reference.

Maybe it should be uuid by default (with replaced - characters to underscores _) with cli option like --use-secret-key to additionally expand to env variable by key (to be more user friendly, maybe even prefixed by project name or id ?)

What would you think of a BWS_USE_UNIQUE_NAMES=1 environment variable that could be set that would ensure that all secrets that are set get the secret UUID (in snake_case) appended to them? So, if you're running a script where you have secrets with identical names, you can ensure uniqueness. We could possibly add an equivalent argument (--use-unique-names?), but I feel like you would be much more likely to need that functionality on a per-script/session basis, rather than as a one-off. Either way, I think having something like that would help people that can't guarantee the uniqueness of their secret names.

Copy link
Contributor Author

@tangowithfoxtrot tangowithfoxtrot Jun 3, 2024

Choose a reason for hiding this comment

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

will shell start with invalid environment variables ? don't we need to filter those out ?

It will set the environment variables, even if they're not POSIX-compliant, yes. You'll get warnings printed to stderr stating that you have some non-POSIX-compliant key names, but they are technically set correctly by the run command. I figured that if someone were to executing a binary/script that had less restrictive naming conventions for environment variables, we could leave them set. For example:

bws run -- 'python -c "import os; print(os.getenv(\'1 non-compliant keyname\'))"'

would work, since getenv doesn't seem to require POSIX compliance. I imagine the same is possible for equivalent libs in other languages.

I'm open to un-setting them, but I'm not sure how people might feel about that if they're used to not being limited by POSIX-compliance.

Copy link
Contributor

Choose a reason for hiding this comment

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

--use-unique-name

I like this, being explicit in the cli options is better.
And like you mentioned, makes the solution more future proof, when users wants to do things by Id.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm open to un-setting them, but I'm not sure how people might feel about that if they're used to not being limited by POSIX-compliance.

I am fine either way, just want to avoid bws run not working because of some special characters in the secret key.

eprintln!(
"Warning: secret '{}' does not have a POSIX-compliant name",
key
);
}

Check warning on line 477 in crates/bws/src/main.rs

View check run for this annotation

Codecov / codecov/patch

crates/bws/src/main.rs#L471-L477

Added lines #L471 - L477 were not covered by tests
}

let mut command = process::Command::new(shell);
command
.arg("-c")
.arg(&user_command)
.stdout(process::Stdio::inherit())
.stderr(process::Stdio::inherit());

if no_inherit_env {
let path = std::env::var("PATH").unwrap_or_else(|_| "/bin:/usr/bin".to_string());
command.env_clear();
command.env("PATH", path); // PATH is always necessary
command.envs(&environment);
} else {
command.envs(&environment);
Copy link
Contributor

Choose a reason for hiding this comment

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

for additional security, do we want to remove "BWS_ACCESS_TOKEN" from inherited env variables ?

Copy link
Contributor Author

@tangowithfoxtrot tangowithfoxtrot Jun 3, 2024

Choose a reason for hiding this comment

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

I have also wondered this. I added the --no-inherit-env argument for a similar reason, but I suppose I could remove that variable by default as well.

Copy link
Contributor

Choose a reason for hiding this comment

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

@bwdil thoughts ?

Copy link

Choose a reason for hiding this comment

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

@mzieniukbw please unpack what you mean by 'for additional security' what is your concern? About having BWS_ACCESS_TOKEN inherited and how it gets subsequently used thereafter?

What are the security gains you're trying to achieve and what's the risk?

Copy link
Contributor

Choose a reason for hiding this comment

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

@bwdil My though is that whatever get's executed as part of bws run is probably something that needs to run one off and just need read access to some of the secrets.
With BWS_ACCESS_TOKEN we expose much more than intended:

  • Access to all secrets that the token have access to - bws run can specify a project, but with access token we have access to every single of them
  • With access token you can do write operations - which is really bad in case it get's to wrong hands.

Copy link

Choose a reason for hiding this comment

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

@mzieniukbw if BWS_ACCESS_TOKEN is not required for subsequent commands that get spawned then it can be cleared from env to limit exposure. I think your concern is something that bws run invokes (another process) getting hijacked and then stealing the access token.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sounds good. I'll remove the BWS_ACCESS_TOKEN var by default as well then. Thanks for calling this out.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

BWS_ACCESS_TOKEN is now unset by default.

}

Check warning on line 494 in crates/bws/src/main.rs

View check run for this annotation

Codecov / codecov/patch

crates/bws/src/main.rs#L480-L494

Added lines #L480 - L494 were not covered by tests

let mut child = command.spawn().expect("failed to execute process");

let exit_status = child.wait().expect("process failed to execute");
let exit_code = exit_status.code().unwrap_or(1);

let _ = child.wait();
Copy link
Member

Choose a reason for hiding this comment

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

I don't think this is needed, we're already calling child.wait() above, any other calls will just return immediately, I think


if exit_code != 0 {
process::exit(exit_code);
}

Check warning on line 505 in crates/bws/src/main.rs

View check run for this annotation

Codecov / codecov/patch

crates/bws/src/main.rs#L496-L505

Added lines #L496 - L505 were not covered by tests
}

Commands::Config { .. } | Commands::Completions { .. } => {
unreachable!()
}
Expand Down
6 changes: 2 additions & 4 deletions crates/bws/src/render.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::util::is_valid_posix_name;
use bitwarden::secrets_manager::{projects::ProjectResponse, secrets::SecretResponse};
use bitwarden_cli::Color;
use chrono::{DateTime, Utc};
Expand Down Expand Up @@ -27,15 +28,12 @@
pretty_print("yaml", &text, color);
}
Output::Env => {
let valid_key_regex =
regex::Regex::new("^[a-zA-Z_][a-zA-Z0-9_]*$").expect("regex is valid");

let mut commented_out = false;
let mut text: Vec<String> = data
.get_values()
.into_iter()
.map(|row| {
if valid_key_regex.is_match(&row[1]) {
if is_valid_posix_name(&row[1]) {

Check warning on line 36 in crates/bws/src/render.rs

View check run for this annotation

Codecov / codecov/patch

crates/bws/src/render.rs#L36

Added line #L36 was not covered by tests
format!("{}=\"{}\"", row[1], row[2])
} else {
commented_out = true;
Expand Down
10 changes: 10 additions & 0 deletions crates/bws/src/util.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use regex::Regex;

const VALID_POSIX_NAME_REGEX: &str = "^[a-zA-Z_][a-zA-Z0-9_]*$";

pub(crate) fn is_valid_posix_name(input_text: &str) -> bool {
match Regex::new(VALID_POSIX_NAME_REGEX) {
Ok(r) => r.is_match(input_text),
Err(_) => false,

Check warning on line 8 in crates/bws/src/util.rs

View check run for this annotation

Codecov / codecov/patch

crates/bws/src/util.rs#L5-L8

Added lines #L5 - L8 were not covered by tests
}
Hinton marked this conversation as resolved.
Show resolved Hide resolved
}

Check warning on line 10 in crates/bws/src/util.rs

View check run for this annotation

Codecov / codecov/patch

crates/bws/src/util.rs#L10

Added line #L10 was not covered by tests
Loading