Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions src/lib/storage/action-processors/user-preference.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,24 @@ class UserPreferenceActionProcessor extends BaseActionProcessor {
this.store.set({ allowInsecureCerts: value })
break;
}
case USER_PREFERENCE.GET_DEV_SCRIPT_MODE:
return !!this.store.get("devScriptMode")
case USER_PREFERENCE.UPDATE_DEV_SCRIPT_MODE: {
// RQ-2426: fail SAFE. Dev mode (full host access for code rules) is enabled
// only for an explicit boolean `true`, or a recognized truthy boolean-string
// (IPC may serialize booleans). A missing key, object, or unknown value stays
// `false` (safe QuickJS sandbox).
// @ts-ignore
const raw = payload?.data?.devScriptMode;
let value = false;
if (typeof raw === "boolean") {
value = raw;
} else if (typeof raw === "string") {
value = raw === "true" || raw === "1";
}
this.store.set({ devScriptMode: value })
break;
}
case USER_PREFERENCE.GET_COMPLETE_LOGGING_CONFIG:
return this.store.get("localFileLogConfig")

Expand Down
8 changes: 8 additions & 0 deletions src/lib/storage/schemas/userPreferenceSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ export const userPreferenceSchema = {
default: false
},

// RQ-2426: when true, "code" rules run via the legacy full-access executor
// (DEV mode) instead of the safe QuickJS sandbox. Full system access — off
// (safe) by default.
devScriptMode: {
type: "boolean",
default: false
},

