Skip to content

Commit

Permalink
[Enhancement] Fixes #57 - Add support for client certificates
Browse files Browse the repository at this point in the history
  • Loading branch information
mdeloupy authored and benichu committed Aug 8, 2016
1 parent 123f4af commit 6aa8ba2
Show file tree
Hide file tree
Showing 13 changed files with 162 additions and 76 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@
tags
gems.tags
.DS_Store
byebug_history
1 change: 1 addition & 0 deletions .ruby-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
2.3.1
14 changes: 8 additions & 6 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
sudo: false
language: ruby
cache: bundler
rvm:
- 2.0.0
- 2.1.4
- 2.2.2
before_install: gem install bundler -v 1.10.5
script: 'bundle exec rake'
- 2.2.5
- 2.3.1
before_install:
- gem install bundler
cache: bundler

script: "bundle exec rake"
3 changes: 1 addition & 2 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
source 'https://rubygems.org'

source "https://rubygems.org"
# Specify your gem's dependencies in checklister.gemspec
gemspec
99 changes: 64 additions & 35 deletions bin/checklister
Original file line number Diff line number Diff line change
@@ -1,9 +1,22 @@
#!/usr/bin/env ruby
# CLI Tools
require "gli"
require "highline"
# Gem logic entrypoint
require "checklister"

include GLI::App

# Highline
ft = HighLine::ColorScheme.new do |cs|
cs[:question] = [ :bold, :cyan ]
cs[:info] = [ :bold, :white ]
cs[:error] = [ :magenta ]
end

HighLine.color_scheme = ft
bot = HighLine.new

ISSUE_SERVICES = { "1" => "gitlab", "2" => "github" }.freeze

program_desc "gives you the power to transform any markdown file or url checklist into an actionable gitlab and github issue."
Expand All @@ -28,20 +41,22 @@ pre do |global_options,command,options,args|
config_options = global_options
elsif config_file.exist?
saved_services = config_file.services
choice = 0
if saved_services.size > 1
puts "* Which Issue Service would you like to use?"
saved_services.each_with_index do |service, index|
line = []
line << "[#{index+1}] #{service[:endpoint]}"
line << "(#{service[:label]})" if service[:label]
puts line.join(" ")
bot.say "<%= color('Which Issue Service would you like to use?', :question) %>"
bot.choose do |menu|
menu.select_by = :index
# Options
saved_services.each_with_index do |service, index|
label = [service[:endpoint]]
label << "- #{service[:label]}" if service[:label].to_s != ""
menu.choice(label.join(" ")) { choice = index }
end
end
choice = STDIN.gets.to_i
raise("You need to select a service.") if choice < 1
else
choice = 1
choice = 0
end
service_selected = saved_services[choice-1]
service_selected = saved_services[choice]
config_options = service_selected
else
config_options = {}
Expand All @@ -65,51 +80,65 @@ desc "Save your gitlab or github settings for later"
command :setup do |c|
c.action do |global_options,options,args|
data = {}
choice = nil
config_file = Checklister::ConfigurationFile.new(global_options["config"])

if global_options[:service]
service_selected = global_options[:service]
else
puts "* Which Issue Service would you like to setup?"
ISSUE_SERVICES.each do |index, service|
puts "[#{index}] #{service}"
bot.say "<%= color('Which Issue Service would you like to setup?', :info) %>"
bot.choose do |menu|
menu.select_by = :index
# Options
ISSUE_SERVICES.each do |index, service|
menu.choice(service) { choice = index }
end
end
choice = STDIN.gets.to_i
raise("You need to select a service.") if choice < 1
service_selected = ISSUE_SERVICES[choice.to_s]
end
data["kind"] = service_selected

puts ""
puts "* We are going to help you set up the #{service_selected} service"
bot.say "<%= color('We are going to help you set up the #{service_selected} service', :info) %>"

if service_selected == "gitlab"
puts ""
puts "** What is your gitlab endpoint? (Ex: https://gitlab.com/api/v3)"
choice = STDIN.gets.chomp
raise("You need to type a endpoint.") if choice == ""
data["endpoint"] = choice
# Get the service url
data["endpoint"] = bot.ask("<%= color('What is your gitlab endpoint? (Ex: https://gitlab.com/api/v3)', :question) %>") do |q|
q.validate = /https?:\/\/[\S]+/
end

# Configure tls client certificate, if any
if bot.agree("<%= color('Does your Gitlab server require a client certificate? [y/n]', :question) %>")
# Set the endpoint certificate path
data["endpoint_certificate_path"] = bot.ask("<%= color('Please enter the path to your SSL certificate (the extension should be .crt)', :question) %>") do |q|
q.validate = /.*\S.*/
end

# Set the private certificate path
data["client_certificate_path"] = bot.ask("<%= color('Please enter the path to your private certificate (the extension should be .p12)', :question) %>") do |q|
q.validate = /.*\S.*/
end

