*/ private const DROPPED_FIELDS = [ 'evidence_jsonb', 'raw_evidence', 'snapshot_payload', ]; private const MAX_ITEMS = 50; private const MAX_STRING_LENGTH = 500; public static function sanitize(mixed $value): mixed { if (is_array($value)) { $sanitized = []; $count = 0; foreach ($value as $key => $item) { $count++; if ($count > self::MAX_ITEMS) { $sanitized['truncated'] = true; break; } if (is_string($key) && in_array($key, self::DROPPED_FIELDS, true)) { continue; } if (is_string($key) && self::classifier()->protectsField('audit', $key)) { $sanitized[$key] = self::REDACTED; continue; } $sanitized[$key] = self::sanitize($item); } return $sanitized; } if (is_string($value)) { return self::sanitizeString($value); } return $value; } private static function sanitizeString(string $value): string { $candidate = trim($value); if ($candidate === '') { return $value; } $sanitized = self::classifier()->sanitizeAuditString($value); if (mb_strlen($sanitized) <= self::MAX_STRING_LENGTH) { return $sanitized; } return mb_substr($sanitized, 0, self::MAX_STRING_LENGTH).' [truncated]'; } private static function classifier(): SecretClassificationService { return app(SecretClassificationService::class); } }