pg_rails 7.0.8.pre.alpha.83 → 7.0.8.pre.alpha.85

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f13f3f371227ad2016ab3996077254555a2d258d2132b6c61e1dbb616cdabf48
4
- data.tar.gz: 11206668b12f2acfc9f7878ab7049b27476f7984013a5a107a269ab8273aa8bd
3
+ metadata.gz: a8e7f1383530ebb81fee806358820682f5296214306d3e7a31e552f977f84e08
4
+ data.tar.gz: c824d6e755c9048e05f30cb628ab21d991b9a737f754e5be17fc915c273d9446
5
5
  SHA512:
6
- metadata.gz: b274dd6247c0d49ced832c8ad44c7bfb4c2916876b87921399c88468ee4297c0008ca2fd9a1a806db8477a7d9fada576b8b02faa19c48fe69298bb8a33bd32fe
7
- data.tar.gz: 6a4dbbff767631ed6f1ee0cf9b1eea4a8e8ef7f61c015b900b3f6d4656481f9b74aecd77704bd65931884665230194bbec53d3710c64c27c8b32cde6d77309fb
6
+ metadata.gz: e96376b503168349f4383a6f12a9b617c0da2454b3a03e490e48bebe5bb4ee7732581fd8b9757e2ade08559c5a3d9b2b189f23b2d095740a318cd5964fa3dab2
7
+ data.tar.gz: f2f9f557c97be28535b81cc28efcf6aca1e306ef3aa22e1b97941161f468bf2381038c4c952bdd9da56ea233fe04e36e1f206baf424711b6596c83457d711328
@@ -229,7 +229,7 @@ module PgEngine
229
229
  instancia_modelo.assign_attributes(modelo_params) if action_name.in? %w[update]
230
230
  end
231
231
 
232
- authorize instancia_modelo
232
+ Current.user&.developer? || authorize(instancia_modelo)
233
233
 
234
234
  # TODO: problema en create y update cuando falla la validacion
235
235
  # Reproducir el error antes de arreglarlo
@@ -40,6 +40,9 @@ module PgEngine
40
40
  render turbo_stream: (turbo_stream.remove_all('.modal') + render_turbo_stream_flash_messages),
41
41
  status: :internal_server_error
42
42
  end
43
+ format.any do
44
+ head :internal_server_error
45
+ end
43
46
  end
44
47
  end
45
48
 
@@ -1,10 +1,77 @@
1
1
  module Public
2
2
  class WebhooksController < PublicController
3
+ skip_before_action :verify_authenticity_token
4
+
5
+ before_action :verify_signature, only: :mailgun
6
+
7
+ rescue_from StandardError do
8
+ pg_err 'webhook internal server error', request.body.read
9
+ head :internal_server_error
10
+ end
11
+
12
+ rescue_from ActionDispatch::Http::Parameters::ParseError do
13
+ pg_warn 'webhook parser error', request.body.read
14
+ head :bad_request
15
+ end
16
+
3
17
  def mailgun
4
- # FIXME: verify signature
5
- # params['signature']['timestamp']
6
- PgEngine::Mailgun::LogSync.digest(params['event-data'])
18
+ if PgEngine::Mailgun::LogSync.digest(params['event-data'])
19
+ head :ok
20
+ else
21
+ # Si no se guardó el log es porque ya existía un log con ese ID
22
+ # Mando :not_acceptable (406) para que Mailgun no vuelva a intentar
23
+ # https://documentation.mailgun.com/docs/mailgun/user-manual/tracking-messages
24
+ pg_warn 'ya existía un log con ese id, raaaaro', params
25
+ head :not_acceptable
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def used_tokens
32
+ Kredis.unique_list 'mailgun_webhook_used_tokens'
33
+ end
34
+
35
+ def not_used_token(token)
36
+ if used_tokens.elements.include?(token)
37
+ pg_warn 'Mailgun Webhook: refusing used token'
38
+ head :ok
39
+
40
+ false
41
+ else
42
+ used_tokens << token
43
+ true
44
+ end
45
+ end
46
+
47
+ def timestamp_not_too_far(timestamp)
48
+ if (Time.zone.at(timestamp.to_i) - Time.zone.now).abs > 1.hour
49
+ pg_warn 'Mailgun Webhook: refusing due to timestamp too far'
50
+ head :ok
51
+
52
+ false
53
+ else
54
+ true
55
+ end
56
+ end
57
+
58
+ def verify_signature
59
+ timestamp = params['signature']['timestamp']
60
+ token = params['signature']['token']
61
+ signature = params['signature']['signature']
62
+ hexdigest = encode(timestamp + token)
63
+
64
+ return unless not_used_token(token)
65
+ return unless timestamp_not_too_far(timestamp)
66
+ return unless hexdigest != signature
67
+
68
+ pg_warn 'Mailgun Webhook: refusing invalid signature'
7
69
  head :ok
