From ee16268ac439f89b15be7cb7f435793baa050c4c Mon Sep 17 00:00:00 2001 From: Glenn Rempe Date: Tue, 30 Jun 2015 11:19:37 -0700 Subject: [PATCH] Add KeybaseDirSign pre-commit hook + tests. See https://keybase.io Signs all of the directory contents (except that which is excluded in .gitignore) with an OpenPGP compliant cryptographic signature. This creates a SIGNED.md file in the root of the repository. This file also gets added to the git index prior to commit. Note, due to the way keybase works, if there are files or changes in the working dir that are not being committed they will still be included with the signature. In that case someone running 'keybase dir verify' will not get a clean verify since their directory does not match exactly. It is best to stash away work dir contents prior to commit if concerned about this. --- config/default.yml | 7 ++++ .../hook/pre_commit/keybase_dir_sign.rb | 25 ++++++++++++ .../hook/pre_commit/keybase_dir_sign_spec.rb | 38 +++++++++++++++++++ 3 files changed, 70 insertions(+) create mode 100644 lib/overcommit/hook/pre_commit/keybase_dir_sign.rb create mode 100644 spec/overcommit/hook/pre_commit/keybase_dir_sign_spec.rb diff --git a/config/default.yml b/config/default.yml index 21528458..e5d53b49 100644 --- a/config/default.yml +++ b/config/default.yml @@ -266,6 +266,13 @@ PreCommit: install_command: 'gem install json' include: '**/*.json' + KeybaseDirSign: + enabled: false + description: Signing directory contents with Keybase + required_executable: 'keybase' + flags: ['dir', 'sign', '--quiet'] + install_command: 'npm install -g keybase-installer && keybase-installer' + LocalPathsInGemfile: enabled: false description: 'Checking for local paths in Gemfile' diff --git a/lib/overcommit/hook/pre_commit/keybase_dir_sign.rb b/lib/overcommit/hook/pre_commit/keybase_dir_sign.rb new file mode 100644 index 00000000..ff4ec2fe --- /dev/null +++ b/lib/overcommit/hook/pre_commit/keybase_dir_sign.rb @@ -0,0 +1,25 @@ +module Overcommit::Hook::PreCommit + # Runs `keybase dir sign` and `git add SIGNED.md` to sign the dir contents + # with an OpenPGP cryptographic signature. Signs *all* files, not just + # those that are part of the current commit. + # + # @see https://keybase.io/ + class KeybaseDirSign < Base + def run + keybase_result = execute(command) + keybase_output = keybase_result.stdout.chomp + + if keybase_result.success? && keybase_output.empty? + git_result = execute(['git', 'add', 'SIGNED.md']) + git_output = git_result.stdout.chomp + + if git_result.success? && git_output.empty? + return :pass + end + [:fail, git_result.stderr] + end + + [:fail, keybase_result.stderr] + end + end +end diff --git a/spec/overcommit/hook/pre_commit/keybase_dir_sign_spec.rb b/spec/overcommit/hook/pre_commit/keybase_dir_sign_spec.rb new file mode 100644 index 00000000..cbdd7094 --- /dev/null +++ b/spec/overcommit/hook/pre_commit/keybase_dir_sign_spec.rb @@ -0,0 +1,38 @@ +require 'spec_helper' + +describe Overcommit::Hook::PreCommit::KeybaseDirSign do + let(:config) { Overcommit::ConfigurationLoader.default_configuration } + let(:context) { double('context') } + subject { described_class.new(config, context) } + + context 'when keybase exits successfully' do + before do + result = double('result') + result.stub(:success?).and_return(true) + result.stub(:stdout).and_return('') + subject.stub(:execute).and_return(result) + end + + it { should pass } + end + + context 'when keybase exits unsucessfully' do + let(:result) { double('result') } + + before do + result.stub(:success?).and_return(false) + result.stub(:stdout).and_return('') + subject.stub(:execute).and_return(result) + end + + context 'and it reports an error' do + before do + result.stub(:stderr).and_return([ + 'an error' + ].join('\n')) + end + + it { should fail_hook } + end + end +end