relay-node: node-scoped workspace credentials (sh_wk_) through Control's broker
Merged
AG
10h ago+2163+2163+0123456789012345678901234567890123456789-120-120-012345678901234567890123456789
Acceptance side of the node-scoped workspace credential (sh_wk_). Contract: relay-control main 1e55273 (#83) and its docs/relay-node-credential.md; the issuing side is layered-control's.
What changes
- An
sh_wk_key is a workspace credential bound to one spawn node name. Itsworkspaces.jsonentry (and project pin) carriescontrol_url/controlUrlbesidebase_urland is refused without a bare https one. A node key is never accepted from an environment variable. - One routing helper sends the node's workspace-key calls (workspace identity, node lookup and enrolment, agent lookup) to
<control_url>/relay-node/v1; the SDK transport refuses to send ansh_wk_key anywhere else, so other calls are unavailable and the credential never reaches Relaycast. The report-back requester asks with the enrolled node token. - Broker errors: 401
token_invalidrejects the credential; 403scope_deniedis unavailable and rejects nothing; 403node_mismatchstops the spawn node with a log line naming the configured node; 502relaycast_unavailableis retried as an outage; Relaycast's own answers pass through as today. - An
rk_/ar_ws_tosh_wk_change on the same workspace is a rotation that keeps the enrolled node. - Workspace-key env vars are stripped from every spawned child (claude, grok, opencode, managed sessions);
sh_wk_joins the request-log and activity redaction lists.
Contract gaps for the issuing side
- The broker must answer with Relaycast's envelopes (
{"ok":false,"error":{code,message}}/{"ok":true,"data":…}); the node parses nothing else. - Relaycast must accept a node token on
GET /v1/actions/spawn/invocations/{id}(report-back). - The token's
nodeNamemust equal the node's configurednode_name; a mismatch stops the node.
Open questions
- Should a passed-through Relaycast 403 mark an
sh_wk_workspace Rejected, or stay unavailable likescope_denied? - Confirm an
sh_wk_tosh_wk_rotation keeps the enrolled node (implemented that way).
Tests
workspace/cli/tests.rs: store entry carries its origins; a workspace key ignores control_url; refused at load without control_url; non-https refused; project pin beside controlUrl; refused from every env var by name. Groups run from the built test binary on the agent host (env -u SSL_CERT_FILE -u SSL_CERT_DIR).
Merge on Khaliq's word via lead-desktop.
🤖 Generated with Claude Code
![Autofix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png)
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.