packages feed

biscuit-haskell 0.3.0.1 → 0.4.0.0

raw patch · 41 files changed

+2439/−1820 lines, 41 filesbinary-addedPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Auth.Biscuit: [$sel:allFacts:AuthorizationSuccess] :: AuthorizationSuccess -> FactGroup
- Auth.Biscuit: [$sel:limits:AuthorizationSuccess] :: AuthorizationSuccess -> Limits
- Auth.Biscuit: [$sel:matchedAllowQuery:AuthorizationSuccess] :: AuthorizationSuccess -> MatchedQuery
- Auth.Biscuit.Datalog.ScopedExecutor: [$sel:allFacts:AuthorizationSuccess] :: AuthorizationSuccess -> FactGroup
- Auth.Biscuit.Datalog.ScopedExecutor: [$sel:limits:AuthorizationSuccess] :: AuthorizationSuccess -> Limits
- Auth.Biscuit.Datalog.ScopedExecutor: [$sel:matchedAllowQuery:AuthorizationSuccess] :: AuthorizationSuccess -> MatchedQuery
- Auth.Biscuit.Proto: [$sel:algorithm:PublicKey] :: PublicKey -> Required 1 (Enumeration Algorithm)
- Auth.Biscuit.Proto: [$sel:authority:Biscuit] :: Biscuit -> Required 2 (Message SignedBlock)
- Auth.Biscuit.Proto: [$sel:block:SignedBlock] :: SignedBlock -> Required 1 (Value ByteString)
- Auth.Biscuit.Proto: [$sel:blocks:Biscuit] :: Biscuit -> Repeated 3 (Message SignedBlock)
- Auth.Biscuit.Proto: [$sel:body:RuleV2] :: RuleV2 -> Repeated 2 (Message PredicateV2)
- Auth.Biscuit.Proto: [$sel:checks_v2:Block] :: Block -> Repeated 6 (Message CheckV2)
- Auth.Biscuit.Proto: [$sel:context:Block] :: Block -> Optional 2 (Value Text)
- Auth.Biscuit.Proto: [$sel:expressions:RuleV2] :: RuleV2 -> Repeated 3 (Message ExpressionV2)
- Auth.Biscuit.Proto: [$sel:externalSig:SignedBlock] :: SignedBlock -> Optional 4 (Message ExternalSig)
- Auth.Biscuit.Proto: [$sel:externalSig:ThirdPartyBlockContents] :: ThirdPartyBlockContents -> Required 2 (Message ExternalSig)
- Auth.Biscuit.Proto: [$sel:facts_v2:Block] :: Block -> Repeated 4 (Message FactV2)
- Auth.Biscuit.Proto: [$sel:head:RuleV2] :: RuleV2 -> Required 1 (Message PredicateV2)
- Auth.Biscuit.Proto: [$sel:key:PublicKey] :: PublicKey -> Required 2 (Value ByteString)
- Auth.Biscuit.Proto: [$sel:kind:CheckV2] :: CheckV2 -> Optional 2 (Enumeration CheckKind)
- Auth.Biscuit.Proto: [$sel:kind:OpBinary] :: OpBinary -> Required 1 (Enumeration BinaryKind)
- Auth.Biscuit.Proto: [$sel:kind:OpTernary] :: OpTernary -> Required 1 (Enumeration TernaryKind)
- Auth.Biscuit.Proto: [$sel:kind:OpUnary] :: OpUnary -> Required 1 (Enumeration UnaryKind)
- Auth.Biscuit.Proto: [$sel:name:PredicateV2] :: PredicateV2 -> Required 1 (Value Int64)
- Auth.Biscuit.Proto: [$sel:nextKey:SignedBlock] :: SignedBlock -> Required 2 (Message PublicKey)
- Auth.Biscuit.Proto: [$sel:ops:ExpressionV2] :: ExpressionV2 -> Repeated 1 (Message Op)
- Auth.Biscuit.Proto: [$sel:payload:ThirdPartyBlockContents] :: ThirdPartyBlockContents -> Required 1 (Value ByteString)
- Auth.Biscuit.Proto: [$sel:pkTable:ThirdPartyBlockRequest] :: ThirdPartyBlockRequest -> Repeated 2 (Message PublicKey)
- Auth.Biscuit.Proto: [$sel:pksTable:Block] :: Block -> Repeated 8 (Message PublicKey)
- Auth.Biscuit.Proto: [$sel:predicate:FactV2] :: FactV2 -> Required 1 (Message PredicateV2)
- Auth.Biscuit.Proto: [$sel:previousPk:ThirdPartyBlockRequest] :: ThirdPartyBlockRequest -> Required 1 (Message PublicKey)
- Auth.Biscuit.Proto: [$sel:proof:Biscuit] :: Biscuit -> Required 4 (Message Proof)
- Auth.Biscuit.Proto: [$sel:publicKey:ExternalSig] :: ExternalSig -> Required 2 (Message PublicKey)
- Auth.Biscuit.Proto: [$sel:queries:CheckV2] :: CheckV2 -> Repeated 1 (Message RuleV2)
- Auth.Biscuit.Proto: [$sel:rootKeyId:Biscuit] :: Biscuit -> Optional 1 (Value Int32)
- Auth.Biscuit.Proto: [$sel:rules_v2:Block] :: Block -> Repeated 5 (Message RuleV2)
- Auth.Biscuit.Proto: [$sel:scope:Block] :: Block -> Repeated 7 (Message Scope)
- Auth.Biscuit.Proto: [$sel:scope:RuleV2] :: RuleV2 -> Repeated 4 (Message Scope)
- Auth.Biscuit.Proto: [$sel:set:TermSet] :: TermSet -> Repeated 1 (Message TermV2)
- Auth.Biscuit.Proto: [$sel:signature:ExternalSig] :: ExternalSig -> Required 1 (Value ByteString)
- Auth.Biscuit.Proto: [$sel:signature:SignedBlock] :: SignedBlock -> Required 3 (Value ByteString)
- Auth.Biscuit.Proto: [$sel:symbols:Block] :: Block -> Repeated 1 (Value Text)
- Auth.Biscuit.Proto: [$sel:terms:PredicateV2] :: PredicateV2 -> Repeated 2 (Message TermV2)
- Auth.Biscuit.Proto: [$sel:version:Block] :: Block -> Optional 3 (Value Int32)
- Auth.Biscuit.Symbols: forgetSymbols :: Symbols -> Symbols
+ Auth.Biscuit: EvaluationError :: String -> ExecutionError
+ Auth.Biscuit: [allFacts] :: AuthorizationSuccess -> FactGroup
+ Auth.Biscuit: [limits] :: AuthorizationSuccess -> Limits
+ Auth.Biscuit: [matchedAllowQuery] :: AuthorizationSuccess -> MatchedQuery
+ Auth.Biscuit.Datalog.Executor: EvaluationError :: String -> ExecutionError
+ Auth.Biscuit.Datalog.ScopedExecutor: BadExpression :: String -> PureExecError
+ Auth.Biscuit.Datalog.ScopedExecutor: [allFacts] :: AuthorizationSuccess -> FactGroup
+ Auth.Biscuit.Datalog.ScopedExecutor: [limits] :: AuthorizationSuccess -> Limits
+ Auth.Biscuit.Datalog.ScopedExecutor: [matchedAllowQuery] :: AuthorizationSuccess -> MatchedQuery
+ Auth.Biscuit.Proto: [algorithm] :: PublicKey -> Required 1 (Enumeration Algorithm)
+ Auth.Biscuit.Proto: [authority] :: Biscuit -> Required 2 (Message SignedBlock)
+ Auth.Biscuit.Proto: [block] :: SignedBlock -> Required 1 (Value ByteString)
+ Auth.Biscuit.Proto: [blocks] :: Biscuit -> Repeated 3 (Message SignedBlock)
+ Auth.Biscuit.Proto: [body] :: RuleV2 -> Repeated 2 (Message PredicateV2)
+ Auth.Biscuit.Proto: [checks_v2] :: Block -> Repeated 6 (Message CheckV2)
+ Auth.Biscuit.Proto: [context] :: Block -> Optional 2 (Value Text)
+ Auth.Biscuit.Proto: [expressions] :: RuleV2 -> Repeated 3 (Message ExpressionV2)
+ Auth.Biscuit.Proto: [externalSig] :: ThirdPartyBlockContents -> Required 2 (Message ExternalSig)
+ Auth.Biscuit.Proto: [facts_v2] :: Block -> Repeated 4 (Message FactV2)
+ Auth.Biscuit.Proto: [head] :: RuleV2 -> Required 1 (Message PredicateV2)
+ Auth.Biscuit.Proto: [key] :: PublicKey -> Required 2 (Value ByteString)
+ Auth.Biscuit.Proto: [kind] :: OpTernary -> Required 1 (Enumeration TernaryKind)
+ Auth.Biscuit.Proto: [name] :: PredicateV2 -> Required 1 (Value Int64)
+ Auth.Biscuit.Proto: [nextKey] :: SignedBlock -> Required 2 (Message PublicKey)
+ Auth.Biscuit.Proto: [ops] :: ExpressionV2 -> Repeated 1 (Message Op)
+ Auth.Biscuit.Proto: [payload] :: ThirdPartyBlockContents -> Required 1 (Value ByteString)
+ Auth.Biscuit.Proto: [pkTable] :: ThirdPartyBlockRequest -> Repeated 2 (Message PublicKey)
+ Auth.Biscuit.Proto: [pksTable] :: Block -> Repeated 8 (Message PublicKey)
+ Auth.Biscuit.Proto: [predicate] :: FactV2 -> Required 1 (Message PredicateV2)
+ Auth.Biscuit.Proto: [previousPk] :: ThirdPartyBlockRequest -> Required 1 (Message PublicKey)
+ Auth.Biscuit.Proto: [proof] :: Biscuit -> Required 4 (Message Proof)
+ Auth.Biscuit.Proto: [publicKey] :: ExternalSig -> Required 2 (Message PublicKey)
+ Auth.Biscuit.Proto: [queries] :: CheckV2 -> Repeated 1 (Message RuleV2)
+ Auth.Biscuit.Proto: [rootKeyId] :: Biscuit -> Optional 1 (Value Int32)
+ Auth.Biscuit.Proto: [rules_v2] :: Block -> Repeated 5 (Message RuleV2)
+ Auth.Biscuit.Proto: [scope] :: RuleV2 -> Repeated 4 (Message Scope)
+ Auth.Biscuit.Proto: [set] :: TermSet -> Repeated 1 (Message TermV2)
+ Auth.Biscuit.Proto: [signature] :: ExternalSig -> Required 1 (Value ByteString)
+ Auth.Biscuit.Proto: [symbols] :: Block -> Repeated 1 (Value Text)
+ Auth.Biscuit.Proto: [terms] :: PredicateV2 -> Repeated 2 (Message TermV2)
+ Auth.Biscuit.Proto: [version] :: Block -> Optional 3 (Value Int32)
+ Auth.Biscuit.Utils: allM :: (Foldable t, Monad m) => (a -> m Bool) -> t a -> m Bool
+ Auth.Biscuit.Utils: anyM :: (Foldable t, Monad m) => (a -> m Bool) -> t a -> m Bool
+ Auth.Biscuit.Utils: foldMapM :: (Monoid b, Monad m, Foldable f) => (a -> m b) -> f a -> m b
+ Auth.Biscuit.Utils: mapMaybeM :: Monad m => (a -> m (Maybe b)) -> [a] -> m [b]
+ Auth.Biscuit.Utils: setFilterM :: (Ord a, Monad m) => (a -> m Bool) -> Set a -> m (Set a)
- Auth.Biscuit: ParserConfig :: BiscuitEncoding -> (Set ByteString -> m Bool) -> (Maybe Int -> PublicKey) -> ParserConfig m
+ Auth.Biscuit: ParserConfig :: BiscuitEncoding -> (Set ByteString -> m Bool) -> (Maybe Int -> PublicKey) -> ParserConfig (m :: Type -> Type)
- Auth.Biscuit: [encoding] :: ParserConfig m -> BiscuitEncoding
+ Auth.Biscuit: [encoding] :: ParserConfig (m :: Type -> Type) -> BiscuitEncoding
- Auth.Biscuit: [getPublicKey] :: ParserConfig m -> Maybe Int -> PublicKey
+ Auth.Biscuit: [getPublicKey] :: ParserConfig (m :: Type -> Type) -> Maybe Int -> PublicKey
- Auth.Biscuit: [isRevoked] :: ParserConfig m -> Set ByteString -> m Bool
+ Auth.Biscuit: [isRevoked] :: ParserConfig (m :: Type -> Type) -> Set ByteString -> m Bool
- Auth.Biscuit: class ToTerm t inSet pof
+ Auth.Biscuit: class ToTerm t (inSet :: IsWithinSet) (pof :: PredicateOrFact)
- Auth.Biscuit: data ParserConfig m
+ Auth.Biscuit: data ParserConfig (m :: Type -> Type)
- Auth.Biscuit: queryAuthorizerFacts :: AuthorizedBiscuit p -> Query -> Set Bindings
+ Auth.Biscuit: queryAuthorizerFacts :: AuthorizedBiscuit p -> Query -> Either String (Set Bindings)
- Auth.Biscuit: queryRawBiscuitFacts :: Biscuit openOrSealed check -> Query -> Set Bindings
+ Auth.Biscuit: queryRawBiscuitFacts :: Biscuit openOrSealed check -> Query -> Either String (Set Bindings)
- Auth.Biscuit.Datalog.AST: AuthorizerPolicy :: Policy' evalCtx ctx -> AuthorizerElement' evalCtx ctx
+ Auth.Biscuit.Datalog.AST: AuthorizerPolicy :: Policy' evalCtx ctx -> AuthorizerElement' (evalCtx :: EvaluationContext) (ctx :: DatalogContext)
- Auth.Biscuit.Datalog.AST: BlockCheck :: Check' evalCtx ctx -> BlockElement' evalCtx ctx
+ Auth.Biscuit.Datalog.AST: BlockCheck :: Check' evalCtx ctx -> BlockElement' (evalCtx :: EvaluationContext) (ctx :: DatalogContext)
- Auth.Biscuit.Datalog.AST: BlockComment :: BlockElement' evalCtx ctx
+ Auth.Biscuit.Datalog.AST: BlockComment :: BlockElement' (evalCtx :: EvaluationContext) (ctx :: DatalogContext)
- Auth.Biscuit.Datalog.AST: BlockElement :: BlockElement' evalCtx ctx -> AuthorizerElement' evalCtx ctx
+ Auth.Biscuit.Datalog.AST: BlockElement :: BlockElement' evalCtx ctx -> AuthorizerElement' (evalCtx :: EvaluationContext) (ctx :: DatalogContext)
- Auth.Biscuit.Datalog.AST: BlockFact :: Predicate' 'InFact ctx -> BlockElement' evalCtx ctx
+ Auth.Biscuit.Datalog.AST: BlockFact :: Predicate' 'InFact ctx -> BlockElement' (evalCtx :: EvaluationContext) (ctx :: DatalogContext)
- Auth.Biscuit.Datalog.AST: BlockRule :: Rule' evalCtx ctx -> BlockElement' evalCtx ctx
+ Auth.Biscuit.Datalog.AST: BlockRule :: Rule' evalCtx ctx -> BlockElement' (evalCtx :: EvaluationContext) (ctx :: DatalogContext)
- Auth.Biscuit.Datalog.AST: Check :: Query' evalCtx ctx -> CheckKind -> Check' evalCtx ctx
+ Auth.Biscuit.Datalog.AST: Check :: Query' evalCtx ctx -> CheckKind -> Check' (evalCtx :: EvaluationContext) (ctx :: DatalogContext)
- Auth.Biscuit.Datalog.AST: QueryItem :: [Predicate' 'InPredicate ctx] -> [Expression' ctx] -> Set (RuleScope' evalCtx ctx) -> QueryItem' evalCtx ctx
+ Auth.Biscuit.Datalog.AST: QueryItem :: [Predicate' 'InPredicate ctx] -> [Expression' ctx] -> Set (RuleScope' evalCtx ctx) -> QueryItem' (evalCtx :: EvaluationContext) (ctx :: DatalogContext)
- Auth.Biscuit.Datalog.AST: Rule :: Predicate' 'InPredicate ctx -> [Predicate' 'InPredicate ctx] -> [Expression' ctx] -> Set (RuleScope' evalCtx ctx) -> Rule' evalCtx ctx
+ Auth.Biscuit.Datalog.AST: Rule :: Predicate' 'InPredicate ctx -> [Predicate' 'InPredicate ctx] -> [Expression' ctx] -> Set (RuleScope' evalCtx ctx) -> Rule' (evalCtx :: EvaluationContext) (ctx :: DatalogContext)
- Auth.Biscuit.Datalog.AST: [body] :: Rule' evalCtx ctx -> [Predicate' 'InPredicate ctx]
+ Auth.Biscuit.Datalog.AST: [body] :: Rule' (evalCtx :: EvaluationContext) (ctx :: DatalogContext) -> [Predicate' 'InPredicate ctx]
- Auth.Biscuit.Datalog.AST: [cKind] :: Check' evalCtx ctx -> CheckKind
+ Auth.Biscuit.Datalog.AST: [cKind] :: Check' (evalCtx :: EvaluationContext) (ctx :: DatalogContext) -> CheckKind
- Auth.Biscuit.Datalog.AST: [cQueries] :: Check' evalCtx ctx -> Query' evalCtx ctx
+ Auth.Biscuit.Datalog.AST: [cQueries] :: Check' (evalCtx :: EvaluationContext) (ctx :: DatalogContext) -> Query' evalCtx ctx
- Auth.Biscuit.Datalog.AST: [expressions] :: Rule' evalCtx ctx -> [Expression' ctx]
+ Auth.Biscuit.Datalog.AST: [expressions] :: Rule' (evalCtx :: EvaluationContext) (ctx :: DatalogContext) -> [Expression' ctx]
- Auth.Biscuit.Datalog.AST: [qBody] :: QueryItem' evalCtx ctx -> [Predicate' 'InPredicate ctx]
+ Auth.Biscuit.Datalog.AST: [qBody] :: QueryItem' (evalCtx :: EvaluationContext) (ctx :: DatalogContext) -> [Predicate' 'InPredicate ctx]
- Auth.Biscuit.Datalog.AST: [qExpressions] :: QueryItem' evalCtx ctx -> [Expression' ctx]
+ Auth.Biscuit.Datalog.AST: [qExpressions] :: QueryItem' (evalCtx :: EvaluationContext) (ctx :: DatalogContext) -> [Expression' ctx]
- Auth.Biscuit.Datalog.AST: [qScope] :: QueryItem' evalCtx ctx -> Set (RuleScope' evalCtx ctx)
+ Auth.Biscuit.Datalog.AST: [qScope] :: QueryItem' (evalCtx :: EvaluationContext) (ctx :: DatalogContext) -> Set (RuleScope' evalCtx ctx)
- Auth.Biscuit.Datalog.AST: [rhead] :: Rule' evalCtx ctx -> Predicate' 'InPredicate ctx
+ Auth.Biscuit.Datalog.AST: [rhead] :: Rule' (evalCtx :: EvaluationContext) (ctx :: DatalogContext) -> Predicate' 'InPredicate ctx
- Auth.Biscuit.Datalog.AST: [scope] :: Rule' evalCtx ctx -> Set (RuleScope' evalCtx ctx)
+ Auth.Biscuit.Datalog.AST: [scope] :: Rule' (evalCtx :: EvaluationContext) (ctx :: DatalogContext) -> Set (RuleScope' evalCtx ctx)
- Auth.Biscuit.Datalog.AST: class ToEvaluation elem
+ Auth.Biscuit.Datalog.AST: class ToEvaluation (elem :: EvaluationContext -> DatalogContext -> Type)
- Auth.Biscuit.Datalog.AST: class ToTerm t inSet pof
+ Auth.Biscuit.Datalog.AST: class ToTerm t (inSet :: IsWithinSet) (pof :: PredicateOrFact)
- Auth.Biscuit.Datalog.AST: data AuthorizerElement' evalCtx ctx
+ Auth.Biscuit.Datalog.AST: data AuthorizerElement' (evalCtx :: EvaluationContext) (ctx :: DatalogContext)
- Auth.Biscuit.Datalog.AST: data BlockElement' evalCtx ctx
+ Auth.Biscuit.Datalog.AST: data BlockElement' (evalCtx :: EvaluationContext) (ctx :: DatalogContext)
- Auth.Biscuit.Datalog.AST: data Check' evalCtx ctx
+ Auth.Biscuit.Datalog.AST: data Check' (evalCtx :: EvaluationContext) (ctx :: DatalogContext)
- Auth.Biscuit.Datalog.AST: data QueryItem' evalCtx ctx
+ Auth.Biscuit.Datalog.AST: data QueryItem' (evalCtx :: EvaluationContext) (ctx :: DatalogContext)
- Auth.Biscuit.Datalog.AST: data Rule' evalCtx ctx
+ Auth.Biscuit.Datalog.AST: data Rule' (evalCtx :: EvaluationContext) (ctx :: DatalogContext)
- Auth.Biscuit.Datalog.AST: elementToAuthorizer :: AuthorizerElement' evalCtx ctx -> Authorizer' evalCtx ctx
+ Auth.Biscuit.Datalog.AST: elementToAuthorizer :: forall (evalCtx :: EvaluationContext) (ctx :: DatalogContext). AuthorizerElement' evalCtx ctx -> Authorizer' evalCtx ctx
- Auth.Biscuit.Datalog.AST: elementToBlock :: BlockElement' evalCtx ctx -> Block' evalCtx ctx
+ Auth.Biscuit.Datalog.AST: elementToBlock :: forall (evalCtx :: EvaluationContext) (ctx :: DatalogContext). BlockElement' evalCtx ctx -> Block' evalCtx ctx
- Auth.Biscuit.Datalog.AST: extractVariables :: [Predicate' 'InPredicate ctx] -> Set Text
+ Auth.Biscuit.Datalog.AST: extractVariables :: forall (ctx :: DatalogContext). [Predicate' 'InPredicate ctx] -> Set Text
- Auth.Biscuit.Datalog.AST: isCheckOne :: Check' evalCtx ctx -> Bool
+ Auth.Biscuit.Datalog.AST: isCheckOne :: forall (evalCtx :: EvaluationContext) (ctx :: DatalogContext). Check' evalCtx ctx -> Bool
- Auth.Biscuit.Datalog.AST: makeQueryItem :: [Predicate' 'InPredicate ctx] -> [Expression' ctx] -> Set (RuleScope' 'Repr ctx) -> Validation (NonEmpty Text) (QueryItem' 'Repr ctx)
+ Auth.Biscuit.Datalog.AST: makeQueryItem :: forall (ctx :: DatalogContext). [Predicate' 'InPredicate ctx] -> [Expression' ctx] -> Set (RuleScope' 'Repr ctx) -> Validation (NonEmpty Text) (QueryItem' 'Repr ctx)
- Auth.Biscuit.Datalog.AST: makeRule :: Predicate' 'InPredicate ctx -> [Predicate' 'InPredicate ctx] -> [Expression' ctx] -> Set (RuleScope' 'Repr ctx) -> Validation (NonEmpty Text) (Rule' 'Repr ctx)
+ Auth.Biscuit.Datalog.AST: makeRule :: forall (ctx :: DatalogContext). Predicate' 'InPredicate ctx -> [Predicate' 'InPredicate ctx] -> [Expression' ctx] -> Set (RuleScope' 'Repr ctx) -> Validation (NonEmpty Text) (Rule' 'Repr ctx)
- Auth.Biscuit.Datalog.AST: type Policy' evalCtx ctx = (PolicyType, Query' evalCtx ctx)
+ Auth.Biscuit.Datalog.AST: type Policy' (evalCtx :: EvaluationContext) (ctx :: DatalogContext) = (PolicyType, Query' evalCtx ctx)
- Auth.Biscuit.Datalog.AST: type Query' evalCtx ctx = [QueryItem' evalCtx ctx]
+ Auth.Biscuit.Datalog.AST: type Query' (evalCtx :: EvaluationContext) (ctx :: DatalogContext) = [QueryItem' evalCtx ctx]
- Auth.Biscuit.Datalog.Executor: checkCheck :: Limits -> Natural -> Natural -> FactGroup -> EvalCheck -> Validation (NonEmpty Check) ()
+ Auth.Biscuit.Datalog.Executor: checkCheck :: Limits -> Natural -> Natural -> FactGroup -> EvalCheck -> Either String (Validation (NonEmpty Check) ())
- Auth.Biscuit.Datalog.Executor: checkPolicy :: Limits -> Natural -> FactGroup -> EvalPolicy -> Maybe (Either MatchedQuery MatchedQuery)
+ Auth.Biscuit.Datalog.Executor: checkPolicy :: Limits -> Natural -> FactGroup -> EvalPolicy -> Either String (Maybe (Either MatchedQuery MatchedQuery))
- Auth.Biscuit.Datalog.Executor: getBindingsForRuleBody :: Limits -> Set (Scoped Fact) -> [Predicate] -> [Expression] -> Set (Scoped Bindings)
+ Auth.Biscuit.Datalog.Executor: getBindingsForRuleBody :: Limits -> Set (Scoped Fact) -> [Predicate] -> [Expression] -> Either String (Set (Scoped Bindings))
- Auth.Biscuit.Datalog.Executor: getFactsForRule :: Limits -> Set (Scoped Fact) -> EvalRule -> Set (Scoped Fact)
+ Auth.Biscuit.Datalog.Executor: getFactsForRule :: Limits -> Set (Scoped Fact) -> EvalRule -> Either String (Set (Scoped Fact))
- Auth.Biscuit.Datalog.Parser: predicateParser' :: Parser (Term' 'NotWithinSet pof 'WithSlices) -> Parser (Predicate' pof 'WithSlices)
+ Auth.Biscuit.Datalog.Parser: predicateParser' :: forall (pof :: PredicateOrFact). Parser (Term' 'NotWithinSet pof 'WithSlices) -> Parser (Predicate' pof 'WithSlices)
- Auth.Biscuit.Datalog.Parser: termParser :: Parser (VariableType inSet pof) -> Parser (SetType inSet 'WithSlices) -> Parser (Term' inSet pof 'WithSlices)
+ Auth.Biscuit.Datalog.Parser: termParser :: forall (inSet :: IsWithinSet) (pof :: PredicateOrFact). Parser (VariableType inSet pof) -> Parser (SetType inSet 'WithSlices) -> Parser (Term' inSet pof 'WithSlices)
- Auth.Biscuit.Datalog.ScopedExecutor: queryAvailableFacts :: [Maybe PublicKey] -> FactGroup -> Limits -> Query -> Set Bindings
+ Auth.Biscuit.Datalog.ScopedExecutor: queryAvailableFacts :: [Maybe PublicKey] -> FactGroup -> Limits -> Query -> Either String (Set Bindings)
- Auth.Biscuit.Datalog.ScopedExecutor: queryGeneratedFacts :: [Maybe PublicKey] -> AuthorizationSuccess -> Query -> Set Bindings
+ Auth.Biscuit.Datalog.ScopedExecutor: queryGeneratedFacts :: [Maybe PublicKey] -> AuthorizationSuccess -> Query -> Either String (Set Bindings)
- Auth.Biscuit.ProtoBufAdapter: pbToThirdPartyBlockRequest :: ThirdPartyBlockRequest -> Either String (PublicKey, [PublicKey])
+ Auth.Biscuit.ProtoBufAdapter: pbToThirdPartyBlockRequest :: ThirdPartyBlockRequest -> Either String PublicKey
- Auth.Biscuit.ProtoBufAdapter: thirdPartyBlockRequestToPb :: (PublicKey, [PublicKey]) -> ThirdPartyBlockRequest
+ Auth.Biscuit.ProtoBufAdapter: thirdPartyBlockRequestToPb :: PublicKey -> ThirdPartyBlockRequest
- Auth.Biscuit.Token: ParserConfig :: BiscuitEncoding -> (Set ByteString -> m Bool) -> (Maybe Int -> PublicKey) -> ParserConfig m
+ Auth.Biscuit.Token: ParserConfig :: BiscuitEncoding -> (Set ByteString -> m Bool) -> (Maybe Int -> PublicKey) -> ParserConfig (m :: Type -> Type)
- Auth.Biscuit.Token: [encoding] :: ParserConfig m -> BiscuitEncoding
+ Auth.Biscuit.Token: [encoding] :: ParserConfig (m :: Type -> Type) -> BiscuitEncoding
- Auth.Biscuit.Token: [getPublicKey] :: ParserConfig m -> Maybe Int -> PublicKey
+ Auth.Biscuit.Token: [getPublicKey] :: ParserConfig (m :: Type -> Type) -> Maybe Int -> PublicKey
- Auth.Biscuit.Token: [isRevoked] :: ParserConfig m -> Set ByteString -> m Bool
+ Auth.Biscuit.Token: [isRevoked] :: ParserConfig (m :: Type -> Type) -> Set ByteString -> m Bool
- Auth.Biscuit.Token: data ParserConfig m
+ Auth.Biscuit.Token: data ParserConfig (m :: Type -> Type)
- Auth.Biscuit.Token: queryAuthorizerFacts :: AuthorizedBiscuit p -> Query -> Set Bindings
+ Auth.Biscuit.Token: queryAuthorizerFacts :: AuthorizedBiscuit p -> Query -> Either String (Set Bindings)
- Auth.Biscuit.Token: queryRawBiscuitFacts :: Biscuit openOrSealed check -> Query -> Set Bindings
+ Auth.Biscuit.Token: queryRawBiscuitFacts :: Biscuit openOrSealed check -> Query -> Either String (Set Bindings)

Files

ChangeLog.md view
@@ -1,5 +1,18 @@ # Changelog for biscuit-haskell +## 0.4.0.0++- abort authorization on evaluation error as mandated by the spec+- use utf8 byte count in `{string}.length()` as mandated by the spec+- fix security issue with third-party blocks public key interning++## 0.3.0.1++- GHC 9.6 and 9.8 support+- Support for `!=`+- Fixed-sized arithmetic and overflow detection+- Allow parsing chained method calls+ ## 0.3.0.0  - GHC 9.2 support
README.md view
@@ -1,6 +1,6 @@ # biscuit-haskell [![CI-badge][CI-badge]][CI-url] [![Hackage][hackage]][hackage-url] -<img src="https://raw.githubusercontent.com/biscuit-auth/biscuit-haskell/main/assets/biscuit-logo.png" align=right>+<img src="https://raw.githubusercontent.com/biscuit-auth/biscuit-haskell/main/assets/logo-black-white-bg.png" align=right>  Main library for biscuit tokens support, providing minting and signature verification of biscuit tokens, as well as a datalog engine allowing to compute the validity of a token in a given context. @@ -96,8 +96,8 @@   pure $ serializeB64 newBiscuit ``` -[CI-badge]: https://img.shields.io/github/workflow/status/Divarvel/biscuit-haskell/CI?style=flat-square-[CI-url]: https://github.com/Divarvel/biscuit-haskell/actions+[CI-badge]: https://img.shields.io/github/actions/workflow/status/biscuit-auth/biscuit-haskell/github-actions.yml?style=flat-square&branch=main+[CI-url]: https://github.com/biscuit-auth/biscuit-haskell/actions [Hackage]: https://img.shields.io/hackage/v/biscuit-haskell?color=purple&style=flat-square [hackage-url]: https://hackage.haskell.org/package/biscuit-haskell [gcouprie]: https://github.com/geal
biscuit-haskell.cabal view
@@ -1,7 +1,7 @@ cabal-version: 2.0  name:           biscuit-haskell-version:        0.3.0.1+version:        0.4.0.0 category:       Security synopsis:       Library support for the Biscuit security token description:    Please see the README on GitHub at <https://github.com/biscuit-auth/biscuit-haskell#readme>
src/Auth/Biscuit/Datalog/Executor.hs view
@@ -53,6 +53,7 @@ import qualified Data.Set                 as Set import           Data.Text                (Text, isInfixOf, unpack) import qualified Data.Text                as Text+import qualified Data.Text.Encoding       as Text import           Data.Void                (absurd) import           Numeric.Natural          (Natural) import qualified Text.Regex.TDFA          as Regex@@ -60,7 +61,7 @@ import           Validation               (Validation (..), failure)  import           Auth.Biscuit.Datalog.AST-import           Auth.Biscuit.Utils       (maybeToRight)+import           Auth.Biscuit.Utils       (allM, anyM, maybeToRight, setFilterM)  -- | A variable name type Name = Text@@ -105,6 +106,8 @@   | ResultError ResultError   -- ^ The evaluation ran to completion, but checks and policies were not   -- fulfilled.+  | EvaluationError String+  -- ^ Datalog evaluation failed while evaluating an expression   deriving (Eq, Show)  -- | Settings for the executor runtime restrictions.@@ -186,40 +189,40 @@ countFacts :: FactGroup -> Int countFacts (FactGroup facts) = sum $ Set.size <$> Map.elems facts --- todo handle Check All-checkCheck :: Limits -> Natural -> Natural -> FactGroup -> EvalCheck -> Validation (NonEmpty Check) ()-checkCheck l blockCount checkBlockId facts c@Check{cQueries,cKind} =+checkCheck :: Limits -> Natural -> Natural -> FactGroup -> EvalCheck -> Either String (Validation (NonEmpty Check) ())+checkCheck l blockCount checkBlockId facts c@Check{cQueries,cKind} = do   let isQueryItemOk = case cKind of         One -> isQueryItemSatisfied l blockCount checkBlockId facts         All -> isQueryItemSatisfiedForAllMatches l blockCount checkBlockId facts-   in if any (isJust . isQueryItemOk) cQueries-      then Success ()-      else failure (toRepresentation c)+  hasOkQueryItem <- anyM (fmap isJust . isQueryItemOk) cQueries+  pure $ if hasOkQueryItem+         then Success ()+         else failure (toRepresentation c) -checkPolicy :: Limits -> Natural -> FactGroup -> EvalPolicy -> Maybe (Either MatchedQuery MatchedQuery)-checkPolicy l blockCount facts (pType, query) =-  let bindings = fold $ mapMaybe (isQueryItemSatisfied l blockCount blockCount facts) query-   in if not (null bindings)-      then Just $ case pType of-        Allow -> Right $ MatchedQuery{matchedQuery = toRepresentation <$> query, bindings}-        Deny  -> Left $ MatchedQuery{matchedQuery = toRepresentation <$> query, bindings}-      else Nothing+checkPolicy :: Limits -> Natural -> FactGroup -> EvalPolicy -> Either String (Maybe (Either MatchedQuery MatchedQuery))+checkPolicy l blockCount facts (pType, query) = do+  bindings <- fold . fold <$> traverse (isQueryItemSatisfied l blockCount blockCount facts) query+  pure $ if not (null bindings)+         then Just $ case pType of+           Allow -> Right $ MatchedQuery{matchedQuery = toRepresentation <$> query, bindings}+           Deny  -> Left $ MatchedQuery{matchedQuery = toRepresentation <$> query, bindings}+         else Nothing -isQueryItemSatisfied :: Limits -> Natural -> Natural -> FactGroup -> QueryItem' 'Eval 'Representation -> Maybe (Set Bindings)-isQueryItemSatisfied l blockCount blockId allFacts QueryItem{qBody, qExpressions, qScope} =+isQueryItemSatisfied :: Limits -> Natural -> Natural -> FactGroup -> QueryItem' 'Eval 'Representation -> Either String (Maybe (Set Bindings))+isQueryItemSatisfied l blockCount blockId allFacts QueryItem{qBody, qExpressions, qScope} = do   let removeScope = Set.map snd       facts = toScopedFacts $ keepAuthorized' False blockCount allFacts qScope blockId-      bindings = removeScope $ getBindingsForRuleBody l facts qBody qExpressions-   in if Set.size bindings > 0-      then Just bindings-      else Nothing+  bindings <- removeScope <$> getBindingsForRuleBody l facts qBody qExpressions+  pure $ if Set.size bindings > 0+         then Just bindings+         else Nothing  -- | Given a set of scoped facts and a rule body, we generate a set of variable -- bindings that satisfy the rule clauses (predicates match, and expression constraints -- are fulfilled), and ensure that all bindings where predicates match also fulfill -- expression constraints. This is the behaviour of `check all`.-isQueryItemSatisfiedForAllMatches :: Limits -> Natural -> Natural -> FactGroup -> QueryItem' 'Eval 'Representation -> Maybe (Set Bindings)-isQueryItemSatisfiedForAllMatches l blockCount blockId allFacts QueryItem{qBody, qExpressions, qScope} =+isQueryItemSatisfiedForAllMatches :: Limits -> Natural -> Natural -> FactGroup -> QueryItem' 'Eval 'Representation -> Either String (Maybe (Set Bindings))+isQueryItemSatisfiedForAllMatches l blockCount blockId allFacts QueryItem{qBody, qExpressions, qScope} = do   let removeScope = Set.map snd       facts = toScopedFacts $ keepAuthorized' False blockCount allFacts qScope blockId       allVariables = extractVariables qBody@@ -228,26 +231,24 @@       -- bindings that unify correctly (each variable has a single possible match)       legalBindingsForFacts = reduceCandidateBindings allVariables candidateBindings       -- bindings that fulfill the constraints-      constraintFulfillingBindings = Set.filter (\b -> all (satisfies l b) qExpressions) legalBindingsForFacts-   in if Set.size constraintFulfillingBindings > 0 -- there is at least one match that fulfills the constraints-      && constraintFulfillingBindings == legalBindingsForFacts -- all matches fulfill the constraints-      then Just $ removeScope constraintFulfillingBindings-      else Nothing+  constraintFulfillingBindings <- setFilterM (\b -> allM (satisfies l b) qExpressions) legalBindingsForFacts+  pure $ if Set.size constraintFulfillingBindings > 0 -- there is at least one match that fulfills the constraints+         && constraintFulfillingBindings == legalBindingsForFacts -- all matches fulfill the constraints+         then Just $ removeScope constraintFulfillingBindings+         else Nothing  -- | Given a rule and a set of available (scoped) facts, we find all fact -- combinations that match the rule body, and generate new facts by applying -- the bindings to the rule head (while keeping track of the facts origins)-getFactsForRule :: Limits -> Set (Scoped Fact) -> EvalRule -> Set (Scoped Fact)-getFactsForRule l facts Rule{rhead, body, expressions} =-  let legalBindings :: Set (Scoped Bindings)-      legalBindings = getBindingsForRuleBody l facts body expressions-      newFacts = mapMaybe (applyBindings rhead) $ Set.toList legalBindings-   in Set.fromList newFacts+getFactsForRule :: Limits -> Set (Scoped Fact) -> EvalRule -> Either String (Set (Scoped Fact))+getFactsForRule l facts Rule{rhead, body, expressions} = do+  legalBindings <- getBindingsForRuleBody l facts body expressions+  pure $ Set.fromList $ mapMaybe (applyBindings rhead) $ Set.toList legalBindings  -- | Given a set of scoped facts and a rule body, we generate a set of variable -- bindings that satisfy the rule clauses (predicates match, and expression constraints -- are fulfilled)-getBindingsForRuleBody :: Limits -> Set (Scoped Fact) -> [Predicate] -> [Expression] -> Set (Scoped Bindings)+getBindingsForRuleBody :: Limits -> Set (Scoped Fact) -> [Predicate] -> [Expression] -> Either String (Set (Scoped Bindings)) getBindingsForRuleBody l facts body expressions =   let -- gather bindings from all the facts that match the query's predicates       candidateBindings = getCandidateBindings facts body@@ -255,13 +256,13 @@       -- only keep bindings combinations where each variable has a single possible match       legalBindingsForFacts = reduceCandidateBindings allVariables candidateBindings       -- only keep bindings that satisfy the query expressions-   in Set.filter (\b -> all (satisfies l b) expressions) legalBindingsForFacts+   in setFilterM (\b -> allM (satisfies l b) expressions) legalBindingsForFacts  satisfies :: Limits           -> Scoped Bindings           -> Expression-          -> Bool-satisfies l b e = evaluateExpression l (snd b) e == Right (LBool True)+          -> Either String Bool+satisfies l b e = (== LBool True) <$> evaluateExpression l (snd b) e  applyBindings :: Predicate -> Scoped Bindings -> Maybe (Scoped Fact) applyBindings p@Predicate{terms} (origins, bindings) =@@ -372,7 +373,7 @@ evalUnary Parens t = pure t evalUnary Negate (LBool b) = pure (LBool $ not b) evalUnary Negate _ = Left "Only booleans support negation"-evalUnary Length (LString t) = pure . LInteger . fromIntegral $ Text.length t+evalUnary Length (LString t) = pure . LInteger . fromIntegral $ ByteString.length $ Text.encodeUtf8 t evalUnary Length (LBytes bs) = pure . LInteger . fromIntegral $ ByteString.length bs evalUnary Length (TermSet s) = pure . LInteger . fromIntegral $ Set.size s evalUnary Length _ = Left "Only strings, bytes and sets support `.length()`"@@ -475,3 +476,4 @@     EValue term -> applyVariable b term     EUnary op e' -> evalUnary op =<< evaluateExpression l b e'     EBinary op e' e'' -> uncurry (evalBinary l op) =<< join bitraverse (evaluateExpression l b) (e', e'')+
src/Auth/Biscuit/Datalog/ScopedExecutor.hs view
@@ -30,14 +30,13 @@                                                 gets, lift, put) import           Data.Bifunctor                (first) import           Data.ByteString               (ByteString)-import           Data.Foldable                 (traverse_)+import           Data.Foldable                 (sequenceA_) import           Data.List                     (genericLength) import           Data.List.NonEmpty            (NonEmpty) import qualified Data.List.NonEmpty            as NE import           Data.Map                      (Map) import qualified Data.Map                      as Map import           Data.Map.Strict               ((!?))-import           Data.Maybe                    (mapMaybe) import           Data.Set                      (Set) import qualified Data.Set                      as Set import           Data.Text                     (Text)@@ -58,11 +57,13 @@                                                 keepAuthorized', toScopedFacts) import           Auth.Biscuit.Datalog.Parser   (fact) import           Auth.Biscuit.Timer            (timer)+import           Auth.Biscuit.Utils            (foldMapM, mapMaybeM)+import           Data.Bitraversable            (bisequence)  type BlockWithRevocationId = (Block, ByteString, Maybe PublicKey)  -- | A subset of 'ExecutionError' that can only happen during fact generation-data PureExecError = Facts | Iterations | BadRule+data PureExecError = Facts | Iterations | BadRule | BadExpression String   deriving (Eq, Show)  -- | Proof that a biscuit was authorized successfully. In addition to the matched@@ -172,6 +173,7 @@         Facts      -> TooManyFacts         Iterations -> TooManyIterations         BadRule    -> InvalidRule+        BadExpression e -> EvaluationError e   allFacts <- first toExecutionError $ computeAllFacts initState   let checks = bChecks <$$> ( zip [0..] (fst' <$> authority : blocks)                            <> [(blockCount,vBlock authorizer)]@@ -179,13 +181,14 @@       policies = vPolicies authorizer       checkResults = checkChecks limits blockCount allFacts (checkToEvaluation externalKeys <$$$> checks)       policyResults = checkPolicies limits blockCount allFacts (policyToEvaluation externalKeys <$> policies)-  case (checkResults, policyResults) of-    (Success (), Left Nothing)  -> Left $ ResultError $ NoPoliciesMatched []-    (Success (), Left (Just p)) -> Left $ ResultError $ DenyRuleMatched [] p-    (Failure cs, Left Nothing)  -> Left $ ResultError $ NoPoliciesMatched (NE.toList cs)-    (Failure cs, Left (Just p)) -> Left $ ResultError $ DenyRuleMatched (NE.toList cs) p-    (Failure cs, Right _)       -> Left $ ResultError $ FailedChecks cs-    (Success (), Right p)       -> Right $ AuthorizationSuccess { matchedAllowQuery = p+  case bisequence (checkResults, policyResults) of+    Left e                            -> Left $ EvaluationError e+    Right (Success (), Left Nothing)  -> Left $ ResultError $ NoPoliciesMatched []+    Right (Success (), Left (Just p)) -> Left $ ResultError $ DenyRuleMatched [] p+    Right (Failure cs, Left Nothing)  -> Left $ ResultError $ NoPoliciesMatched (NE.toList cs)+    Right (Failure cs, Left (Just p)) -> Left $ ResultError $ DenyRuleMatched (NE.toList cs) p+    Right (Failure cs, Right _)       -> Left $ ResultError $ FailedChecks cs+    Right (Success (), Right p)       -> Right $ AuthorizationSuccess { matchedAllowQuery = p                                                                 , allFacts                                                                 , limits                                                                 }@@ -195,8 +198,10 @@   state@ComputeState{sLimits,sFacts,sRules,sBlockCount,sIterations} <- get   let Limits{maxFacts, maxIterations} = sLimits       previousCount = countFacts sFacts-      newFacts = sFacts <> extend sLimits sBlockCount sRules sFacts-      newCount = countFacts newFacts+      generatedFacts :: Either PureExecError FactGroup+      generatedFacts = first BadExpression $ extend sLimits sBlockCount sRules sFacts+  newFacts <- (sFacts <>) <$> lift generatedFacts+  let newCount = countFacts newFacts       -- counting the facts returned by `extend` is not equivalent to       -- comparing complete counts, as `extend` may return facts that       -- are already present in `sFacts`@@ -206,7 +211,7 @@   put $ state { sIterations = sIterations + 1               , sFacts = newFacts               }-  return addedFactsCount+  pure addedFactsCount  -- | Check if every variable from the head is present in the body checkRuleHead :: EvalRule -> Bool@@ -234,39 +239,39 @@   let initState = ComputeState{sIterations = 0, ..}    in computeAllFacts initState -checkChecks :: Limits -> Natural -> FactGroup -> [(Natural, [EvalCheck])] -> Validation (NonEmpty Check) ()+checkChecks :: Limits -> Natural -> FactGroup -> [(Natural, [EvalCheck])] -> Either String (Validation (NonEmpty Check) ()) checkChecks limits blockCount allFacts =-  traverse_ (uncurry $ checkChecksForGroup limits blockCount allFacts)+  fmap sequenceA_ . traverse (uncurry $ checkChecksForGroup limits blockCount allFacts) -checkChecksForGroup :: Limits -> Natural -> FactGroup -> Natural -> [EvalCheck] -> Validation (NonEmpty Check) ()+checkChecksForGroup :: Limits -> Natural -> FactGroup -> Natural -> [EvalCheck] -> Either String (Validation (NonEmpty Check) ()) checkChecksForGroup limits blockCount allFacts checksBlockId =-  traverse_ (checkCheck limits blockCount checksBlockId allFacts)+  fmap sequenceA_ . traverse (checkCheck limits blockCount checksBlockId allFacts) -checkPolicies :: Limits -> Natural -> FactGroup -> [EvalPolicy] -> Either (Maybe MatchedQuery) MatchedQuery-checkPolicies limits blockCount allFacts policies =-  let results = mapMaybe (checkPolicy limits blockCount allFacts) policies-   in case results of-        p : _ -> first Just p-        []    -> Left Nothing+checkPolicies :: Limits -> Natural -> FactGroup -> [EvalPolicy] -> Either String (Either (Maybe MatchedQuery) MatchedQuery)+checkPolicies limits blockCount allFacts policies = do+  results <- mapMaybeM (checkPolicy limits blockCount allFacts) policies+  pure $ case results of+           p : _ -> first Just p+           []    -> Left Nothing  -- | Generate new facts by applying rules on existing facts-extend :: Limits -> Natural -> Map Natural (Set EvalRule) -> FactGroup -> FactGroup+extend :: Limits -> Natural -> Map Natural (Set EvalRule) -> FactGroup -> Either String FactGroup extend l blockCount rules facts =-  let buildFacts :: Natural -> Set EvalRule -> FactGroup -> Set (Scoped Fact)+  let buildFacts :: Natural -> Set EvalRule -> FactGroup -> Either String (Set (Scoped Fact))       buildFacts ruleBlockId ruleGroup factGroup =-        let extendRule :: EvalRule -> Set (Scoped Fact)+        let extendRule :: EvalRule -> Either String (Set (Scoped Fact))             extendRule r@Rule{scope} = getFactsForRule l (toScopedFacts $ keepAuthorized' False blockCount factGroup scope ruleBlockId) r-         in foldMap extendRule ruleGroup+         in foldMapM extendRule ruleGroup -      extendRuleGroup :: Natural -> Set EvalRule -> FactGroup+      extendRuleGroup :: Natural -> Set EvalRule -> Either String FactGroup       extendRuleGroup ruleBlockId ruleGroup =             -- todo pre-filter facts based on the weakest rule scope to avoid passing too many facts             -- to buildFacts         let authorizedFacts = facts -- test $ keepAuthorized facts $ Set.fromList [0..ruleBlockId]             addRuleOrigin = FactGroup . Map.mapKeysWith (<>) (Set.insert ruleBlockId) . getFactGroup-         in addRuleOrigin . fromScopedFacts $ buildFacts ruleBlockId ruleGroup authorizedFacts+         in addRuleOrigin . fromScopedFacts <$> buildFacts ruleBlockId ruleGroup authorizedFacts -   in foldMap (uncurry extendRuleGroup) $ Map.toList rules+   in foldMapM (uncurry extendRuleGroup) $ Map.toList rules   collectWorld :: Natural -> EvalBlock -> (Map Natural (Set EvalRule), FactGroup)@@ -278,18 +283,18 @@       , FactGroup $ Map.singleton (Set.singleton blockId) $ Set.fromList bFacts       ) -queryGeneratedFacts :: [Maybe PublicKey] -> AuthorizationSuccess -> Query -> Set Bindings+queryGeneratedFacts :: [Maybe PublicKey] -> AuthorizationSuccess -> Query -> Either String (Set Bindings) queryGeneratedFacts ePks AuthorizationSuccess{allFacts, limits} =   queryAvailableFacts ePks allFacts limits -queryAvailableFacts :: [Maybe PublicKey] -> FactGroup -> Limits -> Query -> Set Bindings+queryAvailableFacts :: [Maybe PublicKey] -> FactGroup -> Limits -> Query -> Either String (Set Bindings) queryAvailableFacts ePks allFacts limits q =   let blockCount = genericLength ePks       getBindingsForQueryItem QueryItem{qBody,qExpressions,qScope} =         let facts = toScopedFacts $ keepAuthorized' True blockCount allFacts qScope blockCount-         in Set.map snd $+         in Set.map snd <$>             getBindingsForRuleBody limits facts qBody qExpressions-   in foldMap (getBindingsForQueryItem . toEvaluation ePks) q+   in foldMapM (getBindingsForQueryItem . toEvaluation ePks) q  -- | Extract a set of values from a matched variable for a specific type. -- Returning @Set Value@ allows to get all values, whatever their type.
src/Auth/Biscuit/ProtoBufAdapter.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE DataKinds         #-} {-# LANGUAGE LambdaCase        #-}+{-# LANGUAGE MultiWayIf        #-} {-# LANGUAGE NamedFieldPuns    #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards   #-}@@ -25,13 +26,12 @@   , thirdPartyBlockContentsToPb   ) where -import           Control.Monad            (when)+import           Control.Monad            (unless, when) import           Control.Monad.State      (StateT, get, lift, modify)-import           Data.Bitraversable       (bisequence) import           Data.ByteString          (ByteString) import           Data.Int                 (Int64) import qualified Data.List.NonEmpty       as NE-import           Data.Maybe               (isNothing)+import           Data.Maybe               (isJust, isNothing) import qualified Data.Set                 as Set import qualified Data.Text                as T import           Data.Time                (UTCTime)@@ -110,17 +110,17 @@   -- but use the global public keys table:   --   symbols defined in 3rd party blocks are not visible   --   to following blocks, but public keys are-  when (isNothing ePk) $ modify (registerNewSymbols blockSymbols)-  modify (registerNewPublicKeys $ foldMap pure ePk <> blockPks)+  when (isNothing ePk) $ do+    modify (registerNewSymbols blockSymbols)+    modify (registerNewPublicKeys blockPks)   currentSymbols <- get    let symbolsForCurrentBlock =-        -- third party blocks use an isolated symbol table,-        -- but use the global public keys table.+        -- third party blocks use an isolated symbol and public keys table,         --   3rd party blocks don't see previously defined-        --   symbols, but see previously defined public keys+        --   symbols or public keys         if isNothing ePk then currentSymbols-                         else registerNewSymbols blockSymbols $ forgetSymbols currentSymbols+                         else registerNewPublicKeys blockPks $ registerNewSymbols blockSymbols newSymbolTable   let bContext = PB.getField context       bVersion = PB.getField version   lift $ do@@ -129,18 +129,25 @@     bRules <- traverse (pbToRule s) $ PB.getField rules_v2     bChecks <- traverse (pbToCheck s) $ PB.getField checks_v2     bScope <- Set.fromList <$> traverse (pbToScope s) (PB.getField scope)-    let isV3 = isNothing ePk-            && Set.null bScope-            && all ruleHasNoScope bRules-            && all queryHasNoScope (cQueries <$> bChecks)-            && all isCheckOne bChecks-            && all ruleHasNoV4Operators bRules-            && all queryHasNoV4Operators (cQueries <$> bChecks)-    case (bVersion, isV3) of-      (Just 4, _) -> pure Block {..}-      (Just 3, True) -> pure Block {..}-      (Just 3, False) ->-        Left "Biscuit v4 fields are present, but the block version is 3."+    let v5Plus = isJust ePk+        v4Plus = not $ and+          [ Set.null bScope+          , all ruleHasNoScope bRules+          , all (queryHasNoScope . cQueries) bChecks+          , all isCheckOne bChecks+          , all ruleHasNoV4Operators bRules+          , all (queryHasNoV4Operators . cQueries) bChecks+          ]+    case (bVersion, v4Plus, v5Plus) of+      (Just 5, _, _) -> pure Block {..}+      (Just 4, _, False) -> pure Block {..}+      (Just 4, _, True) ->+        Left "Biscuit v5 features are present, but the block version is 4."+      (Just 3, False, False) -> pure Block {..}+      (Just 3, True, False) ->+        Left "Biscuit v4 features are present, but the block version is 3."+      (Just 3, _, True) ->+        Left "Biscuit v5 features are present, but the block version is 3."       _ ->         Left $ "Unsupported biscuit version: " <> maybe "0" show bVersion <> ". Only versions 3 and 4 are supported" @@ -148,13 +155,15 @@ -- along with the newly defined symbols blockToPb :: Bool -> Symbols -> Block -> (BlockSymbols, PB.Block) blockToPb hasExternalPk existingSymbols b@Block{..} =-  let isV3 = not hasExternalPk-            && Set.null bScope-            && all ruleHasNoScope bRules-            && all queryHasNoScope (cQueries <$> bChecks)-            && all isCheckOne bChecks-            && all ruleHasNoV4Operators bRules-            && all queryHasNoV4Operators (cQueries <$> bChecks)+  let v4Plus = not $ and+        [Set.null bScope+        , all ruleHasNoScope bRules+        , all (queryHasNoScope . cQueries) bChecks+        , all isCheckOne bChecks+        , all ruleHasNoV4Operators bRules+        , all (queryHasNoV4Operators . cQueries) bChecks+        ]+      v5Plus = hasExternalPk       bSymbols = buildSymbolTable existingSymbols b       s = reverseSymbols $ addFromBlock existingSymbols bSymbols       symbols   = PB.putField $ getSymbolList bSymbols@@ -164,8 +173,9 @@       checks_v2 = PB.putField $ checkToPb s <$> bChecks       scope     = PB.putField $ scopeToPb s <$> Set.toList bScope       pksTable   = PB.putField $ publicKeyToPb <$> getPkList bSymbols-      version   = PB.putField $ if isV3 then Just 3-                                        else Just 4+      version   = PB.putField $ if | v5Plus    -> Just 5+                                   | v4Plus    -> Just 4+                                   | otherwise -> Just 3    in (bSymbols, PB.Block {..})  pbToFact :: Symbols -> PB.FactV2 -> Either String Fact@@ -415,17 +425,15 @@   BitwiseXor     -> PB.BitwiseXor   NotEqual       -> PB.NotEqual -pbToThirdPartyBlockRequest :: PB.ThirdPartyBlockRequest -> Either String (Crypto.PublicKey, [Crypto.PublicKey])+pbToThirdPartyBlockRequest :: PB.ThirdPartyBlockRequest -> Either String Crypto.PublicKey pbToThirdPartyBlockRequest PB.ThirdPartyBlockRequest{previousPk, pkTable} = do-  bisequence-    ( pbToPublicKey $ PB.getField previousPk-    , traverse pbToPublicKey $ PB.getField pkTable-    )+  unless (null $ PB.getField pkTable) $ Left "Public key table provided in third-party block request"+  pbToPublicKey $ PB.getField previousPk -thirdPartyBlockRequestToPb :: (Crypto.PublicKey, [Crypto.PublicKey]) -> PB.ThirdPartyBlockRequest-thirdPartyBlockRequestToPb (previousPk, pkTable) = PB.ThirdPartyBlockRequest+thirdPartyBlockRequestToPb :: Crypto.PublicKey -> PB.ThirdPartyBlockRequest+thirdPartyBlockRequestToPb previousPk = PB.ThirdPartyBlockRequest   { previousPk = PB.putField $ publicKeyToPb previousPk-  , pkTable = PB.putField $ publicKeyToPb <$> pkTable+  , pkTable = PB.putField []   }  pbToThirdPartyBlockContents :: PB.ThirdPartyBlockContents -> Either String (ByteString, Crypto.Signature, Crypto.PublicKey)
src/Auth/Biscuit/Symbols.hs view
@@ -15,7 +15,6 @@   , addFromBlock   , registerNewSymbols   , registerNewPublicKeys-  , forgetSymbols   , reverseSymbols   , getSymbolList   , getPkList@@ -138,9 +137,6 @@ registerNewPublicKeys newPks s@Symbols{publicKeys} =   let newPkMap = Map.fromList $ zip [getNextPublicKeyOffset s..] (newPks \\ elems publicKeys)    in s { publicKeys = publicKeys <> newPkMap }--forgetSymbols :: Symbols -> Symbols-forgetSymbols s = s { symbols = commonSymbols }  -- | Reverse a symbol table reverseSymbols :: Symbols -> ReverseSymbols
src/Auth/Biscuit/Token.hs view
@@ -215,7 +215,7 @@ -- with a @trusting@ annotation. Be careful with @trusting previous@, as it queries -- facts from all blocks, even untrusted ones. queryRawBiscuitFactsWithLimits :: Biscuit openOrSealed check -> Limits -> Query-                               -> Set Bindings+                               -> Either String (Set Bindings) queryRawBiscuitFactsWithLimits b@Biscuit{authority,blocks} =   let ePks = externalKeys b       getBlock ((_, block), _, _, _) = block@@ -235,7 +235,7 @@ -- 💁 If the facts you want to query are part of an allow query in the authorizer, -- you can directly get values by calling 'getBindings' on 'AuthorizationSuccess'. queryRawBiscuitFacts :: Biscuit openOrSealed check -> Query-                     -> Set Bindings+                     -> Either String (Set Bindings) queryRawBiscuitFacts b = queryRawBiscuitFactsWithLimits b defaultLimits  -- | Turn a 'Biscuit' statically known to be 'Open' into a more generic 'OpenOrSealed' 'Biscuit'@@ -306,26 +306,21 @@                -> Biscuit Open check                -> IO (Biscuit Open check) addSignedBlock eSk block b@Biscuit{..} = do-  let symbolsForCurrentBlock = forgetSymbols $ registerNewPublicKeys [toPublic eSk] symbols-      (newSymbols, blockSerialized) = PB.encodeBlock <$> blockToPb True symbolsForCurrentBlock block+  let (_, blockSerialized) = PB.encodeBlock <$> blockToPb True newSymbolTable block       lastBlock = NE.last (authority :| blocks)       (_, _, lastPublicKey, _) = lastBlock       Open p = proof   (signedBlock, nextSk) <- signExternalBlock p eSk lastPublicKey blockSerialized   pure $ b { blocks = blocks <> [toParsedSignedBlock block signedBlock]-           , symbols = registerNewPublicKeys (getPkList newSymbols) symbols            , proof = Open nextSk            }  mkThirdPartyBlock' :: SecretKey-                   -> [PublicKey]                    -> PublicKey                    -> Block                    -> (ByteString, Signature, PublicKey)-mkThirdPartyBlock' eSk pkTable lastPublicKey block =-  let symbolsForCurrentBlock = registerNewPublicKeys [toPublic eSk] $-        registerNewPublicKeys pkTable newSymbolTable-      (_, payload) = PB.encodeBlock <$> blockToPb True symbolsForCurrentBlock block+mkThirdPartyBlock' eSk lastPublicKey block =+  let (_, payload) = PB.encodeBlock <$> blockToPb True newSymbolTable block       (eSig, ePk) = sign3rdPartyBlock eSk lastPublicKey payload    in (payload, eSig, ePk) @@ -336,17 +331,17 @@                   -> Block                   -> Either String ByteString mkThirdPartyBlock eSk req block = do-  (previousPk, pkTable) <- pbToThirdPartyBlockRequest =<< PB.decodeThirdPartyBlockRequest req-  pure $ PB.encodeThirdPartyBlockContents . thirdPartyBlockContentsToPb $ mkThirdPartyBlock' eSk pkTable previousPk block+  previousPk<- pbToThirdPartyBlockRequest =<< PB.decodeThirdPartyBlockRequest req+  pure $ PB.encodeThirdPartyBlockContents . thirdPartyBlockContentsToPb $ mkThirdPartyBlock' eSk previousPk block  -- | Generate a third-party block request. It can be used in -- conjunction with 'mkThirdPartyBlock' to generate a -- third-party block, which can be then appended to a token with -- 'applyThirdPartyBlock'. mkThirdPartyBlockReq :: Biscuit proof check -> ByteString-mkThirdPartyBlockReq Biscuit{authority,blocks,symbols} =+mkThirdPartyBlockReq Biscuit{authority,blocks} =   let (_, _ , lastPk, _) = NE.last $ authority :| blocks-   in PB.encodeThirdPartyBlockRequest $ thirdPartyBlockRequestToPb (lastPk, getPkTable symbols)+   in PB.encodeThirdPartyBlockRequest $ thirdPartyBlockRequestToPb lastPk  -- | Given a base64-encoded third-party block, append it to a token. applyThirdPartyBlock :: Biscuit Open check -> ByteString -> Either String (IO (Biscuit Open check))@@ -621,7 +616,7 @@ -- 💁 If you are trying to extract facts from a biscuit in order to generate an -- authorizer, have a look at 'queryRawBiscuitFacts' instead. queryAuthorizerFacts :: AuthorizedBiscuit p -> Query-                     -> Set Bindings+                     -> Either String (Set Bindings) queryAuthorizerFacts AuthorizedBiscuit{authorizedBiscuit, authorizationSuccess} =   let ePks = externalKeys authorizedBiscuit    in queryGeneratedFacts ePks authorizationSuccess
src/Auth/Biscuit/Utils.hs view
@@ -11,15 +11,25 @@     encodeHex,     encodeHex',     decodeHex,+    anyM,+    allM,+    setFilterM,+    foldMapM,+    mapMaybeM,   ) where  #if MIN_VERSION_base16(1,0,0)-import qualified Data.Base16.Types as Hex+import qualified Data.Base16.Types      as Hex #endif-import Data.ByteString (ByteString)+import           Data.Bool              (bool)+import           Data.ByteString        (ByteString) import qualified Data.ByteString.Base16 as Hex-import Data.Text (Text)+import           Data.Maybe             (maybeToList)+import           Data.Monoid            (All (..), Any (..))+import           Data.Set               (Set)+import qualified Data.Set               as Set+import           Data.Text              (Text)  encodeHex :: ByteString -> Text #if MIN_VERSION_base16(1,0,0)@@ -51,3 +61,22 @@ -- but without the dependency footprint rightToMaybe :: Either b a -> Maybe a rightToMaybe = either (const Nothing) Just++anyM :: (Foldable t, Monad m) => (a -> m Bool) -> t a -> m Bool+anyM f = fmap getAny . foldMapM (fmap Any . f)++allM :: (Foldable t, Monad m) => (a -> m Bool) -> t a -> m Bool+allM f = fmap getAll . foldMapM (fmap All . f)++setFilterM :: (Ord a, Monad m) => (a -> m Bool) -> Set a -> m (Set a)+setFilterM p = foldMapM (\a -> bool mempty (Set.singleton a) <$> p a)++-- from Relude+foldMapM :: (Monoid b, Monad m, Foldable f) => (a -> m b) -> f a -> m b+foldMapM f xs = foldr step return xs mempty+  where+    step x r z = f x >>= \y -> r $! z `mappend` y+{-# INLINE foldMapM #-}++mapMaybeM :: (Monad m) => (a -> m (Maybe b)) -> [a] -> m [b]+mapMaybeM f = foldMapM (fmap maybeToList . f)
test/Spec/Executor.hs view
@@ -30,6 +30,7 @@   , rulesWithConstraints   , ruleHeadWithNoVars   , limits+  , overflow   ]  authGroup :: Set Fact -> FactGroup@@ -102,6 +103,7 @@     , ("!false", LBool True)     , ("(true)", LBool True)     , ("\"test\".length()", LInteger 4)+    , ("\"é\".length()", LInteger 2)     , ("hex:ababab.length()", LInteger 3)     , ("[].length()", LInteger 0)     , ("[\"test\", \"test\"].length()", LInteger 1)@@ -296,3 +298,20 @@                       ])             ])   ]++overflow :: TestTree+overflow =+  let subtraction = authRulesGroup $ Set.singleton+                   [rule|test(true) <- -9223372036854775808 - 1 != 0|]+      multiplication = authRulesGroup $ Set.singleton+                   [rule|test(true) <- 10000000000 * 10000000000 != 0|]+      addition = authRulesGroup $ Set.singleton+                   [rule|test(true) <- 9223372036854775807 + 1 != 0|]+   in testGroup "Arithmetic overflow"+        [ testCase "subtraction" $+            runFactGeneration defaultLimits 1 subtraction mempty @?= Left (BadExpression "integer underflow")+        , testCase "multiplication" $+            runFactGeneration defaultLimits 1 multiplication mempty @?= Left (BadExpression "integer overflow")+        , testCase "addition" $+            runFactGeneration defaultLimits 1 addition mempty @?= Left (BadExpression "integer overflow")+        ]
test/Spec/SampleReader.hs view
@@ -1,14 +1,15 @@-{-# LANGUAGE DataKinds          #-}-{-# LANGUAGE DeriveAnyClass     #-}-{-# LANGUAGE DeriveFunctor      #-}-{-# LANGUAGE DeriveGeneric      #-}-{-# LANGUAGE DeriveTraversable  #-}-{-# LANGUAGE DerivingStrategies #-}-{-# LANGUAGE FlexibleInstances  #-}-{-# LANGUAGE LambdaCase         #-}-{-# LANGUAGE NamedFieldPuns     #-}-{-# LANGUAGE OverloadedStrings  #-}-{-# LANGUAGE RecordWildCards    #-}+{-# LANGUAGE DataKinds             #-}+{-# LANGUAGE DeriveAnyClass        #-}+{-# LANGUAGE DeriveGeneric         #-}+{-# LANGUAGE DeriveTraversable     #-}+{-# LANGUAGE DerivingStrategies    #-}+{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE FlexibleInstances     #-}+{-# LANGUAGE LambdaCase            #-}+{-# LANGUAGE NamedFieldPuns        #-}+{-# LANGUAGE OverloadedStrings     #-}+{-# LANGUAGE RecordWildCards       #-}+{-# LANGUAGE TypeApplications      #-} module Spec.SampleReader where  import           Control.Arrow                 ((&&&))@@ -31,6 +32,7 @@ import           Data.Text.Encoding            (decodeUtf8, encodeUtf8) import           Data.Traversable              (for) import           GHC.Generics                  (Generic)+import           GHC.Records                   (HasField (getField))  import           Test.Tasty                    hiding (Timeout) import           Test.Tasty.HUnit@@ -151,11 +153,35 @@   deriving stock (Eq, Show, Generic)   deriving anyclass (FromJSON, ToJSON) +data FactSet+  = FactSet+  { origin :: [Maybe Integer]+  , facts  :: [Text]+  }+  deriving stock (Eq, Show, Generic)+  deriving anyclass (FromJSON, ToJSON)++data RuleSet+  = RuleSet+  { origin :: Maybe Integer+  , rules  :: [Text]+  }+  deriving stock (Eq, Show, Generic)+  deriving anyclass (FromJSON, ToJSON)++data CheckSet+  = CheckSet+  { origin :: Maybe Integer+  , checks :: [Text]+  }+  deriving stock (Eq, Show, Generic)+  deriving anyclass (FromJSON, ToJSON)+ data WorldDesc   =  WorldDesc-  { facts    :: [Text]-  , rules    :: [Text]-  , checks   :: [Text]+  { facts    :: [FactSet]+  , rules    :: [RuleSet]+  , checks   :: [CheckSet]   , policies :: [Text]   }   deriving stock (Eq, Show, Generic)@@ -163,9 +189,9 @@  instance Semigroup WorldDesc where   a <> b = WorldDesc-    { facts = facts a <> facts b-    , rules = rules a <> rules b-    , checks = checks a <> checks b+    { facts = getField @"facts" a <> getField @"facts" b+    , rules = getField @"rules" a <> getField @"rules" b+    , checks = getField @"checks" a <> getField @"checks" b     , policies = policies a <> policies b     } @@ -210,7 +236,7 @@ compareParseErrors :: ParseError -> RustError -> Assertion compareParseErrors pe re =   let mustMatch p = assertBool (show (re,pe)) $ isJust $ re ^? p-      mustMatchEither ps = assertBool (show (re, pe)) $ any isJust $ (re ^?) <$> ps+      mustMatchEither ps = assertBool (show (re, pe)) $ any (isJust . (re ^?)) ps    in case pe of         InvalidHexEncoding ->           assertFailure $ "InvalidHexEncoding can't appear here " <> show re@@ -248,6 +274,7 @@         TooManyFacts                       -> mustMatch $ key "RunLimit" . key "TooManyFacts"         TooManyIterations                  -> mustMatch $ key "RunLimit" . key "TooManyIterations"         InvalidRule                        -> mustMatch $ key "FailedLogic" . key "InvalidBlockRule"+        EvaluationError _                  -> mustMatch $ key "Execution"         ResultError (NoPoliciesMatched cs) -> mustMatch $ key "FailedLogic" . key "Unauthorized"         ResultError (FailedChecks cs)      -> mustMatch $ key "FailedLogic" . key "Unauthorized"         ResultError (DenyRuleMatched cs q) -> mustMatch $ key "FailedLogic" . key "Unauthorized"@@ -307,12 +334,7 @@       mkValidation authorizer = do         Right success <- authorizeBiscuit biscuit authorizer         pure ValidationR-          { world = Just $ WorldDesc-             { facts = []-             , rules = []-             , checks = []-             , policies = []-             }+          { world = Just mempty           , result = Ok 0           , authorizer_code = authorizer           , revocation_ids = encodeHex <$> toList (getRevocationIds biscuit)
test/Spec/ScopedExecutor.hs view
@@ -269,7 +269,7 @@           expected = Set.singleton $ Map.fromList             [ ("user", LInteger 1234)             ]-      getUser <$> result @?= Right expected+      getUser <$> result @?= Right (Right expected)   , testCase "Attenuation blocks can be accessed if asked nicely" $ do       (p,s) <- (toPublic &&& id) <$> newSecret       b <- mkBiscuit s [block|user(1234);|]@@ -280,7 +280,7 @@             [ Map.fromList [("user", LInteger 1234)]             , Map.fromList [("user", LString "tampered value")]             ]-      getUser <$> result @?= Right expected+      getUser <$> result @?= Right (Right expected)   , testCase "Signed blocks can be accessed if asked nicely" $ do       (p,s) <- (toPublic &&& id) <$> newSecret       (p1,s1) <- (toPublic &&& id) <$> newSecret@@ -293,7 +293,7 @@             [ Map.fromList [("user", LInteger 1234)]             , Map.fromList [("user", LString "from signed")]             ]-      getUser <$> result @?= Right expected+      getUser <$> result @?= Right (Right expected)   ]  biscuitFactsAreQueried :: TestTree@@ -306,7 +306,7 @@           expected = Set.singleton $ Map.fromList             [ ("user", LInteger 1234)             ]-      user @?= expected+      user @?= Right expected   , testCase "Attenuation blocks can be accessed if asked nicely" $ do       (p,s) <- (toPublic &&& id) <$> newSecret       b <- mkBiscuit s [block|user(1234);|]@@ -316,7 +316,7 @@             [ Map.fromList [("user", LInteger 1234)]             , Map.fromList [("user", LString "tampered value")]             ]-      user @?= expected+      user @?= Right expected   , testCase "Signed blocks can be accessed if asked nicely" $ do       (p,s) <- (toPublic &&& id) <$> newSecret       (p1,s1) <- (toPublic &&& id) <$> newSecret@@ -328,5 +328,5 @@             [ Map.fromList [("user", LInteger 1234)]             , Map.fromList [("user", LString "from signed")]             ]-      user @?= expected+      user @?= Right expected   ]
test/samples/current/samples.json view
@@ -1,1657 +1,2187 @@ {-  "root_private_key": "12aca40167fbdd1a11037e9fd440e3d510d9d9dea70a6646aa4aaf84d718d75a",-  "root_public_key": "acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189",-  "testcases": [-    {-      "title": "basic token",-      "filename": "test001_basic.bc",-      "token": [-        {-          "symbols": [-            "file1",-            "file2"-          ],-          "public_keys": [],-          "external_key": null,-          "code": "right(\"file1\", \"read\");\nright(\"file2\", \"read\");\nright(\"file1\", \"write\");\n"-        },-        {-          "symbols": [-            "0"-          ],-          "public_keys": [],-          "external_key": null,-          "code": "check if resource($0), operation(\"read\"), right($0, \"read\");\n"-        }-      ],-      "validations": {-        "": {-          "world": {-            "facts": [-              "resource(\"file1\")",-              "right(\"file1\", \"read\")",-              "right(\"file1\", \"write\")",-              "right(\"file2\", \"read\")"-            ],-            "rules": [],-            "checks": [-              "check if resource($0), operation(\"read\"), right($0, \"read\")"-            ],-            "policies": [-              "allow if true"-            ]-          },-          "result": {-            "Err": {-              "FailedLogic": {-                "Unauthorized": {-                  "policy": {-                    "Allow": 0-                  },-                  "checks": [-                    {-                      "Block": {-                        "block_id": 1,-                        "check_id": 0,-                        "rule": "check if resource($0), operation(\"read\"), right($0, \"read\")"-                      }-                    }-                  ]-                }-              }-            }-          },-          "authorizer_code": "resource(\"file1\");\n\nallow if true;\n",-          "revocation_ids": [-            "3ee1c0f42ba69ec63b1f39a6b3c57d25a4ccec452233ca6d40530ecfe83af4918fa78d9346f8b7c498545b54663960342b9ed298b2c8bbe2085b80c237b56f09",-            "e16ccf0820b02092adb531e36c2e82884c6c6c647b1c85184007f2ace601648afb71faa261b11f9ab352093c96187870f868588b664579c8018864b306bd5007"-          ]-        }-      }-    },-    {-      "title": "different root key",-      "filename": "test002_different_root_key.bc",-      "token": [-        {-          "symbols": [-            "file1"-          ],-          "public_keys": [],-          "external_key": null,-          "code": "right(\"file1\", \"read\");\n"-        },-        {-          "symbols": [-            "0"-          ],-          "public_keys": [],-          "external_key": null,-          "code": "check if resource($0), operation(\"read\"), right($0, \"read\");\n"-        }-      ],-      "validations": {-        "": {-          "world": null,-          "result": {-            "Err": {-              "Format": {-                "Signature": {-                  "InvalidSignature": "signature error: Verification equation was not satisfied"-                }-              }-            }-          },-          "authorizer_code": "",-          "revocation_ids": []-        }-      }-    },-    {-      "title": "invalid signature format",-      "filename": "test003_invalid_signature_format.bc",-      "token": [-        {-          "symbols": [-            "file1",-            "file2"-          ],-          "public_keys": [],-          "external_key": null,-          "code": "right(\"file1\", \"read\");\nright(\"file2\", \"read\");\nright(\"file1\", \"write\");\n"-        },-        {-          "symbols": [-            "0"-          ],-          "public_keys": [],-          "external_key": null,-          "code": "check if resource($0), operation(\"read\"), right($0, \"read\");\n"-        }-      ],-      "validations": {-        "": {-          "world": null,-          "result": {-            "Err": {-              "Format": {-                "InvalidSignatureSize": 16-              }-            }-          },-          "authorizer_code": "",-          "revocation_ids": []-        }-      }-    },-    {-      "title": "random block",-      "filename": "test004_random_block.bc",-      "token": [-        {-          "symbols": [-            "file1",-            "file2"-          ],-          "public_keys": [],-          "external_key": null,-          "code": "right(\"file1\", \"read\");\nright(\"file2\", \"read\");\nright(\"file1\", \"write\");\n"-        },-        {-          "symbols": [-            "0"-          ],-          "public_keys": [],-          "external_key": null,-          "code": "check if resource($0), operation(\"read\"), right($0, \"read\");\n"-        }-      ],-      "validations": {-        "": {-          "world": null,-          "result": {-            "Err": {-              "Format": {-                "Signature": {-                  "InvalidSignature": "signature error: Verification equation was not satisfied"-                }-              }-            }-          },-          "authorizer_code": "",-          "revocation_ids": []-        }-      }-    },-    {-      "title": "invalid signature",-      "filename": "test005_invalid_signature.bc",-      "token": [-        {-          "symbols": [-            "file1",-            "file2"-          ],-          "public_keys": [],-          "external_key": null,-          "code": "right(\"file1\", \"read\");\nright(\"file2\", \"read\");\nright(\"file1\", \"write\");\n"-        },-        {-          "symbols": [-            "0"-          ],-          "public_keys": [],-          "external_key": null,-          "code": "check if resource($0), operation(\"read\"), right($0, \"read\");\n"-        }-      ],-      "validations": {-        "": {-          "world": null,-          "result": {-            "Err": {-              "Format": {-                "Signature": {-                  "InvalidSignature": "signature error: Verification equation was not satisfied"-                }-              }-            }-          },-          "authorizer_code": "",-          "revocation_ids": []-        }-      }-    },-    {-      "title": "reordered blocks",-      "filename": "test006_reordered_blocks.bc",-      "token": [-        {-          "symbols": [-            "file1",-            "file2"-          ],-          "public_keys": [],-          "external_key": null,-          "code": "right(\"file1\", \"read\");\nright(\"file2\", \"read\");\nright(\"file1\", \"write\");\n"-        },-        {-          "symbols": [-            "0"-          ],-          "public_keys": [],-          "external_key": null,-          "code": "check if resource($0), operation(\"read\"), right($0, \"read\");\n"-        },-        {-          "symbols": [],-          "public_keys": [],-          "external_key": null,-          "code": "check if resource(\"file1\");\n"-        }-      ],-      "validations": {-        "": {-          "world": null,-          "result": {-            "Err": {-              "Format": {-                "Signature": {-                  "InvalidSignature": "signature error: Verification equation was not satisfied"-                }-              }-            }-          },-          "authorizer_code": "",-          "revocation_ids": []-        }-      }-    },-    {-      "title": "scoped rules",-      "filename": "test007_scoped_rules.bc",-      "token": [-        {-          "symbols": [-            "user_id",-            "alice",-            "file1"-          ],-          "public_keys": [],-          "external_key": null,-          "code": "user_id(\"alice\");\nowner(\"alice\", \"file1\");\n"-        },-        {-          "symbols": [-            "0",-            "1"-          ],-          "public_keys": [],-          "external_key": null,-          "code": "right($0, \"read\") <- resource($0), user_id($1), owner($1, $0);\ncheck if resource($0), operation(\"read\"), right($0, \"read\");\n"-        },-        {-          "symbols": [-            "file2"-          ],-          "public_keys": [],-          "external_key": null,-          "code": "owner(\"alice\", \"file2\");\n"-        }-      ],-      "validations": {-        "": {-          "world": {-            "facts": [-              "operation(\"read\")",-              "owner(\"alice\", \"file1\")",-              "owner(\"alice\", \"file2\")",-              "resource(\"file2\")",-              "user_id(\"alice\")"-            ],-            "rules": [-              "right($0, \"read\") <- resource($0), user_id($1), owner($1, $0)"-            ],-            "checks": [-              "check if resource($0), operation(\"read\"), right($0, \"read\")"-            ],-            "policies": [-              "allow if true"-            ]-          },-          "result": {-            "Err": {-              "FailedLogic": {-                "Unauthorized": {-                  "policy": {-                    "Allow": 0-                  },-                  "checks": [-                    {-                      "Block": {-                        "block_id": 1,-                        "check_id": 0,-                        "rule": "check if resource($0), operation(\"read\"), right($0, \"read\")"-                      }-                    }-                  ]-                }-              }-            }-          },-          "authorizer_code": "resource(\"file2\");\noperation(\"read\");\n\nallow if true;\n",-          "revocation_ids": [-            "02d287b0e5b22780192f8351538583c17f7d0200e064b32a1fcf07899e64ffb10e4de324f5c5ebc72c89a63e424317226cf555eb42dae81b2fd4639cf7591108",-            "22e75ea200cf7b2b62b389298fe0dec973b7f9c7e54e76c3c41811d72ea82c68227bc9079b7d05986de17ef9301cccdc08f5023455386987d1e6ee4391b19f06",-            "140a3631fecae550b51e50b9b822b947fb485c80070b34482fa116cdea560140164a1d0a959b40fed8a727e2f62c0b57635760c488c8bf0eda80ee591558c409"-          ]-        }-      }-    },-    {-      "title": "scoped checks",-      "filename": "test008_scoped_checks.bc",-      "token": [-        {-          "symbols": [-            "file1"-          ],-          "public_keys": [],-          "external_key": null,-          "code": "right(\"file1\", \"read\");\n"-        },-        {-          "symbols": [-            "0"-          ],-          "public_keys": [],-          "external_key": null,-          "code": "check if resource($0), operation(\"read\"), right($0, \"read\");\n"-        },-        {-          "symbols": [-            "file2"-          ],-          "public_keys": [],-          "external_key": null,-          "code": "right(\"file2\", \"read\");\n"-        }-      ],-      "validations": {-        "": {-          "world": {-            "facts": [-              "operation(\"read\")",-              "resource(\"file2\")",-              "right(\"file1\", \"read\")",-              "right(\"file2\", \"read\")"-            ],-            "rules": [],-            "checks": [-              "check if resource($0), operation(\"read\"), right($0, \"read\")"-            ],-            "policies": [-              "allow if true"-            ]-          },-          "result": {-            "Err": {-              "FailedLogic": {-                "Unauthorized": {-                  "policy": {-                    "Allow": 0-                  },-                  "checks": [-                    {-                      "Block": {-                        "block_id": 1,-                        "check_id": 0,-                        "rule": "check if resource($0), operation(\"read\"), right($0, \"read\")"-                      }-                    }-                  ]-                }-              }-            }-          },-          "authorizer_code": "resource(\"file2\");\noperation(\"read\");\n\nallow if true;\n",-          "revocation_ids": [-            "567682495bf002eb84c46491e40fad8c55943d918c65e2c110b1b88511bf393072c0305a243e3d632ca5f1e9b0ace3e3582de84838c3a258480657087c267f02",-            "71f0010b1034dbc62c53f67a23947b92ccba46495088567ac7ad5c4d7d65476964bee42053a6a35088110c5918f9c9606057689271fef89d84253cf98e6d4407",-            "6d00d5f2a5d25dbfaa19152a81b44328b368e8fb8300b25e36754cfe8b2ce1eb2d1452ce9b1502e6f377a23aa87098fb05b5b073541624a8815ba0610f793005"-          ]-        }-      }-    },-    {-      "title": "expired token",-      "filename": "test009_expired_token.bc",-      "token": [-        {-          "symbols": [],-          "public_keys": [],-          "external_key": null,-          "code": ""-        },-        {-          "symbols": [-            "file1",-            "expiration"-          ],-          "public_keys": [],-          "external_key": null,-          "code": "check if resource(\"file1\");\ncheck if time($time), $time <= 2018-12-20T00:00:00Z;\n"-        }-      ],-      "validations": {-        "": {-          "world": {-            "facts": [-              "operation(\"read\")",-              "resource(\"file1\")",-              "time(2020-12-21T09:23:12Z)"-            ],-            "rules": [],-            "checks": [-              "check if resource(\"file1\")",-              "check if time($time), $time <= 2018-12-20T00:00:00Z"-            ],-            "policies": [-              "allow if true"-            ]-          },-          "result": {-            "Err": {-              "FailedLogic": {-                "Unauthorized": {-                  "policy": {-                    "Allow": 0-                  },-                  "checks": [-                    {-                      "Block": {-                        "block_id": 1,-                        "check_id": 1,-                        "rule": "check if time($time), $time <= 2018-12-20T00:00:00Z"-                      }-                    }-                  ]-                }-              }-            }-          },-          "authorizer_code": "resource(\"file1\");\noperation(\"read\");\ntime(2020-12-21T09:23:12Z);\n\nallow if true;\n",-          "revocation_ids": [-            "b2474f3e0a5788cdeff811f2599497a04d1ad71ca48dbafb90f20a950d565dda0b86bd6c9072a727c19b6b20a1ae10d8cb88155186550b77016ffd1dca9a6203",-            "0d12152670cbefe2fa504af9a92b513f1a48ae460ae5e66aaac4ed9f7dc3cc1c4c510693312b351465062169a2169fc520ce4e17e548d21982c81a74c66a3c0c"-          ]-        }-      }-    },-    {-      "title": "authorizer scope",-      "filename": "test010_authorizer_scope.bc",-      "token": [-        {-          "symbols": [-            "file1"-          ],-          "public_keys": [],-          "external_key": null,-          "code": "right(\"file1\", \"read\");\n"-        },-        {-          "symbols": [-            "file2"-          ],-          "public_keys": [],-          "external_key": null,-          "code": "right(\"file2\", \"read\");\n"-        }-      ],-      "validations": {-        "": {-          "world": {-            "facts": [-              "operation(\"read\")",-              "resource(\"file2\")",-              "right(\"file1\", \"read\")",-              "right(\"file2\", \"read\")"-            ],-            "rules": [],-            "checks": [-              "check if right($0, $1), resource($0), operation($1)"-            ],-            "policies": [-              "allow if true"-            ]-          },-          "result": {-            "Err": {-              "FailedLogic": {-                "Unauthorized": {-                  "policy": {-                    "Allow": 0-                  },-                  "checks": [-                    {-                      "Authorizer": {-                        "check_id": 0,-                        "rule": "check if right($0, $1), resource($0), operation($1)"-                      }-                    }-                  ]-                }-              }-            }-          },-          "authorizer_code": "resource(\"file2\");\noperation(\"read\");\n\ncheck if right($0, $1), resource($0), operation($1);\n\nallow if true;\n",-          "revocation_ids": [-            "b9ecf192ecb1bbb10e45320c1c86661f0c6b6bd28e89fdd8fa838fe0ab3f754229f7fbbf92ad978d36f744c345c69bc156a2a91a2979a3c235a9d936d401b404",-            "839728735701e589c2612e655afa2b53f573480e6a0477ae68ed71587987d1af398a31296bdec0b6eccee9348f4b4c23ca1031e809991626c579fef80b1d380d"-          ]-        }-      }-    },-    {-      "title": "authorizer authority checks",-      "filename": "test011_authorizer_authority_caveats.bc",-      "token": [-        {-          "symbols": [-            "file1"-          ],-          "public_keys": [],-          "external_key": null,-          "code": "right(\"file1\", \"read\");\n"-        }-      ],-      "validations": {-        "": {-          "world": {-            "facts": [-              "operation(\"read\")",-              "resource(\"file2\")",-              "right(\"file1\", \"read\")"-            ],-            "rules": [],-            "checks": [-              "check if right($0, $1), resource($0), operation($1)"-            ],-            "policies": [-              "allow if true"-            ]-          },-          "result": {-            "Err": {-              "FailedLogic": {-                "Unauthorized": {-                  "policy": {-                    "Allow": 0-                  },-                  "checks": [-                    {-                      "Authorizer": {-                        "check_id": 0,-                        "rule": "check if right($0, $1), resource($0), operation($1)"-                      }-                    }-                  ]-                }-              }-            }-          },-          "authorizer_code": "resource(\"file2\");\noperation(\"read\");\n\ncheck if right($0, $1), resource($0), operation($1);\n\nallow if true;\n",-          "revocation_ids": [-            "593d273d141bf23a3e89b55fffe1b3f96f683a022bb763e78f4e49f31a7cf47668c3fd5e0f580727ac9113ede302d34264597f6f1e6c6dd4167836d57aedf504"-          ]-        }-      }-    },-    {-      "title": "authority checks",-      "filename": "test012_authority_caveats.bc",-      "token": [-        {-          "symbols": [-            "file1"-          ],-          "public_keys": [],-          "external_key": null,-          "code": "check if resource(\"file1\");\n"-        }-      ],-      "validations": {-        "file1": {-          "world": {-            "facts": [-              "operation(\"read\")",-              "resource(\"file1\")"-            ],-            "rules": [],-            "checks": [-              "check if resource(\"file1\")"-            ],-            "policies": [-              "allow if true"-            ]-          },-          "result": {-            "Ok": 0-          },-          "authorizer_code": "resource(\"file1\");\noperation(\"read\");\n\nallow if true;\n",-          "revocation_ids": [-            "0a1d14a145debbb0a2f4ce0631d3a0a48a2e0eddabefda7fabb0414879ec6be24b9ae7295c434609ada3f8cc47b8845bbd5a0d4fba3d96748ff1b824496e0405"-          ]-        },-        "file2": {-          "world": {-            "facts": [-              "operation(\"read\")",-              "resource(\"file2\")"-            ],-            "rules": [],-            "checks": [-              "check if resource(\"file1\")"-            ],-            "policies": [-              "allow if true"-            ]-          },-          "result": {-            "Err": {-              "FailedLogic": {-                "Unauthorized": {-                  "policy": {-                    "Allow": 0-                  },-                  "checks": [-                    {-                      "Block": {-                        "block_id": 0,-                        "check_id": 0,-                        "rule": "check if resource(\"file1\")"-                      }-                    }-                  ]-                }-              }-            }-          },-          "authorizer_code": "resource(\"file2\");\noperation(\"read\");\n\nallow if true;\n",-          "revocation_ids": [-            "0a1d14a145debbb0a2f4ce0631d3a0a48a2e0eddabefda7fabb0414879ec6be24b9ae7295c434609ada3f8cc47b8845bbd5a0d4fba3d96748ff1b824496e0405"-          ]-        }-      }-    },-    {-      "title": "block rules",-      "filename": "test013_block_rules.bc",-      "token": [-        {-          "symbols": [-            "file1",-            "file2"-          ],-          "public_keys": [],-          "external_key": null,-          "code": "right(\"file1\", \"read\");\nright(\"file2\", \"read\");\n"-        },-        {-          "symbols": [-            "valid_date",-            "0",-            "1"-          ],-          "public_keys": [],-          "external_key": null,-          "code": "valid_date(\"file1\") <- time($0), resource(\"file1\"), $0 <= 2030-12-31T12:59:59Z;\nvalid_date($1) <- time($0), resource($1), $0 <= 1999-12-31T12:59:59Z, ![\"file1\"].contains($1);\ncheck if valid_date($0), resource($0);\n"-        }-      ],-      "validations": {-        "file1": {-          "world": {-            "facts": [-              "resource(\"file1\")",-              "right(\"file1\", \"read\")",-              "right(\"file2\", \"read\")",-              "time(2020-12-21T09:23:12Z)",-              "valid_date(\"file1\")"-            ],-            "rules": [-              "valid_date(\"file1\") <- time($0), resource(\"file1\"), $0 <= 2030-12-31T12:59:59Z",-              "valid_date($1) <- time($0), resource($1), $0 <= 1999-12-31T12:59:59Z, ![\"file1\"].contains($1)"-            ],-            "checks": [-              "check if valid_date($0), resource($0)"-            ],-            "policies": [-              "allow if true"-            ]-          },-          "result": {-            "Ok": 0-          },-          "authorizer_code": "resource(\"file1\");\ntime(2020-12-21T09:23:12Z);\n\nallow if true;\n",-          "revocation_ids": [-            "d251352efd4e4c72e8a1609fce002f558f1a0bb5e36cd3d8b3a6c6599e3960880f21bea6fe1857f4ecbc2c399dd77829b154e75f1323e9dec413aad70f97650d",-            "9de4f51e6019540598a957515dad52f5403e5c6cd8d2adbca1bff42a4fbc0eb8c6adab499da2fe894a8a9c9c581276bfb0fdc3d35ab2ff9f920a2c4690739903"-          ]-        },-        "file2": {-          "world": {-            "facts": [-              "resource(\"file2\")",-              "right(\"file1\", \"read\")",-              "right(\"file2\", \"read\")",-              "time(2020-12-21T09:23:12Z)"-            ],-            "rules": [-              "valid_date(\"file1\") <- time($0), resource(\"file1\"), $0 <= 2030-12-31T12:59:59Z",-              "valid_date($1) <- time($0), resource($1), $0 <= 1999-12-31T12:59:59Z, ![\"file1\"].contains($1)"-            ],-            "checks": [-              "check if valid_date($0), resource($0)"-            ],-            "policies": [-              "allow if true"-            ]-          },-          "result": {-            "Err": {-              "FailedLogic": {-                "Unauthorized": {-                  "policy": {-                    "Allow": 0-                  },-                  "checks": [-                    {-                      "Block": {-                        "block_id": 1,-                        "check_id": 0,-                        "rule": "check if valid_date($0), resource($0)"-                      }-                    }-                  ]-                }-              }-            }-          },-          "authorizer_code": "resource(\"file2\");\ntime(2020-12-21T09:23:12Z);\n\nallow if true;\n",-          "revocation_ids": [-            "d251352efd4e4c72e8a1609fce002f558f1a0bb5e36cd3d8b3a6c6599e3960880f21bea6fe1857f4ecbc2c399dd77829b154e75f1323e9dec413aad70f97650d",-            "9de4f51e6019540598a957515dad52f5403e5c6cd8d2adbca1bff42a4fbc0eb8c6adab499da2fe894a8a9c9c581276bfb0fdc3d35ab2ff9f920a2c4690739903"-          ]-        }-      }-    },-    {-      "title": "regex_constraint",-      "filename": "test014_regex_constraint.bc",-      "token": [-        {-          "symbols": [-            "0",-            "file[0-9]+.txt"-          ],-          "public_keys": [],-          "external_key": null,-          "code": "check if resource($0), $0.matches(\"file[0-9]+.txt\");\n"-        }-      ],-      "validations": {-        "file1": {-          "world": {-            "facts": [-              "resource(\"file1\")"-            ],-            "rules": [],-            "checks": [-              "check if resource($0), $0.matches(\"file[0-9]+.txt\")"-            ],-            "policies": [-              "allow if true"-            ]-          },-          "result": {-            "Err": {-              "FailedLogic": {-                "Unauthorized": {-                  "policy": {-                    "Allow": 0-                  },-                  "checks": [-                    {-                      "Block": {-                        "block_id": 0,-                        "check_id": 0,-                        "rule": "check if resource($0), $0.matches(\"file[0-9]+.txt\")"-                      }-                    }-                  ]-                }-              }-            }-          },-          "authorizer_code": "resource(\"file1\");\n\nallow if true;\n",-          "revocation_ids": [-            "1c158e1e12c8670d3f4411597276fe1caab17b7728adb7f7e9c44eeec3e3d85676e6ebe2d28c287e285a45912386cfa53e1752997630bd7a4ca6c2cd9f143500"-          ]-        },-        "file123": {-          "world": {-            "facts": [-              "resource(\"file123.txt\")"-            ],-            "rules": [],-            "checks": [-              "check if resource($0), $0.matches(\"file[0-9]+.txt\")"-            ],-            "policies": [-              "allow if true"-            ]-          },-          "result": {-            "Ok": 0-          },-          "authorizer_code": "resource(\"file123.txt\");\n\nallow if true;\n",-          "revocation_ids": [-            "1c158e1e12c8670d3f4411597276fe1caab17b7728adb7f7e9c44eeec3e3d85676e6ebe2d28c287e285a45912386cfa53e1752997630bd7a4ca6c2cd9f143500"-          ]-        }-      }-    },-    {-      "title": "multi queries checks",-      "filename": "test015_multi_queries_caveats.bc",-      "token": [-        {-          "symbols": [-            "must_be_present",-            "hello"-          ],-          "public_keys": [],-          "external_key": null,-          "code": "must_be_present(\"hello\");\n"-        }-      ],-      "validations": {-        "": {-          "world": {-            "facts": [-              "must_be_present(\"hello\")"-            ],-            "rules": [],-            "checks": [-              "check if must_be_present($0) or must_be_present($0)"-            ],-            "policies": [-              "allow if true"-            ]-          },-          "result": {-            "Ok": 0-          },-          "authorizer_code": "check if must_be_present($0) or must_be_present($0);\n\nallow if true;\n",-          "revocation_ids": [-            "d3eee8a74eacec9c51d4d1eb29b479727dfaafa9df7d4c651d07c493c56f3a5f037a51139ebd036f50d1159d12bccec3e377bbd32db90a39dd52c4776757ad0b"-          ]-        }-      }-    },-    {-      "title": "check head name should be independent from fact names",-      "filename": "test016_caveat_head_name.bc",-      "token": [-        {-          "symbols": [-            "hello"-          ],-          "public_keys": [],-          "external_key": null,-          "code": "check if resource(\"hello\");\n"-        },-        {-          "symbols": [-            "test"-          ],-          "public_keys": [],-          "external_key": null,-          "code": "query(\"test\");\n"-        }-      ],-      "validations": {-        "": {-          "world": {-            "facts": [-              "query(\"test\")"-            ],-            "rules": [],-            "checks": [-              "check if resource(\"hello\")"-            ],-            "policies": [-              "allow if true"-            ]-          },-          "result": {-            "Err": {-              "FailedLogic": {-                "Unauthorized": {-                  "policy": {-                    "Allow": 0-                  },-                  "checks": [-                    {-                      "Block": {-                        "block_id": 0,-                        "check_id": 0,-                        "rule": "check if resource(\"hello\")"-                      }-                    }-                  ]-                }-              }-            }-          },-          "authorizer_code": "allow if true;\n",-          "revocation_ids": [-            "e79679e019f1d7d3a9f9a309673aceadc7b2b2d67c0df3e7a1dccec25218e9b5935b9c8f8249243446406e3cdd86c1b35601a21cf1b119df48ca5e897cc6cd0d",-            "2042ea2dca41ba3eb31196f49b211e615dcba46067be126e6035b8549bb57cdfeb24d07f2b44241bc0f70cc8ddc31e30772116d785b82bc91be8440dfdab500f"-          ]-        }-      }-    },-    {-      "title": "test expression syntax and all available operations",-      "filename": "test017_expressions.bc",-      "token": [-        {-          "symbols": [-            "hello world",-            "hello",-            "world",-            "aaabde",-            "a*c?.e",-            "abd",-            "aaa",-            "b",-            "de",-            "abcD12",-            "abcD12x",-            "abc",-            "def"-          ],-          "public_keys": [],-          "external_key": null,-          "code": "check if true;\ncheck if !false;\ncheck if !false && true;\ncheck if false or true;\ncheck if (true || false) && true;\ncheck if 1 < 2;\ncheck if 2 > 1;\ncheck if 1 <= 2;\ncheck if 1 <= 1;\ncheck if 2 >= 1;\ncheck if 2 >= 2;\ncheck if 3 == 3;\ncheck if 1 != 3;\ncheck if 1 + 2 * 3 - 4 / 2 == 5;\ncheck if 1 | 2 ^ 3 == 0;\ncheck if \"hello world\".starts_with(\"hello\") && \"hello world\".ends_with(\"world\");\ncheck if \"aaabde\".matches(\"a*c?.e\");\ncheck if \"aaabde\".contains(\"abd\");\ncheck if \"aaabde\" == \"aaa\" + \"b\" + \"de\";\ncheck if \"abcD12\" == \"abcD12\";\ncheck if \"abcD12x\" != \"abcD12\";\ncheck if 2019-12-04T09:46:41Z < 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z > 2019-12-04T09:46:41Z;\ncheck if 2019-12-04T09:46:41Z <= 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z >= 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z >= 2019-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z >= 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z == 2020-12-04T09:46:41Z;\ncheck if 2022-12-04T09:46:41Z != 2020-12-04T09:46:41Z;\ncheck if hex:12ab == hex:12ab;\ncheck if hex:12abcd != hex:12ab;\ncheck if [1, 2].contains(2);\ncheck if [2019-12-04T09:46:41Z, 2020-12-04T09:46:41Z].contains(2020-12-04T09:46:41Z);\ncheck if [false, true].contains(true);\ncheck if [\"abc\", \"def\"].contains(\"abc\");\ncheck if [hex:12ab, hex:34de].contains(hex:34de);\ncheck if [1, 2] == [1, 2];\ncheck if [1, 4] != [1, 2];\n"-        }-      ],-      "validations": {-        "": {-          "world": {-            "facts": [],-            "rules": [],-            "checks": [-              "check if !false",-              "check if !false && true",-              "check if \"aaabde\" == \"aaa\" + \"b\" + \"de\"",-              "check if \"aaabde\".contains(\"abd\")",-              "check if \"aaabde\".matches(\"a*c?.e\")",-              "check if \"abcD12\" == \"abcD12\"",-              "check if \"abcD12x\" != \"abcD12\"",-              "check if \"hello world\".starts_with(\"hello\") && \"hello world\".ends_with(\"world\")",-              "check if (true || false) && true",-              "check if 1 != 3",-              "check if 1 + 2 * 3 - 4 / 2 == 5",-              "check if 1 < 2",-              "check if 1 <= 1",-              "check if 1 <= 2",-              "check if 1 | 2 ^ 3 == 0",-              "check if 2 > 1",-              "check if 2 >= 1",-              "check if 2 >= 2",-              "check if 2019-12-04T09:46:41Z < 2020-12-04T09:46:41Z",-              "check if 2019-12-04T09:46:41Z <= 2020-12-04T09:46:41Z",-              "check if 2020-12-04T09:46:41Z == 2020-12-04T09:46:41Z",-              "check if 2020-12-04T09:46:41Z > 2019-12-04T09:46:41Z",-              "check if 2020-12-04T09:46:41Z >= 2019-12-04T09:46:41Z",-              "check if 2020-12-04T09:46:41Z >= 2020-12-04T09:46:41Z",-              "check if 2022-12-04T09:46:41Z != 2020-12-04T09:46:41Z",-              "check if 3 == 3",-              "check if [\"abc\", \"def\"].contains(\"abc\")",-              "check if [1, 2] == [1, 2]",-              "check if [1, 2].contains(2)",-              "check if [1, 4] != [1, 2]",-              "check if [2019-12-04T09:46:41Z, 2020-12-04T09:46:41Z].contains(2020-12-04T09:46:41Z)",-              "check if [false, true].contains(true)",-              "check if [hex:12ab, hex:34de].contains(hex:34de)",-              "check if false or true",-              "check if hex:12ab == hex:12ab",-              "check if hex:12abcd != hex:12ab",-              "check if true"-            ],-            "policies": [-              "allow if true"-            ]-          },-          "result": {-            "Ok": 0-          },-          "authorizer_code": "allow if true;\n",-          "revocation_ids": [-            "3e51db5f0453929a596485b59e89bf628a301a33d476132c48a1c0a208805809f15bdf99593733c1b5f30e8c1f473ee2f78042f81fd0557081bafb5370e65d0c"-          ]-        }-      }-    },-    {-      "title": "invalid block rule with unbound_variables",-      "filename": "test018_unbound_variables_in_rule.bc",-      "token": [-        {-          "symbols": [],-          "public_keys": [],-          "external_key": null,-          "code": "check if operation(\"read\");\n"-        },-        {-          "symbols": [-            "unbound",-            "any1",-            "any2"-          ],-          "public_keys": [],-          "external_key": null,-          "code": "operation($unbound, \"read\") <- operation($any1, $any2);\n"-        }-      ],-      "validations": {-        "": {-          "world": null,-          "result": {-            "Err": {-              "FailedLogic": {-                "InvalidBlockRule": [-                  0,-                  "operation($unbound, \"read\") <- operation($any1, $any2)"-                ]-              }-            }-          },-          "authorizer_code": "",-          "revocation_ids": [-            "c536d07f08f6f73da69a2f49310045168e059b8c07e3ddf25afd524df358a0397744b31a139eced043cb5f7a29dacbe3a510ce449fc792e53623186767cefc0c",-            "8588c74c3701e8d4be770769b4e1054dbb5ea5f231a89d205000802b8718859ea1d596af207a41b1b0f7d05959180c227ea8954e903f13ade3ce3384d1e6a70a"-          ]-        }-      }-    },-    {-      "title": "invalid block rule generating an #authority or #ambient symbol with a variable",-      "filename": "test019_generating_ambient_from_variables.bc",-      "token": [-        {-          "symbols": [],-          "public_keys": [],-          "external_key": null,-          "code": "check if operation(\"read\");\n"-        },-        {-          "symbols": [-            "any"-          ],-          "public_keys": [],-          "external_key": null,-          "code": "operation(\"read\") <- operation($any);\n"-        }-      ],-      "validations": {-        "": {-          "world": {-            "facts": [-              "operation(\"read\")",-              "operation(\"write\")"-            ],-            "rules": [-              "operation(\"read\") <- operation($any)"-            ],-            "checks": [-              "check if operation(\"read\")"-            ],-            "policies": [-              "allow if true"-            ]-          },-          "result": {-            "Err": {-              "FailedLogic": {-                "Unauthorized": {-                  "policy": {-                    "Allow": 0-                  },-                  "checks": [-                    {-                      "Block": {-                        "block_id": 0,-                        "check_id": 0,-                        "rule": "check if operation(\"read\")"-                      }-                    }-                  ]-                }-              }-            }-          },-          "authorizer_code": "operation(\"write\");\n\nallow if true;\n",-          "revocation_ids": [-            "4819e7360fdb840e54e94afcbc110e9b0652894dba2b8bf3b8b8f2254aaf00272bba7eb603c153c7e50cca0e5bb8e20449d70a1b24e7192e902c64f94848a703",-            "4a4c59354354d2f91b3a2d1e7afa2c5eeaf8be9f7b163c6b9091817551cc8661f0f3e0523b525ef9a5e597c0dd1f32e09e97ace531c150dba335bb3e1d329d00"-          ]-        }-      }-    },-    {-      "title": "sealed token",-      "filename": "test020_sealed.bc",-      "token": [-        {-          "symbols": [-            "file1",-            "file2"-          ],-          "public_keys": [],-          "external_key": null,-          "code": "right(\"file1\", \"read\");\nright(\"file2\", \"read\");\nright(\"file1\", \"write\");\n"-        },-        {-          "symbols": [-            "0"-          ],-          "public_keys": [],-          "external_key": null,-          "code": "check if resource($0), operation(\"read\"), right($0, \"read\");\n"-        }-      ],-      "validations": {-        "": {-          "world": {-            "facts": [-              "operation(\"read\")",-              "resource(\"file1\")",-              "right(\"file1\", \"read\")",-              "right(\"file1\", \"write\")",-              "right(\"file2\", \"read\")"-            ],-            "rules": [],-            "checks": [-              "check if resource($0), operation(\"read\"), right($0, \"read\")"-            ],-            "policies": [-              "allow if true"-            ]-          },-          "result": {-            "Ok": 0-          },-          "authorizer_code": "resource(\"file1\");\noperation(\"read\");\n\nallow if true;\n",-          "revocation_ids": [-            "b279f8c6fee5ea3c3fcb5109d8c6b35ba3fecea64d83a4dc387102b9401633a1558ac6ac50ddd7fd9e9877f936f9f4064abd467faeca2bef3114b9695eb0580e",-            "e1f0aca12704c1a3b9bb6292504ca6070462d9e043756dd209e625084e7d4053078bd4e55b6eebebbeb771d26d7794aa95f6b39ff949431548b32585a7379f0c"-          ]-        }-      }-    },-    {-      "title": "parsing",-      "filename": "test021_parsing.bc",-      "token": [-        {-          "symbols": [-            "ns::fact_123",-            "hello é\t😁"-          ],-          "public_keys": [],-          "external_key": null,-          "code": "ns::fact_123(\"hello é\t😁\");\n"-        }-      ],-      "validations": {-        "": {-          "world": {-            "facts": [-              "ns::fact_123(\"hello é\t😁\")"-            ],-            "rules": [],-            "checks": [-              "check if ns::fact_123(\"hello é\t😁\")"-            ],-            "policies": [-              "allow if true"-            ]-          },-          "result": {-            "Ok": 0-          },-          "authorizer_code": "check if ns::fact_123(\"hello é\t😁\");\n\nallow if true;\n",-          "revocation_ids": [-            "4797a528328c8b5fb7939cc8956d8cda2513f552466eee501e26ea13a6cf6b4a381fd74ae547a9b50b627825142287d899b9d7bd1b5cfb18664a1be78320ea06"-          ]-        }-      }-    },-    {-      "title": "default_symbols",-      "filename": "test022_default_symbols.bc",-      "token": [-        {-          "symbols": [],-          "public_keys": [],-          "external_key": null,-          "code": "read(0);\nwrite(1);\nresource(2);\noperation(3);\nright(4);\ntime(5);\nrole(6);\nowner(7);\ntenant(8);\nnamespace(9);\nuser(10);\nteam(11);\nservice(12);\nadmin(13);\nemail(14);\ngroup(15);\nmember(16);\nip_address(17);\nclient(18);\nclient_ip(19);\ndomain(20);\npath(21);\nversion(22);\ncluster(23);\nnode(24);\nhostname(25);\nnonce(26);\nquery(27);\n"-        }-      ],-      "validations": {-        "": {-          "world": {-            "facts": [-              "admin(13)",-              "client(18)",-              "client_ip(19)",-              "cluster(23)",-              "domain(20)",-              "email(14)",-              "group(15)",-              "hostname(25)",-              "ip_address(17)",-              "member(16)",-              "namespace(9)",-              "node(24)",-              "nonce(26)",-              "operation(3)",-              "owner(7)",-              "path(21)",-              "query(27)",-              "read(0)",-              "resource(2)",-              "right(4)",-              "role(6)",-              "service(12)",-              "team(11)",-              "tenant(8)",-              "time(5)",-              "user(10)",-              "version(22)",-              "write(1)"-            ],-            "rules": [],-            "checks": [-              "check if read(0), write(1), resource(2), operation(3), right(4), time(5), role(6), owner(7), tenant(8), namespace(9), user(10), team(11), service(12), admin(13), email(14), group(15), member(16), ip_address(17), client(18), client_ip(19), domain(20), path(21), version(22), cluster(23), node(24), hostname(25), nonce(26), query(27)"-            ],-            "policies": [-              "allow if true"-            ]-          },-          "result": {-            "Ok": 0-          },-          "authorizer_code": "check if read(0), write(1), resource(2), operation(3), right(4), time(5), role(6), owner(7), tenant(8), namespace(9), user(10), team(11), service(12), admin(13), email(14), group(15), member(16), ip_address(17), client(18), client_ip(19), domain(20), path(21), version(22), cluster(23), node(24), hostname(25), nonce(26), query(27);\n\nallow if true;\n",-          "revocation_ids": [-            "38094260b324eff92db2ef79e715d88c18503c0dafa400bff900399f2ab0840cedc5ac25bdd3e97860b3f9e78ca5e0df67a113eb87be50265d49278efb13210f"-          ]-        }-      }-    },-    {-      "title": "execution scope",-      "filename": "test023_execution_scope.bc",-      "token": [-        {-          "symbols": [-            "authority_fact"-          ],-          "public_keys": [],-          "external_key": null,-          "code": "authority_fact(1);\n"-        },-        {-          "symbols": [-            "block1_fact"-          ],-          "public_keys": [],-          "external_key": null,-          "code": "block1_fact(1);\n"-        },-        {-          "symbols": [-            "var"-          ],-          "public_keys": [],-          "external_key": null,-          "code": "check if authority_fact($var);\ncheck if block1_fact($var);\n"-        }-      ],-      "validations": {-        "": {-          "world": {-            "facts": [-              "authority_fact(1)",-              "block1_fact(1)"-            ],-            "rules": [],-            "checks": [-              "check if authority_fact($var)",-              "check if block1_fact($var)"-            ],-            "policies": [-              "allow if true"-            ]-          },-          "result": {-            "Err": {-              "FailedLogic": {-                "Unauthorized": {-                  "policy": {-                    "Allow": 0-                  },-                  "checks": [-                    {-                      "Block": {-                        "block_id": 2,-                        "check_id": 1,-                        "rule": "check if block1_fact($var)"-                      }-                    }-                  ]-                }-              }-            }-          },-          "authorizer_code": "allow if true;\n",-          "revocation_ids": [-            "6a3606836bc63b858f96ce5000c9bead8eda139ab54679a2a8d7a9984c2e5d864b93280acc1b728bed0be42b5b1c3be10f48a13a4dbd05fd5763de5be3855108",-            "5f1468fc60999f22c4f87fa088a83961188b4e654686c5b04bdc977b9ff4666d51a3d8be5594f4cef08054d100f31d1637b50bb394de7cccafc643c9b650390b",-            "3eda05ddb65ee90d715cefc046837c01de944d8c4a7ff67e3d9a9d8470b5e214a20a8b9866bfe5e0d385e530b75ec8fcfde46b7dd6d4d6647d1e955c9d2fb90d"-          ]-        }-      }-    },-    {-      "title": "third party",-      "filename": "test024_third_party.bc",-      "token": [-        {-          "symbols": [],-          "public_keys": [-            "ed25519/a424157b8c00c25214ea39894bf395650d88426147679a9dd43a64d65ae5bc25"-          ],-          "external_key": null,-          "code": "right(\"read\");\ncheck if group(\"admin\") trusting ed25519/a424157b8c00c25214ea39894bf395650d88426147679a9dd43a64d65ae5bc25;\n"-        },-        {-          "symbols": [],-          "public_keys": [],-          "external_key": "ed25519/a424157b8c00c25214ea39894bf395650d88426147679a9dd43a64d65ae5bc25",-          "code": "group(\"admin\");\ncheck if right(\"read\");\n"-        }-      ],-      "validations": {-        "": {-          "world": {-            "facts": [-              "group(\"admin\")",-              "right(\"read\")"-            ],-            "rules": [],-            "checks": [-              "check if group(\"admin\") trusting ed25519/a424157b8c00c25214ea39894bf395650d88426147679a9dd43a64d65ae5bc25",-              "check if right(\"read\")"-            ],-            "policies": [-              "allow if true"-            ]-          },-          "result": {-            "Ok": 0-          },-          "authorizer_code": "allow if true;\n",-          "revocation_ids": [-            "4f61f2f2f9cefdcad03a82803638e459bef70d6fd72dbdf2bdcab78fbd23f33146e4ff9700e23acb547b820b871fa9b9fd3bb6d7a1a755afce47e9907c65600c",-            "683b23943b73f53f57f473571ba266f79f1fca0633be249bc135054371a11ffb101c57150ab2f1b9a6a160b45d09567a314b7dbc84224edf6188afd5b86d9305"-          ]-        }-      }-    },-    {-      "title": "block rules",-      "filename": "test025_check_all.bc",-      "token": [-        {-          "symbols": [-            "allowed_operations",-            "A",-            "B",-            "op",-            "allowed"-          ],-          "public_keys": [],-          "external_key": null,-          "code": "allowed_operations([\"A\", \"B\"]);\ncheck all operation($op), allowed_operations($allowed), $allowed.contains($op);\n"-        }-      ],-      "validations": {-        "A, B": {-          "world": {-            "facts": [-              "allowed_operations([ \"A\", \"B\"])",-              "operation(\"A\")",-              "operation(\"B\")"-            ],-            "rules": [],-            "checks": [-              "check all operation($op), allowed_operations($allowed), $allowed.contains($op)"-            ],-            "policies": [-              "allow if true"-            ]-          },-          "result": {-            "Ok": 0-          },-          "authorizer_code": "operation(\"A\");\noperation(\"B\");\n\nallow if true;\n",-          "revocation_ids": [-            "b4ee591001e4068a7ee8efb7a0586c3ca3a785558f34d1fa8dbfa21b41ace70de0b670ac49222c7413066d0d83e6d9edee94fb0fda4b27ea11e837304dfb4b0b"-          ]-        },-        "A, invalid": {-          "world": {-            "facts": [-              "allowed_operations([ \"A\", \"B\"])",-              "operation(\"A\")",-              "operation(\"invalid\")"-            ],-            "rules": [],-            "checks": [-              "check all operation($op), allowed_operations($allowed), $allowed.contains($op)"-            ],-            "policies": [-              "allow if true"-            ]-          },-          "result": {-            "Err": {-              "FailedLogic": {-                "Unauthorized": {-                  "policy": {-                    "Allow": 0-                  },-                  "checks": [-                    {-                      "Block": {-                        "block_id": 0,-                        "check_id": 0,-                        "rule": "check all operation($op), allowed_operations($allowed), $allowed.contains($op)"-                      }-                    }-                  ]-                }-              }-            }-          },-          "authorizer_code": "operation(\"A\");\noperation(\"invalid\");\n\nallow if true;\n",-          "revocation_ids": [-            "b4ee591001e4068a7ee8efb7a0586c3ca3a785558f34d1fa8dbfa21b41ace70de0b670ac49222c7413066d0d83e6d9edee94fb0fda4b27ea11e837304dfb4b0b"-          ]-        }-      }-    },-    {-      "title": "public keys interning",-      "filename": "test026_public_keys_interning.bc",-      "token": [-        {-          "symbols": [],-          "public_keys": [-            "ed25519/3c8aeced6363b8a862552fb2b0b4b8b0f8244e8cef3c11c3e55fd553f3a90f59"-          ],-          "external_key": null,-          "code": "query(0);\ncheck if true trusting previous, ed25519/3c8aeced6363b8a862552fb2b0b4b8b0f8244e8cef3c11c3e55fd553f3a90f59;\n"-        },-        {-          "symbols": [],-          "public_keys": [-            "ed25519/ecfb8ed11fd9e6be133ca4dd8d229d39c7dcb2d659704c39e82fd7acf0d12dee"-          ],-          "external_key": "ed25519/3c8aeced6363b8a862552fb2b0b4b8b0f8244e8cef3c11c3e55fd553f3a90f59",-          "code": "query(1);\nquery(1, 2) <- query(1), query(2) trusting ed25519/ecfb8ed11fd9e6be133ca4dd8d229d39c7dcb2d659704c39e82fd7acf0d12dee;\ncheck if query(2), query(3) trusting ed25519/ecfb8ed11fd9e6be133ca4dd8d229d39c7dcb2d659704c39e82fd7acf0d12dee;\ncheck if query(1) trusting ed25519/3c8aeced6363b8a862552fb2b0b4b8b0f8244e8cef3c11c3e55fd553f3a90f59;\n"-        },-        {-          "symbols": [],-          "public_keys": [],-          "external_key": "ed25519/ecfb8ed11fd9e6be133ca4dd8d229d39c7dcb2d659704c39e82fd7acf0d12dee",-          "code": "query(2);\ncheck if query(2), query(3) trusting ed25519/ecfb8ed11fd9e6be133ca4dd8d229d39c7dcb2d659704c39e82fd7acf0d12dee;\ncheck if query(1) trusting ed25519/3c8aeced6363b8a862552fb2b0b4b8b0f8244e8cef3c11c3e55fd553f3a90f59;\n"-        },-        {-          "symbols": [],-          "public_keys": [],-          "external_key": "ed25519/ecfb8ed11fd9e6be133ca4dd8d229d39c7dcb2d659704c39e82fd7acf0d12dee",-          "code": "query(3);\ncheck if query(2), query(3) trusting ed25519/ecfb8ed11fd9e6be133ca4dd8d229d39c7dcb2d659704c39e82fd7acf0d12dee;\ncheck if query(1) trusting ed25519/3c8aeced6363b8a862552fb2b0b4b8b0f8244e8cef3c11c3e55fd553f3a90f59;\n"-        },-        {-          "symbols": [],-          "public_keys": [-            "ed25519/2e0118e63beb7731dab5119280ddb117234d0cdc41b7dd5dc4241bcbbb585d14"-          ],-          "external_key": null,-          "code": "query(4);\ncheck if query(2) trusting ed25519/ecfb8ed11fd9e6be133ca4dd8d229d39c7dcb2d659704c39e82fd7acf0d12dee;\ncheck if query(4) trusting ed25519/2e0118e63beb7731dab5119280ddb117234d0cdc41b7dd5dc4241bcbbb585d14;\n"-        }-      ],-      "validations": {-        "": {-          "world": {-            "facts": [-              "query(0)",-              "query(1)",-              "query(1, 2)",-              "query(2)",-              "query(3)",-              "query(4)"-            ],-            "rules": [-              "query(1, 2) <- query(1), query(2) trusting ed25519/ecfb8ed11fd9e6be133ca4dd8d229d39c7dcb2d659704c39e82fd7acf0d12dee"-            ],-            "checks": [-              "check if query(1) trusting ed25519/3c8aeced6363b8a862552fb2b0b4b8b0f8244e8cef3c11c3e55fd553f3a90f59",-              "check if query(1, 2) trusting ed25519/3c8aeced6363b8a862552fb2b0b4b8b0f8244e8cef3c11c3e55fd553f3a90f59, ed25519/ecfb8ed11fd9e6be133ca4dd8d229d39c7dcb2d659704c39e82fd7acf0d12dee",-              "check if query(2) trusting ed25519/ecfb8ed11fd9e6be133ca4dd8d229d39c7dcb2d659704c39e82fd7acf0d12dee",-              "check if query(2), query(3) trusting ed25519/ecfb8ed11fd9e6be133ca4dd8d229d39c7dcb2d659704c39e82fd7acf0d12dee",-              "check if query(4) trusting ed25519/2e0118e63beb7731dab5119280ddb117234d0cdc41b7dd5dc4241bcbbb585d14",-              "check if true trusting previous, ed25519/3c8aeced6363b8a862552fb2b0b4b8b0f8244e8cef3c11c3e55fd553f3a90f59"-            ],-            "policies": [-              "allow if true",-              "deny if query(0) trusting ed25519/3c8aeced6363b8a862552fb2b0b4b8b0f8244e8cef3c11c3e55fd553f3a90f59",-              "deny if query(1, 2)",-              "deny if query(3)"-            ]-          },-          "result": {-            "Ok": 3-          },-          "authorizer_code": "check if query(1, 2) trusting ed25519/3c8aeced6363b8a862552fb2b0b4b8b0f8244e8cef3c11c3e55fd553f3a90f59, ed25519/ecfb8ed11fd9e6be133ca4dd8d229d39c7dcb2d659704c39e82fd7acf0d12dee;\n\ndeny if query(3);\ndeny if query(1, 2);\ndeny if query(0) trusting ed25519/3c8aeced6363b8a862552fb2b0b4b8b0f8244e8cef3c11c3e55fd553f3a90f59;\nallow if true;\n",-          "revocation_ids": [-            "bc144fef824b7ba4b266eac53e9b4f3f2d3cd443c6963833f2f8d4073bef9553f92034c2350fdd50966a9f0c09db35b142d61e0476b0133429885c787052060b",-            "aba1631f8d0bea1c81447e73269f560973d03287c2b44325d1b42d10a496156dc8e78648b946bc7db7a3111d787a10c1a9da8d53fc066b1f207de7415a2e9b0b",-            "539cff0f5c311dcac843a9e6c8bb445aff0d6510bfa9b17d5350747be92dc365217e89e1d733f3ead1ecc05f287f312c41831338708e788503b55517af3ad000",-            "5b10f7a7b4487f4421cf7f7f6d00b24a7a71939037b65b2e44241909564082a3e1e70cf7d866eb96f0a5119b9ea395adb772faaa33252fa62a579eb15a108a0b",-            "3905351588cdfc4433b510cc1ed9c11ca5c1a7bd7d9cef338bcd3f6d374c711f34edd83dd0d53c25b63bf05b49fc78addceb47905d5495580c2fd36c11bc1e0a"-          ]-        }-      }-    },-    {-      "title": "integer wraparound",-      "filename": "test027_integer_wraparound.bc",-      "token": [-        {-          "symbols": [],-          "public_keys": [],-          "external_key": null,-          "code": "check if true || 10000000000 * 10000000000 != 0;\ncheck if true || 9223372036854775807 + 1 != 0;\ncheck if true || -9223372036854775808 - 1 != 0;\n"-        }-      ],-      "validations": {-        "": {-          "world": {-            "facts": [],-            "rules": [],-            "checks": [-              "check if true || -9223372036854775808 - 1 != 0",-              "check if true || 10000000000 * 10000000000 != 0",-              "check if true || 9223372036854775807 + 1 != 0"-            ],-            "policies": [-              "allow if true"-            ]-          },-          "result": {-            "Err": {-              "FailedLogic": {-                "Unauthorized": {-                  "policy": {-                    "Allow": 0-                  },-                  "checks": [-                    {-                      "Block": {-                        "block_id": 0,-                        "check_id": 0,-                        "rule": "check if true || 10000000000 * 10000000000 != 0"-                      }-                    },-                    {-                      "Block": {-                        "block_id": 0,-                        "check_id": 1,-                        "rule": "check if true || 9223372036854775807 + 1 != 0"-                      }-                    },-                    {-                      "Block": {-                        "block_id": 0,-                        "check_id": 2,-                        "rule": "check if true || -9223372036854775808 - 1 != 0"-                      }-                    }-                  ]-                }-              }-            }-          },-          "authorizer_code": "allow if true;\n",-          "revocation_ids": [-            "70d8941198ab5daa445a11357994d93278876ee95b6500f4c4a265ad668a0111440942b762e02513e471d40265d586ea76209921068524f588dc46eb4260db07"+  "root_private_key": "99e87b0e9158531eeeb503ff15266e2b23c2a2507b138c9d1b1f2ab458df2d61",+  "root_public_key": "1055c750b1a1505937af1537c626ba3263995c33a64758aaafb1275b0312e284",+  "testcases": [+    {+      "title": "basic token",+      "filename": "test001_basic.bc",+      "token": [+        {+          "symbols": [+            "file1",+            "file2"+          ],+          "public_keys": [],+          "external_key": null,+          "code": "right(\"file1\", \"read\");\nright(\"file2\", \"read\");\nright(\"file1\", \"write\");\n"+        },+        {+          "symbols": [+            "0"+          ],+          "public_keys": [],+          "external_key": null,+          "code": "check if resource($0), operation(\"read\"), right($0, \"read\");\n"+        }+      ],+      "validations": {+        "": {+          "world": {+            "facts": [+              {+                "origin": [+                  null+                ],+                "facts": [+                  "resource(\"file1\")"+                ]+              },+              {+                "origin": [+                  0+                ],+                "facts": [+                  "right(\"file1\", \"read\")",+                  "right(\"file1\", \"write\")",+                  "right(\"file2\", \"read\")"+                ]+              }+            ],+            "rules": [],+            "checks": [+              {+                "origin": 1,+                "checks": [+                  "check if resource($0), operation(\"read\"), right($0, \"read\")"+                ]+              }+            ],+            "policies": [+              "allow if true"+            ]+          },+          "result": {+            "Err": {+              "FailedLogic": {+                "Unauthorized": {+                  "policy": {+                    "Allow": 0+                  },+                  "checks": [+                    {+                      "Block": {+                        "block_id": 1,+                        "check_id": 0,+                        "rule": "check if resource($0), operation(\"read\"), right($0, \"read\")"+                      }+                    }+                  ]+                }+              }+            }+          },+          "authorizer_code": "resource(\"file1\");\n\nallow if true;\n",+          "revocation_ids": [+            "7595a112a1eb5b81a6e398852e6118b7f5b8cbbff452778e655100e5fb4faa8d3a2af52fe2c4f9524879605675fae26adbc4783e0cafc43522fa82385f396c03",+            "45f4c14f9d9e8fa044d68be7a2ec8cddb835f575c7b913ec59bd636c70acae9a90db9064ba0b3084290ed0c422bbb7170092a884f5e0202b31e9235bbcc1650d"+          ]+        }+      }+    },+    {+      "title": "different root key",+      "filename": "test002_different_root_key.bc",+      "token": [+        {+          "symbols": [+            "file1"+          ],+          "public_keys": [],+          "external_key": null,+          "code": "right(\"file1\", \"read\");\n"+        },+        {+          "symbols": [+            "0"+          ],+          "public_keys": [],+          "external_key": null,+          "code": "check if resource($0), operation(\"read\"), right($0, \"read\");\n"+        }+      ],+      "validations": {+        "": {+          "world": null,+          "result": {+            "Err": {+              "Format": {+                "Signature": {+                  "InvalidSignature": "signature error: Verification equation was not satisfied"+                }+              }+            }+          },+          "authorizer_code": "",+          "revocation_ids": []+        }+      }+    },+    {+      "title": "invalid signature format",+      "filename": "test003_invalid_signature_format.bc",+      "token": [+        {+          "symbols": [+            "file1",+            "file2"+          ],+          "public_keys": [],+          "external_key": null,+          "code": "right(\"file1\", \"read\");\nright(\"file2\", \"read\");\nright(\"file1\", \"write\");\n"+        },+        {+          "symbols": [+            "0"+          ],+          "public_keys": [],+          "external_key": null,+          "code": "check if resource($0), operation(\"read\"), right($0, \"read\");\n"+        }+      ],+      "validations": {+        "": {+          "world": null,+          "result": {+            "Err": {+              "Format": {+                "InvalidSignatureSize": 16+              }+            }+          },+          "authorizer_code": "",+          "revocation_ids": []+        }+      }+    },+    {+      "title": "random block",+      "filename": "test004_random_block.bc",+      "token": [+        {+          "symbols": [+            "file1",+            "file2"+          ],+          "public_keys": [],+          "external_key": null,+          "code": "right(\"file1\", \"read\");\nright(\"file2\", \"read\");\nright(\"file1\", \"write\");\n"+        },+        {+          "symbols": [+            "0"+          ],+          "public_keys": [],+          "external_key": null,+          "code": "check if resource($0), operation(\"read\"), right($0, \"read\");\n"+        }+      ],+      "validations": {+        "": {+          "world": null,+          "result": {+            "Err": {+              "Format": {+                "Signature": {+                  "InvalidSignature": "signature error: Verification equation was not satisfied"+                }+              }+            }+          },+          "authorizer_code": "",+          "revocation_ids": []+        }+      }+    },+    {+      "title": "invalid signature",+      "filename": "test005_invalid_signature.bc",+      "token": [+        {+          "symbols": [+            "file1",+            "file2"+          ],+          "public_keys": [],+          "external_key": null,+          "code": "right(\"file1\", \"read\");\nright(\"file2\", \"read\");\nright(\"file1\", \"write\");\n"+        },+        {+          "symbols": [+            "0"+          ],+          "public_keys": [],+          "external_key": null,+          "code": "check if resource($0), operation(\"read\"), right($0, \"read\");\n"+        }+      ],+      "validations": {+        "": {+          "world": null,+          "result": {+            "Err": {+              "Format": {+                "Signature": {+                  "InvalidSignature": "signature error: Verification equation was not satisfied"+                }+              }+            }+          },+          "authorizer_code": "",+          "revocation_ids": []+        }+      }+    },+    {+      "title": "reordered blocks",+      "filename": "test006_reordered_blocks.bc",+      "token": [+        {+          "symbols": [+            "file1",+            "file2"+          ],+          "public_keys": [],+          "external_key": null,+          "code": "right(\"file1\", \"read\");\nright(\"file2\", \"read\");\nright(\"file1\", \"write\");\n"+        },+        {+          "symbols": [+            "0"+          ],+          "public_keys": [],+          "external_key": null,+          "code": "check if resource($0), operation(\"read\"), right($0, \"read\");\n"+        },+        {+          "symbols": [],+          "public_keys": [],+          "external_key": null,+          "code": "check if resource(\"file1\");\n"+        }+      ],+      "validations": {+        "": {+          "world": null,+          "result": {+            "Err": {+              "Format": {+                "Signature": {+                  "InvalidSignature": "signature error: Verification equation was not satisfied"+                }+              }+            }+          },+          "authorizer_code": "",+          "revocation_ids": []+        }+      }+    },+    {+      "title": "scoped rules",+      "filename": "test007_scoped_rules.bc",+      "token": [+        {+          "symbols": [+            "user_id",+            "alice",+            "file1"+          ],+          "public_keys": [],+          "external_key": null,+          "code": "user_id(\"alice\");\nowner(\"alice\", \"file1\");\n"+        },+        {+          "symbols": [+            "0",+            "1"+          ],+          "public_keys": [],+          "external_key": null,+          "code": "right($0, \"read\") <- resource($0), user_id($1), owner($1, $0);\ncheck if resource($0), operation(\"read\"), right($0, \"read\");\n"+        },+        {+          "symbols": [+            "file2"+          ],+          "public_keys": [],+          "external_key": null,+          "code": "owner(\"alice\", \"file2\");\n"+        }+      ],+      "validations": {+        "": {+          "world": {+            "facts": [+              {+                "origin": [+                  null+                ],+                "facts": [+                  "operation(\"read\")",+                  "resource(\"file2\")"+                ]+              },+              {+                "origin": [+                  0+                ],+                "facts": [+                  "owner(\"alice\", \"file1\")",+                  "user_id(\"alice\")"+                ]+              },+              {+                "origin": [+                  2+                ],+                "facts": [+                  "owner(\"alice\", \"file2\")"+                ]+              }+            ],+            "rules": [+              {+                "origin": 1,+                "rules": [+                  "right($0, \"read\") <- resource($0), user_id($1), owner($1, $0)"+                ]+              }+            ],+            "checks": [+              {+                "origin": 1,+                "checks": [+                  "check if resource($0), operation(\"read\"), right($0, \"read\")"+                ]+              }+            ],+            "policies": [+              "allow if true"+            ]+          },+          "result": {+            "Err": {+              "FailedLogic": {+                "Unauthorized": {+                  "policy": {+                    "Allow": 0+                  },+                  "checks": [+                    {+                      "Block": {+                        "block_id": 1,+                        "check_id": 0,+                        "rule": "check if resource($0), operation(\"read\"), right($0, \"read\")"+                      }+                    }+                  ]+                }+              }+            }+          },+          "authorizer_code": "resource(\"file2\");\noperation(\"read\");\n\nallow if true;\n",+          "revocation_ids": [+            "4d86c9af808dc2e0583f47282e6f5df3e09dc264d5231ec360b4519e15ddaeec60b25a9bbcb22e8d192f4d36a0da3f9243711e30535b00ee55c53cb1395f230a",+            "63208c668c66f3ba6927140ba37533593b25e03459447805d4b2a8b75adeef45794c3d7249afe506ed77ccee276160bb4052a4009302bd34871a440f070b4509",+            "d8da982888eae8c038e4894a8c06fc57d8e5f06ad2e972b9cf4bde49ad60804558a0d1938192596c702d8e4f7f12ec19201d7c33d0cd77774a0d879a33880d02"+          ]+        }+      }+    },+    {+      "title": "scoped checks",+      "filename": "test008_scoped_checks.bc",+      "token": [+        {+          "symbols": [+            "file1"+          ],+          "public_keys": [],+          "external_key": null,+          "code": "right(\"file1\", \"read\");\n"+        },+        {+          "symbols": [+            "0"+          ],+          "public_keys": [],+          "external_key": null,+          "code": "check if resource($0), operation(\"read\"), right($0, \"read\");\n"+        },+        {+          "symbols": [+            "file2"+          ],+          "public_keys": [],+          "external_key": null,+          "code": "right(\"file2\", \"read\");\n"+        }+      ],+      "validations": {+        "": {+          "world": {+            "facts": [+              {+                "origin": [+                  null+                ],+                "facts": [+                  "operation(\"read\")",+                  "resource(\"file2\")"+                ]+              },+              {+                "origin": [+                  0+                ],+                "facts": [+                  "right(\"file1\", \"read\")"+                ]+              },+              {+                "origin": [+                  2+                ],+                "facts": [+                  "right(\"file2\", \"read\")"+                ]+              }+            ],+            "rules": [],+            "checks": [+              {+                "origin": 1,+                "checks": [+                  "check if resource($0), operation(\"read\"), right($0, \"read\")"+                ]+              }+            ],+            "policies": [+              "allow if true"+            ]+          },+          "result": {+            "Err": {+              "FailedLogic": {+                "Unauthorized": {+                  "policy": {+                    "Allow": 0+                  },+                  "checks": [+                    {+                      "Block": {+                        "block_id": 1,+                        "check_id": 0,+                        "rule": "check if resource($0), operation(\"read\"), right($0, \"read\")"+                      }+                    }+                  ]+                }+              }+            }+          },+          "authorizer_code": "resource(\"file2\");\noperation(\"read\");\n\nallow if true;\n",+          "revocation_ids": [+            "a80c985ddef895518c216f64c65dcd50a5d97d012a94453d79159aed2981654b1fe9748c686c5667604026a94fb8db8a1d02de747df61e99fa9a63ff2878ad00",+            "77df45442be86a416aa02fd9d98d6d4703c634a9e3b1d293b41f5dc97849afbe7faeec8c22a210574888acc008fb64fe691ec9e8d2655586f970d9a6b6577000",+            "b31398aefe97d3db41ebc445760f216fb3aa7bf7439adcfc3a07489bfcc163970af3f4e20f5460aa24cf841101a5ab114d21acc0ee8d442bae7793b121284900"+          ]+        }+      }+    },+    {+      "title": "expired token",+      "filename": "test009_expired_token.bc",+      "token": [+        {+          "symbols": [],+          "public_keys": [],+          "external_key": null,+          "code": ""+        },+        {+          "symbols": [+            "file1"+          ],+          "public_keys": [],+          "external_key": null,+          "code": "check if resource(\"file1\");\ncheck if time($time), $time <= 2018-12-20T00:00:00Z;\n"+        }+      ],+      "validations": {+        "": {+          "world": {+            "facts": [+              {+                "origin": [+                  null+                ],+                "facts": [+                  "operation(\"read\")",+                  "resource(\"file1\")",+                  "time(2020-12-21T09:23:12Z)"+                ]+              }+            ],+            "rules": [],+            "checks": [+              {+                "origin": 1,+                "checks": [+                  "check if resource(\"file1\")",+                  "check if time($time), $time <= 2018-12-20T00:00:00Z"+                ]+              }+            ],+            "policies": [+              "allow if true"+            ]+          },+          "result": {+            "Err": {+              "FailedLogic": {+                "Unauthorized": {+                  "policy": {+                    "Allow": 0+                  },+                  "checks": [+                    {+                      "Block": {+                        "block_id": 1,+                        "check_id": 1,+                        "rule": "check if time($time), $time <= 2018-12-20T00:00:00Z"+                      }+                    }+                  ]+                }+              }+            }+          },+          "authorizer_code": "resource(\"file1\");\noperation(\"read\");\ntime(2020-12-21T09:23:12Z);\n\nallow if true;\n",+          "revocation_ids": [+            "c248907bb6e5f433bbb5edf6367b399ebefca0d321d0b2ea9fc67f66dc1064ce926adb0c05d90c3e8a2833328b3578f79c4e1bca43583d9bcfb2ba6c37303d00",+            "a4edf7aaea8658bb9ae19b3ffe2adcc77cc9f16c249aeb0a85a584b5362f89f27f7c67ac0af16d7170673d6d1fb1563d1934b25ec5a461f6c01fa49805cd5e07"+          ]+        }+      }+    },+    {+      "title": "authorizer scope",+      "filename": "test010_authorizer_scope.bc",+      "token": [+        {+          "symbols": [+            "file1"+          ],+          "public_keys": [],+          "external_key": null,+          "code": "right(\"file1\", \"read\");\n"+        },+        {+          "symbols": [+            "file2"+          ],+          "public_keys": [],+          "external_key": null,+          "code": "right(\"file2\", \"read\");\n"+        }+      ],+      "validations": {+        "": {+          "world": {+            "facts": [+              {+                "origin": [+                  null+                ],+                "facts": [+                  "operation(\"read\")",+                  "resource(\"file2\")"+                ]+              },+              {+                "origin": [+                  0+                ],+                "facts": [+                  "right(\"file1\", \"read\")"+                ]+              },+              {+                "origin": [+                  1+                ],+                "facts": [+                  "right(\"file2\", \"read\")"+                ]+              }+            ],+            "rules": [],+            "checks": [+              {+                "origin": 18446744073709551615,+                "checks": [+                  "check if right($0, $1), resource($0), operation($1)"+                ]+              }+            ],+            "policies": [+              "allow if true"+            ]+          },+          "result": {+            "Err": {+              "FailedLogic": {+                "Unauthorized": {+                  "policy": {+                    "Allow": 0+                  },+                  "checks": [+                    {+                      "Authorizer": {+                        "check_id": 0,+                        "rule": "check if right($0, $1), resource($0), operation($1)"+                      }+                    }+                  ]+                }+              }+            }+          },+          "authorizer_code": "resource(\"file2\");\noperation(\"read\");\n\ncheck if right($0, $1), resource($0), operation($1);\n\nallow if true;\n",+          "revocation_ids": [+            "a80c985ddef895518c216f64c65dcd50a5d97d012a94453d79159aed2981654b1fe9748c686c5667604026a94fb8db8a1d02de747df61e99fa9a63ff2878ad00",+            "966eceb2aa937c41b25368808bab6e0698c02a4038de669d007c9c3d43602638a640083558d1576ac80cf3eb2ac6a7585527e0f6c1a65402f0935cf7f4df8005"+          ]+        }+      }+    },+    {+      "title": "authorizer authority checks",+      "filename": "test011_authorizer_authority_caveats.bc",+      "token": [+        {+          "symbols": [+            "file1"+          ],+          "public_keys": [],+          "external_key": null,+          "code": "right(\"file1\", \"read\");\n"+        }+      ],+      "validations": {+        "": {+          "world": {+            "facts": [+              {+                "origin": [+                  null+                ],+                "facts": [+                  "operation(\"read\")",+                  "resource(\"file2\")"+                ]+              },+              {+                "origin": [+                  0+                ],+                "facts": [+                  "right(\"file1\", \"read\")"+                ]+              }+            ],+            "rules": [],+            "checks": [+              {+                "origin": 18446744073709551615,+                "checks": [+                  "check if right($0, $1), resource($0), operation($1)"+                ]+              }+            ],+            "policies": [+              "allow if true"+            ]+          },+          "result": {+            "Err": {+              "FailedLogic": {+                "Unauthorized": {+                  "policy": {+                    "Allow": 0+                  },+                  "checks": [+                    {+                      "Authorizer": {+                        "check_id": 0,+                        "rule": "check if right($0, $1), resource($0), operation($1)"+                      }+                    }+                  ]+                }+              }+            }+          },+          "authorizer_code": "resource(\"file2\");\noperation(\"read\");\n\ncheck if right($0, $1), resource($0), operation($1);\n\nallow if true;\n",+          "revocation_ids": [+            "a80c985ddef895518c216f64c65dcd50a5d97d012a94453d79159aed2981654b1fe9748c686c5667604026a94fb8db8a1d02de747df61e99fa9a63ff2878ad00"+          ]+        }+      }+    },+    {+      "title": "authority checks",+      "filename": "test012_authority_caveats.bc",+      "token": [+        {+          "symbols": [+            "file1"+          ],+          "public_keys": [],+          "external_key": null,+          "code": "check if resource(\"file1\");\n"+        }+      ],+      "validations": {+        "file1": {+          "world": {+            "facts": [+              {+                "origin": [+                  null+                ],+                "facts": [+                  "operation(\"read\")",+                  "resource(\"file1\")"+                ]+              }+            ],+            "rules": [],+            "checks": [+              {+                "origin": 0,+                "checks": [+                  "check if resource(\"file1\")"+                ]+              }+            ],+            "policies": [+              "allow if true"+            ]+          },+          "result": {+            "Ok": 0+          },+          "authorizer_code": "resource(\"file1\");\noperation(\"read\");\n\nallow if true;\n",+          "revocation_ids": [+            "6a8f90dad67ae2ac188460463914ae7326fda431c80785755f4edcc15f1a53911f7366e606ad80cbbeba94672e42713e88632a932128f1d796ce9ba7d7a0b80a"+          ]+        },+        "file2": {+          "world": {+            "facts": [+              {+                "origin": [+                  null+                ],+                "facts": [+                  "operation(\"read\")",+                  "resource(\"file2\")"+                ]+              }+            ],+            "rules": [],+            "checks": [+              {+                "origin": 0,+                "checks": [+                  "check if resource(\"file1\")"+                ]+              }+            ],+            "policies": [+              "allow if true"+            ]+          },+          "result": {+            "Err": {+              "FailedLogic": {+                "Unauthorized": {+                  "policy": {+                    "Allow": 0+                  },+                  "checks": [+                    {+                      "Block": {+                        "block_id": 0,+                        "check_id": 0,+                        "rule": "check if resource(\"file1\")"+                      }+                    }+                  ]+                }+              }+            }+          },+          "authorizer_code": "resource(\"file2\");\noperation(\"read\");\n\nallow if true;\n",+          "revocation_ids": [+            "6a8f90dad67ae2ac188460463914ae7326fda431c80785755f4edcc15f1a53911f7366e606ad80cbbeba94672e42713e88632a932128f1d796ce9ba7d7a0b80a"+          ]+        }+      }+    },+    {+      "title": "block rules",+      "filename": "test013_block_rules.bc",+      "token": [+        {+          "symbols": [+            "file1",+            "file2"+          ],+          "public_keys": [],+          "external_key": null,+          "code": "right(\"file1\", \"read\");\nright(\"file2\", \"read\");\n"+        },+        {+          "symbols": [+            "valid_date",+            "0",+            "1"+          ],+          "public_keys": [],+          "external_key": null,+          "code": "valid_date(\"file1\") <- time($0), resource(\"file1\"), $0 <= 2030-12-31T12:59:59Z;\nvalid_date($1) <- time($0), resource($1), $0 <= 1999-12-31T12:59:59Z, ![\"file1\"].contains($1);\ncheck if valid_date($0), resource($0);\n"+        }+      ],+      "validations": {+        "file1": {+          "world": {+            "facts": [+              {+                "origin": [+                  null+                ],+                "facts": [+                  "resource(\"file1\")",+                  "time(2020-12-21T09:23:12Z)"+                ]+              },+              {+                "origin": [+                  null,+                  1+                ],+                "facts": [+                  "valid_date(\"file1\")"+                ]+              },+              {+                "origin": [+                  0+                ],+                "facts": [+                  "right(\"file1\", \"read\")",+                  "right(\"file2\", \"read\")"+                ]+              }+            ],+            "rules": [+              {+                "origin": 1,+                "rules": [+                  "valid_date(\"file1\") <- time($0), resource(\"file1\"), $0 <= 2030-12-31T12:59:59Z",+                  "valid_date($1) <- time($0), resource($1), $0 <= 1999-12-31T12:59:59Z, ![\"file1\"].contains($1)"+                ]+              }+            ],+            "checks": [+              {+                "origin": 1,+                "checks": [+                  "check if valid_date($0), resource($0)"+                ]+              }+            ],+            "policies": [+              "allow if true"+            ]+          },+          "result": {+            "Ok": 0+          },+          "authorizer_code": "resource(\"file1\");\ntime(2020-12-21T09:23:12Z);\n\nallow if true;\n",+          "revocation_ids": [+            "c46d071ff3f33434223c8305fdad529f62bf78bb5d9cbfc2a345d4bca6bf314014840e18ba353f86fdb9073d58b12b8c872ac1f8e593c2e9064b90f6c2ede006",+            "a0c4c163a0b3ca406df4ece3d1371356190df04208eccef72f77e875ed0531b5d37e243d6f388b1967776a5dfd16ef228f19c5bdd6d2820f145c5ed3c3dcdc00"+          ]+        },+        "file2": {+          "world": {+            "facts": [+              {+                "origin": [+                  null+                ],+                "facts": [+                  "resource(\"file2\")",+                  "time(2020-12-21T09:23:12Z)"+                ]+              },+              {+                "origin": [+                  0+                ],+                "facts": [+                  "right(\"file1\", \"read\")",+                  "right(\"file2\", \"read\")"+                ]+              }+            ],+            "rules": [+              {+                "origin": 1,+                "rules": [+                  "valid_date(\"file1\") <- time($0), resource(\"file1\"), $0 <= 2030-12-31T12:59:59Z",+                  "valid_date($1) <- time($0), resource($1), $0 <= 1999-12-31T12:59:59Z, ![\"file1\"].contains($1)"+                ]+              }+            ],+            "checks": [+              {+                "origin": 1,+                "checks": [+                  "check if valid_date($0), resource($0)"+                ]+              }+            ],+            "policies": [+              "allow if true"+            ]+          },+          "result": {+            "Err": {+              "FailedLogic": {+                "Unauthorized": {+                  "policy": {+                    "Allow": 0+                  },+                  "checks": [+                    {+                      "Block": {+                        "block_id": 1,+                        "check_id": 0,+                        "rule": "check if valid_date($0), resource($0)"+                      }+                    }+                  ]+                }+              }+            }+          },+          "authorizer_code": "resource(\"file2\");\ntime(2020-12-21T09:23:12Z);\n\nallow if true;\n",+          "revocation_ids": [+            "c46d071ff3f33434223c8305fdad529f62bf78bb5d9cbfc2a345d4bca6bf314014840e18ba353f86fdb9073d58b12b8c872ac1f8e593c2e9064b90f6c2ede006",+            "a0c4c163a0b3ca406df4ece3d1371356190df04208eccef72f77e875ed0531b5d37e243d6f388b1967776a5dfd16ef228f19c5bdd6d2820f145c5ed3c3dcdc00"+          ]+        }+      }+    },+    {+      "title": "regex_constraint",+      "filename": "test014_regex_constraint.bc",+      "token": [+        {+          "symbols": [+            "0",+            "file[0-9]+.txt"+          ],+          "public_keys": [],+          "external_key": null,+          "code": "check if resource($0), $0.matches(\"file[0-9]+.txt\");\n"+        }+      ],+      "validations": {+        "file1": {+          "world": {+            "facts": [+              {+                "origin": [+                  null+                ],+                "facts": [+                  "resource(\"file1\")"+                ]+              }+            ],+            "rules": [],+            "checks": [+              {+                "origin": 0,+                "checks": [+                  "check if resource($0), $0.matches(\"file[0-9]+.txt\")"+                ]+              }+            ],+            "policies": [+              "allow if true"+            ]+          },+          "result": {+            "Err": {+              "FailedLogic": {+                "Unauthorized": {+                  "policy": {+                    "Allow": 0+                  },+                  "checks": [+                    {+                      "Block": {+                        "block_id": 0,+                        "check_id": 0,+                        "rule": "check if resource($0), $0.matches(\"file[0-9]+.txt\")"+                      }+                    }+                  ]+                }+              }+            }+          },+          "authorizer_code": "resource(\"file1\");\n\nallow if true;\n",+          "revocation_ids": [+            "da42718ad2631c12d3a44b7710dcc76c6c7809c6bc3a2d7eb0378c4154eae10e0884a8d54a2cd25ca3dfe01091d816ebbb9d246227baf7a359a787cb2344ad07"+          ]+        },+        "file123": {+          "world": {+            "facts": [+              {+                "origin": [+                  null+                ],+                "facts": [+                  "resource(\"file123.txt\")"+                ]+              }+            ],+            "rules": [],+            "checks": [+              {+                "origin": 0,+                "checks": [+                  "check if resource($0), $0.matches(\"file[0-9]+.txt\")"+                ]+              }+            ],+            "policies": [+              "allow if true"+            ]+          },+          "result": {+            "Ok": 0+          },+          "authorizer_code": "resource(\"file123.txt\");\n\nallow if true;\n",+          "revocation_ids": [+            "da42718ad2631c12d3a44b7710dcc76c6c7809c6bc3a2d7eb0378c4154eae10e0884a8d54a2cd25ca3dfe01091d816ebbb9d246227baf7a359a787cb2344ad07"+          ]+        }+      }+    },+    {+      "title": "multi queries checks",+      "filename": "test015_multi_queries_caveats.bc",+      "token": [+        {+          "symbols": [+            "must_be_present",+            "hello"+          ],+          "public_keys": [],+          "external_key": null,+          "code": "must_be_present(\"hello\");\n"+        }+      ],+      "validations": {+        "": {+          "world": {+            "facts": [+              {+                "origin": [+                  0+                ],+                "facts": [+                  "must_be_present(\"hello\")"+                ]+              }+            ],+            "rules": [],+            "checks": [+              {+                "origin": 18446744073709551615,+                "checks": [+                  "check if must_be_present($0) or must_be_present($0)"+                ]+              }+            ],+            "policies": [+              "allow if true"+            ]+          },+          "result": {+            "Ok": 0+          },+          "authorizer_code": "check if must_be_present($0) or must_be_present($0);\n\nallow if true;\n",+          "revocation_ids": [+            "b0d466d31e015fa85a075fa875f7e1c9017edd503fee9f62a5f033e1fcfa811074b6e39dfe5af2f452043db97a3f98650592a370f5685b62c5d6abf9dd10b603"+          ]+        }+      }+    },+    {+      "title": "check head name should be independent from fact names",+      "filename": "test016_caveat_head_name.bc",+      "token": [+        {+          "symbols": [+            "hello"+          ],+          "public_keys": [],+          "external_key": null,+          "code": "check if resource(\"hello\");\n"+        },+        {+          "symbols": [+            "test"+          ],+          "public_keys": [],+          "external_key": null,+          "code": "query(\"test\");\n"+        }+      ],+      "validations": {+        "": {+          "world": {+            "facts": [+              {+                "origin": [+                  1+                ],+                "facts": [+                  "query(\"test\")"+                ]+              }+            ],+            "rules": [],+            "checks": [+              {+                "origin": 0,+                "checks": [+                  "check if resource(\"hello\")"+                ]+              }+            ],+            "policies": [+              "allow if true"+            ]+          },+          "result": {+            "Err": {+              "FailedLogic": {+                "Unauthorized": {+                  "policy": {+                    "Allow": 0+                  },+                  "checks": [+                    {+                      "Block": {+                        "block_id": 0,+                        "check_id": 0,+                        "rule": "check if resource(\"hello\")"+                      }+                    }+                  ]+                }+              }+            }+          },+          "authorizer_code": "allow if true;\n",+          "revocation_ids": [+            "ce6f804f4390e693a8853d9a4a10bd4f3c94b86b7c6d671993a6e19346bc4d20bbb52cc945e5d0d02e4e75fa5da2caa99764050190353564a0a0b4b276809402",+            "916d566cc724e0773046fc5266e9d0d804311435b8d6955b332f823ab296be9a78dfea190447732ac9f6217234cf5726becf88f65169c6de56a766af55451b0f"+          ]+        }+      }+    },+    {+      "title": "test expression syntax and all available operations",+      "filename": "test017_expressions.bc",+      "token": [+        {+          "symbols": [+            "hello world",+            "hello",+            "world",+            "aaabde",+            "a*c?.e",+            "abd",+            "aaa",+            "b",+            "de",+            "abcD12",+            "é",+            "abc",+            "def"+          ],+          "public_keys": [],+          "external_key": null,+          "code": "check if true;\ncheck if !false;\ncheck if !false && true;\ncheck if false || true;\ncheck if (true || false) && true;\ncheck if true == true;\ncheck if false == false;\ncheck if 1 < 2;\ncheck if 2 > 1;\ncheck if 1 <= 2;\ncheck if 1 <= 1;\ncheck if 2 >= 1;\ncheck if 2 >= 2;\ncheck if 3 == 3;\ncheck if 1 + 2 * 3 - 4 / 2 == 5;\ncheck if \"hello world\".starts_with(\"hello\") && \"hello world\".ends_with(\"world\");\ncheck if \"aaabde\".matches(\"a*c?.e\");\ncheck if \"aaabde\".contains(\"abd\");\ncheck if \"aaabde\" == \"aaa\" + \"b\" + \"de\";\ncheck if \"abcD12\" == \"abcD12\";\ncheck if \"abcD12\".length() == 6;\ncheck if \"é\".length() == 2;\ncheck if 2019-12-04T09:46:41Z < 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z > 2019-12-04T09:46:41Z;\ncheck if 2019-12-04T09:46:41Z <= 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z >= 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z >= 2019-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z >= 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z == 2020-12-04T09:46:41Z;\ncheck if hex:12ab == hex:12ab;\ncheck if [1, 2].contains(2);\ncheck if [2019-12-04T09:46:41Z, 2020-12-04T09:46:41Z].contains(2020-12-04T09:46:41Z);\ncheck if [false, true].contains(true);\ncheck if [\"abc\", \"def\"].contains(\"abc\");\ncheck if [hex:12ab, hex:34de].contains(hex:34de);\ncheck if [1, 2].contains([2]);\ncheck if [1, 2] == [1, 2];\ncheck if [1, 2].intersection([2, 3]) == [2];\ncheck if [1, 2].union([2, 3]) == [1, 2, 3];\ncheck if [1, 2, 3].intersection([1, 2]).contains(1);\ncheck if [1, 2, 3].intersection([1, 2]).length() == 2;\n"+        }+      ],+      "validations": {+        "": {+          "world": {+            "facts": [],+            "rules": [],+            "checks": [+              {+                "origin": 0,+                "checks": [+                  "check if !false",+                  "check if !false && true",+                  "check if \"aaabde\" == \"aaa\" + \"b\" + \"de\"",+                  "check if \"aaabde\".contains(\"abd\")",+                  "check if \"aaabde\".matches(\"a*c?.e\")",+                  "check if \"abcD12\" == \"abcD12\"",+                  "check if \"abcD12\".length() == 6",+                  "check if \"hello world\".starts_with(\"hello\") && \"hello world\".ends_with(\"world\")",+                  "check if \"é\".length() == 2",+                  "check if (true || false) && true",+                  "check if 1 + 2 * 3 - 4 / 2 == 5",+                  "check if 1 < 2",+                  "check if 1 <= 1",+                  "check if 1 <= 2",+                  "check if 2 > 1",+                  "check if 2 >= 1",+                  "check if 2 >= 2",+                  "check if 2019-12-04T09:46:41Z < 2020-12-04T09:46:41Z",+                  "check if 2019-12-04T09:46:41Z <= 2020-12-04T09:46:41Z",+                  "check if 2020-12-04T09:46:41Z == 2020-12-04T09:46:41Z",+                  "check if 2020-12-04T09:46:41Z > 2019-12-04T09:46:41Z",+                  "check if 2020-12-04T09:46:41Z >= 2019-12-04T09:46:41Z",+                  "check if 2020-12-04T09:46:41Z >= 2020-12-04T09:46:41Z",+                  "check if 2020-12-04T09:46:41Z >= 2020-12-04T09:46:41Z",+                  "check if 3 == 3",+                  "check if [\"abc\", \"def\"].contains(\"abc\")",+                  "check if [1, 2, 3].intersection([1, 2]).contains(1)",+                  "check if [1, 2, 3].intersection([1, 2]).length() == 2",+                  "check if [1, 2] == [1, 2]",+                  "check if [1, 2].contains(2)",+                  "check if [1, 2].contains([2])",+                  "check if [1, 2].intersection([2, 3]) == [2]",+                  "check if [1, 2].union([2, 3]) == [1, 2, 3]",+                  "check if [2019-12-04T09:46:41Z, 2020-12-04T09:46:41Z].contains(2020-12-04T09:46:41Z)",+                  "check if [false, true].contains(true)",+                  "check if [hex:12ab, hex:34de].contains(hex:34de)",+                  "check if false == false",+                  "check if false || true",+                  "check if hex:12ab == hex:12ab",+                  "check if true",+                  "check if true == true"+                ]+              }+            ],+            "policies": [+              "allow if true"+            ]+          },+          "result": {+            "Ok": 0+          },+          "authorizer_code": "allow if true;\n",+          "revocation_ids": [+            "3d5b23b502b3dd920bfb68b9039164d1563bb8927210166fa5c17f41b76b31bb957bc2ed3318452958f658baa2d398fe4cf25c58a27e6c8bc42c9702c8aa1b0c"+          ]+        }+      }+    },+    {+      "title": "invalid block rule with unbound_variables",+      "filename": "test018_unbound_variables_in_rule.bc",+      "token": [+        {+          "symbols": [],+          "public_keys": [],+          "external_key": null,+          "code": "check if operation(\"read\");\n"+        },+        {+          "symbols": [+            "unbound",+            "any1",+            "any2"+          ],+          "public_keys": [],+          "external_key": null,+          "code": "operation($unbound, \"read\") <- operation($any1, $any2);\n"+        }+      ],+      "validations": {+        "": {+          "world": null,+          "result": {+            "Err": {+              "FailedLogic": {+                "InvalidBlockRule": [+                  0,+                  "operation($unbound, \"read\") <- operation($any1, $any2)"+                ]+              }+            }+          },+          "authorizer_code": "",+          "revocation_ids": [+            "a44210c6a01e55eadefc7d8540c2e6eff80ab6eeedde4751de734f9d780435780680d3f42d826b7e0f0dcf4a5ba303fd4c116984bb30978813d46ed867924307",+            "b0a33e3f4cd0994c0766c196c4d11c15e5a0f9bfba79a3a2b35ddd04ddb890282a7c63336ada5c680b9f9c940c1fa7127d2699754cbc77c21e1a2d85c5ef700c"+          ]+        }+      }+    },+    {+      "title": "invalid block rule generating an #authority or #ambient symbol with a variable",+      "filename": "test019_generating_ambient_from_variables.bc",+      "token": [+        {+          "symbols": [],+          "public_keys": [],+          "external_key": null,+          "code": "check if operation(\"read\");\n"+        },+        {+          "symbols": [+            "any"+          ],+          "public_keys": [],+          "external_key": null,+          "code": "operation(\"read\") <- operation($any);\n"+        }+      ],+      "validations": {+        "": {+          "world": {+            "facts": [+              {+                "origin": [+                  null+                ],+                "facts": [+                  "operation(\"write\")"+                ]+              },+              {+                "origin": [+                  null,+                  1+                ],+                "facts": [+                  "operation(\"read\")"+                ]+              }+            ],+            "rules": [+              {+                "origin": 1,+                "rules": [+                  "operation(\"read\") <- operation($any)"+                ]+              }+            ],+            "checks": [+              {+                "origin": 0,+                "checks": [+                  "check if operation(\"read\")"+                ]+              }+            ],+            "policies": [+              "allow if true"+            ]+          },+          "result": {+            "Err": {+              "FailedLogic": {+                "Unauthorized": {+                  "policy": {+                    "Allow": 0+                  },+                  "checks": [+                    {+                      "Block": {+                        "block_id": 0,+                        "check_id": 0,+                        "rule": "check if operation(\"read\")"+                      }+                    }+                  ]+                }+              }+            }+          },+          "authorizer_code": "operation(\"write\");\n\nallow if true;\n",+          "revocation_ids": [+            "a44210c6a01e55eadefc7d8540c2e6eff80ab6eeedde4751de734f9d780435780680d3f42d826b7e0f0dcf4a5ba303fd4c116984bb30978813d46ed867924307",+            "d3f8822a9b9bc0ee3933283c493ca9e711be5dd8339b5fe2eba1de3805aad4e84d3e2fb4affb4a743f1289915c167582b9425343635e45b70573ea1ee7a1ea03"+          ]+        }+      }+    },+    {+      "title": "sealed token",+      "filename": "test020_sealed.bc",+      "token": [+        {+          "symbols": [+            "file1",+            "file2"+          ],+          "public_keys": [],+          "external_key": null,+          "code": "right(\"file1\", \"read\");\nright(\"file2\", \"read\");\nright(\"file1\", \"write\");\n"+        },+        {+          "symbols": [+            "0"+          ],+          "public_keys": [],+          "external_key": null,+          "code": "check if resource($0), operation(\"read\"), right($0, \"read\");\n"+        }+      ],+      "validations": {+        "": {+          "world": {+            "facts": [+              {+                "origin": [+                  null+                ],+                "facts": [+                  "operation(\"read\")",+                  "resource(\"file1\")"+                ]+              },+              {+                "origin": [+                  0+                ],+                "facts": [+                  "right(\"file1\", \"read\")",+                  "right(\"file1\", \"write\")",+                  "right(\"file2\", \"read\")"+                ]+              }+            ],+            "rules": [],+            "checks": [+              {+                "origin": 1,+                "checks": [+                  "check if resource($0), operation(\"read\"), right($0, \"read\")"+                ]+              }+            ],+            "policies": [+              "allow if true"+            ]+          },+          "result": {+            "Ok": 0+          },+          "authorizer_code": "resource(\"file1\");\noperation(\"read\");\n\nallow if true;\n",+          "revocation_ids": [+            "7595a112a1eb5b81a6e398852e6118b7f5b8cbbff452778e655100e5fb4faa8d3a2af52fe2c4f9524879605675fae26adbc4783e0cafc43522fa82385f396c03",+            "45f4c14f9d9e8fa044d68be7a2ec8cddb835f575c7b913ec59bd636c70acae9a90db9064ba0b3084290ed0c422bbb7170092a884f5e0202b31e9235bbcc1650d"+          ]+        }+      }+    },+    {+      "title": "parsing",+      "filename": "test021_parsing.bc",+      "token": [+        {+          "symbols": [+            "ns::fact_123",+            "hello é\t😁"+          ],+          "public_keys": [],+          "external_key": null,+          "code": "ns::fact_123(\"hello é\t😁\");\n"+        }+      ],+      "validations": {+        "": {+          "world": {+            "facts": [+              {+                "origin": [+                  0+                ],+                "facts": [+                  "ns::fact_123(\"hello é\t😁\")"+                ]+              }+            ],+            "rules": [],+            "checks": [+              {+                "origin": 18446744073709551615,+                "checks": [+                  "check if ns::fact_123(\"hello é\t😁\")"+                ]+              }+            ],+            "policies": [+              "allow if true"+            ]+          },+          "result": {+            "Ok": 0+          },+          "authorizer_code": "check if ns::fact_123(\"hello é\t😁\");\n\nallow if true;\n",+          "revocation_ids": [+            "d4b2f417b6e906434fdf5058afcabfcb98d3628f814f1c9dd7e64250d9beec4465aff51bd0cb2e85d0e67dc9f613c2a42af6158c678bc6f8b4684cd3a2d0d302"+          ]+        }+      }+    },+    {+      "title": "default_symbols",+      "filename": "test022_default_symbols.bc",+      "token": [+        {+          "symbols": [],+          "public_keys": [],+          "external_key": null,+          "code": "read(0);\nwrite(1);\nresource(2);\noperation(3);\nright(4);\ntime(5);\nrole(6);\nowner(7);\ntenant(8);\nnamespace(9);\nuser(10);\nteam(11);\nservice(12);\nadmin(13);\nemail(14);\ngroup(15);\nmember(16);\nip_address(17);\nclient(18);\nclient_ip(19);\ndomain(20);\npath(21);\nversion(22);\ncluster(23);\nnode(24);\nhostname(25);\nnonce(26);\nquery(27);\n"+        }+      ],+      "validations": {+        "": {+          "world": {+            "facts": [+              {+                "origin": [+                  0+                ],+                "facts": [+                  "admin(13)",+                  "client(18)",+                  "client_ip(19)",+                  "cluster(23)",+                  "domain(20)",+                  "email(14)",+                  "group(15)",+                  "hostname(25)",+                  "ip_address(17)",+                  "member(16)",+                  "namespace(9)",+                  "node(24)",+                  "nonce(26)",+                  "operation(3)",+                  "owner(7)",+                  "path(21)",+                  "query(27)",+                  "read(0)",+                  "resource(2)",+                  "right(4)",+                  "role(6)",+                  "service(12)",+                  "team(11)",+                  "tenant(8)",+                  "time(5)",+                  "user(10)",+                  "version(22)",+                  "write(1)"+                ]+              }+            ],+            "rules": [],+            "checks": [+              {+                "origin": 18446744073709551615,+                "checks": [+                  "check if read(0), write(1), resource(2), operation(3), right(4), time(5), role(6), owner(7), tenant(8), namespace(9), user(10), team(11), service(12), admin(13), email(14), group(15), member(16), ip_address(17), client(18), client_ip(19), domain(20), path(21), version(22), cluster(23), node(24), hostname(25), nonce(26), query(27)"+                ]+              }+            ],+            "policies": [+              "allow if true"+            ]+          },+          "result": {+            "Ok": 0+          },+          "authorizer_code": "check if read(0), write(1), resource(2), operation(3), right(4), time(5), role(6), owner(7), tenant(8), namespace(9), user(10), team(11), service(12), admin(13), email(14), group(15), member(16), ip_address(17), client(18), client_ip(19), domain(20), path(21), version(22), cluster(23), node(24), hostname(25), nonce(26), query(27);\n\nallow if true;\n",+          "revocation_ids": [+            "75ce48d496fd28f99905901783a1ba46d7ff8d69f9d364d1546fd73006026eae51849ad1190a4ae521a0a1269f9c6951e226afba8fcd24fa50f679162439ae09"+          ]+        }+      }+    },+    {+      "title": "execution scope",+      "filename": "test023_execution_scope.bc",+      "token": [+        {+          "symbols": [+            "authority_fact"+          ],+          "public_keys": [],+          "external_key": null,+          "code": "authority_fact(1);\n"+        },+        {+          "symbols": [+            "block1_fact"+          ],+          "public_keys": [],+          "external_key": null,+          "code": "block1_fact(1);\n"+        },+        {+          "symbols": [+            "var"+          ],+          "public_keys": [],+          "external_key": null,+          "code": "check if authority_fact($var);\ncheck if block1_fact($var);\n"+        }+      ],+      "validations": {+        "": {+          "world": {+            "facts": [+              {+                "origin": [+                  0+                ],+                "facts": [+                  "authority_fact(1)"+                ]+              },+              {+                "origin": [+                  1+                ],+                "facts": [+                  "block1_fact(1)"+                ]+              }+            ],+            "rules": [],+            "checks": [+              {+                "origin": 2,+                "checks": [+                  "check if authority_fact($var)",+                  "check if block1_fact($var)"+                ]+              }+            ],+            "policies": [+              "allow if true"+            ]+          },+          "result": {+            "Err": {+              "FailedLogic": {+                "Unauthorized": {+                  "policy": {+                    "Allow": 0+                  },+                  "checks": [+                    {+                      "Block": {+                        "block_id": 2,+                        "check_id": 1,+                        "rule": "check if block1_fact($var)"+                      }+                    }+                  ]+                }+              }+            }+          },+          "authorizer_code": "allow if true;\n",+          "revocation_ids": [+            "f9b49866caef5ece7be14ec5a9b36d98ca81d06b306eb0b4c57cd7436af176f40ee972f40903f87ec4460ab8b1adfcbfa9b19b20a6955a1e8dae7d88b2076005",+            "889054b9119e4440e54da1b63266a98d0f6646cde195fef206efd8b133cfb2ee7be49b32a9a5925ece452e64f9e6f6d80dab422e916c599675dd68cdea053802",+            "0a85ffbf27e08aa23665ba0d96a985b274d747556c9f016fd7f590c641ed0e4133291521aa442b320ee9ce80f5ad701b914a0c87b3dfa0cc92629dce94201806"+          ]+        }+      }+    },+    {+      "title": "third party",+      "filename": "test024_third_party.bc",+      "token": [+        {+          "symbols": [],+          "public_keys": [+            "ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189"+          ],+          "external_key": null,+          "code": "right(\"read\");\ncheck if group(\"admin\") trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189;\n"+        },+        {+          "symbols": [],+          "public_keys": [],+          "external_key": "ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189",+          "code": "group(\"admin\");\ncheck if right(\"read\");\n"+        }+      ],+      "validations": {+        "": {+          "world": {+            "facts": [+              {+                "origin": [+                  0+                ],+                "facts": [+                  "right(\"read\")"+                ]+              },+              {+                "origin": [+                  1+                ],+                "facts": [+                  "group(\"admin\")"+                ]+              }+            ],+            "rules": [],+            "checks": [+              {+                "origin": 0,+                "checks": [+                  "check if group(\"admin\") trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189"+                ]+              },+              {+                "origin": 1,+                "checks": [+                  "check if right(\"read\")"+                ]+              }+            ],+            "policies": [+              "allow if true"+            ]+          },+          "result": {+            "Ok": 0+          },+          "authorizer_code": "allow if true;\n",+          "revocation_ids": [+            "470e4bf7aa2a01ab39c98150bd06aa15b4aa5d86509044a8809a8634cd8cf2b42269a51a774b65d10bac9369d013070b00187925196a8e680108473f11cf8f03",+            "342167bc54bc642b6718a276875e55b6d39e9b21e4ce13b926a3d398b6c057fc436385bf4c817a16f9ecdf0b0d950e8b8258a20aeb3fd8896c5e9c1f0a53da03"+          ]+        }+      }+    },+    {+      "title": "block rules",+      "filename": "test025_check_all.bc",+      "token": [+        {+          "symbols": [+            "allowed_operations",+            "A",+            "B",+            "op",+            "allowed"+          ],+          "public_keys": [],+          "external_key": null,+          "code": "allowed_operations([\"A\", \"B\"]);\ncheck all operation($op), allowed_operations($allowed), $allowed.contains($op);\n"+        }+      ],+      "validations": {+        "A, B": {+          "world": {+            "facts": [+              {+                "origin": [+                  null+                ],+                "facts": [+                  "operation(\"A\")",+                  "operation(\"B\")"+                ]+              },+              {+                "origin": [+                  0+                ],+                "facts": [+                  "allowed_operations([\"A\", \"B\"])"+                ]+              }+            ],+            "rules": [],+            "checks": [+              {+                "origin": 0,+                "checks": [+                  "check all operation($op), allowed_operations($allowed), $allowed.contains($op)"+                ]+              }+            ],+            "policies": [+              "allow if true"+            ]+          },+          "result": {+            "Ok": 0+          },+          "authorizer_code": "operation(\"A\");\noperation(\"B\");\n\nallow if true;\n",+          "revocation_ids": [+            "c456817012e1d523c6d145b6d6a3475d9f7dd4383c535454ff3f745ecf4234984ce09b9dec0551f3d783abe850f826ce43b12f1fd91999a4753a56ecf4c56d0d"+          ]+        },+        "A, invalid": {+          "world": {+            "facts": [+              {+                "origin": [+                  null+                ],+                "facts": [+                  "operation(\"A\")",+                  "operation(\"invalid\")"+                ]+              },+              {+                "origin": [+                  0+                ],+                "facts": [+                  "allowed_operations([\"A\", \"B\"])"+                ]+              }+            ],+            "rules": [],+            "checks": [+              {+                "origin": 0,+                "checks": [+                  "check all operation($op), allowed_operations($allowed), $allowed.contains($op)"+                ]+              }+            ],+            "policies": [+              "allow if true"+            ]+          },+          "result": {+            "Err": {+              "FailedLogic": {+                "Unauthorized": {+                  "policy": {+                    "Allow": 0+                  },+                  "checks": [+                    {+                      "Block": {+                        "block_id": 0,+                        "check_id": 0,+                        "rule": "check all operation($op), allowed_operations($allowed), $allowed.contains($op)"+                      }+                    }+                  ]+                }+              }+            }+          },+          "authorizer_code": "operation(\"A\");\noperation(\"invalid\");\n\nallow if true;\n",+          "revocation_ids": [+            "c456817012e1d523c6d145b6d6a3475d9f7dd4383c535454ff3f745ecf4234984ce09b9dec0551f3d783abe850f826ce43b12f1fd91999a4753a56ecf4c56d0d"+          ]+        }+      }+    },+    {+      "title": "public keys interning",+      "filename": "test026_public_keys_interning.bc",+      "token": [+        {+          "symbols": [],+          "public_keys": [+            "ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189"+          ],+          "external_key": null,+          "code": "query(0);\ncheck if true trusting previous, ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189;\n"+        },+        {+          "symbols": [],+          "public_keys": [+            "ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463",+            "ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189"+          ],+          "external_key": "ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189",+          "code": "query(1);\nquery(1, 2) <- query(1), query(2) trusting ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463;\ncheck if query(2), query(3) trusting ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463;\ncheck if query(1) trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189;\n"+        },+        {+          "symbols": [],+          "public_keys": [+            "ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463",+            "ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189"+          ],+          "external_key": "ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463",+          "code": "query(2);\ncheck if query(2), query(3) trusting ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463;\ncheck if query(1) trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189;\n"+        },+        {+          "symbols": [],+          "public_keys": [+            "ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463",+            "ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189"+          ],+          "external_key": "ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463",+          "code": "query(3);\ncheck if query(2), query(3) trusting ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463;\ncheck if query(1) trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189;\n"+        },+        {+          "symbols": [],+          "public_keys": [+            "ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463",+            "ed25519/f98da8c1cf907856431bfc3dc87531e0eaadba90f919edc232405b85877ef136"+          ],+          "external_key": null,+          "code": "query(4);\ncheck if query(2) trusting ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463;\ncheck if query(4) trusting ed25519/f98da8c1cf907856431bfc3dc87531e0eaadba90f919edc232405b85877ef136;\n"+        }+      ],+      "validations": {+        "": {+          "world": {+            "facts": [+              {+                "origin": [+                  0+                ],+                "facts": [+                  "query(0)"+                ]+              },+              {+                "origin": [+                  1+                ],+                "facts": [+                  "query(1)"+                ]+              },+              {+                "origin": [+                  1,+                  2+                ],+                "facts": [+                  "query(1, 2)"+                ]+              },+              {+                "origin": [+                  2+                ],+                "facts": [+                  "query(2)"+                ]+              },+              {+                "origin": [+                  3+                ],+                "facts": [+                  "query(3)"+                ]+              },+              {+                "origin": [+                  4+                ],+                "facts": [+                  "query(4)"+                ]+              }+            ],+            "rules": [+              {+                "origin": 1,+                "rules": [+                  "query(1, 2) <- query(1), query(2) trusting ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463"+                ]+              }+            ],+            "checks": [+              {+                "origin": 0,+                "checks": [+                  "check if true trusting previous, ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189"+                ]+              },+              {+                "origin": 1,+                "checks": [+                  "check if query(1) trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189",+                  "check if query(2), query(3) trusting ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463"+                ]+              },+              {+                "origin": 2,+                "checks": [+                  "check if query(1) trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189",+                  "check if query(2), query(3) trusting ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463"+                ]+              },+              {+                "origin": 3,+                "checks": [+                  "check if query(1) trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189",+                  "check if query(2), query(3) trusting ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463"+                ]+              },+              {+                "origin": 4,+                "checks": [+                  "check if query(2) trusting ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463",+                  "check if query(4) trusting ed25519/f98da8c1cf907856431bfc3dc87531e0eaadba90f919edc232405b85877ef136"+                ]+              },+              {+                "origin": 18446744073709551615,+                "checks": [+                  "check if query(1, 2) trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189, ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463"+                ]+              }+            ],+            "policies": [+              "deny if query(3)",+              "deny if query(1, 2)",+              "deny if query(0) trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189",+              "allow if true"+            ]+          },+          "result": {+            "Ok": 3+          },+          "authorizer_code": "check if query(1, 2) trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189, ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463;\n\ndeny if query(3);\ndeny if query(1, 2);\ndeny if query(0) trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189;\nallow if true;\n",+          "revocation_ids": [+            "3771cefe71beb21ead35a59c8116ee82627a5717c0295f35980662abccb159fe1b37848cb1818e548656bd4fd882d0094a2daab631c76b2b72e3a093914bfe04",+            "6528db2c9a561ada9086268549a600a8a52ff434ea8183812623eec0e9b6c5d3c41ab7868808623021d92294d583afdf92f4354bcdaa1bc50453e1b89afd630d",+            "5d5679fe69bfe74b7919323515e9ecba9d01422b16be9341b57f88e695b2bb0bd7966b781001d2b9e00ee618fdc239c96e17e32cb379f13f12d6bd7b1b47ad04",+            "c37bf24c063f0310eccab8864e48dbeffcdd7240b4f8d1e01eba4fc703e6c9082b845bb55543b10f008dc7f4e78540411912ac1f36fa2aa90011dca40f323b09",+            "3f675d6c364e06405d4868c904e40f3d81c32b083d91586db814d4cb4bf536b4ba209d82f11b4cb6da293b60b20d6122fc3e0e08e80c381dee83edd848211900"+          ]+        }+      }+    },+    {+      "title": "integer wraparound",+      "filename": "test027_integer_wraparound.bc",+      "token": [+        {+          "symbols": [],+          "public_keys": [],+          "external_key": null,+          "code": "check if true || 10000000000 * 10000000000 != 0;\ncheck if true || 9223372036854775807 + 1 != 0;\ncheck if true || -9223372036854775808 - 1 != 0;\n"+        }+      ],+      "validations": {+        "": {+          "world": {+            "facts": [],+            "rules": [],+            "checks": [+              {+                "origin": 0,+                "checks": [+                  "check if true || -9223372036854775808 - 1 != 0",+                  "check if true || 10000000000 * 10000000000 != 0",+                  "check if true || 9223372036854775807 + 1 != 0"+                ]+              }+            ],+            "policies": [+              "allow if true"+            ]+          },+          "result": {+            "Err": {+              "Execution": "Overflow"+            }+          },+          "authorizer_code": "allow if true;\n",+          "revocation_ids": [+            "3346a22aae0abfc1ffa526f02f7650e90af909e5e519989026441e78cdc245b7fd126503cfdc8831325fc04307edc65238db319724477915f7040a2f6a719a05"+          ]+        }+      }+    },+    {+      "title": "test expression syntax and all available operations (v4 blocks)",+      "filename": "test028_expressions_v4.bc",+      "token": [+        {+          "symbols": [+            "abcD12x",+            "abcD12"+          ],+          "public_keys": [],+          "external_key": null,+          "code": "check if 1 != 3;\ncheck if 1 | 2 ^ 3 == 0;\ncheck if \"abcD12x\" != \"abcD12\";\ncheck if 2022-12-04T09:46:41Z != 2020-12-04T09:46:41Z;\ncheck if hex:12abcd != hex:12ab;\ncheck if [1, 4] != [1, 2];\n"+        }+      ],+      "validations": {+        "": {+          "world": {+            "facts": [],+            "rules": [],+            "checks": [+              {+                "origin": 0,+                "checks": [+                  "check if \"abcD12x\" != \"abcD12\"",+                  "check if 1 != 3",+                  "check if 1 | 2 ^ 3 == 0",+                  "check if 2022-12-04T09:46:41Z != 2020-12-04T09:46:41Z",+                  "check if [1, 4] != [1, 2]",+                  "check if hex:12abcd != hex:12ab"+                ]+              }+            ],+            "policies": [+              "allow if true"+            ]+          },+          "result": {+            "Ok": 0+          },+          "authorizer_code": "allow if true;\n",+          "revocation_ids": [+            "117fa653744c859561555e6a6f5990e3a8e7817f91b87aa6991b6d64297158b4e884c92d10f49f74c96069df722aa676839b72751ca9d1fe83a7025b591de00b"           ]         }       }
test/samples/current/test001_basic.bc view

binary file changed (358 → 358 bytes)

test/samples/current/test002_different_root_key.bc view

binary file changed (321 → 321 bytes)

test/samples/current/test003_invalid_signature_format.bc view

binary file changed (309 → 309 bytes)

test/samples/current/test004_random_block.bc view

binary file changed (347 → 347 bytes)

test/samples/current/test005_invalid_signature.bc view

binary file changed (358 → 358 bytes)

test/samples/current/test006_reordered_blocks.bc view

binary file changed (485 → 485 bytes)

test/samples/current/test007_scoped_rules.bc view

binary file changed (535 → 535 bytes)

test/samples/current/test008_scoped_checks.bc view

binary file changed (454 → 454 bytes)

test/samples/current/test009_expired_token.bc view

binary file changed (338 → 321 bytes)

test/samples/current/test010_authorizer_scope.bc view

binary file changed (302 → 302 bytes)

test/samples/current/test011_authorizer_authority_caveats.bc view

binary file changed (169 → 169 bytes)

test/samples/current/test012_authority_caveats.bc view

binary file changed (171 → 171 bytes)

test/samples/current/test013_block_rules.bc view

binary file changed (490 → 490 bytes)

test/samples/current/test014_regex_constraint.bc view

binary file changed (205 → 205 bytes)

test/samples/current/test015_multi_queries_caveats.bc view

binary file changed (183 → 183 bytes)

test/samples/current/test016_caveat_head_name.bc view

binary file changed (298 → 298 bytes)

test/samples/current/test017_expressions.bc view

binary file changed (1609 → 1799 bytes)

test/samples/current/test018_unbound_variables_in_rule.bc view

binary file changed (323 → 323 bytes)

test/samples/current/test019_generating_ambient_from_variables.bc view

binary file changed (297 → 297 bytes)

test/samples/current/test020_sealed.bc view

binary file changed (390 → 390 bytes)

test/samples/current/test021_parsing.bc view

binary file changed (188 → 188 bytes)

test/samples/current/test022_default_symbols.bc view

binary file changed (428 → 428 bytes)

test/samples/current/test023_execution_scope.bc view

binary file changed (461 → 461 bytes)

test/samples/current/test024_third_party.bc view

binary file changed (458 → 458 bytes)

test/samples/current/test025_check_all.bc view

binary file changed (258 → 258 bytes)

test/samples/current/test026_public_keys_interning.bc view

binary file changed (1316 → 1547 bytes)

test/samples/current/test027_integer_wraparound.bc view

binary file changed (329 → 329 bytes)

+ test/samples/current/test028_expressions_v4.bc view

binary file changed (absent → 388 bytes)