use std::process::Command; use anyhow::{Context, Result}; use serde_json::{json, Value}; use crate::client::{ authenticated_or_local_trusted_request, stored_session_for_coordinator, JsonLineSession, }; use crate::config::StoredCliSession; use crate::tools::dap_binary_path; use crate::{DapArgs, DebugAttachArgs}; pub(crate) fn dap_plan(args: DapArgs) -> Result { Ok(json!({ "command": "dap", "adapter": dap_binary_path()?.display().to_string(), "args": args.args, "private_website_required": false, })) } pub(crate) fn exec_dap(args: DapArgs) -> Result<()> { let status = Command::new(dap_binary_path()?) .args(args.args) .status() .context("failed to launch clusterflux-debug-dap")?; if !status.success() { anyhow::bail!("clusterflux-debug-dap exited with {status}"); } Ok(()) } #[cfg(test)] pub(crate) fn debug_attach_report_with_dap(args: DebugAttachArgs, dap: String) -> Result { debug_attach_report_with_dap_and_session(args, dap, None) } pub(crate) fn debug_attach_report_with_dap_and_session( mut args: DebugAttachArgs, dap: String, stored_session: Option<&StoredCliSession>, ) -> Result { if args.scope.coordinator.is_none() { args.scope.coordinator = stored_session .filter(|session| session.session_secret.is_some()) .map(|session| session.coordinator.clone()); } if let Some(bound_session) = args .scope .coordinator .as_deref() .and_then(|coordinator| stored_session_for_coordinator(coordinator, stored_session)) { args.scope.tenant = bound_session.tenant.clone(); args.scope.project = bound_session.project.clone(); args.scope.user = bound_session.user.clone(); } if let Some(coordinator) = &args.scope.coordinator { let tenant = args.scope.tenant.clone(); let project = args.scope.project.clone(); let user = args.scope.user.clone(); let process = args.process.clone(); let mut session = JsonLineSession::connect(coordinator)?; let response = session.request(authenticated_or_local_trusted_request( coordinator, stored_session, json!({ "type": "debug_attach", "process": process, }), json!({ "type": "debug_attach", "tenant": tenant, "project": project, "actor_user": user, "process": process, }), )?)?; let authorization = response.get("authorization").cloned().unwrap_or_else( || json!({"allowed": false, "reason": "missing authorization response"}), ); return Ok(json!({ "command": "debug attach", "process": process, "coordinator": coordinator, "tenant": tenant, "project": project, "user": user, "dap": dap, "authorized": authorization .get("allowed") .cloned() .unwrap_or(json!(false)), "authorization": authorization, "audit_event": response.get("audit_event").cloned().unwrap_or(Value::Null), "charged_debug_read_bytes": response .get("charged_debug_read_bytes") .cloned() .unwrap_or_else(|| json!(0)), "used_debug_read_bytes": response .get("used_debug_read_bytes") .cloned() .unwrap_or_else(|| json!(0)), "debug_reads_quota_limited": true, "private_website_required": false, "coordinator_session_requests": session.requests(), })); } Ok(json!({ "command": "debug attach", "process": args.process, "coordinator": args.scope.coordinator, "tenant": args.scope.tenant, "project": args.scope.project, "dap": dap, "authorized": "unknown_without_coordinator", "debug_reads_quota_limited": "unknown_without_coordinator", "private_website_required": false, })) }