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