Skip to content

feat(serve): desktop-app CORS + self-heal beacon re-arm and forcelist reconcile#42

Merged
MichaelTaylor3d merged 3 commits into
mainfrom
feat/node-beacon-driver
Jul 16, 2026
Merged

feat(serve): desktop-app CORS + self-heal beacon re-arm and forcelist reconcile#42
MichaelTaylor3d merged 3 commits into
mainfrom
feat/node-beacon-driver

Conversation

@MichaelTaylor3d

Copy link
Copy Markdown
Contributor

Draft — WIP (cap insurance). Single dig-node family lane.

Closes #669 #651
Refs #584

Scope

  • #669 (user priority): widen the loopback serve-surface CORS to desktop-app origins (Tauri) + expose X-Dig-Verified/-Root/-Inclusion-Proof/-Chunk-Lens so dig-urn-resolver's browser node-first path can read the verification attestation.
  • #584: always-on driver re-arms the beacon schedule (dig-updater schedule ensure) on startup + a 6h tick, resolving the dig-updater binary absolutely from the admin-only #565 install root.
  • #651: same-tick ext-forcelist channel-follow reconcile (recover a post-remove-failure uninstall), idempotent + best-effort, absolute sibling-exec.

Status

WIP. Privileged/serve-surface parts go through the dual gate + loop-security before merge. SYSTEM.md CORS/expose-header coherence flagged for the orchestrator.

🤖 Generated with Claude Code

… reconcile

