A Ruby gem that boots YAML config into a Rack or CLI service and signs every operation as it happens.
A request comes in. The engine walks a chain of boundaries — small pieces of code with declared inputs and outputs. Each boundary produces a crossing: a record of what it did, signed by its identity, linked to the previous crossing by hash. The chain is a Merkle structure; tampering with any record breaks every signature that follows.
The same YAML configures the HTTP server and the command-line tool. Rack is the reference HTTP adapter; Commander is the reference CLI. The engine doesn't care which adapter brought the request in — it runs the chain and records the result.
Logging, tracing, audit trails, and scope-based authorization are work that services usually write on their own, partially, and at the edges. Wanderland builds them into the substrate. Every crossing is signed. Every context is append-only. Every request has a cryptographic provenance chain as a natural side effect of running it.
Sites opt into durable audit by declaring an :audits: mount and an injection. The result: one signed record per request, containing every crossing that occurred during execution, each still signed by its producer. Auditors pick any crossing out of the bundle, reconstruct its canonical payload, and verify against the producer's public key.
:pki:keys:{id})Active development. Ships with HTTP (Rack) and CLI (Commander) adapters. Apache 2.0 licensed.
wanderland.dev
Wanderland::Derive shapes values over ShapeMatcher. It is pure: a record goes in, an augmented record comes out. A clock (now:) and lookups (bindings:) are injected, so it runs without IO — loading lives behind adapters, and Derive transforms what they return.
A value expression is one of three things, and it may appear in any value position, which is the whole recursion:
42, "high", true"fields.status.name", dot-dig into the record; "$me.accountId"` / `"$now" / "$today" read bindings{ op:, from:|on:, args:, cases:, then:, default: }Input positions (from, on) read a bare string as a path; output positions (then, default) read a bare string as a literal. An op-node computes in any position.
Derive.run(record, spec, bindings:, now:) applies an ordered spec — [{ as:, op:, … }] — each entry storing its result under as; later entries read earlier ones. Ops register like matchers, Derive.register(:name) { |value, args, ctx| … }, with builtins pluck, default, age_days, days_until, present, blank, eq, ne, matches, capture, in, gt/gte/lt/lte, map, lower, upper, size, join, coalesce, after, before, max, min, select, and the general case. case gates each branch with ShapeMatcher: given an input (from:, or on:) each branch's when is a predicate on that value; with neither, when is a whole-record shape (multi-field conditions). First match's then wins, else default.
Ops over lists and times:
| Op | Args | Result |
|---|---|---|
after / before |
than: — an input expression (a path or a literal time) |
true when the value is strictly later / earlier than than; false when either side is absent |
max / min |
path: — optional, digs each element first |
the largest / smallest element; times compare as times, numbers as numbers; nil on an empty list |
select |
shape: — a ShapeMatcher shape |
the elements that match the shape; no shape keeps all |
Derive.partition(records, categories) is the same first-wins ShapeMatcher pass for bucketing, with optional group_by; a nil or empty match is the catch-all.
The derive_config boundary loads a record (inline data or a YAML file), runs a derive spec, and returns { config: … }, seeding the context so downstream slots gate on derived flags with when: { config: { flag: value } }.
Source: lib/wanderland/derive.rb, lib/wanderland/boundaries/derive_config.rb, spec/wanderland/derive_spec.rb.
Full reference — ops, value expressions, match shapes, registration: Wanderland Derive.
The derive_gate boundary is a gate written as data. It runs a derive spec over a record and matches the result against a pass shape. On a match it returns ok. On a miss it halts the run (on_fail: halt, the default) or returns ok with passed: false (on_fail: warn). A new check is a new YAML block, not a new boundary.
The gate does no IO. An earlier slot gathers the data — kubectl_get (wanderland-k8s-pack), ecr_verify_image (wanderland-aws-pack), any boundary whose result lands on the context — and the gate reads it through input:, usually as !Context plucks.
| Arg | Meaning |
|---|---|
name |
Gate label. It is on the result and in the halt error. |
input |
The record the spec reads. A mapping. Default {}. |
derive |
A Derive spec. A !Reference or !Fixture to a named block works. |
pass |
A ShapeMatcher shape over the derived record. An absent shape passes. |
on_fail |
halt (default) or warn. |
status |
Halt status. Default 412. |
bindings |
Static values for $ tokens in the spec. |
The result is { gate, passed, record, failures }. The halt carries the same keys and an error, so a report slot gated when: { always: true } reads for_boundary.derive_gate.record on a red run.
A bare true leaf in a ShapeMatcher shape is the presence wildcard: it matches any non-nil value, false included. Test a derived boolean with { eq: true } or { eq: false }.
# Halt when the pod that reads a ConfigMap through envFrom started before the
# ConfigMap last changed: the pod runs the old values.
- boundary: derive_gate
args:
name: coordinator-fresh
input:
configmap: !Context for_boundary.image_tags.object # kubectl_get, show_managed_fields: true
pods: !Context for_boundary.coordinator_pods.items # kubectl_get, selector
derive:
- as: configmap_changed_at
from: configmap.metadata.managedFields
op: max
args:
path: time
- as: live_pods
from: pods
op: select
args:
shape:
metadata:
not:
has_key: deletionTimestamp
- as: pod_started_at
from: live_pods
op: min
args:
path: status.startTime
- as: pod_stale
from: pod_started_at
op: before
args:
than: configmap_changed_at
pass:
pod_stale:
eq: false
A worked example that runs end to end on a local cluster is image-promotion/ in vivarta-examples.
Source: lib/wanderland/boundaries/derive_gate.rb, spec/wanderland/derive_gate_spec.rb.