module EhcAnalyze
EhcAnalyze — orchestrate passive fetch, probe, AI hints, and self-improving storage. Public: dispatch, analyze Depends: AiAccess, EhcAgent, EhcFetch, EhcProbe, EhcReport, EhcStore, EhcUrl Tests: test/lib/ehc_analyze_test.rb
Public Instance Methods
Source
# File lib/ehc_analyze.rb, line 35 def analyze(args:, nick:, fetch: nil, eh_fetch: nil, runner: nil, store: RabbotDb, model: EhcAgent::AGENT_MODEL, now: Time.now.utc) resolved = EhcTarget.resolve(args: args, eh_fetch: eh_fetch, now: now) if resolved[:error] reply = target_error_reply(resolved) return { success: false, reply: reply } end url = resolved[:url] host = resolved[:host] focus = resolved[:focus] challenge = resolved[:challenge] http_fetch = fetch || EhcFetch.default_fetch page = EhcFetch.fetch(url, fetch: http_fetch) if page[:error] || page[:body].to_s.empty? detail = page[:error] || "empty response body" return fetch_failure(url, detail: detail) end probe = EhcProbe.analyze(page[:body], url: url) header_lines = EhcFetch.extract_security_headers(page[:headers]) status_line = EhcFetch.format_status_line( status: page[:status], content_type: page[:headers].is_a?(Hash) ? page[:headers]["content-type"] : nil ) robots_body = fetch_robots_body(url, fetch: http_fetch) probe_lines = EhcProbe.signal_lines(probe, headers: [status_line] + header_lines.first(1), robots_body: robots_body) insights = EhcStore.insights_for(host: host, store: store) ai_result = EhcAgent.analyze( url: url, host: host, probe: probe, insights: insights, focus: focus, nick: nick, challenge: challenge, runner: runner, model: model ) return { success: false, reply: EhcReport.format_ai_error(ai_result[:error]) } unless ai_result[:success] EhcStore.record_scan( host: host, scan: { status: page[:status], signals: probe_lines, findings: ai_result[:lines] }, store: store ) { success: true, reply: EhcReport.format_success( host: host, probe_lines: probe_lines, ai_lines: ai_result[:lines], model: ai_result[:model], duration_s: ai_result[:duration_s], focus: focus, challenge: challenge ) } end
Source
# File lib/ehc_analyze.rb, line 19 def dispatch(args:, nick:, ai_allowed:, fetch: nil, eh_fetch: nil, runner: nil, store: RabbotDb, model: EhcAgent::AGENT_MODEL, now: Time.now.utc) return { success: false, reply: AiAccess.denial_message } unless ai_allowed analyze( args: args, nick: nick, fetch: fetch, eh_fetch: eh_fetch, runner: runner, store: store, model: model, now: now ) end
Source
# File lib/ehc_analyze.rb, line 130 def fetch_failure(url, detail: nil) { success: false, reply: EhcReport.format_fetch_error(url, detail: detail) } end
Source
# File lib/ehc_analyze.rb, line 117 def fetch_robots_body(url, fetch:) robots_url = EhcFetch.robots_url(url) return nil if robots_url.nil? response = EhcFetch.fetch(robots_url, fetch: fetch) return nil if response[:error] body = response[:body].to_s body.strip.empty? ? nil : body rescue StandardError nil end
Source
# File lib/ehc_analyze.rb, line 104 def target_error_reply(resolved) case resolved[:error] when :unsafe EhcReport.format_unsafe_url when :not_found EhcReport.format_eh_not_found(index: resolved[:index], listed: resolved[:listed]) when :eh_fetch EhcReport.format_eh_fetch_error else EhcReport.format_usage end end