8
70
  end
71
+
72
+ def encode(data)
73
+ webhook_secret_key = Rails.application.credentials.dig(:mailgun, :webhook_secret_key)
74
+ OpenSSL::HMAC.hexdigest('sha256', webhook_secret_key, data)
75
+ end
9
76
  end
10
77
  end
@@ -21,6 +21,7 @@ module PgEngine
21
21
 
22
22
  rescue_from StandardError do |err|
23
23
  pg_err err
24
+ # TODO: agregar un backtrace
24
25
  @email_object.update_columns(status: :failed, status_detail: err.to_s) if @email_object.present?
25
26
  end
26
27
 
@@ -25,7 +25,7 @@ class MensajeContactoPolicy < ApplicationPolicy
25
25
  # acceso_total? && !record.readonly?
26
26
  # end
27
27
 
28
- def acceso_total?
28
+ def puede_crear?
29
29
  true
30
30
  end
31
31
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PgEngine
4
- class ApplicationPolicy
4
+ class BasePolicy
5
5
  attr_reader :user, :record
6
6
 
7
7
  def initialize(user, record)
@@ -9,19 +9,13 @@ module PgEngine
9
9
  @record = record
10
10
  end
11
11
 
12
- def editar_en_lugar?
13
- puede_editar?
14
- end
15
-
16
12
  def index?
17
- raise "esta policy se llama con la clase modelo y no con #{record.class}" unless record.class
18
-
19
- acceso_total? || Pundit.policy_scope!(user, record).any?
13
+ base_access_to_collection?
20
14
  end
21
15
 
22
16
  def show?
23
17
  # scope.where(id: record.id).exists?
24
- acceso_total?
18
+ base_access_to_record?
25
19
  end
26
20
 
27
21
  def create?
@@ -57,7 +51,7 @@ module PgEngine
57
51
  end
58
52
 
59
53
  def resolve
60
- if policy.acceso_total?
54
+ if policy.base_access_to_collection?
61
55
  scope.all
62
56
  else
63
57
  scope.none
@@ -72,29 +66,31 @@ module PgEngine
72
66
  end
73
67
 
74
68
  def puede_editar?
75
- acceso_total?
69
+ base_access_to_record?
76
70
  end
77
71
 
78
72
  def puede_crear?
79
- acceso_total?
73
+ base_access_to_collection?
80
74
  end
81
75
 
82
76
  def puede_borrar?
83
- acceso_total?
77
+ base_access_to_record?
84
78
  end
85
79
 
86
80
  def export?
87
- acceso_total?
81
+ base_access_to_collection?
82
+ end
83
+
84
+ def base_access_to_record?
85
+ user&.developer?
88
86
  end
89
87
 
90
- def acceso_total?
88
+ def base_access_to_collection?
91
89
  user&.developer?
92
90
  end
93
91
 
94
92
  def objeto_borrado?
95
- if record.respond_to?(:deleted?)
96
- record.deleted?
97
- elsif record.respond_to?(:discarded?)
93
+ if record.respond_to?(:discarded?)
98
94
  record.discarded?
99
95
  else
100
96
  false
@@ -47,8 +47,6 @@ module PgEngine
47
47
  timestamp: item['timestamp'],
48
48
  message_id:
49
49
  )
50
- rescue StandardError => e
51
- pg_err e, item
52
50
  end
53
51
 
54
52
  def self.write_log(items)
