Wanderland

Wanderland Core

A Ruby gem that boots YAML config into a Rack or CLI service and signs every operation as it happens.

What it is

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.

Why it exists

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.

What's in the box

Status

Active development. Ships with HTTP (Rack) and CLI (Commander) adapters. Apache 2.0 licensed.

Site Audit

wanderland.dev

oculus-view: fence: Fence execute bit is disabled. Use force=true to override.

derive

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:

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.

derive gate

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.