hephaestus 0.8.11 → 0.8.12.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.ruby-version +1 -1
- data/CHANGELOG.md +12 -0
- data/README.md +3 -1
- data/bin/hephaestus +37 -19
- data/lib/hephaestus/app_builder.rb +23 -145
- data/lib/hephaestus/app_name.rb +33 -0
- data/lib/hephaestus/generators/app_generator.rb +79 -75
- data/lib/hephaestus/generators/base.rb +0 -1
- data/lib/hephaestus/generators/config_generator.rb +3 -114
- data/lib/hephaestus/generators/core_generator.rb +18 -58
- data/lib/hephaestus/generators/db_generator.rb +12 -0
- data/lib/hephaestus/generators/deployment_generator.rb +3 -8
- data/lib/hephaestus/generators/lib_generator.rb +0 -10
- data/lib/hephaestus/generators/license_generator.rb +4 -1
- data/lib/hephaestus/generators/rubocop_generator.rb +1 -1
- data/lib/hephaestus/version.rb +1 -1
- data/lib/hephaestus.rb +2 -1
- data/templates/Dockerfile +7 -75
- data/templates/Gemfile +73 -0
- data/templates/Procfile +2 -0
- data/templates/app/controllers/app_controller.rb.tt +35 -0
- data/templates/app/controllers/application_controller.rb +1 -7
- data/templates/app/controllers/concerns/authable.rb.tt +50 -0
- data/templates/app/controllers/settings_controller.rb +5 -28
- data/templates/app/controllers/yetto_controller.rb +9 -10
- data/templates/app/lib/body_parameter/yetto_parameters.rb +8 -29
- data/templates/app/lib/{constants/app.rb → constants.rb} +1 -3
- data/templates/app/services/{http_service.rb → app_service.rb.tt} +6 -6
- data/templates/app/views/settings/new.json.jbuilder.tt +18 -0
- data/templates/bin/bundle +115 -0
- data/templates/bin/docker-entrypoint +20 -10
- data/templates/bin/foreman +27 -0
- data/templates/bin/jobs +7 -0
- data/templates/bin/rails +6 -0
- data/templates/bin/rake +6 -0
- data/templates/bin/setup +28 -0
- data/templates/bin/tapioca +27 -0
- data/templates/config/application.rb.tt +36 -0
- data/templates/config/boot.rb +7 -0
- data/templates/config/environment.rb +8 -0
- data/templates/config/environments/blank.rb +7 -0
- data/templates/config/initializers/environment.rb +2 -36
- data/templates/config/locales/en.yml +5 -31
- data/templates/config/puma.rb +5 -0
- data/templates/config/routes.rb.tt +28 -0
- data/templates/config.ru +9 -0
- data/templates/db/queue_schema.rb +132 -0
- data/templates/db/schema.rb +17 -0
- data/templates/hephaestus_env.sample +12 -0
- data/templates/hephaestus_github/dependabot.yml +27 -0
- data/templates/hephaestus_github/workflows/automerge.yml +14 -0
- data/templates/hephaestus_github/workflows/deploy.yml +30 -0
- data/templates/hephaestus_github/workflows/licenses.yml +17 -0
- data/templates/hephaestus_github/workflows/lint.yml +17 -0
- data/templates/hephaestus_github/workflows/security.yml +19 -0
- data/templates/hephaestus_github/workflows/sorbet.yml +19 -0
- data/templates/hephaestus_github/workflows/test.yml.tt +21 -0
- data/templates/hephaestus_github/workflows/updater.yml +18 -0
- data/templates/hephaestus_vscode/extensions.json +9 -0
- data/templates/hephaestus_vscode/launch.json +13 -0
- data/templates/hephaestus_vscode/settings.json +58 -0
- data/templates/lib/schemas/api/2023-03-06/components/parameters/headers/yetto.json +42 -0
- data/templates/lib/schemas/api/2023-03-06/components/parameters/plugInstallation.json +12 -0
- data/templates/lib/schemas/api/2023-03-06/components/schemas/plug.json +9 -0
- data/templates/lib/schemas/api/2023-03-06/components/schemas/responses.json +64 -0
- data/templates/lib/schemas/api/2023-03-06/components/schemas/yetto.json +116 -0
- data/templates/lib/schemas/api/2023-03-06/openapi.json +30 -0
- data/templates/lib/schemas/api/2023-03-06/paths/app.json +90 -0
- data/templates/lib/schemas/api/2023-03-06/paths/yetto/message_created.json +51 -0
- data/templates/lib/schemas/api/2023-03-06/paths/yetto/plug_installation_created.json +51 -0
- data/templates/script/docker-build-prod.tt +11 -0
- data/templates/script/docker-run.tt +8 -0
- data/templates/script/edit-credentials +12 -3
- data/templates/script/hmac_text +1 -1
- data/templates/script/ngrok.tt +7 -0
- data/templates/script/server +6 -45
- data/templates/test/controllers/app_controller_test.rb.tt +188 -0
- data/templates/test/controllers/settings_controller_test.rb.tt +125 -0
- data/templates/test/controllers/yetto_controller_test.rb +100 -71
- data/templates/test/fixtures/files/plug_installation_settings/valid.json +1 -1
- data/templates/test/support/rails.rb +16 -36
- data/templates/test/support/webmocks/app_webmock.rb.tt +29 -0
- data/templates/test/test_helper.rb +1 -31
- data/templates/vendor/fly/{fly-production.toml → fly-production.toml.tt} +24 -11
- data/templates/vendor/fly/{fly-staging.toml → fly-staging.toml.tt} +18 -15
- metadata +59 -72
- data/lib/hephaestus/exit_on_failure.rb +0 -22
- data/templates/Gemfile.erb +0 -120
- data/templates/Procfile.debug +0 -2
- data/templates/Procfile.dev +0 -2
- data/templates/app/controllers/app_controller.rb +0 -72
- data/templates/app/controllers/concerns/authable.rb +0 -50
- data/templates/app/controllers/staff_controller.rb +0 -15
- data/templates/app/jobs/update_yetto_job.rb +0 -26
- data/templates/app/lib/headers/yetto.rb +0 -19
- data/templates/app/lib/headers.rb +0 -5
- data/templates/app/lib/path_parameter/settings_parameters.rb +0 -22
- data/templates/app/lib/path_parameter/yetto_parameters.rb +0 -28
- data/templates/app/lib/path_parameter.rb +0 -8
- data/templates/app/lib/plug_app/http.rb +0 -37
- data/templates/app/lib/plug_app/middleware/malformed_request.rb +0 -110
- data/templates/app/lib/plug_app/middleware/openapi_validation.rb +0 -83
- data/templates/app/lib/plug_app/middleware/tracing_attributes.rb +0 -46
- data/templates/app/lib/query_parameter.rb +0 -6
- data/templates/app/serializers/error_serializer.rb +0 -16
- data/templates/app/services/yetto_service.rb +0 -51
- data/templates/app/views/settings/new.json.jbuilder +0 -21
- data/templates/compose.yml +0 -5
- data/templates/config/initializers/000-oj.rb +0 -6
- data/templates/config/initializers/cors.rb +0 -19
- data/templates/config/initializers/filter_parameter_logging.rb +0 -25
- data/templates/config/initializers/inflections.rb +0 -20
- data/templates/config/initializers/lograge.rb +0 -25
- data/templates/config/initializers/opentelemetry.rb +0 -32
- data/templates/config/initializers/sidekiq.rb +0 -11
- data/templates/config/initializers/slack_webhook_logger.rb +0 -17
- data/templates/config/sidekiq.yml +0 -20
- data/templates/script/ngrok +0 -5
- data/templates/test/controllers/settings_controller_test.rb +0 -27
- data/templates/test/fixtures/plug_installation_settings/invalid.json +0 -3
- data/templates/test/fixtures/plug_installation_settings/valid.json +0 -3
- data/templates/test/jobs/update_yetto_job_test.rb +0 -26
- data/templates/test/support/api.rb +0 -76
- data/templates/test/support/webmocks/slack_webmock.rb +0 -24
- data/templates/test/support/webmocks/yetto_webmock.rb +0 -119
- data/templates/test/support/webmocks.rb +0 -5
@@ -1,19 +0,0 @@
|
|
1
|
-
# typed: false
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
module Headers
|
5
|
-
module Yetto
|
6
|
-
YETTO_DELIVERY_ID = "HTTP_X_YETTO_DELIVERY_ID"
|
7
|
-
|
8
|
-
HEADER_EVENT = "HTTP_X_YETTO_EVENT"
|
9
|
-
EVENT_AFTER_CREATE = "created"
|
10
|
-
EVENT_AFTER_UPDATE = "updated"
|
11
|
-
EVENT_AFTER_DESTROY = "destroyed"
|
12
|
-
|
13
|
-
HEADER_RECORD_TYPE = "HTTP_X_YETTO_RECORD_TYPE"
|
14
|
-
RECORD_TYPE_PLUG_INSTALLATION = "plug_installation"
|
15
|
-
RECORD_TYPE_MESSAGE = "message"
|
16
|
-
|
17
|
-
HEADER_SIGNATURE = "HTTP_X_YETTO_SIGNATURE"
|
18
|
-
end
|
19
|
-
end
|
@@ -1,22 +0,0 @@
|
|
1
|
-
# typed: false
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
module PathParameter
|
5
|
-
module SettingsParameters
|
6
|
-
extend T::Sig
|
7
|
-
|
8
|
-
sig { returns(String) }
|
9
|
-
def pparam_plug_installation_id
|
10
|
-
yetto_path_params.fetch(:event, "")
|
11
|
-
end
|
12
|
-
|
13
|
-
sig { returns(T::Hash[Symbol, T.untyped]) }
|
14
|
-
def settings_path_params
|
15
|
-
return {} if params.blank?
|
16
|
-
|
17
|
-
{
|
18
|
-
plug_installation_id: params.fetch(:plug_installation_id, ""),
|
19
|
-
}
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
@@ -1,28 +0,0 @@
|
|
1
|
-
# typed: false
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
module PathParameter
|
5
|
-
module YettoParameters
|
6
|
-
extend T::Sig
|
7
|
-
|
8
|
-
sig { returns(String) }
|
9
|
-
def pparam_yetto_event
|
10
|
-
yetto_path_params.fetch(:event, "")
|
11
|
-
end
|
12
|
-
|
13
|
-
sig { returns(String) }
|
14
|
-
def pparam_yetto_record_type
|
15
|
-
yetto_path_params.fetch(:record_type, "")
|
16
|
-
end
|
17
|
-
|
18
|
-
sig { returns(T::Hash[String, String]) }
|
19
|
-
def yetto_path_params
|
20
|
-
return {} if path_parameters.blank?
|
21
|
-
|
22
|
-
{
|
23
|
-
event: path_parameters.fetch(:event, ""),
|
24
|
-
record_type: path_parameters.fetch(:record_type, ""),
|
25
|
-
}
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
@@ -1,37 +0,0 @@
|
|
1
|
-
# typed: strict
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
module PlugApp
|
5
|
-
module HTTP
|
6
|
-
extend T::Sig
|
7
|
-
|
8
|
-
OK = "OK"
|
9
|
-
OK_I = 200
|
10
|
-
|
11
|
-
CREATED = "Created"
|
12
|
-
CREATED_I = 201
|
13
|
-
NO_CONTENT = "No Content"
|
14
|
-
NO_CONTENT_I = 204
|
15
|
-
|
16
|
-
FOUND = "Found"
|
17
|
-
FOUND_I = 302
|
18
|
-
|
19
|
-
NOT_FOUND = "Not Found"
|
20
|
-
NOT_FOUND_I = 404
|
21
|
-
BAD_REQUEST = "Bad Request"
|
22
|
-
BAD_REQUEST_I = 400
|
23
|
-
UNAUTHORIZED = "Unauthorized"
|
24
|
-
UNAUTHORIZED_I = 401
|
25
|
-
FORBIDDEN = "Forbidden"
|
26
|
-
FORBIDDEN_I = 403
|
27
|
-
NOT_ACCEPTABLE = "Not Acceptable"
|
28
|
-
NOT_ACCEPTABLE_I = 406
|
29
|
-
SERVICE_UNAVAILABLE = "Service Unavailable"
|
30
|
-
SERVICE_UNAVAILABLE_I = 503
|
31
|
-
|
32
|
-
sig { params(status: Integer).returns(T::Boolean) }
|
33
|
-
def status_ok?(status)
|
34
|
-
status == OK_I
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
@@ -1,110 +0,0 @@
|
|
1
|
-
# typed: strict
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
module PlugApp
|
5
|
-
module Middleware
|
6
|
-
# There is no valid reason for a request to contain a malformed string
|
7
|
-
# so just return HTTP 400 (Bad Request) if we receive one
|
8
|
-
class MalformedRequest
|
9
|
-
extend T::Sig
|
10
|
-
|
11
|
-
include ActionController::HttpAuthentication::Basic
|
12
|
-
|
13
|
-
NULL_BYTE_REGEX = T.let(Regexp.new(Regexp.escape("\u0000")).freeze, Regexp)
|
14
|
-
|
15
|
-
sig { returns(T.untyped) }
|
16
|
-
attr_reader :app
|
17
|
-
|
18
|
-
sig { params(app: T.untyped).void }
|
19
|
-
def initialize(app)
|
20
|
-
@app = T.let(app, T.untyped)
|
21
|
-
end
|
22
|
-
|
23
|
-
sig { params(env: T.untyped).returns(T.untyped) }
|
24
|
-
def call(env)
|
25
|
-
return [PlugApp::HTTP::BAD_REQUEST_I, { "Content-Type" => "text/plain" }, [PlugApp::HTTP::BAD_REQUEST]] if request_contains_malformed_string?(env)
|
26
|
-
|
27
|
-
app.call(env)
|
28
|
-
end
|
29
|
-
|
30
|
-
private
|
31
|
-
|
32
|
-
sig { params(env: T.untyped).returns(T::Boolean) }
|
33
|
-
def request_contains_malformed_string?(env)
|
34
|
-
# Duplicate the env, so it is not modified when accessing the parameters
|
35
|
-
# https://github.com/rails/rails/blob/34991a6ae2fc68347c01ea7382fa89004159e019/actionpack/lib/action_dispatch/http/parameters.rb#L59
|
36
|
-
request = ActionDispatch::Request.new(env.dup)
|
37
|
-
|
38
|
-
return true if malformed_path?(request.path)
|
39
|
-
return true if credentials_malformed?(request)
|
40
|
-
|
41
|
-
request.params.values.any? do |value|
|
42
|
-
param_has_null_byte?(value)
|
43
|
-
end
|
44
|
-
rescue ActionController::BadRequest
|
45
|
-
# If we can't build an ActionDispatch::Request something's wrong
|
46
|
-
# This would also happen if `#params` contains invalid UTF-8
|
47
|
-
# in this case we'll return a 400
|
48
|
-
true
|
49
|
-
end
|
50
|
-
|
51
|
-
sig { params(path: String).returns(T::Boolean) }
|
52
|
-
def malformed_path?(path)
|
53
|
-
string_malformed?(Rack::Utils.unescape(path))
|
54
|
-
rescue ArgumentError
|
55
|
-
# Rack::Utils.unescape raised this, path is malformed.
|
56
|
-
true
|
57
|
-
end
|
58
|
-
|
59
|
-
sig { params(request: T.untyped).returns(T::Boolean) }
|
60
|
-
def credentials_malformed?(request)
|
61
|
-
credentials = if has_basic_credentials?(request)
|
62
|
-
decode_credentials(request).presence
|
63
|
-
else
|
64
|
-
request.authorization.presence
|
65
|
-
end
|
66
|
-
|
67
|
-
return false unless credentials
|
68
|
-
|
69
|
-
string_malformed?(credentials)
|
70
|
-
end
|
71
|
-
|
72
|
-
sig { params(value: T.untyped, depth: Integer).returns(T::Boolean) }
|
73
|
-
def param_has_null_byte?(value, depth = 0)
|
74
|
-
# Guard against possible attack sending large amounts of nested params
|
75
|
-
# Should be safe as deeply nested params are highly uncommon.
|
76
|
-
return false if depth > 2
|
77
|
-
|
78
|
-
depth += 1
|
79
|
-
|
80
|
-
if value.respond_to?(:match)
|
81
|
-
string_malformed?(value)
|
82
|
-
elsif value.respond_to?(:values)
|
83
|
-
value.values.any? do |hash_value|
|
84
|
-
param_has_null_byte?(hash_value, depth)
|
85
|
-
end
|
86
|
-
elsif value.is_a?(Array)
|
87
|
-
value.any? do |array_value|
|
88
|
-
param_has_null_byte?(array_value, depth)
|
89
|
-
end
|
90
|
-
else
|
91
|
-
false
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
sig { params(string: String).returns(T::Boolean) }
|
96
|
-
def string_malformed?(string)
|
97
|
-
# We're using match instead of include because that raises an ArgumentError
|
98
|
-
# when the string contains invalid UTF-8
|
99
|
-
#
|
100
|
-
# We try to encode the string from ASCII-8BIT to UTF8. If we failed to do
|
101
|
-
# so for certain characters in the string, those chars are probably incomplete
|
102
|
-
# multibyte characters.
|
103
|
-
string.dup.force_encoding(Encoding::UTF_8).match?(NULL_BYTE_REGEX)
|
104
|
-
rescue ArgumentError, Encoding::UndefinedConversionError
|
105
|
-
# If we're here, we caught a malformed string. Return true
|
106
|
-
true
|
107
|
-
end
|
108
|
-
end
|
109
|
-
end
|
110
|
-
end
|
@@ -1,83 +0,0 @@
|
|
1
|
-
# typed: false
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
require "openapi_first"
|
5
|
-
|
6
|
-
module PlugApp
|
7
|
-
module Middleware
|
8
|
-
class OpenapiValidation
|
9
|
-
API_PATH_PREFIX = "/api/"
|
10
|
-
SPEC_PATH = Rails.root.join("lib/plug_app/schemas/api/2023-03-06/openapi.json")
|
11
|
-
SPEC = OpenapiFirst.load(SPEC_PATH)
|
12
|
-
|
13
|
-
def initialize(app)
|
14
|
-
@app = app
|
15
|
-
end
|
16
|
-
|
17
|
-
def call(env)
|
18
|
-
request = Rack::Request.new(env)
|
19
|
-
|
20
|
-
return @app.call(env) unless request.path.starts_with?(API_PATH_PREFIX) && request.path.exclude?("/settings")
|
21
|
-
|
22
|
-
begin
|
23
|
-
# force content-type to JSON
|
24
|
-
env["CONTENT_TYPE"] = "application/json" if env["CONTENT_TYPE"] != "application/json"
|
25
|
-
|
26
|
-
validated_request = SPEC.validate_request(request)
|
27
|
-
|
28
|
-
return @app.call(env) if validated_request.valid?
|
29
|
-
|
30
|
-
case validated_request.error
|
31
|
-
when OpenapiFirst::Schema::ValidationError
|
32
|
-
error_arr = format_arr(validated_request.error.errors.map(&:message))
|
33
|
-
Rails.logger.error(error_arr) if print_user_api_errors?
|
34
|
-
[PlugApp::HTTP::BAD_REQUEST_I, { "Content-Type" => "application/json" }, [error_arr]]
|
35
|
-
else
|
36
|
-
case validated_request.error.type
|
37
|
-
when :not_found
|
38
|
-
[PlugApp::HTTP::NOT_FOUND_I, { "Content-Type" => "application/json" }, [format_str("Not Found")]]
|
39
|
-
else
|
40
|
-
error_message = if validated_request.error.errors.present?
|
41
|
-
format_arr(validated_request.error.errors.map(&:message))
|
42
|
-
else
|
43
|
-
format_str(validated_request.error.message)
|
44
|
-
end
|
45
|
-
|
46
|
-
Rails.logger.error(error_message) if print_user_api_errors?
|
47
|
-
[PlugApp::HTTP::BAD_REQUEST_I, { "Content-Type" => "application/json" }, [error_message]]
|
48
|
-
end
|
49
|
-
end
|
50
|
-
rescue StandardError => e
|
51
|
-
raise e unless Rails.env.production?
|
52
|
-
|
53
|
-
logger.error(
|
54
|
-
"openapi.request_validation.error",
|
55
|
-
path: request.path,
|
56
|
-
method: request.env["REQUEST_METHOD"],
|
57
|
-
error_message: e.message,
|
58
|
-
)
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
private def format_str(error)
|
63
|
-
{
|
64
|
-
errors: [
|
65
|
-
{
|
66
|
-
message: error,
|
67
|
-
},
|
68
|
-
],
|
69
|
-
}.to_json
|
70
|
-
end
|
71
|
-
|
72
|
-
private def format_arr(errors)
|
73
|
-
{
|
74
|
-
errors: errors.each_with_object([]) do |error, arr|
|
75
|
-
arr << {
|
76
|
-
message: error,
|
77
|
-
}
|
78
|
-
end,
|
79
|
-
}.to_json
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
@@ -1,46 +0,0 @@
|
|
1
|
-
# typed: false
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
require "openapi_first"
|
5
|
-
require "active_support/parameter_filter"
|
6
|
-
|
7
|
-
module PlugApp
|
8
|
-
module Middleware
|
9
|
-
class TracingAttributes
|
10
|
-
extend T::Sig
|
11
|
-
|
12
|
-
sig { returns(T.untyped) }
|
13
|
-
attr_reader :app
|
14
|
-
|
15
|
-
HTTP_REQUEST_BODY = "http.request.body"
|
16
|
-
PLUG_APP_PATH_PREFIX = "/app/"
|
17
|
-
RACK_REQUEST_BODY = "rack.input"
|
18
|
-
|
19
|
-
sig { params(app: T.untyped).void }
|
20
|
-
def initialize(app)
|
21
|
-
@app = T.let(app, T.untyped)
|
22
|
-
@filterer = ActiveSupport::ParameterFilter.new(Rails.application.config.filter_parameters)
|
23
|
-
end
|
24
|
-
|
25
|
-
sig { params(env: T.untyped).returns(T.untyped) }
|
26
|
-
def call(env)
|
27
|
-
OpenTelemetry::Trace.current_span.add_attributes({
|
28
|
-
OpenTelemetry::VERSION => PlugApp::Application::GIT_SHA,
|
29
|
-
OpenTelemetry::SemanticConventions::Trace::HTTP_REQUEST_CONTENT_LENGTH => env["CONTENT_LENGTH"].to_i,
|
30
|
-
HTTP_REQUEST_BODY => filtered_params(env),
|
31
|
-
})
|
32
|
-
|
33
|
-
app.call(env)
|
34
|
-
end
|
35
|
-
|
36
|
-
def filtered_params(env)
|
37
|
-
body = env[RACK_REQUEST_BODY]&.read
|
38
|
-
return "{}" if body.blank? || body == "{}"
|
39
|
-
|
40
|
-
@filterer.filter(JSON.parse(body)).to_json
|
41
|
-
ensure
|
42
|
-
env[RACK_REQUEST_BODY]&.try(:rewind)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
@@ -1,51 +0,0 @@
|
|
1
|
-
# typed: strict
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
class YettoService
|
5
|
-
cattr_reader :yetto_client, instance_accessor: false do
|
6
|
-
Httpsensible::Client.new(user_agent: "PlugApp/#{PlugApp::Application::GIT_SHA}")
|
7
|
-
end
|
8
|
-
|
9
|
-
# explicitly different than what's in environment.rb, because local
|
10
|
-
# Yetto expects HTTP; environment.rb can use HTTPS because it passes through ngrok.io
|
11
|
-
PROTOCOL = Rails.env.development? ? "http" : "https"
|
12
|
-
YETTO_API_VERSION_TLD = "#{PROTOCOL}://#{YETTO_API_TLD}/#{YETTO_API_VERSION}"
|
13
|
-
JWT_ALGORITHM = "RS256"
|
14
|
-
|
15
|
-
class << self
|
16
|
-
def perform_token_exchange(plug_installation_id)
|
17
|
-
encoded_jwt = Httpsensible::JWT.encode_jwt(Hephaestus::YETTO_PLUG_PEM, Hephaestus::YETTO_PLUG_ID)
|
18
|
-
response = yetto_client.with_headers({ "Authorization" => "Bearer #{encoded_jwt}" }).post("#{YETTO_API_VERSION_TLD}/plug/installations/#{plug_installation_id}/access_tokens")
|
19
|
-
body = response.parsed_json_body
|
20
|
-
body["token"]
|
21
|
-
end
|
22
|
-
|
23
|
-
def get_plug_installation(plug_installation_id)
|
24
|
-
token = perform_token_exchange(plug_installation_id)
|
25
|
-
yetto_client.with_headers("Authorization" => "Bearer #{token}").get("#{YETTO_API_VERSION_TLD}/installations/#{plug_installation_id}")
|
26
|
-
end
|
27
|
-
|
28
|
-
def update_plug_installation(plug_installation_id, params)
|
29
|
-
plug_installation = {}
|
30
|
-
plug_installation[:settings] = params.fetch(:settings, {})
|
31
|
-
plug_installation[:credentials] = params.fetch(:credentials, {})
|
32
|
-
|
33
|
-
token = perform_token_exchange(plug_installation_id)
|
34
|
-
yetto_client.with_headers("Authorization" => "Bearer #{token}").patch("#{YETTO_API_VERSION_TLD}/installations/#{plug_installation_id}", json: plug_installation)
|
35
|
-
end
|
36
|
-
|
37
|
-
def update_message(plug_installation_id, message_id, params)
|
38
|
-
payload = params[:payload]
|
39
|
-
token = perform_token_exchange(plug_installation_id)
|
40
|
-
|
41
|
-
yetto_client.with_headers("Authorization" => "Bearer #{token}").patch("#{YETTO_API_VERSION_TLD}/messages/#{message_id}", json: payload)
|
42
|
-
end
|
43
|
-
|
44
|
-
def create_message_reply(message_id, plug_installation_id, params)
|
45
|
-
payload = params[:payload]
|
46
|
-
token = perform_token_exchange(plug_installation_id)
|
47
|
-
|
48
|
-
yetto_client.with_headers("Authorization" => "Bearer #{token}").post("#{YETTO_API_VERSION_TLD}/messages/#{message_id}/replies", json: payload)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
@@ -1,21 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
json.version("2023-03-06")
|
4
|
-
json.settings do
|
5
|
-
json.array!([
|
6
|
-
{
|
7
|
-
component: "text_field",
|
8
|
-
name: "from_name",
|
9
|
-
heading: t(:some_example_heading),
|
10
|
-
placeholder: "{{ organization['name'] }} - {{ inbox['name'] }}",
|
11
|
-
label: t(:some_example),
|
12
|
-
},
|
13
|
-
{
|
14
|
-
component: "email_field",
|
15
|
-
name: "reply_to_email",
|
16
|
-
heading: t(:another_example_heading),
|
17
|
-
placeholder: "{{ inbox['slug'] }}@{{ organization['name'] | downcase }}.biz",
|
18
|
-
label: t(:another_example_label),
|
19
|
-
},
|
20
|
-
])
|
21
|
-
end
|
data/templates/compose.yml
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
# typed: false
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
# Be sure to restart your server when you modify this file.
|
5
|
-
|
6
|
-
# Avoid CORS issues when API is called from the frontend app.
|
7
|
-
# Handle Cross-Origin Resource Sharing (CORS) in order to accept cross-origin AJAX requests.
|
8
|
-
|
9
|
-
# Read more: https://github.com/cyu/rack-cors
|
10
|
-
|
11
|
-
# Rails.application.config.middleware.insert_before 0, Rack::Cors do
|
12
|
-
# allow do
|
13
|
-
# origins "example.com"
|
14
|
-
#
|
15
|
-
# resource "*",
|
16
|
-
# headers: :any,
|
17
|
-
# methods: [:get, :post, :put, :patch, :delete, :options, :head]
|
18
|
-
# end
|
19
|
-
# end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
# typed: false
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
# Be sure to restart your server when you modify this file.
|
5
|
-
|
6
|
-
# Configure parameters to be filtered from the log file. Use this to limit dissemination of
|
7
|
-
# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported
|
8
|
-
# notations and behaviors.
|
9
|
-
Rails.application.config.filter_parameters += [
|
10
|
-
:passw,
|
11
|
-
:secret,
|
12
|
-
:token,
|
13
|
-
:_key,
|
14
|
-
:crypt,
|
15
|
-
:salt,
|
16
|
-
:certificate,
|
17
|
-
:otp,
|
18
|
-
:ssn,
|
19
|
-
:credentials,
|
20
|
-
:state,
|
21
|
-
:access_token,
|
22
|
-
:refresh_token,
|
23
|
-
:html_content,
|
24
|
-
:text_content,
|
25
|
-
]
|
@@ -1,20 +0,0 @@
|
|
1
|
-
# typed: false
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
# Be sure to restart your server when you modify this file.
|
5
|
-
|
6
|
-
# Add new inflection rules using the following format. Inflections
|
7
|
-
# are locale specific, and you may define rules for as many different
|
8
|
-
# locales as you wish. All of these examples are active by default:
|
9
|
-
# ActiveSupport::Inflector.inflections(:en) do |inflect|
|
10
|
-
# inflect.plural /^(ox)$/i, "\\1en"
|
11
|
-
# inflect.singular /^(ox)en/i, "\\1"
|
12
|
-
# inflect.irregular "person", "people"
|
13
|
-
# inflect.uncountable %w( fish sheep )
|
14
|
-
# end
|
15
|
-
|
16
|
-
# These inflection rules are supported but not enabled by default:
|
17
|
-
ActiveSupport::Inflector.inflections(:en) do |inflect|
|
18
|
-
inflect.acronym("API")
|
19
|
-
inflect.acronym("HTTP")
|
20
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
# typed: false
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
Rails.application.configure do
|
5
|
-
config.lograge.enabled = true
|
6
|
-
config.lograge.custom_options = lambda do |event|
|
7
|
-
span = OpenTelemetry::Trace.current_span
|
8
|
-
{
|
9
|
-
time: event.time,
|
10
|
-
trace_id: span.context.hex_trace_id,
|
11
|
-
span_id: span.context.hex_span_id,
|
12
|
-
}
|
13
|
-
end
|
14
|
-
|
15
|
-
config.lograge.custom_payload do |controller|
|
16
|
-
payload = {
|
17
|
-
host: controller.request.host,
|
18
|
-
}
|
19
|
-
|
20
|
-
payload
|
21
|
-
end
|
22
|
-
|
23
|
-
config.lograge.keep_original_rails_log = true
|
24
|
-
config.lograge.logger = ActiveSupport::Logger.new(Rails.root.join("log", "lograge_#{Rails.env}.log"))
|
25
|
-
end
|
@@ -1,32 +0,0 @@
|
|
1
|
-
# typed: false
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
unless Rails.env.development?
|
5
|
-
# establish the environment for OTEL
|
6
|
-
ENV["OTEL_EXPORTER_OTLP_ENDPOINT"] = Rails.application.credentials.fetch(:OTEL_EXPORTER_OTLP_ENDPOINT, ENV.fetch("OTEL_EXPORTER_OTLP_ENDPOINT", "https://api.honeycomb.io"))
|
7
|
-
ENV["OTEL_EXPORTER_OTLP_HEADERS"] = Rails.application.credentials.fetch(:OTEL_EXPORTER_OTLP_HEADERS, ENV.fetch("OTEL_EXPORTER_OTLP_HEADERS", "x-honeycomb-team=your-api-key"))
|
8
|
-
ENV["OTEL_SERVICE_NAME"] = Rails.application.credentials.fetch(:OTEL_SERVICE_NAME, ENV.fetch("OTEL_SERVICE_NAME", "your-service-name"))
|
9
|
-
|
10
|
-
require "opentelemetry/sdk"
|
11
|
-
require "opentelemetry/semantic_conventions"
|
12
|
-
|
13
|
-
OpenTelemetry::SDK.configure do |c|
|
14
|
-
c.logger = Rails.logger
|
15
|
-
|
16
|
-
c.use_all("OpenTelemetry::Instrumentation::PG" => { db_statement: :obfuscate })
|
17
|
-
|
18
|
-
if productionish?
|
19
|
-
c.add_span_processor(
|
20
|
-
OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor.new(
|
21
|
-
OpenTelemetry::Exporter::OTLP::Exporter.new,
|
22
|
-
),
|
23
|
-
)
|
24
|
-
else # useful for testing instrumentation
|
25
|
-
c.add_span_processor(
|
26
|
-
OpenTelemetry::SDK::Trace::Export::SimpleSpanProcessor.new(
|
27
|
-
OpenTelemetry::SDK::Trace::Export::SpanExporter.new,
|
28
|
-
),
|
29
|
-
)
|
30
|
-
end # development is intentionally disabled
|
31
|
-
end
|
32
|
-
end
|
@@ -1,11 +0,0 @@
|
|
1
|
-
# typed: false
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
Sidekiq.configure_server do |config|
|
5
|
-
config.logger = Sidekiq::Logger.new($stdout)
|
6
|
-
config.redis = { url: ENV.fetch("REDIS_URL", "redis://localhost:6379/1") }
|
7
|
-
end
|
8
|
-
Sidekiq.configure_client do |config|
|
9
|
-
config.logger = Sidekiq::Logger.new($stdout)
|
10
|
-
config.redis = { url: ENV.fetch("REDIS_URL", "redis://localhost:6379/1") }
|
11
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
# typed: false
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
SlackWebhookLogger.setup do |config|
|
5
|
-
# Webhook URL
|
6
|
-
#
|
7
|
-
# The URL where messages will be sent.
|
8
|
-
config.webhook_url = SLACK_LOG_URL
|
9
|
-
|
10
|
-
# The minimum error level to see in Slack.
|
11
|
-
#
|
12
|
-
# All log levels are supported, but don't do anything less then :warn since Slack only allows one message
|
13
|
-
# per minute.
|
14
|
-
config.level = :WARN
|
15
|
-
|
16
|
-
config.ignore_patterns = [/Can't verify CSRF token authenticity/, /is not a valid MIME type/]
|
17
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
# Sample configuration file for Sidekiq.
|
2
|
-
# Options here can still be overridden by cmd line args.
|
3
|
-
# Place this file at config/sidekiq.yml and Sidekiq will
|
4
|
-
# pick it up automatically.
|
5
|
-
---
|
6
|
-
:verbose: false
|
7
|
-
:logfile: ./log/sidekiq.log
|
8
|
-
:concurrency: <%= ENV.fetch("SIDEKIQ_CONCURRENCY", 10) %>
|
9
|
-
:timeout: 25
|
10
|
-
:max_retries: 3
|
11
|
-
|
12
|
-
# https://phil.tech/2016/tips-on-sidekiq-queues/
|
13
|
-
:queues:
|
14
|
-
- [update_yetto, 10]
|
15
|
-
|
16
|
-
- [default, 5]
|
17
|
-
- [mailers, 3]
|
18
|
-
|
19
|
-
- [active_storage_analysis, 1]
|
20
|
-
- [active_storage_purge, 1]
|