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

Open
wants to merge 25 commits into
base: main
Choose a base branch
from

Conversation

tangowithfoxtrot
Copy link
Contributor

@tangowithfoxtrot tangowithfoxtrot commented Feb 21, 2024

Type of change

  • Bug fix
  • New feature development
  • Tech debt (refactoring, code cleanup, dependency upgrades, etc)
  • Build/deploy pipeline (DevOps)
  • Other

Objective

Add a run command to allow running processes with secrets injected.

Example:
bws run 'docker compose up -d', bws run -- docker compose up -d, or from stdin: echo 'docker compose up -d' | bws run

Where the compose file is expecting secrets:

version: "3.9"
services:
  echo:
    image: hashicorp/http-echo
    container_name: echo
    ports:
      - "127.0.0.1:5678:5678"
    command: [
        "-text",
        "Local DB user: $LOCAL_DB_USER\nLocal DB pass: $LOCAL_DB_PASS", # secrets from Secrets Manager
      ]

Any command can be run as well: bws run -- npm run start, bws run -- ./some_script.sh, etc.

A --shell option is provided to override the default shell (sh on UNIX-like OSes, and powershell on Windows) where the process is executed.

A --no-inherit-env option is provided for additional safety in cases where you want to pass the minimum amount of values into a process. $PATH is always passed though, as omitting it would cause nearly every command to fail.

Code changes

  • crates/bws/src/main.rs: Add the run command and associated args.

Before you submit

  • Please add unit tests where it makes sense to do so

@bitwarden-bot
Copy link

bitwarden-bot commented Feb 21, 2024

Logo
Checkmarx One – Scan Summary & Detailsf722b8ba-cad2-4b02-81cf-7b215dfc87da

No New Or Fixed Issues Found

Copy link

codecov bot commented Feb 21, 2024

Codecov Report

Attention: Patch coverage is 0% with 84 lines in your changes are missing coverage. Please review.

Project coverage is 61.30%. Comparing base (34b7213) to head (1ab92be).

Files Patch % Lines
crates/bws/src/main.rs 0.00% 84 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #621      +/-   ##
==========================================
- Coverage   61.77%   61.30%   -0.48%     
==========================================
  Files         172      172              
  Lines       10927    11011      +84     
==========================================
  Hits         6750     6750              
- Misses       4177     4261      +84     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@differsthecat differsthecat changed the title Run command with secrets [SM-1129] Run command with secrets Mar 6, 2024
crates/bws/src/main.rs Fixed Show fixed Hide fixed
crates/bws/src/main.rs Fixed Show fixed Hide fixed
@tangowithfoxtrot tangowithfoxtrot marked this pull request as ready for review April 29, 2024 19:04
@tangowithfoxtrot tangowithfoxtrot requested review from dani-garcia, Hinton and a team April 29, 2024 19:04
Copy link
Member

@dani-garcia dani-garcia left a comment

Choose a reason for hiding this comment

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

Nice, looks like a great start to me, left some comments with a few small improvements.

Comment on lines +637 to +643
let shell = match std::env::consts::OS {
os if os == "linux" || os == "macos" || os.contains("bsd") => {
shell.unwrap_or_else(|| "sh".to_string())
}
"windows" => shell.unwrap_or_else(|| "powershell".to_string()),
_ => unreachable!(),
};
Copy link
Member

Choose a reason for hiding this comment

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

Would it be better to invert this condition like this?

Suggested change
let shell = match std::env::consts::OS {
os if os == "linux" || os == "macos" || os.contains("bsd") => {
shell.unwrap_or_else(|| "sh".to_string())
}
"windows" => shell.unwrap_or_else(|| "powershell".to_string()),
_ => unreachable!(),
};
let shell = match std::env::consts::OS {
"windows" => shell.unwrap_or_else(|| "powershell".to_string()),
_ => shell.unwrap_or_else(|| "sh".to_string())
};

Any other platform that might fall under the unreachable line (maybe android?) probably has some kind of basic sh, so at least it would work.

@@ -222,6 +238,15 @@ enum DeleteCommand {
Secret { secret_ids: Vec<Uuid> },
}

#[derive(Subcommand, Debug)]
enum RunCommand {
Copy link
Member

Choose a reason for hiding this comment

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

This enum doesn't seem to be used anywhere, only the Run variant above is used, right?

no_inherit_env,
project_id,
} => {
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?

}

let user_command = if command.is_empty() {
if atty::is(Stream::Stdin) {
Copy link
Member

Choose a reason for hiding this comment

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

This makes me think that when using the run command without extra arguments they'll be read from stdin, but for me it just prints the help. I tried running it as:

  • bws run
  • bws run --
  • bws run -- ""
  • bws run ""

Is there anything I'm missing?

.collect::<std::collections::HashMap<String, String>>();

let valid_key_regex =
regex::Regex::new("^[a-zA-Z_][a-zA-Z0-9_]*$").expect("valid regex");
Copy link
Member

Choose a reason for hiding this comment

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

We have the same regex in the render.rs function, should we extract it to an is_valid_posix_name function somewhere?

Comment on lines +688 to +691
let environment = secrets
.iter()
.map(|s| (s.key.clone(), s.value.clone()))
.collect::<std::collections::HashMap<String, String>>();
Copy link
Member

Choose a reason for hiding this comment

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

If you use into_iter here, you can avoid the key and value clones

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

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants