feat: http triggers scopes (#7385)

This commit is contained in:
hugocasa
2025-12-16 20:46:45 +01:00
committed by GitHub
parent a9612165ab
commit 1a4f1e2d79
3 changed files with 59 additions and 37 deletions

View File

@@ -93,11 +93,11 @@ pub mod embeddings;
mod favorite;
mod flow_conversations;
pub mod flows;
mod folders;
mod folder_history;
mod folders;
mod granular_acls;
mod groups;
mod group_history;
mod groups;
#[cfg(feature = "private")]
pub mod indexer_ee;
mod indexer_oss;
@@ -661,43 +661,35 @@ pub async fn run_server(
#[cfg(not(feature = "oauth2"))]
Router::new()
})
.nest(
"/r",
.nest("/r", {
#[cfg(feature = "http_trigger")]
{
#[cfg(feature = "http_trigger")]
{
triggers::http::handler::http_route_trigger_handler()
}
triggers::http::handler::http_route_trigger_handler()
}
#[cfg(not(feature = "http_trigger"))]
{
Router::new()
}
}
.layer(from_extractor::<OptAuthed>()),
)
.nest(
"/gcp/w/:workspace_id",
#[cfg(not(feature = "http_trigger"))]
{
#[cfg(all(
feature = "enterprise",
feature = "gcp_trigger",
feature = "private"
))]
{
triggers::gcp::handler_oss::gcp_push_route_handler()
}
#[cfg(not(all(
feature = "enterprise",
feature = "gcp_trigger",
feature = "private"
)))]
{
Router::new()
}
Router::new()
}
.layer(from_extractor::<OptAuthed>()),
)
})
.nest("/gcp/w/:workspace_id", {
#[cfg(all(
feature = "enterprise",
feature = "gcp_trigger",
feature = "private"
))]
{
triggers::gcp::handler_oss::gcp_push_route_handler()
}
#[cfg(not(all(
feature = "enterprise",
feature = "gcp_trigger",
feature = "private"
)))]
{
Router::new()
}
})
.route("/version", get(git_v))
.route("/uptodate", get(is_up_to_date))
.route("/ee_license", get(ee_license))

View File

@@ -19,7 +19,7 @@ use crate::{
Trigger, TriggerCrud, TriggerData, TriggerMode,
},
users::fetch_api_authed,
utils::ExpiringCacheEntry,
utils::{check_scopes, ExpiringCacheEntry},
};
use axum::{
async_trait,
@@ -736,6 +736,8 @@ async fn get_http_route_trigger(
None
};
if let Some(authed) = opt_authed {
check_scopes(&authed, || format!("http_triggers:read:{}", &trigger.path))?;
// check that the user has access to the trigger
let cache_key = (
trigger.workspace_id.clone(),

View File

@@ -16,7 +16,13 @@
type TriggerMode
} from '$lib/gen'
import { usedTriggerKinds, userStore, workspaceStore } from '$lib/stores'
import { canWrite, capitalize, emptyString, sendUserToast } from '$lib/utils'
import {
canWrite,
capitalize,
emptyString,
generateRandomString,
sendUserToast
} from '$lib/utils'
import Section from '$lib/components/Section.svelte'
import { Loader2, Pipette, Plus } from 'lucide-svelte'
import Label from '$lib/components/Label.svelte'
@@ -49,6 +55,8 @@
import { deepEqual } from 'fast-equals'
import TriggerSuspendedJobsAlert from '../TriggerSuspendedJobsAlert.svelte'
import TriggerSuspendedJobsModal from '../TriggerSuspendedJobsModal.svelte'
import UserSettings from '$lib/components/UserSettings.svelte'
import Tooltip from '$lib/components/Tooltip.svelte'
let {
useDrawer = true,
@@ -118,8 +126,10 @@
let suspendedJobsModal = $state<TriggerSuspendedJobsModal | null>(null)
let originalConfig = $state<NewHttpTrigger | undefined>(undefined)
let userSettings = $state<UserSettings | undefined>(undefined)
let hasChanged = $derived(!deepEqual(getRouteConfig(), originalConfig ?? {}))
let scopes = $derived(['http_triggers:read:' + path])
const isAdmin = $derived($userStore?.is_admin || $userStore?.is_super_admin)
const routeConfig = $derived.by(getRouteConfig)
@@ -438,6 +448,15 @@
/>
{/if}
{#if authentication_method === 'windmill'}
<UserSettings
bind:this={userSettings}
newTokenWorkspace={$workspaceStore}
newTokenLabel={`http-${$userStore?.username ?? 'superadmin'}-${generateRandomString(4)}`}
{scopes}
/>
{/if}
{#if mode === 'suspended'}
<TriggerSuspendedJobsModal
bind:this={suspendedJobsModal}
@@ -858,6 +877,15 @@
</p>
</div>
{/if}
{:else if authentication_method === 'windmill'}
<Button size="xs" variant="default" on:click={() => userSettings?.openDrawer()}>
Create a route-specific token
<Tooltip light>
The token will have a scope such that it can only be used to read and
trigger this route. It is safe to share as it cannot be used to impersonate
you.
</Tooltip>
</Button>
{/if}
<RouteBodyTransformerOption