UnENVerse Find a guide: importing, command line, nodes

All releases

UnENVerse 2026-10-09

Licence: LICENSE replaced by the official Apache-2.0 text (curl from apache.org), NOTICE added, license fields in package.json, vscode-extension, tauri.conf, 4 Cargo.toml, image label.

second rename sweep, Apache-2.0, README and CHANGELOG rewrite, demo server and screenshots, CI hardening

  1. Licence: LICENSE replaced by the official Apache-2.0 text (curl from apache.org), NOTICE added, license fields in package.json, vscode-extension, tauri.conf, 4 Cargo.toml, image label.
  2. Demo + screenshots: tools/demo/seed.py (fake vault via the unv CLI against a throwaway server: 29 entries across the common providers and kinds, 3 projects, 12 categories, users alice/bob/ci-bot, classes Developers/Operators, permission expressions), tools/demo/shots_demo.py, tools/demo/run.sh (starts unv-demo on :18743, seeds, runs the real app in the viewer container over --network host). Output `Scr
  3. CI: unv-server/tests/nodes_e2e.rs waits for last_polled (Windows race), history.rs snapshot test sleeps between saves (timing under load), cargo fmt applied everywhere (the Ubuntu failure was import order after the rename), scripts/preflight.sh + npm run preflight + .githooks/pre-commit mirror CI's gates.
  4. Verification: cargo test --workspace 707 passed; npm run check 1497 passed; fmt/clippy clean for unv-cli.
  5. Nothing pushed; no CI run observed for these changes.
  6. VPS node binary is still release 0.42.1 (pre-rename strings); protocol domains unchanged so it interoperates. Apply (push) for wg0 still off; decision pending (root agent vs polkit).
  7. Peer comment lines (# name) of the live wg0.conf are not produced by the exporter.
  8. The CHANGELOG is machine-compiled from session notes; wording is uneven for older entries.
  9. VS Code extension settings keys are now unenverse.* (users must re-set them).

the rename to UnENVerse, the Discord acceptance, restore-into-chunks, and a way to see the app

  • New in this round: public inference (ImportedVar.public). A variable is marked public only when it is plainly not a secret: names that look secret (key, token, secret, password, webhook, sig, auth, passkey) always win; hex ints, bools and floats are public; short ints are public; URLs are public unless they carry userinfo, a credential query parameter, a webhook path or a token-looking path segment; prose strin
  • History pane: a "Restore into chunks" button on each snapshot row for formats with a reader. It fetches the real text with reveal: true, confirms, applies, saves, repaints.
  • Nodes pane: "Read into a chunk" is now offered for those formats as well as .env, using the same plan and confirmation.
  • Values arrive as literal text (the deployed file had no references), and the confirmation says so. There is deliberately no Rust twin (six formats parsed twice would be six chances to disagree); no new Tauri command, so the capability map needs no entry. Test: tests/restore-chunks.test.ts.
  • Lazy version_history loading in the app; concurrent polls for listening nodes; certificate and hub transport key rotation; a Nextcloud rotation adapter; the 24.4 container benchmark (needs a 2 vCPU host); a hardware or passkey approver; Grafana token expiry in the probe. Each needs either a decision or a real service; none is a code gap that tests can close.
  • A4, A9, A10 smoke tests: the viewer now makes them possible (Xvfb has X11 only; Wayland is still not covered, and Caps Lock and the input method need xdotool and an IM inside the image).

everything that was left: 30.1/30.2, 34.1, 37.1, 38.1, 29.1, 28.1, 31.3 and the leftovers of 24.5, 35 and 36

  • Restore a history snapshot into chunks (35): only .env-style files have a Rust parser; the other formats' parsers are TypeScript, and a second implementation would be a new twin pair. The pulled-file path (--into-chunk) covers the .env case.
  • **Lazy version_history in the app (30.2), concurrent polls and certificate rotation for listening nodes (ADR-0145), a hardware key as approver (ADR-0147), a Nextcloud rotation adapter and Grafana token expiry** (ADR-0148).

30.1 (delta saves, server and store half) and 29.1 (two more rules)

FileChange and why
src/ts/state.tsRemoteVaultStore.save now calls private send('PUT', data); new saveRows(put, del) calls send('PATCH', {put, delete}). One body of toast, If-Match and etag logic for both.
tests/remote-save-rows.test.ts (new)Stubs fetch: PATCH method, body is exactly the delta, the returned ETag is sent as the next If-Match.

| vault-core/src/config_check.rs | Two rules, RULES 12 to 14. compose-network-undeclared (error): a service networks entry that no docker_network chunk declares; silent unless the project declares at least one network, default always exists, refs are skipped, names compared case-insensitively. k8s-service-selector-unmatched (warning): the starters generate selector: app: <name>, so a Service selects the

  • App dirty tracking. The Tauri side and state.ts stores still save the whole document; nothing calls saveRows yet, and no Tauri save_vault_rows / Access::save_rows exists. The app tracks no dirty ids. This is the larger half of 30.1 and the one that touches every mutation site in the renderer.
  • Pinned-HTTPS proxy (remote_request) still returns no headers, so ETag and X-Vault-Merged do not reach the store over it.
  • 30.2 (chunk rows, age-based retention, full-load speed) untouched.
  • 29.1: envv check --all-projects and a separate gate() function remain unbuilt (the push gate already refuses on errors).
  • 38.1, 34.1, 28.1 per-pane tests, 31.3 further catalogue entries unchanged.

Sub-phases 28.1 and 29.1, the 1.0 viability review, the decision to defer 30.1/30.2

Phase 39: pre-1.0 security review and pentest checklist

Phase 38: stack integrations

  • Integrations (Prometheus, Grafana, Homarr/Homepage, Nextcloud, VS Code) each hand-written in four places (Rust exporter, TS exporter, starters, rules) would add a dozen drift points. Phase 38 also had to name "the adapter shape they share".
  • The shape: a JSON descriptor per integration (vault-core/data/stack-adapters.json) with chunk types (fields, secret flags, defaults), an output document grammar (literal, {f,as,fmt}, map, list, each, singleton, group, entry, when) and rules (unique, required, exclusive, together, choices, needs_one_of). Two interpreters: vault-core/src/stack.rs and src/ts/stack.ts, pinned by golden files. Adapters shipped: `p

