phronomy 0.5.3 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,100 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Phronomy
4
- module Guardrail
5
- module Builtin
6
- # Input guardrail that detects common PII patterns in the input string.
7
- #
8
- # Four categories are supported and each can be individually toggled:
9
- #
10
- # - +:ssn+ — US Social Security Numbers (###-##-####)
11
- # - +:credit_card+ — Credit / debit card numbers
12
- # - +:email+ — E-mail addresses
13
- # - +:phone+ — Phone numbers
14
- #
15
- # All four categories are active by default.
16
- #
17
- # @example Default — all categories active:
18
- # agent.add_input_guardrail(Phronomy::Guardrail::Builtin::PIIPatternDetector.new)
19
- #
20
- # @example Only check for credit cards and email:
21
- # detector = Phronomy::Guardrail::Builtin::PIIPatternDetector.new(
22
- # detect: [:credit_card, :email]
23
- # )
24
- class PIIPatternDetector < InputGuardrail
25
- # Recognised PII categories and their detection patterns.
26
- PATTERNS = {
27
- # US Social Security Number: ###-##-#### (hyphens required).
28
- ssn: {
29
- pattern: /\b\d{3}-\d{2}-\d{4}\b/,
30
- label: "SSN"
31
- },
32
- # Credit / debit card: 16 digits, optionally separated by spaces or hyphens.
33
- # Matched candidates are additionally validated with the Luhn algorithm
34
- # to eliminate false positives from arbitrary 16-digit sequences.
35
- credit_card: {
36
- pattern: /\b(?:\d{4}[- ]?){3}\d{4}\b/,
37
- label: "credit card number",
38
- validate_luhn: true
39
- },
40
- # Email address (simplified RFC 5322).
41
- email: {
42
- pattern: /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/,
43
- label: "email address"
44
- },
45
- # Phone number: 3-digit area code, 3-4-digit exchange, 4-digit subscriber;
46
- # optional E.164 country-code prefix (e.g. +1, +44).
47
- phone: {
48
- pattern: /(?:\+\d{1,3}[.\- ]?)?\(?\d{3}\)?[.\- ]?\d{3,4}[.\- ]?\d{4}\b/,
49
- label: "phone number"
50
- }
51
- }.freeze
52
-
53
- ALL_CATEGORIES = PATTERNS.keys.freeze
54
-
55
- # @param detect [Array<Symbol>] categories to detect.
56
- # Defaults to all four: +:ssn+, +:credit_card+, +:email+, +:phone+.
57
- # @raise [ArgumentError] when an unknown category symbol is provided.
58
- def initialize(detect: ALL_CATEGORIES)
59
- unknown = Array(detect) - ALL_CATEGORIES
60
- raise ArgumentError, "Unknown PII categories: #{unknown.inspect}" if unknown.any?
61
-
62
- @active_patterns = Array(detect).map { |cat| PATTERNS.fetch(cat) }
63
- end
64
-
65
- # @param value [Object] the input to check
66
- # @raise [Phronomy::GuardrailError] when a PII pattern is matched,
67
- # with a message identifying the category.
68
- def check(value)
69
- text = value.to_s
70
- @active_patterns.each do |entry|
71
- detected = if entry[:validate_luhn]
72
- # Scan for all candidates then filter by Luhn check-digit validation.
73
- # This avoids false positives on arbitrary 16-digit strings (e.g. internal IDs).
74
- text.scan(entry[:pattern]).any? { |m| luhn_valid?(m.gsub(/[- ]/, "")) }
75
- else
76
- text.match?(entry[:pattern])
77
- end
78
- fail!("PII detected in input: #{entry[:label]}") if detected
79
- end
80
- end
81
-
82
- private
83
-
84
- # Returns true when +digits+ (a string of decimal digits) satisfies the
85
- # Luhn check-digit algorithm used by payment card networks.
86
- def luhn_valid?(digits)
87
- digits.chars.reverse.each_with_index.sum do |d, i|
88
- n = d.to_i
89
- if i.odd?
90
- doubled = n * 2
91
- (doubled > 9) ? (doubled - 9) : doubled
92
- else
93
- n
94
- end
95
- end % 10 == 0
96
- end
97
- end
98
- end
99
- end
100
- end
@@ -1,67 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Phronomy
4
- module Guardrail
5
- module Builtin
6
- # Input guardrail that detects common prompt injection attempts.
7
- #
8
- # Matches a built-in list of injection patterns (case-insensitive) and raises
9
- # {Phronomy::GuardrailError} when any pattern is found in the input string.
10
- # Additional patterns can be supplied via the +additional_patterns:+ argument.
11
- #
12
- # **Limitations**: the built-in patterns cover well-known English and Japanese
13
- # phrasings. Obfuscated, Base64-encoded, or novel injection phrasing may not
14
- # be detected. For higher-assurance use cases, combine this guardrail with an
15
- # LLM-based classifier.
16
- #
17
- # @example
18
- # agent.add_input_guardrail(
19
- # Phronomy::Guardrail::Builtin::PromptInjectionDetector.new
20
- # )
21
- #
22
- # # With extra patterns:
23
- # detector = Phronomy::Guardrail::Builtin::PromptInjectionDetector.new(
24
- # additional_patterns: [/do anything now/i]
25
- # )
26
- class PromptInjectionDetector < InputGuardrail
27
- # Default patterns that signal a prompt injection attempt.
28
- DEFAULT_PATTERNS = [
29
- # --- English patterns ---
30
- /ignore\s+(all\s+)?(previous|prior|above)\s+(instructions?|rules?|prompts?)/i,
31
- /disregard\s+(all\s+)?(previous|prior|above)\s+(instructions?|rules?|prompts?)/i,
32
- /forget\s+(all\s+)?(previous|prior|above)\s+(instructions?|rules?|prompts?)/i,
33
- /\bsystem\s*prompt\s*:/i,
34
- /\byou\s+are\s+now\s+(?:a|an)\b/i,
35
- /\bact\s+as\s+(?:a|an)\b/i,
36
- /\bpretend\s+(?:you\s+are|to\s+be)\b/i,
37
- /\bjailbreak\b/i,
38
- /\bdan\s*mode\b/i,
39
- /\bdev(?:eloper)?\s*mode\b/i,
40
- # --- Japanese patterns ---
41
- /以前の(指示|ルール|プロンプト)を無視/,
42
- /指示を無視して/,
43
- /ルールを無視して/,
44
- /あなたは今(から)?(?!助けて)/,
45
- /システムプロンプト/,
46
- /制約(を|から)無視/,
47
- /制限(を|から)解除/
48
- ].freeze
49
-
50
- # @param additional_patterns [Array<Regexp>] extra patterns to check in addition
51
- # to the built-in list.
52
- def initialize(additional_patterns: [])
53
- @patterns = DEFAULT_PATTERNS + Array(additional_patterns)
54
- end
55
-
56
- # @param value [Object] the input to check
57
- # @raise [Phronomy::GuardrailError] when an injection pattern is matched
58
- def check(value)
59
- text = value.to_s
60
- @patterns.each do |pattern|
61
- fail!("Potential prompt injection detected") if text.match?(pattern)
62
- end
63
- end
64
- end
65
- end
66
- end
67
- end
@@ -1,16 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "builtin/prompt_injection_detector"
4
- require_relative "builtin/pii_pattern_detector"
5
-
6
- module Phronomy
7
- module Guardrail
8
- # Namespace for built-in guardrail implementations shipped with phronomy.
9
- #
10
- # Available classes:
11
- # - {Phronomy::Guardrail::Builtin::PromptInjectionDetector}
12
- # - {Phronomy::Guardrail::Builtin::PIIPatternDetector}
13
- module Builtin
14
- end
15
- end
16
- end