Skip to content

fix: graceful decrypt failure + CSP wasm-unsafe-eval for Rive mascot#2671

Merged
M3gA-Mind merged 2 commits into
tinyhumansai:mainfrom
M3gA-Mind:bug-fixes
May 26, 2026
Merged

fix: graceful decrypt failure + CSP wasm-unsafe-eval for Rive mascot#2671
M3gA-Mind merged 2 commits into
tinyhumansai:mainfrom
M3gA-Mind:bug-fixes

Conversation

@M3gA-Mind
Copy link
Copy Markdown
Contributor

@M3gA-Mind M3gA-Mind commented May 26, 2026

Summary

  • Config crash fix: decrypt_optional_secret now degrades gracefully when a stored enc2: secret can't be decrypted (e.g. after a keyring reset or machine migration). The field is cleared and a WARN is logged instead of propagating an error that made every config load fail and crashed the app after login.
  • Mascot CSP fix: Added an explicit script-src directive with 'wasm-unsafe-eval' to tauri.conf.json so CEF allows WebAssembly.instantiate(). Without it, Tauri generated a restrictive script-src 'self' <sha256s> at compile time that blocked the Rive WebGL2 renderer introduced in PR feat(mascot): replace SVG animations with Rive renderer #2659, making the mascot invisible.
  • Regression test: Added config_load_succeeds_when_decryption_key_inaccessible to verify the config loads cleanly when a field contains a stale/garbage enc2: ciphertext.

Problem

  • App crashed immediately after login when discord.bot_token (or any other credential) was stored with an enc2: prefix but the master key had been rotated or lost — decrypt_optional_secret returned Err via ?, causing the entire Config::load_or_init to fail. The subconscious bootstrap failure cascaded into all RPC calls that depend on config, making the app unusable.
  • The Rive mascot (@rive-app/react-webgl2) requires WASM compilation. Tauri v2's CSP generator creates script-src from scratch (only 'self' + sha256 hashes) when no explicit script-src is present in the config, which CEF honoured — blocking WebAssembly.instantiate() with a CSP violation.

Solution

  • In decrypt_optional_secret: replaced ? propagation on store.decrypt() error with a match arm that logs warn and sets the field to None, returning Ok(()).
  • In tauri.conf.json security.csp: added script-src 'self' 'unsafe-inline' 'wasm-unsafe-eval' so Tauri appends its sha256 hashes to this directive rather than generating a restrictive one.

Submission Checklist

  • Tests added or updated (happy path + at least one failure / edge case) per Testing Strategy — config_load_succeeds_when_decryption_key_inaccessible covers the decrypt-failure path
  • Diff coverage ≥ 80% — the new load_tests.rs test directly exercises the changed lines in load.rs; CSP change is config-only with no testable code path
  • N/A: Coverage matrix updated — no new feature rows; this is a crash/rendering fix
  • N/A: All affected feature IDs — no feature matrix entries for crash-on-config-load or CSP config
  • No new external network dependencies introduced
  • N/A: Manual smoke checklist — not a release-cut surface change
  • N/A: Linked issue — no tracking issue; bugs found via log analysis

Impact

  • Desktop only (macOS/Windows/Linux). No iOS/web surface changes.
  • Config load is now resilient to stale encrypted credentials — affected integrations show as unconfigured rather than crashing the app.
  • 'wasm-unsafe-eval' is narrower than 'unsafe-eval'; it permits only WASM compilation, not arbitrary eval().

Related


AI Authored PR Metadata (required for Codex/Linear PRs)

Linear Issue

  • Key: N/A
  • URL: N/A

Commit & Branch

  • Branch: bug-fixes
  • Commit SHA: a93a3ba5, ecfbdf37

Validation Run

  • pnpm --filter openhuman-app format:check
  • pnpm typecheck (npx tsc --noEmit — clean)
  • Focused tests: config_load_succeeds_when_decryption_key_inaccessible (via pre-push hook cargo check)
  • Rust fmt/check (if changed): cargo fmt --check — clean after auto-fix
  • Tauri fmt/check (if changed): cargo fmt --manifest-path src-tauri/Cargo.toml --check — clean

Validation Blocked

  • command: N/A
  • error: N/A
  • impact: N/A

