class Analyzer::Ruby::ActionCable

Overview

Surfaces Rails Action Cable real-time attack surface as ws:// endpoints. An ApplicationCable::Channel subclass exposes public methods the client invokes as actions (perform("speak", ...)) over the cable connection; mount ActionCable.server => "/cable" mounts the connection in config/routes.rb. Each callable action becomes one endpoint ws://<mount>/<Channel>/<action> (bare ws://<mount>/<Channel> when a channel has no actions), method "SEND", protocol "ws" — so the existing WebsocketTagger tags them.

Line-scan analyzer (Ruby house style). The cable mount lives in routes.rb while channels live under app/channels/, so the mount is collected across every .rb file first, then joined onto the channels.

Defined in:

analyzer/analyzers/ruby/actioncable.cr

Constant Summary

CABLE_MOUNT = /\bmount\s+ActionCable\.server\s*=>\s*["']([^"']+)["']/

mount ActionCable.server => "/cable".

CHANNEL_CLASS = /^\s*class\s+(\w+)\s*<\s*(?:ApplicationCable::Channel|ActionCable::Channel::Base)\b/

class ChatChannel < ApplicationCable::Channel (or the framework base ActionCable::Channel::Base). The base module class ApplicationCable::Channel < ... carries a :: in the subclass name, so (\w+) never matches it — the base definition is skipped.

DEF_RE = /^\s*def\s+([a-z_]\w*[?!]?)\s*(?:[(\s]|$)/

An instance method definition (Ruby CLI house-style regex).

DEFAULT_MOUNT = "cable"

Rails' default Action Cable mount path when routes.rb does not mount it explicitly (a standalone cable server still serves /cable).

NON_ACTION_METHODS = Set {"subscribed", "unsubscribed", "initialize"}

Action Cable lifecycle callbacks — never client-invocable actions.

NON_CHANNEL_NAMES = Set {"Channel"}

The generated ApplicationCable::Channel base (class Channel < ActionCable::Channel::Base) matches CHANNEL_CLASS but is the shared base, not a real channel. Real channels follow the <Feature>Channel convention, so the bare name "Channel" is the base to skip.

Instance Method Summary

Instance methods inherited from class Analyzer::Ruby::RubyEngine

line_to_endpoint(content : String, details : Details | Nil = nil) : Endpoint line_to_endpoint

Class methods inherited from class Analyzer::Ruby::RubyEngine

ruby_test_path?(path : String) : Bool ruby_test_path?

Instance methods inherited from class Analyzer

analyze analyze, base_path : String base_path, base_paths : Array(String) base_paths, callees_needed? : Bool callees_needed?, http_header_name(name : String) : String | Nil http_header_name, line_number_for_index(content : String, char_index : Int32) : Int32 line_number_for_index, logger : NoirLogger logger, parallel_analyze(files : Array(String), &block : String -> Nil) parallel_analyze, read_file_content(path : String) : String read_file_content, result : Array(Endpoint) result, unique_params(params : Array(Param)) : Array(Param) unique_params, url : String url, web_root_path(path : String, markers : Array(String)) : String web_root_path

Constructor methods inherited from class Analyzer

new(options : Hash(String, YAML::Any)) new

Instance methods inherited from module FileHelper

all_files : Array(String) all_files, get_files_by_extension(extension : String) : Array(String) get_files_by_extension, get_files_by_extensions(extensions : Array(String)) : Array(String) get_files_by_extensions, get_files_by_prefix(prefix : String) : Array(String) get_files_by_prefix, get_files_by_prefix_and_extension(prefix : String, extension : String) : Array(String) get_files_by_prefix_and_extension, get_public_dir_files(base_path : String, folder : String) : Array(String) get_public_dir_files, get_public_files(base_path : String, anchors : Array(String) = ["shard.yml", "Gemfile"]) : Array(String) get_public_files

Instance Method Detail

def analyze #

[View source]