Class: Rigor::Plugin::TrustPolicy

Inherits:
Object
  • Object
show all
Defined in:
lib/rigor/plugin/trust_policy.rb,
sig/rigor/plugin/trust_policy.rbs

Overview

Declarative trust / I/O policy for the active plugin set. Pinned by ADR-2 § "Plugin Trust and I/O Policy": plugins are trusted Ruby gems selected by the user, their Gemfile, or project configuration; this class is the programmatic surface that documents that trust and lets the analyzer enforce read scope + network disablement at the documented edges.

The policy is not a sandbox. A plugin that uses raw File.read or Net::HTTP bypasses the policy — ADR-2 explicitly chooses documentation over forced isolation. The contract is: when plugins go through IoBoundary (the analyzer-side helper service slice 2 introduces), the boundary checks against this policy and feeds compliant reads into the cache descriptor for invalidation. Slices 3-6 wire plugin contributions through the boundary so the policy is the actual mechanism, not just paperwork.

Fields

  • trusted_gems: gem names the user has authorised. Derived from the plugins: section of .rigor.yml plus any gems they reach transitively. Used today for documentation and future trust diagnostics.
  • allowed_read_roots: absolute paths plugin code may read from through the IoBoundary. The default set covers the project root, the project's signature_paths, the active Gemfile.lock, and each trusted gem's Gem::Specification#full_gem_path. The user extends this with .rigor.yml's plugins_io.allowed_paths:.
  • network_policy: one of VALID_NETWORK_POLICIES. :disabled (default) makes IoBoundary#open_url always raise. :allowlist (v0.1.2) consults allowed_url_hosts on every fetch — the hostname must be on the list and the URL scheme MUST be https. The list of allowed hosts is exact-match (no wildcards in v0.1.2).

Constant Summary collapse

VALID_NETWORK_POLICIES =
%i[disabled allowlist].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(trusted_gems: [], allowed_read_roots: [], network_policy: :disabled, allowed_url_hosts: []) ⇒ TrustPolicy

Returns a new instance of TrustPolicy.

Parameters:

  • trusted_gems: (Object) (defaults to: [])
  • allowed_read_roots: (Object) (defaults to: [])
  • network_policy: (Object) (defaults to: :disabled)
  • allowed_url_hosts: (Object) (defaults to: [])


34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/rigor/plugin/trust_policy.rb', line 34

def initialize(trusted_gems: [], allowed_read_roots: [], network_policy: :disabled, allowed_url_hosts: [])
  validate_network_policy!(network_policy)

  @trusted_gems = trusted_gems.map { |g| g.to_s.dup.freeze }.uniq.sort.freeze
  @allowed_read_roots = allowed_read_roots
                        .map { |path| File.expand_path(path).freeze }
                        .uniq
                        .sort
                        .freeze
  @network_policy = network_policy
  @allowed_url_hosts = allowed_url_hosts.map { |h| h.to_s.downcase.dup.freeze }.uniq.sort.freeze
  freeze
end

Instance Attribute Details

#allowed_read_rootsObject (readonly)

Returns the value of attribute allowed_read_roots.



32
33
34
# File 'lib/rigor/plugin/trust_policy.rb', line 32

def allowed_read_roots
  @allowed_read_roots
end

#allowed_url_hostsObject (readonly)

Returns the value of attribute allowed_url_hosts.



32
33
34
# File 'lib/rigor/plugin/trust_policy.rb', line 32

def allowed_url_hosts
  @allowed_url_hosts
end

#network_policyObject (readonly)

Returns the value of attribute network_policy.



32
33
34
# File 'lib/rigor/plugin/trust_policy.rb', line 32

def network_policy
  @network_policy
end

#trusted_gemsObject (readonly)

Returns the value of attribute trusted_gems.



32
33
34
# File 'lib/rigor/plugin/trust_policy.rb', line 32

def trusted_gems
  @trusted_gems
end

Instance Method Details

#allow_read?(path) ⇒ Boolean

Returns true when the absolute path falls inside any allowed read root. Symlinks are resolved through File.expand_path only (no realpath); plugins with adversarial intent are out of scope per ADR-2.

Parameters:

  • path (String)

Returns:

  • (Boolean)

    true when the absolute path falls inside any allowed read root. Symlinks are resolved through File.expand_path only (no realpath); plugins with adversarial intent are out of scope per ADR-2.



52
53
54
55
# File 'lib/rigor/plugin/trust_policy.rb', line 52

def allow_read?(path)
  absolute = File.expand_path(path.to_s)
  @allowed_read_roots.any? { |root| inside?(absolute, root) }
end

#allow_url?(url) ⇒ Boolean

Returns true when the URL scheme is https and the parsed hostname is in allowed_url_hosts. Always false while network_policy is :disabled.

Parameters:

  • url (String, URI)

Returns:

  • (Boolean)

    true when the URL scheme is https and the parsed hostname is in allowed_url_hosts. Always false while network_policy is :disabled.



64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/rigor/plugin/trust_policy.rb', line 64

def allow_url?(url)
  return false if @network_policy == :disabled
  return false if @allowed_url_hosts.empty?

  require "uri"
  uri = url.is_a?(URI::Generic) ? url : URI.parse(url.to_s)
  return false unless uri.is_a?(URI::HTTPS)
  return false if uri.host.nil?

  @allowed_url_hosts.include?(uri.host.downcase)
rescue URI::InvalidURIError
  false
end

#gem_trusted?(name) ⇒ Boolean

Returns:

  • (Boolean)


78
79
80
# File 'lib/rigor/plugin/trust_policy.rb', line 78

def gem_trusted?(name)
  @trusted_gems.include?(name.to_s)
end

#network_allowed?Boolean

Returns:

  • (Boolean)


57
58
59
# File 'lib/rigor/plugin/trust_policy.rb', line 57

def network_allowed?
  @network_policy != :disabled
end

#to_hHash[String, untyped]

Returns:

  • (Hash[String, untyped])


82
83
84
85
86
87
88
89
# File 'lib/rigor/plugin/trust_policy.rb', line 82

def to_h
  {
    "trusted_gems" => trusted_gems,
    "allowed_read_roots" => allowed_read_roots,
    "network_policy" => network_policy.to_s,
    "allowed_url_hosts" => allowed_url_hosts
  }
end