mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-31 15:45:23 +00:00
fix: fleets, proxmox and automations not getting the host sudo password
This commit is contained in:
1 parent
6f442c5863
commit
5e31642379
8 files changed
+65
-5
No files matched your search
@@ -17,6 +17,7 @@
|
|||||||
"capabilities": [
|
"capabilities": [
|
||||||
"hosts:read",
|
"hosts:read",
|
||||||
"credentials:use",
|
"credentials:use",
|
||||||
|
"credentials:read",
|
||||||
"ssh:connect",
|
"ssh:connect",
|
||||||
"db:own",
|
"db:own",
|
||||||
"events:core",
|
"events:core",
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
import fs from "node:fs";
|
||||||
|
import path from "node:path";
|
||||||
|
|
||||||
|
// Elevated commands read the host's sudo password, which core only hands to
|
||||||
|
// a plugin holding credentials:read.
|
||||||
|
describe("sudo password access", () => {
|
||||||
|
it("declares credentials:read", () => {
|
||||||
|
const manifest = JSON.parse(
|
||||||
|
fs.readFileSync(
|
||||||
|
path.resolve(import.meta.dirname, "../../manifest.json"),
|
||||||
|
"utf8",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(manifest.capabilities).toContain("credentials:read");
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -18,6 +18,7 @@
|
|||||||
"hosts:read",
|
"hosts:read",
|
||||||
"hosts:write",
|
"hosts:write",
|
||||||
"credentials:use",
|
"credentials:use",
|
||||||
|
"credentials:read",
|
||||||
"ssh:connect",
|
"ssh:connect",
|
||||||
"db:own",
|
"db:own",
|
||||||
"network:serve",
|
"network:serve",
|
||||||
|
|||||||
@@ -1357,9 +1357,9 @@ export function registerFleetRoutes(
|
|||||||
fleetId,
|
fleetId,
|
||||||
"manage",
|
"manage",
|
||||||
async (host) => {
|
async (host) => {
|
||||||
// Package actions need the host's sudo password, an operational
|
// Package actions need the host's sudo password. connect() hands
|
||||||
// secret ctx.hosts.get() leaves out. ctx.ssh.connect resolves the
|
// back a redacted host, so read it through resolveHost.
|
||||||
// full host the connect pipeline uses, which carries it.
|
const full = await ctx.ssh.resolveHost(host.id);
|
||||||
const connection = await ctx.ssh.connect(host.id, {
|
const connection = await ctx.ssh.connect(host.id, {
|
||||||
purpose: "fleet",
|
purpose: "fleet",
|
||||||
});
|
});
|
||||||
@@ -1388,7 +1388,7 @@ export function registerFleetRoutes(
|
|||||||
const result = await execElevated(
|
const result = await execElevated(
|
||||||
sshClient,
|
sshClient,
|
||||||
cmd,
|
cmd,
|
||||||
connection.host.sudoPassword as string | undefined,
|
full?.sudoPassword as string | undefined,
|
||||||
{ forceSudo: true, timeoutMs: 600000 },
|
{ forceSudo: true, timeoutMs: 600000 },
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
import fs from "node:fs";
|
||||||
|
import path from "node:path";
|
||||||
|
|
||||||
|
// Elevated commands read the host's sudo password, which core only hands to
|
||||||
|
// a plugin holding credentials:read.
|
||||||
|
describe("sudo password access", () => {
|
||||||
|
it("declares credentials:read", () => {
|
||||||
|
const manifest = JSON.parse(
|
||||||
|
fs.readFileSync(
|
||||||
|
path.resolve(import.meta.dirname, "../../manifest.json"),
|
||||||
|
"utf8",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(manifest.capabilities).toContain("credentials:read");
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -18,6 +18,7 @@
|
|||||||
"hosts:read",
|
"hosts:read",
|
||||||
"hosts:write",
|
"hosts:write",
|
||||||
"credentials:use",
|
"credentials:use",
|
||||||
|
"credentials:read",
|
||||||
"ssh:connect",
|
"ssh:connect",
|
||||||
"db:own",
|
"db:own",
|
||||||
"network:serve",
|
"network:serve",
|
||||||
|
|||||||
@@ -275,7 +275,13 @@ async function discoverProxmoxGuestsForHost(
|
|||||||
timeoutMs: 35000,
|
timeoutMs: 35000,
|
||||||
overrides: { tryKeyboard: false, readyTimeout: 30000 },
|
overrides: { tryKeyboard: false, readyTimeout: 30000 },
|
||||||
});
|
});
|
||||||
const hostWithSudo: PluginSshHostWithSudo = host;
|
// connect() always hands back a redacted host; the sudo password comes
|
||||||
|
// from resolveHost, which needs credentials:read.
|
||||||
|
const full = await ctx.ssh.resolveHost(parsedHostId);
|
||||||
|
const hostWithSudo: PluginSshHostWithSudo = {
|
||||||
|
...host,
|
||||||
|
sudoPassword: (full?.sudoPassword as string | undefined) ?? undefined,
|
||||||
|
};
|
||||||
const hostCredentialId = (hostWithSudo.credentialId as number | null) ?? null;
|
const hostCredentialId = (hostWithSudo.credentialId as number | null) ?? null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
import fs from "node:fs";
|
||||||
|
import path from "node:path";
|
||||||
|
|
||||||
|
// Elevated commands read the host's sudo password, which core only hands to
|
||||||
|
// a plugin holding credentials:read.
|
||||||
|
describe("sudo password access", () => {
|
||||||
|
it("declares credentials:read", () => {
|
||||||
|
const manifest = JSON.parse(
|
||||||
|
fs.readFileSync(
|
||||||
|
path.resolve(import.meta.dirname, "../../manifest.json"),
|
||||||
|
"utf8",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(manifest.capabilities).toContain("credentials:read");
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in new issue
Block a user