Widen the loopback serve-surface CORS to desktop-app origins (Tauri built-in +
DIG_NODE_CORS_APP_ORIGINS opt-in) and expose the X-Dig-* verification/provenance
headers via Access-Control-Expose-Headers, so dig-urn-resolver's browser node-first
path can read the Verified-by-Chia attestation instead of failing closed to rpc (#669).

Add the always-on self-heal driver (privileged service only): on startup + a 6h tick
it re-arms a drifted beacon schedule (dig-updater schedule ensure, opt-out-respecting)
and reconciles the ext-forcelist channel-follow state (dig-installer
--set-ext-forcelist-channel), resolving sibling CLIs by an absolute path from the
admin-only #565 install root and rejecting a user-writable root (#584, #651).

Minor bump 0.33.0 -> 0.34.0 (feat, backwards-compatible).

Closes #669 #651
Refs #584

Co-Authored-By: Claude <noreply@anthropic.com>
@MichaelTaylor3d
MichaelTaylor3d force-pushed the feat/node-beacon-driver branch from 731b4dc to 095f43a Compare July 16, 2026 17:14
@MichaelTaylor3d MichaelTaylor3d changed the title feat(self-heal): dig-node CORS for desktop-app origins + beacon re-arm + ext-forcelist reconcile driver feat(serve): desktop-app CORS + self-heal beacon re-arm and forcelist reconcile Jul 16, 2026
@MichaelTaylor3d

Copy link
Copy Markdown
Contributor Author

Loop merge-gate: CHANGES-REQUIRED (loop-security HIGH, §565-class LPE) — fix incoming, do not merge.

Triple gate: loop-reviewer PASS + adversarial CONFIRMED-SAFE (both flagged the item as non-blocking), but loop-security escalated it to a gate-blocker:

  • HIGH LPE — self_heal.rs:103 windows_owner_is_privileged spawns powershell by BARE NAME. Windows program search resolves a bare name against the application directory (current_exe() parent = the install root) at step 2, BEFORE PowerShell's real location (reached only via PATH at step 5, since powershell.exe lives in System32\WindowsPowerShell\v1.0\, not System32 directly). So on a user-writable install root — the exact condition resolve_privileged_sibling_in exists to REFUSE — a low-priv user plants <root>\powershell.exe, and the next self-heal pass runs it as SYSTEM before the owner check that would return UserWritableRoot. The LPE gate undoes its own guarantee ("never a bare name", self_heal.rs:23).

Fix (dispatched): replace the powershell owner-probe with the Win32 security API (GetNamedSecurityInfoW owner SID → compare well-known SIDs S-1-5-18 SYSTEM / S-1-5-32-544 Administrators) — no spawn, which also removes the name-suffix owner check (adversarial's ends_with("\administrators") note → SID-equality instead) AND the blocking-spawn robustness concern. Mirror dig-installer's proven pattern (secure.rs, #584/#565). + a regression test: user-writable root with a planted powershell.exe must NOT execute it.

Everything else CLEAR (CORS read-only widening, 10 X-Dig-* expose headers are public metadata, WS/CSWSH path unbroadened, env provenance admin-only, sibling resolution absolute + TOCTOU-closed). Non-gating follow-ups (per-child spawn timeout; Tauri-origin wallet-read exposure) → separate tickets.

MichaelTaylor3d and others added 2 commits July 16, 2026 10:53
…e powershell spawn

The `windows_owner_is_privileged` LPE gate probed the install-root owner by
spawning `Command::new("powershell")` by BARE NAME. Windows resolves a bare
program name against the application directory (`current_exe()` parent = the
install root) BEFORE System32, so on a USER-WRITABLE root — the exact condition
this gate exists to REFUSE — a low-priv user could plant `<root>\powershell.exe`
and the SYSTEM service would execute it before the owner check returned,
undoing self_heal.rs's own "never a bare name" invariant.

Replace the spawn with a direct Win32 security-API read: `GetNamedSecurityInfoW`
(SE_FILE_OBJECT, OWNER_SECURITY_INFORMATION) -> owner SID -> `ConvertSidToStringSidW`
-> exact SID EQUALITY against the well-known S-1-5-18 (LocalSystem) / S-1-5-32-544
(BUILTIN\Administrators). This launches no process, and the SID-equality match
replaces the old `\administrators` name-suffix (which a domain group literally
named "Administrators" could satisfy). Fails CLOSED on any read error.

Regression test plants a `powershell.exe` in a user-owned root and asserts the
probe classifies it not-privileged and executes nothing (no sentinel written).

Co-Authored-By: Claude <noreply@anthropic.com>
Records the new dig-node-service -> windows-sys dependency edge so the
--locked CI clippy/build gates resolve without a lockfile update.

Co-Authored-By: Claude <noreply@anthropic.com>
@MichaelTaylor3d
MichaelTaylor3d marked this pull request as ready for review July 16, 2026 18:19
@MichaelTaylor3d
MichaelTaylor3d merged commit c642140 into main Jul 16, 2026
13 checks passed
@MichaelTaylor3d
MichaelTaylor3d deleted the feat/node-beacon-driver branch July 16, 2026 18:19
MichaelTaylor3d added a commit that referenced this pull request Jul 16, 2026
…timeout (#43)

* feat(tls): TLS-root owner gate + leaf-rotation hardening + self-heal timeout

Batches four #624/#42-arc follow-ups in dig-node-service.

- #661: verify the TLS root is SYSTEM/Administrators-owned (Windows) or
  root-owned + not group/world-writable (unix) before reading the leaf or
  ca.key; fail CLOSED to plaintext otherwise. Extracts the spawn-free Win32
  owner-SID reader from self_heal (#565) into a shared `security` module reused
  by both the LPE spawn gate and this TLS-root gate (DRY).
- #660: set MissedTickBehavior::Delay on the daily leaf-rotation interval so a
  host sleep/suspend coalesces into one catch-up pass, never a burst.
- #659: unit-test the rotation cadence, missed-tick behaviour, and the rotation
  action (fresh leaf untouched; leaf inside its 30-day window re-issued).
- #693: bound each self-heal child spawn to a 120s timeout so a hung
  dig-updater/dig-installer child cannot stall future 6h passes; document the
  Tauri app-origin wallet-read CORS exposure in SPEC §4.3 (custody/sign stay
  token-gated; a route-scoped gate is not currently cheap).

SemVer: minor (0.34.0 -> 0.35.0) — the #661 owner gate is a new
backwards-compatible capability; the rest are hardening + tests.

Closes #661
Closes #660
Closes #659
Closes #693

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(self_heal): kill child processes on timeout via kill_on_drop(true)

The spawn_process function spawned privileged siblings (dig-updater,
dig-installer) without kill_on_drop(true), so on CHILD_TIMEOUT elapse
the child process was orphaned instead of killed. The with_child_timeout
doc comment and error message claimed the child was "cancelled" but it
was actually still running.

Added .kill_on_drop(true) to the Command builder so tokio terminates the
child when the timeout future is dropped. Updated doc comments and error
text to accurately state the child IS killed on timeout.

Fixes accuracy (accuracy/LOW per gate agents) and prevents slow orphan
accumulation under wedged dependencies. Not a vulnerability (trusted
absolute-path siblings, hang not attacker-triggerable), but hardens
the implementation.

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant