forest_admin_agent 1.37.0 → 1.37.1
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
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5f51fef26a1f52081d72076f28f72f437b54a83098e102a42a6296762c9132b7
|
|
4
|
+
data.tar.gz: 21687f62160a1c9cec54ecd22ec825916b01b8e7dba199effa38155bf562d1f7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2cfb0856639abffe732513e6cc01d94f91f7f26e251e211f56405b6b695410a77a66b767315ec5a775ce2f534629121bc44e9315389e5764e338c4da49e911eb
|
|
7
|
+
data.tar.gz: ca3e278582b7166879c261efffbd47e85ae991e1b18867b10ec4d8f05c0eed3505420a455cc3b393730eb8d0a9f16d1b61c422d50e9f198d4d4d75316ed913ce
|
|
@@ -13,6 +13,8 @@ module ForestAdminAgent
|
|
|
13
13
|
attr_reader :customizer, :container, :has_env_secret
|
|
14
14
|
attr_accessor :schema_only_mode
|
|
15
15
|
|
|
16
|
+
ENV_SECRET_FORMAT = /\A[0-9a-f]{64}\z/
|
|
17
|
+
|
|
16
18
|
def initialize
|
|
17
19
|
super
|
|
18
20
|
@reloading = false
|
|
@@ -20,7 +22,7 @@ module ForestAdminAgent
|
|
|
20
22
|
|
|
21
23
|
def setup(options)
|
|
22
24
|
@options = options
|
|
23
|
-
@has_env_secret = options.to_h.
|
|
25
|
+
@has_env_secret = !options.to_h[:env_secret].nil?
|
|
24
26
|
@customizer = ForestAdminDatasourceCustomizer::DatasourceCustomizer.new
|
|
25
27
|
build_container
|
|
26
28
|
build_cache
|
|
@@ -115,6 +117,7 @@ module ForestAdminAgent
|
|
|
115
117
|
end
|
|
116
118
|
|
|
117
119
|
return unless @has_env_secret
|
|
120
|
+
return unless secrets_format_valid?
|
|
118
121
|
|
|
119
122
|
schema = generate_schema_file
|
|
120
123
|
|
|
@@ -127,7 +130,19 @@ module ForestAdminAgent
|
|
|
127
130
|
end
|
|
128
131
|
end
|
|
129
132
|
|
|
130
|
-
|
|
133
|
+
begin
|
|
134
|
+
post_schema(schema, force)
|
|
135
|
+
rescue StandardError => e
|
|
136
|
+
# A well-formed secret can still be rejected by the server (wrong project, revoked
|
|
137
|
+
# secret, network down, ...). Same rule as an invalid format: block boot in
|
|
138
|
+
# production, but never in dev - warn and move on instead. Scoped to this call
|
|
139
|
+
# only, so a local bug (a broken customization, an unwritable schema_path, ...)
|
|
140
|
+
# still surfaces immediately instead of being logged as a generic warning.
|
|
141
|
+
raise e if Facades::Container.cache(:is_production)
|
|
142
|
+
|
|
143
|
+
@logger.log('Warn', "[ForestAdmin] #{e.message}")
|
|
144
|
+
@logger.log('Warn', '[ForestAdmin] Schema sync failed, continuing without it.')
|
|
145
|
+
end
|
|
131
146
|
end
|
|
132
147
|
|
|
133
148
|
# Generates or loads the schema and writes it to file (in development mode).
|
|
@@ -175,6 +190,40 @@ module ForestAdminAgent
|
|
|
175
190
|
|
|
176
191
|
private
|
|
177
192
|
|
|
193
|
+
# Checked from send_schema rather than setup, so that schema-only mode (which never
|
|
194
|
+
# syncs to the server) never fails on a secret it doesn't actually need.
|
|
195
|
+
def secrets_format_valid?
|
|
196
|
+
errors = secret_format_errors
|
|
197
|
+
return true if errors.empty?
|
|
198
|
+
|
|
199
|
+
if Facades::Container.cache(:is_production)
|
|
200
|
+
raise ForestAdminAgent::Http::Exceptions::ValidationError, errors.join(' ')
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# Don't block boot on a config mistake in dev: warn loudly and skip the schema
|
|
204
|
+
# sync instead, so the developer can still work on the rest of the app.
|
|
205
|
+
errors.each { |error| @logger.log('Warn', "[ForestAdmin] #{error}") }
|
|
206
|
+
@logger.log('Warn', '[ForestAdmin] Skipping schema sync until this is fixed.')
|
|
207
|
+
false
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def secret_format_errors
|
|
211
|
+
errors = []
|
|
212
|
+
env_secret = @options.to_h[:env_secret]
|
|
213
|
+
|
|
214
|
+
unless env_secret.is_a?(String) && env_secret.match?(ENV_SECRET_FORMAT)
|
|
215
|
+
errors << 'config.env_secret is invalid: it must be the 64-character hexadecimal secret from your ' \
|
|
216
|
+
'Forest Admin project settings.'
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
auth_secret = @options.to_h[:auth_secret]
|
|
220
|
+
unless auth_secret.is_a?(String)
|
|
221
|
+
errors << 'config.auth_secret is invalid: it must be a string. Any long random value works.'
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
errors
|
|
225
|
+
end
|
|
226
|
+
|
|
178
227
|
def container_replace(key, value)
|
|
179
228
|
@container._container.delete(key.to_s)
|
|
180
229
|
@container.register(key, value)
|
|
@@ -211,6 +260,7 @@ module ForestAdminAgent
|
|
|
211
260
|
|
|
212
261
|
begin
|
|
213
262
|
response = client.post('/forest/apimaps/hashcheck', { schemaFileHash: hash }.to_json)
|
|
263
|
+
client.raise_for_response!(response)
|
|
214
264
|
body = JSON.parse(response.body)
|
|
215
265
|
body['sendSchema']
|
|
216
266
|
rescue JSON::ParserError => e
|
|
@@ -281,7 +331,8 @@ module ForestAdminAgent
|
|
|
281
331
|
def send_schema_to_server(api_map)
|
|
282
332
|
ForestAdminAgent::Facades::Container.logger.log('Info', 'schema was updated, sending new version')
|
|
283
333
|
client = ForestAdminAgent::Http::ForestAdminApiRequester.new
|
|
284
|
-
client.post('/forest/apimaps', api_map.to_json)
|
|
334
|
+
response = client.post('/forest/apimaps', api_map.to_json)
|
|
335
|
+
client.raise_for_response!(response)
|
|
285
336
|
rescue Faraday::Error => e
|
|
286
337
|
status = e.response[:status] if e.response
|
|
287
338
|
if status
|
|
@@ -41,33 +41,48 @@ module ForestAdminAgent
|
|
|
41
41
|
)
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
raise_for_status(error.response[:status], cause: error)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Faraday does not raise on HTTP error statuses here (no raise_error middleware
|
|
48
|
+
# configured), so a response has to be checked explicitly to turn e.g. an
|
|
49
|
+
# invalid envSecret (404) into the same typed errors as handle_response_error.
|
|
50
|
+
def raise_for_response!(response)
|
|
51
|
+
return if response.success?
|
|
52
|
+
|
|
53
|
+
raise_for_status(response.status, message: response.reason_phrase)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
|
|
58
|
+
def raise_for_status(status, cause: nil, message: cause&.message)
|
|
59
|
+
if status.zero? || status == 502
|
|
45
60
|
raise BadGatewayError.new(
|
|
46
61
|
'Failed to reach ForestAdmin server. Are you online?',
|
|
47
|
-
details: { status:
|
|
48
|
-
cause:
|
|
62
|
+
details: { status: status },
|
|
63
|
+
cause: cause
|
|
49
64
|
)
|
|
50
65
|
end
|
|
51
66
|
|
|
52
|
-
if
|
|
67
|
+
if status == 404
|
|
53
68
|
raise NotFoundError.new(
|
|
54
69
|
'ForestAdmin server failed to find the project related to the envSecret you configured. Can you check that you copied it properly in the Forest initialization?',
|
|
55
|
-
details: { status:
|
|
70
|
+
details: { status: status }
|
|
56
71
|
)
|
|
57
72
|
end
|
|
58
73
|
|
|
59
|
-
if
|
|
74
|
+
if status == 503
|
|
60
75
|
raise ServiceUnavailableError.new(
|
|
61
76
|
'Forest is in maintenance for a few minutes. We are upgrading your experience in the forest. We just need a few more minutes to get it right.',
|
|
62
|
-
details: { status:
|
|
63
|
-
cause:
|
|
77
|
+
details: { status: status },
|
|
78
|
+
cause: cause
|
|
64
79
|
)
|
|
65
80
|
end
|
|
66
81
|
|
|
67
82
|
raise InternalServerError.new(
|
|
68
83
|
'An unexpected error occurred while contacting the ForestAdmin server. Please contact support@forestadmin.com for further investigations.',
|
|
69
|
-
details: { status:
|
|
70
|
-
cause:
|
|
84
|
+
details: { status: status, message: message },
|
|
85
|
+
cause: cause
|
|
71
86
|
)
|
|
72
87
|
end
|
|
73
88
|
end
|