mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-20 16:02:19 +00:00
d6c642b170
* feat: add Azure Event Grid triggers (EE)
Introduces a new enterprise trigger kind `azure` that supports three
modes via a single unified trigger type:
- basic_push: Azure Event Grid basic — custom topics, system topics
(Storage, Resource Manager, Key Vault, etc.), domains (push only)
- namespace_push: Event Grid Namespace topics (CloudEvents over HTTP push)
- namespace_pull: Event Grid Namespace topics (HTTP pull with lock-token
ack/reject for dead-lettering)
Auth uses a Service Principal resource (tenant_id, client_id,
client_secret, subscription_id). Subscriptions are created in
CloudEvents 1.0 schema so the push webhook handler and the pull listener
share one payload parser.
Backend
- New crate `windmill-trigger-azure` (OSS stubs + EE impl symlinked from
windmill-ee-private)
- Migration `azure_trigger` table with CHECK constraints enforcing
mode/columns coherence
- `TriggerKind::Azure`, `JobTriggerKind::Azure`,
`DeployedObject::AzureTrigger` variants
- Push route `/api/azure/w/{workspace}/*path` handles classic
Event Grid SubscriptionValidation handshake and CloudEvents 1.0
abuse-protection OPTIONS handshake
- Optional inbound JWT validation (audience check only for v1)
- Feature flag `azure_trigger` propagated through windmill-api,
windmill-store (resource helper), and added to ee_core
Frontend
- `triggers/azure/` editor with mode toggle (basic/namespace-push/
namespace-pull) and per-mode config (topic ARM id / namespace +
topic name / subscription / filters / push auth / pull options)
- Registered in icon map, display names, save functions, badge,
wrapper, editor, add-trigger menu
OpenAPI
- `AzureTrigger`, `AzureTriggerData`, `AzureMode`,
`AzureSubscriptionMode`, `AzureDeliveryConfig`, `TestAzureConnection`
schemas; `/azure_triggers/*` endpoints; client regenerated
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore: update ee-repo-ref to eaa7c3a9cb37a9ccc93f10a2535d929365acd2d8
This commit updates the EE repository reference after PR #541 was merged in windmill-ee-private.
Previous ee-repo-ref: 9689014e8c12c36c1059fd8fa5758d550b8b8bc9
New ee-repo-ref: eaa7c3a9cb37a9ccc93f10a2535d929365acd2d8
Automated by sync-ee-ref workflow.
* feat(azure-trigger): secret-auth push, ARM discovery, capture isolation, CLI + parity
Frontend:
- Split mode selector into Namespace/Basic + Pull/Push
- ARM resource dropdowns (namespaces, Basic topics, namespace topics)
populated from the service principal; cascade with stale-selection
reset on SP / edition change
- Remove stale authenticate toggle + audience input (server-managed
push_auth_config has replaced them)
- Azure listing page: "Create from template" button; "Also delete Azure
subscription" toggle in the delete modal; simplified trigger label
falling back to path
- AzureCapture.svelte: "Test subscription name" with -wm-capture suffix
- CompareWorkspaces.svelte: wire Azure for fork/compare
- Drop Trigger-deployed/event-loss warning (capture subscription is
isolated with -wm-capture)
Backend:
- Shared-secret push auth (see EE crate for detail)
- JSONB push_auth_config column (renamed from delivery_config), #[serde(skip)]
so clients/CLI/exports never see it
- Drop redundant enabled column; mode supersedes
- Azure capture infra: AzureTriggerConfig + set_azure_trigger_config +
azure_payload route + TriggerKind::Azure arm; PT15M queue TTL on
capture subscriptions so they bound storage after tab close
- Granular ACLs, users offboarding, trash, git-sync deployed-object:
all include azure_trigger
CLI:
- Add azure to TRIGGER_TYPES, pushObj dispatch, getTypeStrFromPath,
trigger commands (get/update/create/list/template), sync delete
switch + regex; e2e test for `trigger new --kind azure`
- system_prompts: SCHEMA_MAPPINGS + schema_names include AzureTrigger;
auto-generated/* regenerated
Skill:
- .claude/skills/adding-a-trigger/ checklist covering every file that
needs editing when wiring a new trigger type (learned from this PR)
ee-repo-ref bumped to b0e490cbf3724b7b64c6a5b010e3bdf24acd873c.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(azure-trigger): ci — ShareModal Kind + regenerated system_prompts
- frontend/src/lib/components/ShareModal.svelte: add 'azure_trigger'
to the Kind type so the listing page's "Permissions" action compiles
(ts2345 — caught by npm_check on CI, missed by fast-check locally).
- system_prompts/auto-generated/: regenerate to drop the stale
delivery_config / AzureDeliveryConfig fields from the Azure schema
(check-freshness on CI).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* refactor(azure-trigger): use workspace constant_time_eq crate
Drop hand-rolled constant-time compare in favour of the workspace
constant_time_eq crate (same one used by http_trigger_auth).
ee-repo-ref bumped to 9659382d47286e7f7f66d01b6f5dd8d4ed34848b.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(azure-trigger): pass placeholder + disabled via inputProps
`TextInput`'s `placeholder` and `disabled` go through its `inputProps`
prop — CI's `npm run check` caught the stale top-level passing that
`npm run check:fast` missed. Align with the DefaultEmailConfigSection
pattern.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(azure-trigger): correct LATEST_GIT_SYNC_SCRIPT_PATH version to 28213
The hub deploy of the azure-aware sync-script is version 28213, not
28214. Backend was pinning a non-existent hub script, which broke the
git_sync_e2e suite (every deploy's sync step 404'd).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(azure-trigger): add azure_triggers to token scope selector + skill
- windmill-api/src/token.rs: `build_trigger_scope_domains` was missing
`("azure_triggers", "Azure Event Grid")`, so the CreateToken UI's scope
selector didn't surface azure_triggers:read/write. Backend already had
`ScopeDomain::AzureTriggers` wired (scopes.rs), this just exposes it.
- .claude/skills/adding-a-trigger/SKILL.md: capture both scope-related
files under the hardcoded-arrays section so future triggers don't miss
the UI surface.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs(adding-a-trigger-skill): clarify token.rs scope effect
Not a regression — nothing was working before. Skipping TRIGGER_DOMAINS
just means the scope works via API/CLI but has no UI checkbox.
* docs(adding-a-trigger-skill): trim token.rs bullet
* fix(azure-trigger): regen openapi-deref + swap textarea for TextInput
- Run build_openapi.sh to regenerate openapi-deref.{yaml,json} with the
12 azure_triggers paths + schemas. These files are served by the
runtime (include_str! in windmill-api/src/lib.rs) to external SDK
consumers; without this regen the new endpoints wouldn't be advertised.
- Replace the raw <textarea> for event type filters with the
design-system TextInput in textarea mode (frontend/CLAUDE.md bans raw
HTML elements).
Addresses cubic + claude PR review items.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
189 lines
9.8 KiB
TOML
189 lines
9.8 KiB
TOML
[package]
|
|
name = "windmill-api"
|
|
version.workspace = true
|
|
authors.workspace = true
|
|
edition.workspace = true
|
|
|
|
[lib]
|
|
name = "windmill_api"
|
|
path = "src/lib.rs"
|
|
|
|
[features]
|
|
default = []
|
|
private = ["windmill-audit/private", "windmill-common/private", "windmill-api-auth/private", "windmill-store/private", "windmill-api-users/private", "windmill-api-workspaces/private", "windmill-api-groups/private", "windmill-api-configs/private", "windmill-api-settings/private", "windmill-api-agent-workers?/private", "windmill-trigger-kafka?/private", "windmill-trigger-postgres?/private", "windmill-trigger-mqtt?/private", "windmill-trigger-websocket?/private", "windmill-trigger-nats?/private", "windmill-trigger-sqs?/private", "windmill-trigger-gcp?/private", "windmill-trigger-azure?/private", "windmill-trigger-email?/private", "windmill-git-sync/private", "windmill-autoscaling?/private"]
|
|
enterprise = ["windmill-queue/enterprise", "windmill-audit/enterprise", "windmill-git-sync/enterprise", "windmill-common/enterprise", "windmill-worker?/enterprise", "windmill-api-auth/enterprise", "windmill-store/enterprise", "windmill-api-jobs/enterprise", "windmill-api-scripts/enterprise", "windmill-api-flows/enterprise", "windmill-api-users/enterprise", "windmill-api-workspaces/enterprise", "windmill-api-groups/enterprise", "windmill-api-configs/enterprise", "windmill-api-settings/enterprise", "windmill-api-schedule/enterprise", "windmill-api-agent-workers?/enterprise", "windmill-trigger/enterprise", "windmill-trigger-kafka?/enterprise", "windmill-trigger-postgres?/enterprise", "windmill-trigger-mqtt?/enterprise", "windmill-trigger-websocket?/enterprise", "windmill-trigger-email?/enterprise", "windmill-trigger-nats?/enterprise", "windmill-trigger-sqs?/enterprise", "windmill-trigger-gcp?/enterprise", "windmill-trigger-azure?/enterprise", "windmill-trigger-http?/enterprise", "windmill-native-triggers?/enterprise", "dep:windmill-autoscaling", "windmill-autoscaling/enterprise"]
|
|
stripe = []
|
|
run_inline = ["dep:windmill-worker", "windmill-api-configs/run_inline"]
|
|
agent_worker_server = ["dep:windmill-worker", "dep:windmill-api-agent-workers"]
|
|
enterprise_saml = ["dep:samael", "dep:libxml"]
|
|
benchmark = []
|
|
embedding = ["windmill-api-embeddings/embedding"]
|
|
parquet = ["dep:datafusion", "windmill-common/parquet", "windmill-object-store/parquet", "windmill-worker?/parquet", "windmill-api-users/parquet", "windmill-api-settings/parquet", "windmill-api-workspaces/parquet", "dep:aws-sigv4", "dep:aws-sdk-config"]
|
|
prometheus = ["windmill-common/prometheus", "windmill-queue/prometheus", "dep:prometheus", "windmill-worker?/prometheus"]
|
|
openidconnect = ["dep:openidconnect", "windmill-common/openidconnect", "windmill-store/openidconnect"]
|
|
tantivy = ["dep:windmill-indexer"]
|
|
kafka = ["dep:windmill-trigger-kafka", "windmill-store/kafka"]
|
|
kafka-gssapi = ["kafka", "windmill-trigger-kafka/kafka-gssapi"]
|
|
nats = ["dep:windmill-trigger-nats", "windmill-store/nats"]
|
|
websocket = ["dep:windmill-trigger-websocket"]
|
|
smtp = ["dep:mail-parser", "dep:openssl", "windmill-common/smtp", "dep:windmill-trigger-email"]
|
|
license = ["dep:rsa", "windmill-api-settings/license"]
|
|
zip = ["dep:async_zip"]
|
|
oauth2 = ["dep:windmill-oauth", "windmill-store/oauth2"]
|
|
http_trigger = ["dep:matchit", "dep:windmill-trigger-http", "windmill-store/http_trigger", "dep:windmill-api-openapi"]
|
|
static_frontend = ["dep:rust-embed"]
|
|
postgres_trigger = ["dep:windmill-trigger-postgres", "windmill-store/postgres_trigger"]
|
|
mqtt_trigger = ["dep:windmill-trigger-mqtt", "windmill-store/mqtt_trigger"]
|
|
native_trigger = ["dep:windmill-native-triggers", "windmill-native-triggers/native_trigger", "dep:strum", "oauth2"]
|
|
sqs_trigger = ["dep:windmill-trigger-sqs", "windmill-store/sqs_trigger"]
|
|
gcp_trigger = ["dep:windmill-trigger-gcp", "windmill-store/gcp_trigger"]
|
|
azure_trigger = ["dep:windmill-trigger-azure", "windmill-store/azure_trigger"]
|
|
cloud = ["windmill-common/cloud", "windmill-api-auth/cloud", "windmill-store/cloud", "windmill-api-workspaces/cloud"]
|
|
mcp = ["dep:windmill-mcp", "windmill-mcp/server", "windmill-mcp/auth", "windmill-api-auth/mcp", "windmill-store/mcp"]
|
|
bedrock = ["windmill-ai/bedrock", "dep:aws-sdk-bedrock", "dep:aws-sdk-bedrockruntime", "dep:aws-config", "dep:aws-credential-types", "dep:aws-smithy-types"]
|
|
python = ["windmill-dep-map/python", "dep:windmill-parser-py", "dep:windmill-parser-py-imports", "windmill-api-scripts/python", "windmill-api-configs/python", "windmill-api-agent-workers?/python", "windmill-trigger/python", "windmill-common/python"]
|
|
no_auth = ["windmill-api-auth/no_auth", "windmill-store/no_auth", "windmill-api-users/no_auth"]
|
|
quickjs = ["windmill-jseval/quickjs"]
|
|
|
|
[dependencies]
|
|
windmill-ai = { workspace = true, default-features = false }
|
|
windmill-mcp = { workspace = true, optional = true }
|
|
windmill-api-auth.workspace = true
|
|
windmill-api-scripts.workspace = true
|
|
windmill-api-flows.workspace = true
|
|
windmill-api-users.workspace = true
|
|
windmill-api-workspaces.workspace = true
|
|
windmill-api-groups.workspace = true
|
|
windmill-api-sse.workspace = true
|
|
windmill-api-jobs.workspace = true
|
|
windmill-trigger.workspace = true
|
|
windmill-store.workspace = true
|
|
windmill-queue.workspace = true
|
|
windmill-common = { workspace = true, default-features = false }
|
|
windmill-types.workspace = true
|
|
windmill-object-store.workspace = true
|
|
windmill-audit.workspace = true
|
|
windmill-parser.workspace = true
|
|
windmill-parser-sql.workspace = true
|
|
windmill-parser-sql-asset.workspace = true
|
|
windmill-parser-ts.workspace = true
|
|
windmill-parser-py = { workspace = true, optional = true }
|
|
windmill-parser-py-imports = { workspace = true, optional = true }
|
|
windmill-git-sync.workspace = true
|
|
windmill-indexer = { workspace = true, optional = true }
|
|
windmill-autoscaling = { workspace = true, optional = true }
|
|
windmill-worker = { workspace = true, optional = true }
|
|
windmill-worker-volumes.workspace = true
|
|
windmill-dep-map.workspace = true
|
|
tokio.workspace = true
|
|
tokio-stream.workspace = true
|
|
anyhow.workspace = true
|
|
argon2.workspace = true
|
|
axum.workspace = true
|
|
futures.workspace = true
|
|
git-version.workspace = true
|
|
tower.workspace = true
|
|
tower-cookies.workspace = true
|
|
tower-http.workspace = true
|
|
hyper.workspace = true
|
|
itertools.workspace = true
|
|
reqwest.workspace = true
|
|
serde.workspace = true
|
|
sqlx.workspace = true
|
|
windmill-oauth = { workspace = true, optional = true }
|
|
tracing.workspace = true
|
|
sql-builder.workspace = true
|
|
serde_json.workspace = true
|
|
chrono.workspace = true
|
|
chrono-tz.workspace = true
|
|
hex.workspace = true
|
|
base64.workspace = true
|
|
base32.workspace = true
|
|
serde_urlencoded.workspace = true
|
|
serde_yml.workspace = true
|
|
cron.workspace = true
|
|
mime_guess.workspace = true
|
|
rust-embed = { workspace = true, optional = true }
|
|
tracing-subscriber.workspace = true
|
|
quick_cache.workspace = true
|
|
rand.workspace = true
|
|
ed25519-dalek.workspace = true
|
|
time.workspace = true
|
|
native-tls.workspace = true
|
|
tokio-native-tls.workspace = true
|
|
openssl = { workspace = true, optional = true }
|
|
mail-parser = { workspace = true, features = ["serde_support"], optional = true }
|
|
magic-crypt.workspace = true
|
|
tempfile.workspace = true
|
|
tokio-util.workspace = true
|
|
astral-tokio-tar.workspace = true
|
|
tokio-postgres.workspace = true
|
|
postgres-native-tls.workspace = true
|
|
hmac.workspace = true
|
|
cookie.workspace = true
|
|
sha2.workspace = true
|
|
urlencoding.workspace = true
|
|
lazy_static.workspace = true
|
|
prometheus = { workspace = true, optional = true }
|
|
async_zip = { workspace = true, optional = true }
|
|
regex.workspace = true
|
|
bytes.workspace = true
|
|
url.workspace = true
|
|
samael = { workspace = true, optional = true }
|
|
libxml = { workspace = true, optional = true }
|
|
async-recursion.workspace = true
|
|
rsa = { workspace = true, optional = true}
|
|
uuid.workspace = true
|
|
datafusion = { workspace = true, optional = true}
|
|
openidconnect = { workspace = true, optional = true}
|
|
jsonwebtoken = { workspace = true }
|
|
matchit = { workspace = true, optional = true }
|
|
windmill-trigger-kafka = { workspace = true, optional = true }
|
|
windmill-trigger-postgres = { workspace = true, optional = true }
|
|
windmill-trigger-mqtt = { workspace = true, optional = true }
|
|
windmill-trigger-websocket = { workspace = true, optional = true }
|
|
windmill-trigger-email = { workspace = true, optional = true }
|
|
windmill-trigger-nats = { workspace = true, optional = true }
|
|
windmill-trigger-sqs = { workspace = true, optional = true }
|
|
windmill-trigger-gcp = { workspace = true, optional = true }
|
|
windmill-trigger-azure = { workspace = true, optional = true }
|
|
windmill-trigger-http = { workspace = true, optional = true }
|
|
windmill-native-triggers = { workspace = true, optional = true }
|
|
windmill-alerting.workspace = true
|
|
windmill-api-agent-workers = { workspace = true, optional = true }
|
|
windmill-api-assets.workspace = true
|
|
windmill-api-configs = { workspace = true }
|
|
windmill-api-debug.workspace = true
|
|
windmill-api-embeddings.workspace = true
|
|
windmill-api-flow-conversations.workspace = true
|
|
windmill-api-inputs.workspace = true
|
|
windmill-api-npm-proxy.workspace = true
|
|
windmill-api-openapi = { workspace = true, optional = true }
|
|
windmill-api-schedule.workspace = true
|
|
windmill-api-settings = { workspace = true }
|
|
windmill-api-workers.workspace = true
|
|
const_format.workspace = true
|
|
pin-project.workspace = true
|
|
http.workspace = true
|
|
indexmap.workspace = true
|
|
async-stream.workspace = true
|
|
ulid.workspace = true
|
|
rustls = { workspace = true }
|
|
|
|
aws-sigv4 = { workspace = true, optional = true }
|
|
aws-sdk-config = { workspace = true, optional = true }
|
|
aws-config = { workspace = true, optional = true }
|
|
aws-credential-types = { workspace = true, optional = true }
|
|
aws-sdk-bedrock = { workspace = true, optional = true }
|
|
aws-sdk-bedrockruntime = { workspace = true, optional = true }
|
|
aws-smithy-types = { workspace = true, optional = true }
|
|
async-trait.workspace = true
|
|
eventsource-stream.workspace = true
|
|
windmill-jseval.workspace = true
|
|
tar.workspace = true
|
|
flate2.workspace = true
|
|
strum = { workspace = true, optional = true }
|
|
dashmap.workspace = true
|
|
|
|
[build-dependencies]
|