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