localFileLogConfig: {
type: "object",
properties: {
Expand Down
5 changes: 5 additions & 0 deletions src/lib/storage/types/action-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ export enum USER_PREFERENCE {
GET_ALLOW_INSECURE_CERTS = "USER_PREFERENCE:GET_ALLOW_INSECURE_CERTS",
UPDATE_ALLOW_INSECURE_CERTS = "USER_PREFERENCE:UPDATE_ALLOW_INSECURE_CERTS",

// RQ-2426: DEV script-execution mode (full host access for code rules). Off (safe
// QuickJS sandbox) by default.
GET_DEV_SCRIPT_MODE = "USER_PREFERENCE:GET_DEV_SCRIPT_MODE",
UPDATE_DEV_SCRIPT_MODE = "USER_PREFERENCE:UPDATE_DEV_SCRIPT_MODE",

GET_COMPLETE_LOGGING_CONFIG = "USER_PREFERENCE:LOCAL_LOG_FILE:GET_ALL",

GET_IS_LOGGING_ENABLED = "USER_PREFERENCE:LOCAL_LOG_FILE:GET_IS_ENABLED",
Expand Down
2 changes: 2 additions & 0 deletions src/lib/storage/types/user-preference.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export interface UserPreferenceObj {
defaultPort: number;
allowInsecureCerts?: boolean;
devScriptMode?: boolean;
localFileLogConfig: {
isEnabled: boolean;
storePath: string;
Expand All @@ -11,6 +12,7 @@ export interface UserPreferenceObj {
export interface ISource {
defaultPort: number;
allowInsecureCerts?: boolean;
devScriptMode?: boolean;
isLocalLoggingEnabled: boolean;
logStorePath: string;
localLogFilterfilter: string[]
Expand Down
5 changes: 4 additions & 1 deletion src/renderer/actions/proxy/startProxyServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { staticConfig } from "../../config";
import * as Sentry from "@sentry/browser";
import startHelperServer, { stopHelperServer } from "../startHelperServer";
import logger from "utils/logger";
import { getDefaultProxyPort, getAllowInsecureCerts } from "../storage/cacheUtils";
import { getDefaultProxyPort, getAllowInsecureCerts, getDevScriptMode } from "../storage/cacheUtils";
import { handleCARegeneration } from "../apps/os/ca/utils";
import { startHelperSocketServer, stopHelperSocketServer } from "../helperSocketServer";
import portfinder from "portfinder";
Expand Down Expand Up @@ -46,6 +46,9 @@ function startProxyFromModule(PROXY_PORT: number) {
// RQ-2425: user-controlled toggle for upstream TLS verification.
// Defaults to false (verify) unless the user enabled insecure requests.
allowInsecureCerts: getAllowInsecureCerts(),
// RQ-2426: DEV script-execution mode for code rules. Defaults to false
// (safe QuickJS sandbox) unless the user explicitly opted into full access.
devScriptMode: getDevScriptMode(),
};
RQProxyProvider.createInstance(
proxyConfig,
Expand Down
7 changes: 7 additions & 0 deletions src/renderer/actions/storage/cacheUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ export const getAllowInsecureCerts = (): boolean => {
return !!userPreferences.getConfig()?.allowInsecureCerts;
}

// RQ-2426: true only when the user has explicitly opted into DEV script mode
// (full host access for code rules). Defaults to false (safe sandbox).
export const getDevScriptMode = (): boolean => {
const userPreferences = new UserPreferenceFetcher();
return userPreferences.getConfig()?.devScriptMode === true;
}

export const getLocalFileLogConfig = () => {
const userPreferences = new UserPreferenceFetcher();
const { localFileLogConfig }= userPreferences.getConfig()
Expand Down
8 changes: 7 additions & 1 deletion src/renderer/services/storage-cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,14 @@ class StorageCacheService {
rqProxy.setAllowInsecureCerts(!!newUserPreferences?.allowInsecureCerts);
appliedLive = true;
}
// RQ-2426: apply the DEV script-mode toggle live on the running proxy too.
// Only an explicit `true` enables it (full host access); anything else is
// the safe sandbox.
if (rqProxy?.setDevScriptMode) {
rqProxy.setDevScriptMode(newUserPreferences?.devScriptMode === true);
}
} catch (e) {
console.log("Failed to apply allowInsecureCerts live", e);
console.log("Failed to apply allowInsecureCerts/devScriptMode live", e);
Comment on lines +49 to +56

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Ensure the fallback restart triggers if setDevScriptMode is unavailable.

Currently, appliedLive is set to true when setAllowInsecureCerts is present, regardless of whether setDevScriptMode exists. If an older proxy build has setAllowInsecureCerts but lacks setDevScriptMode, appliedLive will still evaluate to true, preventing the fallback proxy restart. This will cause the devScriptMode preference change to be silently ignored until the proxy restarts naturally.

To guarantee that the proxy restarts when any live update fails, appliedLive should only be true if both methods are available and applied successfully.

🐛 Proposed fix
-        let appliedLive = false;
+        let appliedLive = true;
         try {
           const rqProxy: any = RQProxyProvider.getInstance();
           if (rqProxy?.setAllowInsecureCerts) {
             rqProxy.setAllowInsecureCerts(!!newUserPreferences?.allowInsecureCerts);
-            appliedLive = true;
+          } else {
+            appliedLive = false;
           }
           // RQ-2426: apply the DEV script-mode toggle live on the running proxy too.
           // Only an explicit `true` enables it (full host access); anything else is
           // the safe sandbox.
           if (rqProxy?.setDevScriptMode) {
             rqProxy.setDevScriptMode(newUserPreferences?.devScriptMode === true);
+          } else {
+            appliedLive = false;
           }
         } catch (e) {
+          appliedLive = false;
           console.log("Failed to apply allowInsecureCerts/devScriptMode live", e);
         }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// RQ-2426: apply the DEV script-mode toggle live on the running proxy too.
// Only an explicit `true` enables it (full host access); anything else is
// the safe sandbox.
if (rqProxy?.setDevScriptMode) {
rqProxy.setDevScriptMode(newUserPreferences?.devScriptMode === true);
}
} catch (e) {
console.log("Failed to apply allowInsecureCerts live", e);
console.log("Failed to apply allowInsecureCerts/devScriptMode live", e);
// RQ-2426: apply the DEV script-mode toggle live on the running proxy too.
// Only an explicit `true` enables it (full host access); anything else is
// the safe sandbox.
if (rqProxy?.setDevScriptMode) {
rqProxy.setDevScriptMode(newUserPreferences?.devScriptMode === true);
} else {
appliedLive = false;
}
} catch (e) {
appliedLive = false;
console.log("Failed to apply allowInsecureCerts/devScriptMode live", e);
🤖 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 `@src/renderer/services/storage-cache.ts` around lines 49 - 56, Update the live
preference application flow around appliedLive, setAllowInsecureCerts, and
setDevScriptMode so appliedLive is true only when both methods exist and
complete successfully. If either method is unavailable or throws, preserve the
false state so the fallback proxy restart is triggered.

}

// Restart the proxy only when the port actually changed (or as a fallback
Expand Down