mirror of
https://github.com/ivuorinen/monolog-gdpr-filter.git
synced 2026-02-08 11:48:06 +00:00
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:
@@ -22,7 +22,25 @@ class ConfigValidationTest extends TestCase
|
||||
*
|
||||
* @return ((bool|int|string)[]|bool|int)[]
|
||||
*
|
||||
* @psalm-return array{auto_register: bool, channels: list{'single', 'daily', 'stack'}, patterns: array<never, never>, field_paths: array<never, never>, custom_callbacks: array<never, never>, max_depth: int<1, 1000>, audit_logging: array{enabled: bool, channel: string}, performance: array{chunk_size: int<100, 10000>, garbage_collection_threshold: int<1000, 100000>}, validation: array{max_pattern_length: int<10, 1000>, max_field_path_length: int<5, 500>, allow_empty_patterns: bool, strict_regex_validation: bool}}
|
||||
* @psalm-return array{
|
||||
* auto_register: bool,
|
||||
* channels: list{'single', 'daily', 'stack'},
|
||||
* patterns: array<never, never>,
|
||||
* field_paths: array<never, never>,
|
||||
* custom_callbacks: array<never, never>,
|
||||
* max_depth: int<1, 1000>,
|
||||
* audit_logging: array{enabled: bool, channel: string},
|
||||
* performance: array{
|
||||
* chunk_size: int<100, 10000>,
|
||||
* garbage_collection_threshold: int<1000, 100000>
|
||||
* },
|
||||
* validation: array{
|
||||
* max_pattern_length: int<10, 1000>,
|
||||
* max_field_path_length: int<5, 500>,
|
||||
* allow_empty_patterns: bool,
|
||||
* strict_regex_validation: bool
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
private function getTestConfig(): array
|
||||
{
|
||||
@@ -42,10 +60,22 @@ class ConfigValidationTest extends TestCase
|
||||
'garbage_collection_threshold' => max(1000, min(100000, (int) ($_ENV['GDPR_GC_THRESHOLD'] ?? 10000))),
|
||||
],
|
||||
'validation' => [
|
||||
'max_pattern_length' => max(10, min(1000, (int) ($_ENV['GDPR_MAX_PATTERN_LENGTH'] ?? 500))),
|
||||
'max_field_path_length' => max(5, min(500, (int) ($_ENV['GDPR_MAX_FIELD_PATH_LENGTH'] ?? 100))),
|
||||
'allow_empty_patterns' => filter_var($_ENV['GDPR_ALLOW_EMPTY_PATTERNS'] ?? false, FILTER_VALIDATE_BOOLEAN),
|
||||
'strict_regex_validation' => filter_var($_ENV['GDPR_STRICT_REGEX_VALIDATION'] ?? true, FILTER_VALIDATE_BOOLEAN),
|
||||
'max_pattern_length' => max(
|
||||
10,
|
||||
min(1000, (int) ($_ENV['GDPR_MAX_PATTERN_LENGTH'] ?? 500))
|
||||
),
|
||||
'max_field_path_length' => max(
|
||||
5,
|
||||
min(500, (int) ($_ENV['GDPR_MAX_FIELD_PATH_LENGTH'] ?? 100))
|
||||
),
|
||||
'allow_empty_patterns' => filter_var(
|
||||
$_ENV['GDPR_ALLOW_EMPTY_PATTERNS'] ?? false,
|
||||
FILTER_VALIDATE_BOOLEAN
|
||||
),
|
||||
'strict_regex_validation' => filter_var(
|
||||
$_ENV['GDPR_STRICT_REGEX_VALIDATION'] ?? true,
|
||||
FILTER_VALIDATE_BOOLEAN
|
||||
),
|
||||
],
|
||||
];
|
||||
}
|
||||
@@ -426,9 +456,18 @@ class ConfigValidationTest extends TestCase
|
||||
|
||||
// Security-focused defaults
|
||||
$this->assertFalse($config['auto_register'], 'auto_register should default to false');
|
||||
$this->assertFalse($config['audit_logging']['enabled'], 'audit logging should default to false');
|
||||
$this->assertFalse($config['validation']['allow_empty_patterns'], 'empty patterns should not be allowed by default');
|
||||
$this->assertTrue($config['validation']['strict_regex_validation'], 'strict regex validation should be enabled by default');
|
||||
$this->assertFalse(
|
||||
$config['audit_logging']['enabled'],
|
||||
'audit logging should default to false'
|
||||
);
|
||||
$this->assertFalse(
|
||||
$config['validation']['allow_empty_patterns'],
|
||||
'empty patterns should not be allowed by default'
|
||||
);
|
||||
$this->assertTrue(
|
||||
$config['validation']['strict_regex_validation'],
|
||||
'strict regex validation should be enabled by default'
|
||||
);
|
||||
|
||||
// Restore environment variables
|
||||
foreach ($oldValues as $var => $value) {
|
||||
|
||||
@@ -21,6 +21,7 @@ use Tests\TestConstants;
|
||||
* Tests for the GdprProcessor class.
|
||||
*
|
||||
* @api
|
||||
* @psalm-suppress DeprecatedMethod - Tests for deprecated validation methods
|
||||
*/
|
||||
#[CoversClass(GdprProcessor::class)]
|
||||
class GdprProcessorValidationTest extends TestCase
|
||||
@@ -272,7 +273,8 @@ class GdprProcessorValidationTest extends TestCase
|
||||
public function constructorThrowsExceptionForInvalidDataTypeMaskKey(): void
|
||||
{
|
||||
$this->expectException(InvalidConfigurationException::class);
|
||||
$this->expectExceptionMessage("Must be one of: integer, double, string, boolean, NULL, array, object, resource");
|
||||
$expectedMsg = 'Must be one of: integer, double, string, boolean, NULL, array, object, resource';
|
||||
$this->expectExceptionMessage($expectedMsg);
|
||||
|
||||
new GdprProcessor([], [], [], null, 100, ['invalid_type' => MaskConstants::MASK_MASKED]);
|
||||
}
|
||||
@@ -408,8 +410,12 @@ class GdprProcessorValidationTest extends TestCase
|
||||
#[Test]
|
||||
public function constructorHandlesComplexValidRegexPatterns(): void
|
||||
{
|
||||
// Complex IP address pattern (IPv4 octet validation)
|
||||
$ipPattern = '/(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}'
|
||||
. '(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/';
|
||||
|
||||
$complexPatterns = [
|
||||
'/(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/' => MaskConstants::MASK_IP,
|
||||
$ipPattern => MaskConstants::MASK_IP,
|
||||
TestConstants::PATTERN_EMAIL_FULL => MaskConstants::MASK_EMAIL,
|
||||
'/\b\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}\b/' => MaskConstants::MASK_CARD
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user