Skip to content

Commit

Permalink
Seal (#9)
Browse files Browse the repository at this point in the history
# Description

- Move `parser.zig` into `biscuit-builder`
- Cleans up some of the lifetime stuff:
    - `Biscuit.fromBytes` can now take _any_ `mem.Allocator`
- Internally it now creates an `ArenaAllocator` (this is heap allocated
because some objects created during `Biscuit.fromBytes` retain their
allocator which would be the `arena` in `Biscuit.fromBytes` that is
pointing to the stack-allocated `ArenaAllocator`)
    - A similar change is made to `SerializedBiscuit`
- Adds `fn seal` to `SerializedBiscuit` that does the sealing (but
doesn't serialize)
  • Loading branch information
malcolmstill authored Jun 12, 2024
1 parent 9aaff35 commit e733306
Show file tree
Hide file tree
Showing 40 changed files with 1,187 additions and 486 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
- uses: actions/checkout@v2
- uses: goto-bus-stop/setup-zig@v1
with:
version: master
version: 0.12.0
- name: zig build test
working-directory: "./${{matrix.dir}}"
run: zig build test
Expand All @@ -29,5 +29,5 @@ jobs:
- uses: actions/checkout@v2
- uses: goto-bus-stop/setup-zig@v1
with:
version: master
version: 0.12.0
- run: zig fmt --check .
34 changes: 32 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,35 @@
# biscuit-zig

```sh
protoc --zig_out=. schema.proto
Zig implementation of https://www.biscuitsec.org/

## Usage

### Authorizing a token

```zig
var biscuit = try Biscuit.fromBytes(allocator, token, root_public_key);
defer biscuit.deinit();
var authorizer = try biscuit.authorizer();
defer authorizer.deinit();
var errors = std.ArrayList(AuthorizerError).init(allocator);
defer errors.deinit();
try authorizer.authorize(&errors);
```

### Attenuating a token

```zig
var biscuit = try Biscuit.fromBytes(allocator, token, root_public_key);
defer biscuit.deinit();
var authorizer = try biscuit.authorizer();
defer authorizer.deinit();
var errors = std.ArrayList(AuthorizerError).init(allocator);
defer errors.deinit();
try authorizer.authorize(&errors);
```
16 changes: 7 additions & 9 deletions biscuit-builder/build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -15,28 +15,26 @@ pub fn build(b: *std.Build) void {
// set a preferred release mode, allowing the user to decide how to optimize.
const optimize = b.standardOptimizeOption(.{});

const schema = b.dependency("biscuit-schema", .{ .target = target, .optimize = optimize });
const format = b.dependency("biscuit-format", .{ .target = target, .optimize = optimize });
const datalog = b.dependency("biscuit-datalog", .{ .target = target, .optimize = optimize });
const ziglyph = b.dependency("ziglyph", .{ .optimize = optimize, .target = target });
const set = b.dependency("biscuit-set", .{ .target = target, .optimize = optimize });

_ = b.addModule("biscuit-builder", .{
.root_source_file = .{ .path = "src/root.zig" },
.imports = &.{
.{ .name = "biscuit-schema", .module = schema.module("biscuit-schema") },
.{ .name = "biscuit-format", .module = format.module("biscuit-format") },
.{ .name = "biscuit-datalog", .module = datalog.module("biscuit-datalog") },
.{ .name = "biscuit-set", .module = set.module("biscuit-set") },
.{ .name = "ziglyph", .module = ziglyph.module("ziglyph") },
},
});

// Creates a step for unit testing. This only builds the test executable
// but does not run it.
const lib_unit_tests = b.addTest(.{
.root_source_file = .{ .path = "src/main.zig" },
.root_source_file = .{ .path = "src/root.zig" },
.target = target,
.optimize = optimize,
});
lib_unit_tests.root_module.addImport("biscuit-schema", schema.module("biscuit-schema"));
lib_unit_tests.root_module.addImport("biscuit-format", format.module("biscuit-format"));
lib_unit_tests.root_module.addImport("biscuit-set", set.module("biscuit-set"));
lib_unit_tests.root_module.addImport("ziglyph", ziglyph.module("ziglyph"));

const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests);

Expand Down
6 changes: 5 additions & 1 deletion biscuit-builder/build.zig.zon
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,11 @@
//},
.@"biscuit-schema" = .{ .path = "../biscuit-schema" },
.@"biscuit-format" = .{ .path = "../biscuit-format" },
.@"biscuit-datalog" = .{ .path = "../biscuit-datalog" },
.@"biscuit-set" = .{ .path = "../biscuit-set" },
.ziglyph = .{
.url = "https://codeberg.org/dude_the_builder/ziglyph/archive/947ed39203bf90412e3d16cbcf936518b6f23af0.tar.gz",
.hash = "12208b23d1eb6dcb929e85346524db8f8b8aa1401bdf8a97dee1e0cfb55da8d5fb42",
},
},

// Specifies the set of files and directories that are included in this package.
Expand Down
78 changes: 78 additions & 0 deletions biscuit-builder/src/block.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
const std = @import("std");
const Fact = @import("fact.zig").Fact;
const Rule = @import("rule.zig").Rule;
const Check = @import("check.zig").Check;
const Scope = @import("scope.zig").Scope;
const Parser = @import("parser.zig").Parser;

const log = std.log.scoped(.builder_block);

/// Block builder that allows us to append blocks to a token
pub const Block = struct {
arena: std.mem.Allocator,
context: ?[]const u8,
facts: std.ArrayList(Fact),
rules: std.ArrayList(Rule),
checks: std.ArrayList(Check),
scopes: std.ArrayList(Scope),

/// Initialise a new block builder.
///
/// This can take any std.mem.Allocator but by design allocations
/// leak so the caller should pass in an ArenaAllocator or other
/// allocator with arena-like properties.
pub fn init(arena: std.mem.Allocator) Block {
return .{
.arena = arena,
.context = null,
.facts = std.ArrayList(Fact).init(arena),
.rules = std.ArrayList(Rule).init(arena),
.checks = std.ArrayList(Check).init(arena),
.scopes = std.ArrayList(Scope).init(arena),
};
}

pub fn addFact(block: *Block, input: []const u8) !void {
log.debug("addFact = {s}", .{input});
defer log.debug("addFact = {s}", .{input});

var parser = Parser.init(block.arena, input);

const fact = try parser.fact();

try block.facts.append(fact);
}

pub fn addRule(block: *Block, input: []const u8) !void {
log.debug("addRule = {s}", .{input});
defer log.debug("addRule = {s}", .{input});

var parser = Parser.init(block.arena, input);

const rule = try parser.rule();

try block.rules.append(rule);
}

pub fn addCheck(block: *Block, input: []const u8) !void {
log.debug("addCheck = {s}", .{input});
defer log.debug("addCheck = {s}", .{input});

var parser = Parser.init(block.arena, input);

const check = try parser.check();

try block.checks.append(check);
}

pub fn addScope(block: *Block, input: []const u8) !void {
log.debug("addScope = {s}", .{input});
defer log.debug("addScope = {s}", .{input});

var parser = Parser.init(block.arena, input);

const scope = try parser.scope();

try block.scopes.append(scope);
}
};
16 changes: 0 additions & 16 deletions biscuit-builder/src/check.zig
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
const std = @import("std");
const datalog = @import("biscuit-datalog");
const Predicate = @import("predicate.zig").Predicate;
const Term = @import("term.zig").Term;
const Rule = @import("rule.zig").Rule;
Expand All @@ -21,21 +20,6 @@ pub const Check = struct {
// check.queries.deinit();
}

pub fn toDatalog(check: Check, allocator: std.mem.Allocator, symbols: *datalog.SymbolTable) !datalog.Check {
var queries = std.ArrayList(datalog.Rule).init(allocator);

for (check.queries.items) |query| {
try queries.append(try query.toDatalog(allocator, symbols));
}

const kind: datalog.Check.Kind = switch (check.kind) {
.one => .one,
.all => .all,
};

return .{ .kind = kind, .queries = queries };
}

pub fn format(check: Check, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
try writer.print("check ", .{});

Expand Down
57 changes: 0 additions & 57 deletions biscuit-builder/src/expression.zig
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
const std = @import("std");
const datalog = @import("biscuit-datalog");
const Predicate = @import("predicate.zig").Predicate;
const Term = @import("term.zig").Term;

Expand Down Expand Up @@ -57,62 +56,6 @@ pub const Expression = union(ExpressionType) {
not_equal,
};

/// convert to datalog fact
pub fn toDatalog(expression: Expression, allocator: std.mem.Allocator, symbols: *datalog.SymbolTable) !datalog.Expression {
var ops = std.ArrayList(datalog.Op).init(allocator);

try expression.toOpcodes(allocator, &ops, symbols);

return .{ .ops = ops };
}

pub fn toOpcodes(expression: Expression, allocator: std.mem.Allocator, ops: *std.ArrayList(datalog.Op), symbols: *datalog.SymbolTable) !void {
switch (expression) {
.value => |v| try ops.append(.{ .value = try v.toDatalog(allocator, symbols) }),
.unary => |u| {
try u.expression.toOpcodes(allocator, ops, symbols);

try ops.append(.{
.unary = switch (u.op) {
.negate => .negate,
.parens => .parens,
.length => .length,
},
});
},
.binary => |b| {
try b.left.toOpcodes(allocator, ops, symbols);
try b.right.toOpcodes(allocator, ops, symbols);

try ops.append(.{
.binary = switch (b.op) {
.less_than => .less_than,
.greater_than => .greater_than,
.less_or_equal => .less_or_equal,
.greater_or_equal => .greater_or_equal,
.equal => .equal,
.contains => .contains,
.prefix => .prefix,
.suffix => .suffix,
.regex => .regex,
.add => .add,
.sub => .sub,
.mul => .mul,
.div => .div,
.@"and" => .@"and",
.@"or" => .@"or",
.intersection => .intersection,
.@"union" => .@"union",
.bitwise_and => .bitwise_and,
.bitwise_or => .bitwise_or,
.bitwise_xor => .bitwise_xor,
.not_equal => .not_equal,
},
});
},
}
}

pub fn deinit(_: *Expression) void {
// switch (expression.*) {
// .value => |v| v.deinit(),
Expand Down
6 changes: 0 additions & 6 deletions biscuit-builder/src/fact.zig
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
const std = @import("std");
const datalog = @import("biscuit-datalog");
const Predicate = @import("predicate.zig").Predicate;
const Term = @import("term.zig").Term;

Expand All @@ -11,11 +10,6 @@ pub const Fact = struct {
// fact.predicate.deinit();
}

/// convert to datalog fact
pub fn toDatalog(fact: Fact, allocator: std.mem.Allocator, symbols: *datalog.SymbolTable) !datalog.Fact {
return .{ .predicate = try fact.predicate.toDatalog(allocator, symbols) };
}

pub fn format(fact: Fact, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
return writer.print("{any}", .{fact.predicate});
}
Expand Down
Loading

0 comments on commit e733306

Please sign in to comment.