Class: Vangrail::Rails::PersonalData
- Inherits:
-
Vangrail::Rail
- Object
- Vangrail::Rail
- Vangrail::Rails::PersonalData
- Defined in:
- lib/vangrail/rails/personal_data.rb
Overview
Redacts a reader's own details before the question leaves the building.
This is a privacy rail rather than a security one, and it exists because of where the text goes next. A question typed into a documentation desk is about to be sent to a model endpoint, which may be a third party, may log, and may sit in another jurisdiction. A reader pasting a support thread into it has not thought about any of that, and nothing in the answer needs their phone number.
Redacts rather than blocks, for the same reason the secrets rail does: the question is answerable, and one span in it should not have been sent.
The hard part on a cluster desk is not detection. It is that
ssh rgoswami@snellius.example.org is an email address by every
syntactic measure, and redacting it destroys the answer to the most
commonly asked question there is. So an address is left alone when it is
inside backticks or a fence, when its line carries a command that takes a
user@host argument or an ssh config keyword, or when a remote path
follows it. All three are in the corpus, because a rail that eats login
examples is worse for a handbook than no rail at all.
Deliberately not included: national identity numbers. The Dutch BSN is nine digits with a checksum, a Slurm job id is six to eight digits, and one in eleven job ids passes the checksum by accident. A rail that redacts job ids from a cluster support question is unusable, and the trade is not close.
Constant Summary collapse
- PLACEHOLDER =
'[redacted]'- HOST_COMMANDS =
Commands whose argument is a login target rather than a mailbox. Read over the line rather than the character before the match: scp puts a source path in between, and an ssh config line has no command on it at all, only the User keyword.
/\b(?:ssh|scp|sftp|rsync|mosh|ssh-copy-id|ssh:\/\/|sftp:\/\/|User)\b/i- REMOTE_PATH =
The other half of scp and rsync syntax: an address followed by a remote path is a target, not a mailbox.
/\A:[~\/\w.]/- PLACEHOLDER_USERS =
Local parts that are documentation rather than a person.
/\A(?:user|username|your[._-]?name|login|account|me|example| firstname|lastname|name|admin|root)\z/xi- PATTERNS =
{ 'email' => /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/, # International or national, with a separator, long enough to be a # phone number and not a job id: a leading + or 00, or a leading zero # with grouping. 'phone' => /(?:\+|\b00)[1-9]\d{0,2}[\s.-]?(?:\(?\d{1,4}\)?[\s.-]?){2,5}\d{2,4}\b |\b0\d{1,3}[\s.-]\d{3}[\s.-]?\d{3,4}\b/x, 'iban' => /\b[A-Z]{2}\d{2}\s?(?:[A-Z0-9]{4}\s?){2,7}[A-Z0-9]{1,4}\b/, 'card' => /\b(?:\d[ -]?){13,19}\b/ }.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: PATTERNS, placeholder: PLACEHOLDER, name: 'personal_data', sides: [:input]) ⇒ PersonalData
constructor
A new instance of PersonalData.
- #offline? ⇒ Boolean
Methods inherited from Vangrail::Rail
#applies_to?, #placeholder?, #to_s
Constructor Details
#initialize(patterns: PATTERNS, placeholder: PLACEHOLDER, name: 'personal_data', sides: [:input]) ⇒ PersonalData
Returns a new instance of PersonalData.
63 64 65 66 67 68 |
# File 'lib/vangrail/rails/personal_data.rb', line 63 def initialize(patterns: PATTERNS, placeholder: PLACEHOLDER, name: 'personal_data', sides: [:input]) super(name: name, sides: sides) @patterns = patterns @placeholder = placeholder end |
Instance Attribute Details
#patterns ⇒ Object (readonly)
Returns the value of attribute patterns.
61 62 63 |
# File 'lib/vangrail/rails/personal_data.rb', line 61 def patterns @patterns end |
#placeholder ⇒ Object (readonly)
Returns the value of attribute placeholder.
61 62 63 |
# File 'lib/vangrail/rails/personal_data.rb', line 61 def placeholder @placeholder end |
Instance Method Details
#cache_key(text, _context) ⇒ Object
74 75 76 |
# File 'lib/vangrail/rails/personal_data.rb', line 74 def cache_key(text, _context) text end |
#call(text, _context) ⇒ Object
78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/vangrail/rails/personal_data.rb', line 78 def call(text, _context) body = text.to_s found = [] redacted = patterns.reduce(body) do |acc, (label, pattern)| replace(acc, label, pattern, found) end return pass if found.empty? modify(redacted, categories: found.uniq, reason: "redacted #{found.uniq.join(', ')} before sending") end |
#offline? ⇒ Boolean
70 71 72 |
# File 'lib/vangrail/rails/personal_data.rb', line 70 def offline? true end |