Module: PWN::AI::Agent::ToolGuard
- Defined in:
- lib/pwn/ai/agent/tool_guard.rb
Overview
Shared pre-dispatch guards for the two high-volume runtime tools (shell / pwn_eval). Rejects placeholder payloads, aliases wrong schema keys, and names the shell that will actually run the command.
Constant Summary collapse
- ALIASES =
{ 'command' => %w[value cmd input], 'code' => %w[value source ruby input], 'query' => %w[value q text] }.freeze
- PLACEHOLDER_RX =
Token-level junk the model keeps emitting instead of a real command.
/ \A\s*(?:\.{3}|…|\{\s*\.{3}\s*\}|\{\s*…\s*\}|<\.{3}>)\s*\z |(?:^|[\s;|&])(?:\.{3}|…|\{\s*\.{3}\s*\}|\{\s*…\s*\})(?:$|[\s;|&]) /x- BASHISM_RX =
Conservative bash-only constructs. POSIX
$(())is allowed. / \bPIPESTATUS\b |\[\[(?:\s|\z) |(?:^|[\s;|&])source\s+\S |<\([^)] |&> /x
Class Method Summary collapse
- .authors ⇒ Object
- .bashism?(opts = {}) ⇒ Boolean
-
.coerce_args(opts = {}) ⇒ Object
Coerce common wrong keys onto the first required schema field.
- .help ⇒ Object
- .invalid_payload(opts = {}) ⇒ Object
- .placeholder?(opts = {}) ⇒ Boolean
- .present?(opts = {}) ⇒ Boolean
- .shell_bash? ⇒ Boolean
- .shell_name ⇒ Object
Class Method Details
.authors ⇒ Object
97 98 99 |
# File 'lib/pwn/ai/agent/tool_guard.rb', line 97 public_class_method def self. "AUTHOR(S):\n 0day Inc. <support@0dayinc.com>\n" end |
.bashism?(opts = {}) ⇒ Boolean
42 43 44 45 46 |
# File 'lib/pwn/ai/agent/tool_guard.rb', line 42 public_class_method def self.bashism?(opts = {}) BASHISM_RX.match?(opts[:text].to_s) rescue StandardError false end |
.coerce_args(opts = {}) ⇒ Object
Coerce common wrong keys onto the first required schema field. Returns the args hash; sets :__schema_error when still missing.
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
# File 'lib/pwn/ai/agent/tool_guard.rb', line 61 public_class_method def self.coerce_args(opts = {}) args = (opts[:args] || {}).dup args = args.each_with_object({}) { |(k, v), m| m[k.to_sym] = v } unless args.empty? req = Array(opts[:required]).map(&:to_s) req.each do |key| next if present?(value: args[key.to_sym]) hit = Array(ALIASES[key]).find { |a| present?(value: args[a.to_sym]) } args[key.to_sym] = args[hit.to_sym] if hit end missing = req.reject { |k| present?(value: args[k.to_sym]) } unless missing.empty? args[:__schema_error] = "missing required #{missing.join(', ')}" args[:__expected] = req args[:__schema_hint] = "Expected keys: #{req.join(', ')}. " \ 'Do not send value/placeholder/ellipsis. ' \ 'Example: shell(command="uname -r") or pwn_eval(code="1+1").' end args rescue StandardError opts[:args] || {} end |
.help ⇒ Object
101 102 103 104 105 106 107 108 |
# File 'lib/pwn/ai/agent/tool_guard.rb', line 101 public_class_method def self.help puts <<~USAGE USAGE: PWN::AI::Agent::ToolGuard.placeholder?(text: '...') PWN::AI::Agent::ToolGuard.coerce_args(args: { value: 'id' }, required: %w[command]) #{self}.authors USAGE end |
.invalid_payload(opts = {}) ⇒ Object
85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/pwn/ai/agent/tool_guard.rb', line 85 public_class_method def self.invalid_payload(opts = {}) hint = opts[:hint].to_s { stdout: '', stderr: hint, exit: 2, error: 'invalid_payload', hint: hint, shell: opts[:shell] || shell_name } end |
.placeholder?(opts = {}) ⇒ Boolean
36 37 38 39 40 |
# File 'lib/pwn/ai/agent/tool_guard.rb', line 36 public_class_method def self.placeholder?(opts = {}) PLACEHOLDER_RX.match?(opts[:text].to_s) rescue StandardError false end |
.present?(opts = {}) ⇒ Boolean
31 32 33 34 |
# File 'lib/pwn/ai/agent/tool_guard.rb', line 31 public_class_method def self.present?(opts = {}) value = opts.is_a?(Hash) ? opts[:value] : opts !value.nil? && !value.to_s.strip.empty? end |
.shell_bash? ⇒ Boolean
48 49 50 51 52 53 |
# File 'lib/pwn/ai/agent/tool_guard.rb', line 48 public_class_method def self.shell_bash? v = (PWN::Env.dig(:ai, :agent, :shell_bash) if defined?(PWN::Env)) v == true || v.to_s.match?(/\A(1|true|yes|on)\z/i) rescue StandardError false end |
.shell_name ⇒ Object
55 56 57 |
# File 'lib/pwn/ai/agent/tool_guard.rb', line 55 public_class_method def self.shell_name shell_bash? ? 'bash -lc' : '/bin/sh' end |