mirror of
https://github.com/coollabsio/coolify.git
synced 2025-12-28 13:41:51 +00:00
Major architectural improvements:
- Merged download and restore into single atomic operation
- Eliminated separate S3DownloadFinished event (redundant)
- Files now transfer directly: S3 → helper container → server → database container
- Removed download progress tracking in favor of unified restore progress
UI/UX improvements:
- Unified restore method selection with visual cards
- Consistent "File Information" display between local and S3 restore
- Single slide-over for all restore operations (removed separate S3 download monitor)
- Better visual feedback with loading states
Security enhancements:
- Added isSafeTmpPath() helper for path traversal protection
- URL decode validation to catch encoded attacks
- Canonical path resolution to prevent symlink attacks
- Comprehensive path validation in all cleanup events
Cleanup improvements:
- S3RestoreJobFinished now handles all cleanup (helper container + all temp files)
- RestoreJobFinished uses new isSafeTmpPath() validation
- CoolifyTask dispatches cleanup events even on job failure
- All cleanup uses non-throwing commands (2>/dev/null || true)
Other improvements:
- S3 storage policy authorization on Show component
- Storage Form properly syncs is_usable state after test
- Removed debug code and improved error handling
- Better command organization and documentation
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
85 lines
3.2 KiB
PHP
85 lines
3.2 KiB
PHP
<?php
|
|
|
|
use App\Jobs\CoolifyTask;
|
|
|
|
it('CoolifyTask has failed method that handles cleanup', function () {
|
|
$reflection = new ReflectionClass(CoolifyTask::class);
|
|
|
|
// Verify failed method exists
|
|
expect($reflection->hasMethod('failed'))->toBeTrue();
|
|
|
|
// Get the failed method
|
|
$failedMethod = $reflection->getMethod('failed');
|
|
|
|
// Read the method source to verify it dispatches events
|
|
$filename = $reflection->getFileName();
|
|
$startLine = $failedMethod->getStartLine();
|
|
$endLine = $failedMethod->getEndLine();
|
|
|
|
$source = file($filename);
|
|
$methodSource = implode('', array_slice($source, $startLine - 1, $endLine - $startLine + 1));
|
|
|
|
// Verify the implementation contains event dispatch logic
|
|
expect($methodSource)
|
|
->toContain('call_event_on_finish')
|
|
->and($methodSource)->toContain('event(new $eventClass')
|
|
->and($methodSource)->toContain('call_event_data')
|
|
->and($methodSource)->toContain('Log::info');
|
|
});
|
|
|
|
it('CoolifyTask failed method updates activity status to ERROR', function () {
|
|
$reflection = new ReflectionClass(CoolifyTask::class);
|
|
$failedMethod = $reflection->getMethod('failed');
|
|
|
|
// Read the method source
|
|
$filename = $reflection->getFileName();
|
|
$startLine = $failedMethod->getStartLine();
|
|
$endLine = $failedMethod->getEndLine();
|
|
|
|
$source = file($filename);
|
|
$methodSource = implode('', array_slice($source, $startLine - 1, $endLine - $startLine + 1));
|
|
|
|
// Verify activity status is set to ERROR
|
|
expect($methodSource)
|
|
->toContain("'status' => ProcessStatus::ERROR->value")
|
|
->and($methodSource)->toContain("'error' =>")
|
|
->and($methodSource)->toContain("'failed_at' =>");
|
|
});
|
|
|
|
it('CoolifyTask failed method has proper error handling for event dispatch', function () {
|
|
$reflection = new ReflectionClass(CoolifyTask::class);
|
|
$failedMethod = $reflection->getMethod('failed');
|
|
|
|
// Read the method source
|
|
$filename = $reflection->getFileName();
|
|
$startLine = $failedMethod->getStartLine();
|
|
$endLine = $failedMethod->getEndLine();
|
|
|
|
$source = file($filename);
|
|
$methodSource = implode('', array_slice($source, $startLine - 1, $endLine - $startLine + 1));
|
|
|
|
// Verify try-catch around event dispatch
|
|
expect($methodSource)
|
|
->toContain('try {')
|
|
->and($methodSource)->toContain('} catch (\Throwable $e) {')
|
|
->and($methodSource)->toContain("Log::error('Error dispatching cleanup event");
|
|
});
|
|
|
|
it('CoolifyTask constructor stores call_event_on_finish and call_event_data', function () {
|
|
$reflection = new ReflectionClass(CoolifyTask::class);
|
|
$constructor = $reflection->getConstructor();
|
|
|
|
// Get constructor parameters
|
|
$parameters = $constructor->getParameters();
|
|
$paramNames = array_map(fn ($p) => $p->getName(), $parameters);
|
|
|
|
// Verify both parameters exist
|
|
expect($paramNames)
|
|
->toContain('call_event_on_finish')
|
|
->and($paramNames)->toContain('call_event_data');
|
|
|
|
// Verify they are public properties (constructor property promotion)
|
|
expect($reflection->hasProperty('call_event_on_finish'))->toBeTrue();
|
|
expect($reflection->hasProperty('call_event_data'))->toBeTrue();
|
|
});
|