fix: add SSH key selection to workspace tool starter + docker compose policy
tool-starter.tsx was hardcoding ssh_key_ids=[] and only showing a read-only SSH key status. Users couldn't select keys when starting tools from workspaces. Changes: - tool-starter.tsx: add checkboxes for SSH key selection with repo key pre-selected, pass selected keys to createInstance/startInstance - AGENTS.md: add explicit rule forbidding docker compose commands without user approval and proper isolation The web container must be rebuilt to pick up the frontend changes: docker compose up -d --build web Quality gates: tsc clean, pytest (19 passed, 1 skipped)
This commit is contained in:
@@ -31,6 +31,7 @@ export function ToolStarter({
|
||||
|
||||
const [sshKeys, setSshKeys] = useState<SSHKey[]>([]);
|
||||
const [sshKeysLoading, setSshKeysLoading] = useState(true);
|
||||
const [selectedSshKeyIds, setSelectedSshKeyIds] = useState<string[]>([]);
|
||||
|
||||
const [starting, setStarting] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
@@ -89,14 +90,18 @@ export function ToolStarter({
|
||||
try {
|
||||
const data = await listSSHKeys();
|
||||
setSshKeys(data);
|
||||
} catch {
|
||||
// ignore
|
||||
// Auto-select the repository's SSH key if available
|
||||
if (workspace.repo_ssh_key_id) {
|
||||
setSelectedSshKeyIds([workspace.repo_ssh_key_id]);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Failed to load SSH keys:", err);
|
||||
} finally {
|
||||
setSshKeysLoading(false);
|
||||
}
|
||||
};
|
||||
void load();
|
||||
}, []);
|
||||
}, [workspace.repo_ssh_key_id]);
|
||||
|
||||
const repoHasSshKey = !!workspace.repo_ssh_key_id;
|
||||
const repoSshKey = sshKeys.find((k) => k.id === workspace.repo_ssh_key_id);
|
||||
@@ -119,7 +124,7 @@ export function ToolStarter({
|
||||
undefined,
|
||||
undefined,
|
||||
selectedProfileId || undefined,
|
||||
[],
|
||||
selectedSshKeyIds.length > 0 ? selectedSshKeyIds : undefined,
|
||||
workspace.id,
|
||||
);
|
||||
await startInstance(
|
||||
@@ -127,6 +132,7 @@ export function ToolStarter({
|
||||
workspace.repo_id,
|
||||
instance.id,
|
||||
selectedProfileId || undefined,
|
||||
selectedSshKeyIds.length > 0 ? selectedSshKeyIds : undefined,
|
||||
);
|
||||
onStarted(instance);
|
||||
} catch (err) {
|
||||
@@ -208,20 +214,53 @@ export function ToolStarter({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* SSH Key Status */}
|
||||
<div className="form-group ssh-key-status">
|
||||
<label>SSH Key</label>
|
||||
{/* SSH Key Selection */}
|
||||
<div className="form-group ssh-key-selection">
|
||||
<label>SSH Keys</label>
|
||||
{sshKeysLoading ? (
|
||||
<span className="muted">Checking...</span>
|
||||
) : repoHasSshKey ? (
|
||||
<span className="success-text">
|
||||
<Icon name="success" size="sm" />{" "}
|
||||
{repoSshKey?.name || "SSH key assigned"}
|
||||
</span>
|
||||
<span className="muted">Loading SSH keys...</span>
|
||||
) : sshKeys.length === 0 ? (
|
||||
<span className="muted">No SSH keys configured.</span>
|
||||
) : (
|
||||
<span className="warning-text">
|
||||
<Icon name="warning" size="sm" /> No SSH key assigned to repository
|
||||
</span>
|
||||
<div style={{ display: "flex", flexWrap: "wrap", gap: "0.5rem" }}>
|
||||
{sshKeys.map((key) => (
|
||||
<label
|
||||
key={key.id}
|
||||
className="checkbox-label"
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "0.25rem",
|
||||
padding: "0.375rem 0.75rem",
|
||||
background: "var(--panel)",
|
||||
borderRadius: "0.375rem",
|
||||
border: "1px solid var(--border)",
|
||||
cursor: "pointer",
|
||||
}}
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={selectedSshKeyIds.includes(key.id)}
|
||||
onChange={(e) => {
|
||||
if (e.target.checked) {
|
||||
setSelectedSshKeyIds((prev) => [...prev, key.id]);
|
||||
} else {
|
||||
setSelectedSshKeyIds((prev) =>
|
||||
prev.filter((id) => id !== key.id),
|
||||
);
|
||||
}
|
||||
}}
|
||||
disabled={starting}
|
||||
/>
|
||||
{key.name}
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
{!sshKeysLoading && repoHasSshKey && repoSshKey && (
|
||||
<div className="hint" style={{ marginTop: "0.5rem" }}>
|
||||
Repository key <strong>{repoSshKey.name}</strong> is pre-selected.
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user