Files
TallyNote/tests/helpers/pty-run.py
T
Qiufeng ab2d24a5c7
TallyNote release / linux-x64 (push) Successful in 6m11s
fix: keep manually set admin password, echo SSH input
- manual admin password no longer forces first-login change
- --generate still requires password change on first login
- add --mark-password-configured to repair legacy flag
- echo interactive username/password input in SSH terminal
- installer prints absolute admin-init path (sudo secure_path compat)
- use python3 pty helper for CI tests (no expect on Linux)
release: 1.2.9
2026-09-10 18:04:06 +08:00

67 lines
2.0 KiB
Python
Executable File

#!/usr/bin/env python3
"""Minimal cross-platform pty driver for the admin-init CLI tests.
Forks a child on a real pseudo-terminal so the CLI sees a TTY and runs its
raw-mode password prompts. Forwards a prepared input file to the child's stdin
and copies child output to stdout. Writes the child's exit code to a file so
the Node test can read it deterministically.
Used instead of `expect` (not installed on CI) or BSD `script` (injects a stray
EOT byte when stdin is a regular file, corrupting the first prompt value).
"""
import os
import pty
import select
import sys
argv = sys.argv[1:]
exit_file = os.environ.get("PTY_EXIT_FILE", "")
stdin_file = os.environ.get("PTY_STDIN_FILE", "")
pid, master = pty.fork()
if pid == 0:
# Child: replace with the target command. argv[0] is an absolute node path.
os.execvp(argv[0], argv)
os._exit(127)
in_fd = os.open(stdin_file, os.O_RDONLY) if stdin_file else -1
open_stdin = in_fd >= 0
try:
while True:
fds = [master]
if open_stdin:
fds.append(in_fd)
try:
readable, _, _ = select.select(fds, [], [], 30.0)
except (OSError, ValueError):
break
if not readable:
break
if master in readable:
try:
data = os.read(master, 4096)
except OSError:
break
if not data:
break
os.write(1, data)
if open_stdin and in_fd in readable:
data = os.read(in_fd, 4096)
if data:
os.write(master, data)
else:
open_stdin = False
os.close(in_fd)
finally:
try:
_, status = os.waitpid(pid, 0)
except ChildProcessError:
status = 0
code = os.waitstatus_to_exitcode(status) if hasattr(os, "waitstatus_to_exitcode") else (status >> 8)
if exit_file:
try:
with open(exit_file, "w") as handle:
handle.write(str(code))
except OSError:
pass