Class: Hitch::Doctor
- Inherits:
-
Object
- Object
- Hitch::Doctor
- Defined in:
- lib/hitch/doctor.rb
Constant Summary collapse
- SCHEMA =
"hitch.doctor.v1"- CHECK_IDS =
%w[ versions configuration resource_discovery route_order migrations registry hosts origins rate_limit_store ].freeze
- REMEDIES =
What to do about it, keyed by the code that named it. A diagnosis without a next step sends the reader back to the source, which is the thing a doctor exists to save them from. Machine consumers get the same answer from
detailsplus this file. { "unsupported" => "Match Hitch's supported window, or upgrade Hitch.", "invalid" => "Run the failing setting's validation directly: Hitch.configuration.validate!", "dynamic_client_registration_rate_store_invalid" => "Configure config.dynamic_client_registration_rate_store with a shared cache store whose two increments return 1 then 2.", "device_authorization_rate_store_invalid" => "Configure config.device_authorization_rate_store with a shared cache store whose two increments return 1 then 2.", "unresolvable" => "Boot the app to see which tool failed; " \ "Hitch.configuration.validate! does not build the registry and will report success.", "mismatch" => "resource_uri must equal the URI clients send as `resource`, byte for byte.", "missing_endpoint" => "Add `match \"/mcp\", to: \"mcp#handle\", via: :all` to config/routes.rb.", "invalid_engine_mount" => "Mount the engine exactly once, at root: `mount Hitch::Engine => \"/\"`.", "wrong_verbs" => "The MCP route needs `via: :all` — the endpoint answers POST and OPTIONS.", "shadowed" => "Move the MCP route above whichever host route matches the same path first.", "after_engine" => "Put the MCP route before `mount Hitch::Engine`.", "missing" => "Run bin/rails db:migrate.", "empty" => "Register a tool: bin/rails generate hitch:tool NAME.", "blocked" => "Add the host to config.hosts, or remove it from Hitch's allowed_hosts.", "insecure_http" => "Use https origins in production; plain http ones cannot be trusted.", "uncountable" => "Point mcp.rate_limit_store at a store whose #increment returns a count.", "unshared" => "Configure a shared config.cache_store (Solid Cache, Redis, Memcached), " \ "or set mcp.rate_limit_store explicitly.", "probe_error" => "The check itself could not run; HITCH_DOCTOR_FORMAT=json names the error class." }.freeze
- ConfigurationStoreError =
Class.new(StandardError) do attr_reader :setting, :store_class def initialize(setting:, store:) @setting = setting.to_s.freeze @store_class = store.class.name.to_s.freeze super("#{@setting} is unusable in production") end end
Class Method Summary collapse
- .call(system: System.new) ⇒ Object
-
.copy_json(value) ⇒ Object
Bounds hostile store output: keys and non-JSON values are coerced to strings, so a broken store cannot put rich objects into the report.
- .render(report, format: "human") ⇒ Object
Instance Method Summary collapse
- #call ⇒ Object
-
#initialize(system:) ⇒ Doctor
constructor
A new instance of Doctor.
Constructor Details
#initialize(system:) ⇒ Doctor
Returns a new instance of Doctor.
446 447 448 |
# File 'lib/hitch/doctor.rb', line 446 def initialize(system:) @system = system end |
Class Method Details
.call(system: System.new) ⇒ Object
407 408 409 |
# File 'lib/hitch/doctor.rb', line 407 def call(system: System.new) new(system:).call end |
.copy_json(value) ⇒ Object
Bounds hostile store output: keys and non-JSON values are coerced to strings, so a broken store cannot put rich objects into the report. Cyclic input raises (and the check reports probe_error) instead of recursing without a floor.
423 424 425 426 427 |
# File 'lib/hitch/doctor.rb', line 423 def copy_json(value) Hitch::MCP::Internal::JsonValues.copy( value, keys: :to_s, symbols: :to_s, foreign: :to_s, freeze: true ) end |
.render(report, format: "human") ⇒ Object
411 412 413 414 415 416 417 |
# File 'lib/hitch/doctor.rb', line 411 def render(report, format: "human") case format when "human" then render_human(report) when "json" then "#{JSON.pretty_generate(report.to_h)}\n" else raise ArgumentError, "HITCH_DOCTOR_FORMAT must be human or json" end end |
Instance Method Details
#call ⇒ Object
450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 |
# File 'lib/hitch/doctor.rb', line 450 def call checks = [ versions_check, configuration_check, resource_discovery_check, route_order_check, migrations_check, registry_check, hosts_check, origins_check, rate_limit_store_check ] raise "Hitch doctor check set drifted" unless checks.map(&:id) == CHECK_IDS overall = if checks.any? { |check| check.status == "fail" } "error" elsif checks.any? { |check| check.status == "warn" } "warning" else "ok" end Report.new(schema: SCHEMA, status: overall, checks:) end |