1use cedar_policy_core::extensions::Extensions;
27use cedar_policy_core::validator::SchemaError;
28
29use super::{Schema, SchemaFragment};
30
31impl SchemaFragment {
32 #[deprecated(
36 since = "4.5.0",
37 note = "use `SchemaFragment::from_json_value` instead"
38 )]
39 pub fn from_deprecated_json_value(json: serde_json::Value) -> Result<Self, SchemaError> {
40 let lossless =
41 cedar_policy_core::validator::json_schema::Fragment::from_deprecated_json_value(json)?;
42 Ok(Self {
43 value: lossless.clone().try_into()?,
44 lossless,
45 })
46 }
47
48 #[deprecated(since = "4.5.0", note = "use `SchemaFragment::from_json_str` instead")]
52 pub fn from_deprecated_json_str(src: &str) -> Result<Self, SchemaError> {
53 let lossless =
54 cedar_policy_core::validator::json_schema::Fragment::from_deprecated_json_str(src)?;
55 Ok(Self {
56 value: lossless.clone().try_into()?,
57 lossless,
58 })
59 }
60
61 #[deprecated(since = "4.5.0", note = "use `SchemaFragment::from_json_file` instead")]
66 pub fn from_deprecated_json_file(file: impl std::io::Read) -> Result<Self, SchemaError> {
67 let lossless =
68 cedar_policy_core::validator::json_schema::Fragment::from_deprecated_json_file(file)?;
69 Ok(Self {
70 value: lossless.clone().try_into()?,
71 lossless,
72 })
73 }
74}
75
76impl Schema {
77 #[deprecated(since = "4.5.0", note = "use `Schema::from_json_str` instead")]
81 pub fn from_deprecated_json_value(json: serde_json::Value) -> Result<Self, SchemaError> {
82 Ok(Self(
83 cedar_policy_core::validator::ValidatorSchema::from_deprecated_json_value(
84 json,
85 Extensions::all_available(),
86 )?,
87 ))
88 }
89
90 #[deprecated(since = "4.5.0", note = "use `Schema::from_json_value` instead")]
94 pub fn from_deprecated_json_str(json: &str) -> Result<Self, SchemaError> {
95 Ok(Self(
96 cedar_policy_core::validator::ValidatorSchema::from_deprecated_json_str(
97 json,
98 Extensions::all_available(),
99 )?,
100 ))
101 }
102
103 #[deprecated(since = "4.5.0", note = "use `Schema::from_json_file` instead")]
107 pub fn from_deprecated_json_file(file: impl std::io::Read) -> Result<Self, SchemaError> {
108 Ok(Self(
109 cedar_policy_core::validator::ValidatorSchema::from_deprecated_json_file(
110 file,
111 Extensions::all_available(),
112 )?,
113 ))
114 }
115}
116
117#[cfg(test)]
118#[expect(deprecated, reason = "testing deprecated functionality")]
119mod test_utils {
120 use cedar_policy_core::test_utils::{
121 expect_err, ExpectedErrorMessage, ExpectedErrorMessageBuilder,
122 };
123 use miette::Report;
124 use serde_json::json;
125
126 use crate::Schema;
127
128 fn schema_with_entity_attribute(attr_ty: &serde_json::Value) -> serde_json::Value {
129 json!({
130 "ns": {
131 "commonTypes": {"ty": {"type": "Long"}},
132 "entityTypes": {
133 "User": {
134 "shape": {
135 "type": "Record",
136 "attributes": {
137 "foo": attr_ty,
138 },
139 },
140 }
141 },
142 "actions": {},
143 }
144 })
145 }
146
147 fn schema_with_context_attribute(attr_ty: &serde_json::Value) -> serde_json::Value {
148 json!({
149 "ns": {
150 "commonTypes": {"ty": {"type": "Long"}},
151 "entityTypes": {
152 "User": {}
153 },
154 "actions": {
155 "Act": {
156 "appliesTo": {
157 "principalTypes": [],
158 "resourceTypes": [],
159 "context": {
160 "type": "Record",
161 "attributes": {
162 "foo": attr_ty,
163 },
164 }
165 }
166 }
167 },
168 }
169 })
170 }
171
172 fn schema_with_common_type(ty: &serde_json::Value) -> serde_json::Value {
173 json!({
174 "ns": {
175 "commonTypes": {
176 "ty": {"type": "Long"},
177 "ty2": ty,
178 },
179 "entityTypes": {
180 "User": {}
181 },
182 "actions": {},
183 }
184 })
185 }
186
187 #[track_caller]
188 pub(crate) fn assert_type_json_ok_deprecated_and_err_standard(
189 ty: &serde_json::Value,
190 err: &str,
191 ) {
192 let in_entity_attr = schema_with_entity_attribute(ty);
193 Schema::from_deprecated_json_value(in_entity_attr.clone()).unwrap();
194 expect_err(
195 "",
196 &Report::new(Schema::from_json_value(in_entity_attr).unwrap_err()),
197 &ExpectedErrorMessageBuilder::error(err).build(),
198 );
199 let in_context = schema_with_context_attribute(ty);
200 Schema::from_deprecated_json_value(in_context.clone()).unwrap();
201 expect_err(
202 "",
203 &Report::new(Schema::from_json_value(in_context).unwrap_err()),
204 &ExpectedErrorMessageBuilder::error(err).build(),
205 );
206 let in_common = schema_with_common_type(ty);
207 Schema::from_deprecated_json_value(in_common.clone()).unwrap();
208 expect_err(
209 "",
210 &Report::new(Schema::from_json_value(in_common).unwrap_err()),
211 &ExpectedErrorMessageBuilder::error(err).build(),
212 );
213 }
214
215 #[track_caller]
216 pub(crate) fn assert_type_json_ok_deprecated_and_standard(ty: &serde_json::Value) {
217 let in_entity_attr = schema_with_entity_attribute(ty);
218 Schema::from_deprecated_json_value(in_entity_attr.clone()).unwrap();
219 Schema::from_json_value(in_entity_attr).unwrap();
220 let in_context = schema_with_context_attribute(ty);
221 Schema::from_deprecated_json_value(in_context.clone()).unwrap();
222 Schema::from_json_value(in_context).unwrap();
223 let in_common = schema_with_common_type(ty);
224 Schema::from_deprecated_json_value(in_common.clone()).unwrap();
225 Schema::from_json_value(in_common).unwrap();
226 }
227
228 #[track_caller]
229 pub(crate) fn assert_type_json_err_deprecated_and_standard(
230 ty: &serde_json::Value,
231 current_err: &ExpectedErrorMessage<'_>,
232 deprecated_err: &ExpectedErrorMessage<'_>,
233 ) {
234 let in_entity_attr = schema_with_entity_attribute(ty);
235 assert_schema_json_err_deprecated_and_standard(in_entity_attr, current_err, deprecated_err);
236 let in_context = schema_with_context_attribute(ty);
237 assert_schema_json_err_deprecated_and_standard(in_context, current_err, deprecated_err);
238 let in_common = schema_with_common_type(ty);
239 assert_schema_json_err_deprecated_and_standard(in_common, current_err, deprecated_err);
240 }
241
242 #[track_caller]
243 pub(crate) fn assert_schema_json_err_deprecated_and_standard(
244 schema: serde_json::Value,
245 current_err: &ExpectedErrorMessage<'_>,
246 deprecated_err: &ExpectedErrorMessage<'_>,
247 ) {
248 expect_err(
249 "",
250 &Report::new(Schema::from_json_value(schema.clone()).unwrap_err()),
251 current_err,
252 );
253 expect_err(
254 "",
255 &Report::new(Schema::from_deprecated_json_value(schema).unwrap_err()),
256 deprecated_err,
257 );
258 }
259}
260
261#[cfg(test)]
264mod extra_fields_allowed {
265 use super::test_utils::*;
266 use serde_json::json;
267
268 #[test]
269 fn in_long() {
270 assert_type_json_ok_deprecated_and_err_standard(
271 &json!({
272 "type": "Long",
273 "bogus": "bogus",
274 }),
275 "unknown field `bogus`, expected one of `type`, `element`, `attributes`, `additionalAttributes`, `name`",
276 );
277 assert_type_json_ok_deprecated_and_err_standard(
278 &json!({
279 "type": "Long",
280 "name": "my_long",
281 }),
282 "unknown field `name`, there are no fields",
283 );
284 assert_type_json_ok_deprecated_and_err_standard(
285 &json!({
286 "type": "Long",
287 "element": "bogus"
288 }),
289 "invalid type: string \"bogus\", expected builtin type or reference to type defined in commonTypes",
290 );
291 assert_type_json_ok_deprecated_and_err_standard(
292 &json!({
293 "type": "Long",
294 "attributes": "bogus",
295 }),
296 "invalid type: string \"bogus\", expected a map",
297 );
298 assert_type_json_ok_deprecated_and_err_standard(
299 &json!({
300 "type": "Long",
301 "additionalAttributes": "bogus",
302 }),
303 "invalid type: string \"bogus\", expected a boolean",
304 );
305 assert_type_json_ok_deprecated_and_standard(&json!({
306 "type": "Long",
307 "annotations": {},
308 }));
309 }
310
311 #[test]
312 fn in_bool() {
313 assert_type_json_ok_deprecated_and_err_standard(
314 &json!({
315 "type": "Boolean",
316 "bogus": "bogus",
317 }),
318 "unknown field `bogus`, expected one of `type`, `element`, `attributes`, `additionalAttributes`, `name`",
319 );
320 assert_type_json_ok_deprecated_and_err_standard(
321 &json!({
322 "type": "Boolean",
323 "name": "my_long",
324 }),
325 "unknown field `name`, there are no fields",
326 );
327 assert_type_json_ok_deprecated_and_err_standard(
328 &json!({
329 "type": "Boolean",
330 "element": "bogus",
331 }),
332 "invalid type: string \"bogus\", expected builtin type or reference to type defined in commonTypes",
333 );
334 assert_type_json_ok_deprecated_and_err_standard(
335 &json!({
336 "type": "Boolean",
337 "attributes": "bogus",
338 }),
339 "invalid type: string \"bogus\", expected a map",
340 );
341 assert_type_json_ok_deprecated_and_err_standard(
342 &json!({
343 "type": "Boolean",
344 "additionalAttributes": "bogus",
345 }),
346 "invalid type: string \"bogus\", expected a boolean",
347 );
348 assert_type_json_ok_deprecated_and_standard(&json!({
349 "type": "Boolean",
350 "annotations": {},
351 }));
352 }
353
354 #[test]
355 fn in_string() {
356 assert_type_json_ok_deprecated_and_err_standard(
357 &json!({
358 "type": "String",
359 "bogus": "bogus",
360 }),
361 "unknown field `bogus`, expected one of `type`, `element`, `attributes`, `additionalAttributes`, `name`",
362 );
363 assert_type_json_ok_deprecated_and_err_standard(
364 &json!({
365 "type": "String",
366 "name": "bogus",
367 }),
368 "unknown field `name`, there are no fields",
369 );
370 assert_type_json_ok_deprecated_and_err_standard(
371 &json!({
372 "type": "String",
373 "element": {"type": "Long"}
374 }),
375 "unknown field `element`, there are no fields",
376 );
377 assert_type_json_ok_deprecated_and_err_standard(
378 &json!({
379 "type": "String",
380 "attributes": {},
381 }),
382 "unknown field `attributes`, there are no fields",
383 );
384 assert_type_json_ok_deprecated_and_err_standard(
385 &json!({
386 "type": "String",
387 "additionalAttributes": false,
388 }),
389 "unknown field `additionalAttributes`, there are no fields",
390 );
391 assert_type_json_ok_deprecated_and_standard(&json!({
392 "type": "String",
393 "annotations": {},
394 }));
395 }
396
397 #[test]
398 fn in_common() {
399 assert_type_json_ok_deprecated_and_err_standard(
400 &json!({
401 "type": "ty",
402 "bogus": "bogus",
403 }),
404 "unknown field `bogus`, expected one of `type`, `element`, `attributes`, `additionalAttributes`, `name`",
405 );
406 assert_type_json_ok_deprecated_and_err_standard(
407 &json!({
408 "type": "ty",
409 "name": "my_long",
410 }),
411 "unknown field `name`, there are no fields",
412 );
413 assert_type_json_ok_deprecated_and_err_standard(
414 &json!({
415 "type": "ty",
416 "element": 10,
417 }),
418 "invalid type: integer `10`, expected builtin type or reference to type defined in commonTypes",
419 );
420 assert_type_json_ok_deprecated_and_err_standard(
421 &json!({
422 "type": "ty",
423 "attributes": ["bogus"],
424 }),
425 "invalid type: sequence, expected a map",
426 );
427 assert_type_json_ok_deprecated_and_err_standard(
428 &json!({
429 "type": "ty",
430 "additionalAttributes": {"bogus": "bogus"},
431 }),
432 "invalid type: map, expected a boolean",
433 );
434 assert_type_json_ok_deprecated_and_standard(&json!({
435 "type": "ty",
436 "annotations": {},
437 }));
438 }
439
440 #[test]
441 fn in_set_elem() {
442 assert_type_json_ok_deprecated_and_err_standard(
443 &json!({
444 "type": "Set",
445 "element": {"type": "Long", "name": "my_long"},
446 }),
447 "unknown field `name`, there are no fields",
448 );
449 }
450
451 #[test]
452 fn in_record_attr() {
453 assert_type_json_ok_deprecated_and_err_standard(
454 &json!({
455 "type": "Record",
456 "attributes": { "a": {"type": "Long", "name": "foo"} },
457 }),
458 "unknown field `name`, there are no fields",
459 );
460 }
461}
462
463#[cfg(test)]
465mod extra_fields_forbidden {
466 use super::test_utils::*;
467 use cedar_policy_core::test_utils::ExpectedErrorMessageBuilder;
468 use serde_json::json;
469
470 #[test]
471 fn in_set() {
472 assert_type_json_err_deprecated_and_standard(
473 &json!({
474 "type": "Set",
475 "element": {"type": "Long"},
476 "bogus": "bogus",
477 }),
478 &ExpectedErrorMessageBuilder::error("unknown field `bogus`, expected one of `type`, `element`, `attributes`, `additionalAttributes`, `name`")
479 .build(),
480 &ExpectedErrorMessageBuilder::error("failed to resolve type: Set")
481 .help("neither `ns::Set` nor `Set` refers to anything that has been declared as a common type")
482 .exactly_one_underline("Set")
483 .build(),
484 );
485 assert_type_json_err_deprecated_and_standard(
486 &json!({
487 "type": "Set",
488 "element": {"type": "Long"},
489 "name": "my_long",
490 }),
491 &ExpectedErrorMessageBuilder::error("unknown field `name`, expected `element`")
492 .build(),
493 &ExpectedErrorMessageBuilder::error("failed to resolve type: Set")
494 .help("neither `ns::Set` nor `Set` refers to anything that has been declared as a common type")
495 .exactly_one_underline("Set")
496 .build(),
497 );
498
499 assert_type_json_err_deprecated_and_standard(
500 &json!({
501 "type": "Set",
502 "element": {"type": "Long"},
503 "attributes": {},
504 }),
505 &ExpectedErrorMessageBuilder::error("unknown field `attributes`, expected `element`")
506 .build(),
507 &ExpectedErrorMessageBuilder::error("failed to resolve type: Set")
508 .help("neither `ns::Set` nor `Set` refers to anything that has been declared as a common type")
509 .exactly_one_underline("Set")
510 .build(),
511 );
512 assert_type_json_err_deprecated_and_standard(
513 &json!({
514 "type": "Set",
515 "element": {"type": "Long"},
516 "additionalAttributes": false,
517 }),
518 &ExpectedErrorMessageBuilder::error("unknown field `additionalAttributes`, expected `element`")
519 .build(),
520 &ExpectedErrorMessageBuilder::error("failed to resolve type: Set")
521 .help("neither `ns::Set` nor `Set` refers to anything that has been declared as a common type")
522 .exactly_one_underline("Set")
523 .build(),
524 );
525 }
526
527 #[test]
528 fn in_entity() {
529 assert_type_json_err_deprecated_and_standard(
530 &json!({
531 "type": "Entity",
532 "name": "User",
533 "bogus": "bogus",
534 }),
535 &ExpectedErrorMessageBuilder::error("unknown field `bogus`, expected one of `type`, `element`, `attributes`, `additionalAttributes`, `name`")
536 .build(),
537 &ExpectedErrorMessageBuilder::error("failed to resolve type: Entity")
538 .help("neither `ns::Entity` nor `Entity` refers to anything that has been declared as a common type")
539 .exactly_one_underline("Entity")
540 .build(),
541 );
542 assert_type_json_err_deprecated_and_standard(
543 &json!({
544 "type": "Entity",
545 "name": "User",
546 "element": {"type": "Long"},
547 }),
548 &ExpectedErrorMessageBuilder::error("unknown field `element`, expected `name`")
549 .build(),
550 &ExpectedErrorMessageBuilder::error("failed to resolve type: Entity")
551 .help("neither `ns::Entity` nor `Entity` refers to anything that has been declared as a common type")
552 .exactly_one_underline("Entity")
553 .build(),
554 );
555 assert_type_json_err_deprecated_and_standard(
556 &json!({
557 "type": "Entity",
558 "name": "User",
559 "attributes": {},
560 }),
561 &ExpectedErrorMessageBuilder::error("unknown field `attributes`, expected `name`")
562 .build(),
563 &ExpectedErrorMessageBuilder::error("failed to resolve type: Entity")
564 .help("neither `ns::Entity` nor `Entity` refers to anything that has been declared as a common type")
565 .exactly_one_underline("Entity")
566 .build(),
567 );
568 assert_type_json_err_deprecated_and_standard(
569 &json!({
570 "type": "Entity",
571 "name": "User",
572 "additionalAttributes": false,
573 }),
574 &ExpectedErrorMessageBuilder::error( "unknown field `additionalAttributes`, expected `name`",)
575 .build(),
576 &ExpectedErrorMessageBuilder::error( "failed to resolve type: Entity",)
577 .help("neither `ns::Entity` nor `Entity` refers to anything that has been declared as a common type")
578 .exactly_one_underline("Entity")
579 .build(),
580 );
581 }
582
583 #[test]
584 fn in_extension() {
585 assert_type_json_err_deprecated_and_standard(
586 &json!({
587 "type": "Extension",
588 "name": "ip",
589 "bogus": "bogus"
590 }),
591 &ExpectedErrorMessageBuilder::error("unknown field `bogus`, expected one of `type`, `element`, `attributes`, `additionalAttributes`, `name`")
592 .build(),
593 &ExpectedErrorMessageBuilder::error("failed to resolve type: Extension")
594 .help("neither `ns::Extension` nor `Extension` refers to anything that has been declared as a common type")
595 .exactly_one_underline("Extension")
596 .build(),
597 );
598 assert_type_json_err_deprecated_and_standard(
599 &json!({
600 "type": "Extension",
601 "name": "ip",
602 "element": {"type": "Long"},
603 }),
604 &ExpectedErrorMessageBuilder::error("unknown field `element`, expected `name`")
605 .build(),
606 &ExpectedErrorMessageBuilder::error("failed to resolve type: Extension")
607 .help("neither `ns::Extension` nor `Extension` refers to anything that has been declared as a common type")
608 .exactly_one_underline("Extension")
609 .build(),
610 );
611 assert_type_json_err_deprecated_and_standard(
612 &json!({
613 "type": "Extension",
614 "name": "ip",
615 "attributes": {},
616 }),
617 &ExpectedErrorMessageBuilder::error("unknown field `attributes`, expected `name`")
618 .build(),
619 &ExpectedErrorMessageBuilder::error("failed to resolve type: Extension")
620 .help("neither `ns::Extension` nor `Extension` refers to anything that has been declared as a common type")
621 .exactly_one_underline("Extension")
622 .build(),
623 );
624 assert_type_json_err_deprecated_and_standard(
625 &json!({
626 "type": "Extension",
627 "name": "ip",
628 "additionalAttributes": false,
629 }),
630 &ExpectedErrorMessageBuilder::error( "unknown field `additionalAttributes`, expected `name`",)
631 .build(),
632 &ExpectedErrorMessageBuilder::error("failed to resolve type: Extension")
633 .help("neither `ns::Extension` nor `Extension` refers to anything that has been declared as a common type")
634 .exactly_one_underline("Extension")
635 .build(),
636 );
637 }
638
639 #[test]
640 fn in_record() {
641 assert_type_json_err_deprecated_and_standard(
642 &json!({
643 "type": "Record",
644 "attributes": {},
645 "bogus": "bogus"
646 }),
647 &ExpectedErrorMessageBuilder::error("unknown field `bogus`, expected one of `type`, `element`, `attributes`, `additionalAttributes`, `name`")
648 .build(),
649 &ExpectedErrorMessageBuilder::error("failed to resolve type: Record")
650 .help("neither `ns::Record` nor `Record` refers to anything that has been declared as a common type")
651 .exactly_one_underline("Record")
652 .build(),
653 );
654 assert_type_json_err_deprecated_and_standard(
655 &json!({
656 "type": "Record",
657 "attributes": {},
658 "element": {"type": "Long"},
659 }),
660 &ExpectedErrorMessageBuilder::error( "unknown field `element`, expected `attributes` or `additionalAttributes`",)
661 .build(),
662 &ExpectedErrorMessageBuilder::error( "failed to resolve type: Record",)
663 .help("neither `ns::Record` nor `Record` refers to anything that has been declared as a common type")
664 .exactly_one_underline("Record")
665 .build(),
666 );
667 assert_type_json_err_deprecated_and_standard(
668 &json!({
669 "type": "Record",
670 "attributes": {},
671 "name": "ip",
672 }),
673 &ExpectedErrorMessageBuilder::error( "unknown field `name`, expected `attributes` or `additionalAttributes`",)
674 .build(),
675 &ExpectedErrorMessageBuilder::error( "failed to resolve type: Record",)
676 .help("neither `ns::Record` nor `Record` refers to anything that has been declared as a common type")
677 .exactly_one_underline("Record")
678 .build(),
679 );
680 }
681
682 #[test]
683 fn in_namespace() {
684 assert_schema_json_err_deprecated_and_standard(
685 json!({
686 "ns": {
687 "entityTypes": {},
688 "actions": {},
689 "commonTypes": {},
690 "foo": {},
691 }
692 }),
693 &ExpectedErrorMessageBuilder::error("unknown field `foo`, expected one of `commonTypes`, `entityTypes`, `actions`, `annotations`").build(),
694 &ExpectedErrorMessageBuilder::error("unknown field `foo`, expected one of `commonTypes`, `entityTypes`, `actions`").build(),
695 );
696 }
697
698 #[test]
699 fn in_entity_type() {
700 assert_schema_json_err_deprecated_and_standard(
701 json!({
702 "ns": {
703 "entityTypes": {
704 "User": {
705 "foo": {},
706 }
707 },
708 "actions": {},
709 }
710 }),
711 &ExpectedErrorMessageBuilder::error("unknown field `foo`, expected one of `memberOfTypes`, `shape`, `tags`, `enum`, `annotations`").build(),
712 &ExpectedErrorMessageBuilder::error("unknown field `foo`, expected `memberOfTypes` or `shape`").build(),
713 );
714 }
715
716 #[test]
717 fn in_action() {
718 assert_schema_json_err_deprecated_and_standard(
719 json!({
720 "ns": {
721 "entityTypes": {
722 },
723 "actions": {
724 "act": {
725 "foo": {}
726 },
727 },
728 }
729 }),
730 &ExpectedErrorMessageBuilder::error("unknown field `foo`, expected one of `attributes`, `appliesTo`, `memberOf`, `annotations`").build(),
731 &ExpectedErrorMessageBuilder::error("unknown field `foo`, expected one of `attributes`, `appliesTo`, `memberOf`").build(),
732 );
733 }
734
735 #[test]
736 fn in_applies_to() {
737 assert_schema_json_err_deprecated_and_standard(
738 json!({
739 "ns": {
740 "entityTypes": { },
741 "actions": {
742 "act": {
743 "appliesTo": {
744 "principalTypes": [],
745 "resourceTypes": [],
746 "foo": {},
747 }
748 },
749 },
750 }
751 }),
752 &ExpectedErrorMessageBuilder::error(
753 "unknown field `foo`, expected one of `resourceTypes`, `principalTypes`, `context`",
754 )
755 .build(),
756 &ExpectedErrorMessageBuilder::error(
757 "unknown field `foo`, expected one of `resourceTypes`, `principalTypes`, `context`",
758 )
759 .build(),
760 );
761 }
762}
763
764#[cfg(test)]
766mod unspecified_not_allowed {
767 use cedar_policy_core::test_utils::ExpectedErrorMessageBuilder;
768 use serde_json::json;
769
770 use super::test_utils::*;
771
772 #[test]
773 fn missing_principal() {
774 assert_schema_json_err_deprecated_and_standard(
775 json!({
776 "ns": {
777 "entityTypes": { },
778 "actions": {
779 "act": {
780 "appliesTo": {
781 "resourceTypes": [],
782 }
783 },
784 },
785 }
786 }),
787 &ExpectedErrorMessageBuilder::error("missing field `principalTypes`").build(),
788 &ExpectedErrorMessageBuilder::error("missing field `principalTypes`").build(),
789 );
790 }
791
792 #[test]
793 fn missing_resource() {
794 assert_schema_json_err_deprecated_and_standard(
795 json!({
796 "ns": {
797 "entityTypes": { },
798 "actions": {
799 "act": {
800 "appliesTo": {
801 "principalTypes": [],
802 }
803 },
804 },
805 }
806 }),
807 &ExpectedErrorMessageBuilder::error("missing field `resourceTypes`").build(),
808 &ExpectedErrorMessageBuilder::error("missing field `resourceTypes`").build(),
809 );
810 }
811
812 #[test]
813 fn missing_both() {
814 assert_schema_json_err_deprecated_and_standard(
815 json!({
816 "ns": {
817 "entityTypes": { },
818 "actions": {
819 "act": {
820 "appliesTo": { }
821 },
822 },
823 }
824 }),
825 &ExpectedErrorMessageBuilder::error("missing field `resourceTypes`").build(),
826 &ExpectedErrorMessageBuilder::error("missing field `resourceTypes`").build(),
827 );
828 }
829
830 #[test]
831 fn null_values() {
832 assert_schema_json_err_deprecated_and_standard(
833 json!({
834 "ns": {
835 "entityTypes": { },
836 "actions": {
837 "act": {
838 "appliesTo": {
839 "principalTypes": [],
840 "resourceTypes": null
841 }
842 },
843 },
844 }
845 }),
846 &ExpectedErrorMessageBuilder::error("invalid type: null, expected a sequence").build(),
847 &ExpectedErrorMessageBuilder::error("missing field `resourceTypes`").build(),
848 );
849 assert_schema_json_err_deprecated_and_standard(
850 json!({
851 "ns": {
852 "entityTypes": { },
853 "actions": {
854 "act": {
855 "appliesTo": {
856 "principalTypes": null,
857 "resourceTypes": [],
858 }
859 },
860 },
861 }
862 }),
863 &ExpectedErrorMessageBuilder::error("invalid type: null, expected a sequence").build(),
864 &ExpectedErrorMessageBuilder::error("missing field `principalTypes`").build(),
865 );
866 }
867}
868
869#[cfg(test)]
870mod invalid_names_detected {
871 use cedar_policy_core::test_utils::ExpectedErrorMessageBuilder;
872 use serde_json::json;
873
874 use super::test_utils::*;
875
876 #[test]
877 fn in_namespace() {
878 assert_schema_json_err_deprecated_and_standard(
879 json!({
880 " space": {
881 "entityTypes": { },
882 "actions": { },
883 }
884 }),
885 &ExpectedErrorMessageBuilder::error("invalid namespace ` space`: `Name` needs to be normalized (e.g., whitespace removed): space").build(),
886 &ExpectedErrorMessageBuilder::error("invalid namespace ` space`: `Name` needs to be normalized (e.g., whitespace removed): space").build(),
887 );
888 }
889
890 #[test]
891 fn in_common_type() {
892 assert_schema_json_err_deprecated_and_standard(
893 json!({
894 "ns": {
895 "commonTypes": {
896 " space": {"type": "Long"}
897 },
898 "entityTypes": { },
899 "actions": { },
900 }
901 }),
902 &ExpectedErrorMessageBuilder::error("invalid id ` space`: `Id` needs to be normalized (e.g., whitespace removed): space").build(),
903 &ExpectedErrorMessageBuilder::error("invalid id ` space`: `Id` needs to be normalized (e.g., whitespace removed): space").build(),
904 );
905 }
906
907 #[test]
908 fn in_common_type_ref() {
909 assert_schema_json_err_deprecated_and_standard(
910 json!({
911 "ns": {
912 "entityTypes": {
913 "User": {
914 "shape": {
915 "type": "Record",
916 "attributes": {
917 "foo": {"type": " space"}
918 }
919 }
920 }
921 },
922 "actions": { },
923 }
924 }),
925 &ExpectedErrorMessageBuilder::error("invalid common type ` space`: `internal name` needs to be normalized (e.g., whitespace removed): space").build(),
926 &ExpectedErrorMessageBuilder::error("invalid common type ` space`: `internal name` needs to be normalized (e.g., whitespace removed): space").build(),
927 );
928 }
929
930 #[test]
931 fn reserved_common_type() {
932 assert_schema_json_err_deprecated_and_standard(
933 json!({
934 "ns": {
935 "commonTypes": {
936 "Long": {"type": "Long"}
937 },
938 "entityTypes": { },
939 "actions": { },
940 }
941 }),
942 &ExpectedErrorMessageBuilder::error(
943 "this is reserved and cannot be the basename of a common-type declaration: Long",
944 )
945 .build(),
946 &ExpectedErrorMessageBuilder::error(
947 "this is reserved and cannot be the basename of a common-type declaration: Long",
948 )
949 .build(),
950 );
951 }
952
953 #[test]
954 fn in_entity_type() {
955 assert_schema_json_err_deprecated_and_standard(
956 json!({
957 "ns": {
958 "entityTypes": {
959 " space": { }
960 },
961 "actions": { },
962 }
963 }),
964 &ExpectedErrorMessageBuilder::error("invalid id ` space`: `Id` needs to be normalized (e.g., whitespace removed): space").build(),
965 &ExpectedErrorMessageBuilder::error("invalid id ` space`: `Id` needs to be normalized (e.g., whitespace removed): space").build(),
966 );
967 }
968
969 #[test]
970 fn in_member_of_types() {
971 assert_schema_json_err_deprecated_and_standard(
972 json!({
973 "ns": {
974 "entityTypes": {
975 "User": {
976 "memberOfTypes": [" User"]
977 }
978 },
979 "actions": { },
980 }
981 }),
982 &ExpectedErrorMessageBuilder::error("invalid name ` User`: `internal name` needs to be normalized (e.g., whitespace removed): User").build(),
983 &ExpectedErrorMessageBuilder::error("invalid name ` User`: `internal name` needs to be normalized (e.g., whitespace removed): User").build(),
984 );
985 }
986
987 #[test]
988 fn in_entity_type_ref() {
989 assert_schema_json_err_deprecated_and_standard(
990 json!({
991 "ns": {
992 "entityTypes": {
993 "User": {
994 "shape": {
995 "type": "Record",
996 "attributes": {
997 "foo": {"type": "Entity", "name": " space"}
998 }
999 }
1000 }
1001 },
1002 "actions": { },
1003 }
1004 }),
1005 &ExpectedErrorMessageBuilder::error("invalid entity type ` space`: `internal name` needs to be normalized (e.g., whitespace removed): space").build(),
1006 &ExpectedErrorMessageBuilder::error("invalid entity type ` space`: `internal name` needs to be normalized (e.g., whitespace removed): space").build(),
1007 );
1008 }
1009
1010 #[test]
1011 fn in_extension_type() {
1012 assert_schema_json_err_deprecated_and_standard(
1013 json!({
1014 "ns": {
1015 "entityTypes": {
1016 "User": {
1017 "shape": {
1018 "type": "Record",
1019 "attributes": {
1020 "foo": {"type": "Extension", "name": " ip"}
1021 }
1022 }
1023 }
1024 },
1025 "actions": { },
1026 }
1027 }),
1028 &ExpectedErrorMessageBuilder::error("invalid extension type ` ip`: `Unreserved Id` needs to be normalized (e.g., whitespace removed): ip").build(),
1029 &ExpectedErrorMessageBuilder::error("invalid extension type ` ip`: `Unreserved Id` needs to be normalized (e.g., whitespace removed): ip").build(),
1030 );
1031 }
1032
1033 #[test]
1034 fn in_applies_to_principals() {
1035 assert_schema_json_err_deprecated_and_standard(
1036 json!({
1037 "ns": {
1038 "entityTypes": { },
1039 "actions": {
1040 "act": {
1041 "appliesTo": {
1042 "principalTypes": [" User"],
1043 "resourceTypes": [],
1044 }
1045 }
1046 },
1047 }
1048 }),
1049 &ExpectedErrorMessageBuilder::error("invalid name ` User`: `internal name` needs to be normalized (e.g., whitespace removed): User").build(),
1050 &ExpectedErrorMessageBuilder::error("invalid name ` User`: `internal name` needs to be normalized (e.g., whitespace removed): User").build(),
1051 );
1052 }
1053
1054 #[test]
1055 fn in_applies_to_resources() {
1056 assert_schema_json_err_deprecated_and_standard(
1057 json!({
1058 "ns": {
1059 "entityTypes": { },
1060 "actions": {
1061 "act": {
1062 "appliesTo": {
1063 "principalTypes": [],
1064 "resourceTypes": [" User"],
1065 }
1066 }
1067 },
1068 }
1069 }),
1070 &ExpectedErrorMessageBuilder::error("invalid name ` User`: `internal name` needs to be normalized (e.g., whitespace removed): User").build(),
1071 &ExpectedErrorMessageBuilder::error("invalid name ` User`: `internal name` needs to be normalized (e.g., whitespace removed): User").build(),
1072 );
1073 }
1074
1075 #[test]
1076 fn in_member_of() {
1077 assert_schema_json_err_deprecated_and_standard(
1078 json!({
1079 "ns": {
1080 "entityTypes": { },
1081 "actions": {
1082 "other": {},
1083 "act": {
1084 "memberOf": [{"type": " Action", "id": "other"}],
1085 }
1086 },
1087 }
1088 }),
1089 &ExpectedErrorMessageBuilder::error("invalid name ` Action`: `internal name` needs to be normalized (e.g., whitespace removed): Action").build(),
1090 &ExpectedErrorMessageBuilder::error("invalid name ` Action`: `internal name` needs to be normalized (e.g., whitespace removed): Action").build(),
1091 );
1092 }
1093}
1094
1095#[cfg(test)]
1096#[expect(deprecated, reason = "testing deprecated functionality")]
1097mod from_str_parse_err {
1098
1099 use miette::Report;
1100
1101 use crate::{Schema, SchemaFragment};
1102 use cedar_policy_core::test_utils::{expect_err, ExpectedErrorMessageBuilder};
1103
1104 #[test]
1105 fn from_cedar_schema_str_err() {
1106 let src = "entity User;";
1107 expect_err(
1108 src,
1109 &Report::new(Schema::from_deprecated_json_str(src).unwrap_err()),
1110 &ExpectedErrorMessageBuilder::error("expected value at line 1 column 1").help("this API was expecting a schema in the JSON format; did you mean to use a different function, which expects the Cedar schema format?").build(),
1111 );
1112 expect_err(
1113 src,
1114 &Report::new(SchemaFragment::from_deprecated_json_str(src).unwrap_err()),
1115 &ExpectedErrorMessageBuilder::error("expected value at line 1 column 1").help("this API was expecting a schema in the JSON format; did you mean to use a different function, which expects the Cedar schema format?").build(),
1116 );
1117 }
1118}