Class: Browserctl::Redactor
- Inherits:
-
Object
- Object
- Browserctl::Redactor
- Defined in:
- lib/browserctl/redactor.rb
Overview
Redacts known secret values from arbitrary strings.
Used by ‘browserctl trace` to ensure traces are safe to attach to issues by default. Secret values are sourced from two places:
1. ENV variables whose names match well-known secret patterns
(`*_TOKEN`, `*_KEY`, `*_SECRET`, `*_PASSWORD`).
2. Values captured at runtime by `SecretResolverRegistry` (in-memory
only — never persisted).
Replacement marker is the literal ‘[REDACTED]`. We considered including a sha256 prefix to distinguish values, but that doubles the surface area for accidental leakage (a determined attacker could brute-force short secrets from the prefix), and the timeline is more scannable with a uniform marker.
Constant Summary collapse
- MARKER =
"[REDACTED]"- MIN_LENGTH =
4- ENV_PATTERNS =
[/_TOKEN\z/, /_KEY\z/, /_SECRET\z/, /_PASSWORD\z/].freeze
Class Method Summary collapse
-
.from_env(env: ENV, extra: []) ⇒ Object
Build a Redactor from the current ENV using well-known patterns.
Instance Method Summary collapse
- #empty? ⇒ Boolean
-
#initialize(secrets: []) ⇒ Redactor
constructor
A new instance of Redactor.
- #redact(string) ⇒ String?
Constructor Details
#initialize(secrets: []) ⇒ Redactor
Returns a new instance of Redactor.
24 25 26 27 28 29 30 31 32 33 |
# File 'lib/browserctl/redactor.rb', line 24 def initialize(secrets: []) # Filter empty / too-short values; longest-first to avoid partial # overlaps (e.g. redacting "abcd" before "abcdef" would leave "ef"). @secrets = secrets .compact .map(&:to_s) .reject { |s| s.length < MIN_LENGTH } .uniq .sort_by { |s| -s.length } end |
Class Method Details
.from_env(env: ENV, extra: []) ⇒ Object
Build a Redactor from the current ENV using well-known patterns. Optionally merges in additional values (e.g. from runtime instrumentation).
51 52 53 54 55 56 |
# File 'lib/browserctl/redactor.rb', line 51 def self.from_env(env: ENV, extra: []) values = env.each_with_object([]) do |(name, value), acc| acc << value if ENV_PATTERNS.any? { |re| name =~ re } end new(secrets: values + Array(extra)) end |
Instance Method Details
#empty? ⇒ Boolean
45 46 47 |
# File 'lib/browserctl/redactor.rb', line 45 def empty? @secrets.empty? end |
#redact(string) ⇒ String?
37 38 39 40 41 42 43 |
# File 'lib/browserctl/redactor.rb', line 37 def redact(string) return string if string.nil? result = string.to_s @secrets.each { |secret| result = result.gsub(secret, MARKER) } result end |