Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bugfix: overzealous data masking rule for US social security numbers #751

Merged
merged 5 commits into from
Aug 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@

The most robust observability solution for Salesforce experts. Built 100% natively on the platform, and designed to work seamlessly with Apex, Lightning Components, Flow, Process Builder & integrations.

## Unlocked Package - v4.14.6
## Unlocked Package - v4.14.7

[![Install Unlocked Package in a Sandbox](./images/btn-install-unlocked-package-sandbox.png)](https://test.salesforce.com/packaging/installPackage.apexp?p0=04t5Y0000015oRhQAI)
[![Install Unlocked Package in Production](./images/btn-install-unlocked-package-production.png)](https://login.salesforce.com/packaging/installPackage.apexp?p0=04t5Y0000015oRhQAI)
[![Install Unlocked Package in a Sandbox](./images/btn-install-unlocked-package-sandbox.png)](https://test.salesforce.com/packaging/installPackage.apexp?p0=04t5Y0000015oRrQAI)
[![Install Unlocked Package in Production](./images/btn-install-unlocked-package-production.png)](https://login.salesforce.com/packaging/installPackage.apexp?p0=04t5Y0000015oRrQAI)
[![View Documentation](./images/btn-view-documentation.png)](https://jongpie.github.io/NebulaLogger/)

`sf package install --wait 20 --security-type AdminsOnly --package 04t5Y0000015oRhQAI`
`sf package install --wait 20 --security-type AdminsOnly --package 04t5Y0000015oRrQAI`

`sfdx force:package:install --wait 20 --securitytype AdminsOnly --package 04t5Y0000015oRhQAI`
`sfdx force:package:install --wait 20 --securitytype AdminsOnly --package 04t5Y0000015oRrQAI`

---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@
</values>
<values>
<field>ReplacementRegEx__c</field>
<value xsi:type="xsd:string">$1XXX-XX-$4</value>
<value xsi:type="xsd:string">$1XXX-XX-$4$5</value>
</values>
<values>
<field>SensitiveDataRegEx__c</field>
<value xsi:type="xsd:string">(^|[ ])(\d{3})[- ]*(\d{2})[- ]*(\d{4})</value>
<value xsi:type="xsd:string">(^|[ ])(\d{3})[- ]*(\d{2})[- ]*(\d{4})([ ]|$)</value>
</values>
</CustomMetadata>
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,16 @@ public inherited sharing class ComponentLogger {
set;
}

private static final Map<String, Schema.SObjectField> LOG_ENTRY_EVENT_FIELD_NAME_TO_FIELD {
get {
if (LOG_ENTRY_EVENT_FIELD_NAME_TO_FIELD == null) {
LOG_ENTRY_EVENT_FIELD_NAME_TO_FIELD = Schema.LogEntryEvent__e.SObjectType.getDescribe().fields.getMap();
}
return LOG_ENTRY_EVENT_FIELD_NAME_TO_FIELD;
}
set;
}

static {
LoggerStackTrace.ignoreOrigin(ComponentLogger.class);
LoggerStackTrace.ignoreOrigin(LoggerStackTrace.SourceLanguage.JavaScript, LOGGER_COMPONENT_NAME);
Expand Down Expand Up @@ -94,9 +104,8 @@ public inherited sharing class ComponentLogger {
return resolvedFieldToFieldValue;
}

Map<String, Schema.SObjectField> fieldNameToField = Schema.LogEntryEvent__e.SObjectType.getDescribe().fields.getMap();
for (String fieldName : fieldNameToValue.keySet()) {
Schema.SObjectField field = fieldNameToField.get(fieldName);
Schema.SObjectField field = LOG_ENTRY_EVENT_FIELD_NAME_TO_FIELD.get(fieldName);
if (field != null) {
resolvedFieldToFieldValue.put(field, fieldNameToValue.get(fieldName));
}
Expand Down
2 changes: 1 addition & 1 deletion nebula-logger/core/main/logger-engine/classes/Logger.cls
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
global with sharing class Logger {
// There's no reliable way to get the version number dynamically in Apex
@TestVisible
private static final String CURRENT_VERSION_NUMBER = 'v4.14.6';
private static final String CURRENT_VERSION_NUMBER = 'v4.14.7';
private static final System.LoggingLevel FALLBACK_LOGGING_LEVEL = System.LoggingLevel.DEBUG;
private static final List<LogEntryEventBuilder> LOG_ENTRIES_BUFFER = new List<LogEntryEventBuilder>();
private static final String MISSING_SCENARIO_ERROR_MESSAGE = 'No logger scenario specified. A scenario is required for logging in this org.';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import FORM_FACTOR from '@salesforce/client/formFactor';
import { log as lightningLog } from 'lightning/logger';
import { LoggerStackTrace } from './loggerStackTrace';

const CURRENT_VERSION_NUMBER = 'v4.14.6';
const CURRENT_VERSION_NUMBER = 'v4.14.7';

const LOGGING_LEVEL_EMOJIS = {
ERROR: '⛔',
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "nebula-logger",
"version": "4.14.6",
"version": "4.14.7",
"description": "The most robust logger for Salesforce. Works with Apex, Lightning Components, Flow, Process Builder & Integrations. Designed for Salesforce admins, developers & architects.",
"author": "Jonathan Gillespie",
"license": "MIT",
Expand Down
120 changes: 103 additions & 17 deletions scripts/build/validate-custom-metadata-records.apex
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,123 @@
// LogEntryDataMaskRule__mdt checks
// The field LogEntryDataMaskRule__mdt.IsEnabled__c should be set to true for any records included in the packages.
for (LogEntryDataMaskRule__mdt record : [SELECT DeveloperName, IsEnabled__c FROM LogEntryDataMaskRule__mdt ORDER BY DeveloperName]) {
if (record.IsEnabled__c == false) {
throw new System.IllegalArgumentException('😡 IsEnabled__c field should be set to true for LogEntryDataMaskRule.' + record.DeveloperName);
}
if (record.IsEnabled__c == false) {
throw new System.IllegalArgumentException('😡 IsEnabled__c field should be set to true for LogEntryDataMaskRule.' + record.DeveloperName);
}
}
System.debug('🥳 LogEntryDataMaskRule__mdt records have been correctly configured!');
System.debug('🥳 LogEntryDataMaskRule__mdt records have been correctly enabled!');

// LogEntryDataMaskRule__mdt checks
// The fields SensitiveDataRegEx__c and ReplacementRegEx__c should contain valid regex patterns that mask the appropriate data.
// US social security number rule
LogEntryDataMaskRule__mdt socialSecurityNumberRule = LogEntryDataMaskRule__mdt.getInstance('SocialSecurityNumber');
System.Assert.areEqual(
'>>> Here is a number XXX-XX-6789 which is the correct length for US SSN',
'>>> Here is a number 123-45-6789 which is the correct length for US SSN'
.replaceAll(socialSecurityNumberRule.SensitiveDataRegEx__c, socialSecurityNumberRule.ReplacementRegEx__c)
);
System.Assert.areEqual(
'>>> Here is a number XXX-XX-6789 which is the correct length for US SSN',
'>>> Here is a number 123 45 6789 which is the correct length for US SSN'
.replaceAll(socialSecurityNumberRule.SensitiveDataRegEx__c, socialSecurityNumberRule.ReplacementRegEx__c)
);
List<String> invalidSSNLookalikes = new List<String>{
'0123-45-6789',
'0123-45-67890',
'23-45-678',
'23-45-6789',
'123-45-678',
// US phone number formats
'111-555-1234',
'111 555 1234',
'(111) 555-1234'
};
for (String lookalike : invalidSSNLookalikes) {
String originalInput = '>>> Here is a value ' + lookalike + ' and it is not a valid form for US SSN, so masking should not occur';
System.Assert.areEqual(
originalInput,
originalInput.replaceAll(socialSecurityNumberRule.SensitiveDataRegEx__c, socialSecurityNumberRule.ReplacementRegEx__c)
);
}
System.debug(
'🥳 LogEntryDataMaskRule__mdt record \'SocialSecurityNumber\' has been correctly configured with functioning regexes for sensitive data & replacement!'
);

// Mastercard credit card rule
LogEntryDataMaskRule__mdt mastercardCreditCardNumberRule = LogEntryDataMaskRule__mdt.getInstance('MastercardCreditCardNumber');
System.Assert.areEqual(
'>>> Here is a credit card number ****-****-****-0005 which is the correct length for Mastercard',
'>>> Here is a credit card number 5000-1111-2222-0005 which is the correct length for Mastercard'
.replaceAll(mastercardCreditCardNumberRule.SensitiveDataRegEx__c, mastercardCreditCardNumberRule.ReplacementRegEx__c)
);
List<String> invalidMastercardLookalikes = new List<String>{
'05000-1111-2222-0005',
'05000-1111-2222-00050',
'000-1111-2222-000',
'000-1111-2222-0005',
'5000-1111-2222-000'
};
for (String lookalike : invalidMastercardLookalikes) {
String originalInput = '>>> Here is a value ' + lookalike + ' and it is not a valid form for Mastercard, so masking should not occur';
System.Assert.areEqual(
originalInput,
originalInput.replaceAll(socialSecurityNumberRule.SensitiveDataRegEx__c, socialSecurityNumberRule.ReplacementRegEx__c)
);
}
System.debug(
'🥳 LogEntryDataMaskRule__mdt record \'MastercardCreditCardNumber\' has been correctly configured with functioning regexes for sensitive data & replacement!'
);

// Visa credit card rule
LogEntryDataMaskRule__mdt visaCreditCardNumberRule = LogEntryDataMaskRule__mdt.getInstance('VisaCreditCardNumber');
System.Assert.areEqual(
'>>> Here is a credit card number ****-****-****-0004 which is the correct length for Visa',
'>>> Here is a credit card number 4000-1111-2222-0004 which is the correct length for Visa'
.replaceAll(visaCreditCardNumberRule.SensitiveDataRegEx__c, visaCreditCardNumberRule.ReplacementRegEx__c)
);
List<String> invalidVisaLookalikes = new List<String>{
'04000-1111-2222-0004',
'04000-1111-2222-00040',
'000-1111-2222-000',
'000-1111-2222-0004',
'4000-1111-2222-000'
};
for (String lookalike : invalidVisaLookalikes) {
String originalInput = '>>> Here is a value ' + lookalike + ' and it is not a valid form for Visa, so masking should not occur';
System.Assert.areEqual(
originalInput,
originalInput.replaceAll(socialSecurityNumberRule.SensitiveDataRegEx__c, socialSecurityNumberRule.ReplacementRegEx__c)
);
}
System.debug(
'🥳 LogEntryDataMaskRule__mdt record \'VisaCreditCardNumber\' has been correctly configured with functioning regexes for sensitive data & replacement!'
);

// LoggerParameter__mdt checks
// The field LoggerParameter__mdt.Description__c is a long textarea field, so it can't be marked as required - but every record
// should have the field populated before being added to the unlocked & managed packages.
for (LoggerParameter__mdt record : [SELECT DeveloperName, Description__c FROM LoggerParameter__mdt ORDER BY DeveloperName]) {
if (record.Description__c == null) {
throw new System.IllegalArgumentException('😡 Description__c field should be populated for LoggerParameter.' + record.DeveloperName);
}
if (record.Description__c == null) {
throw new System.IllegalArgumentException('😡 Description__c field should be populated for LoggerParameter.' + record.DeveloperName);
}
}
System.debug('🥳 LoggerParameter__mdt records have been correctly configured!');
System.debug('🥳 LoggerParameter__mdt records have been correctly populated with a description!');

// LoggerSObjectHandler__mdt checks
// The field LoggerSObjectHandler__mdt.IsEnabled__c should be set to true for any records included in the packages.
for (LoggerSObjectHandler__mdt record : [SELECT DeveloperName, IsEnabled__c FROM LoggerSObjectHandler__mdt ORDER BY DeveloperName]) {
if (record.IsEnabled__c == false) {
throw new System.IllegalArgumentException('😡 IsEnabled__c field should be set to true for LoggerSObjectHandler.' + record.DeveloperName);
}
if (record.IsEnabled__c == false) {
throw new System.IllegalArgumentException('😡 IsEnabled__c field should be set to true for LoggerSObjectHandler.' + record.DeveloperName);
}
}
System.debug('🥳 LoggerSObjectHandler__mdt records have been correctly configured!');
System.debug('🥳 LoggerSObjectHandler__mdt records have been correctly enabled!');

// LogStatus__mdt checks
// The field LogStatus__mdt.IsActive__c should be set to true for any records included in the packages.
for (LogStatus__mdt record : [SELECT DeveloperName, IsActive__c FROM LogStatus__mdt ORDER BY DeveloperName]) {
// TODO rename LogStatus__mdt.IsActive__c to IsEnabled__c for consistency with other objects
if (record.IsActive__c == false) {
throw new System.IllegalArgumentException('😡 IsActive__c field should be set to true for LogStatus.' + record.DeveloperName);
}
// TODO rename LogStatus__mdt.IsActive__c to IsEnabled__c for consistency with other objects
if (record.IsActive__c == false) {
throw new System.IllegalArgumentException('😡 IsActive__c field should be set to true for LogStatus.' + record.DeveloperName);
}
}
System.debug('🥳 LogStatus__mdt records have been correctly configured!');
System.debug('🥳 LogStatus__mdt records records have been correctly enabled!');
7 changes: 4 additions & 3 deletions sfdx-project.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
"path": "./nebula-logger/core",
"definitionFile": "./config/scratch-orgs/build-base-scratch-def.json",
"scopeProfiles": true,
"versionNumber": "4.14.6.NEXT",
"versionName": "Custom Field Mappings Support for Lightning Components",
"versionDescription": "Added the ability to set custom fields in JavaScript via a new function setField() in logEntryBuilder.js. This is equivalent to the Apex method overloads setField() in LogEntryEventBuilder.cls that were introduced in v4.13.14.",
"versionNumber": "4.14.7.NEXT",
"versionName": "Bugfix: US Social Security Number Data Mask Rule",
"versionDescription": "Corrected the regular expressions used in data mask rule 'SocialSecurityNumber' to be stricter to avoid incorrectly masking credit card numbers as social security numbers",
"releaseNotesUrl": "https://github.com/jongpie/NebulaLogger/releases",
"unpackagedMetadata": {
"path": "./nebula-logger/extra-tests"
Expand Down Expand Up @@ -191,6 +191,7 @@
"Nebula Logger - Core@4.14.4-optionally-auto-call-lightning-logger-lwc": "04t5Y0000015oRNQAY",
"Nebula Logger - Core@4.14.5-added-logger-settings-to-utility-bar": "04t5Y0000015oRXQAY",
"Nebula Logger - Core@4.14.6-custom-field-mappings-support-for-lightning-components": "04t5Y0000015oRhQAI",
"Nebula Logger - Core@4.14.7-bugfix:-us-social-security-number-data-mask-rule": "04t5Y0000015oRrQAI",
"Nebula Logger - Core Plugin - Async Failure Additions": "0Ho5Y000000blO4SAI",
"Nebula Logger - Core Plugin - Async Failure Additions@1.0.0": "04t5Y0000015lhiQAA",
"Nebula Logger - Core Plugin - Async Failure Additions@1.0.1": "04t5Y0000015lhsQAA",
Expand Down