feat(infra): temp IdeA launch-scoped alloué par lancement d'agent, injecté via TMPDIR/TMP/TEMP, writable_roots + release au stop, fail-closed — #200 (QA verte)
This commit is contained in:
@ -9,6 +9,7 @@ use domain::{
|
||||
};
|
||||
|
||||
use crate::error::AppError;
|
||||
use crate::managed_temp::{ReleaseManagedTemp, ReleaseManagedTempInput};
|
||||
|
||||
use super::registry::{LiveRuntimeState, LiveSessionKind, LiveSessions, TerminalSessions};
|
||||
|
||||
@ -202,13 +203,39 @@ pub struct CloseTerminalOutput {
|
||||
pub struct CloseTerminal {
|
||||
pty: Arc<dyn PtyPort>,
|
||||
sessions: Arc<TerminalSessions>,
|
||||
managed_temp_releaser: Option<Arc<ReleaseManagedTemp>>,
|
||||
}
|
||||
|
||||
impl CloseTerminal {
|
||||
/// Builds the use case.
|
||||
#[must_use]
|
||||
pub fn new(pty: Arc<dyn PtyPort>, sessions: Arc<TerminalSessions>) -> Self {
|
||||
Self { pty, sessions }
|
||||
Self {
|
||||
pty,
|
||||
sessions,
|
||||
managed_temp_releaser: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Injects the releaser for launch-scoped managed temp roots.
|
||||
#[must_use]
|
||||
pub fn with_managed_temp_releaser(mut self, releaser: Arc<ReleaseManagedTemp>) -> Self {
|
||||
self.managed_temp_releaser = Some(releaser);
|
||||
self
|
||||
}
|
||||
|
||||
/// Releases a launch-scoped managed temp handle retained by a live session.
|
||||
pub async fn release_managed_temp_handle(
|
||||
&self,
|
||||
handle: Option<String>,
|
||||
) -> Result<(), AppError> {
|
||||
let (Some(releaser), Some(handle)) = (&self.managed_temp_releaser, handle) else {
|
||||
return Ok(());
|
||||
};
|
||||
releaser
|
||||
.execute(ReleaseManagedTempInput { handle })
|
||||
.await
|
||||
.map(|_| ())
|
||||
}
|
||||
|
||||
/// Kills the session's PTY and removes it from the registry. Idempotent on
|
||||
@ -226,7 +253,12 @@ impl CloseTerminal {
|
||||
.handle(&input.session_id)
|
||||
.ok_or_else(|| AppError::NotFound(format!("terminal session {}", input.session_id)))?;
|
||||
let status = self.pty.kill(&handle).await?;
|
||||
self.sessions.remove(&input.session_id);
|
||||
let managed_temp_handle = self
|
||||
.sessions
|
||||
.remove_runtime(&input.session_id)
|
||||
.and_then(|removed| removed.managed_temp_handle);
|
||||
self.release_managed_temp_handle(managed_temp_handle)
|
||||
.await?;
|
||||
Ok(CloseTerminalOutput { code: status.code })
|
||||
}
|
||||
}
|
||||
@ -264,11 +296,15 @@ pub async fn stop_live_agent_runtime_in_project(
|
||||
live.mark_runtime_state(snapshot, LiveRuntimeState::Stopping);
|
||||
match snapshot.kind {
|
||||
LiveSessionKind::Structured => {
|
||||
if let Some(session) = live.structured.remove(&snapshot.session_id) {
|
||||
session
|
||||
if let Some(removed) = live.structured.remove_runtime(&snapshot.session_id) {
|
||||
removed
|
||||
.session
|
||||
.shutdown()
|
||||
.await
|
||||
.map_err(|e| AppError::Process(e.to_string()))?;
|
||||
close
|
||||
.release_managed_temp_handle(removed.managed_temp_handle)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
LiveSessionKind::Pty => {
|
||||
|
||||
Reference in New Issue
Block a user