From 47f13f7598c6d2cac8d7a14c2fa4b0e62e8b6874 Mon Sep 17 00:00:00 2001 From: Michel Paulissen <862400+MichelPaulissen@users.noreply.github.com> Date: Mon, 27 Jul 2026 05:15:55 +0200 Subject: [PATCH] Use stored sessions for logs and artifacts Source commit: 8faa1e3b54e5474bc31b53a3b308b6f8198b6310 --- crates/clusterflux-cli/src/artifact.rs | 10 +++++--- crates/clusterflux-cli/src/logs.rs | 4 +++- crates/clusterflux-cli/src/process.rs | 5 +++- crates/clusterflux-cli/src/tests.rs | 32 ++++++++++++++++++++++++-- 4 files changed, 44 insertions(+), 7 deletions(-) diff --git a/crates/clusterflux-cli/src/artifact.rs b/crates/clusterflux-cli/src/artifact.rs index a0440be..a2c0620 100644 --- a/crates/clusterflux-cli/src/artifact.rs +++ b/crates/clusterflux-cli/src/artifact.rs @@ -12,6 +12,7 @@ use crate::client::{ }; use crate::config::StoredCliSession; use crate::errors::cli_error_summary_for_category; +use crate::process::hydrate_process_scope; use crate::process_events::{ artifact_download_grant_disclosures, artifact_download_session_summary, artifact_export_plan_summary, artifact_response_machine_error, artifact_summaries, @@ -27,9 +28,10 @@ pub(crate) fn artifact_list_report(args: ArtifactListArgs) -> Result { } pub(crate) fn artifact_list_report_with_session( - args: ArtifactListArgs, + mut args: ArtifactListArgs, stored_session: Option<&StoredCliSession>, ) -> Result { + hydrate_process_scope(&mut args.scope, stored_session); let events = list_task_events_if_available_with_session( args.scope.coordinator.as_deref(), &args.scope, @@ -53,9 +55,10 @@ pub(crate) fn artifact_download_report(args: ArtifactDownloadArgs) -> Result, ) -> Result { + hydrate_process_scope(&mut args.scope, stored_session); if let Some(coordinator) = &args.scope.coordinator { let mut session = JsonLineSession::connect(coordinator)?; let response = session.request(authenticated_or_local_trusted_request( @@ -143,9 +146,10 @@ pub(crate) fn artifact_export_report(args: ArtifactExportArgs) -> Result } pub(crate) fn artifact_export_report_with_session( - args: ArtifactExportArgs, + mut args: ArtifactExportArgs, stored_session: Option<&StoredCliSession>, ) -> Result { + hydrate_process_scope(&mut args.scope, stored_session); if let Some(coordinator) = &args.scope.coordinator { let mut session = JsonLineSession::connect(coordinator)?; let response = session.request(authenticated_or_local_trusted_request( diff --git a/crates/clusterflux-cli/src/logs.rs b/crates/clusterflux-cli/src/logs.rs index a12815a..dcad5f7 100644 --- a/crates/clusterflux-cli/src/logs.rs +++ b/crates/clusterflux-cli/src/logs.rs @@ -3,6 +3,7 @@ use serde_json::{json, Value}; use crate::client::list_task_events_if_available_with_session; use crate::config::StoredCliSession; +use crate::process::hydrate_process_scope; use crate::process_events::log_entries; use crate::LogsArgs; @@ -12,9 +13,10 @@ pub(crate) fn logs_report(args: LogsArgs) -> Result { } pub(crate) fn logs_report_with_session( - args: LogsArgs, + mut args: LogsArgs, stored_session: Option<&StoredCliSession>, ) -> Result { + hydrate_process_scope(&mut args.scope, stored_session); let events = list_task_events_if_available_with_session( args.scope.coordinator.as_deref(), &args.scope, diff --git a/crates/clusterflux-cli/src/process.rs b/crates/clusterflux-cli/src/process.rs index e7696b4..5e6adde 100644 --- a/crates/clusterflux-cli/src/process.rs +++ b/crates/clusterflux-cli/src/process.rs @@ -15,7 +15,10 @@ use crate::{ ProcessListArgs, ProcessRestartArgs, ProcessStatusArgs, }; -fn hydrate_process_scope(scope: &mut CliScopeArgs, stored_session: Option<&StoredCliSession>) { +pub(crate) fn hydrate_process_scope( + scope: &mut CliScopeArgs, + stored_session: Option<&StoredCliSession>, +) { if scope.coordinator.is_none() { scope.coordinator = stored_session .filter(|session| session.session_secret.is_some()) diff --git a/crates/clusterflux-cli/src/tests.rs b/crates/clusterflux-cli/src/tests.rs index 7afd3be..57b4afe 100644 --- a/crates/clusterflux-cli/src/tests.rs +++ b/crates/clusterflux-cli/src/tests.rs @@ -3004,6 +3004,14 @@ fn user_control_commands_use_authenticated_envelope_with_stored_cli_session() { "restart_task", br#"{"type":"task_restart","process":"vp","task":"task-a","actor":"user-session","accepted":false,"clean_boundary_available":false,"active_task":false,"completed_event_observed":false,"requires_whole_process_restart":true,"message":"restart requires checkpoint","charged_debug_read_bytes":1024,"used_debug_read_bytes":1024,"audit_event":{"tenant":"tenant-session","project":"project-session","process":"vp","task":"task-a","actor":"user-session","operation":"restart_task","allowed":true,"reason":"restart requires checkpoint","charged_debug_read_bytes":1024,"used_debug_read_bytes":1024}}"#.as_slice(), ), + ( + "list_task_events", + br#"{"type":"task_events","events":[{"process":"vp","task":"task-a","terminal_state":"completed","stdout_tail":"compiled\n","stderr_tail":""}]}"#.as_slice(), + ), + ( + "list_task_events", + br#"{"type":"task_events","events":[{"process":"vp","task":"task-a","terminal_state":"completed","artifact_path":"/vfs/artifacts/app.txt","artifact_digest":"sha256:app","artifact_size_bytes":3}]}"#.as_slice(), + ), ( "create_artifact_download_link", br#"{"type":"artifact_download_link","link":{"artifact":"app.txt","source":{"RetainedNode":"node-a"},"url_path":"/artifacts/tenant-session/project-session/vp/app.txt","scoped_token_digest":"sha256:token","expires_at_epoch_seconds":60,"tenant":"tenant-session","project":"project-session","process":"vp","actor":{"User":"user-session"},"max_bytes":2048,"policy_context_digest":"sha256:policy"}}"#.as_slice(), @@ -3108,9 +3116,26 @@ fn user_control_commands_use_authenticated_envelope_with_stored_cli_session() { Some(&session), ) .unwrap(); - artifact_download_report_with_session( + let logs = logs_report_with_session( + LogsArgs { + scope: scope.clone(), + process: Some("vp".to_owned()), + task: Some("task-a".to_owned()), + }, + Some(&session), + ) + .unwrap(); + let artifacts = artifact_list_report_with_session( + ArtifactListArgs { + scope: scope.clone(), + process: Some("vp".to_owned()), + }, + Some(&session), + ) + .unwrap(); + let download = artifact_download_report_with_session( ArtifactDownloadArgs { - scope: coordinator_scope.clone(), + scope, artifact: "app.txt".to_owned(), to: None, max_bytes: 2048, @@ -3118,6 +3143,9 @@ fn user_control_commands_use_authenticated_envelope_with_stored_cli_session() { Some(&session), ) .unwrap(); + assert_eq!(logs["log_entries"][0]["stdout_tail"], "compiled\n"); + assert_eq!(artifacts["artifacts"][0]["artifact"], "app.txt"); + assert_eq!(download["coordinator"], session.coordinator); debug_attach_report_with_dap_and_session( DebugAttachArgs { scope: coordinator_scope,