mirror of
https://github.com/tiennm99/coolify.git
synced 2026-04-17 19:21:36 +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>
54 lines
1.6 KiB
PHP
54 lines
1.6 KiB
PHP
<?php
|
|
|
|
use App\Models\S3Storage;
|
|
|
|
test('S3Storage model has correct cast definitions', function () {
|
|
$s3Storage = new S3Storage;
|
|
$casts = $s3Storage->getCasts();
|
|
|
|
expect($casts['is_usable'])->toBe('boolean');
|
|
expect($casts['key'])->toBe('encrypted');
|
|
expect($casts['secret'])->toBe('encrypted');
|
|
});
|
|
|
|
test('S3Storage isUsable method returns is_usable attribute value', function () {
|
|
$s3Storage = new S3Storage;
|
|
|
|
// Set the attribute directly to avoid encryption
|
|
$s3Storage->setRawAttributes(['is_usable' => true]);
|
|
expect($s3Storage->isUsable())->toBeTrue();
|
|
|
|
$s3Storage->setRawAttributes(['is_usable' => false]);
|
|
expect($s3Storage->isUsable())->toBeFalse();
|
|
|
|
$s3Storage->setRawAttributes(['is_usable' => null]);
|
|
expect($s3Storage->isUsable())->toBeNull();
|
|
});
|
|
|
|
test('S3Storage awsUrl method constructs correct URL format', function () {
|
|
$s3Storage = new S3Storage;
|
|
|
|
// Set attributes without triggering encryption
|
|
$s3Storage->setRawAttributes([
|
|
'endpoint' => 'https://s3.amazonaws.com',
|
|
'bucket' => 'test-bucket',
|
|
]);
|
|
|
|
expect($s3Storage->awsUrl())->toBe('https://s3.amazonaws.com/test-bucket');
|
|
|
|
// Test with custom endpoint
|
|
$s3Storage->setRawAttributes([
|
|
'endpoint' => 'https://minio.example.com:9000',
|
|
'bucket' => 'backups',
|
|
]);
|
|
|
|
expect($s3Storage->awsUrl())->toBe('https://minio.example.com:9000/backups');
|
|
});
|
|
|
|
test('S3Storage model is guarded correctly', function () {
|
|
$s3Storage = new S3Storage;
|
|
|
|
// The model should have $guarded = [] which means everything is fillable
|
|
expect($s3Storage->getGuarded())->toBe([]);
|
|
});
|