问题的产生
有个项目php网站部署的服务器时Windows Server环境(不要问我为什么....),php运行于openresty-nginx,代码托管与gitee.com。网站自动部署方案为:gitee.com上为项目配置部署的公钥和WebHooks,网站中的php页面响应gitee.com下的钩子,然后调用exec执行"git pull"。
但是不知道哪一天,这个自动化部署方案突然崩了.....,跟踪了一下php页面中“git pull”的结果,居然无权限访问远程仓库:
fatal: Could not read from remote repository.
Please make sure you have the correct access rights
and the repository exists.
奇怪,之前一直正常的过程,为什么突然git没权限了?
分析与验证
仔细回想,服务器的nginx刚刚替换成了openresty-nginxj,再仔细检查,nginx进程和php进程的用户,是SYSTEM,不是Administrator。而Git Bash默认的用户是Administrator,默认的ssh配置也仅Administrator有。也就是说,php中exec 执行“git pull”时,是没有ssh秘钥配置的另一个用户:SYSTEM。
为了验证这个猜想,我在php中exec调用"whoami",检查输出结果,不出所料,输出了:
nt authority\system
通过在php中exec调用"cd ~ && pwd",找到了SYSTEM用户的HOME目录:"C:\Windows\System32\config\systemprofile"
再检查system用户有没有默认的.ssh目录以及秘钥文件,果然没有。
最后
为system用户配置全套的ssh秘钥,并在gitee.com上重新配置部署公钥,问题得到解决。
附上php端响应gitee.com钩子实现自动拉取的代码(部分参考了:https://gist.github.com/ada10fl2/9118419):
<html>
<head>
</head>
<body>
<?php
$header = get_all_header(); //获取头信息
$json = json_decode(file_get_contents('php://input'), true); //解析json
$filename = "logs/log".date("Ymdhis").".txt";
$resp_name = "prj"; // 替换成你自己的仓库名称
$branch = "refs/heads/release"; // 替换成你想要拉取的分支名称
//验证信息是否正确
if (strcmp($header["user-agent"], "git-oschina-hook")==0 &&
strcmp($json["hook_name"], "push_hooks")==0 &&
strcmp($json["repository"]["name"], $resp_name)==0 &&
strcmp($json["ref"], $branch) == 0)
{
// 下面这些路径,请根据你自己的安装位置修改
$l_git = "/d/Program Files/Git/bin/git.exe";
$l_sshadd = "/d/Program Files/Git/usr/bin/ssh-add.exe";
$w_agent = "D:\\Program Files\\Git\\usr\\bin\\ssh-agent.exe";
$w_bash = "D:\\Program Files\\Git\\bin\\bash.exe";
$l_cmd = "'\"$l_sshadd\" /path/to/your/rsa; "
. "\"$l_git\" pull'";
$exec = "\"$w_agent\" \"$w_bash\" -c $l_cmd 2>&1";
echo "Runnning...\n<br>";
$t0 = microtime(true);
echo "<pre>$exec</pre>";
$logs = shell_exec($exec);
echo ($logs);
$t = round(microtime(true) - $t0,3)*1000;
echo "<br>Done: $t ms";
//输出git结果到log.txt
file_put_contents($filename, "\n[git output]\r\n ".$logs."\n");
}
else
{
$logs = "user-agent:" . $header["user-agent"] . "\r\n";
$logs = $logs . "hook_name:" . $json["hook_name"] . "\r\n";
$logs = $logs . "repository name:" . $json["repository"]["name"] . "\r\n";
$logs = $logs . "branch name:" . $json["ref"] . "\r\n";
file_put_contents($filename, "\n[log]\r\n".$logs."\n");
echo ($logs);
}
http_response_code(200);;
exit("");
function get_all_header()
{
$ignore = array('host','accept','content-length','content-type');
$headers = array();
foreach($_SERVER as $key=>$value)
{
if (substr($key, 0, 5)==='HTTP_')
{
$key = substr($key, 5);
$key = str_replace('_', ' ', $key);
$key = str_replace(' ', '-', $key);
$key = strtolower($key);
if(!in_array($key, $ignore)){
$headers[$key] = $value;
}
}
}
return $headers;
}
?>
</body>
</html>
代码比较粗糙,大家有好的改进可以贴在下面👇,谢谢😁。