projectlocker_errata 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. data/CHANGELOG +908 -0
  2. data/Gemfile +3 -0
  3. data/Guardfile +6 -0
  4. data/INSTALL +20 -0
  5. data/MIT-LICENSE +23 -0
  6. data/README.md +460 -0
  7. data/README_FOR_HEROKU_ADDON.md +94 -0
  8. data/Rakefile +223 -0
  9. data/SUPPORTED_RAILS_VERSIONS +38 -0
  10. data/TESTING.md +41 -0
  11. data/features/metal.feature +18 -0
  12. data/features/rack.feature +60 -0
  13. data/features/rails.feature +272 -0
  14. data/features/rails_with_js_notifier.feature +97 -0
  15. data/features/rake.feature +27 -0
  16. data/features/sinatra.feature +29 -0
  17. data/features/step_definitions/file_steps.rb +10 -0
  18. data/features/step_definitions/metal_steps.rb +23 -0
  19. data/features/step_definitions/rack_steps.rb +23 -0
  20. data/features/step_definitions/rails_application_steps.rb +478 -0
  21. data/features/step_definitions/rake_steps.rb +17 -0
  22. data/features/support/env.rb +18 -0
  23. data/features/support/matchers.rb +35 -0
  24. data/features/support/projectlocker_errata_shim.rb.template +16 -0
  25. data/features/support/rails.rb +201 -0
  26. data/features/support/rake/Rakefile +68 -0
  27. data/features/support/terminal.rb +107 -0
  28. data/features/user_informer.feature +63 -0
  29. data/generators/projectlocker_errata/lib/insert_commands.rb +34 -0
  30. data/generators/projectlocker_errata/lib/rake_commands.rb +24 -0
  31. data/generators/projectlocker_errata/projectlocker_errata_generator.rb +94 -0
  32. data/generators/projectlocker_errata/templates/capistrano_hook.rb +6 -0
  33. data/generators/projectlocker_errata/templates/initializer.rb +6 -0
  34. data/generators/projectlocker_errata/templates/projectlocker_errata_tasks.rake +25 -0
  35. data/install.rb +1 -0
  36. data/lib/projectlocker_errata/backtrace.rb +108 -0
  37. data/lib/projectlocker_errata/capistrano.rb +43 -0
  38. data/lib/projectlocker_errata/configuration.rb +305 -0
  39. data/lib/projectlocker_errata/notice.rb +390 -0
  40. data/lib/projectlocker_errata/rack.rb +54 -0
  41. data/lib/projectlocker_errata/rails/action_controller_catcher.rb +30 -0
  42. data/lib/projectlocker_errata/rails/controller_methods.rb +85 -0
  43. data/lib/projectlocker_errata/rails/error_lookup.rb +33 -0
  44. data/lib/projectlocker_errata/rails/javascript_notifier.rb +47 -0
  45. data/lib/projectlocker_errata/rails/middleware/exceptions_catcher.rb +33 -0
  46. data/lib/projectlocker_errata/rails.rb +40 -0
  47. data/lib/projectlocker_errata/rails3_tasks.rb +98 -0
  48. data/lib/projectlocker_errata/railtie.rb +48 -0
  49. data/lib/projectlocker_errata/rake_handler.rb +65 -0
  50. data/lib/projectlocker_errata/sender.rb +128 -0
  51. data/lib/projectlocker_errata/shared_tasks.rb +47 -0
  52. data/lib/projectlocker_errata/tasks.rb +83 -0
  53. data/lib/projectlocker_errata/user_informer.rb +27 -0
  54. data/lib/projectlocker_errata/utils/blank.rb +53 -0
  55. data/lib/projectlocker_errata/version.rb +3 -0
  56. data/lib/projectlocker_errata.rb +159 -0
  57. data/lib/projectlocker_errata_tasks.rb +64 -0
  58. data/lib/rails/generators/projectlocker_errata/projectlocker_errata_generator.rb +100 -0
  59. data/lib/templates/javascript_notifier.erb +15 -0
  60. data/lib/templates/rescue.erb +91 -0
  61. data/projectlocker_errata.gemspec +39 -0
  62. data/rails/init.rb +1 -0
  63. data/resources/README.md +34 -0
  64. data/resources/ca-bundle.crt +3376 -0
  65. data/script/integration_test.rb +38 -0
  66. data/test/airbrake_2_3.xsd +88 -0
  67. data/test/backtrace_test.rb +162 -0
  68. data/test/capistrano_test.rb +34 -0
  69. data/test/catcher_test.rb +333 -0
  70. data/test/configuration_test.rb +236 -0
  71. data/test/helper.rb +263 -0
  72. data/test/javascript_notifier_test.rb +51 -0
  73. data/test/logger_test.rb +79 -0
  74. data/test/notice_test.rb +490 -0
  75. data/test/notifier_test.rb +276 -0
  76. data/test/projectlocker_errata_tasks_test.rb +170 -0
  77. data/test/rack_test.rb +58 -0
  78. data/test/rails_initializer_test.rb +36 -0
  79. data/test/recursion_test.rb +10 -0
  80. data/test/sender_test.rb +288 -0
  81. data/test/user_informer_test.rb +29 -0
  82. metadata +440 -0
