Shell “如何修复”;不会分配伪终端,因为stdin不是终端;在Alpine Linux中?

Shell “如何修复”;不会分配伪终端,因为stdin不是终端;在Alpine Linux中?,shell,docker,terminal,alpine,Shell,Docker,Terminal,Alpine,我正在编写一个运行各种shell命令的PHP程序。有时它需要调用su,根据设计,我希望它提示输入提升的特权密码。在PHP中使用passthru() 我选择只为我的程序编写功能测试,因为它依赖于ssh、su和其他shell命令。因此,我想在PHPUnit中运行真实的东西,看看它是否如我所期望的那样工作 因为这需要SSH服务器和用户帐户配置,所以我设置了在Docker中运行的测试。这种方法看起来会很好——映像生成,运行时调用PHPUnit,然后退出。我希望有一种方法可以通过Docker将结果返回给调

我正在编写一个运行各种shell命令的PHP程序。有时它需要调用
su
,根据设计,我希望它提示输入提升的特权密码。在PHP中使用
passthru()

我选择只为我的程序编写功能测试,因为它依赖于
ssh
su
和其他shell命令。因此,我想在PHPUnit中运行真实的东西,看看它是否如我所期望的那样工作

因为这需要SSH服务器和用户帐户配置,所以我设置了在Docker中运行的测试。这种方法看起来会很好——映像生成,运行时调用PHPUnit,然后退出。我希望有一种方法可以通过Docker将结果返回给调用系统,例如Travis CI

我选择了Alpine Linux作为我的基本Docker映像,但我在终端分配方面遇到了问题。我原本以为PHPUnit会碍事(请参阅此问题的原始版本),但现在我将其缩小到SSH,可以通过PHP运行,也可以仅在控制台上运行

这很好:

su -c whoami
$ ssh localhost -t 'su -c whoami'
Password: 
root
Connection to localhost closed.
然而,这并不是:

ssh localhost -t 'su -c whoami'
我得到:

苏:必须使用suid才能正常工作
与本地主机的连接已关闭

请注意,
ssh
设置为对本地主机进行无密码访问(出于测试目的),因此我希望输入的唯一密码是
su
密码

ssh
手册建议
-f
有助于询问密码的位置(开关“在命令执行之前请求ssh转到后台”),因此我尝试以下方法:

ssh localhost -t -f 'su -c whoami'
我得到:

不会分配伪终端,因为stdin不是终端。
4275760bde94:~$su:必须suid才能正常工作

啊,又错了!好的,特别是强制一个终端:

ssh localhost -tt -f 'su -c whoami'
double-t仍然对SUID发出抱怨,仍然不起作用

但是,如果我在我的Ubuntu开发机器(也配置了PPK访问self)上执行此操作,它可以正常工作:

su -c whoami
$ ssh localhost -t 'su -c whoami'
Password: 
root
Connection to localhost closed.
这让它看起来像是阿尔卑斯或BusyBox的OpenSSH出了问题。我怎样才能更深入地了解这一点

一个解决方案是换到另一个基本发行版,Ubuntu肯定会工作得很好,但这将大大增加我的Docker图像大小(目前总计6800万)。所以,如果可以的话,我想坚持一下阿尔卑斯山

不太可能是码头工人 我确实想知道Docker是否会阻止创建或连接终端,但很快就打消了这个念头,因为我可以使用
Docker exec-it container\u name sh
获得一个交互式shell。此外,我可以在Docker shell中的两个单独的命令中完成
ssh
su

巴什帮不上忙 我注意到Bash在Alpine中可用,但这也没有帮助,这让我感到惊讶:

/ $ apk add bash
bash-4.3$ bash
bash-4.3$ su nonpriv
bash-4.3$ ssh localhost whoami
nonpriv
bash-4.3$ ssh localhost 'su -c whoami'
su: must be suid to work properly
bash-4.3$ ssh localhost 'su -s /bin/bash -c whoami'
su: must be suid to work properly
bash-4.3$ ssh -t localhost 'su -s /bin/bash -c whoami'
su: must be suid to work properly
Connection to localhost closed.
bash-4.3$ ssh -tt localhost 'su -s /bin/bash -c whoami'
su: must be suid to work properly
Connection to localhost closed.
bash-4.3$ ssh -tf localhost 'su -s /bin/bash -c whoami'
Pseudo-terminal will not be allocated because stdin is not a terminal.
bash-4.3$ su: must be suid to work properly

bash-4.3$ ssh -ttf localhost 'su -s /bin/bash -c whoami'
bash-4.3$ su: must be suid to work properly
Connection to localhost closed.
试壳插值 我发现这几乎是可行的:

/ $ ssh -t localhost "$( su -c whoami )"
sh: Password:: not found
sh: root: not found
Connection to localhost closed.
这使用了标准的Alpine
sh
shell,并使用了上述链接中的
“$()”
构造,我并不完全理解。它输出
密码:
,这是
su
中的提示,然后等待密码。输入密码后,运行
whoami
,打印
root

所以它看起来像是在运行命令,但我不确定它是否立即运行
whoami
,然后将其传递给
ssh
(不是我想要的),或者它是否正在将一个远程shell发送到localhost,然后再执行它(这是我的意图)


在任何情况下,它都试图运行标准输出行,就好像它们本身就是命令一样。我怎样才能只打印通过SSH运行的输出?

在我的问题中,我猜这将在Ubuntu容器中工作,这被证明是正确的。有趣的是,我仍然会收到“必须从终端运行”错误:

su -c whoami
但不是在这里,在SSH无密码命令中将终端显式分配给self:

ssh -t localhost 'su -c whoami'

不幸的是,新的操作系统把我68M的图像提升到了430M,呃!因此,我很高兴能收到新的答案,让这个问题在阿尔卑斯山上得到解决。

我真的不知道,但出于对完整性的好奇,你的测试是什么样子的?谢谢@Jeff,事实证明问题不在PHPUnit。它确实会妨碍及时触发
expect
的输出,但我可以通过超时来缓解这种情况。问题似乎在于Alpine如何允许命令包含在
ssh
命令中。我想知道SSH中是否有我遗漏的标志。当我有时间的时候,我会简化这个问题,因为PHPUnit的事情似乎是一条红鲱鱼。乍一看,这可能是一个错误,但那里的解决方案不起作用。我想知道我是不是在看一个阿尔卑斯山特有的问题?我重写了这个问题,把重点放在我认为问题的核心。