fix(electrobun): complete all 16 Codex #3 findings

CRITICAL:
- Message persistence race: snapshot batchEnd before async save
- Double-start guard: startingProjects Set prevents concurrent launches
- Symlink path traversal: fs.realpathSync() in path-guard.ts
- Relay false success: connect() returns { ok, machineId, error }

HIGH:
- Session restore skips if active session exists
- Remote remove: new RPC, cleans backend map
- Task board poll token: stale responses discarded after drag-drop
- Health concurrent tools: toolsInFlight counter (was boolean)
- bttask transactions: delete wraps comments+task, addComment validates
- PTY buffer cleared on reconnect
- PTY large paste: chunked String.fromCharCode (8KB chunks)
- Sidecar max line: 10MB limit prevents unbounded memory
- btmsg authorization: group validation, channel membership checks

MEDIUM:
- Session retention: max 5 per project, purgeSession/untrackProject
- Relay IPv6: URL parser replaces string split
- PTY schema: fixed misleading base64 comment
This commit is contained in:
Hibryda 2026-03-22 02:52:04 +01:00
parent c145e37316
commit 0f75cb8e32
12 changed files with 190 additions and 42 deletions

View file

@ -84,10 +84,11 @@
} catch { /* ignore */ }
}
// Fix #6 (Codex audit): Use remote.remove RPC that disconnects AND deletes
async function handleRemove(machineId: string) {
try {
await appRpc.request['remote.disconnect']({ machineId });
} catch { /* may already be disconnected */ }
await appRpc.request['remote.remove']({ machineId });
} catch { /* may already be disconnected/removed */ }
removeMachine(machineId);
}
@ -131,6 +132,9 @@
<span class="status-text" style:color={statusColor(m.status)}>
{statusLabel(m.status)}
</span>
{#if m.error}
<span class="machine-error" title={m.error}>{m.error}</span>
{/if}
</div>
<div class="machine-actions">
{#if m.status === 'connected'}
@ -239,6 +243,7 @@
}
.status-text { font-size: 0.6875rem; font-weight: 500; }
.machine-error { font-size: 0.625rem; color: var(--ctp-red); max-width: 10rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.machine-actions { display: flex; gap: 0.25rem; flex-shrink: 0; }