Merge pull request 'clan-app: Add password input' (#5068) from Qubasa/clan-core:password_prompt into main

Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5068
This commit is contained in:
Luis Hebendanz
2025-09-02 15:48:24 +00:00
4 changed files with 46 additions and 5 deletions

View File

@@ -53,6 +53,7 @@ export interface InstallStoreType {
install: {
targetHost: string;
port?: string;
password?: string;
machineName: string;
mainDisk: string;
// ...TODO Vars

View File

@@ -54,6 +54,7 @@ const ConfigureAdressSchema = v.object({
v.transform((val) => (val === "" ? undefined : val)),
),
),
password: v.optional(v.string()),
});
type ConfigureAdressForm = v.InferInput<typeof ConfigureAdressSchema>;
@@ -84,6 +85,7 @@ const ConfigureAddress = () => {
...s,
targetHost: values.targetHost,
port: values.port,
password: values.password,
}));
// Here you would typically trigger the ISO creation process
@@ -98,12 +100,14 @@ const ConfigureAddress = () => {
const portValue = getValue(formStore, "port");
const port = portValue ? parseInt(portValue, 10) : undefined;
const password = getValue(formStore, "password") || undefined;
setLoading(true);
const call = client.fetch("check_machine_ssh_login", {
remote: {
address,
...(port && { port }),
password: password,
ssh_options: {
StrictHostKeyChecking: "no",
UserKnownHostsFile: "/dev/null",
@@ -163,6 +167,24 @@ const ConfigureAddress = () => {
/>
)}
</Field>
<Field name="password">
{(field, props) => (
<TextInput
{...field}
label="Password"
description="SSH password (optional)"
value={field.value}
orientation="horizontal"
validationState={
getError(formStore, "port") ? "invalid" : "valid"
}
input={{
...props,
type: "password",
}}
/>
)}
</Field>
</Fieldset>
</div>
}
@@ -224,6 +246,7 @@ const CheckHardware = () => {
target_host: {
address: store.install.targetHost,
...(port && { port }),
password: store.install.password,
ssh_options: {
StrictHostKeyChecking: "no",
UserKnownHostsFile: "/dev/null",
@@ -650,6 +673,7 @@ const InstallSummary = () => {
target_host: {
address: store.install.targetHost,
...(port && { port }),
password: store.install.password,
ssh_options: {
StrictHostKeyChecking: "no",
UserKnownHostsFile: "/dev/null",

View File

@@ -1,5 +1,6 @@
import json
import logging
import os
from dataclasses import dataclass
from enum import Enum
from pathlib import Path
@@ -91,6 +92,15 @@ def run_machine_hardware_info(
str(opts.backend.config_path(machine)),
]
environ = os.environ.copy()
if target_host.password:
cmd += [
"--env-password",
"--ssh-option",
"IdentitiesOnly=yes",
]
environ["SSHPASS"] = target_host.password
if target_host.private_key:
cmd += ["--ssh-option", f"IdentityFile={target_host.private_key}"]
@@ -113,7 +123,9 @@ def run_machine_hardware_info(
run(
cmd,
RunOpts(log=Log.BOTH, prefix=machine.name, needs_user_terminal=True),
RunOpts(
log=Log.BOTH, prefix=machine.name, needs_user_terminal=True, env=environ
),
)
print(f"Successfully generated: {hw_file}")

View File

@@ -122,9 +122,6 @@ def run_machine_install(opts: InstallOptions, target_host: Remote) -> None:
phases=["partitioning"],
)
if target_host.password:
os.environ["SSHPASS"] = target_host.password
cmd = [
"nixos-anywhere",
"--flake",
@@ -161,12 +158,14 @@ def run_machine_install(opts: InstallOptions, target_host: Remote) -> None:
],
)
environ = os.environ.copy()
if target_host.password:
cmd += [
"--env-password",
"--ssh-option",
"IdentitiesOnly=yes",
]
environ["SSHPASS"] = target_host.password
# Always set a nixos-anywhere private key to prevent failures when running
# 'clan install --phases kexec' followed by 'clan install --phases disko,install,reboot'.
@@ -226,7 +225,12 @@ def run_machine_install(opts: InstallOptions, target_host: Remote) -> None:
notify_install_step(notification)
run(
[*cmd, "--phases", phase],
RunOpts(log=Log.BOTH, prefix=machine.name, needs_user_terminal=True),
RunOpts(
log=Log.BOTH,
prefix=machine.name,
needs_user_terminal=True,
env=environ,
),
)
if opts.phases: