设为首页收藏本站

LUPA开源社区

 找回密码
 注册
文章 帖子 博客
LUPA开源社区 首页 业界资讯 技术文摘 查看内容

Git使用中的教训:签名提交确保代码完整可信

2014-9-23 10:53| 发布者: joejoe0332| 查看: 7800| 评论: 0|原作者: 几点人, 无若, petert, Sophietyl, f4f, sg90, 请叫我益达张|来自: oschina

摘要: GIT是一款分布式版本控制系统。简而言之,这意味着任何人可以私自拥有一份你的仓库的副本(copy)进行线下工作。他们可能提交版本到自己的仓库,也可以相互之间进行push和pull。中心仓库对分布式版本控制系统来说不是 ...


大量合并的管理

到此刻为止,我们讨论的都是应用补丁或者合并单个提交。接下来,假设我们接收到一个对有300个提交的(我向你保证这么做很正常)某个功能或者漏洞修补的pull请求,我们该怎么做的?这时我们可以选择下面其中的一种方法:

  1. 要求用户把所有的提交压缩为单个提交,这么做可以避免使用前面讨论方法时所出现的问题。不过我个人由于以下原由不愿意采用这一方法:

    • 我们不能再追踪到功能或者漏洞修补的历史,从而不能够了解到开发如何进行或者说不能够看到开始采用后来替代的其他处理方法。

    • 这么做使得git bisect无法使用。如果我们要查找由压缩300个提交为单个补丁而引起的软件漏洞,我们将需要亲自进行代码阅读和调试,而不是可能让Git给我们指出问题所在。

  2. 增加这样的安全策略:要求只给合并提交进行签名(如果需要的话,可以通过使用--no-ff强制进行合并提交)。

    • 这当然是最快的解决方案,它允许代码审核人员在对全部代码的存在差异的部分审核后对合并进行签名。

    • 不过这也让个人随时可以进行提交。例如,某个提交引入了负荷,但这个负荷要在未来的某个提交中删除,因此为了防止提交引起与整体代码出现差异,并且会引入极坏的结果,那么就应当对这样的提交进行单独审核(比如,通过git bitsect)。压缩所有的提交(方法1),对每个提交分别进行签名(方法3),或者在执行(不必对每个提交进行签名的)合并前只要对每个提交进行审核就可以避免这个问题的发生。

    • 这一方法还不能完全阻止在这篇文章开始时虚构的故事中出现的哪种情形 --- 其他人仍然可以以你作者的名义进行提交,而且这样的提交不需要签名。

    • 给每个单独的提交保存一份SHA-1哈希值。

  3. 对合并所涉及的每个提交都进行签名

    • 这一处理方法中的繁琐枯燥的工作可以通过使用gpg-agent而大大地减少。

    • 要确保对每个提交都进行仔细的审核,而不是对整体上有差异的地方进行审核,这样才能确保不会有任何恶意提交偷偷的出现在提交历史里(参考方法2中的各项说明)。如果你不想对每个差异之处进行审核,而只想通过脚本对每个提交进行签名,那么你可以考虑一下方法2

    • 如果你要挑选出最好的单个提交,那么这种方法就非常适合,因为这种方法结果就是所有的提交都进行了签名。

    • 你可能辩论说这种方法存在不必须的多余的处理,认为你只要对没有签名的单个提交进行审核,然后再对合并提交进行签名就可以表明所有的提交都经过了审核(方法2)。这儿要提到的最重要的一点是:这一方法为所有审核了的提交提供了证明(除非自动进行提交,那是就不会出现审核)。

    • 这一方法为每个提交创建了一份新的SHA-1哈希值(这个哈希值不会保存)。

你选择三种方法中的哪一个取决于具体项目中哪个因素最重要且最可行。特别是:

  • 如果历史信息对你来说不怎么重要,那么你只要要求压缩所有提交(方法1)就可以避免许多麻烦。

  • 如果历史信息对你很重要,而且你没有足够的时间审核各个提交:

    • 如果你明了方法2的风险,那么就可以采用方法2。

    • 否则,采用方法3,但是不要自动进行签名处理,这样你才能查看到每个提交。如果你希望保存历史信息,那么请这么做。

上面罗列的方法1可以很容易地解决前一节的所讨论的问题。


(方法2)

