Skip to content

Conversation

@David-Crty
Copy link
Owner

@David-Crty David-Crty commented Feb 11, 2026

Summary

  • Add Redis/Valkey as a new database type with backup-only support using redis-cli --rdb for RDB snapshots
  • Show manual restore instructions modal (no automated restore due to Redis limitations)
  • Include Docker/CI infrastructure (Redis 7 service, redis-cli in PHP image, GitHub Actions config)

Changes

Core: DatabaseType::REDIS enum, RedisDatabase handler implementing DatabaseInterface, backup/restore task integration, connection tester via redis-cli PING/INFO, database list service, backup job factory

UI: Form hides database selection for Redis, username optional, SSH tunnel hidden; Index page shows manual restore instructions modal with link to backup snapshots

Infrastructure: Redis 7 Docker service, redis package in Dockerfile, GitHub Actions Redis service, test config

Tests: 500 tests passing - new tests for Redis backup commands, restore rejection, connection testing, integration backup workflow, Livewire components

Test plan

  • make test - all 500 tests pass
  • make phpstan - no errors
  • Create a Redis/Valkey server in the UI
  • Test connection (expect PONG + server info)
  • Trigger manual backup, verify RDB snapshot created
  • Click Restore on Redis server, verify manual restore instructions modal

Summary by CodeRabbit

  • New Features

    • Added Redis/Valkey as a supported database type, including connection testing and backup creation (.rdb.gz).
    • Updated UI forms to handle Redis-specific fields and skip database selection when not applicable.
  • Changes

    • Automated restore for Redis/Valkey is not supported; added in-app modal with manual restore instructions.
  • Documentation

    • Updated guides to include Redis/Valkey across setup, architecture notes, and workflows.
  • Chores

    • Added Redis service to local development and CI environments.
  • Tests

    • Expanded unit and integration coverage for Redis/Valkey workflows.

Add Redis/Valkey as a new database type with backup support using
redis-cli --rdb for RDB snapshots. Automated restore is not supported
due to Redis limitations — a manual restore instructions modal is shown
instead.
@coderabbitai
Copy link

coderabbitai bot commented Feb 11, 2026

📝 Walkthrough

Walkthrough

This PR adds comprehensive Redis/Valkey support to the database backup system, including a new RedisDatabase service class, Redis-specific form validation and UI components, Redis backup workflow integration, explicit prevention of Redis restore operations, and corresponding Docker, CI, test infrastructure, and fixture updates.

Changes

Cohort / File(s) Summary
Infrastructure & CI
.github/workflows/tests.yml, docker-compose.yml, docker/php/Dockerfile, config/testing.php
Added Redis service to CI pipeline with health checks, exposed TEST_REDIS_HOST environment variable, added redis:7 Docker service with volume persistence and healthcheck, installed redis package in Alpine image, and configured Redis test database credentials.
Core Enum & Database Interface
app/Enums/DatabaseType.php, app/Services/Backup/Databases/RedisDatabase.php
Added DatabaseType::REDIS enum case with label "Redis / Valkey" and default port 6379; throws exceptions when attempting PDO/DSN operations. Introduced new RedisDatabase class implementing DatabaseInterface with methods for dump/ping/info commands via redis-cli, authentication flag building, and explicit restore unsupported exception.
Livewire Forms & Validation
app/Livewire/Forms/DatabaseServerForm.php
Added isRedis() detection method, Redis-specific validation rules (getRedisValidationRules), conditional form branching to Redis rules, and Redis-specific behavior during store/update (forcing backup_all_databases true, clearing database_names, validating host/port instead of generic credentials).
Livewire Components
app/Livewire/DatabaseServer/Edit.php, app/Livewire/DatabaseServer/Index.php, app/Livewire/DatabaseServer/RestoreModal.php
Updated Edit to skip loadDatabases for Redis alongside SQLite; added showRedisRestoreModal property and early-return logic in Index confirmRestore for Redis; refactored RestoreModal validation to use appDatabaseTypes and direct enum comparison for SQLite detection.
Backup Services
app/Services/Backup/BackupTask.php, app/Services/Backup/BackupJobFactory.php, app/Services/Backup/DatabaseListService.php
Extended BackupTask constructor to accept RedisDatabase dependency, added redis-cli dump command mapping to 'rdb' extension, and Redis configuration via setConfig. BackupJobFactory creates single 'all' snapshot for Redis like SQLite. DatabaseListService returns ['all'] for Redis without SSH/query overhead.
Restore & Connection Services
app/Services/Backup/RestoreTask.php, app/Services/DatabaseConnectionTester.php
RestoreTask throws UnsupportedDatabaseTypeException for Redis restores. DatabaseConnectionTester added Redis testing via testRedisConnection, validates host/port with PING command, disallows SSH tunneling for Redis, and formats success response with version/memory info.
Blade Templates
resources/views/livewire/database-server/_form.blade.php, resources/views/livewire/database-server/index.blade.php, resources/views/livewire/database-server/restore-modal.blade.php
Form added Redis-specific field visibility (optional Username, hidden SSH config, adjusted step numbering). Index added new showRedisRestoreModal with instructional modal for manual RDB restore. Restore modal restructured HTML formatting without functional changes.
Test Infrastructure & Fixtures
tests/Pest.php, tests/Support/IntegrationTestHelpers.php, tests/Integration/fixtures/redis-init.txt, database/factories/DatabaseServerFactory.php, database/seeders/DatabaseSeeder.php
Added 'redis' database type to test datasets and configs. DatabaseServerFactory::redis() returns Redis configuration (host, port 6379, backup_all_databases true). DatabaseSeeder creates Redis server entry. IntegrationTestHelpers added getDatabaseConfig/createRedisDatabaseServer/loadRedisTestData methods. Redis fixture seeds sample data (users, products, config hashes, events).
Feature & Integration Tests
tests/Feature/DatabaseServer/CreateTest.php, tests/Feature/DatabaseServer/EditTest.php, tests/Feature/DatabaseServer/RestoreModalTest.php, tests/Feature/Services/Backup/BackupTaskTest.php, tests/Feature/Services/Backup/RestoreTaskTest.php, tests/Integration/BackupRestoreTest.php, tests/Integration/DatabaseConnectionTesterTest.php
CreateTest/EditTest added Redis server type handling with host/port assertions. RestoreModalTest updated to explicit database types array and added Redis manual restore modal test. BackupTaskTest added RedisDatabase constructor injection and Redis backup/authenticated backup workflow tests. RestoreTaskTest added test for UnsupportedDatabaseTypeException on Redis restore. Integration BackupRestoreTest added redis backup workflow test validating .rdb.gz filename and 'all' database name. DatabaseConnectionTesterTest added Redis success/failure connection tests with port validation.
Documentation
CLAUDE.md
Updated project overview to include Redis/Valkey among supported databases; documented Redis in docker services, make commands, connection testing, and backup/restore task wiring; expanded scaffolding references for adding new database types to include Redis-related files.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Poem

