mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-23 01:32:40 +00:00
Explain that daemon set-password needs a terminal when stdin is piped (#5358)
* Explain that daemon set-password needs a terminal when stdin is piped The password prompt only resolves on a keypress from a terminal. With stdin piped or redirected it never settled, so Node exited 13 with an unsettled top-level await warning and no message. The command now fails with PASSWORD_TTY_REQUIRED and points at PASEO_PASSWORD. Closes #5350 * Assert the set-password terminal error message --------- Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
This commit is contained in:
@@ -57,6 +57,17 @@ function createCommandError(code: string, message: string, details?: string): Co
|
||||
return { code, message, ...(details ? { details } : {}) };
|
||||
}
|
||||
|
||||
function terminalPasswordPrompt(): PromptPassword {
|
||||
if (!process.stdin.isTTY) {
|
||||
throw createCommandError(
|
||||
"PASSWORD_TTY_REQUIRED",
|
||||
"paseo daemon set-password needs a terminal to read the password",
|
||||
"Run it in an interactive terminal, or set PASEO_PASSWORD in the daemon's environment instead.",
|
||||
);
|
||||
}
|
||||
return (message) => passwordPrompt({ message });
|
||||
}
|
||||
|
||||
async function promptForPassword(promptPassword: PromptPassword): Promise<string> {
|
||||
const first = await promptPassword("New daemon password");
|
||||
if (isCancel(first)) {
|
||||
@@ -112,7 +123,7 @@ export async function runSetPasswordCommand(
|
||||
const promptPassword =
|
||||
typeof options.promptPassword === "function"
|
||||
? (options.promptPassword as PromptPassword)
|
||||
: (message: string) => passwordPrompt({ message });
|
||||
: terminalPasswordPrompt();
|
||||
const newPassword = await promptForPassword(promptPassword);
|
||||
const result = await setDaemonPasswordInConfig(newPassword, {
|
||||
home: options.daemonTarget.kind === "instance" ? options.daemonTarget.home : undefined,
|
||||
|
||||
@@ -6,6 +6,7 @@ import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import type { Command } from "commander";
|
||||
import { isBearerTokenValid } from "@getpaseo/server/auth";
|
||||
import { runLocalPaseo } from "./helpers/local-cli.ts";
|
||||
import {
|
||||
runSetPasswordCommand,
|
||||
setDaemonPasswordInConfig,
|
||||
@@ -105,6 +106,27 @@ try {
|
||||
);
|
||||
console.log("✓ command refuses password mismatch\n");
|
||||
}
|
||||
|
||||
{
|
||||
console.log("Test 4: piped stdin fails with a message instead of exiting silently");
|
||||
const pipedHome = join(root, "piped");
|
||||
await mkdir(pipedHome, { recursive: true });
|
||||
const run = runLocalPaseo(["daemon", "set-password", "--home", pipedHome, "--json"]);
|
||||
run.stdin.end("x\nx\n");
|
||||
const result = await run;
|
||||
|
||||
assert.strictEqual(result.exitCode, 1, result.stderr);
|
||||
const error = JSON.parse(result.stderr).error as {
|
||||
code: string;
|
||||
message: string;
|
||||
details: string;
|
||||
};
|
||||
assert.strictEqual(error.code, "PASSWORD_TTY_REQUIRED");
|
||||
assert.match(error.message, /needs a terminal/);
|
||||
assert.match(error.details, /PASEO_PASSWORD/);
|
||||
await assert.rejects(readFile(join(pipedHome, "config.json"), "utf-8"));
|
||||
console.log("✓ piped stdin reports that a terminal is required\n");
|
||||
}
|
||||
} finally {
|
||||
await rm(root, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user