Skip to content

harden the ipc transport used by background jobs - #330

Open
kevinushey wants to merge 1 commit into
mainfrom
feature/ipc-hardening
Open

kevinushey wants to merge 1 commit into
mainfrom
feature/ipc-hardening

Conversation

@kevinushey

Copy link
Copy Markdown
Contributor

Hardens the file-based IPC that R processes launched by RStudio (background jobs, renders, and so on) use to call back into the IDE. Companion RStudio change to follow; this PR is independently releasable and is compatible with every RStudio version in either order.

What changes

Version 2 request format. When RStudio advertises support via RSTUDIOAPI_IPC_VERSION, callRemote() writes a plain-text ticket (magic line, version=2, secret=, id=) to the requests path and the serialized call to a sibling <requests>.payload file. The payload is written first and the ticket last, each via temp file + rename, so a complete ticket implies a complete payload. This lets RStudio verify the secret before deserializing anything. The response is list(id, value) or list(id, error); the client discards responses whose id doesn't match, so a stale response from a timed-out call can't be mistaken for the current one.

Fallback. Without RSTUDIOAPI_IPC_VERSION, the existing single-RDS format and bare response are used, so new rstudioapi works with older RStudio. Both paths now tolerate a partially written or stale response file by discarding it and continuing to poll until the timeout.

Secret scrubbed from the environment. .onLoad() moves RSTUDIOAPI_IPC_SHARED_SECRET into the rstudioapi.ipc.secret option and unsets it. Previously every process a job spawned (callr workers, compilers, package managers, shell tools) inherited a token that could evaluate arbitrary R in the IDE session. The request and response path variables are left in place, so isJob() and third-party job detection are unaffected. A spawned R process that tries to call rstudioapi now gets a clear error instead of silently reaching the IDE.

Tests

tests/testthat/test-remote.R runs callRemote() against a fake RStudio implemented in a background Rscript, covering the v2 ticket/payload layout and id matching, the v1 fallback, error propagation, timeout, missing credentials, and the .onLoad() scrub.

Verified end to end against an RStudio build with the server side of this change: a background job calling rstudioapi::versionInfo() succeeds via both the legacy and the v2 path.

Adds a version 2 request format used when RStudio advertises it via RSTUDIOAPI_IPC_VERSION: a plain-text ticket (secret + request id) with the serialized call in a sibling payload file, so RStudio can verify the secret before deserializing anything, and a response of list(id, value | error) so stale responses are discarded. Falls back to the existing format for older RStudio versions.

The shared secret is moved from the environment into an option when the package loads, so processes spawned by a job no longer inherit the ability to call into the IDE.

This branch has not been deployed

No deployments
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