3535import com .cedarpolicy .model .schema .Schema ;
3636import com .cedarpolicy .pbt .EntityGen ;
3737import com .cedarpolicy .value .EntityTypeName ;
38+ import com .cedarpolicy .value .EntityUID ;
3839import com .cedarpolicy .value .PrimBool ;
3940import com .cedarpolicy .value .PrimString ;
4041
42+ import java .util .HashMap ;
43+ import java .util .HashSet ;
44+
4145/**
4246 * Tests for entity validator
4347 */
@@ -193,6 +197,147 @@ public void testEntityWithUnknownTagWithCedarSchema() throws AuthException {
193197 "Expected to match regex but was: '%s'" .formatted (errMsg ));
194198 }
195199
200+ /**
201+ * Test that valid enum entities are accepted.
202+ */
203+ @ Test
204+ public void testValidEnumEntities () throws AuthException {
205+ // Create valid entities using enum types
206+ EntityTypeName userType = EntityTypeName .parse ("User" ).get ();
207+ EntityTypeName taskType = EntityTypeName .parse ("Task" ).get ();
208+ EntityTypeName colorType = EntityTypeName .parse ("Color" ).get ();
209+
210+ Entity user = new Entity (userType .of ("alice" ), new HashMap <>() {
211+ {
212+ put ("name" , new PrimString ("Alice" ));
213+ }
214+ }, new HashSet <>());
215+
216+ Entity task = new Entity (taskType .of ("task1" ), new HashMap <>() {
217+ {
218+ put ("owner" , user .getEUID ());
219+ put ("name" , new PrimString ("Complete project" ));
220+ put ("status" , new EntityUID (colorType , "Red" ));
221+ }
222+ }, new HashSet <>());
223+
224+ EntityValidationRequest request = new EntityValidationRequest (ENUM_SCHEMA , List .of (user , task ));
225+ engine .validateEntities (request );
226+ }
227+
228+ /**
229+ * Test that enum entities with invalid enum values are rejected.
230+ */
231+ @ Test
232+ public void testEnumEntitiesWithInvalidValues () throws AuthException {
233+ EntityTypeName userType = EntityTypeName .parse ("User" ).get ();
234+ EntityTypeName taskType = EntityTypeName .parse ("Task" ).get ();
235+ EntityTypeName colorType = EntityTypeName .parse ("Color" ).get ();
236+
237+ Entity user = new Entity (userType .of ("alice" ), new HashMap <>() {
238+ {
239+ put ("name" , new PrimString ("Alice" ));
240+ }
241+ }, new HashSet <>());
242+
243+ // Create task with invalid enum value "Purple" (not in Color enum)
244+ Entity task = new Entity (taskType .of ("task1" ), new HashMap <>() {
245+ {
246+ put ("owner" , user .getEUID ());
247+ put ("name" , new PrimString ("Complete project" ));
248+ put ("status" , new EntityUID (colorType , "Purple" )); // Invalid enum value
249+ }
250+ }, new HashSet <>());
251+
252+ EntityValidationRequest request = new EntityValidationRequest (ENUM_SCHEMA , List .of (user , task ));
253+
254+ BadRequestException exception = assertThrows (BadRequestException .class , () -> engine .validateEntities (request ));
255+
256+ String errMsg = exception .getErrors ().get (0 );
257+ assertTrue (errMsg .contains ("Purple" ) || errMsg .contains ("Color" ),
258+ "Expected error about invalid enum value but was: '%s'" .formatted (errMsg ));
259+ }
260+
261+ /**
262+ * Test that enum entities cannot have attributes.
263+ */
264+ @ Test
265+ public void testEnumEntitiesCannotHaveAttributes () throws AuthException {
266+ EntityTypeName colorType = EntityTypeName .parse ("Color" ).get ();
267+
268+ // Try to create enum entity with attributes (should fail)
269+ Entity enumEntity = new Entity (colorType .of ("Red" ), new HashMap <>() {
270+ {
271+ put ("shade" , new PrimString ("Dark" )); // Enum entities shouldn't have attributes
272+ }
273+ }, new HashSet <>());
274+
275+ EntityValidationRequest request = new EntityValidationRequest (ENUM_SCHEMA , List .of (enumEntity ));
276+
277+ BadRequestException exception = assertThrows (BadRequestException .class , () -> engine .validateEntities (request ));
278+
279+ String errMsg = exception .getErrors ().get (0 );
280+ assertTrue (errMsg .contains ("attribute" ) && (errMsg .contains ("Color" ) || errMsg .contains ("Red" )),
281+ "Expected error about enum entity having attributes but was: '%s'" .formatted (errMsg ));
282+ }
283+
284+ /**
285+ * Test that enum entities cannot have parents.
286+ */
287+ @ Test
288+ public void testEnumEntitiesCannotHaveParents () throws AuthException {
289+ EntityTypeName colorType = EntityTypeName .parse ("Color" ).get ();
290+ EntityTypeName userType = EntityTypeName .parse ("User" ).get ();
291+
292+ Entity user = new Entity (userType .of ("alice" ), new HashMap <>() {
293+ {
294+ put ("name" , new PrimString ("Alice" ));
295+ }
296+ }, new HashSet <>());
297+
298+ // Try to create enum entity with parent (should fail)
299+ Entity enumEntity = new Entity (colorType .of ("Red" ), new HashMap <>(), new HashSet <>() {
300+ {
301+ add (user .getEUID ()); // Enum entities shouldn't have parents
302+ }
303+ });
304+
305+ EntityValidationRequest request = new EntityValidationRequest (ENUM_SCHEMA , List .of (user , enumEntity ));
306+
307+ BadRequestException exception = assertThrows (BadRequestException .class , () -> engine .validateEntities (request ));
308+
309+ String errMsg = exception .getErrors ().get (0 );
310+ assertTrue (errMsg .contains ("parent" ) || errMsg .contains ("ancestor" ) || errMsg .contains ("Color" ),
311+ "Expected error about enum entity having parents but was: '%s'" .formatted (errMsg ));
312+ }
313+
314+ /**
315+ * Test enum entity validation with Cedar schema format.
316+ */
317+ @ Test
318+ public void testEnumEntitiesWithCedarSchema () throws AuthException {
319+ EntityTypeName userType = EntityTypeName .parse ("User" ).get ();
320+ EntityTypeName taskType = EntityTypeName .parse ("Task" ).get ();
321+ EntityTypeName colorType = EntityTypeName .parse ("Color" ).get ();
322+
323+ Entity user = new Entity (userType .of ("bob" ), new HashMap <>() {
324+ {
325+ put ("name" , new PrimString ("Bob" ));
326+ }
327+ }, new HashSet <>());
328+
329+ Entity task = new Entity (taskType .of ("task2" ), new HashMap <>() {
330+ {
331+ put ("owner" , user .getEUID ());
332+ put ("name" , new PrimString ("Review code" ));
333+ put ("status" , new EntityUID (colorType , "Green" ));
334+ }
335+ }, new HashSet <>());
336+
337+ EntityValidationRequest cedarRequest = new EntityValidationRequest (ENUM_SCHEMA_CEDAR , List .of (user , task ));
338+ engine .validateEntities (cedarRequest );
339+ }
340+
196341 @ BeforeAll
197342 public static void setUp () {
198343
@@ -204,4 +349,6 @@ public static void setUp() {
204349
205350 private static final Schema ROLE_SCHEMA = loadSchemaResource ("/role_schema.json" );
206351 private static final Schema ROLE_SCHEMA_CEDAR = loadCedarSchemaResource ("/role_schema.cedarschema" );
352+ private static final Schema ENUM_SCHEMA = loadSchemaResource ("/enum_schema.json" );
353+ private static final Schema ENUM_SCHEMA_CEDAR = loadCedarSchemaResource ("/enum_schema.cedarschema" );
207354}
0 commit comments