# Set the private certificate password (not compulsory)
data["client_certificate_password"] = bot.ask("<%= color('Please enter your private certificate password', :question) %>") do |q|
q.echo = "*"
end
end
elsif service_selected == "github"
data["endpoint"] = "https://api.github.com"
end

puts ""
puts "** What is your private token with the #{service_selected} service?"
choice = STDIN.gets.chomp
raise("You need to type a private token.") if choice == ""
data["private_token"] = choice

puts ""
puts "** You can give a label to #{data["endpoint"]} (you can leave it blank too)"
choice = STDIN.gets.chomp
if choice != ""
data["label"] = choice
# Private token
data["private_token"] = bot.ask("<%= color('What is your private token with the #{service_selected} service?', :question) %>") do |q|
q.validate = /.*\S.*/
end

# Label
data["label"] = bot.ask("<%= color('You can give a label to #{data["endpoint"]} (you can leave it blank too)', :question) %>")

# Persist the configuration to file
config_file.add_service data
config_file.persist
puts ""
puts "* Your configuration data has been saved at #{global_options[:config]}"
bot.say "<%= color('Your configuration data has been saved at #{global_options[:config]}', :info) %>"
end
end

Expand Down
16 changes: 9 additions & 7 deletions checklister.gemspec
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# coding: utf-8
lib = File.expand_path('../lib', __FILE__)
lib = File.expand_path("../lib", __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'checklister/version'
require "checklister/version"

Gem::Specification.new do |spec|
spec.name = "checklister"
Expand All @@ -14,25 +14,27 @@ Gem::Specification.new do |spec|
spec.homepage = "https://github.com/benichu/checklister"
spec.license = "MIT"

spec.required_ruby_version = '>= 2.0'
spec.required_rubygems_version = '>= 1.9'
spec.required_rubygems_version = ">= 1.9"

spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
spec.bindir = "bin"
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
spec.require_paths = ["lib"]

spec.add_dependency "gitlab" , "~> 3.4.0"
spec.add_dependency "gli" , "~> 2.13"
spec.add_dependency "octokit" , "~> 4.0"
spec.add_dependency "gitlab" , "~> 3.4.0"
spec.add_dependency "gli" , "~> 2.13"
spec.add_dependency "octokit" , "~> 4.0"
spec.add_dependency "highline" , "~> 1.7"

spec.add_development_dependency "bundler" , "~> 1.10"
spec.add_development_dependency "byebug" , "~> 8.2.1"
spec.add_development_dependency "coveralls" , "~> 0.8.2"
spec.add_development_dependency "guard" , "~> 2.13"
spec.add_development_dependency "guard-rspec" , "~> 4.6"
spec.add_development_dependency "guard-ctags-bundler"
spec.add_development_dependency "rake" , "~> 10.4"
spec.add_development_dependency "rspec" , "~> 3.3"
spec.add_development_dependency "ruby_dep" , "~> 1.4"
spec.add_development_dependency "yard" , "~> 0.8"
spec.add_development_dependency "webmock" , "~> 1.21"
end
4 changes: 4 additions & 0 deletions lib/checklister.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,9 @@ def config
def configure(attributes = {})
config.apply attributes
end

def root
File.expand_path('../..',__FILE__)
end
end
end
6 changes: 5 additions & 1 deletion lib/checklister/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ def get_api_client
end

def prepare_options_for_kind(options, kind)
httparty_options = {}
if kind == "github"
# Octokit uses ENV for overide
# See: https://github.com/octokit/octokit.rb/blob/a98979107a4bf9741a05a1f751405f8a29f29b38/lib/octokit/default.rb#L136-L138
Expand All @@ -80,7 +81,10 @@ def prepare_options_for_kind(options, kind)
# :private_token is called :access_token
options[:access_token] = options.delete(:private_token)
elsif kind == "gitlab"
options.merge!(httparty: { verify: false }) # FIXME
httparty_options[:ssl_ca_file] = options[:endpoint_certificate_path] unless options[:endpoint_certificate_path].to_s == ""
httparty_options[:p12] = File.read(options[:client_certificate_path]) unless options[:client_certificate_path].to_s == ""
httparty_options[:p12_password] = options[:client_certificate_password] unless options[:client_certificate_password].to_s == ""
options.merge!(httparty: httparty_options)
end
options
end
Expand Down
4 changes: 2 additions & 2 deletions lib/checklister/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,9 @@ module Checklister
#
class Configuration
# List of all the configuration attributes stored for use within the gem
ATTRIBUTES = [:endpoint, :private_token, :label, :kind]
ATTRIBUTES = [:endpoint, :private_token, :label, :kind, :client_certificate_path, :client_certificate_password, :endpoint_certificate_path]

attr_accessor :endpoint, :private_token, :kind
attr_accessor :endpoint, :private_token, :kind, :client_certificate_path, :client_certificate_password, :endpoint_certificate_path
attr_writer :label

# Apply a configuration hash to a configuration instance
Expand Down
73 changes: 51 additions & 22 deletions spec/checklister/client_spec.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
require "spec_helper"
require "byebug"

describe Checklister::Client do
let(:gitlab_config) do
{ endpoint: "https://www.gitlab.com/api", private_token: "supersecret", kind: "gitlab" }
end

let(:gitlab_with_certificate_config) do
{
endpoint: "https://www.gitlab.com/api", private_token: "supersecret", kind: "gitlab",
endpoint_certificate_path: "#{Checklister.root}/spec/support/files/foo.crt",
client_certificate_path: "#{Checklister.root}/spec/support/files/foo.p12",
client_certificate_password: "client_certificate_password"
}
end

let(:github_config) do
{ endpoint: "https://api.github.com", private_token: "supersecret", kind: "github" }
end
Expand Down Expand Up @@ -36,35 +46,54 @@
end

context "create gitlab API client" do
subject(:gitlab_client) { Checklister::Client.new(gitlab_config).api_client }
it "initializes client" do
expect(gitlab_client).to be_a Gitlab::Client
end
context "without client certificates" do
subject(:gitlab_client) { Checklister::Client.new(gitlab_config).api_client }

it "needs a valid kind option" do
expect do
Checklister::Client.new(gitlab_config.reject { |k| k == :kind })
end.to raise_error ArgumentError, "No API client can be initialized"
end
it "initializes client" do
expect(gitlab_client).to be_a Gitlab::Client
end

it "sets the appropriate endpoint" do
expect(gitlab_client.endpoint).to eq(gitlab_config[:endpoint])
end
it "needs a valid kind option" do
expect do
Checklister::Client.new(gitlab_config.reject { |k| k == :kind })
end.to raise_error ArgumentError, "No API client can be initialized"
end

it "sets the appropriate token" do
expect(gitlab_client.private_token).to eq(gitlab_config[:private_token])
end
it "sets the appropriate endpoint" do
expect(gitlab_client.endpoint).to eq(gitlab_config[:endpoint])
end

it "sets the user agent" do
expect(gitlab_client.user_agent).to eq "Checklister for gitlab #{Checklister::VERSION}"
end
it "sets the appropriate token" do
expect(gitlab_client.private_token).to eq(gitlab_config[:private_token])
end

it "initializes a project" do
expect(Checklister::Client.new(gitlab_config).project).to be_a Checklister::Gitlab::Project
it "sets the user agent" do
expect(gitlab_client.user_agent).to eq "Checklister for gitlab #{Checklister::VERSION}"
end

it "initializes a project" do
expect(Checklister::Client.new(gitlab_config).project).to be_a Checklister::Gitlab::Project
end

it "initializes an issue" do
expect(Checklister::Client.new(gitlab_config).issue).to be_a Checklister::Gitlab::Issue
end
end

it "initializes an issue" do
expect(Checklister::Client.new(gitlab_config).issue).to be_a Checklister::Gitlab::Issue
context "with a client certificate" do
subject(:gitlab_client) { Checklister::Client.new(gitlab_with_certificate_config).api_client }

it "set the ssl_ca_file" do
expect(gitlab_client.httparty[:ssl_ca_file]).to eq(gitlab_with_certificate_config[:endpoint_certificate_path])
end

it "set the client certificate path" do
expect(gitlab_client.httparty[:p12]).to eq(File.read(gitlab_with_certificate_config[:client_certificate_path]))
end

it "set the client certificate password" do
expect(gitlab_client.httparty[:p12_password]).to eq(gitlab_with_certificate_config[:client_certificate_password])
end
end
end
end
17 changes: 16 additions & 1 deletion spec/checklister/configuration_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,18 @@
it "defines a default kind" do
expect(config.kind).to be_nil
end

it "defines a default endpoint_certificate_path" do
expect(config.endpoint_certificate_path).to be_nil
end

it "defines a default client_certificate_path" do
expect(config.client_certificate_path).to be_nil
end

it "defines a default client_certificate_password" do
expect(config.client_certificate_password).to be_nil
end
end

describe "#apply" do
Expand Down Expand Up @@ -75,7 +87,10 @@
it "returns a valid value with symboled keys" do
expect(config.to_hash).to include(endpoint: valid_configuration_hash[:endpoint],
private_token: valid_configuration_hash[:private_token],
kind: valid_configuration_hash[:kind])
kind: valid_configuration_hash[:kind],
endpoint_certificate_path: valid_configuration_hash[:endpoint_certificate_path],
client_certificate_path: valid_configuration_hash[:client_certificate_path],
client_certificate_password: valid_configuration_hash[:client_certificate_password])
end

it "does not return string keys" do
Expand Down
Empty file added spec/support/files/foo.crt
Empty file.
Empty file added spec/support/files/foo.p12
Empty file.

0 comments on commit 6aa8ba2

Please sign in to comment.