SSH connections, kept by the people who own them

An agent chat will act on a machine you choose, so this is the screen where
you choose it. User-owned like a note, not admin-owned like a connection:
these are somebody's own machines and somebody's own keys, and "anyone in
this group may log in to my server" is a different feature with a different
blast radius. services/sharing.py is deliberately not involved either --
sharing grants reading, and a host somebody else can read is a host they
can log in to.

Trust on first use, made explicit rather than assumed. Adding a host does
not connect to it. Check looks at its key and shows you the fingerprint;
nothing is sent until you accept, because get_server_host_key completes the
key exchange and stops -- no username, no credential. Accepting pins it,
and a host that later presents a different key is refused with the reason
rather than quietly trusted. Moving a profile to another host or port
forgets the pin, since a key belongs to the machine it came from.

Four asyncssh defaults are actively wrong here and all four are passed
explicitly: every LLeMbas user shares one unix account, so `known_hosts`
would be a shared trust store, `client_keys` would authenticate one person
with another's key, `config` would let a ProxyCommand redirect the
connection, and `agent_path` would silently use $SSH_AUTH_SOCK. There is a
test for exactly that, and it needs no server.

Files go over SFTP rather than through a shell. The SSH exec protocol
carries one command *string* that the far side parses, with no argv form at
all, so a model-supplied path in a command line is unavoidably a quoting
problem. Over SFTP a path is a path.

Chat gains its kind, connection, project directory and mode; the first
three are fixed once a chat has a message, because a transcript whose
earlier turns ran somewhere else is not one conversation.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jaroslav Beneš
2026-08-01 22:34:58 +02:00
parent c3d6660881
commit fe7227af62
21 changed files with 2452 additions and 7 deletions
+16
View File
@@ -5,6 +5,12 @@ what ``init_db()`` relies on to create the schema at startup. Any new model
module must be imported here or its table will silently never be created.
"""
from lembas.db.models.agent import (
AUTH_KEY,
AUTH_METHODS,
AUTH_PASSWORD,
SshProfile,
)
from lembas.db.models.attachment import (
KIND_DOCUMENT,
KIND_IMAGE,
@@ -12,6 +18,9 @@ from lembas.db.models.attachment import (
Attachment,
)
from lembas.db.models.chat import (
KIND_AGENT,
KIND_CHAT,
KINDS,
ROLE_ASSISTANT,
ROLE_SYSTEM,
ROLE_TOOL,
@@ -68,8 +77,14 @@ from lembas.db.models.user import (
__all__ = [
"AUTHOR_MODEL",
"AUTH_KEY",
"AUTH_METHODS",
"AUTH_PASSWORD",
"AUTHOR_USER",
"Attachment",
"KINDS",
"KIND_AGENT",
"KIND_CHAT",
"KIND_DOCUMENT",
"KIND_IMAGE",
"KIND_TEXT",
@@ -111,6 +126,7 @@ __all__ = [
"Setting",
"Share",
"Skill",
"SshProfile",
"SkillRevision",
"Suggestion",
"User",