fix gitlab tests
This commit is contained in:
@@ -12,9 +12,9 @@ use Tests\TestCase;
|
||||
*/
|
||||
class ApiAcademicAttendanceFullSurfaceContractTest extends TestCase
|
||||
{
|
||||
use AssertsE2EApiResponses;
|
||||
use RefreshDatabase;
|
||||
use SeedsE2ETestFixtures;
|
||||
use AssertsE2EApiResponses;
|
||||
|
||||
public function test_academic_attendance_and_grading_surfaces_have_controlled_contracts(): void
|
||||
{
|
||||
@@ -24,21 +24,21 @@ class ApiAcademicAttendanceFullSurfaceContractTest extends TestCase
|
||||
|
||||
foreach ($this->teacherGetEndpoints($world) as $uri) {
|
||||
$response = $this->getJson($uri);
|
||||
$this->assertNoServerError($response, 'Teacher GET '.$uri);
|
||||
$this->assertStatusIn($response, [200, 204, 302, 400, 401, 403, 404, 405, 409, 419, 422], 'Teacher GET '.$uri);
|
||||
$this->assertNoServerError($response, 'Teacher GET ' . $uri);
|
||||
$this->assertStatusIn($response, [200, 204, 302, 400, 401, 403, 404, 405, 409, 419, 422], 'Teacher GET ' . $uri);
|
||||
}
|
||||
|
||||
foreach ($this->teacherMutationEndpoints($world) as [$method, $uri, $payload]) {
|
||||
$response = $this->json($method, $uri, $payload);
|
||||
$this->assertNoServerError($response, 'Teacher '.$method.' '.$uri);
|
||||
$this->assertStatusIn($response, [200, 201, 202, 204, 302, 400, 401, 403, 404, 405, 409, 419, 422], 'Teacher '.$method.' '.$uri);
|
||||
$this->assertNoServerError($response, 'Teacher ' . $method . ' ' . $uri);
|
||||
$this->assertStatusIn($response, [200, 201, 202, 204, 302, 400, 401, 403, 404, 405, 409, 419, 422], 'Teacher ' . $method . ' ' . $uri);
|
||||
}
|
||||
|
||||
$this->actingAsApiAdministrator();
|
||||
foreach ($this->adminAcademicEndpoints($world) as [$method, $uri, $payload]) {
|
||||
$response = $this->json($method, $uri, $payload);
|
||||
$this->assertNoServerError($response, 'Admin academic '.$method.' '.$uri);
|
||||
$this->assertStatusIn($response, [200, 201, 202, 204, 302, 400, 401, 403, 404, 405, 409, 419, 422], 'Admin academic '.$method.' '.$uri);
|
||||
$this->assertNoServerError($response, 'Admin academic ' . $method . ' ' . $uri);
|
||||
$this->assertStatusIn($response, [200, 201, 202, 204, 302, 400, 401, 403, 404, 405, 409, 419, 422], 'Admin academic ' . $method . ' ' . $uri);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,35 +49,35 @@ class ApiAcademicAttendanceFullSurfaceContractTest extends TestCase
|
||||
$studentId = (int) $world['student_id'];
|
||||
|
||||
return [
|
||||
'/api/v1/teachers/classes?class_section_id='.$classSectionId,
|
||||
'/api/v1/teacher/class-view?class_section_id='.$classSectionId,
|
||||
'/api/v1/teachers/classes?class_section_id=' . $classSectionId,
|
||||
'/api/v1/teacher/class-view?class_section_id=' . $classSectionId,
|
||||
'/api/v1/teacher/no-classes',
|
||||
'/api/v1/teacher/select-semester',
|
||||
'/api/v1/teacher/homework-list?class_section_id='.$classSectionId,
|
||||
'/api/v1/teacher/add-homework?class_section_id='.$classSectionId,
|
||||
'/api/v1/teacher/add-quiz?class_section_id='.$classSectionId,
|
||||
'/api/v1/teacher/add-quiz-column-form?class_section_id='.$classSectionId,
|
||||
'/api/v1/teacher/add-midterm-exam?class_section_id='.$classSectionId,
|
||||
'/api/v1/teacher/add-final-exam?class_section_id='.$classSectionId,
|
||||
'/api/v1/teacher/add-participation?class_section_id='.$classSectionId,
|
||||
'/api/v1/teacher/add-project?class_section_id='.$classSectionId,
|
||||
'/api/v1/teacher/homework-list?class_section_id=' . $classSectionId,
|
||||
'/api/v1/teacher/add-homework?class_section_id=' . $classSectionId,
|
||||
'/api/v1/teacher/add-quiz?class_section_id=' . $classSectionId,
|
||||
'/api/v1/teacher/add-quiz-column-form?class_section_id=' . $classSectionId,
|
||||
'/api/v1/teacher/add-midterm-exam?class_section_id=' . $classSectionId,
|
||||
'/api/v1/teacher/add-final-exam?class_section_id=' . $classSectionId,
|
||||
'/api/v1/teacher/add-participation?class_section_id=' . $classSectionId,
|
||||
'/api/v1/teacher/add-project?class_section_id=' . $classSectionId,
|
||||
'/api/v1/teacher/teacher-assignment',
|
||||
'/api/v1/teacher/exam-drafts',
|
||||
'/api/v1/teacher/drafts',
|
||||
'/api/v1/teacher/inventory/books/distribute',
|
||||
'/api/v1/teacher/print-requests/context',
|
||||
'/api/v1/teacher/absence-vacation',
|
||||
'/api/v1/teacher/showupdate-attendance?class_section_id='.$classSectionId,
|
||||
'/api/v1/teacher/showupdate_attendance?class_section_id='.$classSectionId,
|
||||
'/api/v1/teacher/scores?class_section_id='.$classSectionId,
|
||||
'/api/v1/teacher/showupdate-attendance?class_section_id=' . $classSectionId,
|
||||
'/api/v1/teacher/showupdate_attendance?class_section_id=' . $classSectionId,
|
||||
'/api/v1/teacher/scores?class_section_id=' . $classSectionId,
|
||||
'/api/v1/teacher/calendar',
|
||||
'/api/v1/teacher/class-progress-submit?class_section_id='.$classSectionId,
|
||||
'/api/v1/teacher/class-progress-history?class_section_id='.$classSectionId,
|
||||
'/api/v1/teacher/class-progress-view?class_section_id='.$classSectionId,
|
||||
'/api/v1/teacher/class-progress-submit?class_section_id=' . $classSectionId,
|
||||
'/api/v1/teacher/class-progress-history?class_section_id=' . $classSectionId,
|
||||
'/api/v1/teacher/class-progress-view?class_section_id=' . $classSectionId,
|
||||
'/api/v1/teacher/competition-scores',
|
||||
'/api/v1/attendance/teacher/grid?class_section_id='.$classSectionId,
|
||||
'/api/v1/attendance/teacher/form?class_section_id='.$classSectionId,
|
||||
'/api/v1/attendance/admin/daily?date=2025-10-05&class_section_id='.$classSectionId,
|
||||
'/api/v1/attendance/teacher/grid?class_section_id=' . $classSectionId,
|
||||
'/api/v1/attendance/teacher/form?class_section_id=' . $classSectionId,
|
||||
'/api/v1/attendance/admin/daily?date=2025-10-05&class_section_id=' . $classSectionId,
|
||||
'/api/v1/attendance/staff/month?month=2025-10',
|
||||
'/api/v1/attendance/staff/admins',
|
||||
'/api/v1/attendance/late-slip-logs',
|
||||
@@ -87,7 +87,7 @@ class ApiAcademicAttendanceFullSurfaceContractTest extends TestCase
|
||||
'/api/v1/attendance/management/dashboard',
|
||||
'/api/v1/attendance-tracking/pending-violations',
|
||||
'/api/v1/attendance-tracking/notified-violations',
|
||||
'/api/v1/attendance-tracking/student-case/'.$studentId,
|
||||
'/api/v1/attendance-tracking/student-case/' . $studentId,
|
||||
'/api/v1/attendance-tracking/compose',
|
||||
'/api/v1/attendance-tracking/parents-info',
|
||||
'/api/v1/attendance-comment-templates',
|
||||
@@ -96,15 +96,15 @@ class ApiAcademicAttendanceFullSurfaceContractTest extends TestCase
|
||||
'/api/v1/attendance-templates',
|
||||
'/api/v1/assignments',
|
||||
'/api/v1/assignments/class-assignment-data',
|
||||
'/api/v1/scores/overview?class_section_id='.$classSectionId,
|
||||
'/api/v1/scores/homework?class_section_id='.$classSectionId,
|
||||
'/api/v1/scores/quiz?class_section_id='.$classSectionId,
|
||||
'/api/v1/scores/project?class_section_id='.$classSectionId,
|
||||
'/api/v1/scores/midterm?class_section_id='.$classSectionId,
|
||||
'/api/v1/scores/final?class_section_id='.$classSectionId,
|
||||
'/api/v1/scores/participation?class_section_id='.$classSectionId,
|
||||
'/api/v1/grading/homework-tracking?class_section_id='.$classSectionId,
|
||||
'/api/v1/reports/report-cards/meta?class_section_id='.$classSectionId,
|
||||
'/api/v1/scores/overview?class_section_id=' . $classSectionId,
|
||||
'/api/v1/scores/homework?class_section_id=' . $classSectionId,
|
||||
'/api/v1/scores/quiz?class_section_id=' . $classSectionId,
|
||||
'/api/v1/scores/project?class_section_id=' . $classSectionId,
|
||||
'/api/v1/scores/midterm?class_section_id=' . $classSectionId,
|
||||
'/api/v1/scores/final?class_section_id=' . $classSectionId,
|
||||
'/api/v1/scores/participation?class_section_id=' . $classSectionId,
|
||||
'/api/v1/grading/homework-tracking?class_section_id=' . $classSectionId,
|
||||
'/api/v1/reports/report-cards/meta?class_section_id=' . $classSectionId,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -159,8 +159,8 @@ class ApiAcademicAttendanceFullSurfaceContractTest extends TestCase
|
||||
private function adminAcademicEndpoints(array $world): array
|
||||
{
|
||||
return [
|
||||
['GET', '/api/v1/reports/report-cards?student_id='.$world['student_id'], []],
|
||||
['GET', '/api/v1/reports/stickers?student_id='.$world['student_id'], []],
|
||||
['GET', '/api/v1/reports/report-cards?student_id=' . $world['student_id'], []],
|
||||
['GET', '/api/v1/reports/stickers?student_id=' . $world['student_id'], []],
|
||||
['GET', '/api/v1/badges/form-options', []],
|
||||
['POST', '/api/v1/print-requests', ['title' => 'Contract Probe', 'copies' => 1, 'needed_by' => '2025-10-12']],
|
||||
['GET', '/api/v1/print-requests/admin', []],
|
||||
|
||||
@@ -24,7 +24,7 @@ class ApiAccountStatusLifecycleContractTest extends FullSurfaceE2EContractCase
|
||||
$response = $this->requestAs($actor, 'GET', $uri);
|
||||
|
||||
$this->assertControlled($response, 'GET', $uri);
|
||||
$this->assertNoServerError($response, 'account status '.$status.' at GET '.$uri);
|
||||
$this->assertNoServerError($response, 'account status ' . $status . ' at GET ' . $uri);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,9 +12,9 @@ use Tests\TestCase;
|
||||
*/
|
||||
class ApiAdminOperationsFullSurfaceContractTest extends TestCase
|
||||
{
|
||||
use AssertsE2EApiResponses;
|
||||
use RefreshDatabase;
|
||||
use SeedsE2ETestFixtures;
|
||||
use AssertsE2EApiResponses;
|
||||
|
||||
public function test_administrator_operational_surface_responds_with_controlled_contracts(): void
|
||||
{
|
||||
@@ -24,19 +24,19 @@ class ApiAdminOperationsFullSurfaceContractTest extends TestCase
|
||||
|
||||
foreach ($this->adminGetEndpoints($world) as $uri) {
|
||||
$response = $this->getJson($uri);
|
||||
$this->assertNoServerError($response, 'Admin GET '.$uri);
|
||||
$this->assertStatusIn($response, [200, 204, 302, 400, 401, 403, 404, 405, 409, 419, 422], 'Admin GET '.$uri);
|
||||
$this->assertNoServerError($response, 'Admin GET ' . $uri);
|
||||
$this->assertStatusIn($response, [200, 204, 302, 400, 401, 403, 404, 405, 409, 419, 422], 'Admin GET ' . $uri);
|
||||
}
|
||||
|
||||
foreach ($this->adminMutationEndpoints($world, $admin->id) as [$method, $uri, $payload]) {
|
||||
$response = $this->json($method, $uri, $payload);
|
||||
$this->assertNoServerError($response, 'Admin '.$method.' '.$uri);
|
||||
$this->assertStatusIn($response, [200, 201, 202, 204, 302, 400, 401, 403, 404, 405, 409, 419, 422], 'Admin '.$method.' '.$uri);
|
||||
$this->assertNoServerError($response, 'Admin ' . $method . ' ' . $uri);
|
||||
$this->assertStatusIn($response, [200, 201, 202, 204, 302, 400, 401, 403, 404, 405, 409, 419, 422], 'Admin ' . $method . ' ' . $uri);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $world
|
||||
* @param array<string, mixed> $world
|
||||
* @return list<string>
|
||||
*/
|
||||
private function adminGetEndpoints(array $world): array
|
||||
@@ -76,7 +76,7 @@ class ApiAdminOperationsFullSurfaceContractTest extends TestCase
|
||||
'/api/v1/administrator/flags/students/1',
|
||||
'/api/v1/administrator/flags/processed',
|
||||
'/api/v1/administrator/flags/analysis',
|
||||
'/api/v1/administrator/grading/homework-tracking?class_section_id='.$classSectionId,
|
||||
'/api/v1/administrator/grading/homework-tracking?class_section_id=' . $classSectionId,
|
||||
'/api/v1/administrator/expenses',
|
||||
'/api/v1/administrator/expenses/options',
|
||||
'/api/v1/administrator/expenses/1',
|
||||
@@ -110,13 +110,13 @@ class ApiAdminOperationsFullSurfaceContractTest extends TestCase
|
||||
'/api/v1/class-sections',
|
||||
'/api/v1/classes',
|
||||
'/api/v1/users',
|
||||
'/api/v1/users/'.$world['parent_id'],
|
||||
'/api/v1/students/'.$studentId,
|
||||
'/api/v1/users/' . $world['parent_id'],
|
||||
'/api/v1/students/' . $studentId,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $world
|
||||
* @param array<string, mixed> $world
|
||||
* @return list<array{0: string, 1: string, 2: array<string, mixed>}>
|
||||
*/
|
||||
private function adminMutationEndpoints(array $world, int $adminId): array
|
||||
|
||||
@@ -43,7 +43,7 @@ class ApiAttachmentUploadContentSafetyContractTest extends FullSurfaceE2EContrac
|
||||
continue;
|
||||
}
|
||||
|
||||
$path = $this->materializePath($route->uri()).'?filename=../../.env&path=../../storage/logs/laravel.log';
|
||||
$path = $this->materializePath($route->uri()) . '?filename=../../.env&path=../../storage/logs/laravel.log';
|
||||
$response = $this->actingAs($this->actorFor($route->uri()), 'api')->getJson($path);
|
||||
|
||||
$this->assertStatusIn($response, [200, 204, 400, 401, 403, 404, 409, 422], "GET {$route->uri()} path traversal probe");
|
||||
|
||||
+2
-2
@@ -21,8 +21,8 @@ class ApiAuditLogAndAdministrativeTraceabilityContractTest extends FullSurfaceE2
|
||||
|
||||
$this->assertNoServerError($response, "$method $uri admin mutation traceability");
|
||||
$this->assertControlled($response, $method, $uri);
|
||||
$this->assertStringNotContainsStringIgnoringCase('audit_log_id', $response->getContent(), $uri.' should not leak raw internal audit identifiers by accident.');
|
||||
$this->assertStringNotContainsStringIgnoringCase('stack_trace', $response->getContent(), $uri.' should not leak stack traces in mutation responses.');
|
||||
$this->assertStringNotContainsStringIgnoringCase('audit_log_id', $response->getContent(), $uri . ' should not leak raw internal audit identifiers by accident.');
|
||||
$this->assertStringNotContainsStringIgnoringCase('stack_trace', $response->getContent(), $uri . ' should not leak stack traces in mutation responses.');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,12 +20,12 @@ class ApiAuthenticationLifecycleDepthContractTest extends FullSurfaceE2EContract
|
||||
'password' => 'password',
|
||||
]);
|
||||
|
||||
$this->assertNoServerError($response, 'valid login at '.$path);
|
||||
$this->assertNoServerError($response, 'valid login at ' . $path);
|
||||
|
||||
if ($response->getStatusCode() >= 200 && $response->getStatusCode() < 300) {
|
||||
$this->assertTrue(
|
||||
$response->json('token') !== null || $response->json('access_token') !== null || $response->json('user') !== null,
|
||||
$path.' must return a usable login contract, not a mystery envelope.'
|
||||
$path . ' must return a usable login contract, not a mystery envelope.'
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -36,18 +36,18 @@ class ApiAuthenticationLifecycleDepthContractTest extends FullSurfaceE2EContract
|
||||
'password' => 'definitely-wrong-password',
|
||||
]);
|
||||
|
||||
$this->assertStatusIn($response, [400, 401, 403, 419, 422], 'invalid login at '.$path);
|
||||
$this->assertNoServerError($response, 'invalid login at '.$path);
|
||||
$this->assertStatusIn($response, [400, 401, 403, 419, 422], 'invalid login at ' . $path);
|
||||
$this->assertNoServerError($response, 'invalid login at ' . $path);
|
||||
}
|
||||
|
||||
foreach (['/api/v1/auth/me', '/api/v1/me', '/api/user'] as $path) {
|
||||
$response = $this->actingAs($this->admin, 'api')->getJson($path);
|
||||
$this->assertNoServerError($response, 'authenticated identity lookup at '.$path);
|
||||
$this->assertNoServerError($response, 'authenticated identity lookup at ' . $path);
|
||||
|
||||
if ($response->getStatusCode() === 200) {
|
||||
$this->assertTrue(
|
||||
$response->json('user') !== null || $response->json('id') !== null || $response->json('data') !== null,
|
||||
$path.' must expose a stable identity payload.'
|
||||
$path . ' must expose a stable identity payload.'
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -56,10 +56,10 @@ class ApiAuthenticationLifecycleDepthContractTest extends FullSurfaceE2EContract
|
||||
$first = $this->actingAs($this->admin, 'api')->postJson($path);
|
||||
$second = $this->actingAs($this->admin, 'api')->postJson($path);
|
||||
|
||||
$this->assertNoServerError($first, 'first logout at '.$path);
|
||||
$this->assertNoServerError($second, 'repeat logout at '.$path);
|
||||
$this->assertStatusIn($first, [200, 202, 204, 302, 401, 404, 419, 422], 'first logout at '.$path);
|
||||
$this->assertStatusIn($second, [200, 202, 204, 302, 401, 404, 419, 422], 'repeat logout at '.$path);
|
||||
$this->assertNoServerError($first, 'first logout at ' . $path);
|
||||
$this->assertNoServerError($second, 'repeat logout at ' . $path);
|
||||
$this->assertStatusIn($first, [200, 202, 204, 302, 401, 404, 419, 422], 'first logout at ' . $path);
|
||||
$this->assertStatusIn($second, [200, 202, 204, 302, 401, 404, 419, 422], 'repeat logout at ' . $path);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,16 +75,16 @@ class ApiAuthenticationLifecycleDepthContractTest extends FullSurfaceE2EContract
|
||||
|
||||
$uri = $route->uri();
|
||||
$response = $this->json($method, $this->materializePath($uri), [
|
||||
'email' => 'nobody.'.uniqid().'@example.test',
|
||||
'email' => 'nobody.' . uniqid() . '@example.test',
|
||||
'password' => 'password',
|
||||
'password_confirmation' => 'not-the-same',
|
||||
'token' => 'not-a-real-token',
|
||||
]);
|
||||
|
||||
$this->assertControlled($response, $method, $uri);
|
||||
$this->assertNoServerError($response, $method.' '.$uri);
|
||||
$this->assertStringNotContainsStringIgnoringCase('select * from', $response->getContent(), $uri.' must not leak account lookup SQL.');
|
||||
$this->assertStringNotContainsStringIgnoringCase('No query results for model', $response->getContent(), $uri.' must not leak framework model lookups.');
|
||||
$this->assertNoServerError($response, $method . ' ' . $uri);
|
||||
$this->assertStringNotContainsStringIgnoringCase('select * from', $response->getContent(), $uri . ' must not leak account lookup SQL.');
|
||||
$this->assertStringNotContainsStringIgnoringCase('No query results for model', $response->getContent(), $uri . ' must not leak framework model lookups.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,8 +22,8 @@ class ApiAuthorizationCacheInvalidationContractTest extends FullSurfaceE2EContra
|
||||
|
||||
$response = $this->requestAs($this->parent, $method, $uri, $payload);
|
||||
|
||||
$this->assertStatusIn($response, [401, 403, 404, 405, 419, 422], 'parent privilege escalation should be blocked at '.$method.' '.$uri);
|
||||
$this->assertNoServerError($response, 'permission cache escalation probe at '.$method.' '.$uri);
|
||||
$this->assertStatusIn($response, [401, 403, 404, 405, 419, 422], 'parent privilege escalation should be blocked at ' . $method . ' ' . $uri);
|
||||
$this->assertNoServerError($response, 'permission cache escalation probe at ' . $method . ' ' . $uri);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ class ApiBatch11RouteRegressionNetTest extends FullSurfaceE2EContractCase
|
||||
foreach ($families as $family => $needles) {
|
||||
$this->assertNotEmpty(
|
||||
$this->apiRoutesContainingAny($needles),
|
||||
'Batch 11 expects at least one route for the '.$family.' family. If this fails, update the route catalog instead of pretending the family vanished.'
|
||||
'Batch 11 expects at least one route for the ' . $family . ' family. If this fails, update the route catalog instead of pretending the family vanished.'
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -53,7 +53,7 @@ class ApiBatch11RouteRegressionNetTest extends FullSurfaceE2EContractCase
|
||||
])->json($method, $this->materializePath($uri), $payload);
|
||||
|
||||
$this->assertControlled($response, $method, $uri);
|
||||
$this->assertNoServerError($response, 'batch 11 combined hostile probe at '.$method.' '.$uri);
|
||||
$this->assertNoServerError($response, 'batch 11 combined hostile probe at ' . $method . ' ' . $uri);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
|
||||
namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
use Illuminate\Http\UploadedFile;
|
||||
|
||||
class ApiBatch12AttachmentLifecycleContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_attachment_upload_routes_handle_multiple_file_shapes_cleanly(): void
|
||||
|
||||
+3
-5
@@ -6,7 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
class ApiBatch14AcademicPromotionRollbackIntegrityContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_promotion_and_school_year_routes_reject_unsafe_rollback_payloads(): void
|
||||
public function test_promotion_and_school_year_routes_reject_unsafe_rollback_payloads(): void
|
||||
{
|
||||
foreach (array_slice($this->apiRoutesContainingAny(['promotion', 'promote', 'school-year', 'semester', 'close', 'reopen', 'rollback']), 0, 45) as $route) {
|
||||
$method = $this->primaryMethod($route);
|
||||
@@ -22,12 +22,10 @@ class ApiBatch14AcademicPromotionRollbackIntegrityContractTest extends FullSurfa
|
||||
{
|
||||
foreach (array_slice($this->apiRoutesContainingAny(['promotion', 'school-year', 'close', 'reopen']), 0, 30) as $route) {
|
||||
$method = $this->primaryMethod($route);
|
||||
if (! in_array($method, ['POST', 'PUT', 'PATCH', 'DELETE'], true)) {
|
||||
continue;
|
||||
}
|
||||
if (! in_array($method, ['POST', 'PUT', 'PATCH', 'DELETE'], true)) { continue; }
|
||||
foreach ([$this->teacher, $this->parent, $this->studentUser] as $actor) {
|
||||
$response = $this->requestAs($actor, $method, $route->uri(), ['force' => true, 'confirmed' => true, 'school_year_id' => $this->ids['schoolYearId']]);
|
||||
$this->assertStatusIn($response, [400, 401, 403, 404, 405, 409, 419, 422], $method.' '.$route->uri());
|
||||
$this->assertStatusIn($response, [400, 401, 403, 404, 405, 409, 419, 422], $method . ' ' . $route->uri());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-6
@@ -6,15 +6,13 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
class ApiBatch14AccountEnumerationAndIdentityPrivacyContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_identity_recovery_routes_do_not_reveal_whether_user_exists(): void
|
||||
public function test_identity_recovery_routes_do_not_reveal_whether_user_exists(): void
|
||||
{
|
||||
$routes = $this->apiRoutesContainingAny(['forgot', 'password', 'reset', 'verify', 'verification', 'recovery']);
|
||||
foreach (array_slice($routes, 0, 30) as $route) {
|
||||
$method = $this->primaryMethod($route);
|
||||
if (! in_array($method, ['POST', 'PUT', 'PATCH'], true)) {
|
||||
continue;
|
||||
}
|
||||
foreach ([$this->admin->email, 'missing-user-'.uniqid().'@example.test'] as $email) {
|
||||
if (! in_array($method, ['POST', 'PUT', 'PATCH'], true)) { continue; }
|
||||
foreach ([$this->admin->email, 'missing-user-' . uniqid() . '@example.test'] as $email) {
|
||||
$response = $this->json($method, $this->materializePath($route->uri()), ['email' => $email, 'token' => 'invalid-token', 'password' => 'NewPassword123!', 'password_confirmation' => 'NewPassword123!']);
|
||||
$this->assertControlled($response, $method, $route->uri());
|
||||
$body = strtolower($response->getContent());
|
||||
@@ -33,7 +31,7 @@ class ApiBatch14AccountEnumerationAndIdentityPrivacyContractTest extends FullSur
|
||||
$this->assertControlled($response, $method, $route->uri());
|
||||
$body = strtolower($response->getContent());
|
||||
foreach (['password', 'remember_token', 'two_factor', 'api_token', 'provider_token', 'secret'] as $forbidden) {
|
||||
$this->assertStringNotContainsString($forbidden, $body, $route->uri().' leaked identity internals.');
|
||||
$this->assertStringNotContainsString($forbidden, $body, $route->uri() . ' leaked identity internals.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-5
@@ -6,7 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
class ApiBatch14AdminDelegationApprovalWorkflowContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_approval_and_delegation_routes_reject_forged_approval_metadata(): void
|
||||
public function test_approval_and_delegation_routes_reject_forged_approval_metadata(): void
|
||||
{
|
||||
foreach (array_slice($this->apiRoutesContainingAny(['approve', 'approval', 'delegate', 'delegation', 'authorize', 'permission', 'role', 'impersonate']), 0, 50) as $route) {
|
||||
$method = $this->primaryMethod($route);
|
||||
@@ -20,12 +20,10 @@ class ApiBatch14AdminDelegationApprovalWorkflowContractTest extends FullSurfaceE
|
||||
{
|
||||
foreach (array_slice($this->apiRoutesContainingAny(['approve', 'approval', 'delegate', 'permission', 'role']), 0, 35) as $route) {
|
||||
$method = $this->primaryMethod($route);
|
||||
if (! in_array($method, ['POST', 'PUT', 'PATCH', 'DELETE'], true)) {
|
||||
continue;
|
||||
}
|
||||
if (! in_array($method, ['POST', 'PUT', 'PATCH', 'DELETE'], true)) { continue; }
|
||||
foreach ([$this->teacher, $this->parent, $this->studentUser] as $actor) {
|
||||
$response = $this->requestAs($actor, $method, $route->uri(), ['approved' => true, 'permissions' => ['*'], 'role' => 'administrator', 'force' => true]);
|
||||
$this->assertStatusIn($response, [400, 401, 403, 404, 405, 409, 419, 422], $method.' '.$route->uri());
|
||||
$this->assertStatusIn($response, [400, 401, 403, 404, 405, 409, 419, 422], $method . ' ' . $route->uri());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
-10
@@ -6,17 +6,15 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
class ApiBatch14ApiConsumerContractCompatibilityTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_core_identity_contracts_remain_compatible_for_web_mobile_and_api_clients(): void
|
||||
public function test_core_identity_contracts_remain_compatible_for_web_mobile_and_api_clients(): void
|
||||
{
|
||||
foreach (array_slice($this->apiRoutesContainingAny(['login', 'auth/me', 'me', 'frontend', 'profile']), 0, 25) as $route) {
|
||||
$method = $this->primaryMethod($route);
|
||||
foreach ([['Accept' => 'application/json', 'X-Client' => 'web'], ['Accept' => 'application/json', 'X-Client' => 'mobile', 'X-App-Version' => '1.0.0'], ['Accept' => 'application/vnd.alrahma.v1+json', 'X-Client' => 'api-consumer']] as $headers) {
|
||||
$response = $this->withHeaders($headers)->actingAs($this->actorFor($route->uri()), 'api')->json($method, $this->materializePath($route->uri()), $this->payloadFor($method, $route->uri()));
|
||||
$this->assertControlled($response, $method, $route->uri());
|
||||
$this->assertJsonResponseWhenSuccessful($response, $method.' '.$route->uri());
|
||||
if ($response->isSuccessful()) {
|
||||
$this->assertStringNotContainsString('undefined index', strtolower($response->getContent()));
|
||||
}
|
||||
$this->assertJsonResponseWhenSuccessful($response, $method . ' ' . $route->uri());
|
||||
if ($response->isSuccessful()) { $this->assertStringNotContainsString('undefined index', strtolower($response->getContent())); }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,15 +23,13 @@ class ApiBatch14ApiConsumerContractCompatibilityTest extends FullSurfaceE2EContr
|
||||
{
|
||||
foreach (array_slice($this->apiRoutesContainingAny(['login', 'auth/login']), 0, 10) as $route) {
|
||||
$method = $this->primaryMethod($route);
|
||||
if ($method !== 'POST') {
|
||||
continue;
|
||||
}
|
||||
if ($method !== 'POST') { continue; }
|
||||
$response = $this->json($method, $this->materializePath($route->uri()), ['email' => $this->admin->email, 'password' => 'password']);
|
||||
$this->assertControlled($response, $method, $route->uri());
|
||||
if ($response->isSuccessful() && $this->isJsonString($response->getContent())) {
|
||||
$data = $response->json();
|
||||
$this->assertTrue(isset($data['token']) || isset($data['access_token']), $route->uri().' should expose token/access_token when login succeeds.');
|
||||
$this->assertArrayHasKey('user', $data, $route->uri().' should expose user when login succeeds.');
|
||||
$this->assertTrue(isset($data['token']) || isset($data['access_token']), $route->uri() . ' should expose token/access_token when login succeeds.');
|
||||
$this->assertArrayHasKey('user', $data, $route->uri() . ' should expose user when login succeeds.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-5
@@ -6,7 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
class ApiBatch14AttendanceDeviceAndKioskAbuseContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_kiosk_scanner_and_attendance_routes_reject_forged_device_identity(): void
|
||||
public function test_kiosk_scanner_and_attendance_routes_reject_forged_device_identity(): void
|
||||
{
|
||||
foreach (array_slice($this->apiRoutesContainingAny(['attendance', 'scanner', 'scan', 'kiosk', 'badge', 'dismissal', 'late']), 0, 55) as $route) {
|
||||
$method = $this->primaryMethod($route);
|
||||
@@ -22,12 +22,10 @@ class ApiBatch14AttendanceDeviceAndKioskAbuseContractTest extends FullSurfaceE2E
|
||||
{
|
||||
foreach (array_slice($this->apiRoutesContainingAny(['attendance', 'scan', 'dismissal', 'late']), 0, 30) as $route) {
|
||||
$method = $this->primaryMethod($route);
|
||||
if (! in_array($method, ['POST', 'PUT', 'PATCH'], true)) {
|
||||
continue;
|
||||
}
|
||||
if (! in_array($method, ['POST', 'PUT', 'PATCH'], true)) { continue; }
|
||||
foreach ([$this->studentUser, $this->parent] as $actor) {
|
||||
$response = $this->requestAs($actor, $method, $route->uri(), ['student_id' => $this->ids['studentId'], 'status' => 'present', 'verified_by_device' => true, 'override_reason' => 'parent approved']);
|
||||
$this->assertStatusIn($response, [400, 401, 403, 404, 405, 409, 419, 422], $method.' '.$route->uri());
|
||||
$this->assertStatusIn($response, [400, 401, 403, 404, 405, 409, 419, 422], $method . ' ' . $route->uri());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-5
@@ -6,7 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
class ApiBatch14AuditTrailTamperResistanceContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_audit_and_log_routes_reject_client_supplied_actor_and_timestamp_fields(): void
|
||||
public function test_audit_and_log_routes_reject_client_supplied_actor_and_timestamp_fields(): void
|
||||
{
|
||||
foreach (array_slice($this->apiRoutesContainingAny(['audit', 'log', 'activity', 'history', 'trace']), 0, 35) as $route) {
|
||||
$method = $this->primaryMethod($route);
|
||||
@@ -22,12 +22,10 @@ class ApiBatch14AuditTrailTamperResistanceContractTest extends FullSurfaceE2ECon
|
||||
{
|
||||
foreach (array_slice($this->apiRoutesContainingAny(['audit', 'log', 'history', 'activity']), 0, 25) as $route) {
|
||||
$method = $this->primaryMethod($route);
|
||||
if (! in_array($method, ['POST', 'PUT', 'PATCH', 'DELETE'], true)) {
|
||||
continue;
|
||||
}
|
||||
if (! in_array($method, ['POST', 'PUT', 'PATCH', 'DELETE'], true)) { continue; }
|
||||
foreach ([$this->parent, $this->teacher, $this->studentUser] as $actor) {
|
||||
$response = $this->requestAs($actor, $method, $route->uri(), ['action' => 'clear', 'purge' => true, 'rewrite' => true]);
|
||||
$this->assertStatusIn($response, [400, 401, 403, 404, 405, 409, 419, 422], $method.' '.$route->uri());
|
||||
$this->assertStatusIn($response, [400, 401, 403, 404, 405, 409, 419, 422], $method . ' ' . $route->uri());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,13 +6,11 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
class ApiBatch14BulkAssignmentCollisionContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_bulk_assignment_routes_handle_duplicate_and_conflicting_ids_cleanly(): void
|
||||
public function test_bulk_assignment_routes_handle_duplicate_and_conflicting_ids_cleanly(): void
|
||||
{
|
||||
foreach (array_slice($this->apiRoutesContainingAny(['assign', 'assignment', 'enroll', 'bulk', 'batch', 'class', 'teacher', 'student']), 0, 50) as $route) {
|
||||
$method = $this->primaryMethod($route);
|
||||
if (! in_array($method, ['POST', 'PUT', 'PATCH'], true)) {
|
||||
continue;
|
||||
}
|
||||
if (! in_array($method, ['POST', 'PUT', 'PATCH'], true)) { continue; }
|
||||
$response = $this->requestAs($this->actorFor($route->uri()), $method, $route->uri(), $this->payloadFor($method, $route->uri()) + [
|
||||
'student_ids' => [$this->ids['studentId'], $this->ids['studentId'], 99999999], 'teacher_ids' => [$this->teacher->id, $this->teacher->id, $this->parent->id],
|
||||
'class_section_ids' => [$this->ids['classSectionId'], $this->ids['classSectionId'], 99999999], 'parent_ids' => [$this->ids['parentId'], $this->ids['parentId'], 99999999], 'force' => true, 'overwrite' => true,
|
||||
@@ -29,12 +27,10 @@ class ApiBatch14BulkAssignmentCollisionContractTest extends FullSurfaceE2EContra
|
||||
{
|
||||
foreach (array_slice($this->apiRoutesContainingAny(['assign', 'bulk', 'batch', 'class-sections', 'teacher-class', 'enroll']), 0, 30) as $route) {
|
||||
$method = $this->primaryMethod($route);
|
||||
if (! in_array($method, ['POST', 'PUT', 'PATCH', 'DELETE'], true)) {
|
||||
continue;
|
||||
}
|
||||
if (! in_array($method, ['POST', 'PUT', 'PATCH', 'DELETE'], true)) { continue; }
|
||||
foreach ([$this->parent, $this->studentUser] as $actor) {
|
||||
$response = $this->requestAs($actor, $method, $route->uri(), ['student_ids' => [$this->ids['studentId']], 'teacher_ids' => [$this->teacher->id], 'class_section_ids' => [$this->ids['classSectionId']], 'all' => true, 'force' => true]);
|
||||
$this->assertStatusIn($response, [400, 401, 403, 404, 405, 409, 419, 422], $method.' '.$route->uri());
|
||||
$this->assertStatusIn($response, [400, 401, 403, 404, 405, 409, 419, 422], $method . ' ' . $route->uri());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
class ApiBatch14CrossModuleInvariantRiskRegisterTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch14_route_families_have_cross_module_risk_coverage(): void
|
||||
public function test_batch14_route_families_have_cross_module_risk_coverage(): void
|
||||
{
|
||||
$riskFamilies = [
|
||||
'session-cookie-boundary' => ['auth', 'login', 'frontend'],
|
||||
@@ -22,7 +22,7 @@ class ApiBatch14CrossModuleInvariantRiskRegisterTest extends FullSurfaceE2EContr
|
||||
];
|
||||
|
||||
foreach ($riskFamilies as $name => $needles) {
|
||||
$this->assertNotEmpty($this->apiRoutesContainingAny($needles), 'Batch 14 expected route coverage for '.$name);
|
||||
$this->assertNotEmpty($this->apiRoutesContainingAny($needles), 'Batch 14 expected route coverage for ' . $name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ class ApiBatch14CrossModuleInvariantRiskRegisterTest extends FullSurfaceE2EContr
|
||||
$mutations = array_filter($this->apiRoutesContainingAny([$family]), function ($route): bool {
|
||||
return in_array($this->primaryMethod($route), ['POST', 'PUT', 'PATCH', 'DELETE'], true);
|
||||
});
|
||||
$this->assertNotEmpty($mutations, 'Batch 14 expected mutating route family: '.$family);
|
||||
$this->assertNotEmpty($mutations, 'Batch 14 expected mutating route family: ' . $family);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-7
@@ -6,15 +6,14 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
class ApiBatch14DataLifecycleArchivePurgeContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_archive_purge_and_retention_routes_require_safe_controlled_requests(): void
|
||||
public function test_archive_purge_and_retention_routes_require_safe_controlled_requests(): void
|
||||
{
|
||||
foreach (array_slice($this->apiRoutesContainingAny(['archive', 'restore', 'purge', 'erase', 'retention', 'delete', 'destroy']), 0, 50) as $route) {
|
||||
$method = $this->primaryMethod($route);
|
||||
$response = $this->requestAs($this->actorFor($route->uri()), $method, $route->uri(), $this->payloadFor($method, $route->uri()) + ['ids' => [$this->ids['studentId'], 99999999, '../../.env'], 'hard_delete' => true, 'purge' => true, 'cascade' => true, 'include_audit_logs' => true, 'reason' => '', 'confirmed' => false]);
|
||||
$this->assertControlled($response, $method, $route->uri());
|
||||
$body = strtolower($response->getContent());
|
||||
$this->assertStringNotContainsString('sqlstate', $body);
|
||||
$this->assertStringNotContainsString('foreign key constraint', $body);
|
||||
$this->assertStringNotContainsString('sqlstate', $body); $this->assertStringNotContainsString('foreign key constraint', $body);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,12 +21,10 @@ class ApiBatch14DataLifecycleArchivePurgeContractTest extends FullSurfaceE2ECont
|
||||
{
|
||||
foreach (array_slice($this->apiRoutesContainingAny(['purge', 'erase', 'restore', 'archive', 'delete']), 0, 35) as $route) {
|
||||
$method = $this->primaryMethod($route);
|
||||
if (! in_array($method, ['POST', 'PUT', 'PATCH', 'DELETE'], true)) {
|
||||
continue;
|
||||
}
|
||||
if (! in_array($method, ['POST', 'PUT', 'PATCH', 'DELETE'], true)) { continue; }
|
||||
foreach ([$this->teacher, $this->parent, $this->studentUser] as $actor) {
|
||||
$response = $this->requestAs($actor, $method, $route->uri(), ['ids' => [$this->ids['studentId']], 'hard_delete' => true, 'purge' => true, 'global' => true]);
|
||||
$this->assertStatusIn($response, [400, 401, 403, 404, 405, 409, 419, 422], $method.' '.$route->uri());
|
||||
$this->assertStatusIn($response, [400, 401, 403, 404, 405, 409, 419, 422], $method . ' ' . $route->uri());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-9
@@ -6,18 +6,16 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
class ApiBatch14FinanceReconciliationAndRefundAbuseContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_finance_reconciliation_routes_reject_mismatched_invoice_parent_and_payment_fields(): void
|
||||
public function test_finance_reconciliation_routes_reject_mismatched_invoice_parent_and_payment_fields(): void
|
||||
{
|
||||
foreach (array_slice($this->apiRoutesContainingAny(['finance', 'invoice', 'payment', 'refund', 'transaction', 'ledger', 'reconcile']), 0, 55) as $route) {
|
||||
$method = $this->primaryMethod($route);
|
||||
$response = $this->requestAs($this->actorFor($route->uri()), $method, $route->uri(), $this->payloadFor($method, $route->uri()) + [
|
||||
'invoice_id' => $this->ids['invoiceId'], 'parent_id' => 99999999, 'student_id' => 99999999, 'payment_id' => 99999999, 'refund_id' => 99999999, 'transaction_id' => 'provider-'.uniqid(), 'provider_transaction_id' => 'provider-'.uniqid(), 'amount' => -99999.99, 'net_amount' => -99999.99, 'fee_amount' => -99999.99, 'currency' => 'XXX', 'reconciled' => true, 'force_posted' => true,
|
||||
'invoice_id' => $this->ids['invoiceId'], 'parent_id' => 99999999, 'student_id' => 99999999, 'payment_id' => 99999999, 'refund_id' => 99999999, 'transaction_id' => 'provider-' . uniqid(), 'provider_transaction_id' => 'provider-' . uniqid(), 'amount' => -99999.99, 'net_amount' => -99999.99, 'fee_amount' => -99999.99, 'currency' => 'XXX', 'reconciled' => true, 'force_posted' => true,
|
||||
]);
|
||||
$this->assertControlled($response, $method, $route->uri());
|
||||
$body = strtolower($response->getContent());
|
||||
$this->assertStringNotContainsString('sqlstate', $body);
|
||||
$this->assertStringNotContainsString('duplicate entry', $body);
|
||||
$this->assertStringNotContainsString('foreign key constraint', $body);
|
||||
$this->assertStringNotContainsString('sqlstate', $body); $this->assertStringNotContainsString('duplicate entry', $body); $this->assertStringNotContainsString('foreign key constraint', $body);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,11 +23,9 @@ class ApiBatch14FinanceReconciliationAndRefundAbuseContractTest extends FullSurf
|
||||
{
|
||||
foreach (array_slice($this->apiRoutesContainingAny(['refund', 'reconcile', 'ledger', 'payment']), 0, 35) as $route) {
|
||||
$method = $this->primaryMethod($route);
|
||||
if (! in_array($method, ['POST', 'PUT', 'PATCH', 'DELETE'], true)) {
|
||||
continue;
|
||||
}
|
||||
if (! in_array($method, ['POST', 'PUT', 'PATCH', 'DELETE'], true)) { continue; }
|
||||
$response = $this->requestAs($this->parent, $method, $route->uri(), ['invoice_id' => $this->ids['invoiceId'], 'amount' => 100.00, 'approved' => true, 'reconciled' => true, 'refund_now' => true]);
|
||||
$this->assertStatusIn($response, [400, 401, 403, 404, 405, 409, 419, 422], $method.' '.$route->uri());
|
||||
$this->assertStatusIn($response, [400, 401, 403, 404, 405, 409, 419, 422], $method . ' ' . $route->uri());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-11
@@ -6,21 +6,17 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
class ApiBatch14NotificationTemplateInjectionContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_notification_and_template_routes_reject_template_injection_payloads(): void
|
||||
public function test_notification_and_template_routes_reject_template_injection_payloads(): void
|
||||
{
|
||||
foreach (array_slice($this->apiRoutesContainingAny(['notification', 'notify', 'message', 'email', 'whatsapp', 'template', 'broadcast']), 0, 55) as $route) {
|
||||
$method = $this->primaryMethod($route);
|
||||
if (! in_array($method, ['POST', 'PUT', 'PATCH'], true)) {
|
||||
continue;
|
||||
}
|
||||
if (! in_array($method, ['POST', 'PUT', 'PATCH'], true)) { continue; }
|
||||
$response = $this->requestAs($this->actorFor($route->uri()), $method, $route->uri(), $this->payloadFor($method, $route->uri()) + [
|
||||
'subject' => '{{ config("app.key") }}', 'message' => '<script>alert(document.cookie)</script>{{ $user->password }}', 'body' => '${jndi:ldap://127.0.0.1/a}', 'template' => '@php echo env("APP_KEY"); @endphp', 'channel' => 'all', 'recipients' => ['*'], 'phone' => "+15551234567\r\nBcc: attacker@example.test", 'email' => "victim@example.test\r\nBcc: attacker@example.test",
|
||||
]);
|
||||
$this->assertControlled($response, $method, $route->uri());
|
||||
$body = strtolower($response->getContent());
|
||||
$this->assertStringNotContainsString('app_key', $body);
|
||||
$this->assertStringNotContainsString('document.cookie', $body);
|
||||
$this->assertStringNotContainsString('jndi:ldap', $body);
|
||||
$this->assertStringNotContainsString('app_key', $body); $this->assertStringNotContainsString('document.cookie', $body); $this->assertStringNotContainsString('jndi:ldap', $body);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,12 +24,10 @@ class ApiBatch14NotificationTemplateInjectionContractTest extends FullSurfaceE2E
|
||||
{
|
||||
foreach (array_slice($this->apiRoutesContainingAny(['broadcast', 'notification', 'email', 'whatsapp']), 0, 30) as $route) {
|
||||
$method = $this->primaryMethod($route);
|
||||
if (! in_array($method, ['POST', 'PUT', 'PATCH'], true)) {
|
||||
continue;
|
||||
}
|
||||
if (! in_array($method, ['POST', 'PUT', 'PATCH'], true)) { continue; }
|
||||
foreach ([$this->parent, $this->teacher, $this->studentUser] as $actor) {
|
||||
$response = $this->requestAs($actor, $method, $route->uri(), ['channel' => 'all', 'recipients' => ['all_school'], 'template_id' => 1, 'force_send' => true]);
|
||||
$this->assertStatusIn($response, [400, 401, 403, 404, 405, 409, 419, 422], $method.' '.$route->uri());
|
||||
$this->assertStatusIn($response, [400, 401, 403, 404, 405, 409, 419, 422], $method . ' ' . $route->uri());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
class ApiBatch14PrintExportTamperingContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_print_export_and_document_generation_routes_reject_tampered_scope_fields(): void
|
||||
public function test_print_export_and_document_generation_routes_reject_tampered_scope_fields(): void
|
||||
{
|
||||
foreach (array_slice($this->apiRoutesContainingAny(['print', 'export', 'download', 'certificate', 'badge', 'receipt', 'transcript', 'report-card']), 0, 50) as $route) {
|
||||
$method = $this->primaryMethod($route);
|
||||
@@ -15,9 +15,7 @@ class ApiBatch14PrintExportTamperingContractTest extends FullSurfaceE2EContractC
|
||||
]);
|
||||
$this->assertControlled($response, $method, $route->uri());
|
||||
$body = strtolower($response->getContent());
|
||||
foreach (['app_key', 'laravel.log', 'password', 'remember_token', 'sqlstate'] as $forbidden) {
|
||||
$this->assertStringNotContainsString($forbidden, $body);
|
||||
}
|
||||
foreach (['app_key', 'laravel.log', 'password', 'remember_token', 'sqlstate'] as $forbidden) { $this->assertStringNotContainsString($forbidden, $body); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +25,7 @@ class ApiBatch14PrintExportTamperingContractTest extends FullSurfaceE2EContractC
|
||||
$method = $this->primaryMethod($route);
|
||||
foreach ([$this->parent, $this->teacher, $this->studentUser] as $actor) {
|
||||
$response = $this->requestAs($actor, $method, $route->uri(), ['scope' => 'all_school', 'all_students' => true, 'include_finance' => true, 'include_guardians' => true, 'format' => 'csv']);
|
||||
$this->assertStatusIn($response, [200, 204, 302, 400, 401, 403, 404, 405, 409, 419, 422], $method.' '.$route->uri());
|
||||
$this->assertStatusIn($response, [200, 204, 302, 400, 401, 403, 404, 405, 409, 419, 422], $method . ' ' . $route->uri());
|
||||
$this->assertStringNotContainsString('remember_token', strtolower($response->getContent()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
class ApiBatch14RegressionMegaSweepTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch14_mega_sweep_keeps_new_risk_payloads_under_controlled_failure(): void
|
||||
public function test_batch14_mega_sweep_keeps_new_risk_payloads_under_controlled_failure(): void
|
||||
{
|
||||
$families = [
|
||||
['auth', 'login', 'password', 'verify'], ['users', 'roles', 'permissions', 'profile'], ['students', 'parents', 'family', 'guardian'],
|
||||
@@ -26,9 +26,7 @@ class ApiBatch14RegressionMegaSweepTest extends FullSurfaceE2EContractCase
|
||||
$response = $this->requestAs($this->actorFor($route->uri()), $method, $route->uri(), $payload);
|
||||
$this->assertControlled($response, $method, $route->uri());
|
||||
$body = strtolower($response->getContent());
|
||||
foreach (['sqlstate', 'app_key', 'db_password', 'remember_token', 'stack trace', 'laravel.log'] as $forbidden) {
|
||||
$this->assertStringNotContainsString($forbidden, $body);
|
||||
}
|
||||
foreach (['sqlstate', 'app_key', 'db_password', 'remember_token', 'stack trace', 'laravel.log'] as $forbidden) { $this->assertStringNotContainsString($forbidden, $body); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-8
@@ -6,19 +6,15 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
class ApiBatch14RelationshipOwnershipMatrixExpansionTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_relationship_owner_override_fields_are_not_trusted_across_route_families(): void
|
||||
public function test_relationship_owner_override_fields_are_not_trusted_across_route_families(): void
|
||||
{
|
||||
foreach (array_slice($this->apiRoutesContainingAny(['student', 'parent', 'family', 'invoice', 'attendance', 'score', 'guardian', 'authorized']), 0, 60) as $route) {
|
||||
$method = $this->primaryMethod($route);
|
||||
if (! in_array($method, ['POST', 'PUT', 'PATCH', 'DELETE'], true)) {
|
||||
continue;
|
||||
}
|
||||
if (! in_array($method, ['POST', 'PUT', 'PATCH', 'DELETE'], true)) { continue; }
|
||||
foreach ([$this->parent, $this->teacher] as $actor) {
|
||||
$response = $this->requestAs($actor, $method, $route->uri(), $this->payloadFor($method, $route->uri()) + ['student_ids' => [$this->ids['studentId'], 99999999], 'parent_id' => 99999999, 'family_id' => 99999999, 'guardian_id' => 99999999, 'owner_id' => $this->admin->id, 'owner_type' => 'App\\Models\\User', 'created_by' => $this->admin->id, 'scope' => 'global']);
|
||||
$this->assertControlled($response, $method, $route->uri());
|
||||
$body = strtolower($response->getContent());
|
||||
$this->assertStringNotContainsString('sqlstate', $body);
|
||||
$this->assertStringNotContainsString('remember_token', $body);
|
||||
$body = strtolower($response->getContent()); $this->assertStringNotContainsString('sqlstate', $body); $this->assertStringNotContainsString('remember_token', $body);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,7 +24,7 @@ class ApiBatch14RelationshipOwnershipMatrixExpansionTest extends FullSurfaceE2EC
|
||||
foreach (array_slice($this->apiRoutesContainingAny(['parent', 'family', 'guardian', 'invoice', 'attendance', 'report-card']), 0, 40) as $route) {
|
||||
$method = $this->primaryMethod($route);
|
||||
$response = $this->requestAs($this->studentUser, $method, $route->uri(), ['student_id' => 99999999, 'parent_id' => 99999999, 'family_id' => 99999999, 'include' => 'guardians,invoices,attendance,notes']);
|
||||
$this->assertStatusIn($response, [200, 204, 302, 400, 401, 403, 404, 405, 409, 419, 422], $method.' '.$route->uri());
|
||||
$this->assertStatusIn($response, [200, 204, 302, 400, 401, 403, 404, 405, 409, 419, 422], $method . ' ' . $route->uri());
|
||||
$this->assertStringNotContainsString('remember_token', strtolower($response->getContent()));
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -6,7 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
class ApiBatch14SessionCookieCsrfBoundaryContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_api_auth_routes_do_not_depend_on_browser_session_cookies(): void
|
||||
public function test_api_auth_routes_do_not_depend_on_browser_session_cookies(): void
|
||||
{
|
||||
foreach (array_slice($this->apiRoutesContainingAny(['auth', 'login', 'logout', 'me', 'profile', 'frontend']), 0, 40) as $route) {
|
||||
$method = $this->primaryMethod($route);
|
||||
@@ -26,7 +26,7 @@ class ApiBatch14SessionCookieCsrfBoundaryContractTest extends FullSurfaceE2ECont
|
||||
$response = $this->withCookie('laravel_session', 'fake-admin-browser-session')
|
||||
->withHeaders(['X-Requested-With' => 'XMLHttpRequest', 'X-CSRF-TOKEN' => 'fake-csrf', 'X-User-Id' => (string) $this->admin->id])
|
||||
->json($method, $this->materializePath($route->uri()), $this->payloadFor($method, $route->uri()));
|
||||
$this->assertStatusIn($response, [401, 403, 404, 405, 419, 422], $method.' '.$route->uri());
|
||||
$this->assertStatusIn($response, [401, 403, 404, 405, 419, 422], $method . ' ' . $route->uri());
|
||||
$this->assertStringNotContainsString('sqlstate', strtolower($response->getContent()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,16 +6,14 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
class ApiBatch14StoragePathAndSignedUrlContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_file_and_signed_url_routes_reject_path_and_disk_overrides(): void
|
||||
public function test_file_and_signed_url_routes_reject_path_and_disk_overrides(): void
|
||||
{
|
||||
foreach (array_slice($this->apiRoutesContainingAny(['file', 'media', 'upload', 'download', 'export', 'import', 'attachment', 'document', 'signed']), 0, 55) as $route) {
|
||||
$method = $this->primaryMethod($route);
|
||||
$response = $this->requestAs($this->actorFor($route->uri()), $method, $route->uri(), $this->payloadFor($method, $route->uri()) + ['path' => '../../.env', 'filename' => '../../storage/logs/laravel.log', 'disk' => 'local', 'storage_disk' => 's3://private-bucket', 'url' => 'file:///etc/passwd', 'expires' => '2099-01-01', 'signature' => 'forged-signature', 'mime_type' => 'text/x-php']);
|
||||
$this->assertControlled($response, $method, $route->uri());
|
||||
$body = strtolower($response->getContent());
|
||||
foreach (['app_key', 'db_password', 'laravel.log', '/etc/passwd', 'begin rsa private key'] as $forbidden) {
|
||||
$this->assertStringNotContainsString($forbidden, $body);
|
||||
}
|
||||
foreach (['app_key', 'db_password', 'laravel.log', '/etc/passwd', 'begin rsa private key'] as $forbidden) { $this->assertStringNotContainsString($forbidden, $body); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,8 +21,8 @@ class ApiBatch14StoragePathAndSignedUrlContractTest extends FullSurfaceE2EContra
|
||||
{
|
||||
foreach (array_slice($this->apiRoutesContainingAny(['download', 'signed', 'public', 'media', 'file']), 0, 35) as $route) {
|
||||
$method = $this->primaryMethod($route);
|
||||
$response = $this->json($method, $this->materializePath($route->uri()).'?signature=forged&expires=1&path=../../.env');
|
||||
$this->assertStatusIn($response, [200, 204, 302, 400, 401, 403, 404, 405, 410, 419, 422], $method.' '.$route->uri());
|
||||
$response = $this->json($method, $this->materializePath($route->uri()) . '?signature=forged&expires=1&path=../../.env');
|
||||
$this->assertStatusIn($response, [200, 204, 302, 400, 401, 403, 404, 405, 410, 419, 422], $method . ' ' . $route->uri());
|
||||
$this->assertStringNotContainsString('app_key', strtolower($response->getContent()));
|
||||
}
|
||||
}
|
||||
|
||||
+2
@@ -6,6 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
class ApiBatch15AdminImpersonationSessionBoundaryContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
|
||||
public function test_batch15_impersonation_and_acting_as_routes_require_real_admin_context_not_payload_claims(): void
|
||||
{
|
||||
$routes = $this->apiRoutesContainingAny(['impersonate', 'acting-as', 'act-as', 'switch-user', 'delegate', 'behalf']);
|
||||
@@ -27,4 +28,5 @@ class ApiBatch15AdminImpersonationSessionBoundaryContractTest extends FullSurfac
|
||||
$this->assertStringNotContainsString('access_token', strtolower($parentResponse->getContent()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
@@ -6,6 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
class ApiBatch15AuthTokenRotationAndRevocationContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
|
||||
public function test_batch15_token_rotation_revocation_and_identity_routes_do_not_accept_stale_or_forged_tokens(): void
|
||||
{
|
||||
$routes = $this->apiRoutesContainingAny(['auth', 'login', 'logout', 'refresh', 'token', 'me', 'profile', 'session']);
|
||||
@@ -45,4 +46,5 @@ class ApiBatch15AuthTokenRotationAndRevocationContractTest extends FullSurfaceE2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
@@ -6,6 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
class ApiBatch15BackgroundCommandAndSchedulerContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
|
||||
public function test_batch15_command_scheduler_and_job_trigger_routes_are_admin_only_and_idempotent(): void
|
||||
{
|
||||
$routes = $this->apiRoutesContainingAny(['command', 'schedule', 'scheduler', 'cron', 'job', 'queue', 'sync', 'recalculate', 'cleanup', 'send']);
|
||||
@@ -29,4 +30,5 @@ class ApiBatch15BackgroundCommandAndSchedulerContractTest extends FullSurfaceE2E
|
||||
$this->assertControlled($adminResponse, $method, $uri);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
@@ -6,6 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
class ApiBatch15ConsentPrivacyAndDataSubjectRightsContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
|
||||
public function test_batch15_privacy_consent_erasure_and_export_routes_are_admin_or_owner_scoped(): void
|
||||
{
|
||||
$routes = $this->apiRoutesContainingAny(['privacy', 'consent', 'erase', 'erasure', 'delete-account', 'export-data', 'data-subject', 'retention']);
|
||||
@@ -43,4 +44,5 @@ class ApiBatch15ConsentPrivacyAndDataSubjectRightsContractTest extends FullSurfa
|
||||
$this->assertStringNotContainsString('db_password', strtolower($response->getContent()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
@@ -6,6 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
class ApiBatch15CrossSchoolIdentityCollisionContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
|
||||
public function test_batch15_duplicate_external_identifiers_and_cross_school_aliases_fail_cleanly(): void
|
||||
{
|
||||
$routes = $this->apiRoutesContainingAny(['students', 'users', 'parents', 'family', 'guardian', 'enrollment', 'registration']);
|
||||
@@ -30,4 +31,5 @@ class ApiBatch15CrossSchoolIdentityCollisionContractTest extends FullSurfaceE2EC
|
||||
$this->assertStringNotContainsString('duplicate entry', strtolower($response->getContent()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
@@ -6,6 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
class ApiBatch15DataResidencyBackupAndRestoreContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
|
||||
public function test_batch15_backup_restore_residency_and_snapshot_routes_do_not_expose_or_mutate_for_low_privilege_users(): void
|
||||
{
|
||||
$routes = $this->apiRoutesContainingAny(['backup', 'restore', 'snapshot', 'residency', 'tenant', 'database', 'dump', 'archive']);
|
||||
@@ -31,4 +32,5 @@ class ApiBatch15DataResidencyBackupAndRestoreContractTest extends FullSurfaceE2E
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
@@ -6,6 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
class ApiBatch15DomainEventOutboxAndNotificationConsistencyContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
|
||||
public function test_batch15_event_outbox_and_notification_trigger_routes_reject_forged_event_metadata(): void
|
||||
{
|
||||
$routes = $this->apiRoutesContainingAny(['event', 'outbox', 'notification', 'broadcast', 'message', 'email', 'whatsapp', 'webhook']);
|
||||
@@ -27,4 +28,5 @@ class ApiBatch15DomainEventOutboxAndNotificationConsistencyContractTest extends
|
||||
$this->assertControlled($response, $method, $uri);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
@@ -6,6 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
class ApiBatch15FeatureFlagExperimentAndRolloutContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
|
||||
public function test_batch15_feature_flag_and_rollout_routes_reject_low_privilege_override_payloads(): void
|
||||
{
|
||||
$routes = $this->apiRoutesContainingAny(['feature', 'flag', 'experiment', 'rollout', 'settings', 'configuration']);
|
||||
@@ -27,4 +28,5 @@ class ApiBatch15FeatureFlagExperimentAndRolloutContractTest extends FullSurfaceE
|
||||
$this->assertControlled($response, $method, $uri);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
@@ -6,6 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
class ApiBatch15FormRequestAuthorizationCoverageContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
|
||||
public function test_batch15_mutating_routes_do_not_allow_public_or_low_privilege_form_request_bypass(): void
|
||||
{
|
||||
foreach (array_slice($this->apiRoutes(), 0, 120) as $route) {
|
||||
@@ -28,4 +29,5 @@ class ApiBatch15FormRequestAuthorizationCoverageContractTest extends FullSurface
|
||||
$this->assertControlled($response, $method, $uri);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
@@ -6,6 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
class ApiBatch15GlobalSearchAndDirectoryEnumerationContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
|
||||
public function test_batch15_global_search_directory_and_lookup_routes_resist_enumeration_inputs(): void
|
||||
{
|
||||
$routes = $this->apiRoutesContainingAny(['search', 'lookup', 'directory', 'autocomplete', 'users', 'students', 'parents']);
|
||||
@@ -26,4 +27,5 @@ class ApiBatch15GlobalSearchAndDirectoryEnumerationContractTest extends FullSurf
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
@@ -6,6 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
class ApiBatch15LocalizationContentDirectionAndEncodingContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
|
||||
public function test_batch15_rtl_unicode_and_encoding_payloads_remain_controlled_across_text_routes(): void
|
||||
{
|
||||
$routes = $this->apiRoutesContainingAny(['message', 'contact', 'support', 'notification', 'student', 'parent', 'settings', 'certificate']);
|
||||
@@ -30,4 +31,5 @@ class ApiBatch15LocalizationContentDirectionAndEncodingContractTest extends Full
|
||||
$this->assertStringNotContainsString('malformed utf-8', strtolower($response->getContent()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
@@ -6,6 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
class ApiBatch15MetadataFilteringAndSparseFieldsetSecurityContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
|
||||
public function test_batch15_sparse_fieldsets_metadata_and_embeds_do_not_reveal_sensitive_associations(): void
|
||||
{
|
||||
$routes = $this->apiRoutesContainingAny(['users', 'students', 'parents', 'family', 'finance', 'attendance', 'reports', 'dashboard']);
|
||||
@@ -30,4 +31,5 @@ class ApiBatch15MetadataFilteringAndSparseFieldsetSecurityContractTest extends F
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
class ApiBatch15RateLimitAndAbusePatternContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
|
||||
public function test_batch15_repeated_sensitive_requests_return_controlled_responses_without_leaking_internals(): void
|
||||
{
|
||||
$routes = $this->apiRoutesContainingAny(['login', 'password', 'verify', 'contact', 'support', 'message', 'scanner', 'badge']);
|
||||
@@ -15,7 +16,7 @@ class ApiBatch15RateLimitAndAbusePatternContractTest extends FullSurfaceE2EContr
|
||||
$uri = $route->uri();
|
||||
|
||||
for ($attempt = 1; $attempt <= 3; $attempt++) {
|
||||
$response = $this->withHeader('X-Forwarded-For', '203.0.113.'.$attempt)
|
||||
$response = $this->withHeader('X-Forwarded-For', '203.0.113.' . $attempt)
|
||||
->requestAs($this->actorFor($uri), $method, $uri, $this->payloadFor($method, $uri) + [
|
||||
'email' => 'rate-limit-'.$attempt.'@example.test',
|
||||
'password' => 'wrong-password',
|
||||
@@ -30,4 +31,5 @@ class ApiBatch15RateLimitAndAbusePatternContractTest extends FullSurfaceE2EContr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
class ApiBatch15RegressionUltraSweepTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
|
||||
public function test_batch15_ultra_sweep_keeps_cross_domain_hostile_payloads_under_controlled_responses(): void
|
||||
{
|
||||
$families = [
|
||||
@@ -42,4 +43,5 @@ class ApiBatch15RegressionUltraSweepTest extends FullSurfaceE2EContractCase
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
@@ -6,6 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
class ApiBatch15ReportDrilldownAndAggregatePrivacyContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
|
||||
public function test_batch15_report_drilldown_filters_do_not_allow_scope_escape_or_sensitive_field_inclusion(): void
|
||||
{
|
||||
$routes = $this->apiRoutesContainingAny(['report', 'analytics', 'dashboard', 'summary', 'drilldown', 'export']);
|
||||
@@ -33,4 +34,5 @@ class ApiBatch15ReportDrilldownAndAggregatePrivacyContractTest extends FullSurfa
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
class ApiBatch15RouteParameterPoisoningExpansionTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
|
||||
public function test_batch15_route_parameters_reject_encoded_path_script_and_type_confusion_payloads_cleanly(): void
|
||||
{
|
||||
$poisoned = ['..%2F..%2F.env', '%00', '<svg/onload=alert(1)>', '1 or 1=1', str_repeat('9', 80), '٠١٢٣', 'null', '[]'];
|
||||
@@ -17,7 +18,7 @@ class ApiBatch15RouteParameterPoisoningExpansionTest extends FullSurfaceE2EContr
|
||||
|
||||
$method = $this->primaryMethod($route);
|
||||
foreach (array_slice($poisoned, 0, 4) as $value) {
|
||||
$path = '/'.preg_replace('/\{[^}]+\}/', $value, $route->uri());
|
||||
$path = '/' . preg_replace('/\{[^}]+\}/', $value, $route->uri());
|
||||
$this->actingAs($this->actorFor($route->uri()), 'api');
|
||||
$response = $this->json($method, $path, $this->payloadFor($method, $route->uri()));
|
||||
$this->assertControlled($response, $method, $route->uri());
|
||||
@@ -25,4 +26,5 @@ class ApiBatch15RouteParameterPoisoningExpansionTest extends FullSurfaceE2EContr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
@@ -6,6 +6,7 @@ use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
class ApiBatch15StudentSafetyIncidentEscalationContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
|
||||
public function test_batch15_safety_incident_escalation_routes_are_not_mutable_by_parents_or_students(): void
|
||||
{
|
||||
$routes = $this->apiRoutesContainingAny(['incident', 'violation', 'safety', 'alert', 'flag', 'dismissal', 'late', 'absence', 'attendance']);
|
||||
@@ -28,4 +29,5 @@ class ApiBatch15StudentSafetyIncidentEscalationContractTest extends FullSurfaceE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch17AcademicPrerequisiteAndDependencyContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_academic_actions_do_not_skip_required_prerequisites_or_locks(): void
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch17ApiContractDiffAndCriticalKeyRegisterTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_critical_identity_finance_attendance_and_academic_payloads_keep_contract_anchors(): void
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch17AttendanceTamperWindowContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_attendance_cutoff_backdate_future_and_reason_requirements_are_controlled(): void
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch17CommunicationRecipientExpansionContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_message_broadcast_and_notification_recipient_scope_cannot_be_expanded_by_payload(): void
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch17DataLineageAndSourceAttributionContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_client_supplied_lineage_and_audit_source_fields_are_not_authoritative(): void
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch17ExportColumnLevelSecurityContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_export_field_selection_cannot_request_secrets_or_cross_scope_columns(): void
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch17ExternalIdAndNaturalKeyCollisionContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_external_ids_student_numbers_and_emails_are_not_cross_domain_authority(): void
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch17FinancialPeriodCloseAndAdjustmentContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_closed_period_adjustments_writeoffs_and_credit_transfers_are_guarded(): void
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch17InventoryAssetCustodyContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_inventory_asset_custody_transfers_and_disposal_are_not_client_authorized(): void
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch17MultiGuardBoundaryContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_api_guard_boundaries_are_not_crossed_by_session_or_web_identity(): void
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch17PartialFailureErrorDetailRedactionContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_bulk_partial_failure_details_are_actionable_without_leaking_database_or_secret_details(): void
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch17PerResourceRateLimitIdentityContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_repeated_sensitive_actions_are_scoped_by_actor_resource_and_operation(): void
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch17RegressionOmegaSweepTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch17_omega_sweep_combines_headers_payloads_queries_and_route_parameters(): void
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch17SearchRankingAndPermissionFilterContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_search_autocomplete_and_lookup_do_not_bypass_permission_filters(): void
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch17StudentIdentityMergeSplitContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_merge_split_and_duplicate_student_identity_routes_reject_unsafe_payloads(): void
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch17ZeroTrustInternalHeaderContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_internal_proxy_and_service_headers_do_not_grant_privilege(): void
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch18ApiKeyServiceAccountAndMachineIdentityContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch18_apikeyserviceaccountandmachineidentity_stays_controlled(): void
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch18CanonicalIdentifierImmutabilityContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch18_canonicalidentifierimmutability_stays_controlled(): void
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch18ClassCapacityWaitlistAndScheduleConflictContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch18_classcapacitywaitlistandscheduleconflict_stays_controlled(): void
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch18ConsentRevocationAndCommunicationComplianceContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch18_consentrevocationandcommunicationcompliance_stays_controlled(): void
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch18CrossModuleBusinessInvariantRegisterTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch18_business_invariant_route_families_remain_present(): void
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch18ExportWatermarkAndAuditabilityContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch18_exportwatermarkandauditability_stays_controlled(): void
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch18FeatureEntitlementAndLicenseBoundaryContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch18_featureentitlementandlicenseboundary_stays_controlled(): void
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch18FileVirusScanAndQuarantineContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch18_filevirusscanandquarantine_stays_controlled(): void
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch18FinanceChargebackDisputeContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch18_financechargebackdispute_stays_controlled(): void
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch18OrphanedRecordAndCascadeBoundaryContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch18_orphanedrecordandcascadeboundary_stays_controlled(): void
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch18PrivilegeBoundaryAfterRoleMutationContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch18_privilegeboundaryafterrolemutation_stays_controlled(): void
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch18RegressionFinalitySweepTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch18_combined_hostile_payload_sweep_stays_controlled(): void
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch18ReportDrillthroughAndRowLevelSecurityContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch18_reportdrillthroughandrowlevelsecurity_stays_controlled(): void
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch18StudentMedicalAndSafetyDataMinimizationContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch18_studentmedicalandsafetydataminimization_stays_controlled(): void
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch18TemporalAuditAndTimezoneForgeryContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch18_temporalauditandtimezoneforgery_stays_controlled(): void
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch18TwoPersonApprovalAndSegregationContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch18_twopersonapprovalandsegregation_stays_controlled(): void
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch18WebhookOrderingAndOutOfSequenceContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch18_webhookorderingandoutofsequence_stays_controlled(): void
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch19AggregateDashboardScopeContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch19_aggregate_dashboard_scope_stays_controlled(): void
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch19AppendOnlyAuditLedgerContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch19_append_only_audit_ledger_stays_controlled(): void
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch19AttendanceExcuseDocumentLifecycleContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch19_attendance_excuse_document_lifecycle_stays_controlled(): void
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch19AttributeBasedAccessConditionContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch19_attribute_based_access_condition_stays_controlled(): void
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch19BackupRestoreIsolationContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch19_backup_restore_isolation_stays_controlled(): void
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch19ClassTransferTranscriptContinuityContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch19_class_transfer_transcript_continuity_stays_controlled(): void
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch19CommunicationBounceAndSuppressionWebhookContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch19_communication_bounce_and_suppression_webhook_stays_controlled(): void
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch19CustodyRestrictionPickupAuthorizationContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch19_custody_restriction_pickup_authorization_stays_controlled(): void
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch19NestedRelationshipRedactionContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch19_nested_relationship_redaction_stays_controlled(): void
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch19OperationalAndPrivacyInvariantRegisterTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch19_operational_and_privacy_route_families_remain_present(): void
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch19PaymentAllocationAndBalanceContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch19_payment_allocation_and_balance_stays_controlled(): void
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch19RefundMethodAndSettlementBoundaryContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch19_refund_method_and_settlement_boundary_stays_controlled(): void
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch19RegressionContinuitySweepTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch19_continuity_and_privacy_sweep_stays_controlled(): void
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch19ReportCacheInvalidationContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch19_report_cache_invalidation_stays_controlled(): void
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch19RevokedDeletedUserTokenBoundaryContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch19_revoked_deleted_user_token_boundary_stays_controlled(): void
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch19TeacherSubstitutionCoverageContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch19_teacher_substitution_coverage_stays_controlled(): void
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch19TemporaryUrlExpirationRevocationContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch19_temporary_url_expiration_revocation_stays_controlled(): void
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch19ThirdPartySyncCanonicalizationContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch19_third_party_sync_canonicalization_stays_controlled(): void
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch20AdminAuditExportRedactionContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch20_admin_audit_export_redaction_stays_controlled(): void
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch20ApiSunsetDeprecationAndCompatibilityContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch20_api_sunset_deprecation_and_compatibility_stays_controlled(): void
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch20AttendanceGeofenceAndDeviceTrustContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch20_attendance_geofence_and_device_trust_stays_controlled(): void
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch20CashDrawerManualPaymentIntegrityContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch20_cash_drawer_manual_payment_integrity_stays_controlled(): void
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch20ClassCapacityLotteryAndWaitlistContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch20_class_capacity_lottery_and_waitlist_stays_controlled(): void
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch20ContinuityComplianceRiskRegisterTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch20_continuity_and_compliance_route_families_remain_visible(): void
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ namespace Tests\Feature\Api\V1\FullSurface;
|
||||
|
||||
use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;
|
||||
|
||||
|
||||
class ApiBatch20DataWarehouseAnalyticsExportContractTest extends FullSurfaceE2EContractCase
|
||||
{
|
||||
public function test_batch20_data_warehouse_analytics_export_stays_controlled(): void
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user