Use the tools

C API

Compile, build, verify and resolve portable sandbox decisions directly in a native host.

The native API supports two integration levels. Use libmaelys-mir to produce or consume portable decisions. Add libmaelys-sandbox-policy when the host must resolve symbolic roots and prove that a selected execution backend advertises every required guarantee.

Libraries and headers

LibraryHeaderResponsibility
libmaelys-mir.a<maelys/mir.h>build, compile JSON, encode, decode, inspect and hash MIR
libmaelys-sandbox-policy.a<maelys/sandbox_policy.h>resolve host paths and compile an immutable SandboxPlan
CODE
cc -std=c11 -I/usr/local/include app.c \
  /usr/local/lib/libmaelys-sandbox-policy.a \
  /usr/local/lib/libmaelys-mir.a \
  -o app

Compile JSON entirely in memory

Use this when a trusted application already has a JSON manifest:

CODE
#include <maelys/mir.h>

maelys_mir_t *mir = NULL;
char *error = NULL;

maelys_mir_result_t result = maelys_mir_compile_json(
    (const uint8_t *)json,
    json_size,
    &mir,
    &error);

if (result != MAELYS_MIR_OK) {
  fprintf(stderr, "%s: %s\n", maelys_mir_result_name(result), error);
  maelys_mir_error_free(error);
  return 1;
}

No temporary file or CLI subprocess is involved. The returned MIR is already normalized and immutable.

Build a decision without JSON

CODE
maelys_mir_builder_t *builder = NULL;
maelys_mir_t *mir = NULL;
char *error = NULL;

if (maelys_mir_builder_create(&builder, &error) != MAELYS_MIR_OK)
  goto failure;

if (maelys_mir_builder_add_fs_rule(
        builder,
        MAELYS_MIR_FS_READ,
        MAELYS_MIR_ROOT_WORKSPACE,
        "",
        MAELYS_MIR_SCOPE_TREE,
        MAELYS_MIR_MISSING_ERROR,
        &error) != MAELYS_MIR_OK)
  goto failure;

if (maelys_mir_builder_set_network(
        builder, MAELYS_MIR_NETWORK_NONE, &error) != MAELYS_MIR_OK)
  goto failure;

if (maelys_mir_builder_set_process_tree_required(
        builder, 1, &error) != MAELYS_MIR_OK)
  goto failure;

if (maelys_mir_builder_build(builder, &mir, &error) != MAELYS_MIR_OK)
  goto failure;

maelys_mir_builder_destroy(builder);
builder = NULL;

Builders copy input strings, normalize paths, deduplicate destinations and apply deterministic conflict precedence. Destroying the builder after build does not affect the MIR.

Encode, decode and identify MIR

CODE
uint8_t *bytes = NULL;
size_t bytes_size = 0;
char digest[MAELYS_MIR_DIGEST_HEX_SIZE];

if (maelys_mir_encode(mir, &bytes, &bytes_size, &error) != MAELYS_MIR_OK)
  goto failure;

if (maelys_mir_digest_hex(mir, digest, &error) != MAELYS_MIR_OK)
  goto failure;

printf("decision sha256:%s\n", digest);
maelys_mir_bytes_free(bytes);

For untrusted binary input, call maelys_mir_decode. It accepts only canonical MIR. Use maelys_mir_check_canonical when you need validation without retaining a decoded object.

maelys_mir_inspect_json returns an owned human-readable projection. maelys_mir_artifact_digest_hex hashes arbitrary bytes and must not be confused with the decision digest.

Restrict an existing decision

CODE
maelys_mir_t *effective = NULL;
maelys_mir_result_t result =
    maelys_mir_restrict(base, restriction, &effective, &error);

A restriction may add filesystem denies, narrow network access or require process-tree confinement. It cannot add a filesystem grant. Network order is none < mediated < direct; two mediated allowlists are intersected.

Resolve symbolic roots into a SandboxPlan

CODE
#include <maelys/sandbox_policy.h>

maelys_sandbox_policy_host_t *host = NULL;
maelys_sandbox_policy_plan_t *plan = NULL;

maelys_sandbox_policy_host_create(&host, &error);
maelys_sandbox_policy_host_set_workspace(host, "/srv/build/project", &error);
maelys_sandbox_policy_host_set_temp(host, "/srv/build/tmp", &error);
maelys_sandbox_policy_host_add_minimal_runtime_root(host, "/usr", &error);
maelys_sandbox_policy_host_add_minimal_runtime_root(host, "/lib", &error);

maelys_sandbox_policy_capabilities_t available =
    MAELYS_SANDBOX_POLICY_CAP_FS_READ |
    MAELYS_SANDBOX_POLICY_CAP_FS_WRITE |
    MAELYS_SANDBOX_POLICY_CAP_FS_DENY |
    MAELYS_SANDBOX_POLICY_CAP_NETWORK_NONE |
    MAELYS_SANDBOX_POLICY_CAP_PROCESS_TREE;

if (maelys_sandbox_policy_compile(
        mir, host, available, &plan, &error) != MAELYS_MIR_OK)
  goto failure;

For mediated networking, the trusted host must also call maelys_sandbox_policy_host_set_network_mediator. The mediator identifier is opaque host configuration; it is not selected by the manifest.

Inspect the immutable plan

The plan API exposes:

  • resolved filesystem rule count and borrowed rule views;
  • network mode, mediator identifier and destination views;
  • process-tree requirement;
  • original MIR decision digest.

The backend adapter must consume these values without weakening them. Sandbox Policy does not spawn a process.

Ownership and threads

  • objects returned by *_create, *_build, *_decode, *_compile_json, *_restrict and policy compile are caller-owned;
  • release them with the matching *_destroy exactly once;
  • release encoded or inspection bytes with maelys_mir_bytes_free;
  • release diagnostics with maelys_mir_error_free;
  • strings returned inside view structures are borrowed from their owner;
  • builders and host contexts are mutable and not concurrently accessible;
  • sealed MIR and SandboxPlan objects are immutable and support independent concurrent reads.

Every output pointer is cleared before work begins. Failure returns no partial object.