Files
pulse/internal/api/configapi/install_command.go
T
pulse-triage[bot] 2fd114b3ac Keep Proxmox bootstrap credentials out of copied commands
Separate PVE/PBS setup and telemetry credentials from shell source and download URLs. Use silent root/sudo input, private-file handoff, complete downloads and the agent preflight; preserve scope, TLS defaults, single-line paste and coherent rolling-upgrade metadata. Reveal tokens through the existing dialog and discard late issuance after close. Pin executable shell, history, TLS/registration and browser contracts without using real credentials.

Change-source: pulse-maintainer
2026-10-01 05:23:08 +01:00

98 lines
4.2 KiB
Go

package configapi
import (
"strings"
)
type AgentInstallCommandOptions struct {
BaseURL string
Token string
InstallType string
IncludeInstallType bool
EnableCommands bool
Insecure bool
}
type agentInstallCommandOptions = AgentInstallCommandOptions
// BuildProxmoxAgentInstallCommand never puts the credential in shell source.
// Token only selects whether private terminal input is required. The plaintext
// remains in the authenticated response's separate token field.
func BuildProxmoxAgentInstallCommand(opts AgentInstallCommandOptions) string {
baseURL := strings.TrimRight(strings.TrimSpace(opts.BaseURL), "/")
curlFlags := "-fsSL"
if opts.Insecure {
curlFlags = "-kfsSL"
}
trustArgs := ""
if opts.Insecure || strings.HasPrefix(strings.ToLower(baseURL), "http://") {
trustArgs = " --insecure"
}
args := " --url " + posixShellQuote(baseURL) + " --enable-proxmox"
if opts.IncludeInstallType {
args += " --proxmox-type " + posixShellQuote(opts.InstallType)
}
if opts.EnableCommands {
args += " --enable-commands"
}
if strings.TrimSpace(opts.Token) != "" {
args += ` --token-file "$token_file"`
}
args += trustArgs + " --non-interactive"
preflight := "bash \"$install_script\" --url " + posixShellQuote(baseURL) +
" --preflight-only --output json --non-interactive" + trustArgs + ";"
return privateBootstrapCommand(baseURL+"/install.sh", curlFlags, preflight,
"bash \"$1\""+args+";", strings.TrimSpace(opts.Token) != "", "Pulse agent token")
}
// privateBootstrapCommand uses POSIX outer grammar for single-line paste hosts.
// The privileged Bash child owns both the silent input and its 0700/0600
// handoff. Neither sudo nor a child command receives the credential in argv or
// environment. Failed/partial downloads and preflight never reach that child.
func privateBootstrapCommand(scriptURL, curlFlags, preflight, run string, needsToken bool, prompt string) string {
privileged := []string{"set +xv;", "set -eu;", "umask 077;"}
if needsToken {
privileged = append(privileged,
`token_dir=$(mktemp -d /tmp/pulse-agent-bootstrap.XXXXXX);`,
`token_file="$token_dir/token";`,
`cleanup() { unset pulse_token; rm -f -- "$token_file"; rmdir -- "$token_dir"; };`,
`trap cleanup EXIT; trap 'exit 129' HUP; trap 'exit 130' INT; trap 'exit 143' TERM;`,
`if ! IFS= read -r -s -p `+posixShellQuote(prompt+" (paste at this prompt, not in the command): ")+` pulse_token </dev/tty; then echo "A terminal is required to enter the token. No installation was attempted." >&2; exit 1; fi;`,
`printf '\n' >/dev/tty;`,
`if [ -z "$pulse_token" ] || [ "${#pulse_token}" -gt 4096 ]; then echo "A non-empty token of at most 4096 characters is required." >&2; exit 1; fi;`,
`printf %s "$pulse_token" > "$token_file"; unset pulse_token;`,
)
}
privileged = append(privileged, run)
child := "bash -c " + posixShellQuote(strings.Join(privileged, " ")) + ` pulse-bootstrap "$install_script";`
return strings.Join([]string{
"(", "set +xv;", "set -eu;", "umask 077;",
`if [ "$(id -u)" -eq 0 ]; then :; elif command -v sudo >/dev/null 2>&1; then sudo -v; else echo "Root privileges required. Run as root (su -) and retry." >&2; exit 1; fi;`,
`bootstrap_dir=$(mktemp -d /tmp/pulse-bootstrap.XXXXXX);`,
`install_script="$bootstrap_dir/install.sh";`,
`cleanup() { rm -f -- "$install_script"; rmdir -- "$bootstrap_dir"; };`,
`trap cleanup EXIT; trap 'exit 129' HUP; trap 'exit 130' INT; trap 'exit 143' TERM;`,
"curl " + curlFlags + " " + posixShellQuote(strings.TrimSpace(scriptURL)) + ` -o "$install_script";`,
preflight,
`if [ "$(id -u)" -eq 0 ]; then ` + child + " else sudo " + child + " fi;",
")",
}, " ")
}
func buildProxmoxAgentInstallCommand(opts agentInstallCommandOptions) string {
return BuildProxmoxAgentInstallCommand(opts)
}
func withPrivilegeEscalation(command string) string {
const installPipe = "| bash -s --"
idx := strings.Index(command, installPipe)
if idx == -1 {
return command
}
args := command[idx+len(installPipe):]
return command[:idx] +
`| { if [ "$(id -u)" -eq 0 ]; then bash -s --` + args +
`; elif command -v sudo >/dev/null 2>&1; then sudo bash -s --` + args +
`; else echo "Root privileges required. Run as root (su -) and retry." >&2; exit 1; fi; }`
}