Skip to content

Conversation

@ginkelsoft-development
Copy link
Owner

No description provided.

ginkelsoft-development and others added 28 commits October 13, 2025 10:59
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Previously, the encryptedExact() and encryptedPrefix() scopes always
queried the database table 'encrypted_search_index', even when
Elasticsearch was enabled. This caused zero results when ES mode
was active, as tokens were written to ES but queries hit the empty
database table.

Changes:
- Added searchElasticsearch() helper method to query ES index
- Updated scopeEncryptedExact() to check ES config and route accordingly
- Updated scopeEncryptedPrefix() to check ES config and route accordingly
- Both scopes now fall back to database when ES is disabled
- Added error handling with logging for ES query failures

This fixes the critical bug where ES integration was non-functional
for search operations.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…query-scopes

Fix/elasticsearch query scopes
Added validation to skip token generation for fields that don't have
an encrypted cast. This prevents unnecessary indexing and ensures that
only truly encrypted data gets searchable tokens in the index.

Changes:
- Added hasEncryptedCast() helper method to check field cast type
- Updated updateSearchIndex() to validate encrypted cast before processing
- Improved efficiency by skipping non-encrypted fields early
…rypted-fields

fix: only generate search tokens for fields with encrypted cast
Previously, removeFromElasticsearch() only performed a search but never
deleted the matching documents. This caused a memory leak in ES where
deleted model records would leave orphaned tokens in the index.

Changes:
- Added deleteByQuery() method to ElasticsearchService
- Updated removeFromElasticsearch() to use delete-by-query API
- Removed obsolete comment about future optimization
- Improved PHPDoc to reflect actual deletion behavior

This fixes the critical issue where ES tokens accumulated indefinitely
after model deletion.
…delete-implementation

fix: implement actual document deletion in Elasticsearch
Added validation to ensure SEARCH_PEPPER is not empty before generating
tokens. This prevents a security vulnerability where tokens would be
generated without a pepper, making them vulnerable to rainbow table attacks.

Changes:
- Added empty pepper validation in Tokens::exact()
- Added empty pepper validation in Tokens::prefixes()
- Throw RuntimeException with helpful error message and setup instructions
- Updated PHPDoc to document the exception

The error message now guides developers to configure the pepper properly
with a suggested command: openssl rand -base64 32
…r-configuration

fix: validate SEARCH_PEPPER configuration before token generation
Made intl PHP extension a required dependency to ensure consistent
token generation across all installations. Previously, normalization
behavior varied depending on whether intl was available, which could
cause search mismatches between environments.

Changes:
- Added ext-intl as required dependency in composer.json
- Removed conditional intl check in Normalizer class
- Updated PHPDoc to reflect intl requirement
- Ensures diacritics are always normalized consistently
Added comments to clarify the two-step process of removing old tokens
and bulk inserting new ones. While this is two queries, it's still
efficient as the insert is done in bulk rather than individual inserts.
Changed all Elasticsearch service methods to throw RuntimeException with
detailed error messages instead of silently returning boolean values.
This provides better debugging information and ensures failures don't
go unnoticed.

Changes:
- indexDocument() now throws exception with URL and response body on failure
- deleteDocument() now throws exception with URL and response body on failure
- search() now throws exception with URL and response body on failure
- Updated return types from bool to void where appropriate
- Added @throws annotations to PHPDoc
The SearchDriver interface was defined but never implemented anywhere
in the codebase. This is dead code that adds unnecessary complexity.

If a driver pattern becomes necessary in the future, it can be
reintroduced with actual implementations.
Added validation to check Elasticsearch configuration when ES mode is
enabled. This catches configuration errors early at boot time rather
than failing silently during runtime operations.

Changes:
- Added validateConfiguration() method to service provider
- Validates ELASTICSEARCH_HOST is set when ES is enabled
- Validates ELASTICSEARCH_INDEX is set when ES is enabled
- Throws InvalidArgumentException with helpful error messages
- Called automatically during boot()
This commit introduces a configurable debug logging feature that helps
developers and operators monitor encrypted search index operations.

Changes:
- Added 'debug' configuration option in encrypted-search.php
- Implemented conditional logging in updateSearchIndex() method
- Implemented conditional logging in removeSearchIndex() method
- Logs include model class, model ID, token count, and backend type

The logging only activates when ENCRYPTED_SEARCH_DEBUG=true is set
in the environment configuration, preventing unnecessary log noise
in production environments.
This commit significantly expands the test suite to improve code quality
and reliability. The test coverage has increased from 5 to 60 tests.

