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
| Library | Header | Responsibility |
|---|---|---|
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 |
cc -std=c11 -I/usr/local/include app.c \
/usr/local/lib/libmaelys-sandbox-policy.a \
/usr/local/lib/libmaelys-mir.a \
-o appCompile JSON entirely in memory
Use this when a trusted application already has a JSON manifest:
#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
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
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
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
#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,*_restrictand policycompileare caller-owned; - release them with the matching
*_destroyexactly 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.