Class: Hyperion::AdminMiddleware

Inherits:
Object
  • Object
show all
Defined in:
lib/hyperion/admin_middleware.rb

Overview

Rack middleware that exposes administrative endpoints on the same listener as the application. Disabled by default — only mounted when ‘admin_token` is configured. Currently provides:

POST /-/quit     →  triggers graceful master drain (SIGTERM to ppid)
GET  /-/metrics  →  returns Hyperion.stats in Prometheus text format

Auth: the request must include ‘X-Hyperion-Admin-Token: <token>`. Mismatch → 401. Path/method mismatch → falls through to the app (so the app can still own /-/anything if Hyperion’s admin is off). When the token is unset, the constructor refuses to wrap — callers must skip mounting this middleware at all.

SECURITY: the bearer token is defense-in-depth, not a substitute for network isolation. Operators MUST keep the listener on a private network or behind TLS + an authenticating reverse proxy. Anyone who can reach the listener AND knows the token can drain the server or scrape its metrics. See docs/REVERSE_PROXY.md for nginx/ALB recipes that block /-/* at the edge.

Constant Summary collapse

PATH_QUIT =
'/-/quit'
PATH_METRICS =
'/-/metrics'
METRICS_CONTENT_TYPE =
'text/plain; version=0.0.4; charset=utf-8'
JSON_CONTENT_TYPE =
'application/json'
UNAUTHORIZED_BODY =
%({"error":"unauthorized"}\n)

Instance Method Summary collapse

Constructor Details

#initialize(app, token:, signal_target: nil) ⇒ AdminMiddleware

Returns a new instance of AdminMiddleware.

Raises:

  • (ArgumentError)


34
35
36
37
38
39
40
41
42
# File 'lib/hyperion/admin_middleware.rb', line 34

def initialize(app, token:, signal_target: nil)
  raise ArgumentError, 'admin_token must be a non-empty String' if token.nil? || token.to_s.empty?

  @app           = app
  @token         = token.to_s
  # Override hook for tests. Defaults to ppid in worker context, pid
  # for single-worker context (caller decides).
  @signal_target = signal_target
end

Instance Method Details

#call(env) ⇒ Object



44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/hyperion/admin_middleware.rb', line 44

def call(env)
  path   = env['PATH_INFO']
  method = env['REQUEST_METHOD']

  if path == PATH_QUIT && method == 'POST'
    authorize(env) { handle_quit(env) }
  elsif path == PATH_METRICS && method == 'GET'
    authorize(env) { handle_metrics }
  else
    @app.call(env)
  end
end