mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-27 05:57:27 +00:00
Exercise backend bootstrap portability and full terminal restoration
Cover setup, Proxmox and container callers with a real PTY, isolated standalone and BusyBox tool selection, distinct fail-closed modes, private root/sudo history and one bounded command body. These controls expose the unchanged backend reader before its repair. Change-source: pulse-maintainer
This commit is contained in:
@@ -17,6 +17,11 @@ import errno, fcntl, json, os, pty, select, signal, subprocess, sys, termios, ti
|
||||
p = json.load(sys.stdin)
|
||||
master, slave = pty.openpty()
|
||||
tty_watch = os.dup(slave)
|
||||
if p.get("alternate_tty"):
|
||||
alternate = termios.tcgetattr(tty_watch)
|
||||
alternate[0] &= ~termios.IXON
|
||||
alternate[3] &= ~termios.ECHOK
|
||||
termios.tcsetattr(tty_watch, termios.TCSANOW, alternate)
|
||||
initial_tty = termios.tcgetattr(tty_watch)
|
||||
def session():
|
||||
os.setsid()
|
||||
@@ -76,7 +81,10 @@ while time.monotonic() < deadline:
|
||||
# the real bootstrap disables it before printing the input prompt.
|
||||
silent = not (termios.tcgetattr(tty_watch)[3] & termios.ECHO)
|
||||
if output.endswith(b"(paste at this prompt, not in the command): ") and command_ready and silent and not sent:
|
||||
os.write(master, (p["input"] + "\n").encode())
|
||||
if p.get("signal_on_prompt"):
|
||||
os.killpg(child.pid, getattr(signal, "SIG" + p["signal_on_prompt"]))
|
||||
else:
|
||||
os.write(master, (p["input"] + "\n").encode())
|
||||
sent = True
|
||||
if child.poll() is not None and not ready: break
|
||||
else:
|
||||
@@ -84,9 +92,8 @@ else:
|
||||
output += b"\nPTY fixture deadline expired\n"
|
||||
code = child.wait()
|
||||
final_tty = termios.tcgetattr(tty_watch)
|
||||
mode_mask = termios.ECHO | termios.ICANON
|
||||
if (initial_tty[3] & mode_mask) != (final_tty[3] & mode_mask):
|
||||
output += b"\nBootstrap did not restore terminal echo/canonical mode\n"
|
||||
if initial_tty != final_tty:
|
||||
output += b"\nBootstrap did not restore complete terminal settings\n"
|
||||
code = 1
|
||||
os.close(tty_watch)
|
||||
os.close(master)
|
||||
|
||||
@@ -0,0 +1,272 @@
|
||||
package configapi
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type portableBootstrapCaller struct {
|
||||
name string
|
||||
build func(string) string
|
||||
}
|
||||
|
||||
func portableBootstrapCallers() []portableBootstrapCaller {
|
||||
return []portableBootstrapCaller{
|
||||
{"proxmox", func(token string) string {
|
||||
return BuildProxmoxAgentInstallCommand(AgentInstallCommandOptions{BaseURL: "https://pulse.example", Token: token, InstallType: "pbs", IncludeInstallType: true})
|
||||
}},
|
||||
{"setup", func(token string) string {
|
||||
return BuildSetupScriptCommand("https://pulse.example/api/setup-script?type=pbs", token)
|
||||
}},
|
||||
{"container", func(token string) string {
|
||||
return BuildContainerRuntimeAgentInstallCommand("https://pulse.example", token, false)
|
||||
}},
|
||||
}
|
||||
}
|
||||
|
||||
// PATH contains only the prerequisite tools and our closed download/privilege
|
||||
// fixtures. The real controlling PTY is never a customer or appliance terminal.
|
||||
// Explicit proof inputs can supply the exact static BusyBox used on CI hosts.
|
||||
func portableBootstrapFixture(t *testing.T, mode string) (string, []string) {
|
||||
t.Helper()
|
||||
root, env := bootstrapFixture(t, recordingInstaller)
|
||||
bin := filepath.Join(root, "bin")
|
||||
for _, name := range []string{"bash", "cp", "rm", "rmdir", "cat", "stat", "dirname", "touch"} {
|
||||
path, err := exec.LookPath(name)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.Symlink(path, filepath.Join(bin, name)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
if mode == "standalone" || mode == "prefer-standalone" {
|
||||
stty, err := exec.LookPath("stty")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
writeExecutable(t, filepath.Join(bin, "stty"), `#!/bin/sh
|
||||
printf '%s\n' "$*" >> "$FAKE_ROOT/tty-calls"
|
||||
case "${FAKE_TTY_FAILURE:-}:$1" in
|
||||
empty:-g) exit 0 ;;
|
||||
snapshot:-g) exit 1 ;;
|
||||
echo:-echo) exit 1 ;;
|
||||
esac
|
||||
if [ "${FAKE_TTY_FAILURE:-}" = restore ] && [ "$1" != -g ] && [ "$1" != -echo ] && [ ! -e "$FAKE_ROOT/restore-failed" ]; then
|
||||
touch "$FAKE_ROOT/restore-failed"
|
||||
exit 1
|
||||
fi
|
||||
exec `+posixShellQuote(stty)+` "$@"
|
||||
`)
|
||||
}
|
||||
if mode == "busybox" {
|
||||
path := os.Getenv("PULSE_TEST_BUSYBOX")
|
||||
if path == "" {
|
||||
var err error
|
||||
path, err = exec.LookPath("busybox")
|
||||
if err != nil {
|
||||
t.Skip("real BusyBox input unavailable; modeled tool and standalone controls still run")
|
||||
}
|
||||
}
|
||||
body, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.Mkdir(filepath.Join(root, "native"), 0700); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(root, "native", "busybox"), body, 0700); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
writeExecutable(t, filepath.Join(bin, "busybox"), `#!/bin/sh
|
||||
printf '%s\n' "$*" >> "$FAKE_ROOT/tty-calls"
|
||||
exec "$FAKE_ROOT/native/busybox" "$@"
|
||||
`)
|
||||
} else if mode == "unsupported-busybox" || mode == "prefer-standalone" {
|
||||
writeExecutable(t, filepath.Join(bin, "busybox"), `#!/bin/sh
|
||||
printf '%s\n' "$*" >> "$FAKE_ROOT/busybox-calls"
|
||||
exit 97
|
||||
`)
|
||||
}
|
||||
return root, append(env, "PATH="+bin)
|
||||
}
|
||||
|
||||
func runPortableBootstrap(t *testing.T, command, input string, env []string, history, signalName string) ([]byte, error) {
|
||||
t.Helper()
|
||||
payload, err := json.Marshal(map[string]any{
|
||||
"command": command, "input": input, "history": history,
|
||||
"signal_on_prompt": signalName, "alternate_tty": true,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
python, err := exec.LookPath("python3")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cmd := exec.Command(python, "-c", bootstrapPTYRunner)
|
||||
cmd.Stdin = strings.NewReader(string(payload))
|
||||
cmd.Env = append(os.Environ(), env...)
|
||||
return cmd.CombinedOutput()
|
||||
}
|
||||
|
||||
func assertPortableBootstrapPrivate(t *testing.T, root, token string, out []byte) {
|
||||
t.Helper()
|
||||
for _, name := range []string{"argv", "shell-history", "secret-env"} {
|
||||
body, err := os.ReadFile(filepath.Join(root, name))
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if token != "" && strings.Contains(string(body), token) {
|
||||
t.Fatalf("private input reached %s", name)
|
||||
}
|
||||
if name == "secret-env" && err == nil && string(body) != ":" {
|
||||
t.Fatal("installer received a credential through the environment")
|
||||
}
|
||||
}
|
||||
if token != "" && strings.Contains(string(out), token) {
|
||||
t.Fatal("private input was echoed")
|
||||
}
|
||||
if strings.Contains(string(out), "Bootstrap did not restore") || strings.Contains(string(out), "PTY fixture deadline expired") {
|
||||
t.Fatal("complete terminal restoration or bounded execution failed")
|
||||
}
|
||||
assertContainerBootstrapCleanup(t, root)
|
||||
}
|
||||
|
||||
func TestPrivateBootstrapPortableToolFailures(t *testing.T) {
|
||||
for _, caller := range portableBootstrapCallers() {
|
||||
for _, tc := range []struct {
|
||||
name, mode, fault, message string
|
||||
tty bool
|
||||
}{
|
||||
{"no-terminal", "absent", "", "A terminal is required to enter the token.", false},
|
||||
{"no-tool", "absent", "", "Silent token input requires stty or BusyBox stty.", true},
|
||||
{"unsupported-applet", "unsupported-busybox", "", "Cannot read terminal settings with stty or BusyBox stty.", true},
|
||||
{"empty-state", "standalone", "empty", "Cannot read terminal settings with stty or BusyBox stty.", true},
|
||||
{"failed-state", "standalone", "snapshot", "Cannot read terminal settings with stty or BusyBox stty.", true},
|
||||
{"failed-echo", "standalone", "echo", "Cannot disable terminal echo.", true},
|
||||
{"failed-restore", "standalone", "restore", "Cannot restore terminal settings.", true},
|
||||
} {
|
||||
t.Run(caller.name+"/"+tc.name, func(t *testing.T) {
|
||||
root, env := portableBootstrapFixture(t, tc.mode)
|
||||
env = append(env, "FAKE_TTY_FAILURE="+tc.fault)
|
||||
command := caller.build("issued-but-not-in-command")
|
||||
var out []byte
|
||||
var err error
|
||||
if tc.tty {
|
||||
out, err = runPortableBootstrap(t, command, "synthetic-private-token", env, "", "")
|
||||
} else {
|
||||
out, err = runBootstrap(t, command, "", env, false)
|
||||
}
|
||||
if err == nil || !strings.Contains(string(out), tc.message) {
|
||||
t.Fatalf("expected distinct fail-closed %s diagnostic; exit=%v, matched=%t", tc.name, err, strings.Contains(string(out), tc.message))
|
||||
}
|
||||
if _, err := os.Stat(filepath.Join(root, "captured-token")); !os.IsNotExist(err) {
|
||||
t.Fatal("installation preceded safe terminal restoration")
|
||||
}
|
||||
if tc.name != "failed-restore" && strings.Contains(string(out), "(paste at this prompt, not in the command): ") {
|
||||
t.Fatal("credential requested before silent input was available")
|
||||
}
|
||||
if tc.name == "failed-restore" {
|
||||
calls, err := os.ReadFile(filepath.Join(root, "tty-calls"))
|
||||
lines := strings.Split(strings.TrimSpace(string(calls)), "\n")
|
||||
if err != nil || len(lines) != 4 || lines[0] != "-g" || lines[1] != "-echo" || lines[2] != lines[3] {
|
||||
t.Fatal("cleanup did not retry the same full state with the selected tool")
|
||||
}
|
||||
}
|
||||
assertPortableBootstrapPrivate(t, root, "synthetic-private-token", out)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrivateBootstrapRealBusyBoxInput(t *testing.T) {
|
||||
for _, caller := range portableBootstrapCallers() {
|
||||
for _, tc := range []struct {
|
||||
name, input, signalName string
|
||||
failure bool
|
||||
}{
|
||||
{"ordinary", strings.Repeat("p", 32), "", false},
|
||||
{"maximum", strings.Repeat("q", 4096), "", false},
|
||||
{"overflow", strings.Repeat("r", 10000) + "-DISCARDED-CREDENTIAL", "", true},
|
||||
{"empty", "", "", true},
|
||||
{"interrupt", "\x03", "", true},
|
||||
{"hangup", "", "HUP", true},
|
||||
{"terminate", "", "TERM", true},
|
||||
} {
|
||||
t.Run(caller.name+"/"+tc.name, func(t *testing.T) {
|
||||
root, env := portableBootstrapFixture(t, "busybox")
|
||||
command := caller.build("issued-separately")
|
||||
out, err := runPortableBootstrap(t, command, tc.input, env, "", tc.signalName)
|
||||
if (err != nil) != tc.failure {
|
||||
t.Fatalf("BusyBox bootstrap result=%v, expected failure=%t", err, tc.failure)
|
||||
}
|
||||
captured, captureErr := os.ReadFile(filepath.Join(root, "captured-token"))
|
||||
if tc.failure {
|
||||
if !os.IsNotExist(captureErr) {
|
||||
t.Fatal("invalid or interrupted entry reached installation")
|
||||
}
|
||||
} else if captureErr != nil || string(captured) != tc.input {
|
||||
t.Fatal("BusyBox reader lost accepted input")
|
||||
}
|
||||
calls, err := os.ReadFile(filepath.Join(root, "tty-calls"))
|
||||
lines := strings.Split(strings.TrimSpace(string(calls)), "\n")
|
||||
if err != nil || len(lines) != 3 || lines[0] != "stty -g" || lines[1] != "stty -echo" || !strings.HasPrefix(lines[2], "stty ") {
|
||||
t.Fatal("snapshot, silent mode and full restoration did not use the selected real BusyBox applet")
|
||||
}
|
||||
assertPortableBootstrapPrivate(t, root, tc.input, out)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrivateBootstrapStandalonePreferredAndBusyBoxHistory(t *testing.T) {
|
||||
for _, caller := range portableBootstrapCallers() {
|
||||
for _, mode := range []string{"prefer-standalone", "busybox"} {
|
||||
for _, uid := range []string{"0", "1000"} {
|
||||
t.Run(fmt.Sprintf("%s/%s/uid-%s", caller.name, mode, uid), func(t *testing.T) {
|
||||
root, env := portableBootstrapFixture(t, mode)
|
||||
env = append(env, "FAKE_ID_UID="+uid)
|
||||
token := "synthetic-history-token-0123456789"
|
||||
command := caller.build(token)
|
||||
out, err := runPortableBootstrap(t, command, token, env, filepath.Join(root, "shell-history"), "")
|
||||
if err != nil {
|
||||
t.Fatalf("interactive portable bootstrap failed: %v", err)
|
||||
}
|
||||
history, err := os.ReadFile(filepath.Join(root, "shell-history"))
|
||||
if err != nil || !strings.Contains(string(history), command) || !strings.HasSuffix(string(history), "exit\n") {
|
||||
t.Fatal("caller did not record the complete command and regain the terminal")
|
||||
}
|
||||
captured, err := os.ReadFile(filepath.Join(root, "captured-token"))
|
||||
if err != nil || string(captured) != token {
|
||||
t.Fatal("interactive private handoff lost input")
|
||||
}
|
||||
if _, err := os.Stat(filepath.Join(root, "busybox-calls")); !os.IsNotExist(err) {
|
||||
t.Fatal("failed standalone tool selection fell back to another utility")
|
||||
}
|
||||
assertPortableBootstrapPrivate(t, root, token, out)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrivateBootstrapSinglePrivilegedBody(t *testing.T) {
|
||||
for _, caller := range portableBootstrapCallers() {
|
||||
t.Run(caller.name, func(t *testing.T) {
|
||||
command := caller.build("private-not-in-command")
|
||||
if strings.Count(command, "bash -c ") != 1 || !strings.Contains(command, `then set --; else set -- sudo; fi;`) || !strings.Contains(command, `"$@" bash -c `) {
|
||||
t.Fatal("private reader is duplicated or root/sudo prefix escaped its subshell")
|
||||
}
|
||||
if len(command) >= 4096 || strings.ContainsAny(command, "\r\n") {
|
||||
t.Fatalf("ordinary single-line command does not fit the common terminal limit: %d bytes", len(command))
|
||||
}
|
||||
t.Logf("ordinary %s command: %d bytes", caller.name, len(command))
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user