Skip to content

feat(matterviz): add signed prerelease self-updater - #51

Open
Stardust0831 wants to merge 9 commits into
mainfrom
feature/matterviz-prerelease-updater
Open

feat(matterviz): add signed prerelease self-updater#51
Stardust0831 wants to merge 9 commits into
mainfrom
feature/matterviz-prerelease-updater

Conversation

@Stardust0831

@Stardust0831 Stardust0831 commented Jul 22, 2026

Copy link
Copy Markdown
Owner

Summary

  • add a preview-only standalone Rust updater with Ed25519 release and install-inventory proofs
  • preserve settings.ini and unknown files while rejecting modified managed files, unsafe archives, collisions, links and special files
  • apply updates through a detached, journaled helper with durable rollback, first-launch confirmation and crash-safe directory retirement
  • expose capability-protected Host endpoints and a manual update UI compiled out of formal frontend builds
  • keep formal packages free of updater executable, inventory and proof metadata

Verification

  • updater: 21 native tests, cargo check, rustfmt and Clippy with warnings denied
  • frontend: 124 tests, Svelte check, preview and formal production builds
  • volume/Host integration: 106 Rust e2e tests, 30 Python contract tests and C stream/syntax checks
  • three-platform workflow run 29954169768 passed frontend/Host plus Linux, macOS and Windows package jobs
  • independent follow-up security review found no remaining critical or important issue

Release safety

frontend/matterviz-updater/trusted-keys.json intentionally remains empty. Preview signing fails closed until the protected matterviz-preview-signing Environment and production public key are configured. This PR does not create a tag or release. The first trust-root preview must be installed manually; a subsequent signed preview is required for real N-to-N+1 validation.

Summary by CodeRabbit

  • New Features
    • Added an optional prerelease updater for checking, staging, installing, and monitoring updates.
    • Added conflict, recovery, progress, rollback, and retry handling.
    • Desktop managed sessions now coordinate updates using the Multiwfn process identifier.
    • Preview packages support signed metadata and updater assets; formal releases omit updater functionality.
  • Bug Fixes
    • Improved request validation and safer updater visibility when prerequisites are unavailable.
  • Documentation
    • Added updater security, signing, trust, and key-rotation guidance.
  • Tests
    • Expanded updater, signing, and release-packaging verification coverage.

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: fd11cba1-f0b9-4933-9791-058e8e2fbdc6

📥 Commits

Reviewing files that changed from the base of the PR and between 47a5e80 and c3bf0cf.

📒 Files selected for processing (1)
  • frontend/matterviz-desktop/src/service.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/matterviz-desktop/src/service.rs

📝 Walkthrough

Walkthrough

This PR adds a signed prerelease updater across Rust libraries and binaries, desktop HTTP integration, viewer UI, process lifecycle handling, secure packaging, preview signing, release verification, and operational documentation.

Changes

MatterViz updater