@@ -0,0 +1,47 @@
1
+ # :nocov:
2
+ module PgEngine
3
+ module Utils
4
+ class CheckInvalidRecords
5
+ def run
6
+ invalids = []
7
+ classes.each do |klass|
8
+ klass.find_each do |record|
9
+ invalids << record unless record.valid?
10
+ end
11
+ end
12
+ invalids.map do |r|
13
+ [
14
+ (r.account.to_s if r.respond_to?(:account)),
15
+ r.class.to_s,
16
+ r.id,
17
+ r.errors.full_messages
18
+ ]
19
+ end
20
+ end
21
+
22
+ def classes
23
+ all = ActiveRecord::Base.descendants.select { |m| m.table_name.present? }
24
+ all - ignored_classes
25
+ end
26
+
27
+ def ignored_classes
28
+ [
29
+ ActionText::Record,
30
+ ActionMailbox::Record,
31
+ ActiveAdmin::Comment,
32
+ ActiveStorage::Record,
33
+ PgEngine::BaseRecord,
34
+ Audited::Audit,
35
+ ActionText::RichText,
36
+ ActionText::EncryptedRichText,
37
+ ActionMailbox::InboundEmail,
38
+ ActiveStorage::VariantRecord,
39
+ ActiveStorage::Attachment,
40
+ ActiveStorage::Blob,
41
+ ApplicationRecord
42
+ ]
43
+ end
44
+ end
45
+ end
46
+ end
47
+ # :nocov:
@@ -37,6 +37,10 @@ end
37
37
 
38
38
  module PgEngine
39
39
  class PgLogger
40
+ def self.test_logged_messages
41
+ @test_logged_messages ||= []
42
+ end
43
+
40
44
  class << self
41
45
  def log(type, *args)
42
46
  notify_all(build_msg(*args), type)
@@ -48,6 +52,7 @@ module PgEngine
48
52
  send_to_logger(mensaje, type)
49
53
  send_to_rollbar(mensaje, type)
50
54
  send_to_stdout(mensaje, type) if ENV.fetch('LOG_TO_STDOUT', nil)
55
+ save_internal(mensaje, type) if Rails.env.test?
51
56
  nil
52
57
  end
53
58
 
@@ -68,6 +73,10 @@ module PgEngine
68
73
  Rails.logger.send(type, rainbow_wrap(mensaje, type))
69
74
  end
70
75
 
76
+ def save_internal(mensaje, type)
77
+ PgEngine::PgLogger.test_logged_messages << [type, mensaje]
78
+ end
79
+
71
80
  # Format
72
81
 
73
82
  # TODO: loguear time
@@ -117,7 +126,9 @@ module PgEngine
117
126
 
118
127
  def cleaner
119
128
  bc = ActiveSupport::BacktraceCleaner.new
120
- bc.add_filter { |line| line.gsub(%r{.*pg_rails/}, '') }
129
+ bc.remove_silencers!
130
+ pattern = %r{\A[^/]+ \([\w.]+\) }
131
+ bc.add_silencer { |line| pattern.match?(line) && !line.match?(/pg_contable|pg_rails/) }
121
132
  bc.add_silencer { |line| /pg_logger/.match?(line) }
122
133
  bc
123
134
  end
@@ -60,6 +60,17 @@ describe DummyBaseController do
60
60
  expect(response.body).to include '<turbo-stream action="remove" targets=".modal">'
61
61
  end
62
62
  end
63
+
64
+ context 'cuando acepta json' do
65
+ before do
66
+ request.headers['Accept'] = 'application/json'
67
+ end
68
+
69
+ fit do
70
+ subject
71
+ expect(response).to have_http_status(:internal_server_error)
72
+ end
73
+ end
63
74
  end
64
75
 
65
76
  describe 'not_authorized' do
@@ -42,12 +42,6 @@ RSpec.describe Public::MensajeContactosController do
42
42
  }
43
43
  end
44
44
 
45
- let(:logged_user) { create :user, :developer }
46
-
47
- before do
48
- sign_in logged_user if logged_user.present?
49
- end
50
-
51
45
  describe 'routing' do
52
46
  it 'routes GET index correctly' do
53
47
  route = { get: '/contacto/new' }
