fix(docker): retain stored SSH credential association (#1543)

This commit is contained in:
ZacharyZcR authored and GitHub committed 2026-10-03 21:02:21 +08:00
1 parent 117e125d55
commit 4785bf5dfa
2 files changed
+43 -6

No files matched your search

+7 -5
View File
@@ -210,11 +210,13 @@ export function registerRoutes(router: Router, { ctx, sessions, log }: Deps) {
), ),
); );
const target: PluginSshHost = { const hasAuthOverride = [
...host, userProvidedPassword,
id: numericHostId, userProvidedSshKey,
port: host.port || 22, userProvidedKeyPassword,
}; ].some((value) => typeof value === "string" && value.length > 0);
// Core associates the redacted host object with its stored credentials.
const target: PluginSshHost = hasAuthOverride ? { ...host } : host;
if (typeof userProvidedPassword === "string" && userProvidedPassword) { if (typeof userProvidedPassword === "string" && userProvidedPassword) {
target.password = userProvidedPassword; target.password = userProvidedPassword;
target.authType = "password"; target.authType = "password";
+36 -1
View File
@@ -3,7 +3,7 @@ import type {
PluginSshConnectOptions, PluginSshConnectOptions,
PluginSshHost, PluginSshHost,
} from "@termix/plugin-sdk/backend"; } from "@termix/plugin-sdk/backend";
import { startServer, type TestServer } from "./server"; import { startServer, sshHost, type TestServer } from "./server";
import { FakeClient } from "./fake-ssh"; import { FakeClient } from "./fake-ssh";
let server: TestServer | null = null; let server: TestServer | null = null;
@@ -76,6 +76,41 @@ describe("docker routes", () => {
expect((await connect(server, "s1", 99)).status).toBe(404); expect((await connect(server, "s1", 99)).status).toBe(404);
}); });
it("keeps the core-resolved host identity when using stored credentials", async () => {
server = await startServer();
const host = sshHost(7, { authType: "key", password: undefined });
const originalConnect = server.mock.ctx.ssh.connect;
server.mock.ctx.ssh.resolveHost = async () => host;
server.mock.ctx.ssh.connect = (async (target, options) => {
if (target !== host)
throw new Error("Stored credential association lost");
return originalConnect(target, options);
}) as typeof originalConnect;
const response = await connect(server);
expect(response.status).toBe(200);
expect(response.body.success).toBe(true);
});
it("applies explicit authentication overrides without changing the resolved host", async () => {
server = await startServer();
const host = sshHost(7, { authType: "key", password: undefined });
server.mock.ctx.ssh.resolveHost = async () => host;
const response = await server.request("POST", "/ssh/connect", {
body: {
sessionId: "override",
hostId: 7,
userProvidedPassword: "replacement",
},
});
expect(response.status).toBe(200);
expect(server.mock.sshConnections.at(-1)?.host).toMatchObject({
authType: "password",
password: "replacement",
});
expect(host.authType).toBe("key");
expect(host.password).toBeUndefined();
});
it("connects, validates and manages containers on the session", async () => { it("connects, validates and manages containers on the session", async () => {
server = await startServer(); server = await startServer();
const connected = await connect(server); const connected = await connect(server);