Document access
Chapter 2 — Verified manifest loading
Package the policy, verify its source digest, and load it once.Continue from Chapter 1 — Vocabulary and policy. Keep the declarations, policy files and helpers from the earlier chapters.
Load the policy through a manifest
A manifest is a JSON file that packages policy files with their registered domain, expected SHA-256 digests and public queries. Unlike the quickstart's embedded source, this tutorial loads the file you just saved. The rules can be reviewed and packaged separately from the application.
The manifest is not a domain declaration. Its "domain": "doc_access" selects the vocabulary registered in the domain declaration; it does not create that vocabulary. Request facts are supplied later by the request helper.
- RegisterApplication vocabulary
- ManifestDomain, file, query
- Verify + loadSHA-256 and policy checks
- EvaluatePer-request facts
Prepare the two files
Keep policies/doc_access.dl from the policy section and add policies/manifest.json beside it. Run the examples from the directory containing policies/:
your-application/
└── policies/
├── doc_access.dl
└── manifest.jsonThe loader reads the .dl file directly; neither program embeds a copy of its rules. The digest below corresponds to the exact policy source encoded as UTF-8, with LF line endings and one final newline.
Compute the digest of the file you actually saved:
# macOS
shasum -a 256 policies/doc_access.dl
# Linux
sha256sum policies/doc_access.dlCopy the 64 hexadecimal characters into sha256. A different comment, blank line or line ending changes the digest. Here is the complete policies/manifest.json for the source shown above:
{
"policy_set_id": "documents",
"policy_set_version": "1",
"manifest_version": "1",
"default_profile": "enforce",
"created_for": "document-access-tutorial",
"strict_loading": true,
"fail_closed": true,
"capabilities": [],
"policies": [
{
"policy_id": "doc_access.main",
"domain": "doc_access",
"file": "doc_access.dl",
"sha256": "64deaed81401b21788260e73452fe424a963dababe7e142aac7d5d73bbd1bd12",
"mode": "enforce",
"enabled": true,
"description": "Ownership, sharing and sensitivity",
"queries": [
{
"name": "allow",
"arity": 2
}
]
}
]
}| Field | Meaning in this example |
|---|---|
manifest_version | The manifest format version, not the engine or C API version. |
policy_set_version | Your application’s version label for this policy package. |
domain | The already registered doc_access vocabulary. |
file | Resolved relative to the manifest directory: doc_access.dl means policies/doc_access.dl. |
sha256 | Digest of the exact source bytes, checked by the native loader. |
queries | The public query list: allow/2 is declared queryable in the domain and exposed by this policy. |
Load once, before requests
Add this helper after the domain declarations. The startup code in the complete program calls it only after registering the domain. Loading verifies the package; it does not yet evaluate a request.
static maelys_datalog_status_t load_policy(
maelys_datalog_session_t **session,
maelys_datalog_diagnostic_t *diagnostic)
{
maelys_datalog_policy_t *policy = NULL;
maelys_datalog_status_t rc = maelys_datalog_policy_load_manifest(
"policies/manifest.json", MAELYS_DATALOG_PUBLIC_ALLOW_NONE, &policy, diagnostic);
if (rc != MAELYS_DATALOG_STATUS_OK) return rc;
/* This manifest contains one enabled policy, at index 0. */
rc = maelys_datalog_session_create(policy, 0u, session);
(void)maelys_datalog_policy_free(policy);
return rc;
}Why pass MAELYS_DATALOG_PUBLIC_ALLOW_NONE to the C loader? It grants no optional loading permission. Its permanent value is 0u, but the name makes the intent distinct from the later numeric policy index passed to maelys_datalog_session_create().
- Source vocabulary is checked. Our file contains
"mallory", so domain declaration declares that constant in the domain'satoms. Removing it makes loading fail withunknown atom. This does not restrict request values such as"alice". - Test-only entries are rejected. An enabled manifest entry marked
"mode": "test_only"makes loading fail unless the caller explicitly permits test policies. Our manifest uses"mode": "enforce". - Python makes the same choice by default.
engine.load_manifest(path)leaves bothallow_test_onlyandallow_undeclared_policy_atomsfalse.
These are two independent permissions, not a single strict/permissive switch. The public loading-permissions reference explains each opt-in, their combination, and rejection of unknown bits. No opt-in is needed for this tutorial.
The 0u in the subsequent session_create() call is a policy index, not a loading option. This manifest has one enabled policy, so its index is 0.
What you have learned
Keep this model
Load the policy as a verified package- The manifest describes what to load
Its entry names the domain, policy file, expected SHA-256 and public queries. The rules remain in doc_access.dl rather than application source.
- The digest checks the exact file
Changing the policy bytes without updating the trusted manifest makes loading fail. A digest is useful only when the manifest itself is trusted.
- Prepare a session for the selected policy
After registering the domain and loading the package, select policy index 0 to prepare a reusable session. Loading has not yet supplied request facts or made an access decision.