Skip to content

Commit 1fce047

Browse files
saoirse-apreuss-adam
authored andcommitted
Update to support Datalog version 3.3.
1 parent 3ef87dd commit 1fce047

39 files changed

Lines changed: 4297 additions & 1003 deletions

src/main/java/org/eclipse/biscuit/datalog/Check.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
package org.eclipse.biscuit.datalog;
77

88
import static biscuit.format.schema.Schema.CheckV2.Kind.All;
9+
import static biscuit.format.schema.Schema.CheckV2.Kind.Reject;
910

1011
import biscuit.format.schema.Schema;
1112
import java.util.ArrayList;
@@ -17,7 +18,8 @@
1718
public final class Check {
1819
public enum Kind {
1920
ONE,
20-
ALL
21+
ALL,
22+
REJECT
2123
}
2224

2325
private static final int HASH_CODE_SEED = 31;
@@ -47,6 +49,9 @@ public Schema.CheckV2 serialize() {
4749
case ALL:
4850
b.setKind(All);
4951
break;
52+
case REJECT:
53+
b.setKind(Reject);
54+
break;
5055
default:
5156
}
5257

@@ -68,6 +73,9 @@ public static Result<Check, Error.FormatError> deserializeV2(Schema.CheckV2 chec
6873
case All:
6974
kind = Kind.ALL;
7075
break;
76+
case Reject:
77+
kind = Kind.REJECT;
78+
break;
7179
default:
7280
kind = Kind.ONE;
7381
break;
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package org.eclipse.biscuit.datalog;
2+
3+
import biscuit.format.schema.Schema;
4+
import org.eclipse.biscuit.error.Error;
5+
import org.eclipse.biscuit.error.Result;
6+
7+
public abstract class MapKey extends Term {
8+
public abstract Schema.MapKey serializeMapKey();
9+
10+
public abstract org.eclipse.biscuit.token.builder.MapKey toMapKey(SymbolTable symbolTable);
11+
12+
public static Result<MapKey, Error.FormatError> deserializeMapKeyEnum(Schema.MapKey mapKey) {
13+
if (mapKey.hasInteger()) {
14+
return Term.Integer.deserializeMapKey(mapKey);
15+
} else if (mapKey.hasString()) {
16+
return Term.Str.deserializeMapKey(mapKey);
17+
} else {
18+
return Result.err(new Error.FormatError.DeserializationError("invalid MapKey kind"));
19+
}
20+
}
21+
}

src/main/java/org/eclipse/biscuit/datalog/Predicate.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ public Schema.PredicateV2 serialize() {
9090
Schema.PredicateV2.Builder builder = Schema.PredicateV2.newBuilder().setName(this.name);
9191

9292
for (int i = 0; i < this.terms.size(); i++) {
93-
builder.addTerms(this.terms.get(i).serialize());
93+
builder.addTerms(this.terms.get(i).serializeTerm());
9494
}
9595

9696
return builder.build();

src/main/java/org/eclipse/biscuit/datalog/SchemaVersion.java

Lines changed: 133 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -6,87 +6,120 @@
66
package org.eclipse.biscuit.datalog;
77

88
import java.util.List;
9+
import java.util.Optional;
10+
import org.eclipse.biscuit.crypto.PublicKey;
911
import org.eclipse.biscuit.datalog.expressions.Expression;
1012
import org.eclipse.biscuit.datalog.expressions.Op;
1113
import org.eclipse.biscuit.error.Error;
1214
import org.eclipse.biscuit.error.Result;
1315
import org.eclipse.biscuit.token.format.SerializedBiscuit;
1416

1517
public final class SchemaVersion {
16-
private boolean containsScopes;
17-
private boolean containsCheckAll;
18-
private boolean containsV4;
18+
public static int version(
19+
List<Fact> facts,
20+
List<Rule> rules,
21+
List<Check> checks,
22+
List<Scope> scopes,
23+
Optional<PublicKey> externalKey) {
24+
if (containsV6(facts, rules, checks)) {
25+
return SerializedBiscuit.DATALOG_3_3;
26+
}
27+
if (containsV5(externalKey)) {
28+
return SerializedBiscuit.DATALOG_3_2;
29+
}
30+
if (containsV4(rules, checks, scopes)) {
31+
return SerializedBiscuit.DATALOG_3_1;
32+
}
33+
return SerializedBiscuit.MIN_SCHEMA_VERSION;
34+
}
1935

20-
public SchemaVersion(List<Fact> facts, List<Rule> rules, List<Check> checks, List<Scope> scopes) {
21-
containsScopes = !scopes.isEmpty();
36+
public static Result<Void, Error.FormatError> checkCompatibility(
37+
int version,
38+
List<Fact> facts,
39+
List<Rule> rules,
40+
List<Check> checks,
41+
List<Scope> scopes,
42+
Optional<PublicKey> externalKey) {
43+
if (version < SerializedBiscuit.DATALOG_3_1 && containsV4(rules, checks, scopes)) {
44+
return Result.err(
45+
new Error.FormatError.DeserializationError(
46+
"v" + version + " blocks must not have v4 features"));
47+
}
48+
if (version < SerializedBiscuit.DATALOG_3_2 && containsV5(externalKey)) {
49+
return Result.err(
50+
new Error.FormatError.DeserializationError(
51+
"v" + version + " blocks must not have v5 features"));
52+
}
53+
if (version < SerializedBiscuit.DATALOG_3_3 && containsV6(facts, rules, checks)) {
54+
return Result.err(
55+
new Error.FormatError.DeserializationError(
56+
"v" + version + " blocks must not have v6 features"));
57+
}
58+
return Result.ok(null);
59+
}
2260

23-
if (!containsScopes) {
24-
for (Rule r : rules) {
25-
if (!r.scopes().isEmpty()) {
26-
containsScopes = true;
27-
break;
28-
}
29-
}
61+
private static boolean containsV4(List<Rule> rules, List<Check> checks, List<Scope> scopes) {
62+
if (!scopes.isEmpty()) {
63+
return true;
3064
}
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-
}
65+
for (Rule rule : rules) {
66+
if (!rule.scopes().isEmpty()) {
67+
return true;
68+
}
69+
if (containsV4Ops(rule.expressions())) {
70+
return true;
3971
}
4072
}
4173

42-
containsCheckAll = false;
4374
for (Check check : checks) {
4475
if (check.kind() == Check.Kind.ALL) {
45-
containsCheckAll = true;
46-
break;
76+
return true;
4777
}
48-
}
49-
50-
containsV4 = false;
51-
for (Check check : checks) {
5278
for (Rule query : check.queries()) {
79+
if (!query.scopes().isEmpty()) {
80+
return true;
81+
}
5382
if (containsV4Ops(query.expressions())) {
54-
containsV4 = true;
55-
break;
83+
return true;
5684
}
5785
}
5886
}
87+
88+
return false;
5989
}
6090

61-
public int version() {
62-
if (containsScopes || containsV4 || containsCheckAll) {
63-
return 4;
64-
} else {
65-
return SerializedBiscuit.MIN_SCHEMA_VERSION;
66-
}
91+
private static boolean containsV5(Optional<PublicKey> externalKey) {
92+
return externalKey.isPresent();
6793
}
6894

69-
public Result<Void, Error.FormatError> checkCompatibility(int version) {
70-
if (version < 4) {
71-
if (containsScopes) {
72-
return Result.err(
73-
new Error.FormatError.DeserializationError("v3 blocks must not have scopes"));
95+
private static boolean containsV6(List<Fact> facts, List<Rule> rules, List<Check> checks) {
96+
for (Fact fact : facts) {
97+
if (containsV6Terms(fact.predicate().terms())) {
98+
return true;
7499
}
75-
if (containsV4) {
76-
return Result.err(
77-
new Error.FormatError.DeserializationError(
78-
"v3 blocks must not have v4 operators (bitwise operators or !="));
100+
}
101+
102+
for (Rule rule : rules) {
103+
if (containsV6Ops(rule.expressions())) {
104+
return true;
79105
}
80-
if (containsCheckAll) {
81-
return Result.err(
82-
new Error.FormatError.DeserializationError("v3 blocks must not use check all"));
106+
}
107+
108+
for (Check check : checks) {
109+
if (check.kind() == Check.Kind.REJECT) {
110+
return true;
111+
}
112+
for (Rule query : check.queries()) {
113+
if (containsV6Ops(query.expressions())) {
114+
return true;
115+
}
83116
}
84117
}
85118

86-
return Result.ok(null);
119+
return false;
87120
}
88121

89-
public static boolean containsV4Ops(List<Expression> expressions) {
122+
private static boolean containsV4Ops(List<Expression> expressions) {
90123
for (Expression e : expressions) {
91124
for (Op op : e.getOps()) {
92125
if (op instanceof Op.Binary) {
@@ -104,4 +137,55 @@ public static boolean containsV4Ops(List<Expression> expressions) {
104137
}
105138
return false;
106139
}
140+
141+
private static boolean containsV6Ops(List<Expression> expressions) {
142+
for (Expression e : expressions) {
143+
for (Op op : e.getOps()) {
144+
if (op instanceof Op.Unary) {
145+
Op.Unary b = (Op.Unary) op;
146+
switch (b.getOp()) {
147+
case TypeOf:
148+
return true;
149+
default:
150+
}
151+
} else if (op instanceof Op.Binary) {
152+
Op.Binary b = (Op.Binary) op;
153+
switch (b.getOp()) {
154+
case HeterogeneousEqual:
155+
case HeterogeneousNotEqual:
156+
case LazyAnd:
157+
case LazyOr:
158+
case Get:
159+
case Any:
160+
case All:
161+
case TryOr:
162+
return true;
163+
default:
164+
}
165+
} else if (op instanceof Op.Closure) {
166+
return true;
167+
} else if (op instanceof Term.Null) {
168+
return true;
169+
} else if (op instanceof Term.Array) {
170+
return true;
171+
} else if (op instanceof Term.Map) {
172+
return true;
173+
}
174+
}
175+
}
176+
return false;
177+
}
178+
179+
private static boolean containsV6Terms(List<Term> terms) {
180+
for (Term term : terms) {
181+
if (term instanceof Term.Null) {
182+
return true;
183+
} else if (term instanceof Term.Array) {
184+
return true;
185+
} else if (term instanceof Term.Map) {
186+
return true;
187+
}
188+
}
189+
return false;
190+
}
107191
}

src/main/java/org/eclipse/biscuit/datalog/SymbolTable.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import java.util.ArrayList;
1313
import java.util.Collections;
1414
import java.util.List;
15+
import java.util.Map;
1516
import java.util.Optional;
1617
import java.util.stream.Collectors;
1718
import org.eclipse.biscuit.crypto.PublicKey;
@@ -228,7 +229,26 @@ public String formatTerm(final Term i) {
228229
final List<String> values =
229230
((Term.Set) i)
230231
.value().stream().map((v) -> this.formatTerm(v)).collect(Collectors.toList());
232+
if (values.isEmpty()) {
233+
return "{,}";
234+
} else {
235+
Collections.sort(values);
236+
return "{" + String.join(", ", values) + "}";
237+
}
238+
} else if (i instanceof Term.Null) {
239+
return "null";
240+
} else if (i instanceof Term.Array) {
241+
final List<String> values =
242+
((Term.Array) i)
243+
.value().stream().map((v) -> this.formatTerm(v)).collect(Collectors.toList());
231244
return "[" + String.join(", ", values) + "]";
245+
} else if (i instanceof Term.Map) {
246+
ArrayList<String> entries = new ArrayList();
247+
for (Map.Entry<MapKey, Term> entry : ((Term.Map) i).value().entrySet()) {
248+
entries.add(formatTerm(entry.getKey()) + ": " + formatTerm(entry.getValue()));
249+
}
250+
Collections.sort(entries);
251+
return "{" + String.join(", ", entries) + "}";
232252
} else {
233253
return "???";
234254
}
@@ -247,6 +267,9 @@ public String formatCheck(final Check c) {
247267
case ALL:
248268
prefix = "check all ";
249269
break;
270+
case REJECT:
271+
prefix = "reject if ";
272+
break;
250273
default:
251274
prefix = "check if ";
252275
break;

0 commit comments

Comments
 (0)