Repository navigation
Security settings (red-risk confirmation, risk second opinion) are written only through backend commands #856
Copy link
Copy link
Open
Labels
Milestone
Description
Goal
The security settings "Always confirm on red risk" and the AI risk second opinion (on/off and provider) are changed only through backend commands that validate the value, not by the frontend writing the settings file directly.
Context
- Decided by maintainer: the webview is treated as part of the trusted computing base, and security switches are changeable only through backend commands, not by direct writes from the frontend.
- Today the frontend writes these keys straight into
settings.jsonthroughtauri-plugin-store:apps/smart-ssh-community/frontend/src/riskSettings.ts:32-37saveRiskClassifierSettings→riskClassifierEnabled,riskClassifierProviderIdriskSettings.ts:57-60saveRedRiskAlwaysConfirm→redRiskAlwaysConfirm- callers:
src/components/AiProviderSettings.tsx:114,:138
- The backend reads them at
connect():crates/app-shell/src/risk_second_opinion.rs:33-60(red_risk_always_confirmis fail-safe "on" for a missing or non-boolean value, Spec 0092 A1.2/A1.3). - Settings that already go through backend commands and
settings_store::update(crates/app-shell/src/settings_store.rs:122, issue Write settings.json through one helper that keeps memory and file consistent on failure #265): MCP server (mcp_settings.rs:130,234,283), voice language (voice_input.rs:88), chat retention (chat_retention.rs:41), local server notes/tags (local_server.rs:62,69), speech model (speech_models.rs:76). They are the pattern to follow. scripts/check-tauri-commands.mjschecks that every command is defined, registered and invoked.
Requirements
- New Tauri commands in
crates/app-shell(names may follow the existing naming style):set_risk_second_opinion_settings(enabled: bool, provider_id: Option<String>)– rejects aprovider_idthat is not a configured AI provider (error code, not a panic);enabled = truewithout a provider id is rejected.set_red_risk_always_confirm(value: bool).
Both write throughsettings_store::update(atomic with rollback on a failed save).
- Read paths stay as they are (frontend may keep reading through the store; backend reading unchanged, including the fail-safe default).
riskSettings.tssave functions call the new commands; the file no longer callsstore.set,store.deleteorstore.save.- Error codes for rejected values are added to
errorCodes.tsand alllocales/*/common.json; the settings screen shows the error as it does for other failed saves. - Effect timing unchanged: a change applies from the next connection (Spec 0026, Spec 0092 A1.3).
- Comments in new code in English.
Acceptance Criteria
- Rust tests: each command writes the expected key/value; an unknown provider id and
enabledwithout provider are rejected and leave the file unchanged. - Rust test:
set_red_risk_always_confirm(false)followed by reading throughred_risk_always_confirm_from_storedyieldsfalse;trueyieldstrue; the fail-safe for a missing or non-boolean value is unchanged (existing T16 tests pass). - Frontend tests (
riskSettings.test.ts,AiProviderSettingstests): saving invokes the new commands with the right arguments; no direct store write happens (the store mock'sset/saveare not called). - Guard test (frontend, text scan of non-test
src/**/*.ts(x)): the keysredRiskAlwaysConfirm,riskClassifierEnabled,riskClassifierProviderIdnever appear in astore.set(/store.delete(call; counter-check with an in-memory sample that contains such a call. -
scripts/check-tauri-commands.mjs, locale parity and lint pass. - Relevant automated tests pass.
Technical Notes
- Security-critical area (risk settings that control confirmation): read
.claude/skills/smart-ssh-coder/references/security-invariants.md(invariants 2, 3) and Spec 0092. Review priority elevated. - This issue does not yet remove the webview's write permission on the store; a follow-up issue makes the store read-only for the webview and moves the remaining UI preferences behind a backend command.
- No data migration: the keys and their JSON types stay the same.
Spec impact: update 0092 (§A1: how the setting is written), update 0026 (§3: how the second-opinion setting is written)
Related Work
- Threat model: state that the app's webview is part of the trusted base #818 (threat model: webview is part of the trusted base)
- Write settings.json through one helper that keeps memory and file consistent on failure #265 (settings written through one helper)
Metadata
Metadata
Assignees
Labels
Type
Fields
Priority
P1 - High
Activity
19 remaining items