@@ -15,10 +15,12 @@ support files from `packaging/`.
1515 systemd as credential ` wyrelog-system-policy-key `
1616- System policy store: ` /var/lib/wyrelog/system/policy.sqlite `
1717- System audit store: ` /var/log/wyrelog/system/audit.duckdb `
18+ - System Datalog fact root: ` /var/lib/wyrelog/system/facts `
1819- Service KeyProvider root: ` /etc/wyrelog/service/policy.key ` loaded by
1920 systemd as credential ` wyrelog-service-policy-key `
2021- Service policy store: ` /var/lib/wyrelog/service/policy.sqlite `
2122- Service audit store: ` /var/log/wyrelog/service/audit.duckdb `
23+ - Service Datalog fact root: ` /var/lib/wyrelog/service/facts `
2224- Runtime directory: ` /run/wyrelog `
2325- HTTP listen port: ` 127.0.0.1:8765 ` unless overridden by the service file
2426- Production log policy: compile release builds with
@@ -40,9 +42,11 @@ Packaged profile paths:
4042- System policy store: ` /var/lib/wyrelog/system/policy.sqlite `
4143- System KeyProvider root: ` /etc/wyrelog/system/policy.key `
4244- System audit store: ` /var/log/wyrelog/system/audit.duckdb `
45+ - System Datalog fact root: ` /var/lib/wyrelog/system/facts `
4346- Service policy store: ` /var/lib/wyrelog/service/policy.sqlite `
4447- Service KeyProvider root: ` /etc/wyrelog/service/policy.key `
4548- Service audit store: ` /var/log/wyrelog/service/audit.duckdb `
49+ - Service Datalog fact root: ` /var/lib/wyrelog/service/facts `
4650- Service event spool: ` /var/lib/wyrelog/service/event-spool `
4751
4852Inspect the resolved profile contract with:
8690 --policy-db /var/lib/wyrelog/system/policy.sqlite \
8791 --policy-keyprovider file:/etc/wyrelog/system/policy.key \
8892 --audit-db /var/log/wyrelog/system/audit.duckdb \
93+ --fact-root /var/lib/wyrelog/system/facts \
8994 --check
9095 wyrelogd --template-info --template-dir /usr/share/wyrelog/access
9196 wyctl key status --keyprovider /etc/wyrelog/system/policy.key
@@ -235,6 +240,113 @@ wyctl --daemon-url http://127.0.0.1:8765 audit query \
235240 --access-token-file /run/wyrelog/operator.token
236241```
237242
243+ ## Datalog Product Flow
244+
245+ Wyrelog is a Datalog storage and inference engine. The packaged access-control
246+ policy is the default policy template for the daemon, while Datalog facts live in
247+ separate per-tenant, per-graph stores. Keep these paths physically separate:
248+
249+ - Policy DB: encrypted SQLite authority store, for example
250+ ` /var/lib/wyrelog/system/policy.sqlite ` .
251+ - Audit DB: DuckDB audit sink, for example
252+ ` /var/log/wyrelog/system/audit.duckdb ` .
253+ - Fact DBs: DuckDB files below the fact root, for example
254+ ` /var/lib/wyrelog/system/facts/<tenant>/<graph>/facts.duckdb ` .
255+
256+ Back up and restore those stores as separate artifacts. Do not place the policy
257+ or audit DB under the fact root. The static packaged units rely on the daemon's
258+ profile defaults for the fact root so the same unit files remain valid for
259+ builds with and without fact-store support; pass ` --fact-root ` explicitly in
260+ manual checks or local deployments that enable Datalog fact storage.
261+
262+ The commands below show a complete local product flow on the default tenant.
263+ Replace ` alice ` and the paths for your deployment.
264+
265+ ``` sh
266+ BASE_URL=http://127.0.0.1:8765
267+ TOKEN=/run/wyrelog/operator.token
268+ TENANT=__wr_default
269+ GRAPH=orders
270+
271+ wyrelogd --production \
272+ --profile system \
273+ --template-dir /usr/share/wyrelog/access \
274+ --policy-db /var/lib/wyrelog/system/policy.sqlite \
275+ --policy-keyprovider file:/etc/wyrelog/system/policy.key \
276+ --audit-db /var/log/wyrelog/system/audit.duckdb \
277+ --fact-root /var/lib/wyrelog/system/facts \
278+ --bootstrap-admin-subject alice \
279+ --bootstrap-admin-allow-skip-mfa \
280+ --listen-port 8765
281+ ```
282+
283+ Mint the first token and arm the packaged administrator's Datalog authorities on
284+ the tenant scope. The bootstrap role already grants these permissions; the
285+ permission-state transition records that the operator intentionally armed them
286+ for this scope.
287+
288+ ``` sh
289+ python3 - << 'PY '
290+ import json, urllib.request
291+ url = "http://127.0.0.1:8765/auth/login?username=alice&tenant=__wr_default&skip_mfa=true"
292+ req = urllib.request.Request(url, method="POST")
293+ with urllib.request.urlopen(req) as response:
294+ token = json.load(response)["access_token"]
295+ open("/run/wyrelog/operator.token", "w", encoding="utf-8").write(token + "\n")
296+ PY
297+
298+ for perm in wr.graph.manage wr.schema.manage wr.fact.write wr.datalog.query; do
299+ curl -fsS -X POST \
300+ -H " Authorization: Bearer $( cat " $TOKEN " ) " \
301+ " $BASE_URL /policy/permissions/transition?subject=alice&perm=$perm &scope=$TENANT &event=grant&guard_timestamp=$( date +%s) &guard_loc_class=trusted&guard_risk=29"
302+ done
303+ ```
304+
305+ Run the graph, schema, fact, and query commands through ` wyctl ` :
306+
307+ ``` sh
308+ wyctl --daemon-url " $BASE_URL " graph create \
309+ --tenant " $TENANT " --graph " $GRAPH " \
310+ --access-token-file " $TOKEN " \
311+ --guard-timestamp $( date +%s) --guard-loc-class trusted --guard-risk 29
312+
313+ wyctl --daemon-url " $BASE_URL " fact schema register \
314+ --tenant " $TENANT " --graph " $GRAPH " \
315+ --namespace shop --relation orders --schema-version 1 \
316+ --columns order_id:symbol,amount:int64 \
317+ --access-token-file " $TOKEN " \
318+ --guard-timestamp $( date +%s) --guard-loc-class trusted --guard-risk 29
319+
320+ printf ' order_id,amount\no-1,42\n' > /tmp/orders.csv
321+ wyctl --daemon-url " $BASE_URL " fact put \
322+ --tenant " $TENANT " --graph " $GRAPH " \
323+ --namespace shop --relation orders --schema-version 1 \
324+ --batch-id orders-1 --idempotency-key orders-1 \
325+ --format csv --input /tmp/orders.csv \
326+ --access-token-file " $TOKEN " \
327+ --guard-timestamp $( date +%s) --guard-loc-class trusted --guard-risk 29
328+
329+ wyctl --daemon-url " $BASE_URL " datalog query \
330+ --tenant " $TENANT " --graph " $GRAPH " \
331+ --query ' orders(O,A)' --output json --limit 10 \
332+ --access-token-file " $TOKEN " \
333+ --guard-timestamp $( date +%s) --guard-loc-class trusted --guard-risk 29
334+ ```
335+
336+ To verify recovery, restart ` wyrelogd ` with the same policy DB, audit DB, key,
337+ and fact root. Mint a fresh token after restart and run the same
338+ ` wyctl datalog query ` ; the fact graph is replayed from the per-graph DuckDB fact
339+ store. Check graph health with:
340+
341+ ``` sh
342+ curl -fsS " $BASE_URL /facts/status"
343+ ```
344+
345+ A single corrupted graph should report a degraded graph entry while unrelated
346+ graphs remain queryable. Stop the daemon before repairing or replacing a damaged
347+ ` facts.duckdb ` , restore only the affected ` <tenant>/<graph> ` fact directory,
348+ restart, then confirm ` /facts/status ` returns ` "status":"ready" ` .
349+
238350## Day-2 Operations
239351
240352- Template validation from an operator shell. Use ` file: ` for manual checks;
0 commit comments