🐰 A Redis comes to databasement's door,
With snapshots and CLI commands galore,
RDB dumps and pings so swift,
But restores? That's a different gift—
For some databases just watch, don't mend! 🔴

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 65.12% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely describes the main change: adding Redis/Valkey as a new database type across the application.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/redis-valkey-support

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tests/Integration/BackupRestoreTest.php (1)

3-8: ⚠️ Potential issue | 🟡 Minor

Update the file-level docblock to mention Redis.

The docblock states tests require MySQL and PostgreSQL containers, but Redis is now also required.

📝 Suggested docblock update
 /**
  * Integration tests for backup and restore with real databases.
  *
- * These tests require MySQL and PostgreSQL containers to be running.
+ * These tests require MySQL, PostgreSQL, and Redis containers to be running.
  * Run with: php artisan test --group=integration
  */
🤖 Fix all issues with AI agents
In `@app/Services/Backup/RestoreTask.php`:
- Around line 56-58: The current throw in RestoreTask.php uses
UnsupportedDatabaseTypeException with a full sentence which the exception
constructor will wrap into "Database type '...' is not supported" and garble the
message; fix by either throwing a RestoreException with your custom message
(e.g., when $targetServer->database_type === DatabaseType::REDIS throw new
RestoreException('Automated restore is not supported for Redis/Valkey. Please
restore manually.')) or by passing only the raw type identifier to
UnsupportedDatabaseTypeException (e.g., pass $targetServer->database_type) so
the constructor formats the message correctly.

In `@app/Services/DatabaseConnectionTester.php`:
- Around line 38-41: The error message for the SSH-tunneling guard incorrectly
says "SQLite" even when DatabaseType::REDIS is in the checked list; update the
return in the SSH check inside DatabaseConnectionTester (the block that checks
in_array($databaseType, [DatabaseType::SQLITE, DatabaseType::REDIS]) &&
$sshConfig !== null) to return a correct message that references the actual
disallowed types (e.g., "SSH tunneling is not supported for SQLite or Redis
databases") or construct the message dynamically using $databaseType, and keep
the call to self::error(...) unchanged.

In `@tests/Support/IntegrationTestHelpers.php`:
- Around line 146-155: The loadRedisTestData method currently runs redis-cli
without authentication and silences stderr, so authenticated Redis instances
fail silently; update loadRedisTestData to read the test Redis password from
configuration (testing.databases.redis.password), escape it (use escapeshellarg)
and, when non-empty, include the auth flag (e.g. -a <escapedPassword>) in both
exec calls, and stop redirecting stderr to /dev/null (or capture exec return
codes) so failures are visible; refer to loadRedisTestData, $server,
$fixtureFile and the config key testing.databases.redis.password when making the
change.
🧹 Nitpick comments (5)
app/Services/Backup/Databases/RedisDatabase.php (2)

23-81: Consider extracting the repeated command-building preamble.

getDumpCommandLine, getPingCommand, and getInfoCommand all duplicate the same redis-cli -h ... -p ... [auth] --no-auth-warning prefix. A small helper would reduce duplication and make adding future commands easier.

♻️ Suggested refactor
+    /**
+     * Build a base redis-cli command with host, port, auth, and --no-auth-warning.
+     *
+     * `@param`  array<string, mixed>  $config
+     * `@return` array<string>
+     */
+    private function buildBaseCommand(array $config): array
+    {
+        $parts = ['redis-cli'];
+        $parts[] = '-h '.escapeshellarg($config['host']);
+        $parts[] = '-p '.escapeshellarg((string) $config['port']);
+        $parts = array_merge($parts, $this->buildAuthFlags($config));
+        $parts[] = '--no-auth-warning';
+
+        return $parts;
+    }
+
     public function getDumpCommandLine(string $outputPath): string
     {
-        $parts = ['redis-cli'];
-
-        $parts[] = '-h '.escapeshellarg($this->config['host']);
-        $parts[] = '-p '.escapeshellarg((string) $this->config['port']);
-
-        $parts = array_merge($parts, $this->buildAuthFlags($this->config));
-
-        $parts[] = '--no-auth-warning';
+        $parts = $this->buildBaseCommand($this->config);
         $parts[] = '--rdb '.escapeshellarg($outputPath);
 
         return implode(' ', $parts);
     }

Apply the same pattern to getPingCommand and getInfoCommand.


48-61: Design note: getPingCommand/getInfoCommand take $config as parameter while getDumpCommandLine uses instance $this->config.

This inconsistency exists because the connection tester calls getPingCommand/getInfoCommand without setConfig(), while the backup flow uses setConfig() + getDumpCommandLine(). It works correctly but is worth documenting in a PHPDoc note on the class to clarify the two usage patterns.

app/Services/Backup/BackupTask.php (1)

52-56: DRY: extension-mapping logic is duplicated in run() and generateFilename().

The same match expression for mapping DatabaseType → file extension appears in both places. Consider extracting it to a private helper.

♻️ Suggested refactor
+    private function getBaseExtension(DatabaseType $databaseType): string
+    {
+        return match ($databaseType) {
+            DatabaseType::SQLITE => 'db',
+            DatabaseType::REDIS => 'rdb',
+            default => 'sql',
+        };
+    }

Then replace both occurrences:

-            $extension = match ($databaseServer->database_type) {
-                DatabaseType::SQLITE => 'db',
-                DatabaseType::REDIS => 'rdb',
-                default => 'sql',
-            };
+            $extension = $this->getBaseExtension($databaseServer->database_type);

Also applies to: 174-178

app/Livewire/Forms/DatabaseServerForm.php (1)

786-791: Consider excluding Redis from SSH config building, in addition to SQLite.

Currently $sshConfig is built whenever ssh_enabled && !isSqlite(). The UI hides SSH for Redis, so this is low-risk, but for defense-in-depth the condition should also exclude Redis — matching the guard in DatabaseConnectionTester::test().

♻️ Suggested fix
-        $sshConfig = $this->ssh_enabled && ! $this->isSqlite()
+        $sshConfig = $this->ssh_enabled && ! $this->isSqlite() && ! $this->isRedis()
             ? $this->buildSshConfigForTest()
             : null;
resources/views/livewire/database-server/_form.blade.php (1)

101-103: SSH tunnel exclusion for Redis — is this intentional?

Redis servers behind firewalls may also benefit from SSH tunneling. While the PR objectives mention hiding SSH tunnel fields for Redis, consider whether this is a permanent design decision or something that may need to be revisited. If intentional, a brief comment or documentation note explaining the rationale would help future maintainers.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bc2e7fc and 93a2831.

📒 Files selected for processing (31)
  • .github/workflows/tests.yml
  • CLAUDE.md
  • app/Enums/DatabaseType.php
  • app/Livewire/DatabaseServer/Edit.php
  • app/Livewire/DatabaseServer/Index.php
  • app/Livewire/DatabaseServer/RestoreModal.php
  • app/Livewire/Forms/DatabaseServerForm.php
  • app/Services/Backup/BackupJobFactory.php
  • app/Services/Backup/BackupTask.php
  • app/Services/Backup/DatabaseListService.php
  • app/Services/Backup/Databases/RedisDatabase.php
  • app/Services/Backup/RestoreTask.php
  • app/Services/DatabaseConnectionTester.php
  • config/testing.php
  • database/factories/DatabaseServerFactory.php
  • database/seeders/DatabaseSeeder.php
  • docker-compose.yml
  • docker/php/Dockerfile
  • resources/views/livewire/database-server/_form.blade.php
  • resources/views/livewire/database-server/index.blade.php
  • resources/views/livewire/database-server/restore-modal.blade.php
  • tests/Feature/DatabaseServer/CreateTest.php
  • tests/Feature/DatabaseServer/EditTest.php
  • tests/Feature/DatabaseServer/RestoreModalTest.php
  • tests/Feature/Services/Backup/BackupTaskTest.php
  • tests/Feature/Services/Backup/RestoreTaskTest.php
  • tests/Integration/BackupRestoreTest.php
  • tests/Integration/DatabaseConnectionTesterTest.php
  • tests/Integration/fixtures/redis-init.txt
  • tests/Pest.php
  • tests/Support/IntegrationTestHelpers.php
🧰 Additional context used
📓 Path-based instructions (13)
**/*.php

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.php: All PHP commands (php, composer, vendor/bin/*) MUST be run through Docker using docker compose exec --user application -T app <command>. Never run these commands directly on the host.
Always use explicit return type declarations for methods and functions
Use PHP 8 constructor property promotion in __construct() methods with explicit parameter types
Do not allow empty __construct() methods with zero parameters unless the constructor is private
Always use curly braces for control structures, even for single-line bodies
Use appropriate PHP type hints for method parameters
Prefer PHPDoc blocks over inline comments; never use comments within the code itself unless the logic is exceptionally complex
Keys in Enums should typically be TitleCase (e.g., FavoritePerson, BestLake, Monthly)
Always use proper Eloquent relationship methods with return type hints; prefer relationship methods over raw queries or manual joins
Use Laravel's built-in authentication and authorization features (gates, policies, Sanctum) rather than custom implementations
Avoid DB::; prefer Model::query() and leverage Laravel's ORM capabilities rather than bypassing them with raw queries

Files:

  • tests/Integration/DatabaseConnectionTesterTest.php
  • app/Services/DatabaseConnectionTester.php
  • tests/Feature/Services/Backup/RestoreTaskTest.php
  • app/Services/Backup/RestoreTask.php
  • app/Services/Backup/Databases/RedisDatabase.php
  • config/testing.php
  • database/seeders/DatabaseSeeder.php
  • tests/Feature/DatabaseServer/CreateTest.php
  • tests/Pest.php
  • resources/views/livewire/database-server/_form.blade.php
  • resources/views/livewire/database-server/restore-modal.blade.php
  • app/Services/Backup/BackupTask.php
  • app/Livewire/DatabaseServer/Edit.php
  • app/Livewire/Forms/DatabaseServerForm.php
  • tests/Feature/DatabaseServer/RestoreModalTest.php
  • tests/Integration/BackupRestoreTest.php
  • database/factories/DatabaseServerFactory.php
  • app/Enums/DatabaseType.php
  • tests/Support/IntegrationTestHelpers.php
  • tests/Feature/DatabaseServer/EditTest.php
  • resources/views/livewire/database-server/index.blade.php
  • app/Services/Backup/BackupJobFactory.php
  • app/Services/Backup/DatabaseListService.php
  • app/Livewire/DatabaseServer/RestoreModal.php
  • tests/Feature/Services/Backup/BackupTaskTest.php
  • app/Livewire/DatabaseServer/Index.php
tests/**/*.php

📄 CodeRabbit inference engine (CLAUDE.md)

tests/**/*.php: Use factories for creating models in tests via the ModelFactory::create() pattern; check for custom states before manually setting up models
Use Faker methods such as $this->faker->word() or fake()->randomDigit() for generating test data

Files:

  • tests/Integration/DatabaseConnectionTesterTest.php
  • tests/Feature/Services/Backup/RestoreTaskTest.php
  • tests/Feature/DatabaseServer/CreateTest.php
  • tests/Pest.php
  • tests/Feature/DatabaseServer/RestoreModalTest.php
  • tests/Integration/BackupRestoreTest.php
  • tests/Support/IntegrationTestHelpers.php
  • tests/Feature/DatabaseServer/EditTest.php
  • tests/Feature/Services/Backup/BackupTaskTest.php
app/Services/**/*.php

📄 CodeRabbit inference engine (CLAUDE.md)

Services should be injected into component constructors using PHP 8 constructor property promotion

Files:

  • app/Services/DatabaseConnectionTester.php
  • app/Services/Backup/RestoreTask.php
  • app/Services/Backup/Databases/RedisDatabase.php
  • app/Services/Backup/BackupTask.php
  • app/Services/Backup/BackupJobFactory.php
  • app/Services/Backup/DatabaseListService.php
tests/Feature/**/*.php

📄 CodeRabbit inference engine (CLAUDE.md)

Write a new test or update an existing test for every code change; run affected tests to ensure they pass

Files:

  • tests/Feature/Services/Backup/RestoreTaskTest.php
  • tests/Feature/DatabaseServer/CreateTest.php
  • tests/Feature/DatabaseServer/RestoreModalTest.php
  • tests/Feature/DatabaseServer/EditTest.php
  • tests/Feature/Services/Backup/BackupTaskTest.php
app/Services/Backup/Databases/*.php

📄 CodeRabbit inference engine (CLAUDE.md)

Database handler classes should implement the DatabaseInterface for backup/restore operations

Files:

  • app/Services/Backup/Databases/RedisDatabase.php
config/*.php

📄 CodeRabbit inference engine (CLAUDE.md)

Use environment variables only in configuration files; never use the env() function directly outside of config files - always use config('key.name')

Files:

  • config/testing.php
resources/views/livewire/**/*.blade.php

📄 CodeRabbit inference engine (CLAUDE.md)

Blade files for Livewire components should contain only view markup; all PHP logic must be in component classes

Files:

  • resources/views/livewire/database-server/_form.blade.php
  • resources/views/livewire/database-server/restore-modal.blade.php
  • resources/views/livewire/database-server/index.blade.php
resources/views/**/*.blade.php

📄 CodeRabbit inference engine (CLAUDE.md)

resources/views/**/*.blade.php: Use Mary UI components prefixed with x- (e.g., <x-button>, <x-input>, <x-card>)
Use Heroicons for icons with the notation icon="o-user" for outline icons or icon="s-user" for solid icons
Use Mary UI select components with :options prop in format [['id' => 'value', 'name' => 'Label']]
Use Mary UI alert classes with format class="alert-success", class="alert-error", etc.
Use Mary UI tables with <table class="table-default"> with custom styling

Files:

  • resources/views/livewire/database-server/_form.blade.php
  • resources/views/livewire/database-server/restore-modal.blade.php
  • resources/views/livewire/database-server/index.blade.php
resources/**/*.blade.php

📄 CodeRabbit inference engine (CLAUDE.md)

Use Tailwind CSS v4 utility classes for styling (flex, grid, responsive design, dark mode with prefers-color-scheme)

Files:

  • resources/views/livewire/database-server/_form.blade.php
  • resources/views/livewire/database-server/restore-modal.blade.php
  • resources/views/livewire/database-server/index.blade.php
app/Livewire/**/*.php

📄 CodeRabbit inference engine (CLAUDE.md)

app/Livewire/**/*.php: Public properties in Livewire components are automatically bound to views
Use #[Validate] attributes or Form objects for validation in Livewire components
Call $this->validate() before processing data in Livewire components
Use Session::flash() for one-time messages in Livewire components, displayed via @if (session('success')) in Blade
Return $this->redirect() with navigate: true for SPA-like navigation in Livewire components
Use boolean properties with wire:model for controlling modal visibility (e.g., $showDeleteModal)

Files:

  • app/Livewire/DatabaseServer/Edit.php
  • app/Livewire/Forms/DatabaseServerForm.php
  • app/Livewire/DatabaseServer/RestoreModal.php
  • app/Livewire/DatabaseServer/Index.php
app/Livewire/Forms/*.php

📄 CodeRabbit inference engine (CLAUDE.md)

Form classes should encapsulate validation logic with a rules() method and include validation attributes

Files:

  • app/Livewire/Forms/DatabaseServerForm.php
app/Enums/*.php

📄 CodeRabbit inference engine (CLAUDE.md)

Add useful array shape type definitions in PHPDoc blocks for Enum methods that return arrays

Files:

  • app/Enums/DatabaseType.php
app/Enums/DatabaseType.php

📄 CodeRabbit inference engine (CLAUDE.md)

When adding a new database type, include enum case, label, default port, and DSN format in buildDsn() method

Files:

  • app/Enums/DatabaseType.php
🧠 Learnings (19)
📓 Common learnings
Learnt from: CR
Repo: David-Crty/databasement PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-02-09T21:29:11.506Z
Learning: Applies to app/Services/Backup/Databases/*.php : Database handler classes should implement the `DatabaseInterface` for backup/restore operations
📚 Learning: 2026-02-09T21:29:11.506Z
Learnt from: CR
Repo: David-Crty/databasement PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-02-09T21:29:11.506Z
Learning: Applies to app/Services/Backup/Databases/*.php : Database handler classes should implement the `DatabaseInterface` for backup/restore operations

Applied to files:

  • app/Services/DatabaseConnectionTester.php
  • tests/Feature/Services/Backup/RestoreTaskTest.php
  • app/Services/Backup/RestoreTask.php
  • app/Services/Backup/Databases/RedisDatabase.php
  • database/seeders/DatabaseSeeder.php
  • app/Services/Backup/BackupTask.php
  • CLAUDE.md
  • app/Services/Backup/BackupJobFactory.php
  • app/Services/Backup/DatabaseListService.php
  • app/Livewire/DatabaseServer/RestoreModal.php
  • tests/Feature/Services/Backup/BackupTaskTest.php
  • app/Livewire/DatabaseServer/Index.php
📚 Learning: 2026-02-09T21:29:11.506Z
Learnt from: CR
Repo: David-Crty/databasement PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-02-09T21:29:11.506Z
Learning: Applies to app/Services/Backup/Filesystems/*.php : Filesystem classes should implement the `FilesystemInterface` for volume storage operations

Applied to files:

  • app/Services/DatabaseConnectionTester.php
  • app/Services/Backup/Databases/RedisDatabase.php
  • app/Services/Backup/BackupTask.php
  • CLAUDE.md
  • tests/Feature/Services/Backup/BackupTaskTest.php
📚 Learning: 2026-02-09T21:29:11.506Z
Learnt from: CR
Repo: David-Crty/databasement PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-02-09T21:29:11.506Z
Learning: Applies to app/Jobs/*.php : Queue jobs like `ProcessBackupJob` and `ProcessRestoreJob` should wrap service classes and configure retries/timeout appropriately

Applied to files:

  • app/Services/DatabaseConnectionTester.php
  • app/Services/Backup/BackupTask.php
  • CLAUDE.md
  • tests/Feature/Services/Backup/BackupTaskTest.php
📚 Learning: 2026-02-07T23:36:48.880Z
Learnt from: David-Crty
Repo: David-Crty/databasement PR: 76
File: app/Jobs/ProcessRestoreJob.php:32-34
Timestamp: 2026-02-07T23:36:48.880Z
Learning: Restore operations in ProcessRestoreJob are idempotent (they drop and recreate the database regardless), so retrying failed restores is safe and ProcessRestoreJob intentionally shares the backup.job_tries configuration with ProcessBackupJob.

Applied to files:

  • app/Services/Backup/RestoreTask.php
  • CLAUDE.md
📚 Learning: 2026-01-30T22:27:46.107Z
Learnt from: David-Crty
Repo: David-Crty/databasement PR: 61
File: resources/views/livewire/volume/connectors/s3-config.blade.php:1-13
Timestamp: 2026-01-30T22:27:46.107Z
Learning: In Blade template files (any .blade.php) within the databasement project, allow using alert-info for informational content inside <x-alert> components. The guideline that permits alert-success and alert-error does not exclude using alert-info for informational purposes. Apply this consistently to all Blade components that render alerts; ensure semantic usage and accessibility.

Applied to files:

  • resources/views/livewire/database-server/_form.blade.php
  • resources/views/livewire/database-server/restore-modal.blade.php
  • resources/views/livewire/database-server/index.blade.php
📚 Learning: 2026-02-06T10:34:43.585Z
Learnt from: David-Crty
Repo: David-Crty/databasement PR: 75
File: resources/views/livewire/backup-job/_filters.blade.php:36-40
Timestamp: 2026-02-06T10:34:43.585Z
Learning: In Blade template files, when creating compact inline filter controls, prefer using native <input type="checkbox"> elements with daisyUI classes (e.g., checkbox checkbox-warning checkbox-xs) over the Mary UI <x-checkbox> component. The <x-checkbox> component adds wrapper markup (e.g., <div><fieldset><label> with gap-3) that can break tight inline flex layouts. Use the native input approach for compact inline controls, but reserve <x-checkbox> for form fields that require labels, hints, and errors.

Applied to files:

  • resources/views/livewire/database-server/_form.blade.php
  • resources/views/livewire/database-server/restore-modal.blade.php
  • resources/views/livewire/database-server/index.blade.php
📚 Learning: 2026-02-09T21:29:11.506Z
Learnt from: CR
Repo: David-Crty/databasement PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-02-09T21:29:11.506Z
Learning: Applies to tests/**/*.php : Use factories for creating models in tests via the `ModelFactory::create()` pattern; check for custom states before manually setting up models

Applied to files:

  • tests/Feature/DatabaseServer/RestoreModalTest.php
📚 Learning: 2026-02-09T21:29:11.506Z
Learnt from: CR
Repo: David-Crty/databasement PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-02-09T21:29:11.506Z
Learning: The Backup & Restore workflow operates asynchronously via the queue: backups dispatch to queue → queue worker executes BackupTask → creates Snapshot with status; restores dispatch ProcessRestoreJob → queue worker executes RestoreTask

Applied to files:

  • tests/Integration/BackupRestoreTest.php
  • CLAUDE.md
  • tests/Feature/Services/Backup/BackupTaskTest.php
📚 Learning: 2026-02-09T21:29:11.506Z
Learnt from: CR
Repo: David-Crty/databasement PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-02-09T21:29:11.506Z
Learning: Applies to app/Enums/DatabaseType.php : When adding a new database type, include enum case, label, default port, and DSN format in `buildDsn()` method

Applied to files:

  • app/Enums/DatabaseType.php
  • CLAUDE.md
  • app/Livewire/DatabaseServer/RestoreModal.php
  • app/Livewire/DatabaseServer/Index.php
📚 Learning: 2026-02-09T21:29:11.506Z
Learnt from: CR
Repo: David-Crty/databasement PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-02-09T21:29:11.506Z
Learning: Use the Laravel Boost `search-docs` tool for version-specific documentation before making code changes to ensure correct approach

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-02-09T21:29:11.506Z
Learnt from: CR
Repo: David-Crty/databasement PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-02-09T21:29:11.506Z
Learning: Applies to **/*.php : All PHP commands (php, composer, vendor/bin/*) MUST be run through Docker using `docker compose exec --user application -T app <command>`. Never run these commands directly on the host.

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-02-09T21:29:11.506Z
Learnt from: CR
Repo: David-Crty/databasement PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-02-09T21:29:11.506Z
Learning: Applies to app/Enums/VolumeType.php : VolumeType enum should implement `label()`, `icon()`, `sensitiveFields()`, and `configSummary()` methods

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-02-01T11:15:00.924Z
Learnt from: David-Crty
Repo: David-Crty/databasement PR: 64
File: docs/docs/self-hosting/configuration/backup.md:141-144
Timestamp: 2026-02-01T11:15:00.924Z
Learning: Self-hosting documentation (in `docs/docs/self-hosting/`) should use plain `php artisan` commands since the deployment environment is unknown. The Docker command requirement (`docker compose exec --user application -T app`) applies only to local development, not deployment documentation.

Applied to files:

  • CLAUDE.md
📚 Learning: 2026-02-09T21:29:11.506Z
Learnt from: CR
Repo: David-Crty/databasement PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-02-09T21:29:11.506Z
Learning: Applies to app/Livewire/**/*.php : Use boolean properties with `wire:model` for controlling modal visibility (e.g., `$showDeleteModal`)

Applied to files:

  • resources/views/livewire/database-server/index.blade.php
  • app/Livewire/DatabaseServer/RestoreModal.php
  • app/Livewire/DatabaseServer/Index.php
📚 Learning: 2026-02-09T21:29:11.506Z
Learnt from: CR
Repo: David-Crty/databasement PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-02-09T21:29:11.506Z
Learning: Applies to app/Livewire/**/*.php : Use `#[Validate]` attributes or Form objects for validation in Livewire components

Applied to files:

  • app/Livewire/DatabaseServer/RestoreModal.php
📚 Learning: 2026-02-09T21:29:11.506Z
Learnt from: CR
Repo: David-Crty/databasement PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-02-09T21:29:11.506Z
Learning: Applies to app/Livewire/**/*.php : Call `$this->validate()` before processing data in Livewire components

Applied to files:

  • app/Livewire/DatabaseServer/RestoreModal.php
📚 Learning: 2026-02-09T21:29:11.506Z
Learnt from: CR
Repo: David-Crty/databasement PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-02-09T21:29:11.506Z
Learning: Applies to app/Livewire/Forms/*.php : Form classes should encapsulate validation logic with a `rules()` method and include validation attributes

Applied to files:

  • app/Livewire/DatabaseServer/RestoreModal.php
📚 Learning: 2026-02-09T21:29:11.506Z
Learnt from: CR
Repo: David-Crty/databasement PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-02-09T21:29:11.506Z
Learning: Applies to app/Livewire/**/*.php : Public properties in Livewire components are automatically bound to views

Applied to files:

  • app/Livewire/DatabaseServer/RestoreModal.php
🧬 Code graph analysis (13)
app/Services/DatabaseConnectionTester.php (1)
app/Services/Backup/Databases/RedisDatabase.php (3)
  • RedisDatabase (5-104)
  • getPingCommand (48-61)
  • getInfoCommand (68-81)
tests/Feature/Services/Backup/RestoreTaskTest.php (2)
app/Exceptions/Backup/UnsupportedDatabaseTypeException.php (1)
  • UnsupportedDatabaseTypeException (5-11)
app/Services/Backup/RestoreTask.php (1)
  • run (47-146)
app/Services/Backup/RestoreTask.php (2)
app/Models/Restore.php (1)
  • targetServer (70-73)
app/Exceptions/Backup/UnsupportedDatabaseTypeException.php (1)
  • UnsupportedDatabaseTypeException (5-11)
database/seeders/DatabaseSeeder.php (2)
database/factories/DatabaseServerFactory.php (2)
  • redis (55-67)
  • sqlite (38-50)
app/Models/DatabaseServer.php (1)
  • DatabaseServer (60-218)
tests/Feature/DatabaseServer/CreateTest.php (1)
app/Services/AppConfigService.php (1)
  • set (66-86)
app/Livewire/DatabaseServer/Edit.php (1)
app/Livewire/Forms/DatabaseServerForm.php (2)
  • isSqlite (346-349)
  • isRedis (354-357)
tests/Feature/DatabaseServer/RestoreModalTest.php (2)
app/Models/DatabaseServer.php (1)
  • DatabaseServer (60-218)
app/Services/DatabaseConnectionTester.php (1)
  • test (30-93)
tests/Integration/BackupRestoreTest.php (6)
app/Models/Backup.php (3)
  • volume (77-80)
  • databaseServer (69-72)
  • snapshots (93-96)
app/Models/Snapshot.php (4)
  • volume (209-212)
  • databaseServer (193-196)
  • backup (201-204)
  • job (225-228)
tests/Support/IntegrationTestHelpers.php (2)
  • IntegrationTestHelpers (14-245)
  • loadRedisTestData (146-155)
app/Services/Backup/BackupJobFactory.php (1)
  • createSnapshots (30-73)
app/Services/Backup/BackupTask.php (1)
  • run (43-135)
app/Services/Backup/Filesystems/FilesystemProvider.php (1)
  • getForVolume (34-44)
tests/Support/IntegrationTestHelpers.php (1)
app/Models/DatabaseServer.php (1)
  • DatabaseServer (60-218)
app/Services/Backup/BackupJobFactory.php (2)
app/Models/DatabaseServer.php (1)
  • snapshots (120-123)
tests/Feature/Console/CleanupExpiredSnapshotsTest.php (1)
  • createSnapshot (8-27)
app/Services/Backup/DatabaseListService.php (2)
app/Models/Backup.php (1)
  • databaseServer (69-72)
app/Models/Snapshot.php (1)
  • databaseServer (193-196)
app/Livewire/DatabaseServer/RestoreModal.php (2)
app/Livewire/Forms/DatabaseServerForm.php (1)
  • isSqlite (346-349)
app/Models/Restore.php (1)
  • targetServer (70-73)
tests/Feature/Services/Backup/BackupTaskTest.php (2)
app/Services/Backup/Databases/RedisDatabase.php (1)
  • RedisDatabase (5-104)
tests/Support/TestShellProcessor.php (1)
  • getCommands (104-107)
🪛 LanguageTool
CLAUDE.md

[grammar] ~332-~332: Ensure spelling is correct
Context: ... php (FrankenPHP), queue worker, mysql, postgres, redis === ...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🪛 PHPMD (2.15.0)
app/Services/Backup/Databases/RedisDatabase.php

[warning] 38-38: Avoid unused parameters such as '$inputPath'. (undefined)

(UnusedFormalParameter)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-base-image
🔇 Additional comments (41)
docker/php/Dockerfile (1)

39-40: Consider installing only redis CLI tools to reduce image size.

The redis Alpine package includes both the server and CLI. If only redis-cli is needed (for redis-cli --rdb and redis-cli PING), this adds unnecessary bloat. However, Alpine doesn't split these into separate packages, so this is acceptable as-is.

database/seeders/DatabaseSeeder.php (1)

86-98: LGTM!

Redis server seeding and inclusion in the backup configuration loop are consistent with the existing patterns for MySQL, PostgreSQL, and SQLite.

config/testing.php (1)

34-38: LGTM!

Redis test configuration follows the established pattern and correctly uses env() within the config file. As per coding guidelines, env() usage is appropriate here since this is a config file.

docker-compose.yml (1)

85-96: LGTM!

Redis service definition follows the established patterns for other database services, with proper healthcheck configuration and persistent volume.

.github/workflows/tests.yml (2)

36-44: LGTM!

Redis CI service configuration is consistent with the existing MySQL and PostgreSQL service patterns, including proper health checks.


61-61: LGTM!

Adding redis-tools provides redis-cli for CI test runs.

app/Enums/DatabaseType.php (1)

12-12: LGTM!

New REDIS enum case is correctly added with all required mappings: label, default port, and DSN/PDO guards. This follows the coding guideline for adding new database types. Based on learnings: "When adding a new database type, include enum case, label, default port, and DSN format in buildDsn() method."

app/Services/Backup/DatabaseListService.php (1)

38-41: LGTM!

Clean early-return guard that correctly prevents Redis from reaching the PDO-based listing logic. Returning ['all'] is semantically appropriate since Redis RDB dumps are whole-instance snapshots.

app/Livewire/DatabaseServer/RestoreModal.php (2)

130-134: LGTM — correctly scopes app-database check to MySQL/PostgreSQL only.

Excluding Redis (and SQLite) from the isAppDatabase() check is correct since neither can serve as the Laravel application database.


168-168: Good improvement: direct enum comparison instead of string-based check.

Using DatabaseType::SQLITE enum comparison is more type-safe than the previous ->value string comparison.

database/factories/DatabaseServerFactory.php (1)

52-67: LGTM — Redis factory follows established pattern.

Consistent with the sqlite() factory method and correctly sets Redis-specific defaults (port: 6379, backup_all_databases: true, database_names: null).

resources/views/livewire/database-server/restore-modal.blade.php (1)

1-169: LGTM — template restructuring with no behavioral changes.

Proper use of Mary UI components, Heroicons, Tailwind utilities, and Livewire bindings throughout. Step flow and loading states are well-handled.

app/Services/Backup/Databases/RedisDatabase.php (1)

38-41: Static analysis hint about unused $inputPath is a false positive — parameter is required by the interface contract.

The @SuppressWarnings or a brief PHPDoc note would silence the PHPMD warning, but this is entirely optional.

app/Services/Backup/BackupJobFactory.php (1)

45-50: LGTM — Redis snapshot creation follows the established SQLite pattern.

Single snapshot with databaseName: 'all' correctly represents the whole-instance RDB dump. Clean early return avoids the per-database listing logic.

app/Services/DatabaseConnectionTester.php (1)

252-295: LGTM — Redis connection test is well-structured.

The two-step approach (PING for connectivity, then non-critical INFO for metadata) with graceful degradation on the info step is solid. The explode(':', $line, 2) correctly handles values that may contain colons.

app/Services/Backup/BackupTask.php (2)

23-31: LGTM — Redis injected cleanly via constructor property promotion.

Follows the established pattern for database handler dependencies.


146-151: LGTM — Redis dump command wired correctly into the backup flow.

Redis goes through configureDatabaseInterfacegetDumpCommandLine, consistent with the MySQL/PostgreSQL path.

app/Livewire/Forms/DatabaseServerForm.php (4)

351-357: LGTM — isRedis() follows the established isSqlite() pattern.


525-538: LGTM — Redis validation rules are appropriate.

Username is correctly nullable (Redis 6+ ACL is optional), and SSH/database-selection fields are correctly omitted since Redis doesn't use them.


568-572: LGTM — Redis forced to backup_all_databases: true in both store and update paths.

Consistent enforcement prevents misconfiguration.

Also applies to: 605-609


756-760: LGTM — Redis connection test validates only host and port.

Correctly reflects that Redis authentication is optional and doesn't require a username.

app/Livewire/DatabaseServer/Index.php (1)

104-119: LGTM! Clean implementation of the Redis restore flow. Setting restoreId before the Redis check is correct since the modal template references it for the "View Backup Snapshots" link.

app/Livewire/DatabaseServer/Edit.php (1)

65-70: LGTM! Correctly skips database loading for Redis, consistent with the SQLite pattern — Redis doesn't have named databases to enumerate.

resources/views/livewire/database-server/_form.blade.php (1)

85-98: LGTM! Good UX — making username and password optional for Redis with a clear placeholder hint about ACL-enabled servers.

resources/views/livewire/database-server/index.blade.php (1)

229-263: LGTM! Well-structured Redis restore modal with clear step-by-step instructions. Good use of alert-info for the informational context and the conditional "View Backup Snapshots" link.

tests/Pest.php (1)

114-139: LGTM! Redis dataset entries follow the established patterns and use the correct default port (6379).

tests/Feature/Services/Backup/RestoreTaskTest.php (1)

522-557: LGTM! Clean test that validates the Redis restore guard. Correctly expects UnsupportedDatabaseTypeException without setting up download/restore expectations since the exception fires before those code paths.

tests/Integration/fixtures/redis-init.txt (1)

1-7: LGTM! Good coverage of Redis data types (strings with JSON, hashes, lists) for integration testing.

tests/Feature/DatabaseServer/CreateTest.php (1)

29-32: LGTM! Correctly sets only host and port for Redis, omitting credentials and database names — consistent with the form making those fields optional for Redis.

tests/Feature/DatabaseServer/EditTest.php (2)

27-30: LGTM — Redis branch in server creation is clean.

The Redis path correctly sets host, port, and backup_all_databases without username/password, consistent with how Redis is modeled elsewhere.


59-64: LGTM — Redis edit assertions follow the established pattern.

Asserts host and port are loaded, then updates name and host, matching the structure of the other database type branches.

tests/Feature/DatabaseServer/RestoreModalTest.php (1)

191-200: LGTM — Redis restore test correctly validates the manual instructions modal.

Good separation: Redis is excluded from the parameterized RestoreModal tests and instead gets its own test using Index::class with the confirmRestore action, matching the architectural decision that Redis doesn't support automated restore.

tests/Integration/DatabaseConnectionTesterTest.php (2)

14-46: LGTM — Redis integration into connection success test is well-structured.

Clean separation of concerns: Redis skips both data setup and cleanup, and the ?? null on Line 33 gracefully handles types that don't define a database key.


133-145: LGTM — Redis failure test is a good complement to the success path.

Tests that the connection tester properly reports failure when Redis is unreachable on the wrong port.

tests/Integration/BackupRestoreTest.php (1)

183-209: LGTM — Redis backup workflow test is thorough and well-aligned with the architecture.

Assertions correctly validate the Redis-specific snapshot behavior: database_name is 'all', filename ends with .rdb.gz, and there's no restore step since it's unsupported. The afterEach cleanup safely skips Redis since restoredDatabaseName is never set.

tests/Feature/Services/Backup/BackupTaskTest.php (2)

415-452: LGTM — Redis backup workflow test validates the full command pipeline.

Correctly verifies both the redis-cli --rdb dump command and the gzip compression step, with proper snapshot metadata assertions.


454-482: LGTM — Redis authentication test ensures credentials are properly passed to redis-cli.

Validates the --user and -a flags are present in the correct order, matching the RedisDatabase.buildAuthFlags() implementation.

tests/Support/IntegrationTestHelpers.php (2)

62-69: LGTM — Redis config entry follows the established pattern.

Correctly reads from config('testing.databases.redis.*') with appropriate defaults.


124-141: createRedisDatabaseServer could reuse createDatabaseServer but the dedicated method is justified.

Redis requires backup_all_databases => true and omits database_names, making a separate factory method cleaner than conditionalizing the generic one. Good call.

CLAUDE.md (2)

234-237: Good addition — Architecture notes for non-PDO types.

Documenting that types like Redis must throw in buildDsn()/createPdo() and get special handling in several services is valuable institutional knowledge for future contributors.


206-232: LGTM — Comprehensive checklist for adding new database types.

The updated file list covers all the touchpoints needed for a new database type, which will serve as a good template for future additions.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines +56 to +58
if ($targetServer->database_type === DatabaseType::REDIS) {
throw new UnsupportedDatabaseTypeException('Automated restore is not supported for Redis/Valkey. Please restore manually.');
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Bug: Exception message will be garbled due to constructor formatting.

UnsupportedDatabaseTypeException wraps its argument as "Database type '{$databaseType}' is not supported" (see app/Exceptions/Backup/UnsupportedDatabaseTypeException.php). Passing the full sentence here produces:

Database type 'Automated restore is not supported for Redis/Valkey. Please restore manually.' is not supported

Either pass just the type identifier and let the constructor format it, or use a different exception (e.g., RestoreException) for the custom message.

Proposed fix (option A: use RestoreException with custom message)
-            if ($targetServer->database_type === DatabaseType::REDIS) {
-                throw new UnsupportedDatabaseTypeException('Automated restore is not supported for Redis/Valkey. Please restore manually.');
-            }
+            if ($targetServer->database_type === DatabaseType::REDIS) {
+                throw new RestoreException('Automated restore is not supported for Redis/Valkey. Please restore manually.');
+            }
Proposed fix (option B: pass just the type value)
-                throw new UnsupportedDatabaseTypeException('Automated restore is not supported for Redis/Valkey. Please restore manually.');
+                throw new UnsupportedDatabaseTypeException($targetServer->database_type->value);
🤖 Prompt for AI Agents
In `@app/Services/Backup/RestoreTask.php` around lines 56 - 58, The current throw
in RestoreTask.php uses UnsupportedDatabaseTypeException with a full sentence
which the exception constructor will wrap into "Database type '...' is not
supported" and garble the message; fix by either throwing a RestoreException
with your custom message (e.g., when $targetServer->database_type ===
DatabaseType::REDIS throw new RestoreException('Automated restore is not
supported for Redis/Valkey. Please restore manually.')) or by passing only the
raw type identifier to UnsupportedDatabaseTypeException (e.g., pass
$targetServer->database_type) so the constructor formats the message correctly.

Comment on lines +38 to 41
// SSH tunneling is not supported for local-only database types
if (in_array($databaseType, [DatabaseType::SQLITE, DatabaseType::REDIS]) && $sshConfig !== null) {
return self::error('SSH tunneling is not supported for SQLite databases.');
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Bug: Error message is incorrect when Redis is selected with SSH tunneling.

The condition now includes DatabaseType::REDIS but the error message still references only SQLite. A Redis user encountering this would see a confusing message.

🐛 Proposed fix
         // SSH tunneling is not supported for local-only database types
         if (in_array($databaseType, [DatabaseType::SQLITE, DatabaseType::REDIS]) && $sshConfig !== null) {
-            return self::error('SSH tunneling is not supported for SQLite databases.');
+            return self::error("SSH tunneling is not supported for {$databaseType->label()} databases.");
         }
🤖 Prompt for AI Agents
In `@app/Services/DatabaseConnectionTester.php` around lines 38 - 41, The error
message for the SSH-tunneling guard incorrectly says "SQLite" even when
DatabaseType::REDIS is in the checked list; update the return in the SSH check
inside DatabaseConnectionTester (the block that checks in_array($databaseType,
[DatabaseType::SQLITE, DatabaseType::REDIS]) && $sshConfig !== null) to return a
correct message that references the actual disallowed types (e.g., "SSH
tunneling is not supported for SQLite or Redis databases") or construct the
message dynamically using $databaseType, and keep the call to self::error(...)
unchanged.

Comment on lines +146 to +155
public static function loadRedisTestData(DatabaseServer $server): void
{
$fixtureFile = __DIR__.'/../Integration/fixtures/redis-init.txt';
$host = escapeshellarg($server->host);
$port = escapeshellarg((string) $server->port);

// Flush existing data and load fixture
exec("redis-cli -h {$host} -p {$port} FLUSHALL 2>/dev/null");
exec("redis-cli -h {$host} -p {$port} < {$fixtureFile} 2>/dev/null");
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

loadRedisTestData ignores authentication credentials from config.

If testing.databases.redis.password is configured (e.g., in CI or a secured test environment), these redis-cli commands will fail silently since stderr is suppressed. Consider passing auth flags when a password is set.

🛡️ Suggested fix
 public static function loadRedisTestData(DatabaseServer $server): void
 {
     $fixtureFile = __DIR__.'/../Integration/fixtures/redis-init.txt';
     $host = escapeshellarg($server->host);
     $port = escapeshellarg((string) $server->port);
+    $password = $server->getDecryptedPassword();
+    $authFlags = ! empty($password) ? '-a ' . escapeshellarg($password) . ' --no-auth-warning ' : '';

     // Flush existing data and load fixture
-    exec("redis-cli -h {$host} -p {$port} FLUSHALL 2>/dev/null");
-    exec("redis-cli -h {$host} -p {$port} < {$fixtureFile} 2>/dev/null");
+    exec("redis-cli -h {$host} -p {$port} {$authFlags}FLUSHALL 2>/dev/null");
+    exec("redis-cli -h {$host} -p {$port} {$authFlags}< {$fixtureFile} 2>/dev/null");
 }
🤖 Prompt for AI Agents
In `@tests/Support/IntegrationTestHelpers.php` around lines 146 - 155, The
loadRedisTestData method currently runs redis-cli without authentication and
silences stderr, so authenticated Redis instances fail silently; update
loadRedisTestData to read the test Redis password from configuration
(testing.databases.redis.password), escape it (use escapeshellarg) and, when
non-empty, include the auth flag (e.g. -a <escapedPassword>) in both exec calls,
and stop redirecting stderr to /dev/null (or capture exec return codes) so
failures are visible; refer to loadRedisTestData, $server, $fixtureFile and the
config key testing.databases.redis.password when making the change.

@codecov
Copy link

codecov bot commented Feb 11, 2026

Codecov Report

❌ Patch coverage is 89.43089% with 13 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.12%. Comparing base (bc2e7fc) to head (93a2831).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
app/Livewire/Forms/DatabaseServerForm.php 73.91% 6 Missing ⚠️
app/Services/Backup/Databases/RedisDatabase.php 89.74% 4 Missing ⚠️
app/Enums/DatabaseType.php 80.00% 1 Missing ⚠️
app/Services/Backup/DatabaseListService.php 50.00% 1 Missing ⚠️
app/Services/DatabaseConnectionTester.php 96.66% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main      #97      +/-   ##
============================================
+ Coverage     89.01%   89.12%   +0.10%     
- Complexity     1314     1354      +40     
============================================
  Files           126      127       +1     
  Lines          4935     5049     +114     
============================================
+ Hits           4393     4500     +107     
- Misses          542      549       +7     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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.

1 participant