Module: Scrubber
- Defined in:
- lib/scrubber_rb.rb,
lib/scrubber/match.rb,
lib/scrubber/version.rb,
lib/scrubber/instance.rb,
lib/scrubber/llm_guard.rb,
lib/scrubber/middleware.rb,
lib/scrubber/log_formatter.rb,
sig/scrubber_rb.rbs
Overview
Fast PII and secret redaction, with the scanning done in Rust.
Scrubber.scrub("contact nik@example.com") # => "contact [EMAIL]"
The module-level methods are the convenient path and memoize one compiled engine per distinct configuration. For hot loops, build a Instance yourself with Scrubber.new and keep it around.
Defined Under Namespace
Classes: ConfigurationError, Error, Instance, InternalError, LLMGuard, LogFormatter, Match, Middleware, Native, UnknownDetectorError, UnsupportedPatternError
Constant Summary collapse
- DEFAULTS =
Detector keys, sourced from the Rust registry at load time.
Native.default_detectors.map(&:to_sym).freeze
- INDIA =
Native.india_detectors.map(&:to_sym).freeze
- ALL =
Every detector this build knows about.
Native.all_detectors.map(&:to_sym).freeze
- VERSION =
"0.1.1"
Class Method Summary collapse
-
.detect(text, **options) ⇒ Array[Match]
Locate matches without replacing them.
-
.engine(detectors: DEFAULTS, custom: {}, replacement: :label, hash_salt: nil) ⇒ Instance
The memoized Instance for a set of options.
-
.match?(text, **options) ⇒ Boolean
True if anything would be redacted.
-
.new(detectors: DEFAULTS, custom: {}, replacement: :label, hash_salt: nil) ⇒ Object
Build a reusable, frozen scrubber.
-
.reset! ⇒ nil
Drop memoized engines.
-
.scrub(text, **options) ⇒ String
Redact
textusing a memoized engine for these options. -
.scrub!(text, **options) ⇒ String
Redact
textin place. -
.scrub_file(input_path, output_path, **options) ⇒ Integer
Stream a file through the engine.
Class Method Details
.detect(text, **options) ⇒ Array[Match]
Locate matches without replacing them. Returns Match structs.
60 61 62 |
# File 'lib/scrubber_rb.rb', line 60 def detect(text, **) engine(**).detect(text) end |
.engine(detectors: DEFAULTS, custom: {}, replacement: :label, hash_salt: nil) ⇒ Instance
The memoized Instance for a set of options. Exposed because asking for it explicitly beats accidentally rebuilding one per request.
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/scrubber_rb.rb', line 77 def engine(detectors: DEFAULTS, custom: {}, replacement: :label, hash_salt: nil) key = Instance.cache_key( detectors: detectors, custom: custom, replacement: replacement, hash_salt: hash_salt ) # Double-checked: reads are lock-free on the happy path, and building the # same engine twice under a race is harmless (they are identical and # immutable), so the mutex only prevents wasted work. cache[key] || cache_mutex.synchronize do cache[key] ||= new( detectors: detectors, custom: custom, replacement: replacement, hash_salt: hash_salt ) end end |
.match?(text, **options) ⇒ Boolean
True if anything would be redacted.
65 66 67 |
# File 'lib/scrubber_rb.rb', line 65 def match?(text, **) engine(**).match?(text) end |
.new(detectors: DEFAULTS, custom: {}, replacement: :label, hash_salt: nil) ⇒ Object
Build a reusable, frozen scrubber. See Instance.
42 43 44 45 46 47 |
# File 'lib/scrubber_rb.rb', line 42 def new(detectors: DEFAULTS, custom: {}, replacement: :label, hash_salt: nil) Instance.new( detectors: detectors, custom: custom, replacement: replacement, hash_salt: hash_salt ) end |
.reset! ⇒ nil
Drop memoized engines. Only useful in tests.
94 95 96 97 |
# File 'lib/scrubber_rb.rb', line 94 def reset! cache_mutex.synchronize { cache.clear } nil end |
.scrub(text, **options) ⇒ String
Redact text using a memoized engine for these options.
50 51 52 |
# File 'lib/scrubber_rb.rb', line 50 def scrub(text, **) engine(**).scrub(text) end |
.scrub!(text, **options) ⇒ String
Redact text in place.
55 56 57 |
# File 'lib/scrubber_rb.rb', line 55 def scrub!(text, **) engine(**).scrub!(text) end |
.scrub_file(input_path, output_path, **options) ⇒ Integer
Stream a file through the engine. Returns bytes written.
70 71 72 73 |
# File 'lib/scrubber_rb.rb', line 70 def scrub_file(input_path, output_path, **) chunk_size = .delete(:chunk_size) || Instance::CHUNK_SIZE engine(**).scrub_file(input_path, output_path, chunk_size: chunk_size) end |