Repository navigation
data-plane: serve Native files:stat, files:list and files:read - #1372
Merged
Merged
Conversation
This was referenced Nov 3, 2026
nikhilbirmiwal-pplx
approved these changes
Nov 3, 2026
nikhilbirmiwal-pplx
left a comment
Member
There was a problem hiding this comment.
Approving. I checked the request order (authorize from headers first, then body and field checks, then prepare, then the worker call), the reconnect rules against space-api's spaced_client_call! and spaced_stream_open_call!, the read streaming and mid-stream abort, refusal pass-through, the RPC failure mapping, and the should_reconnect_stream_open move. They match space-api, and I found nothing blocking.
Two non-blocking notes:
native_files/call.rs:167: on a failure that isn't retried, the pooled channel to the endpoint is kept. That covers a budget timeout, and on stat a transport close. space-api retires its kept connection in both cases (retire_after_call_failure), and the ECW paths callforget_endpointon transport failures. Keepalive on the node-api endpoint limits how long a half-open connection lingers, but callingforget_endpointonTimedOutand onis_transport_close_statuswould match the API.native_files.rs:110/read.rs:82: owner scope runs before the body is read, so a malformed body or a baddepthsent to a missing or foreign sandbox gets a 404. space-api returns 400/415/422 there, because itsJsonextractor andlist_depthrun beforeensure_sandbox_owner. This follows from the authorize-before-body design and only affects requests that fail either way, but it is a parity difference the parity table doesn't cover.
NancyKwongPerplexity
force-pushed
the
data-plane-native-file-access-authz
branch
from
November 3, 2026 19:40
c38e35f to
fe9375c
Compare
NancyKwongPerplexity
force-pushed
the
data-plane-native-files-read
branch
from
November 3, 2026 19:40
52a2c5e to
5d6bfac
Compare
NancyKwongPerplexity
force-pushed
the
data-plane-native-file-access-authz
branch
from
November 3, 2026 21:53
fe9375c to
d078cb5
Compare
Add the Native read file routes to the data plane behind SPACE_DATA_PLANE_NATIVE_FILES=off|serve (default off, which leaves them unmounted). They are mounted under /v1 and /api/v1, as on space-api. space-api keeps every decision. Each request is authorized from its headers alone through AuthorizeNativeFileRequest on space-api's activation listener (SPACE_INGRESS_ACTIVATION_ENDPOINT, Cluster bearer) before its body is read. Its body is then checked with the shared pplx-space-native-files rules. PrepareNativeFileCall then wakes the sandbox and grants its route, and the worker call goes straight to the granted runtime with the grant's route token. A refusal from either RPC is answered exactly as space-api rendered it. The data plane answers the rest as space-api does: - framework rejections (415/400/422/413, 405 after authorization) in the Native envelope; - sandbox failures through the shared files mapping; - the spaced client's reconnect rules: a unary call reaches the runtime again once, through a fresh preparation, when the node-api drains, and a stream open also after a closed connection; - files:read streams and aborts its body on a mid-stream failure. An API that cannot answer is a retryable Native 503. Supporting changes: - pplx-space-public-api-http exposes normalize_public_error, which normalizes one response, so forwarded refusals stay untouched. - The stream-open transport-close check moves from space-api's spaced client into pplx-space-node-api-client so both servers share it.
NancyKwongPerplexity
force-pushed
the
data-plane-native-files-read
branch
from
November 3, 2026 22:27
5d6bfac to
7af744f
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Lets the data plane answer Native
files:stat,files:listandfiles:read, under/v1and/api/v1as space-api mounts them. A new setting,SPACE_DATA_PLANE_NATIVE_FILES=off|serve, controls it. It defaults tooff, which leaves the routes unmounted, so merging this changes nothing until a deployment setsserveand routes traffic to the data plane.space-api keeps every decision; the data plane carries the bytes. For each request the data plane:
SPACE_INGRESS_ACTIVATION_ENDPOINT, Cluster bearer) to authorize it withAuthorizeNativeFileRequest, from its headers alone, before reading the body (api: serve native file access RPCs on the activation listener #1365).pplx-space-native-filesrules: the same extractor rejections, field checks and messages as space-api's handlers.PrepareNativeFileCallfor the sandbox's route. space-api runs its drain gate, admission charge and wake, and grants the runtime endpoint and route token.WorkerApion that runtime with the grant's route token, and maps a failure with the shared files mapping.A refusal from either RPC is answered byte for byte as space-api rendered it. The data plane also matches space-api in these cases:
Allow: POST, after authorization, in the Native envelope.PrepareNativeFileCall, as space-api's spaced client reconnects. A stream open (list, read) is also retried after a closed connection.files:readstreams the chunks, and a mid-stream failure aborts the body.UNIMPLEMENTED), gets a retryable Native 503service_unavailablewithRetry-After: 1. space-api has no such case, because it is the API.Two small supporting changes:
normalize_public_error:pplx-space-public-api-httpgains this function, which normalizes a single response. The data plane uses it for framework rejections, leaving forwarded refusals as rendered. The middleware calls it, unchanged in behaviour.pplx-space-node-api-client(should_reconnect_stream_open), so both servers retry on the same statuses. space-api's existingstream_open_retry_*tests cover the move.Validation
At this head (
5d6bfac4), onmainat0271415a:main;git range-diffshows only these:data/plane/server/src/lib.rs:main(data-plane: record request latency by route #1356) added aroute_layerthat times each routed request..merge(native_files)now comes before it, so the Native files routes are timed like the other data-plane routes when they are served.data/plane/server/Cargo.toml:mainalready addstonic-prostto the dev-dependencies, so this PR no longer adds it. ItsCargo.lockline goes with it.cargo fmt --all -- --check,scripts/generate-env-contract.sh --check,scripts/check-rust-error-policy.shandscripts/source_guards/env_test_hook_boundary.pypass.cargo clippy --locked --all-targets --all-features -p pplx-space-data-plane-server -p pplx-space-data-plane-svc -p pplx-space-node-api-client -p pplx-space-public-api-http -p pplx-space-api -- -D warningspasses.cargo check --workspace --all-targets --lockedpasses.cargo archagainstmain's baseline, renames andARCHITECTURE.toml: 0 required findings and 112 advisory, the same findings asmain.cargo nextest run --config 'profile.test.package.pplx-space-api.opt-level=0' --all-features --all-targets, one package at a time, with Postgres and Redis from the nextest setup scripts andSPACE_CI_REQUIRE_TEST_DEPS=1:pplx-space-api2189 passed, 1 skipped;pplx-space-data-plane-server402 passed;pplx-space-data-plane-svc7 passed;pplx-space-node-api-client28 passed;pplx-space-public-api-http9 passed;pplx-space-native-files2 passed.The new tests run the real data-plane router against a scripted
NativeFileAccessApiand a fakeWorkerApiruntime, over TCP. Each was mutation-checked: I applied the change, rebuilt, saw the test fail, and reverted.reads_answer_through_the_granted_route_in_the_apis_shapesa_refused_request_is_answered_as_the_api_rendered_iteach_failure_answers_as_the_api_answers_itcode, message,retryable,details,Retry-AfterandAllowspace-api's route gives. The expected values come fromfiles.rs,normalize_public_error_responseand the mappingfiles/tests.rspins. Classes: framework rejections (400/413/415/422/405), field checks, every gRPC code, storage full, refused-before-start hints, guest missing path, list entry capa_draining_runtime_is_reached_again_through_a_fresh_preparationa_read_that_fails_mid_stream_aborts_its_bodyan_api_that_cannot_answer_is_a_retryable_503Retry-After: 1. InvalidArgument gives a 500UNIMPLEMENTEDas a 500the_routes_are_mounted_only_when_servednative_files_are_off_unless_served,native_files_are_served_from_the_environmentSPACE_DATA_PLANE_NATIVE_FILESparseoffandserve, defaultoff, and reject other valuesservestream_open_retry_*(existing)should_reconnect_stream_openNot validated here: a real space-api and runtime behind the data plane. The Kind run at PR 11's head (
smoke-native-files-data-plane) covers that.Severity and risk
Severity: does not apply (new, off by default).
Risk:
serve: the files paths stop reaching the data plane's ECW fallback.off, or revert this PR.Rollout
serveneedsSPACE_INGRESS_ACTIVATION_ENDPOINTset to space-api's activation listener. Without it the data plane refuses to start.SPACE_CLUSTER_API_AUTH_ALLOWED_SERVICE_ACCOUNTS(auth: let the data-plane identity call the native file access RPCs #1371 lets it call the two RPCs).UNIMPLEMENTED, which the data plane turns into a retryable 503. Keep traffic on space-api until both are upgraded.serveanswers only stat, list and read. Route no other files paths to the data plane.Stack
This is PR 6 of 12 and is based on
data-plane-native-file-access-authz(#1371). Merge in order:native-files-shared-requestnative-files-shared-handlingnative-error-rendering-sharednative-file-access-rpcsdata-plane-native-file-access-authzdata-plane-native-files-mutationsdata-plane-native-files-writedata-plane-native-files-drainkind-native-files-data-planesmoke-native-files-data-planedocs-native-files-data-planeNot covered
docs/configuration.mdanddocs/architecture.mddescribe the setting in PR 12.public_api.responsefrom the data plane, notsandbox.api.*.AI assistance: Claude Code drafted the code, tests, and this description; the author reviewed them.