Repository navigation
node-api: remove WorkerApi and BuilderApi RPCs that have no caller - #1213
Merged
Merged
Conversation
|
Thanks for opening this pull request! A SPACE maintainer will take a look. CONTRIBUTING.md explains how we review outside contributions. |
An explicit or implicit wake for a sandbox with no loaded row called the public WorkerApi.WakeSandbox, the only caller of that RPC. Send it to WorkerApiInternal.WakeSandbox instead, which tracked Direct and Kubernetes wakes already use, so the public twin can be removed. The request is unchanged: no start context, no runtime upgrade, blocking, and the implicit wake source for an implicit wake. The internal handler requires control-plane policy authority only for a runtime upgrade or an activation auto-lifecycle policy, so this request needs none, and the api already holds the internal-surface credential its tracked wakes use. A characterization test serves only WorkerApiInternal on the placed worker and checks that both wakes arrive there under the internal bearer with the same fields. It failed with HTTP 501 (UNIMPLEMENTED) before the change.
WorkerApi becomes a 1.x-stable contract at 1.0, and 0.9 is where breaking changes consolidate. Remove 17 relays nothing calls: - GetSandboxHealth, ListSandboxes, SpacedPingGuest - WakeSandbox (the public twin; WorkerApiInternal.WakeSandbox stays) - EnableSnapshots, DisableSnapshots, DeleteSnapshots - ListTemplates, GetTemplate, UpdateTemplateSettings, UpdateTemplateSnapshotPolicy, CreatePool, DeletePool, PoolStatus - UnexposePort, DenyPort - RefreshFacetState Their functions are served elsewhere: template, snapshot, port and facet state arrive through node-ctl facets that call the node services over local sockets, the node-local CLIs cover operator use, and control-plane wakes use WorkerApiInternal.WakeSandbox. Protobuf services cannot reserve names, so worker.proto lists the retired names in a comment. Every message stays: each is imported from an internal package or shared with another service. Delete the node-api handlers, the simulator's handlers, the client-crate wrappers, SpacedPingGuest from the guest-bridge allowlist, and the public wake guards only the removed handler used. Tests that named a removed method now use one that remains, the runtime-upgrade wake test covers the internal service only, and the template and policy authorization tests cover the pool and settings RPCs on the builder only. Docs and the Kind chart comment no longer list worker pool mutation or a public Wake. A caller outside this repository that calls a removed RPC now gets UNIMPLEMENTED.
Remove 12 BuilderApi relays nothing calls: - SandboxState, ListSandboxes, StopSandbox, DeleteSandbox - ListTemplates, GetTemplate, UpdateTemplateSettings, UpdateTemplateSnapshotPolicy, CreatePool, DeletePool, PoolStatus - RefreshFacetState The api's sandbox calls use the worker runtime client, and the template calls were reached only through the TemplateController wrappers the previous change deleted. On a builder node, template state arrives through node-ctl's template facet, which calls template-manager over its local socket, the node-local CLIs cover operator use, and node-ctl serves RefreshFacetState itself. BuilderApi keeps BuildTemplate, GetBuildTemplateStatus, UploadBuildBlob, TriggerStateReconciliation, DeleteTemplate, DeleteTemplateBuild, PullTemplate, NodeExportTemplate and ListNodeTemplates, and stays a separate service. builder.proto lists the retired names in a comment, since services cannot reserve them, and drops the sandbox-manager import it no longer uses along with the node/v1 import nothing in it used. Delete the node-api handlers, their restart-handoff forwarding macro, the client-crate wrappers and node-api's now-unused node-ctl refresh_facet_state helper. The policy authorization test loses its builder settings case, the template authorization test its pool cases, and the peer-node test names a builder method that remains. Docs no longer list builder pool or settings authority. A caller outside this repository that calls a removed RPC now gets UNIMPLEMENTED.
ac-pplx
force-pushed
the
ac/node-api-delete-unused-workerapi-rpcs
branch
from
October 31, 2026 01:08
6a53667 to
746b5f6
Compare
Removing the unused WorkerApi and BuilderApi RPCs left text that still described them. This updates comments, one error message, proto comments and docs. Behaviour does not change. - worker.rs: the require_policy_mutation_authority doc now lists the requests it gates: the two policy setters; CreateSandbox and AdoptPoolSandbox with a policy override or nonzero generation; an activation auto-lifecycle policy on StartSandbox, ResumeSandbox or the internal Wake; and the internal Wake's runtime upgrade. The function is now private, since only worker.rs calls it. The empty template-pools section header is gone. - auth: the k8s.rs comments say a worker serves the policy RPCs and both roles gate template deletion on the trusted policy allowlist. The TrustedPolicyServiceAccountsMissing message no longer calls the builder policy-serving. - worker.proto: the WorkerApi and WorkerApiInternal descriptions match what each service now serves. Rust stubs are generated at build time, so no generated file changes. - simulator: the sim_wake doc names WorkerApiInternal only, "ping" is gone from two comments, and SimState::list is test-only. - docs: the pool-target capacity note moves from the template mutation authority section of configuration.md to warm-pools.md, where targets are set. - untracked_wake_uses_the_internal_worker_wake writes its own token files, so its bearer check can tell the two credentials apart even on a host that has the default token files.
ac-pplx
marked this pull request as ready for review
October 31, 2026 03:37
Collaborator
Review — 4 findingsMedium
Low
Verified against
I relied on CI for compile, clippy, tests and the Kind shards (all green at this head) and didn't rebuild locally. |
the-gigi-pplx
approved these changes
Oct 31, 2026
the-gigi-pplx
left a comment
Collaborator
There was a problem hiding this comment.
Approved. 4 non-blocking findings in the review comment above.
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
space.node.api.v1.WorkerApibecomes a 1.x-stable contract at 1.0, and docs/versioning.md consolidates breaking changes at 0.9.0. This removes 29 node-api relays that nothing in this repository calls, so they don't get frozen into that contract: 17 on WorkerApi and 12 on BuilderApi. No code, script, chart or doc in this repository calls any of them. #1156 already deleted the unreachable api-crate wrappers that reached some of them.Four commits:
WorkerApiInternal.WakeSandbox. An explicit or implicit wake for a sandbox with no loaded row (untracked_actionincrates/libs/api/src/controllers/sandbox/lifecycle.rs) was the only caller of the publicWorkerApi.WakeSandbox. It now usesWorkerApiInternal.WakeSandbox, as tracked Direct and Kubernetes wakes already do. No production caller reaches this path: every caller ofSandboxController::actionpasses the loaded row, so only tests send the untracked wake. The commit keeps that path working against the internal service.require_policy_mutation_authoritynow lists every request it gates, and the function is now private.TrustedPolicyServiceAccountsMissingstartup message no longer describe the builder as serving policy RPCs.WorkerApiandWorkerApiInternalservice descriptions inworker.protomatch what each service now serves.SimState::listis test-only.docs/configuration.mdtodocs/warm-pools.md.Protobuf services cannot
reservenames, and the repository has no proto lint or retired-RPC convention. Each service inworker.protoandbuilder.prototherefore lists its retired names in a comment, marked as retired in 0.9.0. No message type was deleted: every request and response is imported from an internal package or shared with another service (RefreshFacetState*is still served by NodeCtl).builder.protoalso drops its now-unused sandbox-manager import, along with anode/v1import nothing in it used.Each removal deletes the node-api handler, the simulator handler (WorkerApi only; the simulator has no BuilderApi), and the
pplx-space-node-api-clientwrapper. It also removes:SpacedPingGuestfrom the guest-bridge allowlist (auth/k8s.rs).refresh_facet_statehelper.Docs (
docs/configuration.md,docs/execution-environments.md), the Kind README auth table and the node-api chart comment no longer describe the removed authority or a public Wake. The contract list indocs/versioning.mdis unchanged.Removed from WorkerApi, and where each function is served
WakeSandbox(public twin)WorkerApiInternal.WakeSandbox(unchanged), used by every control-plane wakeGetSandboxHealth,ListSandboxesspace-sbxmgron the node; control-plane state comes from node-ctl's published sandbox states andSandboxState(kept)SpacedPingGuestSpacedGetStatus(kept; an operator script uses it) andSpacedWaitReadyEnableSnapshots,DisableSnapshotsspace-sbxmgrfor operatorsDeleteSnapshotsspace-sbxmgr snapshotson the node (no control-plane path)ListTemplates,GetTemplate,UpdateTemplateSettings,UpdateTemplateSnapshotPolicy,CreatePool,DeletePool,PoolStatusspace-tmplmgrfor operatorsUnexposePort,DenyPortspace-nodemgr unexpose/denyRefreshFacetStatespace-nodectlRemoved from BuilderApi, and where each function is served
SandboxState,ListSandboxes,StopSandbox,DeleteSandboxspace-sbxmgron the builder; build sandboxes are internal to template-manager and the builderListTemplates,GetTemplate,UpdateTemplateSettings,UpdateTemplateSnapshotPolicy,CreatePool,DeletePool,PoolStatusspace-tmplmgr. The api reached these only through the TemplateController wrappers #1156 deletedRefreshFacetStatespace-nodectlBuilderApi keeps
BuildTemplate,GetBuildTemplateStatus,UploadBuildBlob,TriggerStateReconciliation,DeleteTemplate,DeleteTemplateBuild,PullTemplate,NodeExportTemplateandListNodeTemplates. Nothing onWorkerApiInternal,NodeInfo, or the internal services (SandboxManager, TemplateManager, NodeManager, NodeCtl) changes.Migration for 0.9
A custom control plane calling node-api directly should:
WorkerApiInternal.WakeSandbox. It is served on the same worker listener asWorkerApibut takes the worker's internal credential, not the oneWorkerApitakes. With Kubernetes token auth, use a token for audiencespace-node-api-internalfrom a service account listed inSPACE_NODE_API_INTERNAL_AUTH_ALLOWED_SERVICE_ACCOUNTS(SPACE's own clients read it fromSPACE_NODE_API_INTERNAL_TOKEN_PATH). With static tokens, useSPACE_INTERNAL_CONTROL_TOKEN; this surface refusesSPACE_INTERNAL_TOKEN. A runtime upgrade, or a start context that carries an activation auto-lifecycle policy, also needs control-plane policy authority: with Kubernetes token auth, an account inSPACE_NODE_API_AUTH_TRUSTED_POLICY_SERVICE_ACCOUNTS; static tokens carry it only when Kubernetes auth is off.ClusterApi.PublishNodeState), or withspace-sbxmgr liston the node, instead ofListSandboxes.SandboxStatereads sandboxes whose IDs you already have. Usespace-sbxmgr healthon the node instead ofGetSandboxHealth, andSpacedGetStatusorSpacedWaitReadyinstead ofSpacedPingGuest.space-sbxmgr snapshotson the node; no control-plane path replacesDeleteSnapshots.A caller that node-api admits gets
UNIMPLEMENTEDfrom a removed method. The auth layer answers first, so accounts restricted by method (the guest-bridge and peer-node accounts) getPERMISSION_DENIED, as for any other method outside their allowlist; for example, the guest-bridge account now getsPERMISSION_DENIEDforSpacedPingGuest.Validation
At this head (
3451e73a, on main atc83b7b9e):cargo check --workspace --all-features --all-targets: exit 0, no warnings. The build regenerated no tracked file; nothing generated fromworker.protois checked in.bash ci/scripts/run-rust-checks.sh clippy: exit 0.cargo arch: exit 0.cargo nextest run --all-features --no-fail-fast -p pplx-space-db-test-fixtures -p pplx-space-common-svc -p pplx-space-node-api-server -p pplx-space-node-api-sim -p pplx-space-node-api-client -p pplx-space-api, with the nextest Postgres and Redis setup scripts: 2461 passed, 0 failed, 1 skipped (a default-ignored test), no dependency skips.controllers::sandbox::lifecycle::characterization_tests::untracked_wake_uses_the_internal_worker_wake.WorkerApiInternalon a placed Direct worker and checks that an explicit and an implicit untracked wake arrive there with the same fields under the internal bearer. It writes its own token files, so the bearer check tells the two credentials apart on any host.UNIMPLEMENTED); with commit 1 it passes. Run by name at this head, its child test process ran against Postgres, so it did not skip.bufconfig, no proto lint in CI). This is a breaking wire change by design.Kind / Firecracker smoke, all four shards, passed in this head's pull-request run. None of the Kind scenarios reaches the untracked wake; only the new characterization test does.Severity and risk
Severity: low. This removes unused API surface before the contract freezes; no in-repo behaviour changes except where the untracked wake is sent.
Risk: a custom control plane outside this repository that calls a removed RPC gets
UNIMPLEMENTED; nothing in this repository does. The only changed code path is the untracked wake, and only tests reach it. Rollback is reverting this PR.Rollout
Any deploy order works:
WakeSandbox, and no production request reaches it.WorkerApiInternal.WakeSandbox, which old node-apis already serve.AI assistance: Claude Code wrote the code changes, the tests and this description.