Examples

Policy gate for Git

Build a fail-closed policy gate in front of the Git command line.

maelys-git is a C wrapper around the git binary. Before any git command runs, it evaluates a Datalog policy to decide whether the operation is allowed. This wrapper runs before git is exec'd, so git hooks and --no-verify are irrelevant to denied operations: a denied operation never reaches git at all.

This tutorial builds the wrapper in five levels of increasing rigour, with one page per level. Start at Level 1, then extend the same wrapper through the remaining levels.

The programming examples have synchronized C / Python tabs. Both languages use the current opaque consumer API: C includes <maelys/datalog.h> and <maelys/datalog_builders.h>; Python imports maelys_datalog. Follow the quickstart setup for Maelys Datalog 0.11.1. The Datalog rules are shared. These are assembly fragments: Git argument normalization and repository discovery are application code, not services provided by the binding. Neither version is a complete security boundary against a user who can bypass the wrapper.

Follow the five levels

Why not git hooks

CODE
git hook (.git/hooks/)             maelys-git
──────────────────────────────────────────────────────────────
Shell scripts, not versioned       Datalog in .maelys/git/policy.dl
Bypassable via --no-verify         Enforced before git runs
One hook per event                 One policy for all operations
No audit trail                     Audit record per decision
Hard to test                       Testable with input facts
Silent conflicts                   Explicit deny rules + stratified negation

The full picture

CODE
Level 1  argv/env → EDB → solve → allow/deny → execv(real_git, argv)
Level 2  deny codes stable, human messages in C lookup table
Level 3  rich EDB: files, classes, tree state; C extracts, policy decides
Level 4  .maelys/git/manifest.json + policy.dl versioned in repo + SHA verify
Level 5  audit record per decision: deny code, policy hash, witness summary

This is the exact pattern Maelys uses for agent orchestration:

CODE
observe context → project into facts → apply deterministic policy
→ produce decision → emit an audit record → execute only if allowed

What you will learn

Learning objectives

The wrapper turns operating-system context into a policy decision
  • Normalize before reasoning

    The C wrapper converts commands, refspecs, paths, identities, and repository state into a small declared vocabulary. Policy evaluates canonical facts, never ambiguous command-line strings.

  • Keep policy outputs stable

    Rules derive machine-stable decision codes; human messages live outside policy and may evolve independently. The same separation keeps audits durable.

  • Context extraction is a security boundary

    Every required fact must be established and every insertion result checked. A silently missing operation, identity, flag, or commit message could otherwise turn a denial into an authorization.

  • Authorization stays explicit and fail-closed

    Unknown subcommands, incomplete push syntax, unnormalizable refspecs, missing facts, and solver errors all deny. The wrapper executes only after the expected allow fact exists.

  • Decision, execution, and audit remain separate

    The solver decides once; the wrapper records policy identity, decision code, and witness summary; then execv starts an absolute trusted Git binary only for an allowed request.

Decision ruleObserve operating-system context, normalize it into declared facts, solve once, query an explicit decision, record the evidence, and execute only on ALLOW.

Where to go next

  • maelys-pty — the same pattern applied to an interactive shell with forkpty and seccomp/execve tracing.
  • Document access — ABAC for document ownership, sharing, and sensitivity levels.
  • Manifest loading in C and Python — verified packages and loading permissions.
  • Rulesets — full policy language reference.