team_fastlane-sequel_base_service 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 6767b25b6ef83e0161e2cad7af91e84fc447bbf3314b0f085c5be03d872063ce
4
+ data.tar.gz: eaecbcd7fdb58e511358d0717973930d6f43a9de53adac084d701c245b84f25b
5
+ SHA512:
6
+ metadata.gz: b4a54e6529d050852c5e3020eeb0e57c1a7cdc95f43b43d07603d571f0b8facd1fa6d4ede7eb405d1f4b7d19ac8d4a8fe71f1fdbae598b2400699ef5c1e2ce74
7
+ data.tar.gz: 1b826be91b18de3d89bbda6ae47dca68a1e560bab640e5604ca9dcd4c0981d45700216eb8a19ba1bac3009134f556020b45fe5ed325a47eaf8fda04e8346e78d
data/CHANGELOG.adoc ADDED
@@ -0,0 +1,110 @@
1
+ = Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on https://keepachangelog.com[Keep a Changelog],
6
+ and this project adheres to https://semver.org[Semantic Versioning].
7
+
8
+ == Unreleased
9
+
10
+ == [1.0.0] - 2023-08-01
11
+ === Changed
12
+ Renamed and restructured for release on rubygems
13
+
14
+ == [0.6.0] - 2023-06-20
15
+ === Added
16
+ - New method for handling validation errors
17
+
18
+ == [0.5.1] - 2022-11-14
19
+ === Added
20
+ - `create_or_replace_view_with_grants` is now available
21
+
22
+ == [0.5.0] - 2022-09-12
23
+ === Fixed
24
+ - health check endpoint actually does test the database now
25
+
26
+ == [0.4.0] - 2022-06-03
27
+ === Added
28
+ - Default behavior for parameter filtering
29
+
30
+ == [0.3.1] - 2022-05-05
31
+ === Changed
32
+ - Extend `create_view_with_grants` to prevent SQL injections.
33
+
34
+ == [0.3.0] - 2022-05-04
35
+ === Added
36
+ - New `create_view_with_grants` methods that allows to set permissions while creating a view
37
+
38
+ == [0.2.1] - 2022-03-29
39
+ === Updated
40
+ - olive_branch version updated to 4.0.1
41
+
42
+ == [0.2.0]- 2022-01-03
43
+ === Removed
44
+ - the rubymine debug mode fix seems to be no longer necessary
45
+
46
+ == [0.1.0] - 2021-06-03
47
+ === Added
48
+ - Allow to configure the migrations table.
49
+
50
+ == [0.0.14] - 2021-05-27
51
+ === Changed
52
+ - Revert change of 0.0.13 and inherit from ActionController::Base again. It wasn't working correctly in our setup.
53
+
54
+ == [0.0.13] - 2021-05-17
55
+ === Changed
56
+ - Inherit from ApplicationController instead of ActionController::Base
57
+ (link:https://docs.rubocop.org/rubocop-rails/cops_rails.html#railsapplicationcontroller[Rubocop]).
58
+
59
+ == [0.0.12] - 2021-04-27
60
+ === Changed
61
+ - Updated olive_branch dependency to v4.0.0.
62
+
63
+ == [0.0.11] - 2021-01-13
64
+ === Added
65
+ - Save from ArgumentError with `unprocessable_entity` method.
66
+
67
+ == [0.0.10] - 2020-09-15
68
+ === Changed
69
+ - Use SQL parser to achieve a more sound binding variable implementation
70
+
71
+ == [0.0.9] - 2020-08-20
72
+ === Added
73
+ - Default option for sequel to not dump the schema on migrate
74
+ - Default option for sequel to ignore missing migration files
75
+
76
+ == [0.0.8] - 2020-08-20
77
+ === Removed
78
+ - Migration execution on startup (this made way too much problems everywhere)
79
+
80
+ == [0.0.7] - 2020-08-18
81
+ === Added
82
+ - Allows the addition of a schema to load in sequel
83
+ - Execute existing migrations on startup
84
+
85
+ == [0.0.6] - 2020-07-31
86
+ === Added
87
+ - Allows to disable binding variables by setting Sequel::Oracle::Database.skip_binding_variables to true
88
+
89
+ == [0.0.5] - 2020-07-23
90
+ === Added
91
+ - Added response method `no_content`.
92
+
93
+ === Changed
94
+ - Use json instead of raw text body for error responses `not_found` and `unprocessable_entity`.
95
+
96
+ == [0.0.4] - 2020-07-21
97
+ === Added
98
+ - Added response methods `created` and `unprocessable_entity`.
99
+
100
+ == [0.0.3] - 2020-07-21
101
+ === Added
102
+ - Allow to configure a blacklist of values that are not substituted with binding variables.
103
+
104
+ == [0.0.2] - 2020-07-21
105
+ === Added
106
+ - All Oracle SQL statements use binding variables by default.
107
+
108
+ == [0.0.1] - 2020-07-14
109
+ === Added
110
+ - Initial gem version based on the team_fastlane_base_service.
data/README.adoc ADDED
@@ -0,0 +1,44 @@
1
+ = Team Fastlane Base Service
2
+
3
+ A service base for a ruby micro service using Sequel
4
+
5
+ == Installation
6
+
7
+ As described by the link:../README.adoc[main readme].
8
+
9
+ == Usage
10
+
11
+ === Health Check
12
+
13
+ You can use the link:../bin/health_check[health_check] executable to provide a method of checking the health of the server (database included).
14
+ For example within a docker file like this:
15
+
16
+ [source, Dockerfile]
17
+ ----
18
+ HEALTHCHECK --interval=30s --timeout=30s --start-period=30s --retries=3 CMD [ "bundle", "exec", "health_check" ]
19
+ ----
20
+
21
+ This makes use of an exposed endpoint called `/health_check`, which you can only use for a custom ping to check for it.
22
+
23
+ === Default responses
24
+
25
+ This also provides some default json responses to be used in your controller. See link:./app/controllers/concerns/responses.rb[responses.rb] for more details.
26
+
27
+ To use these responses let your `ApplicationController` inherit from `ApiBaseController` and you are set.
28
+
29
+ === Oracle Binding Variables
30
+
31
+ This Gem automatically interrupts all Oracle DB statements and substitues the values with binding variables. +
32
+ It is possible to deactivate this behaviour:
33
+
34
+ ```rb
35
+ Sequel::Oracle::Database.skip_binding_variables = true
36
+ ```
37
+
38
+ Beware that this is a global setting which de-/activates binding variables for the whole application.
39
+
40
+ === Parameter handling
41
+
42
+ You get automatically camelCase to snake_case transformation for the request and the reverse for responses via the olive_branch gem.
43
+
44
+ There will be a default parameter filtering enabled. It filters passwords of various key names in development and everything in production.
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ApiBaseController < ActionController::Base
4
+ include Responses
5
+
6
+ rescue_from ArgumentError, with: :unprocessable_entity
7
+ rescue_from StandardError, with: :technical_error
8
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Responses
4
+ extend ActiveSupport::Concern
5
+
6
+ protected
7
+
8
+ def bad_request(errors = {})
9
+ render json: errors, status: :bad_request
10
+ end
11
+
12
+ def created(body = {})
13
+ render json: body, status: :created
14
+ end
15
+
16
+ def no_content
17
+ render json: {}, status: :no_content
18
+ end
19
+
20
+ def not_found(body = {})
21
+ render json: body, status: :not_found
22
+ end
23
+
24
+ def ok(content = {})
25
+ render json: content, status: :ok
26
+ end
27
+
28
+ def technical_error(error, status: :internal_server_error)
29
+ Rails.logger.error("#{error.message}\n#{error.backtrace.join("\n")}")
30
+ response = {error: 'Something technical went wrong. Please try again later'}
31
+ if Rails.env.development?
32
+ response[:exception] = "#{error.class.name} : #{error.message}"
33
+ response[:trace] = error.backtrace[0, 10]
34
+ end
35
+ render json: response, status:
36
+ end
37
+
38
+ def unprocessable_entity(body = {})
39
+ render json: body, status: :unprocessable_entity
40
+ end
41
+
42
+ def unauthorized(error)
43
+ technical_error(error, status: :unauthorized)
44
+ end
45
+
46
+ def validation_error(error)
47
+ Rails.logger.warn("Malformed Request: #{error.message}") if Rails.env.production?
48
+ unprocessable_entity(exception: "#{error.class.name}: #{error.message}")
49
+ end
50
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ class HealthCheckController < ApiBaseController
4
+ def check
5
+ return bad_request unless Sequel::Model.db.synchronize { |conn| Sequel::Model.db.valid_connection?(conn) }
6
+
7
+ ok
8
+ rescue StandardError
9
+ bad_request
10
+ end
11
+
12
+ private
13
+
14
+ def bad_request(_errors = {})
15
+ render plain: 'Health Check failed', status: :bad_request
16
+ end
17
+
18
+ def ok(_content = {})
19
+ render plain: 'Health Check OK', status: :ok
20
+ end
21
+ end
data/bin/health_check ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'net/http'
5
+
6
+ port = ENV.fetch('PORT', 3000)
7
+
8
+ health_check = Net::HTTP.get_response(URI("http://127.0.0.1:#{port}/health_check"))
9
+ raise health_check.body if health_check.code.to_i != 200
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'olive_branch'
4
+
5
+ rails_routes = ->(env) { env['PATH_INFO'].match(%r{^/rails}) }
6
+
7
+ Rails.application.middleware.use OliveBranch::Middleware,
8
+ inflection: 'camel',
9
+ exclude_params: rails_routes,
10
+ exclude_response: rails_routes,
11
+ content_type_check: ->(_) { true }
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Be sure to restart your server when you modify this file.
4
+
5
+ # Configure sensitive parameters which will be filtered from the log file.
6
+ Rails.application.config.filter_parameters += %i[passw secret token _key crypt salt certificate otp ssn]
7
+
8
+ Rails.application.config.filter_parameters += [/.*/] if Rails.env.production?
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sequel
4
+ class TimestampMigrator
5
+ def default_schema_table
6
+ Rails.application.config.schema_migrations_table
7
+ rescue NoMethodError
8
+ :team_fastlane_schema_migrations
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'oracle-sql-parser'
4
+
5
+ module Sequel
6
+ module Oracle
7
+ class Database < Sequel::Database
8
+ alias super_execute execute
9
+
10
+ class_attribute :parser, default: OracleSqlParser::Grammar::GrammarParser.new
11
+ class_attribute :skip_binding_variables, default: false
12
+
13
+ def execute(sql, opts = OPTS, &)
14
+ if skip_binding_variables
15
+ super_execute sql, opts, &
16
+ else
17
+ execute_with_binding_variables sql, opts, &
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def execute_with_binding_variables(sql, opts, &)
24
+ ast = parser.parse(sql)&.ast
25
+ if ast.present?
26
+ parameterized = ast.to_parameterized
27
+ bindings = parameterized.params.values.map(&:value)
28
+ super_execute parameterized.to_sql, opts.merge(arguments: bindings), &
29
+ else
30
+ super_execute sql, opts, &
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ module SequelRails
38
+ module Railties
39
+ class LogSubscriber
40
+ Binding = Struct.new(:name, keyword_init: true)
41
+
42
+ alias super_sql sql
43
+
44
+ ##
45
+ # Extends the sql logger of sequel-rails.
46
+ # Adds human-readable names for the binding variables.
47
+ def sql(event)
48
+ event.payload[:binds] = (event.payload[:binds] || []).map.with_index do |bind_value, index|
49
+ [Binding.new(name: "a#{index}:"), bind_value]
50
+ end
51
+
52
+ super_sql event
53
+ end
54
+ end
55
+ end
56
+ end
data/config/routes.rb ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ Rails.application.routes.draw do
4
+ get '/health_check', to: 'health_check#check'
5
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TeamFastlane
4
+ module SequelBaseService
5
+ class Database
6
+ def self.create_view_with_grants(name:, definition:, grantees:)
7
+ db = Sequel::Model.db
8
+ db.create_view(name, definition)
9
+ grantees.each do |grantee|
10
+ db.run("GRANT SELECT ON \"#{name}\" TO #{db.literal(grantee.to_sym)}")
11
+ end
12
+ end
13
+
14
+ def self.create_or_replace_view_with_grants(name:, definition:, grantees:)
15
+ Sequel::Model.db.drop_view(name)
16
+ rescue StandardError
17
+ # Rescue drop_view errors for cases where the view did not exist
18
+ ensure
19
+ create_view_with_grants(name:, definition:, grantees:)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TeamFastlane
4
+ module SequelBaseService
5
+ VERSION = '1.0.0'
6
+ end
7
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'team_fastlane/sequel_base_service/database'
4
+ require 'team_fastlane/sequel_base_service/version'
5
+
6
+ module TeamFastlane
7
+ module SequelBaseService
8
+ class Engine < Rails::Engine
9
+ # Needed as long we have migrations scattered around the services
10
+ config.sequel.allow_missing_migration_files = true
11
+
12
+ # Because we only create views and no tables
13
+ config.sequel.schema_dump = false
14
+
15
+ # This is a hook for having a different schema than the database user in an oracle database
16
+ config.sequel.after_connect = -> do
17
+ if Sequel::Model.db.opts[:schema]
18
+ Sequel::Model.db.run("alter session set current_schema = \"#{Sequel::Model.db.opts[:schema]}\"")
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: team_fastlane-sequel_base_service
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Team Fastlane
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-08-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: olive_branch
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 4.0.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 4.0.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: oracle-sql-parser
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '='
32
+ - !ruby/object:Gem::Version
33
+ version: 1.0.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '='
39
+ - !ruby/object:Gem::Version
40
+ version: 1.0.0
41
+ description:
42
+ email:
43
+ executables:
44
+ - health_check
45
+ extensions: []
46
+ extra_rdoc_files:
47
+ - README.adoc
48
+ - CHANGELOG.adoc
49
+ files:
50
+ - CHANGELOG.adoc
51
+ - README.adoc
52
+ - app/controllers/api_base_controller.rb
53
+ - app/controllers/concerns/responses.rb
54
+ - app/controllers/health_check_controller.rb
55
+ - bin/health_check
56
+ - config/initializers/camelizer.rb
57
+ - config/initializers/filter_parameter_logging.rb
58
+ - config/initializers/migrations_table.rb
59
+ - config/initializers/oracle_binding_variables.rb
60
+ - config/routes.rb
61
+ - lib/team_fastlane/sequel_base_service.rb
62
+ - lib/team_fastlane/sequel_base_service/database.rb
63
+ - lib/team_fastlane/sequel_base_service/version.rb
64
+ homepage:
65
+ licenses:
66
+ - MIT
67
+ metadata:
68
+ rubygems_mfa_required: 'true'
69
+ post_install_message:
70
+ rdoc_options: []
71
+ require_paths:
72
+ - lib
73
+ required_ruby_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: '3.1'
78
+ required_rubygems_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ requirements: []
84
+ rubygems_version: 3.4.10
85
+ signing_key:
86
+ specification_version: 4
87
+ summary: Gem for an internal project
88
+ test_files: []