Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion src/main/java/org/eclipse/biscuit/datalog/Check.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
package org.eclipse.biscuit.datalog;

import static biscuit.format.schema.Schema.CheckV2.Kind.All;
import static biscuit.format.schema.Schema.CheckV2.Kind.Reject;

import biscuit.format.schema.Schema;
import java.util.ArrayList;
Expand All @@ -17,7 +18,8 @@
public final class Check {
public enum Kind {
ONE,
ALL
ALL,
REJECT
}

private static final int HASH_CODE_SEED = 31;
Expand Down Expand Up @@ -47,6 +49,9 @@ public Schema.CheckV2 serialize() {
case ALL:
b.setKind(All);
break;
case REJECT:
b.setKind(Reject);
break;
default:
}

Expand All @@ -68,6 +73,9 @@ public static Result<Check, Error.FormatError> deserializeV2(Schema.CheckV2 chec
case All:
kind = Kind.ALL;
break;
case Reject:
kind = Kind.REJECT;
break;
default:
kind = Kind.ONE;
break;
Expand Down
21 changes: 21 additions & 0 deletions src/main/java/org/eclipse/biscuit/datalog/MapKey.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.eclipse.biscuit.datalog;

import biscuit.format.schema.Schema;
import org.eclipse.biscuit.error.Error;
import org.eclipse.biscuit.error.Result;

public abstract class MapKey extends Term {
public abstract Schema.MapKey serializeMapKey();

public abstract org.eclipse.biscuit.token.builder.MapKey toMapKey(SymbolTable symbolTable);

public static Result<MapKey, Error.FormatError> deserializeMapKeyEnum(Schema.MapKey mapKey) {
if (mapKey.hasInteger()) {
return Term.Integer.deserializeMapKey(mapKey);
} else if (mapKey.hasString()) {
return Term.Str.deserializeMapKey(mapKey);
} else {
return Result.err(new Error.FormatError.DeserializationError("invalid MapKey kind"));
}
}
}
2 changes: 1 addition & 1 deletion src/main/java/org/eclipse/biscuit/datalog/Predicate.java
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public Schema.PredicateV2 serialize() {
Schema.PredicateV2.Builder builder = Schema.PredicateV2.newBuilder().setName(this.name);

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

return builder.build();
Expand Down
182 changes: 133 additions & 49 deletions src/main/java/org/eclipse/biscuit/datalog/SchemaVersion.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,87 +6,120 @@
package org.eclipse.biscuit.datalog;

import java.util.List;
import java.util.Optional;
import org.eclipse.biscuit.crypto.PublicKey;
import org.eclipse.biscuit.datalog.expressions.Expression;
import org.eclipse.biscuit.datalog.expressions.Op;
import org.eclipse.biscuit.error.Error;
import org.eclipse.biscuit.error.Result;
import org.eclipse.biscuit.token.format.SerializedBiscuit;

public final class SchemaVersion {
private boolean containsScopes;
private boolean containsCheckAll;
private boolean containsV4;
public static int version(
List<Fact> facts,
List<Rule> rules,
List<Check> checks,
List<Scope> scopes,
Optional<PublicKey> externalKey) {
if (containsV6(facts, rules, checks)) {
return SerializedBiscuit.DATALOG_3_3;
}
if (containsV5(externalKey)) {
return SerializedBiscuit.DATALOG_3_2;
}
if (containsV4(rules, checks, scopes)) {
return SerializedBiscuit.DATALOG_3_1;
}
return SerializedBiscuit.MIN_SCHEMA_VERSION;
}

public SchemaVersion(List<Fact> facts, List<Rule> rules, List<Check> checks, List<Scope> scopes) {
containsScopes = !scopes.isEmpty();
public static Result<Void, Error.FormatError> checkCompatibility(
int version,
List<Fact> facts,
List<Rule> rules,
List<Check> checks,
List<Scope> scopes,
Optional<PublicKey> externalKey) {
if (version < SerializedBiscuit.DATALOG_3_1 && containsV4(rules, checks, scopes)) {
return Result.err(
new Error.FormatError.DeserializationError(
"v" + version + " blocks must not have v4 features"));
}
if (version < SerializedBiscuit.DATALOG_3_2 && containsV5(externalKey)) {
return Result.err(
new Error.FormatError.DeserializationError(
"v" + version + " blocks must not have v5 features"));
}
if (version < SerializedBiscuit.DATALOG_3_3 && containsV6(facts, rules, checks)) {
return Result.err(
new Error.FormatError.DeserializationError(
"v" + version + " blocks must not have v6 features"));
}
return Result.ok(null);
}

if (!containsScopes) {
for (Rule r : rules) {
if (!r.scopes().isEmpty()) {
containsScopes = true;
break;
}
}
private static boolean containsV4(List<Rule> rules, List<Check> checks, List<Scope> scopes) {
if (!scopes.isEmpty()) {
return true;
}
if (!containsScopes) {
for (Check check : checks) {
for (Rule query : check.queries()) {
if (!query.scopes().isEmpty()) {
containsScopes = true;
break;
}
}
for (Rule rule : rules) {
if (!rule.scopes().isEmpty()) {
return true;
}
if (containsV4Ops(rule.expressions())) {
return true;
}
}

containsCheckAll = false;
for (Check check : checks) {
if (check.kind() == Check.Kind.ALL) {
containsCheckAll = true;
break;
return true;
}
}

containsV4 = false;
for (Check check : checks) {
for (Rule query : check.queries()) {
if (!query.scopes().isEmpty()) {
return true;
}
if (containsV4Ops(query.expressions())) {
containsV4 = true;
break;
return true;
}
}
}

return false;
}

public int version() {
if (containsScopes || containsV4 || containsCheckAll) {
return 4;
} else {
return SerializedBiscuit.MIN_SCHEMA_VERSION;
}
private static boolean containsV5(Optional<PublicKey> externalKey) {
return externalKey.isPresent();
}

public Result<Void, Error.FormatError> checkCompatibility(int version) {
if (version < 4) {
if (containsScopes) {
return Result.err(
new Error.FormatError.DeserializationError("v3 blocks must not have scopes"));
private static boolean containsV6(List<Fact> facts, List<Rule> rules, List<Check> checks) {
for (Fact fact : facts) {
if (containsV6Terms(fact.predicate().terms())) {
return true;
}
if (containsV4) {
return Result.err(
new Error.FormatError.DeserializationError(
"v3 blocks must not have v4 operators (bitwise operators or !="));
}

for (Rule rule : rules) {
if (containsV6Ops(rule.expressions())) {
return true;
}
if (containsCheckAll) {
return Result.err(
new Error.FormatError.DeserializationError("v3 blocks must not use check all"));
}

for (Check check : checks) {
if (check.kind() == Check.Kind.REJECT) {
return true;
}
for (Rule query : check.queries()) {
if (containsV6Ops(query.expressions())) {
return true;
}
}
}

return Result.ok(null);
return false;
}

public static boolean containsV4Ops(List<Expression> expressions) {
private static boolean containsV4Ops(List<Expression> expressions) {
for (Expression e : expressions) {
for (Op op : e.getOps()) {
if (op instanceof Op.Binary) {
Expand All @@ -104,4 +137,55 @@ public static boolean containsV4Ops(List<Expression> expressions) {
}
return false;
}

private static boolean containsV6Ops(List<Expression> expressions) {
for (Expression e : expressions) {
for (Op op : e.getOps()) {
if (op instanceof Op.Unary) {
Op.Unary b = (Op.Unary) op;
switch (b.getOp()) {
case TypeOf:
return true;
default:
}
} else if (op instanceof Op.Binary) {
Op.Binary b = (Op.Binary) op;
switch (b.getOp()) {
case HeterogeneousEqual:
case HeterogeneousNotEqual:
case LazyAnd:
case LazyOr:
case Get:
case Any:
case All:
case TryOr:
return true;
default:
}
} else if (op instanceof Op.Closure) {
return true;
} else if (op instanceof Term.Null) {
return true;
} else if (op instanceof Term.Array) {
return true;
} else if (op instanceof Term.Map) {
return true;
}
}
}
return false;
}

private static boolean containsV6Terms(List<Term> terms) {
for (Term term : terms) {
if (term instanceof Term.Null) {
return true;
} else if (term instanceof Term.Array) {
return true;
} else if (term instanceof Term.Map) {
return true;
}
}
return false;
}
}
23 changes: 23 additions & 0 deletions src/main/java/org/eclipse/biscuit/datalog/SymbolTable.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import org.eclipse.biscuit.crypto.PublicKey;
Expand Down Expand Up @@ -228,7 +229,26 @@ public String formatTerm(final Term i) {
final List<String> values =
((Term.Set) i)
.value().stream().map((v) -> this.formatTerm(v)).collect(Collectors.toList());
if (values.isEmpty()) {
return "{,}";
} else {
Collections.sort(values);
return "{" + String.join(", ", values) + "}";
}
} else if (i instanceof Term.Null) {
return "null";
} else if (i instanceof Term.Array) {
final List<String> values =
((Term.Array) i)
.value().stream().map((v) -> this.formatTerm(v)).collect(Collectors.toList());
return "[" + String.join(", ", values) + "]";
} else if (i instanceof Term.Map) {
ArrayList<String> entries = new ArrayList();
for (Map.Entry<MapKey, Term> entry : ((Term.Map) i).value().entrySet()) {
entries.add(formatTerm(entry.getKey()) + ": " + formatTerm(entry.getValue()));
}
Collections.sort(entries);
return "{" + String.join(", ", entries) + "}";
} else {
return "???";
}
Expand All @@ -247,6 +267,9 @@ public String formatCheck(final Check c) {
case ALL:
prefix = "check all ";
break;
case REJECT:
prefix = "reject if ";
break;
default:
prefix = "check if ";
break;
Expand Down
Loading