edda
The nordisk shared-lib samling — the collected corpus (Norse Edda) of reusable, NON-facett library crates extracted from nornir so they release on their own cadence and are shared by nornir, korp, holger, skade, znippy, …
edda is a library repo, not an app. facett stays its own repo (it is the egui component framework); edda is everything else that is a library. Each crate is a lean leaf with a tiny dep set, so a consumer pulls only what it needs and no crate drags nornir's warehouse / embedder / server tree behind it.
The crates
| crate | what it is |
| autonom | the completeness / anti-drift subsystem — the constellation home for coverage (wiring-surface gate + test-matrix), and the runnable autonom coverage <repo> feeder that emits the code-that-lacks-tests worklist |
| jera | the shared infra runtime: durable job ledger (redb), a no-shell container runtime (bollard REST, delegated to draupnir's OCI backend), and KVM boot via draupnir. No Command shell-out on the tracked path |
| nornir-testmatrix | the portable core of the multi-aspect test matrix — runner (nextest/cargo), the pure discover/coverage engines, the UI-plane model. Tiny dep set so any leaf repo can run the same matrix |
| nornir-robotui | a reusable robot-UI testing framework for egui apps: drive real interactions (egui_kittest/AccessKit), observe via state_json, replay recorded scenarios, optional wgpu PNG snapshots |
| nornir-saga | capture a user's navigation as toolkit-neutral events → warehouse → replay the path as a generated robot test. The production sibling of nornir-testmatrix. saga_to_ui(events) is the event-model → UI-movement bridge (the inverse of to_saga_events) that folds a stored SagaEvent stream back into a replayable Saga |
| nornir-bench | the project-agnostic bench harness: a uniform run/result envelope + append-only JSONL history; repo metrics live in a free-form JSON object |
| nornir-coverage | source-based line/region coverage (cargo-llvm-cov), the JaCoCo-style report that answers "what fraction of source lines did the run execute?" |
| nornir-git | pure-Rust git helpers over gix (gitoxide) — inspection + history rewriting with no git shell-out and no libgit2/C |
| nornir-cli-outcome | the uniform CLI command result {command, ok, data, human} — the CLI twin of a Facet's state_json |
| guest-host | the reusable mechanics of hosting an untrusted wasm32 guest — fuel + wall-clock + memory/table ceilings that refuse by name (a configured 0 is a misconfiguration, never "unlimited"), a detached-CMS signature gate over the module's blake3 digest (fail-closed without the verifier), a census by digest, and the alloc/result_len/plugin_call calling convention. No product vocabulary: holger's plugin host and monetize's product host put their own ABI on top. wasmtime and verify-modules are features |
| nornir-hash | the shared content-hash primitive — lowercase-hex SHA-256 of bytes/files/streams (sha256_hex, sha256_file, Sha256Hasher) + a dependency-free hex_encode/hex_decode round-trip. sha2-only; consumed by every content-addressed store instead of re-rolling Sha256::new();hex(...) |
| nornir-xtask-support | the std-only xtask primitives toolbox (publish=false) four repos' cargo xtask crates hand-rolled identically: which/run/copy_dir/target_dir ($CARGO_TARGET_DIR-aware)/short_rev + the wasm bootstrap trio (ensure_wasm_target/ensure_wasm_bindgen/locked_wasm_bindgen_version, the blank-canvas-mismatch fix). Boxed Send+Sync error so every caller style adapts |
| nornir-pages | the parameterized gh-pages demo/deploy flow (publish=false) — demo_wasm (release wasm → wasm-bindgen → cache-busted static site into dist/) + deploy_pages (orphan-worktree force-push to the pages branch). All per-repo divergence is PagesConfig's 11 knobs; builds on nornir-xtask-support |
| nornir-humanize | the shared human-readable formatter (publish=false, std-only, zero runtime deps) eight+ human_bytes/human_count/fmt_elapsed twins across nornir + facett drifted on: byte sizes (bytes→1.5 KiB IEC, bytes_si→1.5 KB), compact counts (count→3.4M), grouped digits (thousands→1,234,567), durations (duration/duration_ms/duration_secs→2m 03s), binary throughput (throughput→3.5 MiB/s) and ratios (percent/percent_of→12.3%). Canon = IEC-binary majority; SI dissenters documented |
| nornir-escape | the shared markup-escaping primitive (publish=false, std-only, zero runtime deps) — xml(&str) -> Cow<str> escapes the four XML/SVG entities (&→&, <→<, >→>, "→"), borrowing with no allocation when the input is clean. Seven byte-identical xml_escape/svg_escape copies across nornir/edda/Skidbladnir collapse into it; every repoint is byte-safe (apostrophe deliberately left unescaped, as every twin does). xml_attr(&str) is the five-entity sibling that ALSO escapes '→' — for a single-quoted attribute value, where a bare apostrophe is not legal; byte-identical to xml on apostrophe-free input. Domain-coupled typst/markdown/slug escapers stay in their conductor |
| nornir-appshell | the two PURE, egui-free app-shell MODELS (publish=false, serde + serde_json only) every suite app's About + Tools menu hand-rolled: the Identity card (name/display_name/version/tagline/subtitle/logo_png: Option<Vec<u8>> LFS-tolerant/logo_alt/repository/links/framework/engines) + state_json(open) oracle, and the generic ToolMenu/ToolEntry (title/hover/effect_key/view_target/needs_container + keys/find/state_json(last_picked)). Lifts modgunn's struct Identity; korp/holger const-blobs + korp↔modgunn Tools shell collapse onto it. Each app KEEPS its ToolEffect enum + demo/container specs; the egui About widget is a later facett-about leaf |
The auth provider family
The modern-auth stack: each method is its OWN feature-gated leaf implementing the shared nornir_service::AuthProvider seam, so a server links only the providers its build pinned (an embedded/mini tier ships one bearer provider and nothing heavier). Consumed by holger (reference impl), korp, dwarves.
| crate | auth method |
| nornir-auth-oidc | OIDC / OAuth2 — validate a bearer JWT OFFLINE against a cached/pre-provisioned JWKS (airgap), or an opaque token ONLINE via /userinfo; plus the device-authorization-grant (RFC 8628) flow for interactive CLI login. One protocol covers Entra ID / Okta / Auth0 / Google / Keycloak / Zitadel |
| nornir-auth-bearer | static Bearer token / API-key — the tiny machine-to-machine method (CI runners, agents, headless clients); reuses the shared bearer-secret resolution ladder + constant-time compare |
| nornir-auth-oauth2 | OAuth 2.0 / 2.1 — verify an access token via RFC 7662 introspection (SP side) + drive the client-credentials + authorization-code + PKCE flows. REUSES the oauth2 crate; HTTP egress behind the online feature |
| nornir-auth-apikey | hashed static API-key — verify a presented key against SHA-256-HASHED keys at rest (rotating / multi-tenant stores); REUSES nornir-hash::sha256_hex + nornir_service::token_matches, no crypto/HTTP of its own |
| nornir-auth-mtls | mTLS — map a mutual-TLS leaf-cert Common Name (ALREADY extracted by the rustls transport) to an identity via verify_client_cert; consumes the CN, does NOT itself path-validate the CA |
| nornir-auth-saml | SAML 2.0 (enterprise SSO) Service Provider in pure Rust (sp feature): XML-DSig verification of a browser-posted Response (HTTP-POST binding) against the configured IdP certificate only, XSW-proof; issuer, audience, Destination, Recipient, InResponseTo, time window (skew at most 300 s); the AuthnRequest and both metadata documents. No samael, no C |
| nornir-auth-webauthn | WebAuthn / FIDO2 / passkey (passwordless human login), pure Rust (p256, no C) — pure (default): RP-side assertion checks (signature, challenge, origin, UP/UV flags, counter) and the MAC'd session token; ceremony: the server-held per-client challenge store and the assertion/attestation checks. The webauthn-rs path is deleted (A34-32) |
| nornir-auth-client | the shared CLIENT-side login — the missing <app> login: OIDC device-grant login (reusing nornir-auth-oidc's device helper), token acquire + silent refresh, and a TokenStore seam (default 0600 file store; pluggable to the dwarves Vault) |
nornir re-exports these (nornir::bench, nornir::cli_outcome, …) so its existing call sites resolve unchanged after the extraction. Leaf repos consume nornir-testmatrix + nornir-robotui from the crates.io registry by version.
Benchmarks
One nornir bench run edda covers every leaf that carries a bencher: autonom's source-scan fold, nornir-flight's Arrow-Flight put/get round-trip, and nornir-saga's replay fold. The arms live inside the leaves (each behind that leaf's off-by-default bench feature); bench/ is the single repo-level entrypoint that links them all — see bench/examples/nornir-bench.rs.
Tests
Dependency graph
License
MIT OR Apache-2.0.