feat: add advanced architecture, documentation, and coverage improvements (#65)

* fix(style): resolve PHPCS line-length warnings in source files

* fix(style): resolve PHPCS line-length warnings in test files

* feat(audit): add structured audit logging with ErrorContext and AuditContext

- ErrorContext: standardized error information with sensitive data sanitization
- AuditContext: structured context for audit entries with operation types
- StructuredAuditLogger: enhanced audit logger wrapper with timing support

* feat(recovery): add recovery mechanism for failed masking operations

- FailureMode enum: FAIL_OPEN, FAIL_CLOSED, FAIL_SAFE modes
- RecoveryStrategy interface and RecoveryResult value object
- RetryStrategy: exponential backoff with configurable attempts
- FallbackMaskStrategy: type-aware fallback values

* feat(strategies): add CallbackMaskingStrategy for custom masking logic

- Wraps custom callbacks as MaskingStrategy implementations
- Factory methods: constant(), hash(), partial() for common use cases
- Supports exact match and prefix match for field paths

* docs: add framework integration guides and examples

- symfony-integration.md: Symfony service configuration and Monolog setup
- psr3-decorator.md: PSR-3 logger decorator pattern implementation
- framework-examples.md: CakePHP, CodeIgniter 4, Laminas, Yii2, PSR-15
- docker-development.md: Docker development environment guide

* chore(docker): add Docker development environment

- Dockerfile: PHP 8.2-cli-alpine with Xdebug for coverage
- docker-compose.yml: development services with volume mounts

* feat(demo): add interactive GDPR pattern tester playground

- PatternTester.php: pattern testing utility with strategy support
- index.php: web API endpoint with JSON response handling
- playground.html: interactive web interface for testing patterns

* docs(todo): update with completed medium priority items

- Mark all PHPCS warnings as fixed (81 → 0)
- Document new Audit and Recovery features
- Update test count to 1,068 tests with 2,953 assertions
- Move remaining items to low priority

* feat: add advanced architecture, documentation, and coverage improvements

- Add architecture improvements:
  - ArrayAccessorInterface and DotArrayAccessor for decoupled array access
  - MaskingOrchestrator for single-responsibility masking coordination
  - GdprProcessorBuilder for fluent configuration
  - MaskingPluginInterface and AbstractMaskingPlugin for plugin architecture
  - PluginAwareProcessor for plugin hook execution
  - AuditLoggerFactory for instance-based audit logger creation

- Add advanced features:
  - SerializedDataProcessor for handling print_r/var_export/serialize output
  - KAnonymizer with GeneralizationStrategy for GDPR k-anonymity
  - RetentionPolicy for configurable data retention periods
  - StreamingProcessor for memory-efficient large log processing

- Add comprehensive documentation:
  - docs/performance-tuning.md - benchmarking, optimization, caching
  - docs/troubleshooting.md - common issues and solutions
  - docs/logging-integrations.md - ELK, Graylog, Datadog, etc.
  - docs/plugin-development.md - complete plugin development guide

- Improve test coverage (84.41% → 85.07%):
  - ConditionalRuleFactoryInstanceTest (100% coverage)
  - GdprProcessorBuilderEdgeCasesTest (100% coverage)
  - StrategyEdgeCasesTest for ReDoS detection and type parsing
  - 78 new tests, 119 new assertions

- Update TODO.md with current statistics:
  - 141 PHP files, 1,346 tests, 85.07% line coverage

* chore: tests, update actions, sonarcloud issues

* chore: rector

* fix: more sonarcloud fixes

* chore: more fixes

* refactor: copilot review fix

* chore: rector
This commit is contained in:
2025-12-22 13:38:18 +02:00
committed by GitHub
parent b1eb567b92
commit 8866daaf33
112 changed files with 15391 additions and 607 deletions

264
docs/symfony-integration.md Normal file
View File

@@ -0,0 +1,264 @@
# Symfony Integration Guide
This guide explains how to integrate the Monolog GDPR Filter with Symfony applications.
## Installation
```bash
composer require ivuorinen/monolog-gdpr-filter
```
## Basic Service Configuration
Add the GDPR processor as a service in `config/services.yaml`:
```yaml
services:
App\Logging\GdprProcessor:
class: Ivuorinen\MonologGdprFilter\GdprProcessor
arguments:
$patterns: '%gdpr.patterns%'
$fieldPaths: '%gdpr.field_paths%'
$customCallbacks: []
$auditLogger: null
$maxDepth: 100
$dataTypeMasks: []
$conditionalRules: []
```
## Parameters Configuration
Define GDPR patterns in `config/services.yaml` or a dedicated parameters file:
```yaml
parameters:
gdpr.patterns:
'/\b\d{3}-\d{2}-\d{4}\b/': '***-**-****' # US SSN
'/\b[A-Z]{2}\d{2}[A-Z0-9]{4}\d{7}([A-Z0-9]?){0,16}\b/': '****' # IBAN
'/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/': '[email]' # Email
'/\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b/': '****-****-****-****' # Credit Card
gdpr.field_paths:
'user.password': '***REMOVED***'
'user.ssn': '***-**-****'
'payment.card_number': '****-****-****-****'
```
## Monolog Handler Configuration
Configure Monolog to use the GDPR processor in `config/packages/monolog.yaml`:
```yaml
monolog:
handlers:
main:
type: stream
path: "%kernel.logs_dir%/%kernel.environment%.log"
level: debug
channels: ["!event"]
formatter: monolog.formatter.json
processor: ['@App\Logging\GdprProcessor']
# For production with file rotation
production:
type: rotating_file
path: "%kernel.logs_dir%/%kernel.environment%.log"
level: info
max_files: 14
processor: ['@App\Logging\GdprProcessor']
```
## Environment-Specific Configuration
Create environment-specific configurations:
### config/packages/dev/monolog.yaml
```yaml
monolog:
handlers:
main:
type: stream
path: "%kernel.logs_dir%/%kernel.environment%.log"
level: debug
# In dev, you might want less aggressive masking
```
### config/packages/prod/monolog.yaml
```yaml
monolog:
handlers:
main:
type: fingers_crossed
action_level: error
handler: nested
excluded_http_codes: [404, 405]
buffer_size: 50
nested:
type: rotating_file
path: "%kernel.logs_dir%/%kernel.environment%.log"
level: info
max_files: 14
processor: ['@App\Logging\GdprProcessor']
```
## Advanced Configuration with Audit Logging
Enable audit logging for compliance tracking:
```yaml
services:
App\Logging\AuditLogger:
class: Ivuorinen\MonologGdprFilter\RateLimitedAuditLogger
arguments:
$auditLogger: '@App\Logging\AuditCallback'
$maxRequestsPerMinute: 100
$windowSeconds: 60
App\Logging\AuditCallback:
class: Closure
factory: ['App\Logging\AuditCallbackFactory', 'create']
arguments:
$logger: '@monolog.logger.audit'
App\Logging\GdprProcessor:
class: Ivuorinen\MonologGdprFilter\GdprProcessor
arguments:
$patterns: '%gdpr.patterns%'
$fieldPaths: '%gdpr.field_paths%'
$auditLogger: '@App\Logging\AuditLogger'
```
Create the factory class:
```php
<?php
// src/Logging/AuditCallbackFactory.php
namespace App\Logging;
use Psr\Log\LoggerInterface;
class AuditCallbackFactory
{
public static function create(LoggerInterface $logger): callable
{
return function (string $path, mixed $original, mixed $masked) use ($logger): void {
$logger->info('GDPR masking applied', [
'path' => $path,
'original_type' => gettype($original),
'masked_preview' => substr((string) $masked, 0, 20) . '...',
]);
};
}
}
```
## Conditional Masking by Environment
Apply different masking rules based on log level or channel:
```yaml
services:
App\Logging\ConditionalRuleFactory:
class: App\Logging\ConditionalRuleFactory
App\Logging\GdprProcessor:
class: Ivuorinen\MonologGdprFilter\GdprProcessor
arguments:
$conditionalRules:
error_only: '@=service("App\\Logging\\ConditionalRuleFactory").createErrorOnlyRule()'
```
```php
<?php
// src/Logging/ConditionalRuleFactory.php
namespace App\Logging;
use Monolog\Level;
use Monolog\LogRecord;
class ConditionalRuleFactory
{
public function createErrorOnlyRule(): callable
{
return fn(LogRecord $record): bool =>
$record->level->value >= Level::Error->value;
}
public function createChannelRule(array $channels): callable
{
return fn(LogRecord $record): bool =>
in_array($record->channel, $channels, true);
}
}
```
## Testing in Symfony
Create a test to verify GDPR filtering works:
```php
<?php
// tests/Logging/GdprProcessorTest.php
namespace App\Tests\Logging;
use Ivuorinen\MonologGdprFilter\GdprProcessor;
use Monolog\Level;
use Monolog\LogRecord;
use PHPUnit\Framework\TestCase;
use DateTimeImmutable;
class GdprProcessorTest extends TestCase
{
public function testEmailMasking(): void
{
$processor = new GdprProcessor([
'/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/' => '[email]',
]);
$record = new LogRecord(
datetime: new DateTimeImmutable(),
channel: 'test',
level: Level::Info,
message: 'User logged in: user@example.com',
context: []
);
$result = $processor($record);
$this->assertStringContainsString('[email]', $result->message);
$this->assertStringNotContainsString('user@example.com', $result->message);
}
}
```
## Troubleshooting
### Patterns Not Matching
1. Verify regex patterns are valid: `preg_match('/your-pattern/', 'test-string')`
2. Check pattern escaping in YAML (may need quotes)
3. Enable debug mode to see which patterns are applied
### Performance Issues
1. Use the rate-limited audit logger
2. Consider caching pattern validation results
3. Profile with Symfony profiler
### Memory Issues
1. Set appropriate `maxDepth` to prevent deep recursion
2. Monitor rate limiter statistics
3. Use cleanup intervals for long-running processes
## See Also
- [PSR-3 Decorator Guide](psr3-decorator.md)
- [Framework Examples](framework-examples.md)
- [Docker Development](docker-development.md)