Hide changed connection lines behind -v/--verbose
set_local_db/set_dot_env diffs can contain secrets (connection strings), so printing them unconditionally on every up/down leaked credentials to stdout. Default output is now a line-count summary; pass -v/--verbose to see the actual before/after lines.
This commit is contained in:
@@ -35,13 +35,14 @@ cargo install --path .
|
||||
## Usage
|
||||
|
||||
```
|
||||
dev_tools <project> <up|down>
|
||||
dev_tools <project> <up|down> [-v|--verbose]
|
||||
```
|
||||
|
||||
| Argument | Description |
|
||||
|---|---|
|
||||
| `project` | Project key (matches `<PROJECT>_DIR` in the config, case-insensitive) |
|
||||
| `up` / `down` | Start or stop the environment |
|
||||
| `-v`, `--verbose` | Print the actual before/after lines changed in the env files (values may include secrets, e.g. connection strings). Without it, only a line count is printed. |
|
||||
|
||||
### Examples
|
||||
|
||||
@@ -51,6 +52,9 @@ dev_tools foo up
|
||||
|
||||
# Stop it
|
||||
dev_tools foo down
|
||||
|
||||
# See exactly which lines were changed
|
||||
dev_tools foo up -v
|
||||
```
|
||||
|
||||
## What it does
|
||||
|
||||
@@ -13,6 +13,13 @@ pub struct Arguments {
|
||||
|
||||
#[arg(help = "Possible values are 'up' and 'down'")]
|
||||
pub action: String,
|
||||
|
||||
#[arg(
|
||||
short,
|
||||
long,
|
||||
help = "Show which lines were changed (values may include secrets)"
|
||||
)]
|
||||
pub verbose: bool,
|
||||
}
|
||||
|
||||
impl Arguments {
|
||||
@@ -33,6 +40,7 @@ mod tests {
|
||||
Arguments {
|
||||
project: "test".to_string(),
|
||||
action: action.to_string(),
|
||||
verbose: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+52
-1
@@ -13,10 +13,16 @@ pub struct FileChange {
|
||||
pub diffs: Vec<(String, String)>,
|
||||
}
|
||||
|
||||
impl FileChange {
|
||||
fn no_changes_message(&self) -> String {
|
||||
format!("[!] {}: no changes", self.path)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for FileChange {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
if self.diffs.is_empty() {
|
||||
return writeln!(f, "[!] {}: no changes", self.path);
|
||||
return writeln!(f, "{}", self.no_changes_message());
|
||||
}
|
||||
writeln!(f, "[!] {} changed:", self.path)?;
|
||||
for (before, after) in &self.diffs {
|
||||
@@ -26,6 +32,22 @@ impl fmt::Display for FileChange {
|
||||
}
|
||||
}
|
||||
|
||||
impl FileChange {
|
||||
/// Line-count-only summary that never prints line contents, since those
|
||||
/// can contain secrets (e.g. connection strings). Use `Display` (gated
|
||||
/// behind `-v`/`--verbose` in `main`) to show the actual before/after lines.
|
||||
pub fn summary(&self) -> String {
|
||||
if self.diffs.is_empty() {
|
||||
return format!("{}\n", self.no_changes_message());
|
||||
}
|
||||
format!(
|
||||
"[!] {} changed: {} line(s) (use -v to show)\n",
|
||||
self.path,
|
||||
self.diffs.len()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// writes global connections
|
||||
pub fn set_local_db(start: bool, config: &DevToolsConf) -> Result<FileChange> {
|
||||
let global_connections_env = format!(
|
||||
@@ -476,6 +498,35 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn file_change_summary_no_diffs() {
|
||||
let change = FileChange {
|
||||
path: "some/path".to_string(),
|
||||
diffs: vec![],
|
||||
};
|
||||
assert_eq!(change.summary(), "[!] some/path: no changes\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn file_change_summary_hides_values() {
|
||||
let change = FileChange {
|
||||
path: "some/path".to_string(),
|
||||
diffs: vec![
|
||||
(
|
||||
"connection='ci'".to_string(),
|
||||
"connection='staging'".to_string(),
|
||||
),
|
||||
("a=1".to_string(), "#a=1".to_string()),
|
||||
],
|
||||
};
|
||||
let summary = change.summary();
|
||||
assert_eq!(
|
||||
summary,
|
||||
"[!] some/path changed: 2 line(s) (use -v to show)\n"
|
||||
);
|
||||
assert!(!summary.contains("connection"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn toggle_activate_removes_leading_hash() {
|
||||
assert_eq!(toggle("#value=1", true), "value=1");
|
||||
|
||||
+51
-3
@@ -4,7 +4,7 @@ use env::config::{load_config, DevToolsConf};
|
||||
|
||||
use crate::{
|
||||
arguments::Arguments,
|
||||
config::parse::{set_dot_env, set_local_db},
|
||||
config::parse::{set_dot_env, set_local_db, FileChange},
|
||||
git::command::{restore_connections_env, toggle_index},
|
||||
};
|
||||
use clap::Parser;
|
||||
@@ -15,6 +15,54 @@ mod container;
|
||||
mod env;
|
||||
mod git;
|
||||
|
||||
/// Line-count summary by default, since a full diff can contain secrets
|
||||
/// (e.g. connection strings); `-v`/`--verbose` opts into the diff.
|
||||
fn file_change_output(change: &FileChange, verbose: bool) -> String {
|
||||
if verbose {
|
||||
change.to_string()
|
||||
} else {
|
||||
change.summary()
|
||||
}
|
||||
}
|
||||
|
||||
fn print_file_change(change: &FileChange, verbose: bool) {
|
||||
print!("{}", file_change_output(change, verbose));
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn change_with_diff() -> FileChange {
|
||||
FileChange {
|
||||
path: "some/path".to_string(),
|
||||
diffs: vec![(
|
||||
"connection='ci'".to_string(),
|
||||
"connection='staging'".to_string(),
|
||||
)],
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn file_change_output_hides_values_by_default() {
|
||||
let output = file_change_output(&change_with_diff(), false);
|
||||
assert_eq!(
|
||||
output,
|
||||
"[!] some/path changed: 1 line(s) (use -v to show)\n"
|
||||
);
|
||||
assert!(!output.contains("connection"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn file_change_output_shows_values_when_verbose() {
|
||||
let output = file_change_output(&change_with_diff(), true);
|
||||
assert_eq!(
|
||||
output,
|
||||
"[!] some/path changed:\n connection='ci' -> connection='staging'\n"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let args: Arguments = Arguments::parse();
|
||||
args.validate()?;
|
||||
@@ -24,14 +72,14 @@ fn main() -> Result<()> {
|
||||
start_docker_compose(&config.container_service, &config.container_dir, start)?;
|
||||
|
||||
if start {
|
||||
print!("{}", set_local_db(start, &config)?);
|
||||
print_file_change(&set_local_db(start, &config)?, args.verbose);
|
||||
}
|
||||
toggle_index(start, &config)?;
|
||||
if !start {
|
||||
restore_connections_env(&config)?;
|
||||
println!("[!] conf/global/connections.env restored to committed state.");
|
||||
}
|
||||
print!("{}", set_dot_env(start, &config)?);
|
||||
print_file_change(&set_dot_env(start, &config)?, args.verbose);
|
||||
|
||||
println!(
|
||||
"[!] Don't forget your interpreter! Project directory: {}",
|
||||
|
||||
Reference in New Issue
Block a user