Files
Shadowbroker/desktop-shell
Shadowbroker a930497e14 fix(start-scripts): find bundled privacy_core.dll next to script (#319) (#324)
* fix(start-scripts): find bundled privacy_core.dll next to script

start.bat and start.sh only checked the source-tree DLL path
(``privacy-core/target/release/privacy_core.dll``), not the bundled
location where MSI/AppImage/DMG installers stage the library directly
next to the script in backend-runtime/.

Users running start.bat from inside an MSI install dir (a documented
workaround when the desktop shell crashes) saw a scary "install Rust"
warning even though the DLL was sitting right next to them. See issue
#319 for the user-reported confusion.

Fix: add a fallback check for the bundled location before falling
through to the "build privacy-core from source" warning. Source-tree
behavior unchanged — the source path is still preferred when present.

Also re-stamps the v0.9.81 source archive: ``release_digests.json``
v0.9.81 zip hash updated to point at the rebuilt source archive that
contains these script changes. MSI/EXE/sig hashes are unchanged (the
scripts live at the repo root, not inside the desktop bundle).

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

* fix(#319): bundle start.bat + start.sh into the MSI/EXE installers

Follow-up to the start-script DLL fallback fix in the prior commit.

ChrisMTheMan's report on #319 made it clear the workaround flow was:

  1. MSI install crashes on launch (different bug, fixed in v0.9.81)
  2. User goes looking for start.bat to launch the backend manually
  3. start.bat isn't in their install dir, so they go fetch it from GitHub
  4. They get a working script but it doesn't know about the bundled
     privacy_core.dll layout, so they see a scary "install Rust" warning

The prior commit fixed step 4. This commit fixes step 3 — start.bat and
start.sh now ship inside the MSI/EXE installers (staged into
backend-runtime/ next to the privacy_core.dll they expect to find).
After the rebuild lands, an MSI user looking for these scripts finds
them right inside their install dir, already pointing at the correct
bundled DLL location.

What changed
------------

* ``build-backend-runtime.cjs`` now has a ``stageStartScripts()`` step
  that copies start.bat and start.sh from the repo root into the
  staged backend-runtime/. Preserves the executable bit on .sh under
  POSIX.

* ``release_digests.json`` v0.9.81 block hashes refreshed for the
  rebuilt MSI / EXE / source-zip (the scripts being bundled changed
  the MSI/EXE contents; the source zip also includes the start-script
  fix from the prior commit).

  ShadowBroker_v0.9.81.zip                  6.06 MB
    af8c87ccdece8fbb9aadc6be63cce10d3fcba74e6d87ef83289dda6d555fd270
  ShadowBroker_0.9.81_x64_en-US.msi       122.4 MB
    8977c9a1c54e1f0d030436be9c4e3d81d766cc0080699eb747649095f360c7ff
  ShadowBroker_0.9.81_x64-setup.exe        76.5 MB
    4e866fa0423c0c2470ed32f4809167a7815dc23ee7762b69e95681c1f3a28250

Post-merge plan
---------------

Force-move the v0.9.81 tag to this commit and replace ALL release
assets on the GitHub release: zip, msi, exe, both .sig files,
latest.json, SHA256SUMS.txt, release-manifest.json.

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

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-23 21:34:59 -06:00
..
2026-05-01 22:56:50 -06:00
2026-05-01 22:56:50 -06:00
2026-05-01 22:56:50 -06:00

Desktop Shell

Native-side scaffold for the ShadowBroker desktop boundary.

Purpose

This package owns the accepted desktop track:

  • native privileged control routing through Rust
  • authoritative policy enforcement and audit
  • packaged managed local backend ownership
  • packaged desktop runtime with same-origin /api/*
  • tray/menu-bar lifecycle
  • optional reduced-trust browser companion mode
  • desktop packaging/release tooling

Browser mode remains intact; the desktop path layers on top of it.

Source of truth

The shared desktop control contract still lives in:

  • frontend/src/lib/desktopControlContract.ts
  • frontend/src/lib/desktopControlRouting.ts

The native side imports that contract instead of redefining it.

Layout

desktop-shell/
├── package.json
├── scripts/
│   └── run-desktop-build.cjs          # Cross-platform npm build wrapper
├── src/
│   ├── runtimeBridge.ts
│   ├── nativeControlRouter.ts
│   ├── nativeControlAudit.ts
│   └── handlers/
└── tauri-skeleton/
    ├── dev.sh
    ├── build.sh
    ├── build.ps1
    ├── RELEASE.md
    ├── scripts/
    │   ├── generate-icons.cjs
    │   └── write-release-manifest.cjs
    └── src-tauri/
        ├── Cargo.toml
        ├── tauri.conf.json
        ├── icons/                      # Generated branded bundle assets
        └── src/
            ├── main.rs
            ├── bridge.rs
            ├── policy.rs
            ├── tray.rs
            ├── companion.rs
            ├── companion_server.rs
            ├── handlers.rs
            └── http_client.rs

Desktop runtime model

Native privileged path

The accepted 27-command privileged path remains native-only:

  • frontend bridge detection builds window.__SHADOWBROKER_LOCAL_CONTROL__
  • privileged requests go through Tauri IPC
  • Rust policy enforces capability/profile rules before dispatch
  • Rust audit ring records all outcomes
  • the native admin key never reaches webview JavaScript

Packaged main window

Packaged builds now own a bundled local backend runtime by default, then use an app-level loopback server as the native window origin so ordinary non-privileged /api/* fetches resolve same-origin instead of dying on static asset serving.

Browser companion

Browser companion remains:

  • optional
  • loopback-only
  • explicitly enabled
  • reduced-trust

It never receives the native bridge injection, and it is not a drop-in replacement for standalone browser mode.

Packaging / release flow

Use any of these entrypoints:

./desktop-shell/tauri-skeleton/build.sh
./desktop-shell/tauri-skeleton/build.ps1
npm --prefix desktop-shell run build:desktop

Use --clean to remove the previous export, generated icons, and old installer artifacts before rebuilding.

The release flow now:

  1. generates branded desktop icons
  2. stages a desktop-only frontend export tree without Next server-only route handlers / middleware
  3. stages a managed backend runtime bundle from backend/
  4. builds the frontend export for Tauri packaging
  5. copies the export to companion-www
  6. runs cargo tauri build
  7. writes SHA256SUMS.txt and release-manifest.json next to the bundle output

If the Tauri CLI is missing, the build scripts now fail immediately with the correct cargo install tauri-cli@^2 instruction.

The repo also now has a no-secrets desktop matrix workflow at ../.github/workflows/desktop-release.yml that builds unsigned desktop artifacts on Windows, macOS, and Linux and turns v*.*.* tags into downloadable GitHub release assets.

See tauri-skeleton/RELEASE.md for release-path details and tauri-skeleton/RELEASE_INPUTS.md for the future inputs that only matter once public distribution trust becomes a goal.

Current status

This is a runnable desktop foundation with a repeatable packaging path.

What works:

  • native desktop window with full app UI
  • packaged desktop ownership of a bundled local backend runtime
  • packaged desktop auto-generates and persists its local backend admin/private-plane secrets on first run
  • packaged desktop-managed backend blocks legacy 16-hex node-ID compat and direct legacy_agent_id lookup by default
  • packaged same-origin /api/* path for non-privileged data
  • Rust-side policy enforcement and audit
  • tray/menu-bar background lifecycle
  • macOS dock reopen
  • optional reduced-trust browser companion opener
  • branded Tauri/Windows/macOS bundle icons
  • release manifest + checksum generation

What is still not done:

  • code signing / notarization
  • auto-update mechanism
  • final installer copy / splash polish
  • DM/data-plane native migration
  • standalone-browser-equivalent companion parity

Managed backend defaults

The packaged desktop-managed backend now defaults to the hardened posture for compatibility sunset work:

  • MESH_BLOCK_LEGACY_NODE_ID_COMPAT=true
  • MESH_ALLOW_LEGACY_NODE_ID_COMPAT_UNTIL= unless an operator sets a dated temporary migration override
  • MESH_BLOCK_LEGACY_AGENT_ID_LOOKUP=true

That default applies to the app-owned managed backend created under %LOCALAPPDATA%. Source/server deployments remain operator-controlled and can set those flags independently.

If a managed desktop operator leaves MESH_BLOCK_LEGACY_NODE_ID_COMPAT=false in the managed backend .env, bootstrap now normalizes it back to true. The only supported escape hatch for legacy 16-hex node IDs is a dated MESH_ALLOW_LEGACY_NODE_ID_COMPAT_UNTIL=YYYY-MM-DD override. MESH_BLOCK_LEGACY_AGENT_ID_LOOKUP=false is still preserved if an operator intentionally needs that separate migration path.