Skip to content
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
27 changes: 18 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,19 +135,28 @@ When integrated with Monolog and CloudWatch, logs are automatically sent to Clou

### Sensitive Field Masking

By default, the following sensitive fields have their values masked in logs:
The module provides configurable masking of sensitive field values in entity change logs. When sensitive fields are modified, they appear in logs with masked values (e.g., `***MASKED***`) instead of actual values, providing an audit trail while protecting sensitive data.

#### Default Sensitive Fields

By default, the following field has its value masked:
- `pass` - User passwords
- `uuid` - Entity UUIDs
- `revision_timestamp` - Revision timestamps
- `revision_uid` - Revision authors
- `revision_log` - Revision log messages
- `changed` - Changed timestamps

When these fields are modified, they appear in the logs with masked values (e.g., `***MASKED***`) instead of actual values, providing an audit trail while protecting sensitive data.
#### Configuring Sensitive Fields

You can customize which fields are masked through the administrative interface:

1. Navigate to **Configuration** > **Development** > **Logging and errors** (`/admin/config/development/logging`)
2. Click on the **UCEAP Logging** tab
3. Enter field machine names (one per line) in the "Sensitive Fields" textarea
4. Click "Save configuration"

Additionally, computed and internal fields are automatically excluded from logging as they are derived values.
#### Automatically Excluded Fields

To customize which fields are masked, modify the `$sensitive_fields` array in `_uceap_logging_get_entity_field_changes()`.
In addition to user-configured sensitive fields, the following field types are automatically excluded from change tracking entirely:
- Computed fields (derived values)
- Internal fields (system-managed)
- Specific metadata fields: `changed`, `revision_timestamp`, `revision_uid`, `revision_log`

### Logger Channels

Expand Down
2 changes: 2 additions & 0 deletions config/install/uceap_logging.settings.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
sensitive_fields:
- pass
10 changes: 10 additions & 0 deletions config/schema/uceap_logging.schema.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
uceap_logging.settings:
type: config_object
label: 'UCEAP Logging Settings'
mapping:
sensitive_fields:
type: sequence
label: 'Sensitive fields'
sequence:
type: string
label: 'Field name'
82 changes: 82 additions & 0 deletions src/Form/LoggingSettingsForm.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<?php

namespace Drupal\uceap_logging\Form;

use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;

/**
* Configure UCEAP Logging settings.
*/
class LoggingSettingsForm extends ConfigFormBase {

/**
* {@inheritdoc}
*/
public function getFormId() {
return 'uceap_logging_settings';
}

/**
* {@inheritdoc}
*/
protected function getEditableConfigNames() {
return ['uceap_logging.settings'];
}

/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$config = $this->config('uceap_logging.settings');

$form['sensitive_fields'] = [
'#type' => 'textarea',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I opened a PR with a suggestion to make the list selectable #3

'#title' => $this->t('Sensitive Fields'),
'#description' => $this->t('Enter field machine names (one per line) that should have their values masked in entity change logs. When these fields are modified, they will appear in logs with masked values (e.g., ***MASKED***) instead of actual values.'),
'#default_value' => implode("\n", $config->get('sensitive_fields') ?? []),
'#rows' => 10,
];

$form['help'] = [
'#type' => 'details',
'#title' => $this->t('Examples'),
'#open' => FALSE,
];

$form['help']['examples'] = [
'#markup' => $this->t('<p>Common sensitive fields include:</p>
<ul>
<li><code>field_ssn</code> - Social Security Numbers</li>
<li><code>pass</code> - User passwords</li>
<li><code>field_bank_account</code> - Banking information</li>
<li><code>field_credit_card</code> - Payment information</li>
<li><code>field_api_key</code> - API keys or tokens</li>
</ul>
<p><strong>Note:</strong> The following fields are automatically excluded from logging: <code>changed</code>, <code>revision_timestamp</code>, <code>revision_uid</code>, <code>revision_log</code>. Additionally, computed and internal fields are never logged.</p>'),
];

return parent::buildForm($form, $form_state);
}

/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
// Convert textarea input to array.
$sensitive_fields_raw = $form_state->getValue('sensitive_fields');
$sensitive_fields = array_filter(
array_map('trim', explode("\n", $sensitive_fields_raw)),
function ($field) {
return !empty($field);
}
);

$this->config('uceap_logging.settings')
->set('sensitive_fields', array_values($sensitive_fields))
->save();

parent::submitForm($form, $form_state);
}

}
13 changes: 13 additions & 0 deletions uceap_logging.links.task.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Create a default tab for the system logging page
system.logging_settings_default:
title: 'Settings'
route_name: system.logging_settings
base_route: system.logging_settings
weight: 0

# Add our custom tab
uceap_logging.settings:
title: 'UCEAP Logging'
route_name: uceap_logging.settings
base_route: system.logging_settings
weight: 10
8 changes: 2 additions & 6 deletions uceap_logging.module
Original file line number Diff line number Diff line change
Expand Up @@ -115,12 +115,8 @@ function _uceap_logging_get_entity_field_changes(ContentEntityInterface $entity,
];

// Sensitive fields that should have values masked in logs.
// TODO make this configurable.
$sensitive_fields = [
'field_ssn',
'field_confirm_ssn',
'pass',
];
$config = \Drupal::config('uceap_logging.settings');
$sensitive_fields = $config->get('sensitive_fields') ?? [];
Comment on lines +118 to +119
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a benefit to using config over state?

I guess with config you can review the file directly versus have to look in the binary blob of the database.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the fields themselves exist in config it feels like the field list does too. Lets us cleanly deploy updates to both (new sensitive field added? new senstitive_fields config value).


$changes = [];
$field_definitions = $entity->getFieldDefinitions();
Expand Down
7 changes: 7 additions & 0 deletions uceap_logging.routing.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
uceap_logging.settings:
path: '/admin/config/development/logging/uceap'
defaults:
_form: '\Drupal\uceap_logging\Form\LoggingSettingsForm'
_title: 'Logging Settings'
requirements:
_permission: 'administer site configuration'