superuser()->create()); $target = User::factory()->create(); $response = $this->putJson('/scim/v2/Users/'.$target->id, [ 'schemas' => ['urn:ietf:params:scim:schemas:core:2.0:User'], 'userName' => $target->username, // The bad key: a bare value-path filter with no leading // attribute name. Reproduces the FilterException-from-parser // 500 seen in Rollbar. '[type eq "work"]' => 'newaddress@example.com', ]); $response->assertStatus(400); } public function test_patch_with_malformed_add_value_key_returns_400_not_500(): void { // Same malformed key shape but arriving through the PATCH add() // path (SnipeRootComplex::add()) instead of PUT replace(). Azure // and Entra send add/replace ops without a top-level path field // and put attribute keys inside `value`, so this exercises the // sibling try/catch we added. Passport::actingAs(User::factory()->superuser()->create()); $target = User::factory()->create(); $response = $this->patchJson('/scim/v2/Users/'.$target->id, [ 'schemas' => ['urn:ietf:params:scim:api:messages:2.0:PatchOp'], 'Operations' => [ [ 'op' => 'add', 'value' => [ '[type eq "work"]' => 'newaddress@example.com', ], ], ], ]); $response->assertStatus(400); } }