feat: instance-level SSH key selection for container mounting

- Revert mistaken ssh_key_id from ConfigProfile (model, API, resolver, frontend)
- Add ssh_key_ids JSON column to tool_instances via migration
- Update create_instance to accept and store ssh_key_ids
- Update start_instance to mount selected SSH keys to {home_dir}/.ssh
- Update list_instances to return ssh_key_ids
- Frontend CreateSessionForm: multi-select SSH key checkboxes
- Frontend instance-list: SSH key selector for start/restart actions
- Maintain separate SSH key dirs per key to avoid conflicts

Quality gates: pytest (231 passed, 6 pre-existing), tsc --noEmit clean
This commit is contained in:
Alex Blank
2026-05-29 13:30:53 +02:00
parent cbd3436ff7
commit e9364fa70f
14 changed files with 2049 additions and 1524 deletions
-5
View File
@@ -9,7 +9,6 @@ from src.models.base import Base, TimestampMixin, UUIDPrimaryKeyMixin
if TYPE_CHECKING:
from src.models.project import Project
from src.models.ssh_key import SSHKey
from src.models.tool_type import ToolType
from src.models.user import User
@@ -43,15 +42,11 @@ class ConfigProfile(UUIDPrimaryKeyMixin, TimestampMixin, Base):
git_mounts: Mapped[list] = mapped_column(
JSON, default=list, nullable=False
) # [{"remote_url": "https://github.com/user/repo.git", "source_path": ".", "target_path": "/path", "branch": "main"}, ...]
ssh_key_id: Mapped[uuid.UUID | None] = mapped_column(
UUID(), ForeignKey("ssh_keys.id", ondelete="SET NULL"), nullable=True
)
is_default: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
user: Mapped["User"] = relationship()
project: Mapped["Project | None"] = relationship()
tool_type: Mapped["ToolType | None"] = relationship()
ssh_key: Mapped["SSHKey | None"] = relationship()
includes: Mapped[list["ConfigProfileInclude"]] = relationship(
"ConfigProfileInclude",
foreign_keys="ConfigProfileInclude.profile_id",
+1
View File
@@ -59,6 +59,7 @@ class ToolInstance(UUIDPrimaryKeyMixin, TimestampMixin, Base):
selected_config_profile_id: Mapped[uuid.UUID | None] = mapped_column(
UUID(), ForeignKey("config_profiles.id", ondelete="SET NULL"), nullable=True
)
ssh_key_ids: Mapped[list[str] | None] = mapped_column(JSON, nullable=True)
tool_type: Mapped["ToolType"] = relationship()
repository: Mapped["GitRepository"] = relationship()