方法2就像给git merge传递-S参数那样简单。如果合并运行的非常快(也就是说,所有的提交都只是对HEAD进行修改,而没有进行任何合并),那么你就必须使用--no-ff选项,强制进行合并提交。

# set up another branch to merge 
$ git checkout -b bar
$ echo bar > bar
$ git add bar
$ git commit -m 'Added bar' 
$ echo bar2 >> bar
$ git commit -am 'Modified bar' 
$ git checkout master  

# perform the actual merge (will be a fast-forward, so --no-ff is needed) 
$ git merge -S --no-ff bar
 # ^ GPG-sign merge commit You need a passphrase to unlock the secret key for 
user: "Mike Gerwitz (Free Software Developer) <mike@mikegerwitz.com>" 
4096-bit RSA key, ID 8EE30EAB, created 2011-06-16 

Merge made by the 'recursive' strategy.
  bar | 2 ++ 
 1 file changed, 2 insertions(+)
 create mode 100644 bar

查看日志,你会看到以下内容:

$ git log --show-signature
commit ebadba134bde7ae3d39b173bf8947a69be089cf6
gpg: Signature made Sun 22 Apr 2012 11:36:17 AM EDT using RSA key ID 8EE30EAB
gpg: Good signature from "Mike Gerwitz (Free Software Developer) <mike@mikegerwitz.com>"
Merge: 652f9ae 031f6ee
Author: Mike Gerwitz <mike@mikegerwitz.com>
Date: Sun Apr 22 11:36:15 2012 -0400

  Merge branch 'bar' 

commit 031f6ee20c1fe601d2e808bfb265787d56732974
Author: Mike Gerwitz <mike@mikegerwitz.com> 
Date: Sat Apr 21 17:35:27 2012 -0400

  Modified bar

commit ce77088d85dee3d687f1b87d21c7dce29ec2cff1
Author: Mike Gerwitz <mike@mikegerwitz.com> 
Date: Sat Apr 21 17:35:20 2012 -0400

  Added bar
# [...]

注意合并提交包含了签名,而合并所涉及的两个提交(031f6ee和ce77088)却不包含签名。这就是问题所在---如果提交031f6ee中含有文章一开始所讲述的故事中提到的后门,该怎么做呢?这个提交可以认为是你授权的,然而由于没有签名,所以这样的提交可以由任何人授权。再者,如果提交ce77088里含有已经在031f6ee提交里删除的恶意代码,那么在对两个代码分支进行差异化比较时就不会把恶意代码呈现出来。不过,这是另一个需要安全策略定位的问题。你是否要审核每个提交呢? 如果这么做,那么对提交审核时就会发现任何潜在的问题,同时不需要单独对每个提交进行签名。合并本身就表示"是的,我已经对每个提交单独进行了审核,并没有发现这些修改带了了任何问题。"

如果单独对每个提交进行审核承担的责任太大,那么请考虑使用 方法1


(方法3)

上面所列的方法3很明确也很显然要多每个提交进行审核;而方法2只要求你懒洋洋的瞥一下提交或者根本连瞥一下都不需要。也就是说,你可以在方法3里通过自动对每个提交进行签名做同方法2一样的事情,不过这样就可能认为完全不需要方法3。使用哪一方法,你自己评判。

要使的方法3远端可执行,尤其是在含有大量提交的情况下仍然能够远端可执行方法3的唯一方法是要做到这一点:针对每一次提交,我们都不需要重新输入密钥所对应的密码。要做到这一点,我们需要使用 gpg-agent,它会安全地把密码存储在内存中,以便下一次请求时使用。通过使用gpg-agent,我 们就可以只提示一次输入密码。依据gpg-agent的不同启动方式,你一定要确保在完成工作后以不同的方式杀死该进程!


可以采用许多种方法对每个提交进行签名。总的来说,由于对一个提交进行签名就意味着有一个全新的提交,那么选择哪种签名方法就显得有那么一点重要了。例如,如果你愿意,那么你可以选择每个提交,然后给每个提交加上-S --amedn选项,不过不会把这些提交看作一次合并,而且(除非合并运行的非常快,否则)在查看分支的历史信息的时候会非常迷惑。因此,(再次强调一下,除非合并提交运行的非常快,否则)我们将确定一个能够生成合并提交的方法。实现这个的一种方法就是交互式地对每个提交进行基线更新,这样你就可以非常容易地查看到代码差异,给提交签名,继续在该提交的基础上进行下一个提交。

