team_fastlane-sequel_base_service 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.adoc +110 -0
- data/README.adoc +44 -0
- data/app/controllers/api_base_controller.rb +8 -0
- data/app/controllers/concerns/responses.rb +50 -0
- data/app/controllers/health_check_controller.rb +21 -0
- data/bin/health_check +9 -0
- data/config/initializers/camelizer.rb +11 -0
- data/config/initializers/filter_parameter_logging.rb +8 -0
- data/config/initializers/migrations_table.rb +11 -0
- data/config/initializers/oracle_binding_variables.rb +56 -0
- data/config/routes.rb +5 -0
- data/lib/team_fastlane/sequel_base_service/database.rb +23 -0
- data/lib/team_fastlane/sequel_base_service/version.rb +7 -0
- data/lib/team_fastlane/sequel_base_service.rb +23 -0
- metadata +88 -0
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,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,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,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,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,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: []
|