Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Origins + more test suite passing #7

Merged
merged 47 commits into from
Mar 29, 2024
Merged
Changes from 1 commit
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
190fd93
WIP
malcolmstill Mar 19, 2024
ec48aff
Working test001
malcolmstill Mar 19, 2024
bb0942f
Initial parser
malcolmstill Mar 19, 2024
525d888
Fix parameter name
malcolmstill Mar 20, 2024
40880e4
More illuminating name
malcolmstill Mar 21, 2024
d876d4c
WIP parser
malcolmstill Mar 23, 2024
10432f2
WIP parser
malcolmstill Mar 23, 2024
e7dc323
WIP parser
malcolmstill Mar 23, 2024
7e07bf5
Test 010 passes
malcolmstill Mar 23, 2024
185e678
Test 012 passes
malcolmstill Mar 23, 2024
521bbb9
Test 022 works
malcolmstill Mar 23, 2024
04da1de
Convert bytes and set
malcolmstill Mar 23, 2024
fad0623
Some RFC 3339 support
malcolmstill Mar 24, 2024
7acf870
WIP date
malcolmstill Mar 24, 2024
9d44302
WIP expressions
malcolmstill Mar 24, 2024
59011f7
WIP expression parser
malcolmstill Mar 24, 2024
f5c7dc1
Working expression parse
malcolmstill Mar 24, 2024
b17b962
Fix
malcolmstill Mar 24, 2024
9faa7d8
WIP
malcolmstill Mar 24, 2024
e36ccc6
WIP
malcolmstill Mar 25, 2024
0df1e74
WIP
malcolmstill Mar 25, 2024
e19e375
RuleSet / FactSet
malcolmstill Mar 25, 2024
3d061f8
Trusted facts compiles but does not work
malcolmstill Mar 25, 2024
2524056
Still not working
malcolmstill Mar 26, 2024
9f9fa9d
WIP
malcolmstill Mar 26, 2024
1959667
Fixed iterator (need to be pointers to FactSet, not FactSet by value)…
malcolmstill Mar 26, 2024
ec38967
WIP
malcolmstill Mar 26, 2024
2fd0b47
WIP
malcolmstill Mar 26, 2024
bb37f8c
I have a feeling we shouldn't think about TrustedOrigins as containin…
malcolmstill Mar 26, 2024
283109b
Fix Term.convert
malcolmstill Mar 26, 2024
710f96c
Rule.findMatch: evalute expressions where rule has no body predicates
malcolmstill Mar 26, 2024
9cb5ba4
Parse external key out of block
malcolmstill Mar 26, 2024
d1d7f3b
Verify external signature
malcolmstill Mar 26, 2024
a92c5b0
Test 027 passes
malcolmstill Mar 26, 2024
25ea0f0
More scope stuff
malcolmstill Mar 27, 2024
0aa6dd0
Test 024 third pary works
malcolmstill Mar 28, 2024
fd7aed5
Fix test 025
malcolmstill Mar 28, 2024
3b29527
Partial fix fo r test 026
malcolmstill Mar 28, 2024
286621b
Implement policies / builder expression conversion
malcolmstill Mar 28, 2024
b029049
Fix parser + working test 026...this required some additional mapping…
malcolmstill Mar 28, 2024
5ca2107
Depend on zig-regex + working test 014
malcolmstill Mar 28, 2024
270e63c
Concat
malcolmstill Mar 28, 2024
460f826
Update the samples...eveything now works apart from test 018
malcolmstill Mar 28, 2024
a5a06c0
Latest samples.json + required sample.zig changes
malcolmstill Mar 28, 2024
26028a7
Yay, test018 passes...all the tests pass!
malcolmstill Mar 28, 2024
f8bb0f3
Fix double free
malcolmstill Mar 28, 2024
58cfd30
Let's get all module tests running again
malcolmstill Mar 28, 2024
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
Prev Previous commit
Next Next commit
Trusted facts compiles but does not work
malcolmstill committed Mar 25, 2024
commit 3d061f8fada98f1b433d4a300974ca37c2ca09ba
34 changes: 24 additions & 10 deletions biscuit-datalog/src/combinator.zig
Original file line number Diff line number Diff line change
@@ -4,7 +4,9 @@ const mem = std.mem;
const Fact = @import("fact.zig").Fact;
const Predicate = @import("predicate.zig").Predicate;
const Term = @import("term.zig").Term;
const Set = @import("set.zig").Set;
const FactSet = @import("fact_set.zig").FactSet;
const Origin = @import("origin.zig").Origin;
const TrustedOrigins = @import("origin.zig").TrustedOrigins;
const Expression = @import("expression.zig").Expression;
const MatchedVariables = @import("matched_variables.zig").MatchedVariables;
const SymbolTable = @import("symbol_table.zig").SymbolTable;
@@ -56,11 +58,12 @@ pub const Combinator = struct {
predicates: []Predicate, // List of the predicates so we can generate new Combinators
expressions: []Expression,
current_bindings: ?std.AutoHashMap(u64, Term) = null,
facts: *const Set(Fact),
fact_iterator: Set(Fact).Iterator,
facts: *const FactSet,
trusted_fact_iterator: FactSet.TrustedIterator,
symbols: SymbolTable,
trusted_origins: TrustedOrigins,

pub fn init(id: usize, allocator: mem.Allocator, variables: MatchedVariables, predicates: []Predicate, expressions: []Expression, all_facts: *const Set(Fact), symbols: SymbolTable) !*Combinator {
pub fn init(id: usize, allocator: mem.Allocator, variables: MatchedVariables, predicates: []Predicate, expressions: []Expression, all_facts: *const FactSet, symbols: SymbolTable, trusted_origins: TrustedOrigins) !*Combinator {
std.debug.print("Init combinator[{}]: predicates = {any}\n", .{ id, predicates });
const c = try allocator.create(Combinator);

@@ -73,7 +76,8 @@ pub const Combinator = struct {
.expressions = expressions,
.variables = variables,
.symbols = symbols,
.fact_iterator = all_facts.iterator(),
.trusted_fact_iterator = all_facts.trustedIterator(trusted_origins),
.trusted_origins = trusted_origins,
};

return c;
@@ -84,21 +88,30 @@ pub const Combinator = struct {
combinator.allocator.destroy(combinator);
}

// QUESTION: is the return value guaranteed to be complete? I.e. each variable has been matched with some non-variable term?
/// next returns the next _valid_ combination of variable bindings
pub fn next(combinator: *Combinator) !?MatchedVariables {
pub fn next(combinator: *Combinator) !?struct { Origin, MatchedVariables } {
blk: while (true) {
std.debug.print("next[{}]\n", .{combinator.id});
// Return from next combinator until expended
if (combinator.next_combinator) |c| {
if (try c.next()) |vars| {
return vars;
if (try c.next()) |origin_vars| {
return origin_vars;
} else {
c.deinit();
combinator.next_combinator = null;
continue;
}
}

const fact = combinator.fact_iterator.next() orelse return null;
// Lookup the next (trusted) fact
const origin_fact = combinator.trusted_fact_iterator.next() orelse {
std.debug.print("combinator[{}] trusted fact iterator exhausted\n", .{combinator.id});
return null;
};
const origin = origin_fact.origin.*;
const fact = origin_fact.fact.*;

// Only consider facts that match the current predicate
if (!fact.matchPredicate(combinator.predicates[0])) continue;
std.debug.print("combinator[{}]: fact = {any}\n", .{ combinator.id, fact });
@@ -140,7 +153,7 @@ pub const Combinator = struct {
}
}

return vars;
return .{ origin, vars };
} else {
if (combinator.next_combinator) |c| c.deinit();

@@ -152,6 +165,7 @@ pub const Combinator = struct {
combinator.expressions,
combinator.facts,
combinator.symbols,
combinator.trusted_origins,
);
}
}
128 changes: 119 additions & 9 deletions biscuit-datalog/src/fact_set.zig
Original file line number Diff line number Diff line change
@@ -2,39 +2,149 @@ const std = @import("std");
const Fact = @import("fact.zig").Fact;
const Set = @import("set.zig").Set;
const Origin = @import("origin.zig").Origin;
const TrustedOrigins = @import("origin.zig").TrustedOrigins;

pub const FactSet = struct {
facts: std.AutoHashMap(Origin, Set(Fact)),
sets: std.AutoHashMap(Origin, Set(Fact)),
allocator: std.mem.Allocator,

pub fn init(allocator: std.mem.Allocator) FactSet {
return .{
.facts = std.AutoHashMap(Origin, Set(Fact)).init(allocator),
.sets = std.AutoHashMap(Origin, Set(Fact)).init(allocator),
.allocator = allocator,
};
}

pub fn deinit(fact_set: *FactSet) void {
var it = fact_set.facts.iterator();
var it = fact_set.sets.iterator();

while (it.next()) |entry| {
entry.key_ptr.deinit();
entry.value_ptr.deinit();
while (it.next()) |origin_facts| {
origin_facts.key_ptr.deinit();
origin_facts.value_ptr.deinit();
}

fact_set.facts.deinit();
fact_set.sets.deinit();
}

pub const Iterator = struct {
set_it: std.AutoHashMap(Origin, Set(Fact)).Iterator,
origin_fact_it: ?struct { origin: *Origin, fact_it: Set(Fact).Iterator } = null,

pub fn next(it: *Iterator) ?struct { origin: *Origin, fact: *Fact } {
while (true) {
if (it.origin_fact_it) |origin_fact_it| {
//
const origin = origin_fact_it.origin;
var fact_it = origin_fact_it.fact_it;

const fact = fact_it.next() orelse {
it.origin_fact_it = null;
continue;
};

return .{ .origin = origin, .fact = fact };
} else {
const origin_set = it.set_it.next() orelse return null;

it.origin_fact_it = .{ .origin = origin_set.key_ptr, .fact_it = origin_set.value_ptr.iterator() };

continue;
}

unreachable;
}
}
};

pub fn iterator(fact_set: FactSet) Iterator {
return .{ .set_it = fact_set.sets.iterator() };
}

pub const TrustedIterator = struct {
trusted_origins: TrustedOrigins,
set_it: std.AutoHashMap(Origin, Set(Fact)).Iterator,
origin_fact_it: ?struct { origin: *Origin, fact_it: Set(Fact).Iterator } = null,

pub fn next(it: *TrustedIterator) ?struct { origin: *Origin, fact: *Fact } {
while (true) {
std.debug.print("start\n", .{});
if (it.origin_fact_it) |origin_fact_it| {
const origin = origin_fact_it.origin;
var fact_it = origin_fact_it.fact_it;

std.debug.print("Reading next fact for origin {any}\n", .{origin});
const fact = fact_it.next() orelse {
std.debug.print("no more facts in {any}\n", .{origin});
it.origin_fact_it = null;

std.debug.print("continue ultra\n", .{});
continue;
};

std.debug.print("Gotta be here?\n", .{});
return .{ .origin = origin, .fact = fact };
} else {
std.debug.assert(it.origin_fact_it == null);

const origin_set = it.set_it.next() orelse return null;
const origin = origin_set.key_ptr;

// If we don't trust the origin of this set, we start the loop again
if (!it.trusted_origins.containsAll(origin.*)) {
std.debug.print("continue foxbat\n", .{});
continue;
}
defer std.debug.assert(it.origin_fact_it != null);

std.debug.print("here\n", .{});
it.origin_fact_it = .{
.origin = origin,
.fact_it = origin_set.value_ptr.iterator(),
};

std.debug.print("continue omega\n", .{});
continue;
}

unreachable;
}
}
};

/// Return an iterator over facts that match the trusted origin.
pub fn trustedIterator(fact_set: FactSet, trusted_origins: TrustedOrigins) TrustedIterator {
std.debug.print("Making trusted iterator\n", .{});
return .{ .set_it = fact_set.sets.iterator(), .trusted_origins = trusted_origins };
}

/// Return the total number of facts in the fact set
pub fn count(fact_set: *FactSet) usize {
var n: usize = 0;

var it = fact_set.sets.valueIterator();
while (it.next()) |facts| {
n += facts.count();
}

return n;
}

pub fn add(fact_set: *FactSet, origin: Origin, fact: Fact) !void {
if (fact_set.facts.getEntry(origin)) |entry| {
if (fact_set.sets.getEntry(origin)) |entry| {
try entry.value_ptr.add(fact);
} else {
var set = Set(Fact).init(fact_set.allocator);
try set.add(fact);

try fact_set.facts.put(origin, set);
try fact_set.sets.put(origin, set);
}
}

pub fn contains(fact_set: *const FactSet, origin: Origin, fact: Fact) bool {
const set = fact_set.sets.get(origin) orelse return false;

return set.contains(fact);
}
};

test "FactSet" {
2 changes: 2 additions & 0 deletions biscuit-datalog/src/main.zig
Original file line number Diff line number Diff line change
@@ -11,6 +11,8 @@ pub const symbol_table = @import("symbol_table.zig");
pub const SymbolTable = @import("symbol_table.zig").SymbolTable;
pub const Term = @import("term.zig").Term;
pub const Check = @import("check.zig").Check;
pub const Origin = @import("origin.zig").Origin;
pub const TrustedOrigins = @import("origin.zig").TrustedOrigins;
pub const world = @import("world.zig");

test {
2 changes: 1 addition & 1 deletion biscuit-datalog/src/matched_variables.zig
Original file line number Diff line number Diff line change
@@ -31,7 +31,7 @@ const Term = @import("term.zig").Term;
pub const MatchedVariables = struct {
variables: std.AutoHashMap(u32, ?Term),

pub fn init(allocator: mem.Allocator, rule: *Rule) !MatchedVariables {
pub fn init(allocator: mem.Allocator, rule: *const Rule) !MatchedVariables {
var variables = std.AutoHashMap(u32, ?Term).init(allocator);

// Add all variables in predicates in the rule's body to variable set
67 changes: 56 additions & 11 deletions biscuit-datalog/src/origin.zig
Original file line number Diff line number Diff line change
@@ -6,14 +6,43 @@ const Scope = @import("scope.zig").Scope;
pub const Origin = struct {
block_ids: std.AutoHashMap(usize, void),

// Authorizer id is maximum int storable in u64
pub const AuthorizerId = std.math.maxInt(u64);

pub fn init(allocator: mem.Allocator) Origin {
return .{ .block_ids = std.AutoHashMap(usize, void).init(allocator) };
}

// pub fn initWithId(allocator: mem.Allocator, block_id: usize) !Origin {
// var block_ids = std.AutoHashMap(usize, void).init(allocator);

// try block_ids.put(block_id, {});

// return .{ .block_ids = block_ids };
// }

pub fn deinit(origin: *Origin) void {
origin.block_ids.deinit();
}

pub fn format(origin: Origin, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
var it = origin.block_ids.keyIterator();

try writer.print("[", .{});
while (it.next()) |block_id| {
try writer.print("{}", .{block_id.*});
}
try writer.print("]", .{});
}

pub fn clone(origin: *const Origin) !Origin {
return .{ .block_ids = try origin.block_ids.clone() };
}

// pub fn authorizer(allocator: mem.Allocator) !Origin {
// return try Origin.initWithId(allocator, AuthorizerId);
// }

pub fn insert(origin: *Origin, block_id: usize) !void {
try origin.block_ids.put(block_id, {});
}
@@ -39,6 +68,10 @@ pub const TrustedOrigins = struct {
trusted_origins.origin.block_ids.deinit();
}

pub fn clone(trusted_origins: *const TrustedOrigins) !TrustedOrigins {
return .{ .origin = try trusted_origins.origin.clone() };
}

/// Return a TrustedOrigins default of trusting the authority block (0)
/// and the authorizer (max int).
pub fn defaultOrigins(allocator: mem.Allocator) !TrustedOrigins {
@@ -57,31 +90,30 @@ pub const TrustedOrigins = struct {
default_origins: TrustedOrigins,
current_block: usize,
public_key_to_block_id: std.AutoHashMap(usize, std.ArrayList(usize)),
) TrustedOrigins {
const max_int = std.math.maxInt(usize);
) !TrustedOrigins {
_ = public_key_to_block_id;

if (rule_scopes.len == 0) {
var origins = default_origins.clone();
var trusted_origins = try default_origins.clone();

try origins.insert(current_block);
try origins.insert(max_int);
try trusted_origins.origin.insert(current_block);
try trusted_origins.origin.insert(Origin.AuthorizerId);

return origins;
return trusted_origins;
}

var trusted_origins = TrustedOrigins.init(allocator);
trusted_origins.origin.insert(max_int);
trusted_origins.origin.insert(current_block);
try trusted_origins.origin.insert(Origin.AuthorizerId);
try trusted_origins.origin.insert(current_block);

for (rule_scopes) |scope| {
switch (scope) {
.authority => trusted_origins.origin.insert(0),
.authority => try trusted_origins.origin.insert(0),
.previous => {
if (current_block == max_int) continue;
if (current_block == Origin.AuthorizerId) continue;

for (0..current_block + 1) |i| {
try trusted_origins.origins.insert(i);
try trusted_origins.origin.insert(i);
}
},
.public_key => |public_key_id| {
@@ -94,4 +126,17 @@ pub const TrustedOrigins = struct {

return trusted_origins;
}

/// Check that TrustedOrigins contain _all_ origin ids in fact_origin
pub fn containsAll(trusted_origins: TrustedOrigins, fact_origin: Origin) bool {
var origin_it = fact_origin.block_ids.keyIterator();

while (origin_it.next()) |origin_id| {
if (trusted_origins.origin.block_ids.contains(origin_id.*)) continue;

return false;
}

return true;
}
};
Loading