mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-25 00:01:55 +00:00
74f15e0e51
Round 2 caught that the app-side check was bound to the wrong surface. It checked the policy triggerables, on the premise that they are what `execute_component` resolves. That holds for `rawscript/<sha>`, which is why the raw-script refusal binds, but not for `script/`/`flow/`: in `ExecutionMode::Viewer` run mode falls back to a default triggerable for any such path, so a path absent from the map is invocable rather than forbidden, and the job runs as the viewer. A builder could therefore ship an app pointing at a runnable nobody granted them, and an admin who merely opened it would run it as themselves. - `ExecutionMode::Viewer` is refused for a builder-authored app. `Publisher` and `Anonymous` have no fallback, so the triggerables are exhaustive for them and the deploy-time checks below are an authorization boundary rather than advice. - The value's `runnableByPath` entries are authorized too. They are a separate surface from the policy: the deployed bundle resolves a `runnable_id` against the stored `runnables` and sends that path, so an app with an empty triggerables map still reaches one. Also from round 2: `check_flow_is_composition_only`'s doc now states what it actually returns, and the flow-side refs are deduped, so a flow stepping through one script thirty times stops issuing thirty round trips on every write, preview and dependency job. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>