@@ -1,33 +1,47 @@
1
1
  require 'rails_helper'
2
2
 
3
- describe Public::WebhooksController do
3
+ RSpec::Matchers.define_negated_matcher :not_change, :change
4
+
5
+ def build_body(log_id, signature, timestamp)
6
+ <<~JSON
7
+ {
8
+ "signature": {
9
+ "timestamp": "#{timestamp}",
10
+ "token": "6fcc81a280a2458de8c83bf22dde8c71485be1d51333d3427e",
11
+ "signature": "#{signature}"
12
+ },
13
+ "event-data": {
14
+ "timestamp": 1715014542.2477064,
15
+ "ip": "66.102.8.333",
16
+ "event": "delivered",
17
+ "id": "#{log_id}",
18
+ "severity":"temporary",
19
+ "log-level": "info",
20
+ "message": {
21
+ "headers": { "message-id": "msgid@fakeapp2024.mail" }
22
+ },
23
+ "recipient": "natprobel@fakemail.com"
24
+ }
25
+ }
26
+ JSON
27
+ end
28
+
29
+ fdescribe Public::WebhooksController do
30
+ include ActiveSupport::Testing::TimeHelpers
31
+
32
+ before { travel_to Time.zone.at(1_716_564_587) }
33
+
4
34
  describe '#mailgun' do
5
35
  subject do
6
36
  post :mailgun, body:, as: :json
7
37
  end
8
38
 
39
+ let(:signature) { 'c524037907046276117758afae8a340e77a43a6e48eb35a9521426e7a3ff675b' }
40
+ let(:log_id) { 'log_2' }
41
+ let(:timestamp) { '1716564587' }
42
+
9
43
  let(:body) do
10
- <<~JSON
11
- {
12
- "signature": {
13
- "timestamp": "1529006854",
14
- "token": "a8ce0edb2dd8301dee6c2405235584e45aa91d1e9f979f3de0",
15
- "signature": "d2271d12299f6592d9d44cd9d250f0704e4674c30d79d07c47a66f95ce71cf55"
16
- },
17
- "event-data": {
18
- "timestamp": 1715014542.2477064,
19
- "ip": "66.102.8.333",
20
- "event": "delivered",
21
- "id": "log_2",
22
- "severity":"temporary",
23
- "log-level": "info",
24
- "message": {
25
- "headers": { "message-id": "msgid@fakeapp2024.mail" }
26
- },
27
- "recipient": "natprobel@fakemail.com"
28
- }
29
- }
30
- JSON
44
+ build_body(log_id, signature, timestamp)
31
45
  end
32
46
 
33
47
  it do
@@ -38,5 +52,91 @@ describe Public::WebhooksController do
38
52
  it do
39
53
  expect { subject }.to change(EmailLog, :count).by(1)
40
54
  end