New test files added:
- tests/Unit/NormalizerTest.php: Validates text normalization logic
  including lowercasing, diacritic removal, special character handling,
  null/empty string handling, and international character support.

- tests/Unit/TokensTest.php: Tests token generation for both exact and
  prefix matching, including SHA-256 hash validation, deterministic
  behavior, pepper variation, UTF-8 support, and error handling.

- tests/Unit/EncryptedSearchAttributeTest.php: Validates the PHP 8
  attribute configuration including default values, custom settings,
  and toArray() conversion.

- tests/Unit/ElasticsearchServiceTest.php: Tests HTTP interactions with
  Elasticsearch including document indexing, deletion, searching, and
  delete-by-query operations with proper mocking and error handling.

- tests/Feature/HasEncryptedSearchIndexEdgeCasesTest.php: Comprehensive
  edge case testing including empty/null values, special characters,
  normalization consistency, prefix search boundaries, and field update
  behavior.

Bug fixes:
- Fixed syntax error in HasEncryptedSearchIndex.php (line 301)
- Corrected ElasticsearchService test expectations (boolean returns)
- Fixed Normalizer test assertion for international characters

Test results:
- 60 tests passing
- 108 assertions
- Covers all major components and edge cases
…xtension

fix: require intl extension for consistent normalization
…ase-index-upsert

improve: add clarifying comments to database index update process
…error-handling

fix: add proper error handling with exceptions to Elasticsearch service
…used-searchdriver-contract

refactor: remove unused SearchDriver contract interface
…logging

add optional debug logging for search index operations
…idation

fix: add configuration validation to service provider boot
…overage

expand test coverage with comprehensive unit and edge case tests
This feature addresses the issue of overly broad search matches from
very short prefixes by introducing a configurable minimum length
requirement for prefix-based searches.

Changes:
- Added 'min_prefix_length' configuration option (default: 3)
- Updated Tokens::prefixes() to accept minLength parameter
- Modified HasEncryptedSearchIndex to enforce minimum length during:
  - Token generation (indexing)
  - Query execution (searching)
- Added comprehensive test coverage (10 new feature tests, 6 unit tests)

Behavior:
- With min_prefix_length=3 (default):
  - Searching for "Wi" (2 chars) returns no results
  - Searching for "Wil" (3+ chars) works normally
- Prevents performance issues from single-character searches
- Reduces false positives from very short search terms
- Exact search is unaffected by this setting

Benefits:
- Eliminates unwanted matches (e.g., "W" matching "William", "Wendy", "Walter")
- Improves search precision
- Maintains backwards compatibility (set to 1 for old behavior)
- Configurable per environment via ENCRYPTED_SEARCH_MIN_PREFIX

Test updates:
- Updated existing tests to use min_prefix_length=1 for compatibility
- Added MinimumPrefixLengthTest with 10 comprehensive scenarios
- Added 6 unit tests for Tokens class minimum length behavior
- All 76 tests passing (136 assertions)
…efix-length

add configurable minimum prefix length for search queries
@ginkelsoft-development ginkelsoft-development merged commit 0964003 into main Oct 13, 2025
4 of 8 checks passed
ginkelsoft-development added a commit that referenced this pull request Oct 13, 2025
Fixes test failures in Laravel 9 and 10 by adding required dependencies:
- guzzlehttp/guzzle: Required by Laravel 9's HTTP client for mocking HTTP requests in tests
- doctrine/dbal: Required for Schema::table()->change() operations in migrations/tests

Both dependencies use version constraints compatible across all supported Laravel versions (9-12).

Tested with:
- Laravel 9 + PHP 8.1: All tests pass
- Laravel 10 + PHP 8.2: All tests pass

Fixes #25

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
ginkelsoft-development added a commit that referenced this pull request Oct 14, 2025
Fixes test failures in Laravel 9 and 10 by adding required dependencies:
- guzzlehttp/guzzle: Required by Laravel 9's HTTP client for mocking HTTP requests in tests
- doctrine/dbal: Required for Schema::table()->change() operations in migrations/tests

Both dependencies use version constraints compatible across all supported Laravel versions (9-12).

Tested with:
- Laravel 9 + PHP 8.1: All tests pass
- Laravel 10 + PHP 8.2: All tests pass

Fixes #25
ginkelsoft-development added a commit that referenced this pull request Oct 14, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants