背景
最近有个需求,需要去拦截公司内不规范的提交,因此选择在 server 端去做,但由于有很多台 gitlab,各个版本都有,从 7-13,但唯独在 8.13.6 版本部署时,发现 gitlab 上的保护分支失效了。
问题描述
gitlab 8 由于版本比较低,与高版本不一样,server 端的 hook 在单个仓库下是用的软链接的方式,如下图:
因此,全局的拦截需要放在软链的 hooks 目录下的 pre-receive 文件中,拦截的场景就是用户名配置的不规范及提交信息不规范,就会拦截。然后发现保护分支失效,任何人都能向该仓库提交代码。
问题解决
1、经过排查,发现 gitlab8 在原有的 pre-receive 文件中,有一些内容,经过仔细查看,发现是在这块做的保护分支拦截,内容如下:
#!/opt/gitlab/embedded/bin/ruby
# Fix the PATH so that gitlab-shell can find git-upload-pack and friends.
ENV['PATH'] = '/opt/gitlab/bin:/opt/gitlab/embedded/bin:' + ENV['PATH']
#!/usr/bin/env ruby
# This file was placed here by GitLab. It makes sure that your pushed commits
# will be processed properly.
refs = $stdin.read
key_id = ENV.delete('GL_ID')
protocol = ENV.delete('GL_PROTOCOL')
repo_path = Dir.pwd
print refs
require_relative '../lib/gitlab_custom_hook'
require_relative '../lib/gitlab_reference_counter'
require_relative '../lib/gitlab_access'
# It's important that on pre-receive `increase_reference_counter` gets executed
# last so that it only runs if everything else succeeded. On post-receive on the
# other hand, we run GitlabPostReceive first because the push is already done
# and we don't want to skip it if the custom hook fails.
if GitlabAccess.new(repo_path, key_id, refs, protocol).exec &&
GitlabCustomHook.new(key_id).pre_receive(refs, repo_path) &&
GitlabReferenceCounter.new(repo_path).increase
exit 0
else
exit 1
end
复制代码
发现 gitlab8 居然是在这个脚本里去拦截保护分支的提交,而我们的脚本里只做了我们自己的拦截,并没有考虑这块,因此导致保护分支失效,因此,考虑将这个脚本与我们的拦截脚本融合,但这个脚本是用 ruby 写的,我们的拦截脚本是用 python 写的,而我对 ruby 也不了解,因此直接改写比较困难,因此选择折中的方式,将两个脚本在 shell 脚本中依次调用。
2、将 gitlab8 原有的 pre-receive 重命名为 pre-receive.origin,而我们的拦截脚本使用 pyinstaller 打成二进制文件了,因此改写 pre-receive 内容为:
#!/bin/bash
res=`/opt/gitlab/embedded/bin/ruby /opt/gitlab/embedded/service/gitlab-shell/hooks/pre-receive.origin`
flag=$?
if [ $flag -eq 0 ];
then
echo "pass", $flag
else
exit $flag
fi
echo "返回值", $res
ARR=($res)
parentCommitId=${ARR[0]}
currentCommitId=${ARR[1]}
branch=${ARR[2]}
/opt/gitlab/embedded/service/gitlab-shell/hooks/py-pre-receive $parentCommitId $currentCommitId $branch
复制代码
3、注意事项
因为两个脚本都有从标准输入读 commit id 及分支信息,当第一次读完后,第二次拿到的为空,因此会导致脚本报错,因此在第一个脚本中,将这三个变量输出,然后拿到后,再传到第二个脚本中,从而解决这个问题,最后经过调试,成功解决问题。
评论