mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-10-16 00:03:02 +00:00
* feat: restricted job tokens (job_token_scopes on scripts and flows) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: admit flow-run reads, skip dedicated workers, gate on worker version Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: keep restricted jobs off flow runners, preserve scopes on rename and promotion Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: keep restricted jobs off every dedicated handoff, confine progress flow id Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: exclude restricted runnables from dedicated worker startup Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: gate restrictions on the release after 1.821.0 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: store per-job scopes on job_perms instead of v2_job, pin inline runs to the checked version Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: step-level job_token_scopes for flow steps and agent tools Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FHGE3ynoAu6yrgeg4kLwL * fix: fail closed on perms read errors, refuse restricted queue imports, gate step scopes in previews Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FHGE3ynoAu6yrgeg4kLwL * fix: carry a job's scopes on its completion so a re-run keeps the caller's cap Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FHGE3ynoAu6yrgeg4kLwL * fix: carry a zombie job's scopes into its completion Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FHGE3ynoAu6yrgeg4kLwL * fix: leave a zombie for the next sweep when its scopes cannot be read Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FHGE3ynoAu6yrgeg4kLwL * docs: correct the QueuedJobV2 completion comment Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FHGE3ynoAu6yrgeg4kLwL * fix: validate step scopes in batch flows, fail closed on unvalidated step scopes Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FHGE3ynoAu6yrgeg4kLwL * fix: refuse flows with step or tool restrictions at push while an older worker is live Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FHGE3ynoAu6yrgeg4kLwL * fix: apply the step-scope worker gate to flow restarts Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FHGE3ynoAu6yrgeg4kLwL * fix: list the job token toggle with the other step and flow settings Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FHGE3ynoAu6yrgeg4kLwL * chore: pin the EE companion merged with EE main Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FHGE3ynoAu6yrgeg4kLwL * perf: skip scope lookups for unrestricted jobs; list job token setting last Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FHGE3ynoAu6yrgeg4kLwL * style: rustfmt scopes tests Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FHGE3ynoAu6yrgeg4kLwL * fix: confine restricted job tokens to their own run lineage; drop remaining extra lookups Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FHGE3ynoAu6yrgeg4kLwL * chore: update ee-repo-ref to 259ad3bfeef5285ba80eedc86309b11dca001220 This commit updates the EE repository reference after PR #843 was merged in windmill-ee-private. Previous ee-repo-ref: 2b77c0225dca441235daf7bf0a06ba968df0c927 New ee-repo-ref: 259ad3bfeef5285ba80eedc86309b11dca001220 Automated by sync-ee-ref workflow. --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
77 lines
2.6 KiB
Rust
77 lines
2.6 KiB
Rust
use std::sync::Arc;
|
|
|
|
use axum::{extract::Path, routing::get, Extension, Json, Router};
|
|
use uuid::Uuid;
|
|
use windmill_common::{
|
|
db::UserDB,
|
|
error::{Error, JsonResult},
|
|
};
|
|
|
|
pub use windmill_api_jobs::concurrency_groups::{join_concurrency_key, workspaced_service};
|
|
|
|
use crate::{
|
|
auth::{AuthCache, Tokened},
|
|
db::{ApiAuthed, DB},
|
|
jobs::{require_job_read_access, OptViewToken},
|
|
};
|
|
|
|
pub fn global_service() -> Router {
|
|
windmill_api_jobs::concurrency_groups::global_service()
|
|
.route("/{job_id}/key", get(get_concurrency_key))
|
|
}
|
|
|
|
/// A concurrency key embeds the job's workspace, its runnable path and any
|
|
/// `$args[...]`-templated argument values, so reading one is gated on the same access as
|
|
/// reading the run itself. `ApiAuthed` is taken here rather than left to the router: this
|
|
/// service is nested after `route_layer(from_extractor::<ApiAuthed>())`, which only wraps
|
|
/// the routes present at its call site.
|
|
///
|
|
/// The route carries no workspace, so `authed` is not workspace-scoped (no groups, no
|
|
/// folders, `is_admin` only for superadmins). Re-resolve the caller's token against the
|
|
/// job's own workspace before evaluating access — that also rejects non-members, for whom
|
|
/// the job does not exist. Members reaching [`require_job_read_access`] get its 403, which
|
|
/// discloses existence only inside a workspace they belong to.
|
|
async fn get_concurrency_key(
|
|
_authed: ApiAuthed,
|
|
Tokened { token }: Tokened,
|
|
Extension(cache): Extension<Arc<AuthCache>>,
|
|
Extension(db): Extension<DB>,
|
|
Extension(user_db): Extension<UserDB>,
|
|
OptViewToken(view_token): OptViewToken,
|
|
Path(job_id): Path<Uuid>,
|
|
) -> JsonResult<Option<String>> {
|
|
let not_found = || Error::NotFound(format!("Job {job_id} not found"));
|
|
|
|
// A caller who cannot reach the job must not be able to tell it apart from a job
|
|
// that does not exist, so both answer with the same 404.
|
|
let job = sqlx::query!(
|
|
"SELECT workspace_id, created_by FROM v2_job WHERE id = $1",
|
|
job_id
|
|
)
|
|
.fetch_optional(&db)
|
|
.await?
|
|
.ok_or_else(not_found)?;
|
|
|
|
let authed_in_workspace = cache
|
|
.get_authed(Some(job.workspace_id.clone()), &token)
|
|
.await
|
|
.ok_or_else(not_found)?;
|
|
windmill_api_auth::check_job_token_scope(&authed_in_workspace, || "jobs:read".to_string())?;
|
|
|
|
require_job_read_access(
|
|
&db,
|
|
&user_db,
|
|
&authed_in_workspace,
|
|
&job.workspace_id,
|
|
&job_id,
|
|
&job.created_by,
|
|
view_token.as_deref(),
|
|
)
|
|
.await?;
|
|
|
|
let key = sqlx::query_scalar!("SELECT key FROM concurrency_key WHERE job_id = $1", job_id)
|
|
.fetch_optional(&db)
|
|
.await?;
|
|
Ok(Json(key))
|
|
}
|