Layer / File(s) Summary
Updater protocol and transaction foundation
frontend/matterviz-updater/*
Adds signed manifests, inventory proofs, secure extraction, journaled installation, rollback, candidate persistence, release fetching, and tests.
Updater and signing command-line flows
frontend/matterviz-updater/src/bin/*
Adds updater lifecycle, helper, signing, proof, verification, and manifest-generation commands.
Desktop host updater integration
frontend/matterviz-desktop/src/*, noGUI/matterviz_spawn.c, tests/matterviz-volume-e2e/*
Passes managed-process PIDs, exposes guarded update endpoints, runs updater helpers, confirms updates after readiness, and updates host tests.
Viewer update client and modal
frontend/matterviz-viewer/src/*, frontend/matterviz-viewer/tests/update.test.ts
Adds typed status parsing, endpoint calls, polling, modal actions, state rendering, styling, and client tests.
Preview packaging and release signing
.github/workflows/matterviz-gui.yml, tests/test_matterviz_build_names.py
Adds formal/preview packaging rules, updater metadata checks, protected preview signing, release verification, and checksum validation.
Updater operational documentation
docs/matterviz-updater*.md, docs/matterviz-spectrum-*.md
Documents updater trust, signing, transaction behavior, bootstrap requirements, validation scenarios, and remaining operational tasks.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Viewer
  participant HttpService
  participant UpdateManager
  participant Updater
  participant ReleaseServer
  Viewer->>HttpService: request update status or action
  HttpService->>UpdateManager: validate visibility and start operation
  UpdateManager->>Updater: run JSON updater command
  Updater->>ReleaseServer: fetch signed preview metadata and archive
  ReleaseServer-->>Updater: signed manifest and package
  Updater-->>UpdateManager: update state JSON
  UpdateManager-->>HttpService: status response
  HttpService-->>Viewer: render status or modal progress
Loading

Possibly related PRs

Suggested labels: enhancement

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 37.91% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding a signed prerelease self-updater for MatterViz.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/matterviz-prerelease-updater

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (2)
frontend/matterviz-updater/src/bin/multiwfn-matterviz-sign.rs (1)

117-170: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Deduplicate the release-target builder shared by build-manifest and build-sign.

Lines 119-123 and 162-166 are identical (read archive, parse inventory, verify metadata, build ReleaseTarget). Extracting one helper avoids the two copies drifting apart in security-relevant tooling.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/matterviz-updater/src/bin/multiwfn-matterviz-sign.rs` around lines
117 - 170, Extract the duplicated release-target construction logic from the
“build-manifest” and “build-sign” command branches into a shared helper,
preserving archive reading, inventory parsing, metadata validation, hashing, and
error behavior. Update both branches to call the helper when producing their
target lists, using the existing target/archive/inventory inputs.
frontend/matterviz-viewer/src/UpdateModal.svelte (1)

12-24: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Align UpdateModal.svelte with the viewer’s runes style
This modal still uses legacy export let/$: while the rest of the viewer is on runes ($state). Converting it to $props()/$derived/$effect would keep the Svelte style consistent.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/matterviz-viewer/src/UpdateModal.svelte` around lines 12 - 24,
Convert UpdateModal’s legacy export declarations and reactive `$:` statement to
Svelte runes: obtain the component inputs through `$props()`, store mutable
status and other local state with `$state`, derive the initial status with
`$derived` where appropriate, and synchronize changes from `initial_status`
using `$effect`. Preserve the existing defaults, callback types, and
status-update behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/matterviz-spectrum-log.md`:
- Line 3: Correct the future-dated documentation markers: update the
architecture section heading in docs/matterviz-spectrum-log.md lines 3-3 and the
update marker/self-update section date in docs/matterviz-spectrum-todo.md lines
3-5 to the actual change date or revised review context, using consistent dates
across both documents.

In `@frontend/matterviz-updater/src/bin/multiwfn-matterviz-updater.rs`:
- Around line 37-67: Update reply’s enabled calculation to avoid calling
authenticate_current_inventory, since it re-hashes every managed file on each
response; validate only settings.ini, local target, embedded key registry
presence, and the current inventory proof’s signature/release tag using the
existing non-hashing verification path. Reuse the already computed current and
registry values instead of calling read_current_tag and embedded_key_registry
repeatedly, while preserving the enabled=false behavior when any prerequisite or
proof validation fails.

In `@frontend/matterviz-updater/src/lib.rs`:
- Around line 1462-1469: The write-probe handling in apply_transaction must
tolerate a stale .multiwfn-updater-write-probe from a prior crash. Update the
OpenOptions/create_new flow to remove an existing probe or otherwise handle
AlreadyExists before continuing, while preserving the write and sync validation
and final cleanup.

---

Nitpick comments:
In `@frontend/matterviz-updater/src/bin/multiwfn-matterviz-sign.rs`:
- Around line 117-170: Extract the duplicated release-target construction logic
from the “build-manifest” and “build-sign” command branches into a shared
helper, preserving archive reading, inventory parsing, metadata validation,
hashing, and error behavior. Update both branches to call the helper when
producing their target lists, using the existing target/archive/inventory
inputs.

In `@frontend/matterviz-viewer/src/UpdateModal.svelte`:
- Around line 12-24: Convert UpdateModal’s legacy export declarations and
reactive `$:` statement to Svelte runes: obtain the component inputs through
`$props()`, store mutable status and other local state with `$state`, derive the
initial status with `$derived` where appropriate, and synchronize changes from
`initial_status` using `$effect`. Preserve the existing defaults, callback
types, and status-update behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 759d1537-c878-4821-8a49-57b2cb949065

📥 Commits

Reviewing files that changed from the base of the PR and between e86e0fd and df8ee0b.

⛔ Files ignored due to path filters (1)
  • frontend/matterviz-updater/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (24)
  • .github/workflows/matterviz-gui.yml
  • docs/matterviz-spectrum-log.md
  • docs/matterviz-spectrum-todo.md
  • docs/matterviz-updater-signing.md
  • docs/matterviz-updater.md
  • frontend/matterviz-desktop/src/cli.rs
  • frontend/matterviz-desktop/src/main.rs
  • frontend/matterviz-desktop/src/service.rs
  • frontend/matterviz-desktop/src/updater.rs
  • frontend/matterviz-updater/Cargo.toml
  • frontend/matterviz-updater/README.md
  • frontend/matterviz-updater/src/bin/multiwfn-matterviz-sign.rs
  • frontend/matterviz-updater/src/bin/multiwfn-matterviz-updater.rs
  • frontend/matterviz-updater/src/lib.rs
  • frontend/matterviz-updater/trusted-keys.json
  • frontend/matterviz-viewer/src/App.svelte
  • frontend/matterviz-viewer/src/UpdateModal.svelte
  • frontend/matterviz-viewer/src/styles.css
  • frontend/matterviz-viewer/src/update.ts
  • frontend/matterviz-viewer/src/vite-env.d.ts
  • frontend/matterviz-viewer/tests/update.test.ts
  • noGUI/matterviz_spawn.c
  • tests/matterviz-volume-e2e/src/lib.rs
  • tests/test_matterviz_build_names.py

Comment thread docs/matterviz-spectrum-log.md
Comment thread frontend/matterviz-updater/src/bin/multiwfn-matterviz-updater.rs
Comment thread frontend/matterviz-updater/src/lib.rs
@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
Validation Failed: {"resource":"IssueComment","code":"custom","field":"body","message":"body is too long (maximum is 65536 characters)"} - https://docs.github.com/rest/issues/comments#update-an-issue-comment

@Stardust0831
Stardust0831 force-pushed the feature/matterviz-prerelease-updater branch from 5dcb072 to 47a5e80 Compare August 2, 2026 16:34

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
frontend/matterviz-desktop/src/service.rs (3)

1029-1038: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Add plot_store.clear() to the shared signal_return helper.

ServiceRunner::signal_return clears only volume_store. Every other shutdown/invalidation path in this file (HttpService::signal_return at Line 416-426, ServiceRunner::run's accept-error branch at Line 494-502, terminate_control_session at Line 1346-1361, and the explicit calls in the /api/return handler at Line 812-813) clears both stores. The /api/update/install success branch at Line 696-711 calls this private signal_return, then redundantly re-clears volume_store but never clears plot_store. Stale plot data stays servable through /api/plot-data/{id} during the shutdown window that follows a successful update.

Move the plot_store.clear() call into this shared function so every caller gets consistent cleanup, and the redundant explicit volume_store.clear() calls at the call sites become unnecessary.

🐛 Proposed fix
     fn signal_return(&self) -> Result<(), String> {
         let result = signal_return(
             self.in_memory_session,
             &self.return_signaled,
             self.control_session.as_deref(),
             &self.session,
         );
         self.volume_store.clear();
+        self.plot_store.clear();
         result
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/matterviz-desktop/src/service.rs` around lines 1029 - 1038, Update
ServiceRunner::signal_return to clear plot_store alongside volume_store after
invoking the shared signal_return helper. Remove redundant volume_store.clear()
calls from its callers, including the /api/update/install success path, while
preserving cleanup behavior for all shutdown and invalidation flows.

255-269: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Use active_data_budget for orbital admissions with both stores

active_volume_budget is an alias for active_data_budget, but ServiceRunner::stream_orbital only adds self.volume_store.bytes(). Include self.plot_store.bytes() in that current_active value so admissions and test admission checks use the same active-data budget.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/matterviz-desktop/src/service.rs` around lines 255 - 269, Update
ServiceRunner::stream_orbital so its current_active calculation includes both
self.volume_store.bytes() and self.plot_store.bytes(). Use this combined value
for orbital admission checks, preserving the active_data_budget behavior and
ensuring test admission checks use the same total.

1387-1486: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Bound the total time to read one HTTP request, not just each individual read() call.

read_http_request bounds header size (MAX_HEADERS), request-line length (MAX_REQUEST_LINE), and body size (MAX_PLOT_EXPORT_BYTES), but it has no overall wall-clock deadline. The caller sets stream.set_read_timeout(Duration::from_secs(2)) (Line 538), which only limits how long a single read() call can block. An attacker who sends at least one byte every 1.9 seconds can keep both the header-read loop (Line 1393-1408) and the body-read loop (Line 1469-1479) alive indefinitely.

This is reachable before the Host check (Line 555) and before the capability check (Line 612), so it does not require a valid session token. Each accepted connection runs on its own spawned thread (ServiceRunner::run, Line 486-493), so a small number of slow connections can pin threads for an unbounded time, degrading availability for legitimate clients on this host.

Track an overall deadline across both loops, mirroring the existing Instant-based deadline pattern already used in control_transport.rs's read_exact_timeout.

🔒 Suggested direction
fn read_http_request(stream: &mut TcpStream) -> Result<HttpRequest, HttpRequestError> {
    const MAX_REQUEST_DURATION: Duration = Duration::from_secs(30);
    let deadline = Instant::now() + MAX_REQUEST_DURATION;
    // ...
    loop {
        if Instant::now() >= deadline {
            return Err(HttpRequestError::BadRequest);
        }
        let length = stream.read(&mut chunk).map_err(|_| HttpRequestError::BadRequest)?;
        // ...
    }
    // ...
    while body.len() < body_length {
        if Instant::now() >= deadline {
            return Err(HttpRequestError::BadRequest);
        }
        // ...
    }
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/matterviz-desktop/src/service.rs` around lines 1387 - 1486, Update
read_http_request to establish one Instant-based deadline for the entire
request, using a suitable maximum duration. Check that deadline before each read
in both the header-accumulation loop and body-reading loop, returning BadRequest
when expired, so progress bytes cannot extend the total allowed time.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@frontend/matterviz-desktop/src/service.rs`:
- Around line 1029-1038: Update ServiceRunner::signal_return to clear plot_store
alongside volume_store after invoking the shared signal_return helper. Remove
redundant volume_store.clear() calls from its callers, including the
/api/update/install success path, while preserving cleanup behavior for all
shutdown and invalidation flows.
- Around line 255-269: Update ServiceRunner::stream_orbital so its
current_active calculation includes both self.volume_store.bytes() and
self.plot_store.bytes(). Use this combined value for orbital admission checks,
preserving the active_data_budget behavior and ensuring test admission checks
use the same total.
- Around line 1387-1486: Update read_http_request to establish one Instant-based
deadline for the entire request, using a suitable maximum duration. Check that
deadline before each read in both the header-accumulation loop and body-reading
loop, returning BadRequest when expired, so progress bytes cannot extend the
total allowed time.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f30b289d-41fc-492b-85b7-a463567a6cec

📥 Commits

Reviewing files that changed from the base of the PR and between e137c86 and 47a5e80.

📒 Files selected for processing (12)
  • .github/workflows/matterviz-gui.yml
  • .gitignore
  • docs/matterviz-spectrum-log.md
  • docs/matterviz-spectrum-todo.md
  • frontend/matterviz-desktop/src/main.rs
  • frontend/matterviz-desktop/src/service.rs
  • frontend/matterviz-viewer/src/App.svelte
  • frontend/matterviz-viewer/src/styles.css
  • frontend/matterviz-viewer/src/vite-env.d.ts
  • noGUI/matterviz_spawn.c
  • tests/matterviz-volume-e2e/src/lib.rs
  • tests/test_matterviz_build_names.py
🚧 Files skipped from review as they are similar to previous changes (10)
  • frontend/matterviz-desktop/src/main.rs
  • frontend/matterviz-viewer/src/vite-env.d.ts
  • noGUI/matterviz_spawn.c
  • frontend/matterviz-viewer/src/styles.css
  • docs/matterviz-spectrum-todo.md
  • tests/matterviz-volume-e2e/src/lib.rs
  • frontend/matterviz-viewer/src/App.svelte
  • docs/matterviz-spectrum-log.md
  • tests/test_matterviz_build_names.py
  • .github/workflows/matterviz-gui.yml

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