actionagent 1.9.5 → 1.9.6
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 +4 -4
- data/app/assets/builds/action_agent.css +1 -1
- data/app/assets/builds/action_agent.js +61 -61
- data/app/controllers/action_agent/api/projects_controller.rb +29 -4
- data/app/controllers/action_agent/api/sandboxes_controller.rb +31 -6
- data/lib/action_agent/version.rb +1 -1
- metadata +2 -2
|
@@ -17,6 +17,8 @@ module ActionAgent
|
|
|
17
17
|
LOG_TAIL_BYTES = 8 * 1024
|
|
18
18
|
LOG_PAGE_BYTES = 64 * 1024
|
|
19
19
|
LOG_MAX_PAGE_BYTES = 1024 * 1024
|
|
20
|
+
# The most of a backend's error the boot status carries (see #boot_report).
|
|
21
|
+
BACKEND_ERROR_BYTES = 1_000
|
|
20
22
|
UPDATABLE = %i[name default_ref start_url].freeze
|
|
21
23
|
|
|
22
24
|
before_action :require_owner!
|
|
@@ -214,18 +216,20 @@ module ActionAgent
|
|
|
214
216
|
# The current sandbox's boot, step by step (see
|
|
215
217
|
# SandboxOrchestrator#boot_status), with the scrubbed tail of the step
|
|
216
218
|
# that failed or is running, and the modes its browser can start in
|
|
217
|
-
# (none when the backend runs no browsers).
|
|
219
|
+
# (none when the backend runs no browsers). When the backend cannot
|
|
220
|
+
# report the boot, `boot` is null and `backend_error` names the backend
|
|
221
|
+
# and the reason (see #boot_report).
|
|
218
222
|
def boot_status
|
|
219
223
|
sandbox = @project.current_sandbox_session
|
|
220
224
|
orchestrator = SandboxOrchestrator.new
|
|
221
|
-
status
|
|
222
|
-
status = SecretScrubber.scrub(status.deep_symbolize_keys, @project.scrub_values) if status.is_a?(Hash)
|
|
225
|
+
status, log_tail, backend_error = boot_report(orchestrator, sandbox)
|
|
223
226
|
|
|
224
227
|
render json: {
|
|
225
228
|
project: @project.summary,
|
|
226
229
|
boot: status,
|
|
227
|
-
log_tail:
|
|
230
|
+
log_tail: log_tail,
|
|
228
231
|
error: sandbox&.failed? ? SecretScrubber.scrub(sandbox.error_summary, @project.scrub_values) : nil,
|
|
232
|
+
backend_error: backend_error,
|
|
229
233
|
logs: sandbox.present? && orchestrator.supports?(:boot_log),
|
|
230
234
|
confirmation: @project.local_boot_confirmation(orchestrator),
|
|
231
235
|
browser_modes: browser_modes(orchestrator)
|
|
@@ -535,6 +539,27 @@ module ActionAgent
|
|
|
535
539
|
[]
|
|
536
540
|
end
|
|
537
541
|
|
|
542
|
+
# The backend's account of the sandbox's boot, scrubbed, with the tail
|
|
543
|
+
# of the step's log that goes with it: [status, log_tail, nil]. When the
|
|
544
|
+
# backend cannot give one (no host configured, the host unreachable, a
|
|
545
|
+
# container that has not written its state yet), [nil, nil, error],
|
|
546
|
+
# where error names the backend and the scrubbed reason. The page then
|
|
547
|
+
# shows the boot as unknown for that reason and keeps following it,
|
|
548
|
+
# instead of failing to load the project (#650). The sandbox's own
|
|
549
|
+
# failure, if it failed, is reported beside it as `error`.
|
|
550
|
+
def boot_report(orchestrator, sandbox)
|
|
551
|
+
return [ nil, nil, nil ] unless sandbox && orchestrator.supports?(:boot_status)
|
|
552
|
+
|
|
553
|
+
status = orchestrator.boot_status(sandbox)
|
|
554
|
+
status = SecretScrubber.scrub(status.deep_symbolize_keys, @project.scrub_values) if status.is_a?(Hash)
|
|
555
|
+
[ status, status && log_tail(orchestrator, sandbox, status), nil ]
|
|
556
|
+
rescue StandardError => e
|
|
557
|
+
Rails.logger.warn("[ActionAgent] the #{orchestrator.backend_name} sandbox backend could not report the boot of " \
|
|
558
|
+
"sandbox #{sandbox.session_id}: #{e.class}: #{e.message}")
|
|
559
|
+
[ nil, nil, { backend: orchestrator.backend_name,
|
|
560
|
+
message: SecretScrubber.scrub(e.message.to_s, @project.scrub_values).truncate(BACKEND_ERROR_BYTES) } ]
|
|
561
|
+
end
|
|
562
|
+
|
|
538
563
|
# The last LOG_TAIL_BYTES of the step that failed, else of the one
|
|
539
564
|
# running, else of the last that ran: { step:, text:, truncated: }.
|
|
540
565
|
def log_tail(orchestrator, sandbox, status)
|
|
@@ -211,18 +211,19 @@ module ActionAgent
|
|
|
211
211
|
# GET /api/sandboxes/:session_id/boot
|
|
212
212
|
# How a checkout's boot went, step by step (see
|
|
213
213
|
# SandboxOrchestrator#boot_status). `boot` is null when the backend
|
|
214
|
-
# reports no steps, or holds nothing for the sandbox
|
|
214
|
+
# reports no steps, or holds nothing for the sandbox; when the backend
|
|
215
|
+
# cannot report it at all, `backend_error` names the backend and the
|
|
216
|
+
# reason (see #boot_report).
|
|
215
217
|
def boot
|
|
216
218
|
orchestrator = SandboxOrchestrator.new
|
|
217
|
-
status =
|
|
218
|
-
|
|
219
|
-
# not know to mask.
|
|
220
|
-
status = SecretScrubber.scrub(status, @sandbox.project_scrub_values) if status
|
|
221
|
-
render json: {
|
|
219
|
+
status, backend_error = boot_report(orchestrator)
|
|
220
|
+
payload = {
|
|
222
221
|
boot: status,
|
|
223
222
|
resumable: !!(status&.dig(:kept) && @sandbox.failed? && !@sandbox.past_expiry? && orchestrator.supports?(:resume_boot)),
|
|
224
223
|
logs: @sandbox.app_runtime? && orchestrator.supports?(:boot_log)
|
|
225
224
|
}
|
|
225
|
+
payload[:backend_error] = backend_error if backend_error
|
|
226
|
+
render json: payload
|
|
226
227
|
end
|
|
227
228
|
|
|
228
229
|
# GET /api/sandboxes/:session_id/boot_log?step=NAME&offset=N&limit=N
|
|
@@ -298,6 +299,30 @@ module ActionAgent
|
|
|
298
299
|
|
|
299
300
|
private
|
|
300
301
|
|
|
302
|
+
# The most of a backend's error the boot status carries (see #boot_report).
|
|
303
|
+
BACKEND_ERROR_BYTES = 1_000
|
|
304
|
+
|
|
305
|
+
# The backend's account of the sandbox's boot, scrubbed of its
|
|
306
|
+
# project's secrets (a project's checkout booted with them, which the
|
|
307
|
+
# backend may not know to mask): [status, nil]. When the backend cannot
|
|
308
|
+
# give one (no host configured, the host unreachable, a container that
|
|
309
|
+
# has not written its state yet), [nil, error], where error names the
|
|
310
|
+
# backend and the scrubbed reason, so the page reports it instead of
|
|
311
|
+
# failing on a 500 (#650; Api::ProjectsController#boot_report is the
|
|
312
|
+
# same for a project).
|
|
313
|
+
def boot_report(orchestrator)
|
|
314
|
+
return [ nil, nil ] unless @sandbox.app_runtime? && orchestrator.supports?(:boot_status)
|
|
315
|
+
|
|
316
|
+
status = orchestrator.boot_status(@sandbox)
|
|
317
|
+
status = SecretScrubber.scrub(status, @sandbox.project_scrub_values) if status
|
|
318
|
+
[ status, nil ]
|
|
319
|
+
rescue StandardError => e
|
|
320
|
+
Rails.logger.warn("[ActionAgent] the #{orchestrator.backend_name} sandbox backend could not report the boot of " \
|
|
321
|
+
"sandbox #{@sandbox.session_id}: #{e.class}: #{e.message}")
|
|
322
|
+
[ nil, { backend: orchestrator.backend_name,
|
|
323
|
+
message: SecretScrubber.scrub(e.message.to_s, @sandbox.project_scrub_values).truncate(BACKEND_ERROR_BYTES) } ]
|
|
324
|
+
end
|
|
325
|
+
|
|
301
326
|
def set_sandbox
|
|
302
327
|
@sandbox = account_scoped(owned(SandboxSession)).find_by!(session_id: params[:id])
|
|
303
328
|
end
|
data/lib/action_agent/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: actionagent
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.9.
|
|
4
|
+
version: 1.9.6
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Justin Bowen
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-10-
|
|
11
|
+
date: 2026-10-30 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activeagent
|