Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ exclude = [
[dependencies]
clap = { version = "4.5", features = ["derive", "env"] }
clap_complete = "4.5"
tokio = { version = "1.49", features = ["rt-multi-thread", "macros", "process", "fs", "io-util", "signal"] }
tokio = { version = "1.49", features = ["rt-multi-thread", "macros", "process", "fs", "io-util", "signal", "time"] }
thiserror = "2.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
Expand Down
2 changes: 1 addition & 1 deletion images/base/mino-bootstrap
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ mkdir -p "$STEP_DIR" 2>/dev/null || true
if [ -n "$MINO_QUIET_BOOTSTRAP" ]; then
INSTALL_REDIRECT="/dev/null"
else
INSTALL_REDIRECT="/dev/stderr"
INSTALL_REDIRECT="/tmp/mino-bootstrap.log"
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Security: Predictable log file path in /tmp (Security - 85% confidence)

The bootstrap output is redirected to /tmp/mino-bootstrap.log, which is a predictable path. Inside a rootless container the risk is limited, but the path is not collision-proof. If multiple containers somehow shared /tmp (unlikely with Podman but possible with custom mounts), one container's bootstrap output could be read or overwritten.

Install output may contain URLs, version info, or error messages with sensitive path details.

Suggested fix: Use mktemp for a unique filename or write to the user's home directory:

# Option 1: Use mktemp
INSTALL_REDIRECT="$(mktemp /tmp/mino-bootstrap-XXXXXX.log)"

# Option 2: Use home directory (safer)
INSTALL_REDIRECT="$HOME/.mino-bootstrap.log"

fi

# Log to stderr unless quiet mode is enabled
Expand Down
46 changes: 37 additions & 9 deletions src/cli/commands/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use crate::home::HomeVolume;
use crate::orchestration::{create_runtime, ContainerRuntime};
use crate::ui::{self, UiContext};
use chrono::Utc;
use console::style;
use console::{pad_str, Alignment, style};
use std::env;
use std::path::PathBuf;
use tracing::debug;
Expand Down Expand Up @@ -100,15 +100,25 @@ async fn list_caches(
}

fn print_cache_table(caches: &[(CacheVolume, u64)], total_size: u64, limit_bytes: u64) {
const W_VOLUME: usize = 40;
const W_ECO: usize = 10;
const W_STATE: usize = 10;
const W_SIZE: usize = 10;
const W_CREATED: usize = 16;

let ctx = UiContext::detect();

ui::intro(&ctx, "Cache Volumes");

println!(
"{:<40} {:<10} {:<10} {:<10} {:<16}",
"VOLUME", "ECOSYSTEM", "STATE", "SIZE", "CREATED"
"{} {} {} {} {}",
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Table styling inconsistency (Consistency - 90% confidence)

The headers in this file ("VOLUME", "ECOSYSTEM", etc.) are plain strings, but list.rs wraps headers in style(...).bold() before calling pad_str. Both files were modified in this PR to adopt pad_str, but the styling convention diverged instead of being unified.

Since bold headers (as in list.rs) provide better visual hierarchy, apply bold styling consistently across both files:

pad_str(&style("VOLUME").bold().to_string(), W_VOLUME, Alignment::Left, None),
pad_str(&style("ECOSYSTEM").bold().to_string(), W_ECO, Alignment::Left, None),
// ... etc for all headers in both functions

pad_str("VOLUME", W_VOLUME, Alignment::Left, None),
pad_str("ECOSYSTEM", W_ECO, Alignment::Left, None),
pad_str("STATE", W_STATE, Alignment::Left, None),
pad_str("SIZE", W_SIZE, Alignment::Left, None),
pad_str("CREATED", W_CREATED, Alignment::Left, None),
);
println!("{}", "-".repeat(90));
println!("{}", "-".repeat(W_VOLUME + 1 + W_ECO + 1 + W_STATE + 1 + W_SIZE + 1 + W_CREATED));

for (cache, size) in caches {
let state_display = match cache.state {
Expand All @@ -126,8 +136,12 @@ fn print_cache_table(caches: &[(CacheVolume, u64)], total_size: u64, limit_bytes
let created = cache.created_at.format("%Y-%m-%d %H:%M").to_string();

println!(
"{:<40} {:<10} {:<10} {:<10} {:<16}",
cache.name, cache.ecosystem, state_display, size_display, created
"{} {} {} {} {}",
pad_str(&cache.name, W_VOLUME, Alignment::Left, None),
pad_str(&cache.ecosystem.to_string(), W_ECO, Alignment::Left, None),
pad_str(&state_display, W_STATE, Alignment::Left, None),
pad_str(&size_display, W_SIZE, Alignment::Left, None),
pad_str(&created, W_CREATED, Alignment::Left, None),
);
}

Expand Down Expand Up @@ -162,16 +176,30 @@ fn print_cache_table(caches: &[(CacheVolume, u64)], total_size: u64, limit_bytes
}

fn print_home_table(home_vols: &[HomeVolume]) {
const W_VOLUME: usize = 40;
const W_PROJECT: usize = 40;
const W_CREATED: usize = 16;

let ctx = UiContext::detect();

ui::intro(&ctx, "Home Volumes");

println!("{:<40} {:<40} {:<16}", "VOLUME", "PROJECT", "CREATED");
println!("{}", "-".repeat(96));
println!(
"{} {} {}",
pad_str("VOLUME", W_VOLUME, Alignment::Left, None),
pad_str("PROJECT", W_PROJECT, Alignment::Left, None),
pad_str("CREATED", W_CREATED, Alignment::Left, None),
);
println!("{}", "-".repeat(W_VOLUME + 1 + W_PROJECT + 1 + W_CREATED));

for hv in home_vols {
let created = hv.created_at.format("%Y-%m-%d %H:%M").to_string();
println!("{:<40} {:<40} {:<16}", hv.name, hv.project_path, created);
println!(
"{} {} {}",
pad_str(&hv.name, W_VOLUME, Alignment::Left, None),
pad_str(&hv.project_path, W_PROJECT, Alignment::Left, Some("...")),
pad_str(&created, W_CREATED, Alignment::Left, None),
);
}

println!();
Expand Down
34 changes: 21 additions & 13 deletions src/cli/commands/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::config::Config;
use crate::error::MinoResult;
use crate::session::{Session, SessionManager, SessionStatus};
use crate::ui::{self, UiContext};
use console::style;
use console::{pad_str, Alignment, style};

/// Execute the list command
pub async fn execute(args: ListArgs, _config: &Config) -> MinoResult<()> {
Expand Down Expand Up @@ -64,24 +64,29 @@ fn format_plain(sessions: &[Session]) -> String {
}

fn print_table(sessions: &[Session]) {
const W_NAME: usize = 20;
const W_STATUS: usize = 12;
const W_STARTED: usize = 15;
const W_PROJECT: usize = 30;

let ctx = UiContext::detect();
ui::intro(&ctx, "Sessions");

println!(
"{:<20} {:<12} {:<15} {:<30}",
style("NAME").bold(),
style("STATUS").bold(),
style("STARTED").bold(),
style("PROJECT").bold()
"{} {} {} {}",
pad_str(&style("NAME").bold().to_string(), W_NAME, Alignment::Left, None),
pad_str(&style("STATUS").bold().to_string(), W_STATUS, Alignment::Left, None),
pad_str(&style("STARTED").bold().to_string(), W_STARTED, Alignment::Left, None),
pad_str(&style("PROJECT").bold().to_string(), W_PROJECT, Alignment::Left, None),
);
println!("{}", "-".repeat(77));
println!("{}", "-".repeat(W_NAME + 1 + W_STATUS + 1 + W_STARTED + 1 + W_PROJECT));

for session in sessions {
let status_styled = match session.status {
SessionStatus::Running => style("running").green(),
SessionStatus::Starting => style("starting").yellow(),
SessionStatus::Stopped => style("stopped").dim(),
SessionStatus::Failed => style("failed").red(),
SessionStatus::Running => style("running").green().to_string(),
SessionStatus::Starting => style("starting").yellow().to_string(),
SessionStatus::Stopped => style("stopped").dim().to_string(),
SessionStatus::Failed => style("failed").red().to_string(),
};

let started = session.created_at.format("%Y-%m-%d %H:%M").to_string();
Expand All @@ -92,8 +97,11 @@ fn print_table(sessions: &[Session]) {
.unwrap_or("unknown");

println!(
"{:<20} {:<12} {:<15} {:<30}",
session.name, status_styled, started, project
"{} {} {} {}",
pad_str(&session.name, W_NAME, Alignment::Left, None),
pad_str(&status_styled, W_STATUS, Alignment::Left, None),
pad_str(&started, W_STARTED, Alignment::Left, None),
pad_str(project, W_PROJECT, Alignment::Left, None),
);
}

Expand Down
Loading
Loading