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

- 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:
2026-06-30 14:37:33 -07:00
parent edf0698774
commit d65872dc94
5 changed files with 77 additions and 33 deletions
+10 -2
View File
@@ -196,7 +196,7 @@ export default function ProjectCard({ project }: Props) {
setError(null);
const bytes = await commands.downloadContainerBackup(project.id, hostPath);
const mb = (bytes / (1024 * 1024)).toFixed(1);
setProgressMsg(`Backup saved (${mb} MB)`);
setProgressMsg(`Backup saved (${mb} MB). Note: includes MCP/config — may contain MCP API keys. Keep it private.`);
} catch (e) {
setError(String(e));
} finally {
@@ -531,7 +531,12 @@ export default function ProjectCard({ project }: Props) {
<ActionButton onClick={handleOpenTerminal} disabled={loading} label="Terminal" accent />
<ActionButton onClick={handleOpenBashShell} disabled={loading} label="Shell" />
<ActionButton onClick={() => setShowFileManager(true)} disabled={loading} label="Files" />
<ActionButton onClick={handleBackup} disabled={loading || backingUp} label={backingUp ? "Backing up…" : "Backup"} />
<ActionButton
onClick={handleBackup}
disabled={loading || backingUp}
label={backingUp ? "Backing up…" : "Backup"}
title="Downloads /workspace plus a sanitized home config (MCP servers, settings, skills). OAuth tokens are excluded, but MCP server configs may embed their own API keys/tokens — keep the archive private."
/>
</>
) : (
<>
@@ -1221,12 +1226,14 @@ function ActionButton({
label,
accent,
danger,
title,
}: {
onClick: (e?: React.MouseEvent) => void;
disabled: boolean;
label: string;
accent?: boolean;
danger?: boolean;
title?: string;
}) {
let color = "text-[var(--text-secondary)] hover:text-[var(--text-primary)]";
if (accent) color = "text-[var(--accent)] hover:text-[var(--accent-hover)]";
@@ -1236,6 +1243,7 @@ function ActionButton({
<button
onClick={(e) => { e.stopPropagation(); onClick(e); }}
disabled={disabled}
title={title}
className={`text-xs px-2 py-0.5 rounded transition-colors disabled:opacity-50 ${color} hover:bg-[var(--bg-primary)]`}
>
{label}