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
|
## Usage
|
||||||
|
|
||||||
```
|
```
|
||||||
dev_tools <project> <up|down>
|
dev_tools <project> <up|down> [-v|--verbose]
|
||||||
```
|
```
|
||||||
|
|
||||||
| Argument | Description |
|
| Argument | Description |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `project` | Project key (matches `<PROJECT>_DIR` in the config, case-insensitive) |
|
| `project` | Project key (matches `<PROJECT>_DIR` in the config, case-insensitive) |
|
||||||
| `up` / `down` | Start or stop the environment |
|
| `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
|
### Examples
|
||||||
|
|
||||||
@@ -51,6 +52,9 @@ dev_tools foo up
|
|||||||
|
|
||||||
# Stop it
|
# Stop it
|
||||||
dev_tools foo down
|
dev_tools foo down
|
||||||
|
|
||||||
|
# See exactly which lines were changed
|
||||||
|
dev_tools foo up -v
|
||||||
```
|
```
|
||||||
|
|
||||||
## What it does
|
## What it does
|
||||||
|
|||||||
@@ -13,6 +13,13 @@ pub struct Arguments {
|
|||||||
|
|
||||||
#[arg(help = "Possible values are 'up' and 'down'")]
|
#[arg(help = "Possible values are 'up' and 'down'")]
|
||||||
pub action: String,
|
pub action: String,
|
||||||
|
|
||||||
|
#[arg(
|
||||||
|
short,
|
||||||
|
long,
|
||||||
|
help = "Show which lines were changed (values may include secrets)"
|
||||||
|
)]
|
||||||
|
pub verbose: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Arguments {
|
impl Arguments {
|
||||||
@@ -33,6 +40,7 @@ mod tests {
|
|||||||
Arguments {
|
Arguments {
|
||||||
project: "test".to_string(),
|
project: "test".to_string(),
|
||||||
action: action.to_string(),
|
action: action.to_string(),
|
||||||
|
verbose: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+52
-1
@@ -13,10 +13,16 @@ pub struct FileChange {
|
|||||||
pub diffs: Vec<(String, String)>,
|
pub diffs: Vec<(String, String)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FileChange {
|
||||||
|
fn no_changes_message(&self) -> String {
|
||||||
|
format!("[!] {}: no changes", self.path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Display for FileChange {
|
impl fmt::Display for FileChange {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
if self.diffs.is_empty() {
|
if self.diffs.is_empty() {
|
||||||
return writeln!(f, "[!] {}: no changes", self.path);
|
return writeln!(f, "{}", self.no_changes_message());
|
||||||
}
|
}
|
||||||
writeln!(f, "[!] {} changed:", self.path)?;
|
writeln!(f, "[!] {} changed:", self.path)?;
|
||||||
for (before, after) in &self.diffs {
|
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
|
/// writes global connections
|
||||||
pub fn set_local_db(start: bool, config: &DevToolsConf) -> Result<FileChange> {
|
pub fn set_local_db(start: bool, config: &DevToolsConf) -> Result<FileChange> {
|
||||||
let global_connections_env = format!(
|
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]
|
#[test]
|
||||||
fn toggle_activate_removes_leading_hash() {
|
fn toggle_activate_removes_leading_hash() {
|
||||||
assert_eq!(toggle("#value=1", true), "value=1");
|
assert_eq!(toggle("#value=1", true), "value=1");
|
||||||
|
|||||||
+51
-3
@@ -4,7 +4,7 @@ use env::config::{load_config, DevToolsConf};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arguments::Arguments,
|
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},
|
git::command::{restore_connections_env, toggle_index},
|
||||||
};
|
};
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
@@ -15,6 +15,54 @@ mod container;
|
|||||||
mod env;
|
mod env;
|
||||||
mod git;
|
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<()> {
|
fn main() -> Result<()> {
|
||||||
let args: Arguments = Arguments::parse();
|
let args: Arguments = Arguments::parse();
|
||||||
args.validate()?;
|
args.validate()?;
|
||||||
@@ -24,14 +72,14 @@ fn main() -> Result<()> {
|
|||||||
start_docker_compose(&config.container_service, &config.container_dir, start)?;
|
start_docker_compose(&config.container_service, &config.container_dir, start)?;
|
||||||
|
|
||||||
if start {
|
if start {
|
||||||
print!("{}", set_local_db(start, &config)?);
|
print_file_change(&set_local_db(start, &config)?, args.verbose);
|
||||||
}
|
}
|
||||||
toggle_index(start, &config)?;
|
toggle_index(start, &config)?;
|
||||||
if !start {
|
if !start {
|
||||||
restore_connections_env(&config)?;
|
restore_connections_env(&config)?;
|
||||||
println!("[!] conf/global/connections.env restored to committed state.");
|
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!(
|
println!(
|
||||||
"[!] Don't forget your interpreter! Project directory: {}",
|
"[!] Don't forget your interpreter! Project directory: {}",
|
||||||
|
|||||||
Reference in New Issue
Block a user