# create a new audit branch off of bar 
$ git checkout -b bar-audit bar
$ git rebase -i master 
# | ^ the branch that we will be merging into 
# ^ interactive rebase (alternatively: long option --interactive)

首先,我们根据bar代码分支创建一个新的代码分支---bar-audit----可以对其进行基线更新(参考说明 方法2中创建的bar代码分支)。然后,为了能够逐个执行合并到master中的每个提交,我们需要执行一个把master当作上级分支的基线更新。这将会显示哪些bar-audit(实际上是bar)里有的而master里没有的所有提交,接着用你所选的编辑器打开:

e ce77088 Added bar
e 031f6ee Modified bar

# Rebase 652f9ae..031f6ee onto 652f9ae
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#  f, fixup = like "squash", but discard this commit's log message
#  x, exec = run command (the rest of the line) using shell
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#

修改这些提交,用e(或者edit)来替代所有pick,如上所示。(如果你使用的是vim,那么你还可以使用ex命令:%s/^pick/e/;根据所用编辑器,调整正则表达式格式)。保存,然后关闭。这样就会给呈现首次的(也就是最早的)提交:

Stopped at ce77088... Added bar
You can amend the commit now, with

        git commit --amend

Once you are satisfied with your changes, run

        git rebase --continue  

# first, review the diff (alternatively, use tig/gitk) 
$ git diff HEAD^  
# if everything looks good, sign it 
$ git commit -S --amend  
# GPG-sign ^ ^ amend commit, preserving author, etc 

You need a passphrase to unlock the secret key for 
user: "Mike Gerwitz (Free Software Developer) <mike@mikegerwitz.com>"  
4096-bit RSA key, ID 8EE30EAB, created 2011-06-16  

[detached HEAD 5cd2d91] Added bar 
 1 file changed, 1 insertion(+)
 create mode 100644 bar 

# continue with next commit 
$ git rebase --continue  

# repeat. 
$ ... 
Successfully rebased and updated refs/heads/bar-audit.

浏览一下日志,我们就会看到已经重写了提交,并且包含了签名(不过,SHA-1哈希值却不匹配):

$ git log --show-signature HEAD~2..
commit afb1e7373ae5e7dae3caab2c64cbb18db3d96fba
gpg: Signature made Sun 22 Apr 2012 01:37:26 PM EDT using RSA key ID 8EE30EAB
gpg: Good signature from "Mike Gerwitz (Free Software Developer) <mike@mikegerwitz.com>"
Author: Mike Gerwitz <mike@mikegerwitz.com>
Date:   Sat Apr 21 17:35:27 2012 -0400

    Modified bar

commit f227c90b116cc1d6770988a6ca359a8c92a83ce2
gpg: Signature made Sun 22 Apr 2012 01:36:44 PM EDT using RSA key ID 8EE30EAB
gpg: Good signature from "Mike Gerwitz (Free Software Developer) <mike@mikegerwitz.com>"
Author: Mike Gerwitz <mike@mikegerwitz.com>
Date:   Sat Apr 21 17:35:20 2012 -0400

    Added bar

  接下来,我们就可以像往常一样继续把代码合并到master里。下面要考虑的是是否要像方法2那样对合并提交进行签名的问题。在我们所举的例子里,合并是快速运行的,因此就没有必要进行合并提交了(由于要进行合并的提交都已经签名了,我们就不需要纯粹为了对其进行签名而使用--no-ff选项创建合并提交了)。不过,想想你亲自执行了检查而其他人进行真正的合并这种情况;也许项目是这样运行的:项目管理者必须对代码进行审核,然后对其签名,而其他开发者则负责合并和管理冲突。在这种情况下,你可能就需要对谁合并了修改有一个清新的记录。



酷毙

雷人

鲜花

鸡蛋

漂亮
  • 快毕业了,没工作经验,
    找份工作好难啊?
    赶紧去人才芯片公司磨练吧!!

最新评论

关于LUPA|人才芯片工程|人才招聘|LUPA认证|LUPA教育|LUPA开源社区 ( 浙B2-20090187 浙公网安备 33010602006705号   

返回顶部