Phase 37: approval

Phase 36: blast radius

  1. Nothing recorded which secrets a rendered file *contained*.
  2. Local envv exec and --out are deliberately outside the audit chain, so there was no record of what reached *this* machine.
  3. By the time of a compromise an entry may have been rotated, renamed or deleted, so "what is in the vault now" is the wrong thing to look up.
  4. The app has no UI for --host local (by nature: the app's copy actions are not logged). If the app ever logs its own copy/export actions it should write the same ring through a Tauri command.
  5. matlog::note builds a Matcher per call (O(secrets)); fine for a handful of materialisations per command, wasteful in a loop. Cache the matcher in remember if a command ever materialises per-item.
  6. exposed lists are computed at snapshot time against the vault *then*: an entry created after the file was written is correctly absent; an entry whose value was identical by coincidence is present (reported, marked short if under 8 characters).

Phase 35: the config time machine

Phase 34: Nodes

  • listen mode; pull-into-chunks; per-beat render cache (every beat loads the vault and renders; fine at tens of nodes, measure before hundreds; the ceiling is O(vault) per beat per node).
  • node.apply rows carry the node's reported error text (cut to 400 characters, scrubbed on the node). A hostile node can still write misleading text into its own audit rows; it cannot forge another node's actor.
  • The hub trusts a node's HostInfo/TargetReport for display only; none of it feeds a decision except apply (which only controls whether content is sent, and the node re-checks).
  • No rate limit on a signed node's beats beyond the per-IP failure limiter (a valid node can beat as fast as it likes). Add one if nodes are ever less trusted than "the operator's own machines".
  • Phase 39 (pentest) should cover: enrollment token guessing and the 12-attempt limiter, replay across restart, the signature input format, the config-check gate bypass by project-name tricks, command injection through reload (only the node's own file feeds it), and the long-poll as a resource-holding route.

·