Behavior Changes

  • Intended behavior change: stale/undecryptable enc2: tokens are silently cleared rather than crashing config load
  • User-visible effect: after a keyring reset, integrations that stored a bot token re-prompt for credentials instead of crashing the app; mascot is now visible in the left panel

Parity Contract

  • Legacy behavior preserved: tokens that decrypt successfully are still applied as before; no change to the happy path
  • Guard/fallback/dispatch parity checks: is_encrypted() check is unchanged; only the error branch is modified

Duplicate / Superseded PR Handling

  • Duplicate PR(s): none
  • Canonical PR: this PR
  • Resolution: N/A

Summary by CodeRabbit

  • Bug Fixes

    • Improved resilience when encrypted credentials cannot be decrypted (e.g., after workspace migration or keyring loss). The app now clears affected credentials and continues running instead of failing to load.
  • Tests

    • Added regression test for credential decryption failure handling.

Review Change Stack

M3gA-Mind added 2 commits May 26, 2026 14:10
Two bugs fixed:

1. config decrypt crash (load.rs): when a channel token (e.g.
   discord.bot_token) is stored with enc2: encryption but the decryption
   key is no longer accessible (keyring reset, machine migration, key
   rotation), decrypt_optional_secret was propagating a hard error via ?
   on every config load. This made the app unusable after login — every
   RPC that loaded config failed with "Failed to decrypt discord.bot_token".
   Fix: match on decrypt result, log a warn and clear the field on failure
   so config loads successfully with the affected integration disabled.
   Adds regression test config_load_succeeds_when_decryption_key_inaccessible.

2. Rive mascot invisible (tauri.conf.json): PR tinyhumansai#2659 replaced the SVG
   Ghosty mascot with a Rive WebGL2 renderer. Rive requires WebAssembly
   compilation (WebAssembly.instantiate), which CEF blocks because the
   auto-generated script-src CSP only contains 'self' + sha256 hashes —
   no eval-related source. Fix: add an explicit script-src directive with
   'wasm-unsafe-eval' (CSP Level 3 — permits WASM compilation without
   enabling arbitrary eval). Tauri appends its sha256 hashes to this
   directive at compile time.
@M3gA-Mind M3gA-Mind requested a review from a team May 26, 2026 08:46
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 26, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7989b184-b0b5-457d-bfd7-75d3bd51bc10

📥 Commits

Reviewing files that changed from the base of the PR and between e7e7e8a and ecfbdf3.

📒 Files selected for processing (3)
  • app/src-tauri/tauri.conf.json
  • src/openhuman/config/schema/load.rs
  • src/openhuman/config/schema/load_tests.rs

📝 Walkthrough

Walkthrough

This PR introduces graceful handling of decryption failures in config loading and updates the Tauri app's Content Security Policy to permit WebAssembly unsafe evaluation. Config loading no longer crashes when optional secrets cannot be decrypted; instead, the affected secrets are cleared and a warning is logged.

Changes

Secret Decryption Resilience and CSP Update

Layer / File(s) Summary
Secret Decryption Failure Handling
src/openhuman/config/schema/load.rs, src/openhuman/config/schema/load_tests.rs
decrypt_optional_secret handles decryption failures by logging a warning and clearing the optional field rather than propagating the error, allowing config loading to continue. A new regression test validates that undecryptable channel tokens are cleared instead of causing load failure.
Tauri App Content Security Policy
app/src-tauri/tauri.conf.json
The security.csp configuration adds an explicit script-src directive with 'wasm-unsafe-eval' permission to enable WebAssembly evaluation in the Tauri frontend.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

  • tinyhumansai/openhuman#2091: Overlaps with decryption-on-load resilience changes in the same config schema load path and related load tests.

Suggested labels

rust-core, bug

Suggested reviewers

  • senamakel

Poem

🐰 When secrets hide behind locked doors,
We log, we clear, we still endure—
No crashing when the key's not there,
And WASM breathes freed from care.
A gentler load, a kinder way.


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

@M3gA-Mind M3gA-Mind merged commit de2a78a into tinyhumansai:main May 26, 2026
25 of 28 checks passed
@coderabbitai coderabbitai Bot added rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure. bug labels May 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant