Start
Document access tutorial
Build a complete document access policy from facts, rules, negation, and explicit queries.This tutorial moves beyond the quickstart by loading a policy file through a verified manifest. You will keep the rules separate from the application, check their SHA-256 before loading, and evaluate document-access requests in C or Python. The policy combines ownership, sharing, a sensitivity threshold and explicit blocks.
If you have not read Getting Started yet, start there. This tutorial assumes the library is compiled and linked.
Choose C or Python once: the code tabs stay synchronized throughout this tutorial. The Datalog policy, diagrams and expected decisions are shared. Both versions use the current opaque consumer API; the Python import is maelys_datalog, as in the quickstart. Use the Maelys Datalog 0.11.1 setup from the quickstart. In C, include <maelys/datalog.h> for the opaque API and <maelys/datalog_builders.h> for its convenience macros.
Follow the four chapters
What we are building
A document access system where:
- Users can access documents they own.
- Users can access documents shared with them.
- Users need a sensitivity level of 3 or higher for either path.
- Certain users are explicitly blocked regardless of ownership or sharing.
The final policy will look like this:
blocked("mallory").
allow(User, Doc) :-
owns(User, Doc),
not(blocked(User)),
sensitivity_level(User, Level),
Level >= 3.
allow(User, Doc) :-
shared_with(User, Doc),
not(blocked(User)),
sensitivity_level(User, Level),
Level >= 3.
What you will learn
From source files to decisions
Package, select and evaluate policies- Declare before loading
The domain registers predicate names, arities and origins. Its atoms list permits constants written in the policy, such as "mallory"; declaring that string does not block anyone.
- Keep rules in files
The application loads doc_access.dl through a manifest, instead of embedding its source. Each entry identifies a domain, a source file, its SHA-256 and the queries exposed to the caller.
- Separate policy facts from request facts
blocked("mallory") is fixed in these policy files. Ownership, sharing and sensitivity arrive in a fresh input EDB for each request. The same rules can evaluate Alice, Bob or Carol.
- Understand why access is granted or denied
The normal policy needs ownership or sharing, sensitivity at least 3, and no policy block. Bob fails the threshold; Mallory is blocked; Carol qualifies through sharing.
- One set, two independent sessions
A two-entry manifest loads two programs. Sessions at indices 0 and 1 keep different rules: the same shared-document request for Carol is allowed by the first and denied by the owners-only policy.
- Verify the package, then check the decision
A changed file with the old digest stops loading. After successful loading, solving and querying, authorize only if allow is present. A missing allow fact is a denial; an API error is a failure to log and deny. A digest still requires a trusted manifest.
Decision ruleLoad a trusted policy package once, prepare the session for the intended policy, supply the complete request facts, then solve and query. Preparing two sessions never merges their rules or their answers.
Where to go next
- Registries — more on predicate kinds and domain registration.
- Rulesets — full policy language reference.
- Manifest loading — production-grade loading with SHA verification, multiple policies, and a public query whitelist.
- WASM bindings — run the same policy in a browser.