Class: Vangrail::Rails::Secrets
- Inherits:
-
Vangrail::Rail
- Object
- Vangrail::Rail
- Vangrail::Rails::Secrets
- Defined in:
- lib/vangrail/rails/secrets.rb
Overview
Redacts credentials, returning :modified rather than blocking.
This is the rail that justifies having three statuses. An answer that quotes a config file with a live token is a useful answer with one bad span in it: blocking it throws away the help, and passing it leaks the token. Replacing the span keeps both halves honest, and the caller can see from the status that what it is about to show has been edited.
Patterns cover shapes that are unambiguous on sight. Anything needing judgement belongs in a policy rail, not here: a false positive silently corrupts an answer, which is worse than a missed match a later rail can still catch.
Constant Summary collapse
- PLACEHOLDER =
'[redacted]'- DEFAULT_PATTERNS =
{ 'private_key' => /-----BEGIN[A-Z ]*PRIVATE KEY-----.*?-----END[A-Z ]*PRIVATE KEY-----/m, 'openai_key' => /\bsk-[A-Za-z0-9_-]{20,}\b/, 'anthropic_key' => /\bsk-ant-[A-Za-z0-9_-]{20,}\b/, 'github_token' => /\bgh[pousr]_[A-Za-z0-9]{30,}\b/, 'slack_token' => /\bxox[abposr]-[A-Za-z0-9-]{10,}\b/, 'aws_access_key' => /\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/, 'jwt' => /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b/, 'bearer_header' => /\b(?i:authorization)\s*:\s*(?i:bearer)\s+\S{12,}/, 'inline_password' => /\b(?i:password|passwd|api[_-]?key|secret)\s*[=:]\s*(?!\[redacted\])\S{6,}/ }.freeze
Constants inherited from Vangrail::Rail
Vangrail::Rail::DEFAULT_SIDES, Vangrail::Rail::SIDES
Instance Attribute Summary collapse
-
#patterns ⇒ Object
readonly
Returns the value of attribute patterns.
-
#placeholder ⇒ Object
readonly
Returns the value of attribute placeholder.
Attributes inherited from Vangrail::Rail
Instance Method Summary collapse
- #cache_key(text, _context) ⇒ Object
- #call(text, _context) ⇒ Object
-
#initialize(patterns: DEFAULT_PATTERNS, placeholder: PLACEHOLDER, name: 'secrets', sides: [:output]) ⇒ Secrets
constructor
A new instance of Secrets.
- #offline? ⇒ Boolean
Methods inherited from Vangrail::Rail
#applies_to?, #placeholder?, #to_s
Constructor Details
#initialize(patterns: DEFAULT_PATTERNS, placeholder: PLACEHOLDER, name: 'secrets', sides: [:output]) ⇒ Secrets
Returns a new instance of Secrets.
36 37 38 39 40 41 |
# File 'lib/vangrail/rails/secrets.rb', line 36 def initialize(patterns: DEFAULT_PATTERNS, placeholder: PLACEHOLDER, name: 'secrets', sides: [:output]) super(name: name, sides: sides) @patterns = patterns @placeholder = placeholder end |
Instance Attribute Details
#patterns ⇒ Object (readonly)
Returns the value of attribute patterns.
34 35 36 |
# File 'lib/vangrail/rails/secrets.rb', line 34 def patterns @patterns end |
#placeholder ⇒ Object (readonly)
Returns the value of attribute placeholder.
34 35 36 |
# File 'lib/vangrail/rails/secrets.rb', line 34 def placeholder @placeholder end |
Instance Method Details
#cache_key(text, _context) ⇒ Object
47 48 49 |
# File 'lib/vangrail/rails/secrets.rb', line 47 def cache_key(text, _context) text end |
#call(text, _context) ⇒ Object
51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/vangrail/rails/secrets.rb', line 51 def call(text, _context) body = text.to_s found = [] redacted = patterns.reduce(body) do |acc, (label, pattern)| acc.gsub(pattern) do |match| found << label replacement(label, match) end end return pass if found.empty? modify(redacted, categories: found.uniq, reason: "redacted #{found.uniq.join(', ')}") end |
#offline? ⇒ Boolean
43 44 45 |
# File 'lib/vangrail/rails/secrets.rb', line 43 def offline? true end |