@@ -0,0 +1,159 @@
1
+ require "girl_friday"
2
+ require 'net/http'
3
+ require 'net/https'
4
+ require 'rubygems'
5
+ require 'projectlocker_errata/utils/blank'
6
+ require 'projectlocker_errata/version'
7
+ require 'projectlocker_errata/configuration'
8
+ require 'projectlocker_errata/notice'
9
+ require 'projectlocker_errata/sender'
10
+ require 'projectlocker_errata/backtrace'
11
+ require 'projectlocker_errata/rack'
12
+ require 'projectlocker_errata/user_informer'
13
+
14
+ require 'projectlocker_errata/railtie' if defined?(Rails::Railtie)
15
+
16
+ module ProjectlockerErrata
17
+ API_VERSION = "2.3"
18
+ LOG_PREFIX = "** [ProjectlockerErrata] "
19
+
20
+ HEADERS = {
21
+ 'Content-type' => 'text/xml',
22
+ 'Accept' => 'text/xml, application/xml'
23
+ }
24
+
25
+ class << self
26
+ # The sender object is responsible for delivering formatted data to the ProjectlockerErrata server.
27
+ # Must respond to #send_to_projectlocker_errata. See ProjectlockerErrata::Sender.
28
+ attr_accessor :sender
29
+
30
+ # A ProjectlockerErrata configuration object. Must act like a hash and return sensible
31
+ # values for all ProjectlockerErrata configuration options. See ProjectlockerErrata::Configuration.
32
+ attr_writer :configuration
33
+
34
+ # Tell the log that the Notifier is good to go
35
+ def report_ready
36
+ write_verbose_log("Notifier #{VERSION} ready to catch errors")
37
+ end
38
+
39
+ # Prints out the environment info to the log for debugging help
40
+ def report_environment_info
41
+ write_verbose_log("Environment Info: #{environment_info}")
42
+ end
43
+
44
+ # Prints out the response body from ProjectlockerErrata for debugging help
45
+ def report_response_body(response)
46
+ write_verbose_log("Response from ProjectlockerErrata: \n#{response}")
47
+ end
48
+
49
+ # Prints out the details about the notice that wasn't sent to server
50
+ def report_notice(notice)
51
+ write_verbose_log("Notice details: \n#{notice}")
52
+ end
53
+
54
+ # Returns the Ruby version, Rails version, and current Rails environment
55
+ def environment_info
56
+ info = "[Ruby: #{RUBY_VERSION}]"
57
+ info << " [#{configuration.framework}]" if configuration.framework
58
+ info << " [Env: #{configuration.environment_name}]" if configuration.environment_name
59
+ end
60
+
61
+ # Writes out the given message to the #logger
62
+ def write_verbose_log(message)
63
+ logger.debug LOG_PREFIX + message if logger
64
+ end
65
+
66
+ # Look for the Rails logger currently defined
67
+ def logger
68
+ self.configuration.logger
69
+ end
70
+
71
+ # Call this method to modify defaults in your initializers.
72
+ #
73
+ # @example
74
+ # ProjectlockerErrata.configure do |config|
75
+ # config.api_key = '1234567890abcdef'
76
+ # config.secure = false
77
+ # end
78
+ def configure(silent = false)
79
+ yield(configuration)
80
+ self.sender = Sender.new(configuration)
81
+ report_ready unless silent
82
+ self.sender
83
+ end
84
+
85
+ # The configuration object.
86
+ # @see ProjectlockerErrata.configure
87
+ def configuration
88
+ @configuration ||= Configuration.new
89
+ end
90
+
91
+ # Sends an exception manually using this method, even when you are not in a controller.
92
+ #
93
+ # @param [Exception] exception The exception you want to notify ProjectlockerErrata about.
94
+ # @param [Hash] opts Data that will be sent to ProjectlockerErrata.
95
+ #
96
+ # @option opts [String] :api_key The API key for this project. The API key is a unique identifier that ProjectlockerErrata uses for identification.
97
+ # @option opts [String] :error_message The error returned by the exception (or the message you want to log).
98
+ # @option opts [String] :backtrace A backtrace, usually obtained with +caller+.
99
+ # @option opts [String] :rack_env The Rack environment.
100
+ # @option opts [String] :session The contents of the user's session.
101
+ # @option opts [String] :environment_name The application environment name.
102
+ def notify(exception, opts = {})
103
+ send_notice(build_notice_for(exception, opts))
104
+ end
105
+
106
+ # Sends the notice unless it is one of the default ignored exceptions
107
+ # @see ProjectlockerErrata.notify
108
+ def notify_or_ignore(exception, opts = {})
109
+ notice = build_notice_for(exception, opts)
110
+ send_notice(notice) unless notice.ignore?
111
+ end
112
+
113
+ def build_lookup_hash_for(exception, options = {})
114
+ notice = build_notice_for(exception, options)
115
+
116
+ result = {}
117
+ result[:action] = notice.action rescue nil
118
+ result[:component] = notice.component rescue nil
119
+ result[:error_class] = notice.error_class if notice.error_class
120
+ result[:environment_name] = 'production'
121
+
122
+ unless notice.backtrace.lines.empty?
123
+ result[:file] = notice.backtrace.lines.first.file
124
+ result[:line_number] = notice.backtrace.lines.first.number
125
+ end
126
+
127
+ result
128
+ end
129
+
130
+ private
131
+
132
+ def send_notice(notice)
133
+ if configuration.public?
134
+ if configuration.async?
135
+ configuration.async.call(notice)
136
+ else
137
+ sender.send_to_projectlocker_errata(notice)
138
+ end
139
+ end
140
+ end
141
+
142
+ def build_notice_for(exception, opts = {})
143
+ exception = unwrap_exception(exception)
144
+ opts = opts.merge(:exception => exception) if exception.is_a?(Exception)
145
+ opts = opts.merge(exception.to_hash) if exception.respond_to?(:to_hash)
146
+ Notice.new(configuration.merge(opts))
147
+ end
148
+
149
+ def unwrap_exception(exception)
150
+ if exception.respond_to?(:original_exception)
151
+ exception.original_exception
152
+ elsif exception.respond_to?(:continued_exception)
153
+ exception.continued_exception
154
+ else
155
+ exception
156
+ end
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,64 @@
1
+ require 'net/http'
2
+ require 'uri'
3
+
4
+ # Capistrano tasks for notifying ProjectlockerErrata of deploys
5
+ module ProjectlockerErrataTasks
6
+
7
+ # Alerts ProjectlockerErrata of a deploy.
8
+ #
9
+ # @param [Hash] opts Data about the deploy that is set to ProjectlockerErrata
10
+ #
11
+ # @option opts [String] :api_key Api key of you ProjectlockerErrata application
12
+ # @option opts [String] :rails_env Environment of the deploy (production, staging)
13
+ # @option opts [String] :scm_revision The given revision/sha that is being deployed
14
+ # @option opts [String] :scm_repository Address of your repository to help with code lookups
15
+ # @option opts [String] :local_username Who is deploying
16
+ def self.deploy(opts = {})
17
+ api_key = opts.delete(:api_key) || ProjectlockerErrata.configuration.api_key
18
+ if api_key.blank?
19
+ puts "I don't seem to be configured with an API key. Please check your configuration."
20
+ return false
21
+ end
22
+
23
+ if opts[:rails_env].blank?
24
+ puts "I don't know to which Rails environment you are deploying (use the TO=production option)."
25
+ return false
26
+ end
27
+
28
+ dry_run = opts.delete(:dry_run)
29
+ params = {'api_key' => api_key}
30
+ opts.each {|k,v| params["deploy[#{k}]"] = v }
31
+
32
+ host = ProjectlockerErrata.configuration.host || 'errors.projectlocker.com'
33
+ port = ProjectlockerErrata.configuration.port
34
+
35
+ proxy = Net::HTTP.Proxy(ProjectlockerErrata.configuration.proxy_host,
36
+ ProjectlockerErrata.configuration.proxy_port,
37
+ ProjectlockerErrata.configuration.proxy_user,
38
+ ProjectlockerErrata.configuration.proxy_pass)
39
+ http = proxy.new(host, port)
40
+
41
+
42
+
43
+ # Handle Security
44
+ if ProjectlockerErrata.configuration.secure?
45
+ http.use_ssl = true
46
+ http.ca_file = ProjectlockerErrata.configuration.ca_bundle_path
47
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
48
+ end
49
+
50
+ post = Net::HTTP::Post.new("/deploys.txt")
51
+ post.set_form_data(params)
52
+
53
+ if dry_run
54
+ puts http.inspect, params.inspect
55
+ return true
56
+ else
57
+ response = http.request(post)
58
+
59
+ puts response.body
60
+ return Net::HTTPSuccess === response
61
+ end
62
+ end
63
+ end
64
+
@@ -0,0 +1,100 @@
1
+ require 'rails/generators'
2
+
3
+ class ProjectlockerErrataGenerator < Rails::Generators::Base
4
+
5
+ class_option :api_key, :aliases => "-k", :type => :string, :desc => "Your ProjectlockerErrata API key"
6
+ class_option :heroku, :type => :boolean, :desc => "Use the Heroku addon to provide your ProjectlockerErrata API key"
7
+ class_option :app, :aliases => "-a", :type => :string, :desc => "Your Heroku app name (only required if deploying to >1 Heroku app)"
8
+
9
+ def self.source_root
10
+ @_projectlocker_errata_source_root ||= File.expand_path("../../../../../generators/projectlocker_errata/templates", __FILE__)
11
+ end
12
+
13
+ def install
14
+ ensure_api_key_was_configured
15
+ ensure_plugin_is_not_present
16
+ append_capistrano_hook
17
+ generate_initializer unless api_key_configured?
18
+ determine_api_key if heroku?
19
+ test_projectlocker_errata
20
+ end
21
+
22
+ private
23
+
24
+ def ensure_api_key_was_configured
25
+ if !options[:api_key] && !options[:heroku] && !api_key_configured?
26
+ puts "Must pass --api-key or --heroku or create config/initializers/projectlocker_errata.rb"
27
+ exit
28
+ end
29
+ end
30
+
31
+ def ensure_plugin_is_not_present
32
+ if plugin_is_present?
33
+ puts "You must first remove the projectlocker_errata plugin. Please run: script/plugin remove projectlocker_errata"
34
+ exit
35
+ end
36
+ end
37
+
38
+ def append_capistrano_hook
39
+ if File.exists?('config/deploy.rb') && File.exists?('Capfile')
40
+ append_file('config/deploy.rb', <<-HOOK)
41
+
42
+ require './config/boot'
43
+ require 'projectlocker_errata/capistrano'
44
+ HOOK
45
+ end
46
+ end
47
+
48
+ def api_key_expression
49
+ s = if options[:api_key]
50
+ "'#{options[:api_key]}'"
51
+ elsif options[:heroku]
52
+ "ENV['HOPTOAD_API_KEY']"
53
+ end
54
+ end
55
+
56
+ def generate_initializer
57
+ template 'initializer.rb', 'config/initializers/projectlocker_errata.rb'
58
+ end
59
+
60
+ def determine_api_key
61
+ puts "Attempting to determine your API Key from Heroku..."
62
+ ENV['HOPTOAD_API_KEY'] = heroku_api_key
63
+ if ENV['HOPTOAD_API_KEY'].blank?
64
+ puts "... Failed."
65
+ puts "WARNING: We were unable to detect the ProjectlockerErrata API Key from your Heroku environment."
66
+ puts "Your Heroku application environment may not be configured correctly."
67
+ exit 1
68
+ else
69
+ puts "... Done."
70
+ puts "Heroku's ProjectlockerErrata API Key is '#{ENV['HOPTOAD_API_KEY']}'"
71
+ end
72
+ end
73
+
74
+ def heroku_var(var,app_name = nil)
75
+ app = app_name ? "--app #{app_name}" : ''
76
+ `heroku config #{app} | grep -E "#{var.upcase}" | awk '{ print $3; }'`.strip
77
+ end
78
+
79
+ def heroku_api_key
80
+ heroku_var("(hoptoad|projectlocker_errata)_api_key",options[:app]).split.find {|x| x unless x.blank?}
81
+ end
82
+
83
+ def heroku?
84
+ options[:heroku] ||
85
+ system("grep HOPTOAD_API_KEY config/initializers/projectlocker_errata.rb") ||
86
+ system("grep HOPTOAD_API_KEY config/environment.rb")
87
+ end
88
+
89
+ def api_key_configured?
90
+ File.exists?('config/initializers/projectlocker_errata.rb')
91
+ end
92
+
93
+ def test_projectlocker_errata
94
+ puts run("rake projectlocker_errata:test --trace")
95
+ end
96
+
97
+ def plugin_is_present?
98
+ File.exists?('vendor/plugins/projectlocker_errata')
99
+ end
100
+ end
@@ -0,0 +1,15 @@
1
+ <%= javascript_tag %Q{
2
+ (function(){
3
+ var notifierJsScheme = (("https:" == document.location.protocol) ? "https://" : "http://");
4
+ document.write(unescape("%3Cscript src='" + notifierJsScheme + "#{host}/javascripts/notifier.js' type='text/javascript'%3E%3C/script%3E"));
5
+ })();
6
+ }%>
7
+
8
+ <%= javascript_tag %Q{
9
+ window.Airbrake = (typeof(Airbrake) == 'undefined' && typeof(Hoptoad) != 'undefined') ? Hoptoad : Airbrake
10
+ Airbrake.setKey('#{api_key}');
11
+ Airbrake.setHost('#{host}');
12
+ Airbrake.setEnvironment('#{environment}');
13
+ Airbrake.setErrorDefaults({ url: "#{escape_javascript url}", component: "#{controller_name}", action: "#{action_name}" });
14
+ }
15
+ %>
@@ -0,0 +1,91 @@
1
+ <script type="text/javascript">
2
+ var ProjectlockerErrata = {
3
+ host : <%= host.to_json %>,
4
+ api_key : <%= api_key.to_json %>,
5
+ notice : <%= notice.to_json %>,
6
+ message : 'This error exists in production!',
7
+
8
+ initialize: function() {
9
+ if (this.initialized) {
10
+ return;
11
+ } else {
12
+ this.initialized = true;
13
+ }
14
+
15
+ var data = [];
16
+
17
+ for (var key in this.notice) {
18
+ data[data.length] = 'notice[' + key + ']=' + this.notice[key];
19
+ }
20
+
21
+ data[data.length] = 'notice[api_key]=' + this.api_key;
22
+ data[data.length] = 'callback=ProjectlockerErrata.onSuccess';
23
+ data[data.length] = '_=' + (new Date()).getTime();
24
+
25
+ var head = document.getElementsByTagName('head')[0];
26
+ var done = false;
27
+
28
+ var
29
+ script = document.createElement('script');
30
+ script.src = 'http://' + this.host + '/notices_api/v1/notices/exist?' +
31
+ data.join('&');
32
+ script.type = 'text/javascript';
33
+ script.onload = script.onreadystatechange = function(){
34
+ if (!done && (!this.readyState ||
35
+ this.readyState == 'loaded' || this.readyState == 'complete')) {
36
+
37
+ done = true;
38
+
39
+ // Handle memory leak in IE. (via jQuery)
40
+ script.onload = script.onreadystatechange = null;
41
+ head.removeChild(script);
42
+ }
43
+ };
44
+
45
+ head.appendChild(script);
46
+ },
47
+
48
+ onSuccess: function(error) {
49
+ var body = document.getElementsByTagName('body')[0];
50
+ var text = document.createTextNode(this.message);
51
+ var element = document.createElement('a');
52
+
53
+ element.id = 'projectlocker_errata';
54
+ element.href = 'http://' + error.subdomain + '.' + this.host +
55
+ '/projects/' + error.project_id + '/errors/' + error.id;
56
+ element.appendChild(text);
57
+
58
+ body.insertBefore(element, body.firstChild);
59
+
60
+ var h1 = document.getElementsByTagName('h1')[0];
61
+ var pre = document.getElementsByTagName('pre')[0];
62
+ var wrapper = document.createElement('div');
63
+
64
+ wrapper.id = 'wrapper';
65
+ wrapper.appendChild(h1);
66
+ wrapper.appendChild(pre);
67
+
68
+ body.insertBefore(wrapper, body.children[1]);
69
+ }
70
+ };
71
+
72
+ window.onload = function() {
73
+ ProjectlockerErrata.initialize.apply(ProjectlockerErrata);
74
+ };
75
+ </script>
76
+
77
+ <style type="text/css">
78
+ #projectlocker_errata {
79
+ background: #FFF url(http://projectlocker_errata.io/images/fell-off-the-toad.gif) no-repeat top right;
80
+ color: #F00;
81
+ padding: 45px 101px 45px 12px;
82
+ font-size: 14px;
83
+ font-weight: bold;
84
+ display: block;
85
+ float: right;
86
+ }
87
+
88
+ #wrapper {
89
+ padding-right: 360px;
90
+ }
91
+ </style>
@@ -0,0 +1,39 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "projectlocker_errata/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = %q{projectlocker_errata}
7
+ s.version = ProjectlockerErrata::VERSION.dup
8
+ s.summary = %q{Exception reporting service for ProjectLocker}
9
+
10
+ s.require_paths = ["lib"]
11
+ s.files = Dir["{generators/**/*,lib/**/*,rails/**/*,resources/*,script/*}"] +
12
+ %w(projectlocker_errata.gemspec CHANGELOG Gemfile Guardfile INSTALL MIT-LICENSE Rakefile README_FOR_HEROKU_ADDON.md README.md TESTING.md SUPPORTED_RAILS_VERSIONS install.rb)
13
+ s.test_files = Dir.glob("{test,spec,features}/**/*")
14
+
15
+ s.add_runtime_dependency("builder")
16
+ s.add_runtime_dependency("girl_friday")
17
+
18
+ s.add_development_dependency("actionpack", "~> 2.3.8")
19
+ s.add_development_dependency("activerecord", "~> 2.3.8")
20
+ s.add_development_dependency("activesupport", "~> 2.3.8")
21
+ s.add_development_dependency("mocha", "0.10.5")
22
+ s.add_development_dependency("bourne", ">= 1.0")
23
+ s.add_development_dependency("cucumber", "~> 0.10.6")
24
+ s.add_development_dependency("fakeweb", "~> 1.3.0")
25
+ s.add_development_dependency("nokogiri", "~> 1.4.3.1")
26
+ s.add_development_dependency("rspec", "~> 2.6.0")
27
+ s.add_development_dependency("sham_rack", "~> 1.3.0")
28
+ s.add_development_dependency("shoulda", "~> 2.11.3")
29
+ s.add_development_dependency("capistrano", "~> 2.8.0")
30
+ s.add_development_dependency("guard" )
31
+ s.add_development_dependency("guard-test" )
32
+ s.add_development_dependency("simplecov" )
33
+
34
+ s.authors = ["Airbrake", "C. G. Brown"]
35
+ s.email = %q{support@projectlocker.com}
36
+ s.homepage = "http://www.projectlocker.com"
37
+
38
+ s.platform = Gem::Platform::RUBY
39
+ end
data/rails/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'projectlocker_errata/rails'
@@ -0,0 +1,34 @@
1
+ Airbrake Resources
2
+ ==================
3
+
4
+ Airbrake has an SSL mode available to paying plans. SSL Certificate Authority (CA) certificates are not kept current by default on many environments. When CA certs are stale, Airbrake cannot verify Airbrake's production SSL cert and error reports fail. To avoid this, we now package local CA certs. The production of these certs is detailed here.
5
+
6
+ Building ca-bundle.crt
7
+ ----------------------
8
+
9
+ From https://gist.github.com/996292.
10
+
11
+ If you want to use curl or net-http/open-uri to access https resources, you will often (always?) get an error, because they don't have the large number of root certificates installed that web browsers have.
12
+
13
+ You can manually install the root certs, but first you have to get them from somewhere. [This article](http://notetoself.vrensk.com/2008/09/verified-https-in-ruby/) gives a nice description of how to do that. The [source of the cert files](http://curl.haxx.se/ca/cacert.pem) it points to is hosted by the curl project, who kindly provide it in the .pem format.
14
+
15
+ **problem:** Sadly, ironically, and comically, it's not possible to access that file via https! Luckily, the awesome curl project does provide us with the script that they use to produce the file, so we can do it securely ourselves. Here's how.
16
+
17
+ 1. `git clone https://github.com/bagder/curl.git`
18
+ 2. `cd curl/lib`
19
+ 3. edit `mk-ca-bundle.pl` and change:
20
+
21
+ ```perl
22
+ my $url = 'http://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/certdata.txt?raw=1';
23
+ ```
24
+
25
+ to
26
+
27
+ ```perl
28
+ my $url = 'https://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/certdata.txt?raw=1';
29
+ ```
30
+
31
+ (change `http` to `https`)
32
+ 4. `./mk-ca-bundle.pl`
33
+
34
+ Ta da!