Address remaining review items: L4/M1 + L2/L5 cleanup
Build App / compute-version (pull_request) Successful in 3s
Build Container / build-container (pull_request) Successful in 57s
Build App / build-macos (pull_request) Successful in 2m15s
Build App / build-windows (pull_request) Successful in 2m54s
Build App / build-linux (pull_request) Successful in 5m44s
Build App / create-tag (pull_request) Has been skipped
Build App / sync-to-github (pull_request) Has been skipped
Build App / compute-version (pull_request) Successful in 3s
Build Container / build-container (pull_request) Successful in 57s
Build App / build-macos (pull_request) Successful in 2m15s
Build App / build-windows (pull_request) Successful in 2m54s
Build App / build-linux (pull_request) Successful in 5m44s
Build App / create-tag (pull_request) Has been skipped
Build App / sync-to-github (pull_request) Has been skipped
- L4: sync_bedrock_credentials (renamed from write_bedrock_static_ credentials) now also clears a stale ~/.aws/credentials when the project no longer uses static-credential Bedrock, so static keys don't linger unused in the persistent home volume after switching backends. Skipped when /tmp/.host-aws is mounted (host-managed ~/.aws). HOME is also set explicitly on the exec env for robustness. - M1: the Backup button now has a tooltip and the success toast notes that the archive includes MCP/config which may contain MCP-embedded API keys (OAuth tokens are excluded) — keep it private. - L2: backup now uses async file IO (tokio::fs::File + AsyncWriteExt, tokio::fs::remove_file) instead of blocking std::fs between awaits; dropped-file reads use tokio::fs::metadata/read. - L5: upload_host_file_to_terminal explicitly `mkdir -p`s /tmp/triple-c-drops instead of relying on Docker's tar extractor to create the parent dir. Verified L4 cleanup guard, L5 mkdir, async IO, and exit-code paths against real containers. cargo check / tsc / vitest all pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -254,10 +254,11 @@ rm -rf "$STAGE""#;
|
||||
StartExecResults::Detached => return Err("Backup exec started detached".to_string()),
|
||||
};
|
||||
|
||||
use std::io::Write;
|
||||
let file =
|
||||
std::fs::File::create(&host_path).map_err(|e| format!("Failed to create backup file: {}", e))?;
|
||||
let mut writer = std::io::BufWriter::new(file);
|
||||
use tokio::io::AsyncWriteExt;
|
||||
let file = tokio::fs::File::create(&host_path)
|
||||
.await
|
||||
.map_err(|e| format!("Failed to create backup file: {}", e))?;
|
||||
let mut writer = tokio::io::BufWriter::new(file);
|
||||
let mut total: u64 = 0;
|
||||
let mut stderr_text = String::new();
|
||||
let mut stream_err: Option<String> = None;
|
||||
@@ -265,7 +266,7 @@ rm -rf "$STAGE""#;
|
||||
while let Some(msg) = output.next().await {
|
||||
match msg {
|
||||
Ok(LogOutput::StdOut { message }) => {
|
||||
if let Err(e) = writer.write_all(&message) {
|
||||
if let Err(e) = writer.write_all(&message).await {
|
||||
stream_err = Some(format!("Failed to write backup file: {}", e));
|
||||
break;
|
||||
}
|
||||
@@ -282,7 +283,7 @@ rm -rf "$STAGE""#;
|
||||
}
|
||||
}
|
||||
if stream_err.is_none() {
|
||||
if let Err(e) = writer.flush() {
|
||||
if let Err(e) = writer.flush().await {
|
||||
stream_err = Some(format!("Failed to finalize backup file: {}", e));
|
||||
}
|
||||
}
|
||||
@@ -321,7 +322,7 @@ rm -rf "$STAGE""#;
|
||||
|
||||
if let Some(err) = stream_err {
|
||||
// Don't leave a partial/corrupt archive behind.
|
||||
let _ = std::fs::remove_file(&host_path);
|
||||
let _ = tokio::fs::remove_file(&host_path).await;
|
||||
return Err(err);
|
||||
}
|
||||
|
||||
|
||||
@@ -432,11 +432,11 @@ pub async fn start_project_container(
|
||||
new_id
|
||||
};
|
||||
|
||||
// Refresh Bedrock static/session credentials on every start so rotated
|
||||
// keys are picked up without a full container recreation. No-op for
|
||||
// other backends / auth methods.
|
||||
if let Err(e) = docker::write_bedrock_static_credentials(&container_id, &project).await {
|
||||
log::warn!("Failed to refresh AWS credentials for project {}: {}", project.id, e);
|
||||
// Sync Bedrock credentials on every start: refresh static/session creds
|
||||
// so rotated keys are picked up without a full container recreation, and
|
||||
// clear stale creds when the project no longer uses static-cred Bedrock.
|
||||
if let Err(e) = docker::sync_bedrock_credentials(&container_id, &project).await {
|
||||
log::warn!("Failed to sync AWS credentials for project {}: {}", project.id, e);
|
||||
}
|
||||
|
||||
Ok(container_id)
|
||||
|
||||
@@ -196,7 +196,8 @@ pub async fn upload_host_file_to_terminal(
|
||||
) -> Result<String, String> {
|
||||
let container_id = state.exec_manager.get_container_id(&session_id).await?;
|
||||
|
||||
let meta = std::fs::metadata(&host_path)
|
||||
let meta = tokio::fs::metadata(&host_path)
|
||||
.await
|
||||
.map_err(|e| format!("Cannot access {}: {}", host_path, e))?;
|
||||
if meta.is_dir() {
|
||||
return Err(format!("{} is a directory — drop individual files", host_path));
|
||||
@@ -213,8 +214,9 @@ pub async fn upload_host_file_to_terminal(
|
||||
));
|
||||
}
|
||||
|
||||
let data =
|
||||
std::fs::read(&host_path).map_err(|e| format!("Failed to read {}: {}", host_path, e))?;
|
||||
let data = tokio::fs::read(&host_path)
|
||||
.await
|
||||
.map_err(|e| format!("Failed to read {}: {}", host_path, e))?;
|
||||
|
||||
let base = std::path::Path::new(&host_path)
|
||||
.file_name()
|
||||
@@ -222,6 +224,14 @@ pub async fn upload_host_file_to_terminal(
|
||||
.filter(|s| !s.is_empty())
|
||||
.unwrap_or_else(|| "dropped-file".to_string());
|
||||
|
||||
// Ensure the destination directory exists rather than relying on Docker's
|
||||
// archive extractor to create the parent for the uploaded tar entry.
|
||||
crate::docker::exec::exec_oneshot(
|
||||
&container_id,
|
||||
vec!["mkdir".to_string(), "-p".to_string(), "/tmp/triple-c-drops".to_string()],
|
||||
)
|
||||
.await?;
|
||||
|
||||
let file_name = format!("triple-c-drops/{}", base);
|
||||
state
|
||||
.exec_manager
|
||||
|
||||
Reference in New Issue
Block a user