Skip to content
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
Loading