66package org .eclipse .biscuit .datalog ;
77
88import java .util .List ;
9+ import java .util .Optional ;
10+ import org .eclipse .biscuit .crypto .PublicKey ;
911import org .eclipse .biscuit .datalog .expressions .Expression ;
1012import org .eclipse .biscuit .datalog .expressions .Op ;
1113import org .eclipse .biscuit .error .Error ;
1214import org .eclipse .biscuit .error .Result ;
1315import org .eclipse .biscuit .token .format .SerializedBiscuit ;
1416
1517public final class SchemaVersion {
16- private boolean containsScopes ;
17- private boolean containsCheckAll ;
18- private boolean containsV4 ;
18+ private final boolean containsScopes ;
19+ private final boolean containsV31 ;
20+ private final boolean containsCheckAll ;
21+ private final boolean containsV33 ;
22+ private final boolean containsExternalKey ;
1923
20- public SchemaVersion (List <Fact > facts , List <Rule > rules , List <Check > checks , List <Scope > scopes ) {
21- containsScopes = !scopes .isEmpty ();
24+ public SchemaVersion (
25+ List <Fact > facts ,
26+ List <Rule > rules ,
27+ List <Check > checks ,
28+ List <Scope > scopes ,
29+ Optional <PublicKey > externalKey ) {
30+ containsScopes =
31+ !scopes .isEmpty ()
32+ || rules .stream ().anyMatch (r -> !r .scopes ().isEmpty ())
33+ || checks .stream ()
34+ .anyMatch (c -> c .queries ().stream ().anyMatch (q -> !q .scopes ().isEmpty ()));
2235
23- if (!containsScopes ) {
24- for (Rule r : rules ) {
25- if (!r .scopes ().isEmpty ()) {
26- containsScopes = true ;
27- break ;
28- }
29- }
30- }
31- if (!containsScopes ) {
32- for (Check check : checks ) {
33- for (Rule query : check .queries ()) {
34- if (!query .scopes ().isEmpty ()) {
35- containsScopes = true ;
36- break ;
37- }
38- }
39- }
40- }
36+ containsCheckAll = checks .stream ().anyMatch (c -> c .kind () == Check .Kind .ALL );
4137
42- containsCheckAll = false ;
43- for (Check check : checks ) {
44- if (check .kind () == Check .Kind .ALL ) {
45- containsCheckAll = true ;
46- break ;
47- }
48- }
38+ containsV31 =
39+ rules .stream ().anyMatch (r -> containsV31Op (r .expressions ()))
40+ || checks .stream ()
41+ .anyMatch (c -> c .queries ().stream ().anyMatch (q -> containsV31Op (q .expressions ())));
4942
50- containsV4 = false ;
51- for (Check check : checks ) {
52- for (Rule query : check .queries ()) {
53- if (containsV4Ops (query .expressions ())) {
54- containsV4 = true ;
55- break ;
56- }
57- }
58- }
43+ containsV33 =
44+ checks .stream ().anyMatch (c -> c .kind () == Check .Kind .REJECT )
45+ || rules .stream ()
46+ .anyMatch (
47+ r ->
48+ containsV33Predicate (r .head ())
49+ || r .body ().stream ().anyMatch (SchemaVersion ::containsV33Predicate )
50+ || containsV33Op (r .expressions ()))
51+ || checks .stream ()
52+ .anyMatch (
53+ c ->
54+ c .queries ().stream ()
55+ .anyMatch (
56+ q ->
57+ q .body ().stream ().anyMatch (SchemaVersion ::containsV33Predicate )
58+ || containsV33Op (q .expressions ())))
59+ || facts .stream ().anyMatch (f -> containsV33Predicate (f .predicate ()));
60+
61+ containsExternalKey = externalKey .isPresent ();
5962 }
6063
6164 public int version () {
62- if (containsScopes || containsV4 || containsCheckAll ) {
63- return 4 ;
64- } else {
65- return SerializedBiscuit .MIN_SCHEMA_VERSION ;
65+ if (containsV33 ) {
66+ return SerializedBiscuit .DATALOG_3_3 ;
67+ }
68+ if (containsExternalKey ) {
69+ return SerializedBiscuit .DATALOG_3_2 ;
6670 }
71+ if (containsScopes || containsV31 || containsCheckAll ) {
72+ return SerializedBiscuit .DATALOG_3_1 ;
73+ }
74+ return SerializedBiscuit .MIN_SCHEMA_VERSION ;
6775 }
6876
6977 public Result <Void , Error .FormatError > checkCompatibility (int version ) {
70- if (version < 4 ) {
78+ if (version < SerializedBiscuit . DATALOG_3_1 ) {
7179 if (containsScopes ) {
7280 return Result .err (
73- new Error .FormatError .DeserializationError ("v3 blocks must not have scopes" ));
81+ new Error .FormatError .DeserializationError (
82+ "scopes are only supported in datalog v3.1+" ));
7483 }
75- if (containsV4 ) {
84+ if (containsV31 ) {
7685 return Result .err (
7786 new Error .FormatError .DeserializationError (
78- "v3 blocks must not have v4 operators (bitwise operators or != " ));
87+ "bitwise operators and != are only supported in datalog v3.1+ " ));
7988 }
8089 if (containsCheckAll ) {
8190 return Result .err (
82- new Error .FormatError .DeserializationError ("v3 blocks must not use check all" ));
91+ new Error .FormatError .DeserializationError (
92+ "check all is only supported in datalog v3.1+" ));
8393 }
8494 }
95+ if (version < SerializedBiscuit .DATALOG_3_2 && containsExternalKey ) {
96+ return Result .err (
97+ new Error .FormatError .DeserializationError (
98+ "third-party blocks are only supported in datalog v3.2+" ));
99+ }
85100
101+ if (version < SerializedBiscuit .DATALOG_3_3 && containsV33 ) {
102+ return Result .err (
103+ new Error .FormatError .DeserializationError (
104+ "maps, arrays, null, closures are only supported in datalog v3.3+" ));
105+ }
86106 return Result .ok (null );
87107 }
88108
89- public static boolean containsV4Ops (List <Expression > expressions ) {
109+ private static boolean containsV31Op (List <Expression > expressions ) {
90110 for (Expression e : expressions ) {
91111 for (Op op : e .getOps ()) {
92112 if (op instanceof Op .Binary ) {
@@ -104,4 +124,59 @@ public static boolean containsV4Ops(List<Expression> expressions) {
104124 }
105125 return false ;
106126 }
127+
128+ private static boolean containsV33Op (List <Expression > expressions ) {
129+ for (Expression e : expressions ) {
130+ for (Op op : e .getOps ()) {
131+ if (op instanceof Op .Unary ) {
132+ Op .Unary b = (Op .Unary ) op ;
133+ switch (b .getOp ()) {
134+ case TypeOf :
135+ return true ;
136+ default :
137+ }
138+ } else if (op instanceof Op .Binary ) {
139+ Op .Binary b = (Op .Binary ) op ;
140+ switch (b .getOp ()) {
141+ case HeterogeneousEqual :
142+ case HeterogeneousNotEqual :
143+ case LazyAnd :
144+ case LazyOr :
145+ case Get :
146+ case Any :
147+ case All :
148+ case TryOr :
149+ return true ;
150+ default :
151+ }
152+ } else if (op instanceof Op .Closure ) {
153+ return true ;
154+ } else if (op instanceof Term .Null ) {
155+ return true ;
156+ } else if (op instanceof Term .Array ) {
157+ return true ;
158+ } else if (op instanceof Term .Map ) {
159+ return true ;
160+ }
161+ }
162+ }
163+ return false ;
164+ }
165+
166+ private static boolean containsV33Predicate (Predicate predicate ) {
167+ return predicate .terms ().stream ().anyMatch (SchemaVersion ::containsV33Term );
168+ }
169+
170+ private static boolean containsV33Term (Term term ) {
171+ if (term instanceof Term .Null ) {
172+ return true ;
173+ }
174+ if (term instanceof Term .Array ) {
175+ return true ;
176+ }
177+ if (term instanceof Term .Map ) {
178+ return true ;
179+ }
180+ return false ;
181+ }
107182}
0 commit comments