Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
6 changes: 6 additions & 0 deletions cli/src/services/agent_trace_sync/control_plane.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,12 @@ impl ControlPlaneError {
Self::MissingCredentials | Self::AuthenticationFailed(_)
)
}

/// True when the failure came from loading or saving local authentication
/// credentials, rather than from the control-plane request itself.
pub fn is_storage_failure(&self) -> bool {
matches!(self, Self::Storage(_))
}
}

impl From<TokenStorageError> for ControlPlaneError {
Expand Down
11 changes: 11 additions & 0 deletions cli/src/services/agent_trace_sync/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,17 @@ impl StreamSyncError {
Self::Read(_) | Self::InvalidResponse(_) | Self::DidNotConverge => false,
}
}

/// True only when the underlying `ControlPlaneError` (from a `Refresh`
/// or `Terminal` failure) means local credential storage is unavailable.
/// `Read`, `InvalidResponse`, and `DidNotConverge` never carry a
/// `ControlPlaneError` and are never storage failures.
pub fn is_storage_failure(&self) -> bool {
match self {
Self::Refresh(error) | Self::Terminal(error) => error.is_storage_failure(),
Self::Read(_) | Self::InvalidResponse(_) | Self::DidNotConverge => false,
}
}
}

/// Outcome of a fully converged [`sync_stream`] run for one stream.
Expand Down
41 changes: 20 additions & 21 deletions cli/src/services/app_support.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,12 @@ fn write_error_diagnostic_with_color_policy<W: Write>(
}
CliError::User {
error: user_error, ..
} => user_error.message().to_string(),
} => {
let message = services::security::redact_sensitive_text(user_error.message());
writeln!(writer, "{message}")
.expect("writing user error diagnostic to writer should not fail");
return;
}
};
let styled_message = services::style::error_text_with_color_policy(
&services::security::redact_sensitive_text(&rendered),
Expand Down Expand Up @@ -263,11 +268,12 @@ mod tests {

let stderr_text = String::from_utf8(stderr).expect("stderr is valid utf8");
assert_eq!(
diagnostic_lines(&stderr_text).len(),
1,
"exactly one terminal diagnostic must be written"
stderr_text,
"You are not logged in. Please log in using the `sce auth login` command.\n"
);
assert!(stderr_text.contains("You are not logged in"));
assert!(!stderr_text.contains("Error"));
assert!(!stderr_text.contains("SCE-ERR-"));
assert!(!stderr_text.contains("Try:"));
assert!(!stderr_text.contains("missing credentials"));
assert!(!stderr_text.to_lowercase().contains("control-plane"));
}
Expand Down Expand Up @@ -333,23 +339,16 @@ mod tests {
}

#[test]
fn user_error_diagnostic_is_styled_only_when_color_is_enabled() {
fn user_error_diagnostic_is_plain_in_every_color_policy_mode() {
let error = CliError::user(UserError::NotAuthenticated);
let expected = "You are not logged in. Please log in using the `sce auth login` command.\n";

for color_enabled in [true, false] {
let mut stderr = Vec::new();
write_error_diagnostic_with_color_policy(&mut stderr, &error, color_enabled);
let rendered = String::from_utf8(stderr).expect("stderr is valid utf8");

let mut colored = Vec::new();
write_error_diagnostic_with_color_policy(&mut colored, &error, true);
let colored_text = String::from_utf8(colored).expect("stderr is valid utf8");

let mut plain = Vec::new();
write_error_diagnostic_with_color_policy(&mut plain, &error, false);
let plain_text = String::from_utf8(plain).expect("stderr is valid utf8");

// TTY-following (color_enabled: true) and redirected/NO_COLOR
// (color_enabled: false) diverge: only the enabled case carries ANSI.
assert_ne!(colored_text, plain_text);
assert!(!plain_text.contains('\u{1b}'));
assert!(colored_text.contains('\u{1b}'));
assert!(plain_text.contains("You are not logged in"));
assert!(colored_text.contains("You are not logged in"));
assert_eq!(rendered, expected);
}
}
}
2 changes: 1 addition & 1 deletion cli/src/services/auth_command/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ pub struct AuthCommand {

impl AuthCommand {
pub fn execute<C>(&self, _context: &C) -> Result<String, CliError> {
auth_command::run_auth_subcommand(self.request).map_err(CliError::runtime)
auth_command::run_auth_subcommand(self.request)
}
}
Loading