Skip to content

feat(start-sdk,start-os): tell an action who is running it - #4045

Merged
MattDHill merged 1 commit into
masterfrom
feat/action-caller
Sep 22, 2026
Merged

MattDHill merged 1 commit into
masterfrom
feat/action-caller

Conversation

@dr-bonez

@dr-bonez dr-bonez commented Sep 21, 2026 •

Copy link
Copy Markdown
Member

Summary

access: 'dependent' | 'public' decides whether another service may run an action through effects.action.run, but the action was never told which service that was. run_action used the caller's id for the access check and then forwarded only (procedure_id, action_id, input), so any identity an action needed had to come from its input — and a service allowed to call it could name another package there. That makes it impossible to write an action that lets a service act on its own resources and nothing else.

StartOS now forwards the caller, and the SDK hands it to the package.

  • Service::run_action and Service::get_action_input take caller: Option<PackageId>, carried through the RunAction / GetActionInput actor messages into the procedure's params beside input / prefill. The effects pass the calling service's id — including when a service reaches one of its own actions that way. The user's RPC passes None, and so do the two places StartOS reads a form itself to evaluate a task, since that form is the one the user will be shown.
  • The container runtime reads caller off the params and passes it to System.runAction / getActionInput. The 0.3.5 compat system takes it and ignores it.
  • The SDK adds caller: ActionCaller (PackageId | null) to the run handler, the prefill function and a function-valued input spec. Action.run / getInput take it as optional and normalise a missing one to null.
  • The value comes from the effect context the call arrived on, so a package cannot set or forge it.

No #[ts(export)] type or CLI surface changes, so there are no bindings or man pages to regenerate. SDK 3.0.0 already requires StartOS 0.4.0.2, which is where this lands, so a package that relies on caller cannot be installed on a server that does not send it.

The book gains Knowing Who Is Calling under Controlling Access, with the rule that identity comes from caller and never from the input. The SDK changelog has the entry; following #4037, nothing user-visible changes in StartOS itself.

First consumer: Start9Labs/tor-startos, to let a service add an onion address to one of its own bindings.

Verification

  • cargo check -p start-core and make start-core-format-check pass.
  • @start9labs/start-core: tsc clean; new actionCaller.test.ts covers a service caller, the user, a runtime that names nobody, and that the input spec, the prefill and run all see the same caller; the full suite passes (16 suites).
  • SDK: make bundle, make check, make test (124 tests) pass.
  • container-runtime: npm run check against the rebuilt bundle and npm test pass.
  • Prettier clean on the changed TS and Markdown.
  • Not exercised on a box: no end-to-end run of one service calling another's action.

Not in this PR

effects.action.getInput for another package's action is not gated by access the way run is — get_action_input in service/effects/action.rs dispatches straight to the target. A service can therefore read the form, prefill included, of an action it is not allowed to run. Forwarding the caller makes that more visible rather than worse, and closing it is a behaviour change that deserves its own decision, so it is left alone here.

`access` decides whether another service may run an action, but the
action was never told which service that was: run_action used the
caller's id for the access check and then forwarded only the action id
and the input. Any identity an action needed had to come from its input,
where a service allowed to call it could name another package, so an
action could not be limited to the caller's own resources.

StartOS now forwards the caller. Service::run_action and
Service::get_action_input take it, the actor messages carry it into the
procedure's params, the container runtime passes it on, and the SDK hands
it to the run handler, the prefill function and a function-valued input
spec as `caller`: a package id, or null for the user and for StartOS
reading a form to evaluate a task. It comes from the effect context the
call arrived on, so a package cannot set it.

SDK 3.0.0 already requires StartOS 0.4.0.2, which is where this lands.
@MattDHill
MattDHill merged commit 6e92bba into master Sep 22, 2026
41 checks passed
@MattDHill
MattDHill deleted the feat/action-caller branch September 22, 2026 19:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants