Class: Browsable::PolicyDetector

Inherits:
Object
  • Object
show all
Defined in:
lib/browsable/policy_detector.rb

Overview

Understands Rails ‘allow_browser` call sites.

Parses controller source with Prism (no Rails boot, no eval) and resolves a call’s ‘versions:` argument — following a constant into the same file, then across the app. It is used two ways:

* PolicyDetector.call(root) — ApplicationController's policy, which drives
  the audit target (see Config).
* #scan_calls(source) — every allow_browser call in one file, for the
  project-wide policy landscape (see PolicyScanner).

When an argument cannot be resolved statically the Result carries a ‘note` instead of a policy.

Defined Under Namespace

Classes: CallInfo, Result

Constant Summary collapse

NONE =

The “nothing found” result.

Result.new(policy: nil, note: nil)
SEARCH_GLOBS =

Where to look for a constant defined outside the file being scanned.

["app/**/*.rb", "config/**/*.rb", "lib/**/*.rb"].freeze
MAX_SEARCH_FILES =
600

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(root) ⇒ PolicyDetector

Returns a new instance of PolicyDetector.



40
41
42
# File 'lib/browsable/policy_detector.rb', line 40

def initialize(root)
  @root = root
end

Class Method Details

.call(root) ⇒ Object



38
# File 'lib/browsable/policy_detector.rb', line 38

def self.call(root) = new(root).application_policy

Instance Method Details

#application_policyObject

The policy declared on ApplicationController — the app-wide audit target. When the controller has several allow_browser calls, the first wins.



46
47
48
49
50
51
52
53
# File 'lib/browsable/policy_detector.rb', line 46

def application_policy
  return NONE unless File.file?(controller_path)

  calls = scan_calls(File.read(controller_path))
  calls.empty? ? NONE : calls.first.result
rescue StandardError => e
  Result.new(policy: nil, note: "could not read the allow_browser policy: #{e.message}")
end

#scan_calls(source) ⇒ Object

Every allow_browser call in a single source file, each resolved.



56
57
58
59
60
61
62
63
64
65
66
# File 'lib/browsable/policy_detector.rb', line 56

def scan_calls(source)
  allow_browser_calls(parse(source)).map do |call|
    CallInfo.new(
      result: resolve(versions_argument(call), controller_source: source),
      only:   action_names(keyword_argument(call, :only)),
      except: action_names(keyword_argument(call, :except))
    )
  end
rescue StandardError
  []
end