fix(desktop): prevent proxy password mask corruption - #3704
Conversation
Generated-by: OpenAI Codex
b94e9ab to
c5ec403
Compare
jackwener
left a comment
There was a problem hiding this comment.
Reviewed exact head c5ec40335dcaa0d19756bff067bced9cf2cf687c. I found two blocking correctness issues in the new proxy-credential write path: one cross-client race that can recreate a credential after authentication was disabled, and one partial-commit path that applies proxy policy even though the API reports failure. The hosted checks are green and the branch merges cleanly, but these state-consistency issues need to be resolved before approval.
| else await setCredential(client, PROXY_CREDENTIAL, proxy.password); | ||
| } | ||
| else if (proxy.credential?.kind === "replace") | ||
| await setCredential(client, PROXY_CREDENTIAL, proxy.credential.secret); |
There was a problem hiding this comment.
[P1] Make proxy policy and credential replacement one Host-owned operation across clients. The new queue is local to one RuntimeHostSettingsModule, so two supported Desktop clients have independent lanes. Client A can start a replacement and pause at the credential CAS; client B can then set authEnabled=false and delete the credential; when A receives credential_stale, its retry rereads the now-empty locator and recreates the secret with expected: null. A production-adapter/CAS probe ended with authEnabled=false while the vault again contained A's replacement secret. The existing "disable wins" test uses one module and therefore cannot cover this inter-client ordering. Please move the policy decision plus keep/replace/delete into one Runtime Host atomic or recoverable operation that validates both the policy revision and credential basis, and add a two-client test asserting the vault remains empty after disable.
| ): Promise<void> { | ||
| if (patch.network?.proxy) { | ||
| const proxy = patch.network.proxy; | ||
| await client.updateRuntimePolicy((policy) => ({ |
There was a problem hiding this comment.
[P2] Do not commit proxy policy before the credential write can still fail. A normal update containing both policy fields and credential: replace/delete first commits set_network_proxy here, then performs vault persistence below. If that second step rejects, the caller receives an error even though the Host is already using the new host/auth/username with the old credential. This is also reachable from the schema-v1 settings-plus-credentials import path. A production-adapter failure probe observed the rejected call with enabled=true, authEnabled=true, username=new-user, and the old secret still stored; the success control stored the replacement. Existing failure coverage sends a credential-only patch, so it never checks policy after the failure. Please make this a single Host-side compound operation, or define an explicit recoverable commit protocol, and test each persistence cut for committed/unchanged/known recovery semantics.
Summary
Fixes #3696
Verification
npm run lintnpm run format:checknpm run buildnpm run typechecknpx knip --workspace apps/desktopnpx knip --workspace packages/uiAI use
Select exactly one:
Tool(s) and scope: OpenAI Codex implemented the fix, tests, verification, and review-driven corrections.
Checklist
Does this PR entail a change in behavior?