Class: Aidp::Execute::GuardPolicy
- Inherits:
-
Object
- Object
- Aidp::Execute::GuardPolicy
- Defined in:
- lib/aidp/execute/guard_policy.rb
Overview
Enforces safety constraints during work loops Responsibilities:
-
Check file patterns (include/exclude globs)
-
Enforce max lines changed per commit
-
Track files requiring confirmation
-
Validate changes against policy before execution
Instance Attribute Summary collapse
-
#config ⇒ Object
readonly
Returns the value of attribute config.
-
#project_dir ⇒ Object
readonly
Returns the value of attribute project_dir.
Instance Method Summary collapse
-
#bypass? ⇒ Boolean
Bypass guards (for specific use cases like testing).
-
#can_modify_file?(file_path) ⇒ Boolean
Validate if a file can be modified Returns { allowed: true/false, reason: string }.
-
#confirm_file(file_path) ⇒ Object
Confirm a file for modification (one-time confirmation).
-
#confirmed?(file_path) ⇒ Boolean
Check if file has been confirmed.
-
#disable! ⇒ Object
Disable guards.
-
#enable! ⇒ Object
Enable guards (override bypass).
-
#enabled? ⇒ Boolean
Check if guards are enabled.
-
#files_requiring_confirmation ⇒ Object
Get list of files requiring confirmation.
-
#initialize(project_dir, config) ⇒ GuardPolicy
constructor
A new instance of GuardPolicy.
-
#requires_confirmation?(file_path) ⇒ Boolean
Check if file requires confirmation.
-
#summary ⇒ Object
Get summary of guard policy configuration.
-
#validate_changes(diff_stats) ⇒ Object
Check if total lines changed exceeds limit diff_stats: { file_path => { additions: n, deletions: n } }.
Constructor Details
#initialize(project_dir, config) ⇒ GuardPolicy
Returns a new instance of GuardPolicy.
16 17 18 19 20 |
# File 'lib/aidp/execute/guard_policy.rb', line 16 def initialize(project_dir, config) @project_dir = project_dir @config = config @confirmed_files = Set.new end |
Instance Attribute Details
#config ⇒ Object (readonly)
Returns the value of attribute config.
14 15 16 |
# File 'lib/aidp/execute/guard_policy.rb', line 14 def config @config end |
#project_dir ⇒ Object (readonly)
Returns the value of attribute project_dir.
14 15 16 |
# File 'lib/aidp/execute/guard_policy.rb', line 14 def project_dir @project_dir end |
Instance Method Details
#bypass? ⇒ Boolean
Bypass guards (for specific use cases like testing)
139 140 141 |
# File 'lib/aidp/execute/guard_policy.rb', line 139 def bypass? ENV["AIDP_BYPASS_GUARDS"] == "1" || config.dig(:bypass) == true end |
#can_modify_file?(file_path) ⇒ Boolean
Validate if a file can be modified Returns { allowed: true/false, reason: string }
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/aidp/execute/guard_policy.rb', line 29 def can_modify_file?(file_path) return {allowed: true} unless enabled? normalized_path = normalize_path(file_path) # Check exclude patterns first if excluded?(normalized_path) return { allowed: false, reason: "File matches exclude pattern in guards configuration" } end # Check include patterns (if specified, file must match at least one) if has_include_patterns? && !included?(normalized_path) return { allowed: false, reason: "File does not match any include pattern in guards configuration" } end # Check if file requires confirmation if requires_confirmation?(normalized_path) && !confirmed?(normalized_path) return { allowed: false, reason: "File requires one-time confirmation before modification", requires_confirmation: true, file_path: normalized_path } end {allowed: true} end |
#confirm_file(file_path) ⇒ Object
Confirm a file for modification (one-time confirmation)
64 65 66 67 |
# File 'lib/aidp/execute/guard_policy.rb', line 64 def confirm_file(file_path) normalized_path = normalize_path(file_path) @confirmed_files.add(normalized_path) end |
#confirmed?(file_path) ⇒ Boolean
Check if file has been confirmed
119 120 121 122 |
# File 'lib/aidp/execute/guard_policy.rb', line 119 def confirmed?(file_path) normalized_path = normalize_path(file_path) @confirmed_files.include?(normalized_path) end |
#disable! ⇒ Object
Disable guards
149 150 151 |
# File 'lib/aidp/execute/guard_policy.rb', line 149 def disable! config[:enabled] = false end |
#enable! ⇒ Object
Enable guards (override bypass)
144 145 146 |
# File 'lib/aidp/execute/guard_policy.rb', line 144 def enable! config[:enabled] = true end |
#enabled? ⇒ Boolean
Check if guards are enabled
23 24 25 |
# File 'lib/aidp/execute/guard_policy.rb', line 23 def enabled? config.dig(:enabled) == true end |
#files_requiring_confirmation ⇒ Object
Get list of files requiring confirmation
101 102 103 104 105 106 |
# File 'lib/aidp/execute/guard_policy.rb', line 101 def files_requiring_confirmation return [] unless enabled? patterns = config.dig(:confirm_files) || [] patterns.map { |pattern| (pattern) }.flatten.compact end |
#requires_confirmation?(file_path) ⇒ Boolean
Check if file requires confirmation
109 110 111 112 113 114 115 116 |
# File 'lib/aidp/execute/guard_policy.rb', line 109 def requires_confirmation?(file_path) return false unless enabled? patterns = config.dig(:confirm_files) || [] normalized_path = normalize_path(file_path) patterns.any? { |pattern| matches_pattern?(normalized_path, pattern) } end |
#summary ⇒ Object
Get summary of guard policy configuration
125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'lib/aidp/execute/guard_policy.rb', line 125 def summary return {enabled: false} unless enabled? { enabled: true, include_patterns: config.dig(:include_files) || [], exclude_patterns: config.dig(:exclude_files) || [], confirm_patterns: config.dig(:confirm_files) || [], max_lines_per_commit: config.dig(:max_lines_per_commit), confirmed_files: @confirmed_files.to_a } end |
#validate_changes(diff_stats) ⇒ Object
Check if total lines changed exceeds limit diff_stats: { file_path => { additions: n, deletions: n } }
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/aidp/execute/guard_policy.rb', line 71 def validate_changes(diff_stats) return {valid: true} unless enabled? errors = [] # Check max lines per commit if (max_lines = config.dig(:max_lines_per_commit)) total_changes = calculate_total_changes(diff_stats) if total_changes > max_lines errors << "Total lines changed (#{total_changes}) exceeds limit (#{max_lines})" end end # Check each file against policy diff_stats.each do |file_path, stats| result = can_modify_file?(file_path) unless result[:allowed] errors << "#{file_path}: #{result[:reason]}" end end if errors.any? {valid: false, errors: errors} else {valid: true} end end |