55
+
56
+ context 'cuando tira internal server error' do
57
+ let(:body) { '{ "este json": "no me sirve" }' }
58
+
59
+ it do
60
+ subject
61
+ expect(response).to have_http_status(:internal_server_error)
62
+ end
63
+
64
+ fit do
65
+ expect { subject }.to have_errored('internal server error')
66
+ .and(have_errored('no me sirve'))
67
+ end
68
+ end
69
+
70
+ context 'cuando no es un json' do
71
+ let(:body) { 'mal json' }
72
+
73
+ it do
74
+ subject
75
+ expect(response).to have_http_status(:bad_request)
76
+ end
77
+
78
+ fit do
79
+ expect { subject }.to have_warned('parser error').and(have_warned('mal json'))
80
+ end
81
+ end
82
+
83
+ context 'cuando ya existe un log con ese ID' do
84
+ before do
85
+ create(:email_log, log_id:)
86
+ end
87
+
88
+ it do
89
+ expect { subject }.to have_warned('ya existía un log con ese id')
90
+ .and(not_change(EmailLog, :count))
91
+ end
92
+ end
93
+
94
+ shared_context 'todo bien pero no guarda el log' do
95
+ it 'responds ok' do
96
+ subject
97
+ expect(response).to have_http_status(:ok)
98
+ end
99
+
100
+ it 'no guarda el log ;)' do
101
+ expect { subject }.not_to change(EmailLog, :count)
102
+ end
103
+ end
104
+
105
+ context 'si la signature no es válida' do
106
+ let(:signature) { 'no válida' }
107
+
108
+ it_behaves_like 'todo bien pero no guarda el log'
109
+
110
+ fit do
111
+ expect { subject }.to have_warned('refusing invalid signature')
112
+ end
113
+ end
114
+
115
+ context 'cuando ya se usó el token' do
116
+ subject do
117
+ post :mailgun, body: build_body('otro id', signature, timestamp), as: :json
118
+ end
119
+
120
+ before do
121
+ post :mailgun, body: build_body(log_id, signature, timestamp), as: :json
122
+ end
123
+
124
+ it_behaves_like 'todo bien pero no guarda el log'
125
+
126
+ fit do
127
+ expect { subject }.to have_warned('refusing used token')
128
+ end
129
+ end
130
+
131
+ context 'cuando la timestamp está muy lejos' do
132
+ let(:timestamp) { '1111111' }
133
+ let(:signature) { '869c06cea4be27321a6a7c6a8e3d0668bb9c2b5b3de5532f644dba181a157d9a' }
134
+
135
+ it_behaves_like 'todo bien pero no guarda el log'
136
+
137
+ fit do
138
+ expect { subject }.to have_warned('refusing due to timestamp')
139
+ end
140
+ end
41
141
  end
42
142
  end
