Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
A Git Horror Story: Repository Integrity With Signed Commits (mikegerwitz.com)
89 points by primroot on June 1, 2014 | hide | past | favorite | 25 comments


    > What shall we do, then, if we receive a pull request for a 
    > certain feature or bugfix with, say, 300 commits
    > 1. Request that the user squash all the commits into a
    >    single commit
    > 2. Adopt a security policy that requires signing only the
    >    merge commit (forcing a merge commit to be created with
    >    --no-ff if needed).
    > 3. Sign each commit to be introduced by the merge.
Or, tell them to rebase their branch on master, while cleaning up all their "oops", "revert", "typo", "debug" and whatnot commits; resulting in a sane history and 20 commits to be signed. I find this oversight especially sarcastic as he mentions how 2. ruins git bisect, while such uncleaned 300 commit branches ruin it just as effectively, as you can never be quite sure whether the commit you arrive at isn't reverted by one 20 commits later and the real issue was introduced another 20 commits later.


Maybe that feature actually took 300 "real" commits to finish. Squashing good commits also makes bisect hard because while yes it's easier to find the right commit, that commit now has conflated functionality which makes tracking down the issue within it harder.


I assumed the author means 300 legit, cleaned up commits.


To be honest, i feel like git really needs better wrappers or a better GUI or better defaults. There shouldn't be a quadrillion command flags to know for simple tasks like this. And i don't mean the -S but the "use -S instead of -s but for other things use -asm, oh and then you have command xyz which takes --<long option> followed by other options, but only use those if your SHA hash can be divided by 3.141 and it's full moon".


Git is the subject of, in my opinion, some quality satire in this respect:

http://git-man-page-generator.lokaltog.net/


Try using tig, it will make looking at a repositories history so much easier for you. It's like git log and diff merged together in a command line utility of awesomeness.


For Windows there exists TortoiseGIT, sorta fork of TortoiseSVN. Not sure if anything similar exists on Linux or if it could even be done the easy way ("right-click in explorer"), due to the multitude of file explorers/desktop environments.


Linux GUIs are rather poor and usually you just use the CLI.

It's only that i miss sane defaults and a common sense of workflow amongst the community. Currently it's this huge toolbox that can do everything in thousand ways, but to be honest, i don't want to be able to "get my copy of the sourcecode to the server" in a gazillion ways, i would very much prefer one way and one simple command. If you start googling for "how do i do X in git" you will find 10 ways to do X and 100 philosphical discussions why you should do X in a specific way and about "what would Jes^H^H^H Linus do?". For example, i'd love to have "git init" ask your name, email, if you'd like to sign with GPG, etc. etc. and then save this in git, so that every git commit will be signed with GPG without giving that stupid option. The common way a la "Git" would be to introduce bash aliases, i think. But that doesn't work across machines, OSs or even on the same machine in a different shell.


You can add aliases to ~/.gitconfig (the file created by 'git config --global'). See mine:

  [alias]
    lg  = log --graph --decorate
    llg = log --oneline --graph --decorate
    ll  = log --oneline

    dc = diff --cached
    st = status --short
    ci = commit
    rb = rebase
    br = branch
    co = checkout
Then you can just run (e.g.):

  $ git llg




You're supposed to sign a tag because you've reviewed that tag, not just at random. A commit is much less meaningful - do you always check the diff before you commit?


Do people not check the diff before they commit?


I almost always check the diff before committing (I use git diff --cached more often than plain git diff)


`git config alias.staged 'diff --cached'` was the first alias I ever created.

Even for one-line changes I compulsively check `git staged` before committing.


Wasn't this posted a couple months ago?


Any discussion of how projects like monotone defeat this?


Alternative advice that helps avoid this problem:

Do code reviews.

Write tests.


Code reviews don't do anything to solve issues where an attacker manipulates the repository after the commits are already there. To solve that, you'd have to do reviews of existing commits well after they go in, I think?

I don't see how test cases would fix this either. The attacker can break the test case just as easily as they can insert a backdoor.


You can't rewrite history in git, that's what the shas are there for. An attacker who gains access to a repo can add new commits, but not tamper with the existing ones.


While it's definitely possible to re-write commits, a reasonably strong protection against this is to treat a force-pull of master as a stop-the-world-and-figure-out-what-the-hell-happened type of catastrophe.


Yes you absolutely can rewrite history.


No, you can't. You can create a new history, you can't edit an existing one.

To clarify: You can, e.g., use interactive rebase to remove a commit from a branch. But that creates a new HEAD with a different SHA - this is why rebasing published branches is such a bad thing.

The parent was implying you could change history without anyone noticing. This implies modifying a previous commit whilst keeping the current HEAD the same, which can't be done.


If the attacker has access to your remote repo then isnt that the problem? You can sign your commits all day but you have more serious issues to attend to.


At least if things go horribly wrong, by having all your commits signed you can instantly point out where the illicit tampering happened and have some proof that the illicit change wasn't willingly added by you

I started to sign all my commits in bzr, hg and git since more than 1 year, and it's very easy to do it: you should try to do it as well

(I disagree with Linus and other people who argue that you should just sign the merge commits, since otherwise you'd be "inflationing"/reducing the value of signatures if you'd sign everything: it would be like only signing the very important messages with gpg, and not doing it for the remaining majority: it's fine if you want to have deniability for your unsigned messages, but that's not what I want for my commits: ideally I'd want all of the changes to be auditable)




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: