guardrails-ruby 0.1.1 → 0.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d06593e6904bc4cb5c303bbd4eea1ad890eee72dd5941287f90929c174da05d5
4
- data.tar.gz: ba5f54f032cbcf1d90bb785378de12b4ba71bc29882d0c053d90da4dbc498247
3
+ metadata.gz: 6012f0c117ac82c9c7feb863260f3b84f5ec527dccbe1d85390eff74c7e192e6
4
+ data.tar.gz: e2dab3618bb598cf932bb4e57c5300242e1816c893dee844084c8c36bc396deb
5
5
  SHA512:
6
- metadata.gz: 558a0f6b675528b2a2241354fb17b981a4716bef878c6cb5ba2c6d5eb291e9a56abbfa955dd527d445f50d6520ea617d3a972bc97b280b2452a461524e4b6a0f
7
- data.tar.gz: 9afe4a850e5e9a6dacbd2c8037c5357cd795534e1bd166fc2377cfe5e6bbbacec9263c75be166709546ec566ab56cfe9f4beb1a30d86dd37211896b6b27d062c
6
+ metadata.gz: a0777fb4f923885b9975f7ab174f9d1c3105551957cc71571921fbc34ad1daa26647b707a5605050d877002b0339336db6ce89276a77003ea4eb7baffc802c4d
7
+ data.tar.gz: a6565dc714a17497fdbe907b654c073ab00be71a39c39ae05e78d176ac7e160ad2b06f11507c32ddd825888ad178877f41d0396ace3d5647426e0beb4b3983cf
data/MILESTONES.md ADDED
@@ -0,0 +1,11 @@
1
+ # Milestones
2
+
3
+ ## v0.1.1 (2026-03-10)
4
+
5
+ ### Changes
6
+ - Error type fixes
7
+ - nil input handling
8
+ - 7 new test files for untested checks
9
+
10
+ ## v0.1.0 (Initial release)
11
+ - Initial release
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GuardrailsRuby
4
+ module Checks
5
+ class CodeExecution < Check
6
+ check_name :code_execution
7
+ direction :input
8
+
9
+ PATTERNS = [
10
+ # Shell commands
11
+ /\brm\s+-rf\b/i,
12
+ /\brm\s+-f\b/i,
13
+ /\bcurl\b.+\|\s*(ba)?sh\b/i,
14
+ /\bwget\b.+\|\s*(ba)?sh\b/i,
15
+ /\bchmod\s+[0-7]{3,4}\b/,
16
+ /\bchown\b/,
17
+ /\bsudo\b/,
18
+ /\bmkdir\s+-p\b/,
19
+ /\bdd\s+if=/,
20
+ /\b:(){ :\|:& };:/, # fork bomb
21
+
22
+ # Code execution functions
23
+ /\beval\s*\(/i,
24
+ /\bexec\s*\(/i,
25
+ /\bsystem\s*\(/i,
26
+ /\b__import__\s*\(/i,
27
+ /\bos\.system\s*\(/i,
28
+ /\bsubprocess\.(run|call|Popen)\s*\(/i,
29
+ /\bRuntime\.getRuntime\(\)\.exec\s*\(/i,
30
+
31
+ # Shell interpolation
32
+ /`[^`]+`/, # backticks
33
+ /\$\([^)]+\)/, # $() command substitution
34
+
35
+ # Dangerous redirects
36
+ />\s*\/dev\/sd[a-z]/,
37
+ />\s*\/etc\//,
38
+ /;\s*shutdown\b/i,
39
+ /;\s*reboot\b/i,
40
+ /;\s*halt\b/i,
41
+ /\bpowershell\b.+-enc/i,
42
+ ].freeze
43
+
44
+ def call(text, context: {})
45
+ matched = PATTERNS.select { |p| text.match?(p) }
46
+
47
+ if matched.any?
48
+ fail! "Potential code execution detected",
49
+ matches: matched.map(&:source)
50
+ else
51
+ pass!
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GuardrailsRuby
4
+ module Checks
5
+ class Disclaimer < Check
6
+ check_name :disclaimer
7
+ direction :output
8
+
9
+ DEFAULT_PHRASES = [].freeze
10
+
11
+ def call(text, context: {})
12
+ required = @options.fetch(:required_phrases, DEFAULT_PHRASES)
13
+ return pass! if required.empty?
14
+
15
+ missing = required.reject do |phrase|
16
+ text.downcase.include?(phrase.downcase)
17
+ end
18
+
19
+ if missing.any?
20
+ fail! "Missing required disclaimers: #{missing.join('; ')}",
21
+ matches: missing
22
+ else
23
+ pass!
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -12,7 +12,13 @@ module GuardrailsRuby
12
12
  email: /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/,
13
13
  phone_us: /\b(?:\+?1[-.]?)?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}\b/,
14
14
  ip_address: /\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,
15
- date_of_birth: /\b(?:DOB|date of birth|born)[:\s]*\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4}\b/i
15
+ date_of_birth: /\b(?:DOB|date of birth|born)[:\s]*\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4}\b/i,
16
+
17
+ # International formats
18
+ nik_indonesia: /\b\d{16}\b/,
19
+ phone_international: /\b\+(?:62|44|49|33|81|86|91|61|64|65)\d{8,12}\b/,
20
+ iban: /\b[A-Z]{2}\d{2}[A-Z0-9]{4}\d{7}(?:[A-Z0-9]{0,16})\b/,
21
+ passport: /\b[A-Z]{1,2}\d{6,9}\b/
16
22
  }.freeze
17
23
 
18
24
  REDACT_MAP = {
@@ -21,12 +27,19 @@ module GuardrailsRuby
21
27
  email: "[EMAIL REDACTED]",
22
28
  phone_us: "[PHONE REDACTED]",
23
29
  ip_address: "[IP REDACTED]",
24
- date_of_birth: "[DOB REDACTED]"
30
+ date_of_birth: "[DOB REDACTED]",
31
+ nik_indonesia: "[NIK REDACTED]",
32
+ phone_international: "[PHONE REDACTED]",
33
+ iban: "[IBAN REDACTED]",
34
+ passport: "[PASSPORT REDACTED]"
25
35
  }.freeze
26
36
 
27
37
  def call(text, context: {})
38
+ enabled = @options.fetch(:patterns, PATTERNS.keys)
28
39
  found = {}
40
+
29
41
  PATTERNS.each do |type, pattern|
42
+ next unless enabled.include?(type)
30
43
  matches = text.scan(pattern)
31
44
  found[type] = matches if matches.any?
32
45
  end
@@ -7,6 +7,7 @@ module GuardrailsRuby
7
7
  direction :input
8
8
 
9
9
  INJECTION_PATTERNS = [
10
+ # Original patterns
10
11
  /ignore\s+(all\s+)?previous\s+instructions/i,
11
12
  /ignore\s+(all\s+)?above/i,
12
13
  /disregard\s+(all\s+)?previous/i,
@@ -18,7 +19,39 @@ module GuardrailsRuby
18
19
  /\[\s*system\s*\]/i,
19
20
  /<\s*system\s*>/i,
20
21
  /```\s*(system|instruction)/i,
21
- /STOP\.?\s*(forget|ignore|disregard)/i
22
+ /STOP\.?\s*(forget|ignore|disregard)/i,
23
+
24
+ # Role-play and identity attacks
25
+ /from\s+now\s+on\s+(you|your)\s+(are|will|must|should)/i,
26
+ /forget\s+(everything|all|your)\s+(you|about|previous)/i,
27
+ /your\s+new\s+(role|persona|identity|name)\s+(is|will\s+be)/i,
28
+ /you\s+must\s+(now\s+)?(obey|follow|comply)/i,
29
+ /override\s+(your|all|previous)\s+(instructions|rules|guidelines)/i,
30
+ /bypass\s+(your|all|the)\s+(rules|restrictions|filters|safety)/i,
31
+
32
+ # Jailbreak patterns
33
+ /do\s+anything\s+now/i,
34
+ /\bDAN\b.*\bmode\b/i,
35
+ /jailbreak/i,
36
+ /developer\s+mode\s+(enabled|on|activated)/i,
37
+ /\bunlocked\s+mode\b/i,
38
+
39
+ # Instruction injection via delimiters
40
+ /---\s*(new|system|override)\s*(instructions?|prompt)/i,
41
+ /###\s*(instruction|system|override)/i,
42
+ /<<\s*(SYS|SYSTEM|INST)/i,
43
+ /\[INST\]/i,
44
+
45
+ # Encoding attacks
46
+ /base64[:\s]+[A-Za-z0-9+\/=]{20,}/i,
47
+ /hex[:\s]+(?:[0-9a-f]{2}\s*){10,}/i,
48
+ /rot13[:\s]/i,
49
+
50
+ # Prompt leaking
51
+ /reveal\s+(your|the)\s+(system\s+)?prompt/i,
52
+ /show\s+me\s+(your|the)\s+(system\s+)?(prompt|instructions)/i,
53
+ /what\s+(are|is)\s+your\s+(system\s+)?(prompt|instructions)/i,
54
+ /repeat\s+(your|the)\s+(system\s+)?(prompt|instructions)/i,
22
55
  ].freeze
23
56
 
24
57
  def call(text, context: {})
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GuardrailsRuby
4
+ module Checks
5
+ class ScriptDetection < Check
6
+ check_name :script_detection
7
+ direction :input
8
+
9
+ SCRIPTS = {
10
+ latin: /[\p{Latin}]/,
11
+ cyrillic: /[\p{Cyrillic}]/,
12
+ arabic: /[\p{Arabic}]/,
13
+ cjk: /[\p{Han}]/,
14
+ hangul: /[\p{Hangul}]/,
15
+ hiragana: /[\p{Hiragana}]/,
16
+ katakana: /[\p{Katakana}]/,
17
+ thai: /[\p{Thai}]/,
18
+ devanagari: /[\p{Devanagari}]/,
19
+ greek: /[\p{Greek}]/,
20
+ hebrew: /[\p{Hebrew}]/,
21
+ georgian: /[\p{Georgian}]/,
22
+ armenian: /[\p{Armenian}]/,
23
+ ethiopic: /[\p{Ethiopic}]/,
24
+ tamil: /[\p{Tamil}]/
25
+ }.freeze
26
+
27
+ def call(text, context: {})
28
+ allowed = @options.fetch(:allowed_scripts, [:latin])
29
+ allowed = allowed.map(&:to_sym)
30
+
31
+ detected = detect_scripts(text)
32
+ unexpected = detected - allowed
33
+
34
+ if unexpected.any?
35
+ fail! "Unexpected scripts detected: #{unexpected.join(', ')}",
36
+ matches: unexpected.map(&:to_s)
37
+ else
38
+ pass!
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ def detect_scripts(text)
45
+ found = []
46
+ SCRIPTS.each do |name, pattern|
47
+ found << name if text.match?(pattern)
48
+ end
49
+ found
50
+ end
51
+ end
52
+ end
53
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GuardrailsRuby
4
- VERSION = "0.1.1"
4
+ VERSION = "0.2.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: guardrails-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Johannes Dwi Cahyo
@@ -57,6 +57,7 @@ extra_rdoc_files: []
57
57
  files:
58
58
  - Gemfile
59
59
  - LICENSE
60
+ - MILESTONES.md
60
61
  - README.md
61
62
  - Rakefile
62
63
  - examples/basic.rb
@@ -65,7 +66,9 @@ files:
65
66
  - guardrails-ruby.gemspec
66
67
  - lib/guardrails_ruby.rb
67
68
  - lib/guardrails_ruby/check.rb
69
+ - lib/guardrails_ruby/checks/code_execution.rb
68
70
  - lib/guardrails_ruby/checks/competitor_mention.rb
71
+ - lib/guardrails_ruby/checks/disclaimer.rb
69
72
  - lib/guardrails_ruby/checks/encoding.rb
70
73
  - lib/guardrails_ruby/checks/format.rb
71
74
  - lib/guardrails_ruby/checks/hallucinated_emails.rb
@@ -75,6 +78,7 @@ files:
75
78
  - lib/guardrails_ruby/checks/pii.rb
76
79
  - lib/guardrails_ruby/checks/prompt_injection.rb
77
80
  - lib/guardrails_ruby/checks/relevance.rb
81
+ - lib/guardrails_ruby/checks/script_detection.rb
78
82
  - lib/guardrails_ruby/checks/topic.rb
79
83
  - lib/guardrails_ruby/checks/toxic_language.rb
80
84
  - lib/guardrails_ruby/configuration.rb