Deterministic masking with files
File masking tasks (mask_file) support deterministic generation of masked values which are based on input values. You
can provide a hash_sources list in a rule, similar to the hash_columns for database masking.
However, with hash_sources you must specify additional parameters to fetch the hash.
- Parameters
- Example with
json_path - Example with
xpath - Example with
file_path - Example with relative
json_path - Example with relative
xpath
Parameters
json_path(optional): A path to the value in the JSON data to use for the hash.xpath(optional): An Xpath to the value stored in the XML data to use for the hash.file_path(optional): A boolean value, when set totruethe hash will be performed on the file's path (relative to the base directory). Defaults tofalse.case_transform(optional):upper/lower- Apply a case transform on the input value, for consistent hash values irrespective of case.trim(optional): If the value extracted from thejson_path, orxpathcontains leading or trailing white space, it can be trimmed by setting this option totrue. Defaults tofalse.regex(optional): A regular expression pattern to extract and concatenate values from the hash source before hashing. See Aboutregexfor details.match_index(optional): A zero-based index specifying whichregexmatch to use for hashing. If omitted, all matches are concatenated. Requiresregex. See Aboutregex.
Notes Each of the
json_path,xpathandfile_pathare shown as optional but exactly one of these needs to be specified. For more information onjson_pathorxpathplease refer to the JSON documentation/XML documentation.hash_sourcesfor multirecord files works the same as for object file, except thehash_sourcesare applied to each record in the file instead of the entire file.When
hash_sourcesare specified as part of ajsontransformorxmlnode_transform:
- The
json_path/xpathshould be a relative path from the current node.- If
hash_sourcesare specified as part of the task and within thejson/xmlmask:- The
hash_sourceswill be overwritten with thehash_sourcesspecified in thejson/xmlmask.file_pathis no longer a valid parameter.
Example with json_path
This example will mask a JSON file which contains the following JSON data:
{
"users": {
"name": "Richard",
"addresses": [
{
"type": "postal",
"city": "Nelson"
},
{
"type": "physical",
"city": "Napier"
}
]
}
}
We want to mask the city of the users, hashed with the name of the users. To do this we need
to specify a json_path to the value we want to use for the hash ([users,name]) in the hash_sources, as shown in
the ruleset below. The masked value we would want to replace the city with, would be best if it was from one of the seed
files DataMasque provides.
version: "1.0"
tasks:
- type: mask_file
rules:
- hash_sources:
- json_path: ['users', 'name']
masks:
- type: json
transforms:
- path: ['users','addresses', '*','city']
masks:
- type: from_file
seed_file: DataMasque_mixed_countries_addresses.csv
seed_column: city
As shown in the results below, when the name has the same values for both users the resulting masked values for the city
is also the same.
Note Each row of the results table below represents a separate file.
Show result
| Before | After |
|
|
|---|
If case_transform is specified, then the casing of the hash input values will not affect the consistency of the final
masked result.
version: "1.0"
tasks:
- type: mask_file
rules:
- hash_sources:
- json_path: ['users', 'name']
case_transform: lower
masks:
- type: json
transforms:
- path: ['users','addresses', "*",'city']
masks:
- type: from_file
seed_file: DataMasque_mixed_countries_addresses.csv
seed_column: city
Note Each row of the results table below represents a separate file.
Show result
| Before | After |
|
|
|---|
If trim is specified as true, then any whitespace around the hash input values will not affect the consistency of the final masked
result. In the example below, trim has been applied to the hash_source, and values in the hash_source containing
whitespace have not affected the final masked result.
version: "1.0"
tasks:
- type: mask_file
rules:
- hash_sources:
- json_path: ['users', 'name']
trim: true
masks:
- type: json
transforms:
- path: ['users','addresses', "*",'city']
masks:
- type: from_file
seed_file: DataMasque_mixed_countries_addresses.csv
seed_column: city
Show result
| Before | After |
|
|
|---|
Example with xpath
This example will mask two different XML files but generate consistent masked data by using user id as a hash. The first contains a user's info.
<User id="8472">
<Name>Evelyn</Name>
<Address>
<City>Nelson</City>
</Address>
</User>
The second contains a list of user's log messages:
<Logs userId="8472">
<Message to="Evelyn" date="2022-08-09" type="welcome"/>
<Message to="Evelyn" date="2022-08-10" type="forgot_password"/>
</Logs>
In both cases, we want the user's name to be consistent, and this can be done by specifying the user's ID as the hash
source for each file. We'll create a ruleset with two mask_file tasks, and use includes to map the right task to the
correct file.
The first ruleset will mask the User/Name text value, and the second will mask the to attribute of each
Log/Message element. The first ruleset will use the id attribute on User as the hash source, while the second will
use the userId attribute on Logs.
Here's the ruleset to accomplish this:
version: "1.0"
tasks:
- type: mask_file
include:
- glob: user_info_*.xml
rules:
- hash_sources:
- xpath: 'User/@id'
masks:
- type: xml
fallback_masks:
- type: from_fixed
value: '<User />'
transforms:
- path: 'User/Name'
node_transforms:
- type: text
masks:
- type: from_file
seed_file: DataMasque_firstNames_mixed.csv
- type: mask_file
include:
- glob: user_logs_*.xml
rules:
- hash_sources:
- xpath: 'Logs/@userId'
masks:
- type: xml
fallback_masks:
- type: from_fixed
value: '<Logs />'
transforms:
- path: 'User/Name'
node_transforms:
- type: attribute
attributes: 'to'
masks:
- type: from_file
seed_file: DataMasque_firstNames_mixed.csv
The two output files would use consistent names. The first file:
<User id="8472">
<Name>Sarah</Name>
<Address>
<City>Nelson</City>
</Address>
</User>
And the second:
<Logs userId="8472">
<Message to="Sarah" date="2022-08-09" type="welcome"/>
<Message to="Sarah" date="2022-08-10" type="forgot_password"/>
</Logs>
Example with file_path
This example will just show an example ruleset to mask files based on the file path:
This applies to any mask_file task.
version: "1.0"
tasks:
- type: mask_file
rules:
- hash_sources:
- file_path: true
masks:
- type: json
transforms:
- path: ['users','addresses', '*','city']
masks:
- type: from_file
seed_file: DataMasque_mixed_countries_addresses.csv
seed_column: city
With this ruleset the hashing will be performed on the file path, so each file with a different path with have differing masked values. This is useful if you want repeatable masking based on the name of a file.
Example with relative json_path
Referring to the document from the JSON path example above, DataMasque can generate a hash from a value that is relative to the current node being masked.
In the following example, the node being masked will be one of the ['users', 'addresses', '*','city'] text nodes.
The string .. is used to navigate up through the document hierarchy (analogous to using cd .. to move up a
directory when browsing a files in a terminal).
First we show the ruleset, then explain the hash source's json_path.
version: "1.0"
tasks:
- type: mask_file
rules:
masks:
- type: json
transforms:
- path: ['users','addresses', '*','city']
hash_sources:
- json_path: ['..', '..', '..', 'name']
masks:
- type: from_file
seed_file: DataMasque_mixed_countries_addresses.csv
seed_column: city
Each transform in transforms is applied to each city found at path. There is only one transform in this example.
To fetch the name of the user for that particular city, to use in hashing, we must ascend up three nodes by using
the .. operator three times:
- First ascending from the
citytext node to theaddressobject. - Then to the
addressesarray containing the list of addresses. - Finally, to the
userobject that contains theaddressesarray.
The current node is now the user object. The final element in the json_path (name) can be used to fetch the name
of that user.
In this way the city used in the from_file mask is generated based on the hash of the name of that user.
Example with relative xpath
Since the xml mask uses standard XPaths for node traversal, normal relative XPath syntax may be applied,
as shown in this next example.
version: "1.0"
tasks:
- type: mask_file
include:
- glob: user_info_*.xml
rules:
masks:
- type: xml
fallback_masks:
- type: from_fixed
value: '<User />'
transforms:
- path: '/User/Name'
node_transforms:
- type: text
hash_sources:
- xpath: '../@id'
masks:
- type: from_file
seed_file: DataMasque_firstNames_mixed.csv
- type: mask_file
include:
- glob: user_logs_*.xml
rules:
masks:
- type: xml
fallback_masks:
- type: from_fixed
value: '<Logs />'
transforms:
- path: '/User/Name'
node_transforms:
- type: attribute
attributes: 'to'
hash_sources:
- xpath: '../@userId'
masks:
- type: from_file
seed_file: DataMasque_firstNames_mixed.csv
The above example uses two hash_sources with xpath attributes. The first uses ../@id to fetch the id attribute
of the parent XML node (<User>), and the second similarly uses ../@userId to fetch the userId attribute.