feat: add BlogBodySanitizer for HTML sanitization on article save
- Implemented BlogBodySanitizer to clean HTML content before saving articles, ensuring security against XSS attacks. - Added tests for BlogBodySanitizer to verify that unsafe tags and attributes are stripped from the content. - Introduced ApiLeastPrivilegeTest to ensure that unauthorized users cannot access sensitive API routes, maintaining strict access control.
This commit is contained in:
@@ -415,4 +415,65 @@ class SecretaryResourceEnforcementTest extends ApiTestCase
|
||||
$this->assertSame(403, $this->responseCode());
|
||||
}
|
||||
|
||||
// ── پروتکل درمان ─────────────────────────────────────────────────────────
|
||||
//
|
||||
// آدیت ۲۰۲۶-۰۸-۰۷: TreatmentProtocolController هیچ گِیت مجوزی نداشت و فقط
|
||||
// مالکیتِ tenant را میسنجید، پس منشیِ `services:false` میتوانست پروتکل را
|
||||
// بخواند، بازنویسی کند و حذف کند. پروتکل خاصیتِ سرویس است، پس مجوزش `services`
|
||||
// است. uuidِ ناموجود عمدی است: گیت پیش از واکشیِ سرویس اجرا میشود، پس ۴۰۳
|
||||
// در برابر ۴۰۴ دقیقاً همان چیزی را جدا میکند که این تستها میسنجند.
|
||||
|
||||
private const ABSENT_SERVICE = '00000000-0000-0000-0000-000000000000';
|
||||
|
||||
public function testTreatmentProtocolReadDeniedByDefault(): void
|
||||
{
|
||||
// DEFAULT_PERMISSIONS: services.* = false
|
||||
[$secretary] = $this->makeClinicSecretary();
|
||||
$this->em->flush();
|
||||
|
||||
$this->authJson('GET', '/api/v1/service-item/' . self::ABSENT_SERVICE . '/treatment-protocol', $secretary);
|
||||
$this->assertSame(403, $this->responseCode());
|
||||
}
|
||||
|
||||
public function testTreatmentProtocolReadAllowedWhenServicesGranted(): void
|
||||
{
|
||||
[$secretary, $rel] = $this->makeClinicSecretary();
|
||||
$rel->mergePermissions(['resources' => ['services' => ['view' => true]]]);
|
||||
$this->em->flush();
|
||||
|
||||
// گیت عبور میکند و به «سرویس یافت نشد» میرسد — نه ۴۰۳.
|
||||
$this->authJson('GET', '/api/v1/service-item/' . self::ABSENT_SERVICE . '/treatment-protocol', $secretary);
|
||||
$this->assertSame(404, $this->responseCode());
|
||||
}
|
||||
|
||||
public function testTreatmentProtocolWriteNeedsServicesUpdate(): void
|
||||
{
|
||||
[$secretary, $rel] = $this->makeClinicSecretary();
|
||||
$rel->mergePermissions(['resources' => ['services' => ['view' => true, 'update' => false]]]);
|
||||
$this->em->flush();
|
||||
|
||||
$path = '/api/v1/service-item/' . self::ABSENT_SERVICE . '/treatment-protocol';
|
||||
|
||||
// خواندن مجاز است…
|
||||
$this->authJson('GET', $path, $secretary);
|
||||
$this->assertSame(404, $this->responseCode());
|
||||
|
||||
// …ولی بازنویسی و خاموشکردنِ سوییچ نه.
|
||||
$this->authJson('PUT', $path, $secretary, ['steps' => []]);
|
||||
$this->assertSame(403, $this->responseCode(), 'بازنویسی پروتکل باید services.update بخواهد');
|
||||
|
||||
$this->authJson('DELETE', $path, $secretary);
|
||||
$this->assertSame(403, $this->responseCode(), 'حذف پروتکل باید services.update بخواهد');
|
||||
}
|
||||
|
||||
public function testTreatmentProtocolWriteAllowedWhenServicesUpdateGranted(): void
|
||||
{
|
||||
[$secretary, $rel] = $this->makeClinicSecretary();
|
||||
$rel->mergePermissions(['resources' => ['services' => ['view' => true, 'update' => true]]]);
|
||||
$this->em->flush();
|
||||
|
||||
$this->authJson('DELETE', '/api/v1/service-item/' . self::ABSENT_SERVICE . '/treatment-protocol', $secretary);
|
||||
$this->assertSame(404, $this->responseCode());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user