@@ -92,7 +92,7 @@ describe PgEngine::Mailgun::LogSync, vcr: { cassette_name: 'mailgun/log_sync_dow
92
92
  end
93
93
 
94
94
  it do
95
- expect { subject }.not_to change(EmailLog, :count)
95
+ expect { subject }.to raise_error(NoMethodError)
96
96
  end
97
97
  end
98
98
  end
@@ -33,6 +33,17 @@ html
33
33
  - if @rollbar_token.present?
34
34
  meta name="rollbar-token" content="#{@rollbar_token}"
35
35
  meta name="rollbar-env" content="#{Rails.env}"
36
+
37
+ link rel="preconnect" href="https://fonts.googleapis.com"
38
+ link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="crossorigin"
39
+ link href="https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400;0,500;0,700;1,300;1,400;1,500;1,700&display=swap" rel="stylesheet"
40
+ css:
41
+ body {
42
+ font-family: "Ubuntu", sans-serif;
43
+ font-weight: 400;
44
+ font-style: normal;
45
+ }
46
+
36
47
  body
37
48
  = render partial: 'pg_layout/sidebar_mobile'
38
49
 
@@ -0,0 +1,62 @@
1
+ # :nocov:
2
+ module PgEngine
3
+ module Matchers
4
+ module PgLogger
5
+ class Base < RSpec::Rails::Matchers::BaseMatcher
6
+ def initialize(text, level)
7
+ super()
8
+ @text = text
9
+ @level = level
10
+ end
11
+ end
12
+
13
+ class PgHaveLogged < Base
14
+ def matches?(proc)
15
+ msg = 'have_logged only support block expectations'
16
+ raise ArgumentError, msg unless proc.is_a?(Proc)
17
+
18
+ original_messages = Set.new(PgEngine::PgLogger.test_logged_messages)
19
+ proc.call
20
+ logged_messages = Set.new(PgEngine::PgLogger.test_logged_messages)
21
+
22
+ @new_messages = logged_messages - original_messages
23
+ @new_messages.any? do |level, message|
24
+ if @text.present? && @level.present?
25
+ level == @level && message.include?(@text)
26
+ elsif @text.present?
27
+ message.include? @text
28
+ elsif @level.present?
29
+ level == @level
30
+ else
31
+ true
32
+ end
33
+ end
34
+ end
35
+
36
+ def failure_message
37
+ msg = "expected to #{@level || log}"
38
+ msg << "with text: #{@text}" if @text.present?
39
+ return unless @new_messages.any?
40
+
41
+ msg << "\nLogged messages:"
42
+ @new_messages.each do |level, message|
43
+ msg << "\n #{level}: #{message[0..200]}"
44
+ end
45
+ end
46
+
47
+ def supports_block_expectations?
48
+ true
49
+ end
50
+ end
51
+ end
52
+
53
+ def have_errored(text = nil) # rubocop:disable Naming/PredicateName
54
+ PgLogger::PgHaveLogged.new(text, :error)
55
+ end
56
+
57
+ def have_warned(text = nil) # rubocop:disable Naming/PredicateName
58
+ PgLogger::PgHaveLogged.new(text, :warn)
59
+ end
60
+ end
61
+ end
62
+ # :nocov:
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PgRails
4
- VERSION = '7.0.8-alpha.83'
4
+ VERSION = '7.0.8-alpha.85'
5
5
  end
@@ -10,7 +10,7 @@ require_dependency "<%= namespaced_path %>/application_policy"
10
10
  class <%= class_name %>Policy < ApplicationPolicy
11
11
  class Scope < ApplicationPolicy::Scope
12
12
  # def resolve
13
- # if policy.acceso_total?
13
+ # if policy.base_access_to_collection?
14
14
  # scope.all
15
15
  # else
16
16
  # scope.none
@@ -19,19 +19,23 @@ class <%= class_name %>Policy < ApplicationPolicy
19
19
  end
20
20
 
21
21
  # def puede_editar?
22
- # acceso_total? && !record.readonly?
22
+ # base_access_to_record?
23
23
  # end
24
24
 
25
25
  # def puede_crear?
26
- # acceso_total? || user.asesor?
26
+ # base_access_to_collection?
27
27
  # end
28
28
 
29
29
  # def puede_borrar?
30
- # acceso_total? && !record.readonly?
30
+ # base_access_to_record?
31
31
  # end
32
32
 
33
- # def acceso_total?
34
- # user.developer?
33
+ # def base_access_to_record?
34
+ # base_access_to_collection? && record.account == Current.account
35
+ # end
36
+
37
+ # def base_access_to_collection?
38
+ # user.present?
35
39
  # end
36
40
  end
37
41
  <% end -%>
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pg_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.0.8.pre.alpha.83
4
+ version: 7.0.8.pre.alpha.85
5
5
  platform: ruby
6
6
  authors:
7
7
  - Martín Rosso
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-05-23 00:00:00.000000000 Z
11
+ date: 2024-05-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -1002,7 +1002,7 @@ files:
1002
1002
  - pg_engine/app/policies/email_log_policy.rb
1003
1003
  - pg_engine/app/policies/email_policy.rb
1004
1004
  - pg_engine/app/policies/mensaje_contacto_policy.rb
1005
- - pg_engine/app/policies/pg_engine/application_policy.rb
1005
+ - pg_engine/app/policies/pg_engine/base_policy.rb
1006
1006
  - pg_engine/app/policies/user_account_policy.rb
1007
1007
  - pg_engine/app/policies/user_policy.rb
1008
1008
  - pg_engine/app/policies/user_registration_policy.rb
@@ -1066,6 +1066,7 @@ files:
1066
1066
  - pg_engine/lib/pg_engine/error.rb
1067
1067
  - pg_engine/lib/pg_engine/mailgun/log_sync.rb
1068
1068
  - pg_engine/lib/pg_engine/route_helpers.rb
1069
+ - pg_engine/lib/pg_engine/utils/check_invalid_records.rb
1069
1070
  - pg_engine/lib/pg_engine/utils/pdf_preview_generator.rb
1070
1071
  - pg_engine/lib/pg_engine/utils/pg_logger.rb
1071
1072
  - pg_engine/lib/tasks/auto_anotar_modelos.rake
@@ -1172,6 +1173,7 @@ files:
1172
1173
  - pg_rails/lib/pg_rails/current_attributes_support.rb
1173
1174
  - pg_rails/lib/pg_rails/dotenv_support.rb
1174
1175
  - pg_rails/lib/pg_rails/redis_support.rb
1176
+ - pg_rails/lib/pg_rails/rspec_logger_matchers.rb
1175
1177
  - pg_rails/lib/pg_rails/vcr_support.rb
1176
1178
  - pg_rails/lib/version.rb
1177
1179
  - pg_rails/scss/bootstrap_overrides.scss