Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
52cc8f6
parser: add benchmarks
aojea Sep 30, 2026
179be9e
parser: build the parser once for the FromString helpers
aojea Sep 30, 2026
e31b840
parser: return term errors from expressions
aojea Sep 30, 2026
033be6e
parser: require commas between predicate terms
aojea Sep 30, 2026
a5944df
parser: stop keywords from shadowing identifiers
aojea Sep 30, 2026
3a6c13e
parser: remove unused grammar types
aojea Sep 30, 2026
53c433a
parser: golden test over the spec sample corpus
aojea Sep 30, 2026
4a18418
pb: regenerate from the biscuit spec v3.3 schema
polygloton Feb 27, 2026
b5559fb
samples: read the v3.3 samples.json and gate samples on the block ver…
aojea Oct 18, 2026
9cca58b
parser: spec syntax for sets and strict equality
aojea Oct 7, 2026
79adde1
biscuit: secp256r1 keys and signature payload v1
aojea Oct 8, 2026
86c1184
datalog: resolve symbols inside sets when printing
aojea Oct 8, 2026
bf3c174
biscuit: check all, and datalog v3.1 blocks
aojea Oct 8, 2026
0dc8667
datalog: surface expression errors from queries
aojea Oct 8, 2026
1f6c547
datalog: v3.1 operators and negative integer literals
aojea Oct 8, 2026
473332c
datalog: track fact origins and trusted origins
aojea Oct 8, 2026
c760abd
biscuit: scopes (`trusting`) and the public key table
aojea Oct 8, 2026
6c95d87
biscuit: third-party blocks
aojea Oct 8, 2026
54a5d9d
biscuit: keep the root key id when appending or sealing
aojea Oct 8, 2026
417e320
biscuit: reject if, and datalog v3.3 blocks
aojea Oct 8, 2026
07dc805
datalog: heterogeneous == and !=
aojea Oct 8, 2026
79d90e7
datalog: null term
aojea Oct 8, 2026
13fad41
datalog: closures, lazy && and ||, .all() and .any()
aojea Oct 8, 2026
8814ff5
datalog: arrays and maps
aojea Oct 8, 2026
61d995b
datalog: .type()
aojea Oct 8, 2026
a19c02f
datalog: extern:: function calls
aojea Oct 8, 2026
329a52c
pb: regenerate from spec commit b3d3fe2
aojea Oct 8, 2026
b5e4a6a
datalog: .try_or()
aojea Oct 8, 2026
1f1839e
biscuit: keep the Ed25519 entry points and add RootKeyProvider
aojea Oct 22, 2026
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ build
.gobincache
/go.work
/go.work.sum
.buf-plugins/
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
IMAGE ?= biscuit-go-test

.PHONY: all build test test-local verify lint apidiff clean
.PHONY: all build test test-local verify lint apidiff generate clean

all: verify lint test

Expand All @@ -27,5 +27,9 @@ lint:
apidiff:
./script/apidiff.sh -r main

# Regenerates pb/ from the biscuit spec protobuf schema with buf.
generate:
./script/generate.sh

clean:
rm -rf build
55 changes: 53 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,23 @@ biscuit-go is an implementation of [Biscuit](https://github.com/eclipse-biscuit/
- [biscuit specification](https://github.com/eclipse-biscuit/biscuit)
- [biscuit-rust](https://github.com/eclipse-biscuit/biscuit-rust) for some more technical details.

## Specification compatibility

This library currently accepts datalog `v3.0` to `v3.3` blocks (block versions `3` to `6`, see
`MaxSchemaVersion`). Of datalog `v3.3`, `reject if`, the heterogeneous `==` and `!=`, `null`,
the lazy `&&` and `||`, the `.all()` / `.any()` closures, arrays, maps, `.type()`,
`extern::` function calls (registered with `WithExternFuncs`) and `.try_or()` are supported.

The [specification sample suite](./samples) runs in CI: samples using block versions above
`MaxSchemaVersion` are verified to be rejected and otherwise skipped, so they become active as
support for each version lands.

Tokens may be signed with Ed25519 or ECDSA on P-256 (`secp256r1`). `Biscuit.AuthorizerFrom`
takes a `RootKeyProvider` (`RootKey`, `RootKeysByID`, or your own function) for either key type;
`Biscuit.Authorizer` and `Biscuit.AuthorizerFor` still work with Ed25519 keys and are marked
deprecated. The `datalog.World` methods take the origin of each fact and the origins each rule
trusts, as in biscuit-rust.

## Usage

#### Create a biscuit
Expand Down Expand Up @@ -56,7 +73,7 @@ if err != nil {
// Attenuate the biscuit by appending a new block to it
blockBuilder := b.CreateBlock()
block, err := parser.FromStringBlockWithParams(`
check if resource($file), operation($permission), [{read}].contains($permission);`,
check if resource($file), operation($permission), {{read}}.contains($permission);`,
map[string]biscuit.Term{"read": biscuit.String("read")})
if err != nil {
panic(fmt.Errorf("failed to parse block: %v", err))
Expand All @@ -75,6 +92,40 @@ if err != nil {
// attenuatedToken is a []byte, representing an attenuated token
```

#### Append a third-party block

A third party signs a block for a token without seeing the token. Facts of that block are only
visible to rules that trust the third party's key.

```go
// Token holder: build the request for the third party.
request, err := b.ThirdPartyRequest()
if err != nil {
panic(err)
}
requestBytes, _ := request.Serialize()

// Third party: sign a block for that request with its own key.
request, _ = biscuit.UnmarshalThirdPartyBlockRequest(requestBytes)
blockBuilder := biscuit.NewThirdPartyBlockBuilder()
blockBuilder.AddFact(biscuit.Fact{Predicate: biscuit.Predicate{Name: "group", IDs: []biscuit.Term{biscuit.String("admin")}}})
contents, err := request.CreateBlock(thirdPartyPrivateKey, blockBuilder)
if err != nil {
panic(err)
}
contentsBytes, _ := contents.Serialize()

// Token holder: append the signed block.
contents, _ = biscuit.UnmarshalThirdPartyBlockContents(contentsBytes)
b, err = b.AppendThirdPartyBlock(nil, thirdPartyPublicKey, contents)
if err != nil {
panic(err)
}

// A check trusting the third party's key sees group("admin"):
// check if group("admin") trusting ed25519/<hex of thirdPartyPublicKey>
```

#### Verify a biscuit

```go
Expand All @@ -83,7 +134,7 @@ if err != nil {
panic(fmt.Errorf("failed to deserialize token: %v", err))
}

authorizer, err := b.Authorizer(publicRoot)
authorizer, err := b.AuthorizerFrom(biscuit.RootKey(publicRoot))
if err != nil {
panic(fmt.Errorf("failed to verify token and create authorizer: %v", err))
}
Expand Down
Loading
Loading