Automated PR created by Codex automation. Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #472
178 lines
6.0 KiB
PHP
178 lines
6.0 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Filament\Resources\BackupScheduleResource;
|
|
use App\Filament\Resources\ProviderConnectionResource;
|
|
use App\Filament\Resources\RestoreRunResource;
|
|
use App\Models\BackupSchedule;
|
|
use App\Models\BackupSet;
|
|
use App\Models\ManagedEnvironment;
|
|
use App\Models\OperationRun;
|
|
use App\Models\ProviderConnection;
|
|
use App\Models\RestoreRun;
|
|
use App\Models\User;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
|
|
pest()->browser()->timeout(60_000);
|
|
|
|
uses(RefreshDatabase::class);
|
|
|
|
function spec401BrowserLoginUrl(User $user, ManagedEnvironment $tenant, string $redirect): string
|
|
{
|
|
return route('admin.local.smoke-login', [
|
|
'email' => $user->email,
|
|
'tenant' => $tenant->external_id,
|
|
'workspace' => $tenant->workspace->slug,
|
|
'redirect' => $redirect,
|
|
]);
|
|
}
|
|
|
|
function spec401BrowserPath(string $url): string
|
|
{
|
|
$parts = parse_url($url);
|
|
|
|
return ($parts['path'] ?? '/admin').(isset($parts['query']) ? '?'.$parts['query'] : '');
|
|
}
|
|
|
|
function spec401BrowserBackupSchedule(ManagedEnvironment $tenant, array $attributes = []): BackupSchedule
|
|
{
|
|
return BackupSchedule::query()->create(array_merge([
|
|
'managed_environment_id' => (int) $tenant->getKey(),
|
|
'name' => 'Spec 401 Browser Backup Schedule',
|
|
'is_enabled' => true,
|
|
'timezone' => 'UTC',
|
|
'frequency' => 'daily',
|
|
'time_of_day' => '01:00:00',
|
|
'days_of_week' => null,
|
|
'policy_types' => ['deviceConfiguration'],
|
|
'include_foundations' => true,
|
|
'retention_keep_last' => 30,
|
|
], $attributes));
|
|
}
|
|
|
|
function spec401BrowserClickVisible($page, string $label): void
|
|
{
|
|
$encodedLabel = json_encode($label, JSON_THROW_ON_ERROR);
|
|
|
|
$clicked = $page->script(<<<JS
|
|
(() => {
|
|
const label = {$encodedLabel};
|
|
const candidates = Array.from(document.querySelectorAll('button, a, [role="button"]'));
|
|
const target = candidates.find((element) => {
|
|
const style = window.getComputedStyle(element);
|
|
const text = [
|
|
element.textContent || '',
|
|
element.getAttribute('aria-label') || '',
|
|
element.getAttribute('title') || '',
|
|
].join(' ').replace(/\\s+/g, ' ').trim();
|
|
|
|
return text.includes(label)
|
|
&& style.display !== 'none'
|
|
&& style.visibility !== 'hidden'
|
|
&& ! element.hidden
|
|
&& Boolean(element.offsetWidth || element.offsetHeight || element.getClientRects().length);
|
|
});
|
|
|
|
target?.scrollIntoView({ block: 'center', inline: 'center' });
|
|
target?.click();
|
|
|
|
return Boolean(target);
|
|
})()
|
|
JS);
|
|
|
|
expect($clicked)->toBeTrue();
|
|
}
|
|
|
|
it('smokes high-risk restore backup provider and unauthorized guards', function (): void {
|
|
bindFailHardGraphClient();
|
|
|
|
[$owner, $tenant] = createUserWithTenant(role: 'owner', workspaceRole: 'owner');
|
|
|
|
$backupSchedule = spec401BrowserBackupSchedule($tenant);
|
|
|
|
$backupSet = BackupSet::factory()->create([
|
|
'managed_environment_id' => (int) $tenant->getKey(),
|
|
'name' => 'Spec 401 Browser Restore Backup',
|
|
'status' => 'completed',
|
|
'item_count' => 1,
|
|
]);
|
|
|
|
$restoreRun = RestoreRun::factory()->for($tenant, 'tenant')->for($backupSet)->create([
|
|
'status' => 'draft',
|
|
'is_dry_run' => true,
|
|
'results' => [],
|
|
'metadata' => [],
|
|
'started_at' => null,
|
|
'completed_at' => null,
|
|
]);
|
|
|
|
$providerConnection = ProviderConnection::factory()
|
|
->platform()
|
|
->verifiedHealthy()
|
|
->create([
|
|
'managed_environment_id' => (int) $tenant->getKey(),
|
|
'workspace_id' => (int) $tenant->workspace_id,
|
|
'provider' => 'microsoft',
|
|
'is_default' => true,
|
|
'display_name' => 'Spec 401 Browser Expired Connection',
|
|
'last_health_check_at' => now()->subDays(31),
|
|
]);
|
|
|
|
$backupPath = spec401BrowserPath(BackupScheduleResource::getUrl('index', panel: 'admin', tenant: $tenant));
|
|
$restorePath = spec401BrowserPath(RestoreRunResource::getUrl('view', ['record' => $restoreRun], panel: 'admin', tenant: $tenant));
|
|
$providerPath = spec401BrowserPath(ProviderConnectionResource::getUrl('view', [
|
|
'record' => $providerConnection,
|
|
'environment_id' => (int) $tenant->getKey(),
|
|
], panel: 'admin'));
|
|
|
|
$page = visit(spec401BrowserLoginUrl($owner, $tenant, $backupPath))
|
|
->resize(1440, 1000)
|
|
->waitForText($backupSchedule->name)
|
|
->assertNoJavaScriptErrors()
|
|
->assertNoConsoleLogs();
|
|
|
|
$page
|
|
->click('[aria-label="More"]')
|
|
->wait(1)
|
|
->assertSee('Run now');
|
|
|
|
spec401BrowserClickVisible($page, 'Run now');
|
|
|
|
$page
|
|
->waitForText('Run backup schedule now?')
|
|
->assertSee('This queues a backup run for the selected schedule and records an operation run.')
|
|
->assertNoJavaScriptErrors()
|
|
->assertNoConsoleLogs();
|
|
|
|
spec401BrowserClickVisible($page, 'Cancel');
|
|
|
|
expect(OperationRun::query()
|
|
->where('managed_environment_id', (int) $tenant->getKey())
|
|
->where('type', 'backup.schedule.execute')
|
|
->count())->toBe(0);
|
|
|
|
visit($restorePath)
|
|
->resize(1440, 1000)
|
|
->waitForText('Was this restore executed safely, and is recovery proof available?')
|
|
->assertSee('Not configured')
|
|
->assertSee('View technical run details')
|
|
->assertNoJavaScriptErrors()
|
|
->assertNoConsoleLogs();
|
|
|
|
visit($providerPath)
|
|
->resize(1440, 1000)
|
|
->waitForText('Verification expired')
|
|
->assertDontSee('Healthy')
|
|
->assertNoJavaScriptErrors()
|
|
->assertNoConsoleLogs();
|
|
|
|
[$otherUser, $otherTenant] = createUserWithTenant(role: 'owner', workspaceRole: 'owner');
|
|
|
|
visit(spec401BrowserLoginUrl($otherUser, $otherTenant, $backupPath))
|
|
->resize(1440, 1000)
|
|
->assertScript('document.body.innerText.includes("404") || document.body.innerText.includes("Not Found") || document.body.innerText.includes("No access")', true)
|
|
->assertNoJavaScriptErrors()
|
|
->assertNoConsoleLogs();
|
|
});
|