Module: Wurk::API::ReadOnly

Defined in:
lib/wurk/api/read_only.rb

Overview

Whether this deployment answers anything but reads.

The dashboard has had a read-only mode since the beginning (Wurk::Web.config.read_only, WURK_WEB_READ_ONLY=1): a viewer-only deploy — the public demo is one — where every non-safe verb 403s. The machine plane keeps exactly that rule, verb for verb, so "read-only" means one thing across Wurk instead of two. That freezes admin's destructive routes and enqueue alike: a deployment an operator may not retry a job on is not one a stranger should be able to start a thousand on, and the alternative is a word whose meaning depends on which plane you are standing in.

Only the mount differs, and it has to — see Configuration#api_read_only for the three states. Nested in the engine, this API is part of the dashboard's deployment and inherits its flag through the Rack env (Wurk::Web::Authorization stamps READ_ONLY_ENV). Mounted on its own path or run standalone it is a different deployment, has no engine in front of it to stamp anything, and says so itself or not at all.

Constant Summary collapse

SAFE_METHODS =

RFC 9110 §9.2.1 — the verbs with no side effects the client asked for. The same three the dashboard's Authorization middleware allows; the API registers no OPTIONS route, but a read-only deploy refusing a preflight would be a lie about why.

%w[GET HEAD OPTIONS].freeze

Class Method Summary collapse

Class Method Details

.enabled?(request) ⇒ Boolean

An explicit setting wins both ways — false is how a host keeps its producer live under a read-only dashboard, so it has to outrank what the engine stamped, not merely be OR'd into it.

Returns:

  • (Boolean)

    whether writes are frozen for this request's mount.



40
41
42
43
44
45
# File 'lib/wurk/api/read_only.rb', line 40

def enabled?(request)
  explicit = request.config.api_read_only
  return explicit unless explicit.nil?

  inherited?(request) || request.config.api_read_only?
end

.inherited?(request) ⇒ Boolean

Checked before routing, so a write to a path that does not exist is refused for the reason that applies to every write here rather than 404ing and leaving a client to discover the freeze one route later.

Returns:

  • (Boolean)


63
64
65
# File 'lib/wurk/api/read_only.rb', line 63

def inherited?(request)
  !!request.get_header(::Wurk::API::READ_ONLY_ENV)
end

.refuse(request) ⇒ Array?

Returns a 403 problem triple, or nil to let the request on.

Returns:

  • (Array, nil)

    a 403 problem triple, or nil to let the request on.



48
49
50
51
52
53
54
55
56
57
58
# File 'lib/wurk/api/read_only.rb', line 48

def refuse(request)
  return nil if SAFE_METHODS.include?(request.request_method)
  return nil unless enabled?(request)

  Problem.render(
    Problem::READ_ONLY,
    status: 403,
    detail: 'This Wurk deployment is read-only; it answers GET and HEAD only.',
    instance: request.path
  )
end