Compare commits
30 Commits
v1.630.1
...
rf/testbac
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a9bac09b14 | ||
|
|
607a861b80 | ||
|
|
5ecfa92ac3 | ||
|
|
a3d5ae5425 | ||
|
|
d363fa6098 | ||
|
|
44143e7576 | ||
|
|
4d94d80835 | ||
|
|
c9d5c24c34 | ||
|
|
b11d6ed794 | ||
|
|
ea52a8b8ce | ||
|
|
b9e0ccaefd | ||
|
|
5effb87a36 | ||
|
|
900c76ccad | ||
|
|
ff72b81004 | ||
|
|
2815cfae1a | ||
|
|
700c61243f | ||
|
|
f22eb964e4 | ||
|
|
754b48cb89 | ||
|
|
097d9288c5 | ||
|
|
92c601860f | ||
|
|
e26e437dd1 | ||
|
|
9e8d77436b | ||
|
|
7eb239f1e2 | ||
|
|
317ae9196b | ||
|
|
20bb97fc1f | ||
|
|
5e9b4cfa99 | ||
|
|
31bfccc745 | ||
|
|
0ad4f0232e | ||
|
|
02f4359ba4 | ||
|
|
1a109a7797 |
8
.github/workflows/backend-check.yml
vendored
8
.github/workflows/backend-check.yml
vendored
@@ -23,7 +23,7 @@ jobs:
|
||||
- uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
with:
|
||||
cache: false
|
||||
toolchain: 1.90.0
|
||||
toolchain: 1.93.0
|
||||
- name: cargo check
|
||||
working-directory: ./backend
|
||||
timeout-minutes: 16
|
||||
@@ -44,7 +44,7 @@ jobs:
|
||||
- uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
with:
|
||||
cache: false
|
||||
toolchain: 1.90.0
|
||||
toolchain: 1.93.0
|
||||
- name: cargo check
|
||||
working-directory: ./backend
|
||||
timeout-minutes: 16
|
||||
@@ -81,7 +81,7 @@ jobs:
|
||||
- uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
with:
|
||||
cache: false
|
||||
toolchain: 1.90.0
|
||||
toolchain: 1.93.0
|
||||
- name: cargo check
|
||||
working-directory: ./backend
|
||||
timeout-minutes: 16
|
||||
@@ -118,7 +118,7 @@ jobs:
|
||||
- uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
with:
|
||||
cache-workspaces: backend
|
||||
toolchain: 1.90.0
|
||||
toolchain: 1.93.0
|
||||
- name: cargo check
|
||||
timeout-minutes: 16
|
||||
working-directory: ./backend
|
||||
|
||||
18
.github/workflows/backend-test.yml
vendored
18
.github/workflows/backend-test.yml
vendored
@@ -19,7 +19,7 @@ defaults:
|
||||
|
||||
jobs:
|
||||
cargo_test:
|
||||
runs-on: ubicloud-standard-16
|
||||
runs-on: blacksmith-32vcpu-ubuntu-2404
|
||||
services:
|
||||
postgres:
|
||||
image: postgres
|
||||
@@ -50,9 +50,9 @@ jobs:
|
||||
- uses: denoland/setup-deno@v2
|
||||
with:
|
||||
deno-version: v2.x
|
||||
- uses: actions/setup-go@v2
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: 1.21.5
|
||||
go-version: 1.25.0
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: 1.3.8
|
||||
@@ -72,12 +72,14 @@ jobs:
|
||||
bundler-cache: false
|
||||
- name: Install PowerShell, mold and clang
|
||||
run: |
|
||||
sudo apt-get update && sudo apt-get install -y powershell mold clang libcurl4-openssl-dev
|
||||
dotnet tool install --global PowerShell
|
||||
echo "$HOME/.dotnet/tools" >> $GITHUB_PATH
|
||||
sudo apt-get update && sudo apt-get install -y mold clang libcurl4-openssl-dev
|
||||
working-directory: /
|
||||
- uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
with:
|
||||
cache: false
|
||||
toolchain: 1.90.0
|
||||
cache: true
|
||||
toolchain: 1.93.0
|
||||
- name: Read EE repo commit hash
|
||||
run: |
|
||||
echo "ee_repo_ref=$(cat ./ee-repo-ref.txt)" >> "$GITHUB_ENV"
|
||||
@@ -214,7 +216,7 @@ jobs:
|
||||
RUST_LOG: "off"
|
||||
RUST_LOG_STYLE: never
|
||||
CARGO_NET_GIT_FETCH_WITH_CLI: true
|
||||
CARGO_BUILD_JOBS: 12
|
||||
CARGO_BUILD_JOBS: 16
|
||||
WMDEBUG_FORCE_V0_WORKSPACE_DEPENDENCIES: 1
|
||||
WMDEBUG_FORCE_RUNNABLE_SETTINGS_V0: 1
|
||||
WMDEBUG_FORCE_NO_LEGACY_DEBOUNCING_COMPAT: 1
|
||||
@@ -222,4 +224,4 @@ jobs:
|
||||
run: |
|
||||
deno --version && bun -v && node --version && go version && python3 --version && php --version && ruby --version && pwsh --version && dotnet --version
|
||||
cd windmill-duckdb-ffi-internal && ./build_dev.sh && cd ..
|
||||
DENO_PATH=$(which deno) BUN_PATH=$(which bun) NODE_BIN_PATH=$(which node) GO_PATH=$(which go) UV_PATH=$(which uv) PHP_PATH=$(which php) COMPOSER_PATH=$(which composer) RUBY_PATH=$(which ruby) RUBY_BUNDLE_PATH=$(which bundle) RUBY_GEM_PATH=$(which gem) POWERSHELL_PATH=$(which pwsh) DOTNET_PATH=$(which dotnet) cargo test --features enterprise,deno_core,duckdb,license,python,rust,scoped_cache,parquet,private,private_registry_test,csharp,php,ruby,mysql,quickjs,mcp --all -- --nocapture --test-threads=10
|
||||
DENO_PATH=$(which deno) BUN_PATH=$(which bun) NODE_BIN_PATH=$(which node) GO_PATH=$(which go) UV_PATH=$(which uv) PHP_PATH=$(which php) COMPOSER_PATH=$(which composer) RUBY_PATH=$(which ruby) RUBY_BUNDLE_PATH=$(which bundle) RUBY_GEM_PATH=$(which gem) POWERSHELL_PATH=$(which pwsh) DOTNET_PATH=$(which dotnet) cargo test --features enterprise,deno_core,duckdb,license,python,rust,scoped_cache,parquet,private,private_registry_test,csharp,php,ruby,mysql,quickjs,mcp --all -- --nocapture --test-threads=12
|
||||
|
||||
2
.github/workflows/build_windows_worker_.yml
vendored
2
.github/workflows/build_windows_worker_.yml
vendored
@@ -33,7 +33,7 @@ jobs:
|
||||
- uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
with:
|
||||
cache-workspaces: backend
|
||||
toolchain: 1.90.0
|
||||
toolchain: 1.93.0
|
||||
|
||||
- name: Substitute EE code
|
||||
shell: bash
|
||||
|
||||
2
.github/workflows/claude.yml
vendored
2
.github/workflows/claude.yml
vendored
@@ -83,7 +83,7 @@ jobs:
|
||||
- uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
with:
|
||||
cache-workspaces: backend
|
||||
toolchain: 1.90.0
|
||||
toolchain: 1.93.0
|
||||
|
||||
- name: cargo check
|
||||
working-directory: ./backend
|
||||
|
||||
2
.github/workflows/git-commands.yaml
vendored
2
.github/workflows/git-commands.yaml
vendored
@@ -66,7 +66,7 @@ jobs:
|
||||
- uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
with:
|
||||
cache-workspaces: backend
|
||||
toolchain: 1.90.0
|
||||
toolchain: 1.93.0
|
||||
|
||||
- name: Install xmlsec and gssapi build-time deps
|
||||
run: |
|
||||
|
||||
2
.github/workflows/publish_windows_worker.yml
vendored
2
.github/workflows/publish_windows_worker.yml
vendored
@@ -35,7 +35,7 @@ jobs:
|
||||
- uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
with:
|
||||
cache-workspaces: backend
|
||||
toolchain: 1.90.0
|
||||
toolchain: 1.93.0
|
||||
|
||||
- name: Substitute EE code
|
||||
shell: bash
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -19,3 +19,4 @@ backend/target
|
||||
frontend/node_modules
|
||||
typescript-client/node_modules
|
||||
frontend/.svelte-kit
|
||||
backend/chrome_profiler.json
|
||||
|
||||
39
CHANGELOG.md
39
CHANGELOG.md
@@ -1,5 +1,44 @@
|
||||
# Changelog
|
||||
|
||||
## [1.631.2](https://github.com/windmill-labs/windmill/compare/v1.631.1...v1.631.2) (2026-02-11)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **frontend:** revert CloseButton refactor that broke tag removal in MultiSelect ([#7909](https://github.com/windmill-labs/windmill/issues/7909)) ([b11d6ed](https://github.com/windmill-labs/windmill/commit/b11d6ed7940faddfe74a22b25bcb132527cbcec8))
|
||||
* nix flake libz.so for deno_core ([#7905](https://github.com/windmill-labs/windmill/issues/7905)) ([900c76c](https://github.com/windmill-labs/windmill/commit/900c76ccad09f58fc6adcfa8151db780249617f6))
|
||||
* strip unsupported schema fields for Google AI ([#7894](https://github.com/windmill-labs/windmill/issues/7894)) ([5effb87](https://github.com/windmill-labs/windmill/commit/5effb87a36793e20d17e678619091ef458fe8f0a)), closes [#7759](https://github.com/windmill-labs/windmill/issues/7759)
|
||||
|
||||
## [1.631.1](https://github.com/windmill-labs/windmill/compare/v1.631.0...v1.631.1) (2026-02-11)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add kafka-gssapi support to ee builds ([2815cfa](https://github.com/windmill-labs/windmill/commit/2815cfae1a5eefb2c553e893dc926e62ad1df528))
|
||||
|
||||
## [1.631.0](https://github.com/windmill-labs/windmill/compare/v1.630.2...v1.631.0) (2026-02-11)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **ai:** support 1M context window for Anthropic resources ([#7891](https://github.com/windmill-labs/windmill/issues/7891)) ([f22eb96](https://github.com/windmill-labs/windmill/commit/f22eb964e47defe9922ecdb6ab471dd4ca267952))
|
||||
* **uv:** index resolve strategy ([#7885](https://github.com/windmill-labs/windmill/issues/7885)) ([097d928](https://github.com/windmill-labs/windmill/commit/097d9288c58076882f1991e2fb33e4441fe332d3))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **frontend:** improve time picker ([#7893](https://github.com/windmill-labs/windmill/issues/7893)) ([31bfccc](https://github.com/windmill-labs/windmill/commit/31bfccc74588af10fc11fbbb0bc4833d65ff6421))
|
||||
* otel gracefully handle no native ts ([92c6018](https://github.com/windmill-labs/windmill/commit/92c601860f1e1211aa34838cd08900ba7334a20c))
|
||||
* waitJob getJob and streamJob in raw apps ([#7901](https://github.com/windmill-labs/windmill/issues/7901)) ([754b48c](https://github.com/windmill-labs/windmill/commit/754b48cb898dffe196339cea1c1598c9e1765cdc))
|
||||
* worker do not apply migrations anymore but wait for servers to do so ([7eb239f](https://github.com/windmill-labs/windmill/commit/7eb239f1e2eb1b71234a8d4265c7c5813e5861ae))
|
||||
|
||||
## [1.630.2](https://github.com/windmill-labs/windmill/compare/v1.630.1...v1.630.2) (2026-02-11)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* bump rust version from 1.90.0 to 1.93.0 ([1a109a7](https://github.com/windmill-labs/windmill/commit/1a109a7797d1a50a0d85f3fff236d707b2cfb81d))
|
||||
|
||||
## [1.630.1](https://github.com/windmill-labs/windmill/compare/v1.630.0...v1.630.1) (2026-02-10)
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
ARG DEBIAN_IMAGE=debian:bookworm-slim
|
||||
ARG RUST_IMAGE=rust:1.90-slim-bookworm
|
||||
ARG RUST_IMAGE=rust:1.93-slim-bookworm
|
||||
|
||||
FROM debian:bookworm-slim AS nsjail
|
||||
|
||||
|
||||
@@ -46,11 +46,11 @@
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true
|
||||
]
|
||||
|
||||
20
backend/.sqlx/query-12c3101e02f197ad731b66f539fe677ad25520fcc9c5a2378a293122956bed4c.json
generated
Normal file
20
backend/.sqlx/query-12c3101e02f197ad731b66f539fe677ad25520fcc9c5a2378a293122956bed4c.json
generated
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT error_handler->>'path' FROM workspace_settings WHERE workspace_id = 'test-workspace'",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "?column?",
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
},
|
||||
"nullable": [
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "12c3101e02f197ad731b66f539fe677ad25520fcc9c5a2378a293122956bed4c"
|
||||
}
|
||||
12
backend/.sqlx/query-18d1a6ac94f2c87d5ea8c48a228f061135be4065dca33fbc429d8b0186c5ccb3.json
generated
Normal file
12
backend/.sqlx/query-18d1a6ac94f2c87d5ea8c48a228f061135be4065dca33fbc429d8b0186c5ccb3.json
generated
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n UPDATE workspace_settings\n SET error_handler = '{\"path\": \"script/f/test/error_handler\", \"extra_args\": {\"notify\": true}, \"muted_on_cancel\": true, \"muted_on_user_path\": false}'::jsonb\n WHERE workspace_id = 'test-workspace'\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "18d1a6ac94f2c87d5ea8c48a228f061135be4065dca33fbc429d8b0186c5ccb3"
|
||||
}
|
||||
20
backend/.sqlx/query-25bf3956b4365a4d4f96368bcc6e33817ae284ab26c195eee53d988d74263e86.json
generated
Normal file
20
backend/.sqlx/query-25bf3956b4365a4d4f96368bcc6e33817ae284ab26c195eee53d988d74263e86.json
generated
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT (error_handler->>'muted_on_cancel')::boolean FROM workspace_settings WHERE workspace_id = 'test-workspace'",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "bool",
|
||||
"type_info": "Bool"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
},
|
||||
"nullable": [
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "25bf3956b4365a4d4f96368bcc6e33817ae284ab26c195eee53d988d74263e86"
|
||||
}
|
||||
20
backend/.sqlx/query-28b8264a427e8c19be823d2b8e40736a7b7675780672b503d91737cd0c617657.json
generated
Normal file
20
backend/.sqlx/query-28b8264a427e8c19be823d2b8e40736a7b7675780672b503d91737cd0c617657.json
generated
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT (error_handler->>'muted_on_user_path')::boolean FROM workspace_settings WHERE workspace_id = 'test-workspace'",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "bool",
|
||||
"type_info": "Bool"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
},
|
||||
"nullable": [
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "28b8264a427e8c19be823d2b8e40736a7b7675780672b503d91737cd0c617657"
|
||||
}
|
||||
14
backend/.sqlx/query-51f18c817d4014e847486f5a8dbf205ffa0e53d5bd3fdb97777e988389b1d69e.json
generated
Normal file
14
backend/.sqlx/query-51f18c817d4014e847486f5a8dbf205ffa0e53d5bd3fdb97777e988389b1d69e.json
generated
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n INSERT INTO script (workspace_id, hash, path, content, language, kind, created_by, schema, summary, description, lock)\n VALUES ('test-workspace', $1, 'f/test/success_script', 'export function main() { return \"ok\"; }', 'deno', 'script', 'test-user', '{}', '', '', '')\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int8"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "51f18c817d4014e847486f5a8dbf205ffa0e53d5bd3fdb97777e988389b1d69e"
|
||||
}
|
||||
12
backend/.sqlx/query-5f5bdd667f699a5a1c05e07d805a97afb06252541d06b4785063819c3893b674.json
generated
Normal file
12
backend/.sqlx/query-5f5bdd667f699a5a1c05e07d805a97afb06252541d06b4785063819c3893b674.json
generated
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n INSERT INTO group_ (workspace_id, name, summary, extra_perms)\n VALUES ('test-workspace', 'error_handler', 'The group the error handler acts on behalf of', '{\"u/test-user\": true}')\n ON CONFLICT DO NOTHING\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "5f5bdd667f699a5a1c05e07d805a97afb06252541d06b4785063819c3893b674"
|
||||
}
|
||||
14
backend/.sqlx/query-782c259ccdf71c5e2fa8dcb27515e7c5ff83009774dc15095ed0dbcb0ecdbdde.json
generated
Normal file
14
backend/.sqlx/query-782c259ccdf71c5e2fa8dcb27515e7c5ff83009774dc15095ed0dbcb0ecdbdde.json
generated
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n INSERT INTO script (workspace_id, hash, path, content, language, kind, created_by, schema, summary, description, lock, ws_error_handler_muted)\n VALUES ('test-workspace', $1, 'f/test/muted_failing_script', 'export function main() { throw new Error(\"fail\"); }', 'deno', 'script', 'test-user', '{}', '', '', '', true)\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int8"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "782c259ccdf71c5e2fa8dcb27515e7c5ff83009774dc15095ed0dbcb0ecdbdde"
|
||||
}
|
||||
12
backend/.sqlx/query-79648f03eb50385183c34d57bda1ac984cf6502609df9ee51b7d684b585b8447.json
generated
Normal file
12
backend/.sqlx/query-79648f03eb50385183c34d57bda1ac984cf6502609df9ee51b7d684b585b8447.json
generated
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n UPDATE workspace_settings\n SET error_handler = NULL\n WHERE workspace_id = 'test-workspace'\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "79648f03eb50385183c34d57bda1ac984cf6502609df9ee51b7d684b585b8447"
|
||||
}
|
||||
12
backend/.sqlx/query-7f98c013682aca6d269ef6ef754a7247b6e2dd4958d0968a3f2eb49cc320e877.json
generated
Normal file
12
backend/.sqlx/query-7f98c013682aca6d269ef6ef754a7247b6e2dd4958d0968a3f2eb49cc320e877.json
generated
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n INSERT INTO script (workspace_id, hash, path, content, language, kind, created_by, schema, summary, description, lock)\n VALUES ('test-workspace', 3333333333, 'f/test/error_handler', 'export function main() { return \"handled\"; }', 'deno', 'script', 'test-user', '{}', '', '', '')\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "7f98c013682aca6d269ef6ef754a7247b6e2dd4958d0968a3f2eb49cc320e877"
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE alerts \n SET\n acknowledged = true,\n acknowledged_workspace = CASE\n WHEN $2 THEN\n CASE\n WHEN $1::text IS NOT NULL THEN true\n ELSE acknowledged_workspace\n END\n ELSE true\n END\n WHERE ($1::text IS NOT NULL AND workspace_id = $1)\n OR ($1::text IS NULL)",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Bool"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "80864158f61adaad8df934acc54ba523c9f17d106298d8781885134d28553d36"
|
||||
}
|
||||
@@ -18,8 +18,8 @@
|
||||
"Left": []
|
||||
},
|
||||
"nullable": [
|
||||
true,
|
||||
false
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "b3dbdfb50ee8118bdaed3164b210cb549a34b96554ae1872355b90304f5dcb76"
|
||||
|
||||
@@ -59,9 +59,7 @@
|
||||
"failure",
|
||||
"command",
|
||||
"approval",
|
||||
"preprocessor",
|
||||
"schedule_handler_old",
|
||||
"dynamic_skip"
|
||||
"preprocessor"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
12
backend/.sqlx/query-ba0c3dad5d2a77922821c9c6d58e06a65e6666e197f3e59b880470df35c27bec.json
generated
Normal file
12
backend/.sqlx/query-ba0c3dad5d2a77922821c9c6d58e06a65e6666e197f3e59b880470df35c27bec.json
generated
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n INSERT INTO group_ (workspace_id, name, summary, extra_perms)\n VALUES ('test-workspace', 'error_handler', 'Error handler group', '{\"u/test-user\": true}')\n ON CONFLICT DO NOTHING\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "ba0c3dad5d2a77922821c9c6d58e06a65e6666e197f3e59b880470df35c27bec"
|
||||
}
|
||||
12
backend/.sqlx/query-bb4cde84157126f29680cb36075848e7cde2ab7c6b7f0861becd4c0b8c330a8d.json
generated
Normal file
12
backend/.sqlx/query-bb4cde84157126f29680cb36075848e7cde2ab7c6b7f0861becd4c0b8c330a8d.json
generated
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n UPDATE workspace_settings\n SET error_handler = '{\"path\": \"script/f/test/error_handler\"}'::jsonb\n WHERE workspace_id = 'test-workspace'\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "bb4cde84157126f29680cb36075848e7cde2ab7c6b7f0861becd4c0b8c330a8d"
|
||||
}
|
||||
12
backend/.sqlx/query-cdc594b30855e9384481f561b2c16200d4e6dacb1eb274513c8f1795235dfe20.json
generated
Normal file
12
backend/.sqlx/query-cdc594b30855e9384481f561b2c16200d4e6dacb1eb274513c8f1795235dfe20.json
generated
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n INSERT INTO script (workspace_id, hash, path, content, language, kind, created_by, schema, summary, description, lock)\n VALUES ('test-workspace', 5555555555, 'f/test/error_handler', 'export function main() { return \"handled\"; }', 'deno', 'script', 'test-user', '{}', '', '', '')\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "cdc594b30855e9384481f561b2c16200d4e6dacb1eb274513c8f1795235dfe20"
|
||||
}
|
||||
15
backend/.sqlx/query-d2a9a9af4d00c1c05276c14e6f32044437800a4b0c60aa364ab2f362a4fd9a2c.json
generated
Normal file
15
backend/.sqlx/query-d2a9a9af4d00c1c05276c14e6f32044437800a4b0c60aa364ab2f362a4fd9a2c.json
generated
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n INSERT INTO script (workspace_id, hash, path, content, language, kind, created_by, schema, summary, description, lock)\n VALUES ('test-workspace', $1, 'f/test/failing_script', $2, 'deno', 'script', 'test-user', '{}', 'Failing test script', 'A script that always fails', '')\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int8",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "d2a9a9af4d00c1c05276c14e6f32044437800a4b0c60aa364ab2f362a4fd9a2c"
|
||||
}
|
||||
20
backend/.sqlx/query-d5f1a2bfbac206a33b991d58f9ff4b8e8e4a3840ea1c65d409576379dede41ed.json
generated
Normal file
20
backend/.sqlx/query-d5f1a2bfbac206a33b991d58f9ff4b8e8e4a3840ea1c65d409576379dede41ed.json
generated
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT error_handler->'extra_args' FROM workspace_settings WHERE workspace_id = 'test-workspace'",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "?column?",
|
||||
"type_info": "Jsonb"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
},
|
||||
"nullable": [
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "d5f1a2bfbac206a33b991d58f9ff4b8e8e4a3840ea1c65d409576379dede41ed"
|
||||
}
|
||||
15
backend/.sqlx/query-e00f7877d7bd33cf81e7bf48b1a37a507ab0a8f8b4bd7a38cf44d181f8f2d940.json
generated
Normal file
15
backend/.sqlx/query-e00f7877d7bd33cf81e7bf48b1a37a507ab0a8f8b4bd7a38cf44d181f8f2d940.json
generated
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE alerts\n SET\n acknowledged = true,\n acknowledged_workspace = CASE\n WHEN $2 THEN\n CASE\n WHEN $1::text IS NOT NULL THEN true\n ELSE acknowledged_workspace\n END\n ELSE true\n END\n WHERE ($1::text IS NOT NULL AND workspace_id = $1)\n OR ($1::text IS NULL)",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Bool"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "e00f7877d7bd33cf81e7bf48b1a37a507ab0a8f8b4bd7a38cf44d181f8f2d940"
|
||||
}
|
||||
20
backend/.sqlx/query-e4c9f3bca6bd636c3ee31fc643182ed5ca48a45da895fb992d820682f5169f7c.json
generated
Normal file
20
backend/.sqlx/query-e4c9f3bca6bd636c3ee31fc643182ed5ca48a45da895fb992d820682f5169f7c.json
generated
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT id\n FROM v2_job\n WHERE workspace_id = 'test-workspace'\n AND permissioned_as_email = 'error_handler@windmill.dev'\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "id",
|
||||
"type_info": "Uuid"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "e4c9f3bca6bd636c3ee31fc643182ed5ca48a45da895fb992d820682f5169f7c"
|
||||
}
|
||||
38
backend/.sqlx/query-fdf0a16a72bc2eca2025d64750e2e6a7e7ff90b5ad4b42e6aab53992b447a20e.json
generated
Normal file
38
backend/.sqlx/query-fdf0a16a72bc2eca2025d64750e2e6a7e7ff90b5ad4b42e6aab53992b447a20e.json
generated
Normal file
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT\n id,\n runnable_path,\n permissioned_as_email,\n parent_job\n FROM v2_job\n WHERE workspace_id = 'test-workspace'\n AND permissioned_as_email = 'error_handler@windmill.dev'\n ORDER BY created_at DESC\n LIMIT 1\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "id",
|
||||
"type_info": "Uuid"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "runnable_path",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "permissioned_as_email",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "parent_job",
|
||||
"type_info": "Uuid"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "fdf0a16a72bc2eca2025d64750e2e6a7e7ff90b5ad4b42e6aab53992b447a20e"
|
||||
}
|
||||
14
backend/.sqlx/query-fe17aff543f28cf4d6d09ea7c4c7d18ff6a95a8402468131f5a5f33df91c59e4.json
generated
Normal file
14
backend/.sqlx/query-fe17aff543f28cf4d6d09ea7c4c7d18ff6a95a8402468131f5a5f33df91c59e4.json
generated
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n INSERT INTO script (workspace_id, hash, path, content, language, kind, created_by, schema, summary, description, lock)\n VALUES ('test-workspace', 1111111111, 'f/test/error_handler', $1, 'deno', 'script', 'test-user', '{}', 'Error handler script', 'Handles failed job completions', '')\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "fe17aff543f28cf4d6d09ea7c4c7d18ff6a95a8402468131f5a5f33df91c59e4"
|
||||
}
|
||||
@@ -37,14 +37,22 @@ Windmill uses a workspace-based architecture with multiple crates:
|
||||
- Update database schema with migration if necessary
|
||||
- Use `sqlx` for database operations with prepared statements
|
||||
- Use transactions for multi-step operations
|
||||
- To apply pending migrations: `sqlx migrate run` (never manually run .sql files)
|
||||
- **Never use `SQLX_OFFLINE=true`** — a live database is always available for compilation
|
||||
- After all code changes are done, run `./update-sqlx` to regenerate the offline query cache
|
||||
|
||||
## Enterprise Features
|
||||
|
||||
- Enterprise files use the `*_ee.rs` suffix
|
||||
- Enterprise source is in `windmill-ee-private` folder (sibling directory), symlinked into each crate's `src/`
|
||||
- Enterprise source is in `windmill-ee-private` folder (sibling directory at `../../windmill-ee-private`), symlinked into each crate's `src/`
|
||||
- You can and should modify `windmill-ee-private` directly when needed (e.g., when creating new crates that need EE code, mirror the package structure there)
|
||||
- Use feature flags: `#[cfg(feature = "enterprise")]`
|
||||
- Isolate enterprise code in separate modules
|
||||
|
||||
## Git Workflow
|
||||
|
||||
- **Never push directly to main** — always create a branch and open a pull request
|
||||
|
||||
## Testing
|
||||
|
||||
- Write unit tests for core functionality
|
||||
|
||||
429
backend/Cargo.lock
generated
429
backend/Cargo.lock
generated
@@ -2322,9 +2322,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.57"
|
||||
version = "4.5.58"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6899ea499e3fb9305a65d5ebf6e3d2248c5fab291f300ad0a704fbe142eae31a"
|
||||
checksum = "63be97961acde393029492ce0be7a1af7e323e6bae9511ebfac33751be5e6806"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
@@ -2332,9 +2332,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.57"
|
||||
version = "4.5.58"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b12c8b680195a62a8364d16b8447b01b6c2c8f9aaf68bee653be34d4245e238"
|
||||
checksum = "7f13174bda5dfd69d7e947827e5af4b0f2f94a4a3ee92912fba07a66150f21e2"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@@ -2356,9 +2356,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.7.7"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32"
|
||||
checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831"
|
||||
|
||||
[[package]]
|
||||
name = "clipboard-win"
|
||||
@@ -7858,9 +7858,9 @@ checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553"
|
||||
|
||||
[[package]]
|
||||
name = "lazy-regex"
|
||||
version = "3.5.1"
|
||||
version = "3.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c5c13b6857ade4c8ee05c3c3dc97d2ab5415d691213825b90d3211c425c1f907"
|
||||
checksum = "6bae91019476d3ec7147de9aa291cadb6d870abf2f3015d2da73a90325ac1496"
|
||||
dependencies = [
|
||||
"lazy-regex-proc_macros",
|
||||
"once_cell",
|
||||
@@ -7869,9 +7869,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "lazy-regex-proc_macros"
|
||||
version = "3.5.1"
|
||||
version = "3.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a95c68db5d41694cea563c86a4ba4dc02141c16ef64814108cb23def4d5438"
|
||||
checksum = "4de9c1e1439d8b7b3061b2d209809f447ca33241733d9a3c01eabf2dc8d94358"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -14840,9 +14840,9 @@ checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a"
|
||||
|
||||
[[package]]
|
||||
name = "typed-path"
|
||||
version = "0.12.2"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3015e6ce46d5ad8751e4a772543a30c7511468070e98e64e20165f8f81155b64"
|
||||
checksum = "8e28f89b80c87b8fb0cf04ab448d5dd0dd0ade2f8891bae878de66a75a28600e"
|
||||
|
||||
[[package]]
|
||||
name = "typeid"
|
||||
@@ -15725,7 +15725,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-nats",
|
||||
@@ -15768,7 +15768,9 @@ dependencies = [
|
||||
"url",
|
||||
"uuid",
|
||||
"windmill-api",
|
||||
"windmill-api-agent-workers",
|
||||
"windmill-api-client",
|
||||
"windmill-api-settings",
|
||||
"windmill-autoscaling",
|
||||
"windmill-common",
|
||||
"windmill-dep-map",
|
||||
@@ -15776,14 +15778,28 @@ dependencies = [
|
||||
"windmill-indexer",
|
||||
"windmill-queue",
|
||||
"windmill-runtime-nativets",
|
||||
"windmill-test-utils",
|
||||
"windmill-worker",
|
||||
"windows-service",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windmill-alerting"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"axum 0.7.9",
|
||||
"chrono",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sqlx",
|
||||
"tracing",
|
||||
"windmill-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windmill-api"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"argon2",
|
||||
@@ -15867,13 +15883,26 @@ dependencies = [
|
||||
"url",
|
||||
"urlencoding",
|
||||
"uuid",
|
||||
"windmill-alerting",
|
||||
"windmill-api-agent-workers",
|
||||
"windmill-api-assets",
|
||||
"windmill-api-auth",
|
||||
"windmill-api-configs",
|
||||
"windmill-api-debug",
|
||||
"windmill-api-embeddings",
|
||||
"windmill-api-flow-conversations",
|
||||
"windmill-api-flows",
|
||||
"windmill-api-groups",
|
||||
"windmill-api-inputs",
|
||||
"windmill-api-jobs",
|
||||
"windmill-api-npm-proxy",
|
||||
"windmill-api-openapi",
|
||||
"windmill-api-schedule",
|
||||
"windmill-api-scripts",
|
||||
"windmill-api-settings",
|
||||
"windmill-api-sse",
|
||||
"windmill-api-users",
|
||||
"windmill-api-workers",
|
||||
"windmill-api-workspaces",
|
||||
"windmill-audit",
|
||||
"windmill-autoscaling",
|
||||
@@ -15905,9 +15934,45 @@ dependencies = [
|
||||
"windmill-worker",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windmill-api-agent-workers"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"axum 0.7.9",
|
||||
"chrono",
|
||||
"http 1.4.0",
|
||||
"hyper 1.8.1",
|
||||
"lazy_static",
|
||||
"quick_cache",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sqlx",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"uuid",
|
||||
"windmill-api-auth",
|
||||
"windmill-common",
|
||||
"windmill-parser-py-imports",
|
||||
"windmill-queue",
|
||||
"windmill-worker",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windmill-api-assets"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"axum 0.7.9",
|
||||
"chrono",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sqlx",
|
||||
"windmill-api-auth",
|
||||
"windmill-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windmill-api-auth"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"axum 0.7.9",
|
||||
@@ -15933,7 +15998,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-api-client"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"reqwest 0.12.28",
|
||||
"serde",
|
||||
@@ -15941,9 +16006,49 @@ dependencies = [
|
||||
"urlencoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windmill-api-configs"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"axum 0.7.9",
|
||||
"chrono",
|
||||
"itertools 0.14.0",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sqlx",
|
||||
"windmill-api-auth",
|
||||
"windmill-audit",
|
||||
"windmill-autoscaling",
|
||||
"windmill-common",
|
||||
"windmill-worker",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windmill-api-debug"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"axum 0.7.9",
|
||||
"base64 0.22.1",
|
||||
"chrono",
|
||||
"ed25519-dalek",
|
||||
"hex",
|
||||
"lazy_static",
|
||||
"rand 0.9.0",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2 0.10.9",
|
||||
"sqlx",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"uuid",
|
||||
"windmill-api-auth",
|
||||
"windmill-audit",
|
||||
"windmill-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windmill-api-embeddings"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"axum 0.7.9",
|
||||
@@ -15964,9 +16069,45 @@ dependencies = [
|
||||
"windmill-store",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windmill-api-flow-conversations"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"axum 0.7.9",
|
||||
"chrono",
|
||||
"serde",
|
||||
"sql-builder",
|
||||
"sqlx",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"uuid",
|
||||
"windmill-api-auth",
|
||||
"windmill-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windmill-api-flows"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"axum 0.7.9",
|
||||
"chrono",
|
||||
"hyper 1.8.1",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sql-builder",
|
||||
"sqlx",
|
||||
"tracing",
|
||||
"windmill-api-auth",
|
||||
"windmill-audit",
|
||||
"windmill-common",
|
||||
"windmill-dep-map",
|
||||
"windmill-git-sync",
|
||||
"windmill-queue",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windmill-api-groups"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"axum 0.7.9",
|
||||
"chrono",
|
||||
@@ -15984,9 +16125,47 @@ dependencies = [
|
||||
"windmill-git-sync",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windmill-api-inputs"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"axum 0.7.9",
|
||||
"chrono",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sql-builder",
|
||||
"sqlx",
|
||||
"windmill-api-auth",
|
||||
"windmill-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windmill-api-integration-tests"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-nats",
|
||||
"aws-config",
|
||||
"aws-credential-types",
|
||||
"aws-sdk-sqs",
|
||||
"base64 0.22.1",
|
||||
"rand 0.9.0",
|
||||
"rdkafka",
|
||||
"reqwest 0.13.1",
|
||||
"rumqttc",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sqlx",
|
||||
"tokio",
|
||||
"uuid",
|
||||
"windmill-api-client",
|
||||
"windmill-common",
|
||||
"windmill-test-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windmill-api-jobs"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"axum 0.7.9",
|
||||
@@ -16009,9 +16188,66 @@ dependencies = [
|
||||
"windmill-queue",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windmill-api-npm-proxy"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"axum 0.7.9",
|
||||
"flate2",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sqlx",
|
||||
"tar",
|
||||
"tower-http",
|
||||
"tracing",
|
||||
"windmill-api-auth",
|
||||
"windmill-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windmill-api-openapi"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"axum 0.7.9",
|
||||
"http 1.4.0",
|
||||
"indexmap 2.11.1",
|
||||
"itertools 0.14.0",
|
||||
"lazy_static",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_yml",
|
||||
"sqlx",
|
||||
"url",
|
||||
"windmill-api-auth",
|
||||
"windmill-common",
|
||||
"windmill-store",
|
||||
"windmill-trigger-http",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windmill-api-schedule"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"axum 0.7.9",
|
||||
"chrono",
|
||||
"chrono-tz",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sql-builder",
|
||||
"sqlx",
|
||||
"tracing",
|
||||
"windmill-api-auth",
|
||||
"windmill-api-settings",
|
||||
"windmill-audit",
|
||||
"windmill-common",
|
||||
"windmill-git-sync",
|
||||
"windmill-queue",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windmill-api-scripts"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"axum 0.7.9",
|
||||
"chrono",
|
||||
@@ -16038,9 +16274,35 @@ dependencies = [
|
||||
"windmill-queue",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windmill-api-settings"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"axum 0.7.9",
|
||||
"base64 0.22.1",
|
||||
"bytes",
|
||||
"chrono",
|
||||
"futures",
|
||||
"lazy_static",
|
||||
"object_store",
|
||||
"regex",
|
||||
"rsa",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2 0.10.9",
|
||||
"sqlx",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"uuid",
|
||||
"windmill-alerting",
|
||||
"windmill-api-auth",
|
||||
"windmill-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windmill-api-sse"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"serde",
|
||||
@@ -16052,7 +16314,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-api-users"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"argon2",
|
||||
"axum 0.7.9",
|
||||
@@ -16073,9 +16335,23 @@ dependencies = [
|
||||
"windmill-git-sync",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windmill-api-workers"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"axum 0.7.9",
|
||||
"chrono",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sqlx",
|
||||
"uuid",
|
||||
"windmill-api-auth",
|
||||
"windmill-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windmill-api-workspaces"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"axum 0.7.9",
|
||||
"chrono",
|
||||
@@ -16104,7 +16380,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-audit"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"lazy_static",
|
||||
@@ -16118,7 +16394,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-autoscaling"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"axum 0.7.9",
|
||||
@@ -16137,7 +16413,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-common"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"aes-gcm",
|
||||
"anyhow",
|
||||
@@ -16236,7 +16512,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-dep-map"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"itertools 0.14.0",
|
||||
@@ -16255,7 +16531,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-git-sync"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"regex",
|
||||
"serde",
|
||||
@@ -16270,7 +16546,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-indexer"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"astral-tokio-tar",
|
||||
@@ -16294,7 +16570,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-jseval"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"futures",
|
||||
@@ -16311,7 +16587,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-macros"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"itertools 0.14.0",
|
||||
"lazy_static",
|
||||
@@ -16327,7 +16603,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-mcp"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -16348,7 +16624,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-native-triggers"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -16379,7 +16655,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-oauth"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-oauth2",
|
||||
@@ -16403,7 +16679,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"convert_case 0.6.0",
|
||||
"serde",
|
||||
@@ -16412,7 +16688,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-bash"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"lazy_static",
|
||||
@@ -16424,7 +16700,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-csharp"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"serde_json",
|
||||
@@ -16436,7 +16712,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-go"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"gosyn",
|
||||
@@ -16448,7 +16724,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-graphql"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"lazy_static",
|
||||
@@ -16460,7 +16736,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-java"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"serde_json",
|
||||
@@ -16472,7 +16748,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-nu"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"nu-parser",
|
||||
@@ -16483,7 +16759,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-php"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools 0.14.0",
|
||||
@@ -16494,7 +16770,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-py"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools 0.14.0",
|
||||
@@ -16507,7 +16783,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-py-imports"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-recursion",
|
||||
@@ -16531,7 +16807,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-ruby"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"lazy_static",
|
||||
@@ -16545,7 +16821,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-rust"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"convert_case 0.6.0",
|
||||
@@ -16562,7 +16838,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-sql"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"lazy_static",
|
||||
@@ -16576,7 +16852,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-ts"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"lazy_static",
|
||||
@@ -16595,7 +16871,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-yaml"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"serde",
|
||||
@@ -16606,7 +16882,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-queue"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-recursion",
|
||||
@@ -16643,7 +16919,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-runtime-nativets"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"const_format",
|
||||
@@ -16681,7 +16957,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-sql-datatype-parser-wasm"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-test",
|
||||
@@ -16691,7 +16967,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-store"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-recursion",
|
||||
@@ -16718,9 +16994,32 @@ dependencies = [
|
||||
"windmill-oauth",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windmill-test-utils"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"axum 0.7.9",
|
||||
"chrono",
|
||||
"futures",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sqlx",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"uuid",
|
||||
"windmill-api",
|
||||
"windmill-api-agent-workers",
|
||||
"windmill-api-client",
|
||||
"windmill-common",
|
||||
"windmill-queue",
|
||||
"windmill-runtime-nativets",
|
||||
"windmill-worker",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windmill-trigger"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -16753,7 +17052,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-trigger-email"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -16773,7 +17072,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-trigger-gcp"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -16807,7 +17106,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-trigger-http"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -16841,7 +17140,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-trigger-kafka"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -16864,7 +17163,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-trigger-mqtt"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -16888,7 +17187,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-trigger-nats"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-nats",
|
||||
@@ -16912,7 +17211,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-trigger-postgres"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -16947,7 +17246,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-trigger-sqs"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -16975,7 +17274,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-trigger-websocket"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -16998,7 +17297,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-types"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
@@ -17015,7 +17314,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-worker"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-once-cell",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "windmill"
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
@@ -9,6 +9,7 @@ resolver = "2"
|
||||
members = [
|
||||
"./windmill-api",
|
||||
"./windmill-api-scripts",
|
||||
"./windmill-api-flows",
|
||||
"./windmill-api-users",
|
||||
"./windmill-api-workspaces",
|
||||
"./windmill-api-groups",
|
||||
@@ -26,7 +27,19 @@ members = [
|
||||
"./windmill-trigger-gcp",
|
||||
"./windmill-trigger-http",
|
||||
"./windmill-native-triggers",
|
||||
"./windmill-alerting",
|
||||
"./windmill-api-agent-workers",
|
||||
"./windmill-api-assets",
|
||||
"./windmill-api-configs",
|
||||
"./windmill-api-debug",
|
||||
"./windmill-api-embeddings",
|
||||
"./windmill-api-flow-conversations",
|
||||
"./windmill-api-inputs",
|
||||
"./windmill-api-npm-proxy",
|
||||
"./windmill-api-openapi",
|
||||
"./windmill-api-schedule",
|
||||
"./windmill-api-settings",
|
||||
"./windmill-api-workers",
|
||||
"./windmill-store",
|
||||
"./windmill-queue",
|
||||
"./windmill-worker",
|
||||
@@ -54,12 +67,14 @@ members = [
|
||||
"./parsers/windmill-parser-py",
|
||||
"./parsers/windmill-parser-py-imports",
|
||||
"./parsers/windmill-sql-datatype-parser-wasm",
|
||||
"./parsers/windmill-parser-yaml", "windmill-macros", "parsers/windmill-parser-nu"
|
||||
"./parsers/windmill-parser-yaml", "windmill-macros", "parsers/windmill-parser-nu",
|
||||
"./windmill-test-utils",
|
||||
"./windmill-api-integration-tests",
|
||||
]
|
||||
exclude = ["./windmill-duckdb-ffi-internal"]
|
||||
|
||||
[workspace.package]
|
||||
version = "1.630.1"
|
||||
version = "1.631.2"
|
||||
authors = ["Ruben Fiszel <ruben@windmill.dev>"]
|
||||
edition = "2021"
|
||||
|
||||
@@ -80,9 +95,9 @@ lto = "thin"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
private = ["windmill-api/private", "windmill-autoscaling/private", "windmill-common/private", "windmill-git-sync/private", "windmill-indexer/private", "windmill-queue/private", "windmill-worker/private"]
|
||||
agent_worker_server = ["windmill-api/agent_worker_server"]
|
||||
enterprise = ["windmill-worker/enterprise", "windmill-queue/enterprise", "windmill-api/enterprise", "dep:windmill-autoscaling", "windmill-autoscaling/enterprise", "windmill-git-sync/enterprise", "windmill-common/prometheus", "windmill-common/enterprise"]
|
||||
private = ["windmill-api/private", "windmill-api-agent-workers?/private", "windmill-autoscaling/private", "windmill-common/private", "windmill-git-sync/private", "windmill-indexer/private", "windmill-queue/private", "windmill-worker/private"]
|
||||
agent_worker_server = ["windmill-api/agent_worker_server", "dep:windmill-api-agent-workers"]
|
||||
enterprise = ["windmill-worker/enterprise", "windmill-queue/enterprise", "windmill-api/enterprise", "windmill-api-agent-workers?/enterprise", "dep:windmill-autoscaling", "windmill-autoscaling/enterprise", "windmill-git-sync/enterprise", "windmill-common/prometheus", "windmill-common/enterprise"]
|
||||
local_reports = ["windmill-common/local_reports"]
|
||||
enterprise_saml = ["windmill-api/enterprise_saml", "oauth2"]
|
||||
stripe = ["windmill-api/stripe"]
|
||||
@@ -114,7 +129,7 @@ native_trigger = ["windmill-api/native_trigger"]
|
||||
sqs_trigger = ["windmill-api/sqs_trigger", "windmill-common/aws_auth", "windmill-api/openidconnect"]
|
||||
gcp_trigger = ["windmill-api/gcp_trigger"]
|
||||
smtp = ["windmill-api/smtp", "windmill-common/smtp", "windmill-queue/smtp"]
|
||||
license = ["windmill-api/license"]
|
||||
license = ["windmill-api/license", "windmill-api-settings/license"]
|
||||
oauth2 = ["windmill-api/oauth2"]
|
||||
zip = ["windmill-api/zip"]
|
||||
static_frontend = ["windmill-api/static_frontend"]
|
||||
@@ -160,8 +175,8 @@ oss = ["oss_core", "all_languages", "no_auth"]
|
||||
ce_rpi = ["ce_core", "all_languages"]
|
||||
ce = ["ce_rpi", "jemalloc", "dind", "agent_worker_server"]
|
||||
# Edition meta-features: EE variants
|
||||
ee = ["ce", "ee_core", "ee_server"]
|
||||
ee_rhel = ["ce_core", "ee_core", "all_languages"]
|
||||
ee = ["ce", "ee_core", "ee_server", "kafka-gssapi"]
|
||||
ee_rhel = ["ce_core", "ee_core", "kafka-gssapi", "all_languages"]
|
||||
ee_windows = ["ce_core", "ee_core", "all_languages_windows"]
|
||||
all_sqlx_features = ["all_languages", "enterprise", "enterprise_saml", "embedding", "parquet", "prometheus", "flow_testing",
|
||||
"openidconnect", "cloud", "jemalloc", "tantivy", "sqlx", "kafka", "kafka-gssapi", "nats", "otel", "dind", "websocket", "http_trigger",
|
||||
@@ -182,6 +197,8 @@ windmill-queue.workspace = true
|
||||
windmill-common = { workspace = true, default-features = false }
|
||||
windmill-git-sync.workspace = true
|
||||
windmill-api = { workspace = true, default-features = false }
|
||||
windmill-api-agent-workers = { workspace = true, optional = true }
|
||||
windmill-api-settings.workspace = true
|
||||
windmill-worker.workspace = true
|
||||
windmill-indexer = { workspace = true, optional = true }
|
||||
windmill-autoscaling = { workspace = true, optional = true }
|
||||
@@ -225,6 +242,7 @@ serde_json.workspace = true
|
||||
reqwest.workspace = true
|
||||
windmill-queue = { workspace = true, features = ["failpoints"] }
|
||||
windmill-dep-map.workspace = true
|
||||
windmill-test-utils.workspace = true
|
||||
axum.workspace = true
|
||||
serde.workspace = true
|
||||
windmill-api-client.workspace = true
|
||||
@@ -253,6 +271,7 @@ windmill-oauth = {path = "./windmill-oauth"}
|
||||
windmill-macros = {path = "./windmill-macros"}
|
||||
windmill-api-auth = { path = "./windmill-api-auth" }
|
||||
windmill-api-scripts = { path = "./windmill-api-scripts" }
|
||||
windmill-api-flows = { path = "./windmill-api-flows" }
|
||||
windmill-api-users = { path = "./windmill-api-users" }
|
||||
windmill-api-workspaces = { path = "./windmill-api-workspaces" }
|
||||
windmill-api-groups = { path = "./windmill-api-groups" }
|
||||
@@ -269,7 +288,19 @@ windmill-trigger-sqs = { path = "./windmill-trigger-sqs" }
|
||||
windmill-trigger-gcp = { path = "./windmill-trigger-gcp" }
|
||||
windmill-trigger-http = { path = "./windmill-trigger-http" }
|
||||
windmill-native-triggers = { path = "./windmill-native-triggers" }
|
||||
windmill-alerting = { path = "./windmill-alerting" }
|
||||
windmill-api-agent-workers = { path = "./windmill-api-agent-workers" }
|
||||
windmill-api-assets = { path = "./windmill-api-assets" }
|
||||
windmill-api-configs = { path = "./windmill-api-configs" }
|
||||
windmill-api-debug = { path = "./windmill-api-debug" }
|
||||
windmill-api-embeddings = { path = "./windmill-api-embeddings" }
|
||||
windmill-api-flow-conversations = { path = "./windmill-api-flow-conversations" }
|
||||
windmill-api-inputs = { path = "./windmill-api-inputs" }
|
||||
windmill-api-npm-proxy = { path = "./windmill-api-npm-proxy" }
|
||||
windmill-api-openapi = { path = "./windmill-api-openapi" }
|
||||
windmill-api-schedule = { path = "./windmill-api-schedule" }
|
||||
windmill-api-settings = { path = "./windmill-api-settings" }
|
||||
windmill-api-workers = { path = "./windmill-api-workers" }
|
||||
windmill-store = { path = "./windmill-store" }
|
||||
windmill-parser = { path = "./parsers/windmill-parser" }
|
||||
windmill-parser-ts = { path = "./parsers/windmill-parser-ts" }
|
||||
@@ -289,6 +320,7 @@ windmill-parser-php = { path = "./parsers/windmill-parser-php" }
|
||||
windmill-jseval = { path = "./windmill-jseval" }
|
||||
windmill-runtime-nativets = { path = "./windmill-runtime-nativets" }
|
||||
windmill-api-client = { path = "./windmill-api-client" }
|
||||
windmill-test-utils = { path = "./windmill-test-utils" }
|
||||
|
||||
reqwest-retry = "^0"
|
||||
reqwest-middleware = { version = "^0", features = ["json"] }
|
||||
|
||||
@@ -1 +1 @@
|
||||
de9ff0d258f5a1a3739d9693531bad3972ddfd22
|
||||
ab082a1a65830bf362a32b30fa86741999da091d
|
||||
@@ -46,8 +46,8 @@ use windmill_common::{
|
||||
KEEP_JOB_DIR_SETTING, LICENSE_KEY_SETTING, MAVEN_REPOS_SETTING,
|
||||
MONITOR_LOGS_ON_OBJECT_STORE_SETTING, NO_DEFAULT_MAVEN_SETTING,
|
||||
NPM_CONFIG_REGISTRY_SETTING, NUGET_CONFIG_SETTING, OAUTH_SETTING, OTEL_SETTING,
|
||||
OTEL_TRACING_PROXY_SETTING, PIP_INDEX_URL_SETTING, POWERSHELL_REPO_PAT_SETTING,
|
||||
POWERSHELL_REPO_URL_SETTING, REQUEST_SIZE_LIMIT_SETTING,
|
||||
OTEL_TRACING_PROXY_SETTING, PIP_INDEX_URL_SETTING, UV_INDEX_STRATEGY_SETTING,
|
||||
POWERSHELL_REPO_PAT_SETTING, POWERSHELL_REPO_URL_SETTING, REQUEST_SIZE_LIMIT_SETTING,
|
||||
REQUIRE_PREEXISTING_USER_FOR_OAUTH_SETTING, RETENTION_PERIOD_SECS_SETTING,
|
||||
RUBY_REPOS_SETTING, SAML_METADATA_SETTING, SCIM_TOKEN_SETTING, SMTP_SETTING, TEAMS_SETTING,
|
||||
TIMEOUT_WAIT_RESULT_SETTING,
|
||||
@@ -103,7 +103,7 @@ use crate::monitor::{
|
||||
reload_jwt_secret_setting, reload_license_key, reload_npm_config_registry_setting,
|
||||
reload_otel_tracing_proxy_setting, reload_pip_index_url_setting,
|
||||
reload_retention_period_setting, reload_scim_token_setting, reload_smtp_config,
|
||||
reload_worker_config, MonitorIteration,
|
||||
reload_uv_index_strategy_setting, reload_worker_config, MonitorIteration,
|
||||
};
|
||||
|
||||
#[cfg(feature = "parquet")]
|
||||
@@ -735,8 +735,12 @@ async fn windmill_main() -> anyhow::Result<()> {
|
||||
.unwrap_or(false);
|
||||
|
||||
if !skip_migration {
|
||||
// migration code to avoid break
|
||||
migration_handle = windmill_api::migrate_db(&db, killpill_rx.resubscribe()).await?;
|
||||
if mode == Mode::Worker {
|
||||
windmill_api::wait_for_db_migrations(&db, killpill_rx.resubscribe()).await?;
|
||||
} else {
|
||||
migration_handle =
|
||||
windmill_api::migrate_db(&db, killpill_rx.resubscribe()).await?;
|
||||
}
|
||||
} else {
|
||||
tracing::info!("SKIP_MIGRATION set, skipping db migration...")
|
||||
}
|
||||
@@ -1560,6 +1564,7 @@ async fn process_notify_event(
|
||||
SCIM_TOKEN_SETTING => reload_scim_token_setting(conn).await,
|
||||
EXTRA_PIP_INDEX_URL_SETTING => reload_extra_pip_index_url_setting(conn).await,
|
||||
PIP_INDEX_URL_SETTING => reload_pip_index_url_setting(conn).await,
|
||||
UV_INDEX_STRATEGY_SETTING => reload_uv_index_strategy_setting(conn).await,
|
||||
INSTANCE_PYTHON_VERSION_SETTING => {
|
||||
reload_instance_python_version_setting(conn).await
|
||||
}
|
||||
|
||||
@@ -57,6 +57,7 @@ use windmill_common::{
|
||||
JOB_DEFAULT_TIMEOUT_SECS_SETTING, JWT_SECRET_SETTING, KEEP_JOB_DIR_SETTING,
|
||||
LICENSE_KEY_SETTING, MONITOR_LOGS_ON_OBJECT_STORE_SETTING, NPM_CONFIG_REGISTRY_SETTING,
|
||||
NUGET_CONFIG_SETTING, OTEL_SETTING, OTEL_TRACING_PROXY_SETTING, PIP_INDEX_URL_SETTING,
|
||||
UV_INDEX_STRATEGY_SETTING,
|
||||
POWERSHELL_REPO_PAT_SETTING, POWERSHELL_REPO_URL_SETTING, REQUEST_SIZE_LIMIT_SETTING,
|
||||
REQUIRE_PREEXISTING_USER_FOR_OAUTH_SETTING, RETENTION_PERIOD_SECS_SETTING,
|
||||
SAML_METADATA_SETTING, SCIM_TOKEN_SETTING, TIMEOUT_WAIT_RESULT_SETTING,
|
||||
@@ -88,7 +89,7 @@ use windmill_worker::{
|
||||
SameWorkerSender, BUNFIG_INSTALL_SCOPES, INSTANCE_PYTHON_VERSION, JOB_DEFAULT_TIMEOUT,
|
||||
KEEP_JOB_DIR, MAVEN_REPOS, NO_DEFAULT_MAVEN, NPM_CONFIG_REGISTRY, NUGET_CONFIG,
|
||||
OTEL_TRACING_PROXY_SETTINGS, PIP_EXTRA_INDEX_URL, PIP_INDEX_URL, POWERSHELL_REPO_PAT,
|
||||
POWERSHELL_REPO_URL,
|
||||
POWERSHELL_REPO_URL, UV_INDEX_STRATEGY,
|
||||
};
|
||||
|
||||
#[cfg(feature = "parquet")]
|
||||
@@ -317,6 +318,7 @@ pub async fn initial_load(
|
||||
reload_job_default_timeout_setting(&conn).await;
|
||||
reload_extra_pip_index_url_setting(&conn).await;
|
||||
reload_pip_index_url_setting(&conn).await;
|
||||
reload_uv_index_strategy_setting(&conn).await;
|
||||
reload_npm_config_registry_setting(&conn).await;
|
||||
reload_bunfig_install_scopes_setting(&conn).await;
|
||||
reload_instance_python_version_setting(&conn).await;
|
||||
@@ -1250,6 +1252,16 @@ pub async fn reload_pip_index_url_setting(conn: &Connection) {
|
||||
.await;
|
||||
}
|
||||
|
||||
pub async fn reload_uv_index_strategy_setting(conn: &Connection) {
|
||||
reload_option_setting_with_tracing(
|
||||
conn,
|
||||
UV_INDEX_STRATEGY_SETTING,
|
||||
"UV_INDEX_STRATEGY",
|
||||
UV_INDEX_STRATEGY.clone(),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
pub async fn reload_instance_python_version_setting(conn: &Connection) {
|
||||
reload_option_setting_with_tracing(
|
||||
conn,
|
||||
|
||||
267
backend/tests/agent_workers.rs
Normal file
267
backend/tests/agent_workers.rs
Normal file
@@ -0,0 +1,267 @@
|
||||
#![cfg(all(feature = "private", feature = "agent_worker_server"))]
|
||||
|
||||
use windmill_test_utils::*;
|
||||
use serde_json::json;
|
||||
use sqlx::{Pool, Postgres};
|
||||
use windmill_common::{
|
||||
jobs::{JobPayload, RawCode},
|
||||
scripts::ScriptLang,
|
||||
};
|
||||
|
||||
fn bun_code(code: &str) -> RawCode {
|
||||
RawCode {
|
||||
hash: None,
|
||||
content: code.to_string(),
|
||||
path: None,
|
||||
language: ScriptLang::Bun,
|
||||
lock: None,
|
||||
cache_ttl: None,
|
||||
cache_ignore_s3_path: None,
|
||||
dedicated_worker: None,
|
||||
concurrency_settings:
|
||||
windmill_common::runnable_settings::ConcurrencySettings::default().into(),
|
||||
debouncing_settings: windmill_common::runnable_settings::DebouncingSettings::default(),
|
||||
}
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
async fn test_agent_worker_simple_script(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
let (_client, port, _server) = init_client_agent_mode(db.clone()).await;
|
||||
|
||||
let result = RunJob::from(JobPayload::Code(bun_code(
|
||||
"export function main() { return 42; }",
|
||||
)))
|
||||
.run_until_complete(&db, false, port)
|
||||
.await;
|
||||
|
||||
assert!(result.success, "job should succeed");
|
||||
assert_eq!(result.json_result(), Some(json!(42)));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
async fn test_agent_worker_script_with_args(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
let (_client, port, _server) = init_client_agent_mode(db.clone()).await;
|
||||
|
||||
let result = RunJob::from(JobPayload::Code(bun_code(
|
||||
"export function main(x: number, y: number) { return x + y; }",
|
||||
)))
|
||||
.arg("x", json!(10))
|
||||
.arg("y", json!(32))
|
||||
.run_until_complete(&db, false, port)
|
||||
.await;
|
||||
|
||||
assert!(result.success, "job should succeed");
|
||||
assert_eq!(result.json_result(), Some(json!(42)));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
async fn test_agent_worker_script_with_logs(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
let (_client, port, _server) = init_client_agent_mode(db.clone()).await;
|
||||
|
||||
let result = RunJob::from(JobPayload::Code(bun_code(
|
||||
r#"export function main() {
|
||||
console.log("hello from agent worker");
|
||||
console.log("processing step 1");
|
||||
console.log("processing step 2");
|
||||
return "done";
|
||||
}"#,
|
||||
)))
|
||||
.run_until_complete(&db, false, port)
|
||||
.await;
|
||||
|
||||
assert!(result.success, "job should succeed");
|
||||
assert_eq!(result.json_result(), Some(json!("done")));
|
||||
|
||||
let logs = sqlx::query_scalar::<_, String>(
|
||||
"SELECT logs FROM job_logs WHERE job_id = $1 AND workspace_id = 'test-workspace'",
|
||||
)
|
||||
.bind(result.id)
|
||||
.fetch_optional(&db)
|
||||
.await?;
|
||||
|
||||
let logs = logs.expect("logs should exist");
|
||||
assert!(
|
||||
logs.contains("hello from agent worker"),
|
||||
"logs should contain the printed output, got: {logs}"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
async fn test_agent_worker_script_failure(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
let (_client, port, _server) = init_client_agent_mode(db.clone()).await;
|
||||
|
||||
let result = RunJob::from(JobPayload::Code(bun_code(
|
||||
"export function main() { throw new Error('test error'); }",
|
||||
)))
|
||||
.run_until_complete(&db, false, port)
|
||||
.await;
|
||||
|
||||
assert!(!result.success, "job should fail");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
async fn test_agent_worker_complex_result(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
let (_client, port, _server) = init_client_agent_mode(db.clone()).await;
|
||||
|
||||
let result = RunJob::from(JobPayload::Code(bun_code(
|
||||
r#"export function main() {
|
||||
return {
|
||||
items: [1, 2, 3],
|
||||
metadata: { key: "value" },
|
||||
count: 3,
|
||||
};
|
||||
}"#,
|
||||
)))
|
||||
.run_until_complete(&db, false, port)
|
||||
.await;
|
||||
|
||||
assert!(result.success, "job should succeed");
|
||||
let json = result.json_result().unwrap();
|
||||
assert_eq!(json["items"], json!([1, 2, 3]));
|
||||
assert_eq!(json["metadata"]["key"], json!("value"));
|
||||
assert_eq!(json["count"], json!(3));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
async fn test_agent_worker_token_creation(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
let (client, _port, _server) = init_client_agent_mode(db.clone()).await;
|
||||
|
||||
// client.baseurl() already includes /api
|
||||
let resp = client
|
||||
.client()
|
||||
.post(format!(
|
||||
"{}/agent_workers/create_agent_token",
|
||||
client.baseurl()
|
||||
))
|
||||
.json(&json!({
|
||||
"worker_group": "lifecycle-test",
|
||||
"tags": ["bun", "flow", "dependency"],
|
||||
"exp": usize::MAX
|
||||
}))
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
assert!(
|
||||
resp.status().is_success(),
|
||||
"create_agent_token should succeed, got: {}",
|
||||
resp.status()
|
||||
);
|
||||
|
||||
let token = resp.text().await?;
|
||||
let token = token.trim_matches('"');
|
||||
assert!(
|
||||
token.starts_with("jwt_agent_"),
|
||||
"token should start with jwt_agent_ prefix, got: {token}"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
async fn test_agent_worker_token_and_ping(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
let (client, port, _server) = init_client_agent_mode(db.clone()).await;
|
||||
|
||||
let resp = client
|
||||
.client()
|
||||
.post(format!(
|
||||
"{}/agent_workers/create_agent_token",
|
||||
client.baseurl()
|
||||
))
|
||||
.json(&json!({
|
||||
"worker_group": "lifecycle-test",
|
||||
"tags": ["bun", "flow", "dependency"],
|
||||
"exp": usize::MAX
|
||||
}))
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
assert!(resp.status().is_success());
|
||||
let token = resp.text().await?;
|
||||
let token = token.trim_matches('"');
|
||||
|
||||
let suffix = windmill_common::utils::create_default_worker_suffix("lifecycle-test");
|
||||
let base_url = format!("http://localhost:{port}");
|
||||
let http_client =
|
||||
windmill_common::agent_workers::build_agent_http_client(&suffix, &token, &base_url);
|
||||
|
||||
// Initial ping inserts the worker record into the database
|
||||
let resp = http_client
|
||||
.client
|
||||
.post(format!("{}/api/agent_workers/update_ping", base_url))
|
||||
.json(&json!({
|
||||
"worker_instance": "test-instance",
|
||||
"ip": "127.0.0.1",
|
||||
"tags": ["bun"],
|
||||
"version": "test",
|
||||
"vcpus": 4,
|
||||
"memory": 8192,
|
||||
"ping_type": "Initial"
|
||||
}))
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
assert!(
|
||||
resp.status().is_success(),
|
||||
"initial ping should succeed, got: {}",
|
||||
resp.status()
|
||||
);
|
||||
|
||||
// Verify the ping was recorded in the database
|
||||
let worker_count = sqlx::query_scalar::<_, i64>(
|
||||
"SELECT COUNT(*) FROM worker_ping WHERE worker_instance = 'test-instance'",
|
||||
)
|
||||
.fetch_one(&db)
|
||||
.await?;
|
||||
|
||||
assert!(worker_count > 0, "worker ping should be recorded in database");
|
||||
|
||||
// MainLoop ping updates the existing record
|
||||
let resp = http_client
|
||||
.client
|
||||
.post(format!("{}/api/agent_workers/update_ping", base_url))
|
||||
.json(&json!({
|
||||
"tags": ["bun"],
|
||||
"vcpus": 4,
|
||||
"memory": 8192,
|
||||
"jobs_executed": 0,
|
||||
"ping_type": "MainLoop"
|
||||
}))
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
assert!(
|
||||
resp.status().is_success(),
|
||||
"main loop ping should succeed, got: {}",
|
||||
resp.status()
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
async fn test_agent_worker_multiple_jobs_sequential(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
let (_client, port, _server) = init_client_agent_mode(db.clone()).await;
|
||||
|
||||
for i in 0..3 {
|
||||
let result = RunJob::from(JobPayload::Code(bun_code(&format!(
|
||||
"export function main() {{ return {i}; }}"
|
||||
))))
|
||||
.run_until_complete(&db, false, port)
|
||||
.await;
|
||||
|
||||
assert!(result.success, "job {i} should succeed");
|
||||
assert_eq!(result.json_result(), Some(json!(i)));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
mod common;
|
||||
use crate::common::*;
|
||||
use windmill_test_utils::*;
|
||||
use sqlx::postgres::Postgres;
|
||||
use sqlx::Pool;
|
||||
use windmill_common::jobs::{JobPayload, RawCode};
|
||||
@@ -860,7 +859,7 @@ export function main() {
|
||||
// ============================================================================
|
||||
|
||||
mod dedicated_worker_protocol {
|
||||
use crate::common::{parse_dedicated_worker_line, DedicatedWorkerResult};
|
||||
use windmill_test_utils::{parse_dedicated_worker_line, DedicatedWorkerResult};
|
||||
use std::io::{BufRead, BufReader, Write};
|
||||
use std::process::{Command, Stdio};
|
||||
use windmill_worker::{
|
||||
|
||||
@@ -2,8 +2,9 @@ use sqlx::{Pool, Postgres};
|
||||
use tokio_stream::StreamExt;
|
||||
|
||||
use windmill_api_client::types::NewScript;
|
||||
mod common;
|
||||
use common::{in_test_worker, init_client, listen_for_completed_jobs, ApiServer};
|
||||
use windmill_test_utils::{
|
||||
in_test_worker, init_client, listen_for_completed_jobs, rebuild_dmap, ApiServer,
|
||||
};
|
||||
|
||||
mod dependency_map {
|
||||
use super::*;
|
||||
@@ -170,7 +171,7 @@ mod dependency_map {
|
||||
let (client, _port, _s) = init(db.clone()).await;
|
||||
assert_dmap(&db, None, CORRECT_DMAP.clone()).await;
|
||||
// rebuild map
|
||||
assert!(common::rebuild_dmap(&client).await);
|
||||
assert!(rebuild_dmap(&client).await);
|
||||
assert_dmap(&db, None, CORRECT_DMAP.clone()).await;
|
||||
Ok(())
|
||||
}
|
||||
@@ -183,7 +184,7 @@ mod dependency_map {
|
||||
// Spawn first rebuild
|
||||
let handle = {
|
||||
let client = client.clone();
|
||||
tokio::spawn(async move { common::rebuild_dmap(&client).await })
|
||||
tokio::spawn(async move { rebuild_dmap(&client).await })
|
||||
};
|
||||
|
||||
// Immidiately spawn another
|
||||
|
||||
410
backend/tests/error_handler.rs
Normal file
410
backend/tests/error_handler.rs
Normal file
@@ -0,0 +1,410 @@
|
||||
use sqlx::{Pool, Postgres};
|
||||
|
||||
use windmill_test_utils::*;
|
||||
|
||||
/// Test that workspace error handler can be set and removed via database operations
|
||||
#[cfg(feature = "deno_core")]
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
async fn test_error_handler_settings(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
initialize_tracing().await;
|
||||
|
||||
let _server = ApiServer::start(db.clone()).await?;
|
||||
|
||||
// Initially error_handler should be NULL
|
||||
let initial = sqlx::query_scalar!(
|
||||
r#"SELECT error_handler->>'path' FROM workspace_settings WHERE workspace_id = 'test-workspace'"#
|
||||
)
|
||||
.fetch_one(&db)
|
||||
.await?;
|
||||
assert!(initial.is_none());
|
||||
|
||||
// Set error handler with all options
|
||||
sqlx::query!(
|
||||
r#"
|
||||
UPDATE workspace_settings
|
||||
SET error_handler = '{"path": "script/f/test/error_handler", "extra_args": {"notify": true}, "muted_on_cancel": true, "muted_on_user_path": false}'::jsonb
|
||||
WHERE workspace_id = 'test-workspace'
|
||||
"#
|
||||
)
|
||||
.execute(&db)
|
||||
.await?;
|
||||
|
||||
let after_set = sqlx::query_scalar!(
|
||||
r#"SELECT error_handler->>'path' FROM workspace_settings WHERE workspace_id = 'test-workspace'"#
|
||||
)
|
||||
.fetch_one(&db)
|
||||
.await?;
|
||||
assert_eq!(
|
||||
after_set,
|
||||
Some("script/f/test/error_handler".to_string())
|
||||
);
|
||||
|
||||
// Verify extra_args
|
||||
let extra_args = sqlx::query_scalar!(
|
||||
r#"SELECT error_handler->'extra_args' FROM workspace_settings WHERE workspace_id = 'test-workspace'"#
|
||||
)
|
||||
.fetch_one(&db)
|
||||
.await?;
|
||||
assert!(extra_args.is_some());
|
||||
|
||||
// Verify muted_on_cancel
|
||||
let muted_on_cancel = sqlx::query_scalar!(
|
||||
r#"SELECT (error_handler->>'muted_on_cancel')::boolean FROM workspace_settings WHERE workspace_id = 'test-workspace'"#
|
||||
)
|
||||
.fetch_one(&db)
|
||||
.await?;
|
||||
assert_eq!(muted_on_cancel, Some(true));
|
||||
|
||||
// Verify muted_on_user_path
|
||||
let muted_on_user_path = sqlx::query_scalar!(
|
||||
r#"SELECT (error_handler->>'muted_on_user_path')::boolean FROM workspace_settings WHERE workspace_id = 'test-workspace'"#
|
||||
)
|
||||
.fetch_one(&db)
|
||||
.await?;
|
||||
assert_eq!(muted_on_user_path, Some(false));
|
||||
|
||||
// Remove error handler
|
||||
sqlx::query!(
|
||||
r#"
|
||||
UPDATE workspace_settings
|
||||
SET error_handler = NULL
|
||||
WHERE workspace_id = 'test-workspace'
|
||||
"#
|
||||
)
|
||||
.execute(&db)
|
||||
.await?;
|
||||
|
||||
let after_remove = sqlx::query_scalar!(
|
||||
r#"SELECT error_handler->>'path' FROM workspace_settings WHERE workspace_id = 'test-workspace'"#
|
||||
)
|
||||
.fetch_one(&db)
|
||||
.await?;
|
||||
assert!(after_remove.is_none());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Test that a failed job triggers the workspace error handler
|
||||
#[cfg(all(feature = "deno_core", feature = "enterprise", feature = "private"))]
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
async fn test_error_handler_triggered_on_failure(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
use windmill_common::jobs::JobPayload;
|
||||
use windmill_common::runnable_settings::{ConcurrencySettings, DebouncingSettings};
|
||||
use windmill_common::scripts::{ScriptHash, ScriptLang};
|
||||
|
||||
initialize_tracing().await;
|
||||
|
||||
let server = ApiServer::start(db.clone()).await?;
|
||||
|
||||
// Create the error handler script
|
||||
let error_handler_code = r#"
|
||||
export async function main(path: string, email: string, job_id: string, is_flow: boolean, workspace_id: string, error: any) {
|
||||
console.log("Error handler called for job:", job_id);
|
||||
return { handled: true, original_path: path };
|
||||
}
|
||||
"#;
|
||||
|
||||
sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO script (workspace_id, hash, path, content, language, kind, created_by, schema, summary, description, lock)
|
||||
VALUES ('test-workspace', 1111111111, 'f/test/error_handler', $1, 'deno', 'script', 'test-user', '{}', 'Error handler script', 'Handles failed job completions', '')
|
||||
"#,
|
||||
error_handler_code
|
||||
)
|
||||
.execute(&db)
|
||||
.await?;
|
||||
|
||||
// Create a script that will fail
|
||||
let failing_script_code = "export function main() { throw new Error('intentional failure'); }";
|
||||
let failing_script_hash: i64 = 2222222222;
|
||||
|
||||
sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO script (workspace_id, hash, path, content, language, kind, created_by, schema, summary, description, lock)
|
||||
VALUES ('test-workspace', $1, 'f/test/failing_script', $2, 'deno', 'script', 'test-user', '{}', 'Failing test script', 'A script that always fails', '')
|
||||
"#,
|
||||
failing_script_hash,
|
||||
failing_script_code
|
||||
)
|
||||
.execute(&db)
|
||||
.await?;
|
||||
|
||||
// Set up the error handler in workspace_settings
|
||||
sqlx::query!(
|
||||
r#"
|
||||
UPDATE workspace_settings
|
||||
SET error_handler = '{"path": "script/f/test/error_handler"}'::jsonb
|
||||
WHERE workspace_id = 'test-workspace'
|
||||
"#
|
||||
)
|
||||
.execute(&db)
|
||||
.await?;
|
||||
|
||||
// Create the error_handler group
|
||||
sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO group_ (workspace_id, name, summary, extra_perms)
|
||||
VALUES ('test-workspace', 'error_handler', 'The group the error handler acts on behalf of', '{"u/test-user": true}')
|
||||
ON CONFLICT DO NOTHING
|
||||
"#
|
||||
)
|
||||
.execute(&db)
|
||||
.await?;
|
||||
|
||||
// Run the failing script
|
||||
let completed_job = RunJob::from(JobPayload::ScriptHash {
|
||||
hash: ScriptHash(failing_script_hash),
|
||||
path: "f/test/failing_script".to_string(),
|
||||
cache_ttl: None,
|
||||
cache_ignore_s3_path: None,
|
||||
dedicated_worker: None,
|
||||
language: ScriptLang::Deno,
|
||||
priority: None,
|
||||
apply_preprocessor: false,
|
||||
concurrency_settings: ConcurrencySettings::default(),
|
||||
debouncing_settings: DebouncingSettings::default(),
|
||||
})
|
||||
.run_until_complete(&db, false, server.addr.port())
|
||||
.await;
|
||||
|
||||
// Verify the job actually failed
|
||||
assert!(!completed_job.success, "Job should have failed");
|
||||
|
||||
let main_job_id = completed_job.id;
|
||||
|
||||
// Wait for the error handler job to be created
|
||||
tokio::time::sleep(tokio::time::Duration::from_millis(500)).await;
|
||||
|
||||
// Verify the error handler job was created
|
||||
let error_handler_job = sqlx::query!(
|
||||
r#"
|
||||
SELECT
|
||||
id,
|
||||
runnable_path,
|
||||
permissioned_as_email,
|
||||
parent_job
|
||||
FROM v2_job
|
||||
WHERE workspace_id = 'test-workspace'
|
||||
AND permissioned_as_email = 'error_handler@windmill.dev'
|
||||
ORDER BY created_at DESC
|
||||
LIMIT 1
|
||||
"#
|
||||
)
|
||||
.fetch_optional(&db)
|
||||
.await?;
|
||||
|
||||
assert!(
|
||||
error_handler_job.is_some(),
|
||||
"Error handler job should have been created"
|
||||
);
|
||||
|
||||
let handler_job = error_handler_job.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
handler_job.runnable_path.as_deref(),
|
||||
Some("f/test/error_handler"),
|
||||
"Error handler should run the configured script"
|
||||
);
|
||||
assert_eq!(
|
||||
handler_job.permissioned_as_email.as_str(),
|
||||
"error_handler@windmill.dev",
|
||||
"Error handler should run as error_handler user"
|
||||
);
|
||||
assert_eq!(
|
||||
handler_job.parent_job,
|
||||
Some(main_job_id),
|
||||
"Error handler should have the failed job as parent"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Test that error handler is NOT triggered when ws_error_handler_muted is set on the script
|
||||
#[cfg(all(feature = "deno_core", feature = "enterprise", feature = "private"))]
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
async fn test_error_handler_muted_on_script(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
use windmill_common::jobs::JobPayload;
|
||||
use windmill_common::runnable_settings::{ConcurrencySettings, DebouncingSettings};
|
||||
use windmill_common::scripts::{ScriptHash, ScriptLang};
|
||||
|
||||
initialize_tracing().await;
|
||||
|
||||
let server = ApiServer::start(db.clone()).await?;
|
||||
|
||||
// Create the error handler script
|
||||
sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO script (workspace_id, hash, path, content, language, kind, created_by, schema, summary, description, lock)
|
||||
VALUES ('test-workspace', 3333333333, 'f/test/error_handler', 'export function main() { return "handled"; }', 'deno', 'script', 'test-user', '{}', '', '', '')
|
||||
"#,
|
||||
)
|
||||
.execute(&db)
|
||||
.await?;
|
||||
|
||||
// Create a failing script with ws_error_handler_muted = true
|
||||
let failing_script_hash: i64 = 4444444444;
|
||||
sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO script (workspace_id, hash, path, content, language, kind, created_by, schema, summary, description, lock, ws_error_handler_muted)
|
||||
VALUES ('test-workspace', $1, 'f/test/muted_failing_script', 'export function main() { throw new Error("fail"); }', 'deno', 'script', 'test-user', '{}', '', '', '', true)
|
||||
"#,
|
||||
failing_script_hash,
|
||||
)
|
||||
.execute(&db)
|
||||
.await?;
|
||||
|
||||
// Set up the error handler
|
||||
sqlx::query!(
|
||||
r#"
|
||||
UPDATE workspace_settings
|
||||
SET error_handler = '{"path": "script/f/test/error_handler"}'::jsonb
|
||||
WHERE workspace_id = 'test-workspace'
|
||||
"#
|
||||
)
|
||||
.execute(&db)
|
||||
.await?;
|
||||
|
||||
sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO group_ (workspace_id, name, summary, extra_perms)
|
||||
VALUES ('test-workspace', 'error_handler', 'Error handler group', '{"u/test-user": true}')
|
||||
ON CONFLICT DO NOTHING
|
||||
"#
|
||||
)
|
||||
.execute(&db)
|
||||
.await?;
|
||||
|
||||
// Run the muted failing script
|
||||
let completed_job = RunJob::from(JobPayload::ScriptHash {
|
||||
hash: ScriptHash(failing_script_hash),
|
||||
path: "f/test/muted_failing_script".to_string(),
|
||||
cache_ttl: None,
|
||||
cache_ignore_s3_path: None,
|
||||
dedicated_worker: None,
|
||||
language: ScriptLang::Deno,
|
||||
priority: None,
|
||||
apply_preprocessor: false,
|
||||
concurrency_settings: ConcurrencySettings::default(),
|
||||
debouncing_settings: DebouncingSettings::default(),
|
||||
})
|
||||
.run_until_complete(&db, false, server.addr.port())
|
||||
.await;
|
||||
|
||||
assert!(!completed_job.success, "Job should have failed");
|
||||
|
||||
// Wait and check that NO error handler job was created
|
||||
tokio::time::sleep(tokio::time::Duration::from_millis(500)).await;
|
||||
|
||||
let error_handler_job = sqlx::query_scalar!(
|
||||
r#"
|
||||
SELECT id
|
||||
FROM v2_job
|
||||
WHERE workspace_id = 'test-workspace'
|
||||
AND permissioned_as_email = 'error_handler@windmill.dev'
|
||||
"#
|
||||
)
|
||||
.fetch_optional(&db)
|
||||
.await?;
|
||||
|
||||
assert!(
|
||||
error_handler_job.is_none(),
|
||||
"Error handler should NOT have been triggered for a muted script"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Test that error handler is NOT triggered on successful job completion
|
||||
#[cfg(all(feature = "deno_core", feature = "enterprise", feature = "private"))]
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
async fn test_error_handler_not_triggered_on_success(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
use windmill_common::jobs::JobPayload;
|
||||
use windmill_common::runnable_settings::{ConcurrencySettings, DebouncingSettings};
|
||||
use windmill_common::scripts::{ScriptHash, ScriptLang};
|
||||
|
||||
initialize_tracing().await;
|
||||
|
||||
let server = ApiServer::start(db.clone()).await?;
|
||||
|
||||
// Create the error handler script
|
||||
sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO script (workspace_id, hash, path, content, language, kind, created_by, schema, summary, description, lock)
|
||||
VALUES ('test-workspace', 5555555555, 'f/test/error_handler', 'export function main() { return "handled"; }', 'deno', 'script', 'test-user', '{}', '', '', '')
|
||||
"#,
|
||||
)
|
||||
.execute(&db)
|
||||
.await?;
|
||||
|
||||
// Create a successful script
|
||||
let success_script_hash: i64 = 6666666666;
|
||||
sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO script (workspace_id, hash, path, content, language, kind, created_by, schema, summary, description, lock)
|
||||
VALUES ('test-workspace', $1, 'f/test/success_script', 'export function main() { return "ok"; }', 'deno', 'script', 'test-user', '{}', '', '', '')
|
||||
"#,
|
||||
success_script_hash,
|
||||
)
|
||||
.execute(&db)
|
||||
.await?;
|
||||
|
||||
// Set up the error handler
|
||||
sqlx::query!(
|
||||
r#"
|
||||
UPDATE workspace_settings
|
||||
SET error_handler = '{"path": "script/f/test/error_handler"}'::jsonb
|
||||
WHERE workspace_id = 'test-workspace'
|
||||
"#
|
||||
)
|
||||
.execute(&db)
|
||||
.await?;
|
||||
|
||||
sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO group_ (workspace_id, name, summary, extra_perms)
|
||||
VALUES ('test-workspace', 'error_handler', 'Error handler group', '{"u/test-user": true}')
|
||||
ON CONFLICT DO NOTHING
|
||||
"#
|
||||
)
|
||||
.execute(&db)
|
||||
.await?;
|
||||
|
||||
// Run the successful script
|
||||
let completed_job = RunJob::from(JobPayload::ScriptHash {
|
||||
hash: ScriptHash(success_script_hash),
|
||||
path: "f/test/success_script".to_string(),
|
||||
cache_ttl: None,
|
||||
cache_ignore_s3_path: None,
|
||||
dedicated_worker: None,
|
||||
language: ScriptLang::Deno,
|
||||
priority: None,
|
||||
apply_preprocessor: false,
|
||||
concurrency_settings: ConcurrencySettings::default(),
|
||||
debouncing_settings: DebouncingSettings::default(),
|
||||
})
|
||||
.run_until_complete(&db, false, server.addr.port())
|
||||
.await;
|
||||
|
||||
assert!(completed_job.success, "Job should have succeeded");
|
||||
|
||||
// Wait and check that NO error handler job was created
|
||||
tokio::time::sleep(tokio::time::Duration::from_millis(500)).await;
|
||||
|
||||
let error_handler_job = sqlx::query_scalar!(
|
||||
r#"
|
||||
SELECT id
|
||||
FROM v2_job
|
||||
WHERE workspace_id = 'test-workspace'
|
||||
AND permissioned_as_email = 'error_handler@windmill.dev'
|
||||
"#
|
||||
)
|
||||
.fetch_optional(&db)
|
||||
.await?;
|
||||
|
||||
assert!(
|
||||
error_handler_job.is_none(),
|
||||
"Error handler should NOT have been triggered for a successful job"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -25,8 +25,7 @@ use windmill_common::{
|
||||
scripts::ScriptLang,
|
||||
};
|
||||
|
||||
mod common;
|
||||
use common::*;
|
||||
use windmill_test_utils::*;
|
||||
|
||||
/// Helper to create a FlowModule with default fields
|
||||
fn flow_module(id: &str, value: FlowModuleValue) -> FlowModule {
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
mod common;
|
||||
|
||||
mod job_payload {
|
||||
use serde_json::json;
|
||||
use sqlx::{Pool, Postgres};
|
||||
@@ -8,7 +6,7 @@ mod job_payload {
|
||||
use windmill_common::scripts::{ScriptHash, ScriptLang};
|
||||
use windmill_common::flow_status::RestartedFrom;
|
||||
|
||||
use crate::common::*;
|
||||
use windmill_test_utils::*;
|
||||
use windmill_common::min_version::{
|
||||
MIN_VERSION, MIN_VERSION_IS_AT_LEAST_1_427, MIN_VERSION_IS_AT_LEAST_1_432,
|
||||
MIN_VERSION_IS_AT_LEAST_1_440,
|
||||
|
||||
@@ -7,8 +7,7 @@ use windmill_common::{
|
||||
scripts::ScriptLang,
|
||||
};
|
||||
|
||||
mod common;
|
||||
use common::*;
|
||||
use windmill_test_utils::*;
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct ListJobsResponse {
|
||||
|
||||
@@ -14,10 +14,7 @@
|
||||
*/
|
||||
|
||||
#[cfg(feature = "deno_core")]
|
||||
mod common;
|
||||
|
||||
#[cfg(feature = "deno_core")]
|
||||
use common::*;
|
||||
use windmill_test_utils::*;
|
||||
|
||||
#[cfg(feature = "deno_core")]
|
||||
use futures::StreamExt;
|
||||
|
||||
@@ -11,10 +11,7 @@
|
||||
*/
|
||||
|
||||
#[cfg(feature = "deno_core")]
|
||||
mod common;
|
||||
|
||||
#[cfg(feature = "deno_core")]
|
||||
use common::*;
|
||||
use windmill_test_utils::*;
|
||||
|
||||
#[cfg(feature = "deno_core")]
|
||||
use std::time::Instant;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
mod common;
|
||||
use crate::common::*;
|
||||
use windmill_test_utils::*;
|
||||
use sqlx::postgres::Postgres;
|
||||
use sqlx::Pool;
|
||||
use windmill_common::scripts::ScriptLang;
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
mod common;
|
||||
|
||||
#[cfg(feature = "deno_core")]
|
||||
mod retry {
|
||||
use crate::common::*;
|
||||
use windmill_test_utils::*;
|
||||
use serde_json::json;
|
||||
use sqlx::{Pool, Postgres};
|
||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use sqlx::{Pool, Postgres};
|
||||
|
||||
mod common;
|
||||
use common::*;
|
||||
use windmill_test_utils::*;
|
||||
|
||||
/// Test that the workspace success handler cache works correctly with 60s TTL
|
||||
#[cfg(feature = "deno_core")]
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
mod common;
|
||||
|
||||
mod suspend_resume {
|
||||
#[cfg(feature = "deno_core")]
|
||||
use serde_json::json;
|
||||
|
||||
#[cfg(feature = "deno_core")]
|
||||
use crate::common::*;
|
||||
use windmill_test_utils::*;
|
||||
|
||||
#[cfg(feature = "deno_core")]
|
||||
use futures::{Stream, StreamExt};
|
||||
|
||||
@@ -25,8 +25,7 @@ use windmill_common::{
|
||||
jobs::{JobPayload, RawCode},
|
||||
scripts::ScriptLang,
|
||||
};
|
||||
mod common;
|
||||
use common::*;
|
||||
use windmill_test_utils::*;
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
use futures::StreamExt;
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
mod common;
|
||||
mod workspace_dependencies {
|
||||
|
||||
use crate::common::in_test_worker;
|
||||
use crate::common::init_client;
|
||||
use crate::common::listen_for_completed_jobs;
|
||||
use windmill_test_utils::in_test_worker;
|
||||
use windmill_test_utils::init_client;
|
||||
use windmill_test_utils::listen_for_completed_jobs;
|
||||
use sqlx::{Pool, Postgres};
|
||||
use tokio_stream::StreamExt;
|
||||
use windmill_common::scripts::ScriptLang;
|
||||
|
||||
18
backend/windmill-alerting/Cargo.toml
Normal file
18
backend/windmill-alerting/Cargo.toml
Normal file
@@ -0,0 +1,18 @@
|
||||
[package]
|
||||
name = "windmill-alerting"
|
||||
version.workspace = true
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
[lib]
|
||||
name = "windmill_alerting"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
windmill-common = { workspace = true, default-features = false }
|
||||
axum.workspace = true
|
||||
chrono.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
sqlx.workspace = true
|
||||
tracing.workspace = true
|
||||
208
backend/windmill-alerting/src/lib.rs
Normal file
208
backend/windmill-alerting/src/lib.rs
Normal file
@@ -0,0 +1,208 @@
|
||||
use axum::Json;
|
||||
use serde::Deserialize;
|
||||
|
||||
use windmill_common::error::{self, JsonResult};
|
||||
use windmill_common::worker::CLOUD_HOSTED;
|
||||
use windmill_common::DB;
|
||||
|
||||
#[derive(serde::Serialize)]
|
||||
pub struct CriticalAlert {
|
||||
id: i32,
|
||||
alert_type: String,
|
||||
message: String,
|
||||
created_at: chrono::DateTime<chrono::Utc>,
|
||||
acknowledged: Option<bool>,
|
||||
workspace_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct AlertQueryParams {
|
||||
pub page: Option<i32>,
|
||||
pub page_size: Option<i32>,
|
||||
pub acknowledged: Option<bool>,
|
||||
}
|
||||
|
||||
pub async fn get_critical_alerts(
|
||||
db: DB,
|
||||
params: AlertQueryParams,
|
||||
workspace_id: Option<String>,
|
||||
) -> JsonResult<serde_json::Value> {
|
||||
let page = params.page.unwrap_or(1).max(1);
|
||||
let page_size = params.page_size.unwrap_or(10).min(100) as i64;
|
||||
let offset = ((page - 1) * page_size as i32) as i64;
|
||||
|
||||
let total_rows = if let Some(workspace_id) = &workspace_id {
|
||||
if params.acknowledged.is_none() {
|
||||
sqlx::query_scalar!(
|
||||
"SELECT COUNT(*)
|
||||
FROM alerts
|
||||
WHERE workspace_id = $1",
|
||||
workspace_id
|
||||
)
|
||||
.fetch_one(&db)
|
||||
.await?
|
||||
} else {
|
||||
sqlx::query_scalar!(
|
||||
"SELECT COUNT(*)
|
||||
FROM alerts
|
||||
WHERE workspace_id = $1 AND COALESCE(acknowledged_workspace, false) = $2",
|
||||
workspace_id,
|
||||
params.acknowledged
|
||||
)
|
||||
.fetch_one(&db)
|
||||
.await?
|
||||
}
|
||||
} else {
|
||||
if params.acknowledged.is_none() {
|
||||
sqlx::query_scalar!(
|
||||
"SELECT COUNT(*)
|
||||
FROM alerts"
|
||||
)
|
||||
.fetch_one(&db)
|
||||
.await?
|
||||
} else {
|
||||
sqlx::query_scalar!(
|
||||
"SELECT COUNT(*)
|
||||
FROM alerts
|
||||
WHERE COALESCE(acknowledged, false) = $1",
|
||||
params.acknowledged
|
||||
)
|
||||
.fetch_one(&db)
|
||||
.await?
|
||||
}
|
||||
};
|
||||
|
||||
let alerts = if let Some(workspace_id) = workspace_id {
|
||||
if params.acknowledged.is_none() {
|
||||
sqlx::query_as!(
|
||||
CriticalAlert,
|
||||
"SELECT id, alert_type, message, created_at, COALESCE(acknowledged_workspace, false) AS acknowledged, workspace_id
|
||||
FROM alerts
|
||||
WHERE workspace_id = $1
|
||||
ORDER BY created_at DESC
|
||||
LIMIT $2 OFFSET $3",
|
||||
workspace_id,
|
||||
page_size,
|
||||
offset
|
||||
)
|
||||
.fetch_all(&db)
|
||||
.await?
|
||||
} else {
|
||||
sqlx::query_as!(
|
||||
CriticalAlert,
|
||||
"SELECT id, alert_type, message, created_at, COALESCE(acknowledged_workspace, false) AS acknowledged, workspace_id
|
||||
FROM alerts
|
||||
WHERE workspace_id = $1 AND COALESCE(acknowledged_workspace, false) = $2
|
||||
ORDER BY created_at DESC
|
||||
LIMIT $3 OFFSET $4",
|
||||
workspace_id,
|
||||
params.acknowledged,
|
||||
page_size,
|
||||
offset
|
||||
)
|
||||
.fetch_all(&db)
|
||||
.await?
|
||||
}
|
||||
} else {
|
||||
if params.acknowledged.is_none() {
|
||||
sqlx::query_as!(
|
||||
CriticalAlert,
|
||||
"SELECT id, alert_type, message, created_at, COALESCE(acknowledged, false) AS acknowledged, workspace_id
|
||||
FROM alerts
|
||||
ORDER BY created_at DESC
|
||||
LIMIT $1 OFFSET $2",
|
||||
page_size,
|
||||
offset
|
||||
)
|
||||
.fetch_all(&db)
|
||||
.await?
|
||||
} else {
|
||||
sqlx::query_as!(
|
||||
CriticalAlert,
|
||||
"SELECT id, alert_type, message, created_at, COALESCE(acknowledged, false) AS acknowledged, workspace_id
|
||||
FROM alerts
|
||||
WHERE COALESCE(acknowledged, false) = $1
|
||||
ORDER BY created_at DESC
|
||||
LIMIT $2 OFFSET $3",
|
||||
params.acknowledged,
|
||||
page_size,
|
||||
offset
|
||||
)
|
||||
.fetch_all(&db)
|
||||
.await?
|
||||
}
|
||||
};
|
||||
|
||||
let total_rows = total_rows.unwrap_or(0);
|
||||
let total_pages = ((total_rows as f64) / (page_size as f64)).ceil() as i64;
|
||||
|
||||
Ok(Json(serde_json::json!({
|
||||
"alerts": alerts,
|
||||
"total_rows": total_rows,
|
||||
"total_pages": total_pages
|
||||
})))
|
||||
}
|
||||
|
||||
pub async fn acknowledge_critical_alert(
|
||||
db: DB,
|
||||
workspace_id: Option<String>,
|
||||
id: i32,
|
||||
) -> error::Result<String> {
|
||||
sqlx::query!(
|
||||
"UPDATE alerts
|
||||
SET
|
||||
acknowledged = true,
|
||||
acknowledged_workspace = CASE
|
||||
WHEN $3 THEN
|
||||
CASE
|
||||
WHEN $2::text IS NOT NULL AND workspace_id = $2 THEN true
|
||||
ELSE acknowledged_workspace
|
||||
END
|
||||
ELSE true
|
||||
END
|
||||
WHERE id = $1",
|
||||
id,
|
||||
workspace_id,
|
||||
*CLOUD_HOSTED
|
||||
)
|
||||
.execute(&db)
|
||||
.await?;
|
||||
|
||||
tracing::info!(
|
||||
"Acknowledged critical alert with id: {}{}",
|
||||
id,
|
||||
workspace_id.map_or_else(|| "".to_string(), |w| format!(" for workspace_id: {}", w))
|
||||
);
|
||||
Ok("Critical alert acknowledged".to_string())
|
||||
}
|
||||
|
||||
pub async fn acknowledge_all_critical_alerts(
|
||||
db: DB,
|
||||
workspace_id: Option<String>,
|
||||
) -> error::Result<String> {
|
||||
sqlx::query!(
|
||||
"UPDATE alerts
|
||||
SET
|
||||
acknowledged = true,
|
||||
acknowledged_workspace = CASE
|
||||
WHEN $2 THEN
|
||||
CASE
|
||||
WHEN $1::text IS NOT NULL THEN true
|
||||
ELSE acknowledged_workspace
|
||||
END
|
||||
ELSE true
|
||||
END
|
||||
WHERE ($1::text IS NOT NULL AND workspace_id = $1)
|
||||
OR ($1::text IS NULL)",
|
||||
workspace_id,
|
||||
*CLOUD_HOSTED
|
||||
)
|
||||
.execute(&db)
|
||||
.await?;
|
||||
|
||||
tracing::info!(
|
||||
"Acknowledged all unacknowledged critical alerts{}",
|
||||
workspace_id.map_or_else(|| "".to_string(), |w| format!(" for workspace_id: {}", w))
|
||||
);
|
||||
Ok("All unacknowledged critical alerts acknowledged".to_string())
|
||||
}
|
||||
35
backend/windmill-api-agent-workers/Cargo.toml
Normal file
35
backend/windmill-api-agent-workers/Cargo.toml
Normal file
@@ -0,0 +1,35 @@
|
||||
[package]
|
||||
name = "windmill-api-agent-workers"
|
||||
version.workspace = true
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
[lib]
|
||||
name = "windmill_api_agent_workers"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
enterprise = ["windmill-common/enterprise", "windmill-queue/enterprise"]
|
||||
private = ["windmill-common/private", "windmill-queue/private"]
|
||||
python = ["dep:windmill-parser-py-imports"]
|
||||
benchmark = []
|
||||
|
||||
[dependencies]
|
||||
windmill-api-auth.workspace = true
|
||||
windmill-common = { workspace = true, default-features = false }
|
||||
windmill-queue.workspace = true
|
||||
windmill-worker.workspace = true
|
||||
axum.workspace = true
|
||||
lazy_static.workspace = true
|
||||
chrono.workspace = true
|
||||
http.workspace = true
|
||||
hyper.workspace = true
|
||||
quick_cache.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
sqlx.workspace = true
|
||||
tokio.workspace = true
|
||||
tracing.workspace = true
|
||||
uuid.workspace = true
|
||||
windmill-parser-py-imports = { workspace = true, optional = true }
|
||||
@@ -1,6 +1,8 @@
|
||||
#[cfg(feature = "private")]
|
||||
mod ee;
|
||||
#[cfg(feature = "private")]
|
||||
#[allow(unused)]
|
||||
pub use crate::agent_workers_ee::*;
|
||||
pub use ee::*;
|
||||
|
||||
/*
|
||||
* Author: Ruben Fiszel
|
||||
@@ -11,7 +13,7 @@ pub use crate::agent_workers_ee::*;
|
||||
*/
|
||||
|
||||
#[cfg(not(feature = "private"))]
|
||||
use crate::db::DB;
|
||||
use windmill_common::DB;
|
||||
|
||||
#[cfg(not(feature = "private"))]
|
||||
use axum::Router;
|
||||
18
backend/windmill-api-assets/Cargo.toml
Normal file
18
backend/windmill-api-assets/Cargo.toml
Normal file
@@ -0,0 +1,18 @@
|
||||
[package]
|
||||
name = "windmill-api-assets"
|
||||
version.workspace = true
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
[lib]
|
||||
name = "windmill_api_assets"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
windmill-api-auth.workspace = true
|
||||
windmill-common = { workspace = true, default-features = false }
|
||||
axum.workspace = true
|
||||
chrono.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
sqlx.workspace = true
|
||||
@@ -12,7 +12,7 @@ use windmill_common::{
|
||||
error::JsonResult,
|
||||
};
|
||||
|
||||
use crate::db::ApiAuthed;
|
||||
use windmill_api_auth::ApiAuthed;
|
||||
|
||||
pub fn workspaced_service() -> Router {
|
||||
Router::new()
|
||||
29
backend/windmill-api-configs/Cargo.toml
Normal file
29
backend/windmill-api-configs/Cargo.toml
Normal file
@@ -0,0 +1,29 @@
|
||||
[package]
|
||||
name = "windmill-api-configs"
|
||||
version.workspace = true
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
[lib]
|
||||
name = "windmill_api_configs"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
enterprise = ["dep:windmill-autoscaling"]
|
||||
private = []
|
||||
python = []
|
||||
inline_preview = ["dep:windmill-worker", "dep:itertools"]
|
||||
|
||||
[dependencies]
|
||||
windmill-api-auth.workspace = true
|
||||
windmill-common = { workspace = true, default-features = false }
|
||||
windmill-audit.workspace = true
|
||||
windmill-autoscaling = { workspace = true, optional = true }
|
||||
windmill-worker = { workspace = true, optional = true }
|
||||
axum.workspace = true
|
||||
chrono.workspace = true
|
||||
itertools = { workspace = true, optional = true }
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
sqlx.workspace = true
|
||||
@@ -23,7 +23,7 @@ use windmill_common::{
|
||||
DB,
|
||||
};
|
||||
|
||||
use crate::{db::ApiAuthed, utils::require_devops_role};
|
||||
use windmill_api_auth::{ApiAuthed, require_devops_role};
|
||||
|
||||
pub fn global_service() -> Router {
|
||||
Router::new()
|
||||
28
backend/windmill-api-debug/Cargo.toml
Normal file
28
backend/windmill-api-debug/Cargo.toml
Normal file
@@ -0,0 +1,28 @@
|
||||
[package]
|
||||
name = "windmill-api-debug"
|
||||
version.workspace = true
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
[lib]
|
||||
name = "windmill_api_debug"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
windmill-api-auth.workspace = true
|
||||
windmill-common = { workspace = true, default-features = false }
|
||||
windmill-audit.workspace = true
|
||||
axum.workspace = true
|
||||
base64.workspace = true
|
||||
chrono.workspace = true
|
||||
ed25519-dalek.workspace = true
|
||||
hex.workspace = true
|
||||
lazy_static.workspace = true
|
||||
rand.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
sha2.workspace = true
|
||||
sqlx.workspace = true
|
||||
tokio.workspace = true
|
||||
tracing.workspace = true
|
||||
uuid.workspace = true
|
||||
@@ -41,7 +41,7 @@ use windmill_common::{
|
||||
users::username_to_permissioned_as,
|
||||
};
|
||||
|
||||
use crate::db::ApiAuthed;
|
||||
use windmill_api_auth::ApiAuthed;
|
||||
|
||||
/// TTL for debug tokens in seconds (60 seconds)
|
||||
pub const DEBUG_TOKEN_TTL_SECS: i64 = 60;
|
||||
@@ -6,6 +6,8 @@ use std::{collections::HashMap, path::PathBuf, sync::Arc};
|
||||
use windmill_common::DEFAULT_HUB_BASE_URL;
|
||||
#[cfg(feature = "embedding")]
|
||||
use windmill_common::HUB_BASE_URL;
|
||||
#[cfg(feature = "embedding")]
|
||||
use windmill_common::utils::HTTP_CLIENT_PERMISSIVE as HTTP_CLIENT;
|
||||
|
||||
use axum::Router;
|
||||
|
||||
@@ -54,13 +56,6 @@ lazy_static::lazy_static! {
|
||||
pub static ref EMBEDDINGS_DB: Arc<RwLock<Option<EmbeddingsDb>>> = Arc::new(RwLock::new(None));
|
||||
pub static ref MODEL_INSTANCE: Arc<RwLock<Option<Arc<ModelInstance>>>> = Arc::new(RwLock::new(None));
|
||||
pub static ref HUB_EMBEDDINGS_PULLING_INTERVAL_SECS: u64 = std::env::var("HUB_EMBEDDINGS_PULLING_INTERVAL_SECS").ok().map(|x| x.parse::<u64>().ok()).flatten().unwrap_or(3600 * 24);
|
||||
// Match windmill-api's HTTP_CLIENT config: 30s timeout, ACCEPT_INVALID_CERTS support
|
||||
static ref HTTP_CLIENT: reqwest::Client = windmill_common::utils::configure_client(reqwest::ClientBuilder::new()
|
||||
.user_agent("windmill/beta")
|
||||
.connect_timeout(std::time::Duration::from_secs(10))
|
||||
.timeout(std::time::Duration::from_secs(30))
|
||||
.danger_accept_invalid_certs(std::env::var("ACCEPT_INVALID_CERTS").is_ok()))
|
||||
.build().unwrap();
|
||||
}
|
||||
|
||||
#[cfg(feature = "embedding")]
|
||||
|
||||
21
backend/windmill-api-flow-conversations/Cargo.toml
Normal file
21
backend/windmill-api-flow-conversations/Cargo.toml
Normal file
@@ -0,0 +1,21 @@
|
||||
[package]
|
||||
name = "windmill-api-flow-conversations"
|
||||
version.workspace = true
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
[lib]
|
||||
name = "windmill_api_flow_conversations"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
windmill-api-auth.workspace = true
|
||||
windmill-common = { workspace = true, default-features = false }
|
||||
axum.workspace = true
|
||||
chrono.workspace = true
|
||||
serde.workspace = true
|
||||
sql-builder.workspace = true
|
||||
sqlx.workspace = true
|
||||
tokio.workspace = true
|
||||
tracing.workspace = true
|
||||
uuid.workspace = true
|
||||
@@ -9,7 +9,7 @@ use sql_builder::prelude::*;
|
||||
use sqlx::{FromRow, Postgres};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::db::ApiAuthed;
|
||||
use windmill_api_auth::ApiAuthed;
|
||||
pub use windmill_common::flow_conversations::FlowConversation;
|
||||
use windmill_common::{
|
||||
db::{UserDB, DB},
|
||||
31
backend/windmill-api-flows/Cargo.toml
Normal file
31
backend/windmill-api-flows/Cargo.toml
Normal file
@@ -0,0 +1,31 @@
|
||||
[package]
|
||||
name = "windmill-api-flows"
|
||||
version.workspace = true
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
[lib]
|
||||
name = "windmill_api_flows"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
enterprise = ["windmill-common/enterprise"]
|
||||
private = ["windmill-common/private"]
|
||||
|
||||
[dependencies]
|
||||
windmill-common = { workspace = true, default-features = false }
|
||||
windmill-api-auth.workspace = true
|
||||
windmill-queue.workspace = true
|
||||
windmill-audit.workspace = true
|
||||
windmill-git-sync.workspace = true
|
||||
windmill-dep-map.workspace = true
|
||||
|
||||
axum.workspace = true
|
||||
hyper.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
sql-builder.workspace = true
|
||||
sqlx.workspace = true
|
||||
tracing.workspace = true
|
||||
chrono.workspace = true
|
||||
9
backend/windmill-api-flows/src/lib.rs
Normal file
9
backend/windmill-api-flows/src/lib.rs
Normal file
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
* Author: Ruben Fiszel
|
||||
* Copyright: Windmill Labs, Inc 2022
|
||||
* This file and its contents are licensed under the AGPLv3 License.
|
||||
* Please see the included NOTICE for copyright information and
|
||||
* LICENSE-AGPL for a copy of the license.
|
||||
*/
|
||||
|
||||
pub mod flows;
|
||||
19
backend/windmill-api-inputs/Cargo.toml
Normal file
19
backend/windmill-api-inputs/Cargo.toml
Normal file
@@ -0,0 +1,19 @@
|
||||
[package]
|
||||
name = "windmill-api-inputs"
|
||||
version.workspace = true
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
[lib]
|
||||
name = "windmill_api_inputs"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
windmill-api-auth.workspace = true
|
||||
windmill-common = { workspace = true, default-features = false }
|
||||
axum.workspace = true
|
||||
chrono.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
sql-builder.workspace = true
|
||||
sqlx.workspace = true
|
||||
@@ -6,7 +6,7 @@
|
||||
* LICENSE-AGPL for a copy of the license.
|
||||
*/
|
||||
|
||||
use crate::db::ApiAuthed;
|
||||
use windmill_api_auth::ApiAuthed;
|
||||
use axum::{
|
||||
extract::{Path, Query},
|
||||
routing::{get, post},
|
||||
36
backend/windmill-api-integration-tests/Cargo.toml
Normal file
36
backend/windmill-api-integration-tests/Cargo.toml
Normal file
@@ -0,0 +1,36 @@
|
||||
[package]
|
||||
name = "windmill-api-integration-tests"
|
||||
version.workspace = true
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
[lib]
|
||||
name = "windmill_api_integration_tests"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
private = ["windmill-test-utils/private", "dep:aws-config", "dep:aws-credential-types", "dep:aws-sdk-sqs"]
|
||||
enterprise = ["windmill-test-utils/enterprise", "dep:base64"]
|
||||
deno_core = ["windmill-test-utils/deno_core"]
|
||||
mcp = []
|
||||
|
||||
[dependencies]
|
||||
windmill-test-utils.workspace = true
|
||||
windmill-api-client.workspace = true
|
||||
windmill-common = { workspace = true, default-features = false }
|
||||
sqlx.workspace = true
|
||||
serde_json.workspace = true
|
||||
serde.workspace = true
|
||||
reqwest.workspace = true
|
||||
tokio.workspace = true
|
||||
anyhow.workspace = true
|
||||
uuid.workspace = true
|
||||
rand.workspace = true
|
||||
rumqttc.workspace = true
|
||||
rdkafka.workspace = true
|
||||
async-nats.workspace = true
|
||||
aws-config = { workspace = true, optional = true }
|
||||
aws-credential-types = { workspace = true, optional = true }
|
||||
aws-sdk-sqs = { workspace = true, optional = true }
|
||||
base64 = { workspace = true, optional = true }
|
||||
2
backend/windmill-api-integration-tests/src/lib.rs
Normal file
2
backend/windmill-api-integration-tests/src/lib.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
// This crate exists only to host integration tests.
|
||||
// See tests/ directory for the actual test files.
|
||||
@@ -1,8 +1,7 @@
|
||||
use serde_json::json;
|
||||
use sqlx::{Pool, Postgres};
|
||||
|
||||
mod common;
|
||||
use common::*;
|
||||
use windmill_test_utils::*;
|
||||
|
||||
fn app_url(port: u16, endpoint: &str, path: &str) -> String {
|
||||
format!("http://localhost:{port}/api/w/test-workspace/apps/{endpoint}/{path}")
|
||||
@@ -40,7 +39,7 @@ fn new_app(path: &str, summary: &str) -> serde_json::Value {
|
||||
})
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_app_endpoints(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
initialize_tracing().await;
|
||||
let server = ApiServer::start(db.clone()).await?;
|
||||
@@ -1,8 +1,7 @@
|
||||
use serde_json::json;
|
||||
use sqlx::{Pool, Postgres};
|
||||
|
||||
mod common;
|
||||
use common::*;
|
||||
use windmill_test_utils::*;
|
||||
|
||||
fn client() -> reqwest::Client {
|
||||
reqwest::Client::new()
|
||||
@@ -12,7 +11,7 @@ fn authed(builder: reqwest::RequestBuilder) -> reqwest::RequestBuilder {
|
||||
builder.header("Authorization", "Bearer SECRET_TOKEN")
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_draft_endpoints(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
initialize_tracing().await;
|
||||
let server = ApiServer::start(db.clone()).await?;
|
||||
146
backend/windmill-api-integration-tests/tests/fixtures/base.sql
vendored
Normal file
146
backend/windmill-api-integration-tests/tests/fixtures/base.sql
vendored
Normal file
@@ -0,0 +1,146 @@
|
||||
-- used for backend automated testing
|
||||
-- https://docs.rs/sqlx/latest/sqlx/attr.test.html
|
||||
|
||||
INSERT INTO workspace
|
||||
(id, name, owner)
|
||||
VALUES ('test-workspace', 'test-workspace', 'test-user');
|
||||
|
||||
INSERT INTO usr(workspace_id, email, username, is_admin, role) VALUES
|
||||
('test-workspace', 'test@windmill.dev', 'test-user', true, 'Admin');
|
||||
|
||||
INSERT INTO workspace_key(workspace_id, kind, key) VALUES
|
||||
('test-workspace', 'cloud', 'test-key');
|
||||
|
||||
|
||||
INSERT INTO workspace_settings (workspace_id) VALUES
|
||||
('test-workspace');
|
||||
|
||||
INSERT INTO group_ (workspace_id, name, summary, extra_perms) VALUES
|
||||
('test-workspace', 'all', 'All users', '{}');
|
||||
|
||||
INSERT INTO password(email, password_hash, login_type, super_admin, verified, name, username)
|
||||
VALUES ('test@windmill.dev', 'not-a-real-hash', 'password', true, true, 'Test User', 'test-user');
|
||||
|
||||
INSERT INTO password(email, password_hash, login_type, super_admin, verified, name)
|
||||
VALUES ('test2@windmill.dev', 'not-a-real-hash', 'password', false, true, 'Test User 2');
|
||||
|
||||
INSERT INTO password(email, password_hash, login_type, super_admin, verified, name)
|
||||
VALUES ('test3@windmill.dev', 'not-a-real-hash', 'password', false, true, 'Test User 3');
|
||||
|
||||
INSERT INTO usr(workspace_id, email, username, is_admin, role) VALUES
|
||||
('test-workspace', 'test2@windmill.dev', 'test-user-2', false, 'User');
|
||||
|
||||
INSERT INTO usr(workspace_id, email, username, is_admin, role) VALUES
|
||||
('test-workspace', 'test3@windmill.dev', 'test-user-3', false, 'User');
|
||||
|
||||
insert INTO token(token, email, label, super_admin) VALUES ('SECRET_TOKEN', 'test@windmill.dev', 'test token', true);
|
||||
insert INTO token(token, email, label, super_admin) VALUES ('SECRET_TOKEN_2', 'test2@windmill.dev', 'test token 2', false);
|
||||
insert INTO token(token, email, label, super_admin) VALUES ('SECRET_TOKEN_3', 'test3@windmill.dev', 'test token 3', false);
|
||||
|
||||
GRANT ALL PRIVILEGES ON TABLE workspace_key TO windmill_admin;
|
||||
GRANT ALL PRIVILEGES ON TABLE workspace_key TO windmill_user;
|
||||
|
||||
CREATE FUNCTION "notify_insert_on_completed_job" ()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
PERFORM pg_notify('completed', NEW.id::text);
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE PLPGSQL;
|
||||
|
||||
CREATE TRIGGER "notify_insert_on_completed_job"
|
||||
AFTER INSERT ON "v2_job_completed"
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION "notify_insert_on_completed_job" ();
|
||||
|
||||
|
||||
CREATE FUNCTION "notify_queue" ()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
PERFORM pg_notify('queued', NEW.id::text);
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE PLPGSQL;
|
||||
|
||||
CREATE TRIGGER "notify_queue_after_insert"
|
||||
AFTER INSERT ON "v2_job_queue"
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION "notify_queue" ();
|
||||
|
||||
CREATE TRIGGER "notify_queue_after_flow_status_update"
|
||||
AFTER UPDATE ON "v2_job_status"
|
||||
FOR EACH ROW
|
||||
WHEN (NEW.flow_status IS DISTINCT FROM OLD.flow_status)
|
||||
EXECUTE FUNCTION "notify_queue" ();
|
||||
|
||||
-- Apply phase 4:
|
||||
DROP FUNCTION IF EXISTS v2_job_after_update CASCADE;
|
||||
DROP FUNCTION IF EXISTS v2_job_completed_before_insert CASCADE;
|
||||
DROP FUNCTION IF EXISTS v2_job_completed_before_update CASCADE;
|
||||
DROP FUNCTION IF EXISTS v2_job_queue_after_insert CASCADE;
|
||||
DROP FUNCTION IF EXISTS v2_job_queue_before_insert CASCADE;
|
||||
DROP FUNCTION IF EXISTS v2_job_queue_before_update CASCADE;
|
||||
DROP FUNCTION IF EXISTS v2_job_runtime_before_insert CASCADE;
|
||||
DROP FUNCTION IF EXISTS v2_job_runtime_before_update CASCADE;
|
||||
DROP FUNCTION IF EXISTS v2_job_status_before_insert CASCADE;
|
||||
DROP FUNCTION IF EXISTS v2_job_status_before_update CASCADE;
|
||||
|
||||
DROP VIEW IF EXISTS completed_job, completed_job_view, job, queue, queue_view CASCADE;
|
||||
|
||||
ALTER TABLE v2_job_queue
|
||||
DROP COLUMN IF EXISTS __parent_job CASCADE,
|
||||
DROP COLUMN IF EXISTS __created_by CASCADE,
|
||||
DROP COLUMN IF EXISTS __script_hash CASCADE,
|
||||
DROP COLUMN IF EXISTS __script_path CASCADE,
|
||||
DROP COLUMN IF EXISTS __args CASCADE,
|
||||
DROP COLUMN IF EXISTS __logs CASCADE,
|
||||
DROP COLUMN IF EXISTS __raw_code CASCADE,
|
||||
DROP COLUMN IF EXISTS __canceled CASCADE,
|
||||
DROP COLUMN IF EXISTS __last_ping CASCADE,
|
||||
DROP COLUMN IF EXISTS __job_kind CASCADE,
|
||||
DROP COLUMN IF EXISTS __env_id CASCADE,
|
||||
DROP COLUMN IF EXISTS __schedule_path CASCADE,
|
||||
DROP COLUMN IF EXISTS __permissioned_as CASCADE,
|
||||
DROP COLUMN IF EXISTS __flow_status CASCADE,
|
||||
DROP COLUMN IF EXISTS __raw_flow CASCADE,
|
||||
DROP COLUMN IF EXISTS __is_flow_step CASCADE,
|
||||
DROP COLUMN IF EXISTS __language CASCADE,
|
||||
DROP COLUMN IF EXISTS __same_worker CASCADE,
|
||||
DROP COLUMN IF EXISTS __raw_lock CASCADE,
|
||||
DROP COLUMN IF EXISTS __pre_run_error CASCADE,
|
||||
DROP COLUMN IF EXISTS __email CASCADE,
|
||||
DROP COLUMN IF EXISTS __visible_to_owner CASCADE,
|
||||
DROP COLUMN IF EXISTS __mem_peak CASCADE,
|
||||
DROP COLUMN IF EXISTS __root_job CASCADE,
|
||||
DROP COLUMN IF EXISTS __leaf_jobs CASCADE,
|
||||
DROP COLUMN IF EXISTS __concurrent_limit CASCADE,
|
||||
DROP COLUMN IF EXISTS __concurrency_time_window_s CASCADE,
|
||||
DROP COLUMN IF EXISTS __timeout CASCADE,
|
||||
DROP COLUMN IF EXISTS __flow_step_id CASCADE,
|
||||
DROP COLUMN IF EXISTS __cache_ttl CASCADE;
|
||||
|
||||
LOCK TABLE v2_job_queue IN ACCESS EXCLUSIVE MODE;
|
||||
ALTER TABLE v2_job_completed
|
||||
DROP COLUMN IF EXISTS __parent_job CASCADE,
|
||||
DROP COLUMN IF EXISTS __created_by CASCADE,
|
||||
DROP COLUMN IF EXISTS __created_at CASCADE,
|
||||
DROP COLUMN IF EXISTS __success CASCADE,
|
||||
DROP COLUMN IF EXISTS __script_hash CASCADE,
|
||||
DROP COLUMN IF EXISTS __script_path CASCADE,
|
||||
DROP COLUMN IF EXISTS __args CASCADE,
|
||||
DROP COLUMN IF EXISTS __logs CASCADE,
|
||||
DROP COLUMN IF EXISTS __raw_code CASCADE,
|
||||
DROP COLUMN IF EXISTS __canceled CASCADE,
|
||||
DROP COLUMN IF EXISTS __job_kind CASCADE,
|
||||
DROP COLUMN IF EXISTS __env_id CASCADE,
|
||||
DROP COLUMN IF EXISTS __schedule_path CASCADE,
|
||||
DROP COLUMN IF EXISTS __permissioned_as CASCADE,
|
||||
DROP COLUMN IF EXISTS __raw_flow CASCADE,
|
||||
DROP COLUMN IF EXISTS __is_flow_step CASCADE,
|
||||
DROP COLUMN IF EXISTS __language CASCADE,
|
||||
DROP COLUMN IF EXISTS __is_skipped CASCADE,
|
||||
DROP COLUMN IF EXISTS __raw_lock CASCADE,
|
||||
DROP COLUMN IF EXISTS __email CASCADE,
|
||||
DROP COLUMN IF EXISTS __visible_to_owner CASCADE,
|
||||
DROP COLUMN IF EXISTS __tag CASCADE,
|
||||
DROP COLUMN IF EXISTS __priority CASCADE;
|
||||
238
backend/windmill-api-integration-tests/tests/fixtures/permissions_test.sql
vendored
Normal file
238
backend/windmill-api-integration-tests/tests/fixtures/permissions_test.sql
vendored
Normal file
@@ -0,0 +1,238 @@
|
||||
-- Permissions test fixture
|
||||
-- This sets up a comprehensive permission testing scenario
|
||||
|
||||
-- ============================================
|
||||
-- USERS
|
||||
-- ============================================
|
||||
|
||||
-- Admin user (may already exist from base.sql, use ON CONFLICT)
|
||||
INSERT INTO usr (workspace_id, email, username, is_admin, role)
|
||||
VALUES ('test-workspace', 'admin@windmill.dev', 'admin', true, 'Admin')
|
||||
ON CONFLICT (workspace_id, username) DO NOTHING;
|
||||
|
||||
-- Regular users (non-admin)
|
||||
INSERT INTO usr (workspace_id, email, username, is_admin, role)
|
||||
VALUES
|
||||
('test-workspace', 'alice@windmill.dev', 'alice', false, 'Developer'),
|
||||
('test-workspace', 'bob@windmill.dev', 'bob', false, 'Developer'),
|
||||
('test-workspace', 'charlie@windmill.dev', 'charlie', false, 'Developer');
|
||||
|
||||
-- Operator user (can execute but cannot create/update scripts, flows, apps)
|
||||
INSERT INTO usr (workspace_id, email, username, is_admin, operator, role)
|
||||
VALUES
|
||||
('test-workspace', 'operator@windmill.dev', 'operator', false, true, 'Operator');
|
||||
|
||||
-- Add users to password table (use ON CONFLICT since admin may exist from base.sql)
|
||||
INSERT INTO password (email, password_hash, login_type, super_admin, verified, name)
|
||||
VALUES
|
||||
('admin@windmill.dev', 'dummy_hash', 'password', false, true, 'Admin User'),
|
||||
('alice@windmill.dev', 'dummy_hash', 'password', false, true, 'Alice'),
|
||||
('bob@windmill.dev', 'dummy_hash', 'password', false, true, 'Bob'),
|
||||
('charlie@windmill.dev', 'dummy_hash', 'password', false, true, 'Charlie'),
|
||||
('operator@windmill.dev', 'dummy_hash', 'password', false, true, 'Operator')
|
||||
ON CONFLICT (email) DO NOTHING;
|
||||
|
||||
-- ============================================
|
||||
-- TOKENS for authentication
|
||||
-- ============================================
|
||||
|
||||
-- Tokens associated with emails (workspace-scoped)
|
||||
-- The auth system will look up the user by email in the usr table
|
||||
-- Note: tokens must be at least 10 characters (TOKEN_PREFIX_LEN)
|
||||
INSERT INTO token (token, email, label, super_admin, owner, workspace_id)
|
||||
VALUES
|
||||
('ADMIN_TOKEN_TEST', 'admin@windmill.dev', 'Admin token', false, 'u/admin', 'test-workspace'),
|
||||
('ALICE_TOKEN_TEST', 'alice@windmill.dev', 'Alice token', false, 'u/alice', 'test-workspace'),
|
||||
('BOB_TOKEN_TEST12', 'bob@windmill.dev', 'Bob token', false, 'u/bob', 'test-workspace'),
|
||||
('CHARLIE_TOKEN_01', 'charlie@windmill.dev', 'Charlie token', false, 'u/charlie', 'test-workspace'),
|
||||
('OPERATOR_TOKEN_1', 'operator@windmill.dev', 'Operator token', false, 'u/operator', 'test-workspace');
|
||||
|
||||
-- ============================================
|
||||
-- GROUPS
|
||||
-- ============================================
|
||||
|
||||
-- 'developers' group - Charlie is a member
|
||||
INSERT INTO group_ (workspace_id, name, summary, extra_perms)
|
||||
VALUES ('test-workspace', 'developers', 'Developer group', '{}');
|
||||
|
||||
-- 'editors' group - Bob is a member (has write access to some folders)
|
||||
INSERT INTO group_ (workspace_id, name, summary, extra_perms)
|
||||
VALUES ('test-workspace', 'editors', 'Editor group', '{}');
|
||||
|
||||
-- Group memberships
|
||||
INSERT INTO usr_to_group (workspace_id, group_, usr)
|
||||
VALUES
|
||||
('test-workspace', 'developers', 'charlie'),
|
||||
('test-workspace', 'editors', 'bob');
|
||||
|
||||
-- ============================================
|
||||
-- FOLDERS
|
||||
-- ============================================
|
||||
|
||||
-- 'shared' folder:
|
||||
-- - Alice has read-only access (extra_perms: u/alice -> false)
|
||||
-- - Bob has write access (extra_perms: u/bob -> true)
|
||||
INSERT INTO folder (workspace_id, name, display_name, owners, extra_perms, created_by)
|
||||
VALUES ('test-workspace', 'shared', 'Shared Folder', '{"u/admin"}',
|
||||
'{"u/alice": false, "u/bob": true}', 'admin');
|
||||
|
||||
-- 'team' folder:
|
||||
-- - 'developers' group has read-only access
|
||||
INSERT INTO folder (workspace_id, name, display_name, owners, extra_perms, created_by)
|
||||
VALUES ('test-workspace', 'team', 'Team Folder', '{"u/admin"}',
|
||||
'{"g/developers": false}', 'admin');
|
||||
|
||||
-- 'editable' folder:
|
||||
-- - 'editors' group has write access
|
||||
INSERT INTO folder (workspace_id, name, display_name, owners, extra_perms, created_by)
|
||||
VALUES ('test-workspace', 'editable', 'Editable Folder', '{"u/admin"}',
|
||||
'{"g/editors": true}', 'admin');
|
||||
|
||||
-- 'admin_only' folder:
|
||||
-- - Only admin has access (but we'll add item-level perms for specific items)
|
||||
INSERT INTO folder (workspace_id, name, display_name, owners, extra_perms, created_by)
|
||||
VALUES ('test-workspace', 'admin_only', 'Admin Only Folder', '{"u/admin"}',
|
||||
'{}', 'admin');
|
||||
|
||||
-- 'alice_owned' folder:
|
||||
-- - Alice is an owner (owners must also be in extra_perms for get_folders_for_user to find them)
|
||||
INSERT INTO folder (workspace_id, name, display_name, owners, extra_perms, created_by)
|
||||
VALUES ('test-workspace', 'alice_owned', 'Alice Owned Folder', '{"u/alice"}',
|
||||
'{"u/alice": true}', 'alice');
|
||||
|
||||
-- ============================================
|
||||
-- SCRIPTS
|
||||
-- ============================================
|
||||
|
||||
-- Alice's personal script
|
||||
INSERT INTO script (workspace_id, hash, path, content, language, kind, created_by, schema, summary, description, lock, extra_perms)
|
||||
VALUES ('test-workspace', 1001, 'u/alice/my_script',
|
||||
'export function main() { return "alice script"; }',
|
||||
'deno', 'script', 'alice', '{}', 'Alice script', '', '', '{}');
|
||||
|
||||
-- Bob's personal script
|
||||
INSERT INTO script (workspace_id, hash, path, content, language, kind, created_by, schema, summary, description, lock, extra_perms)
|
||||
VALUES ('test-workspace', 1002, 'u/bob/my_script',
|
||||
'export function main() { return "bob script"; }',
|
||||
'deno', 'script', 'bob', '{}', 'Bob script', '', '', '{}');
|
||||
|
||||
-- Script in shared folder (accessible by Alice read-only, Bob write)
|
||||
INSERT INTO script (workspace_id, hash, path, content, language, kind, created_by, schema, summary, description, lock, extra_perms)
|
||||
VALUES ('test-workspace', 1003, 'f/shared/public_script',
|
||||
'export function main() { return "public"; }',
|
||||
'deno', 'script', 'admin', '{}', 'Public script', '', '', '{}');
|
||||
|
||||
-- Script in team folder (accessible by developers group)
|
||||
INSERT INTO script (workspace_id, hash, path, content, language, kind, created_by, schema, summary, description, lock, extra_perms)
|
||||
VALUES ('test-workspace', 1004, 'f/team/team_script',
|
||||
'export function main() { return "team"; }',
|
||||
'deno', 'script', 'admin', '{}', 'Team script', '', '', '{}');
|
||||
|
||||
-- Script in admin_only folder but with explicit share to Alice
|
||||
INSERT INTO script (workspace_id, hash, path, content, language, kind, created_by, schema, summary, description, lock, extra_perms)
|
||||
VALUES ('test-workspace', 1005, 'f/admin_only/shared_with_alice',
|
||||
'export function main() { return "shared"; }',
|
||||
'deno', 'script', 'admin', '{}', 'Shared with Alice', '', '',
|
||||
'{"u/alice": false}');
|
||||
|
||||
-- Script in alice_owned folder
|
||||
INSERT INTO script (workspace_id, hash, path, content, language, kind, created_by, schema, summary, description, lock, extra_perms)
|
||||
VALUES ('test-workspace', 1006, 'f/alice_owned/owner_script',
|
||||
'export function main() { return "owner"; }',
|
||||
'deno', 'script', 'alice', '{}', 'Owner script', '', '', '{}');
|
||||
|
||||
-- Alice's script with extra_perms sharing to Bob (read-only)
|
||||
INSERT INTO script (workspace_id, hash, path, content, language, kind, created_by, schema, summary, description, lock, extra_perms)
|
||||
VALUES ('test-workspace', 1007, 'u/alice/extra_shared_script',
|
||||
'export function main() { return "extra shared"; }',
|
||||
'deno', 'script', 'alice', '{}', 'Extra shared script', '', '',
|
||||
'{"u/bob": false}');
|
||||
|
||||
-- ============================================
|
||||
-- FLOWS (with flow_versions)
|
||||
-- ============================================
|
||||
|
||||
-- Create flows first (without versions)
|
||||
INSERT INTO flow (workspace_id, path, summary, description, value, edited_by, edited_at, schema, extra_perms)
|
||||
VALUES
|
||||
('test-workspace', 'u/alice/my_flow', 'Alice flow', '', '{"modules": []}', 'alice', NOW(), '{}', '{}'),
|
||||
('test-workspace', 'u/bob/my_flow', 'Bob flow', '', '{"modules": []}', 'bob', NOW(), '{}', '{}'),
|
||||
('test-workspace', 'f/shared/shared_flow', 'Shared flow', '', '{"modules": []}', 'admin', NOW(), '{}', '{}');
|
||||
|
||||
-- Create flow versions
|
||||
INSERT INTO flow_version (id, workspace_id, path, value, schema, created_by, created_at)
|
||||
VALUES
|
||||
(1001, 'test-workspace', 'u/alice/my_flow', '{"modules": []}', '{}', 'alice', NOW()),
|
||||
(1002, 'test-workspace', 'u/bob/my_flow', '{"modules": []}', '{}', 'bob', NOW()),
|
||||
(1003, 'test-workspace', 'f/shared/shared_flow', '{"modules": []}', '{}', 'admin', NOW());
|
||||
|
||||
-- Update flows with version references
|
||||
UPDATE flow SET versions = ARRAY[1001::bigint] WHERE path = 'u/alice/my_flow' AND workspace_id = 'test-workspace';
|
||||
UPDATE flow SET versions = ARRAY[1002::bigint] WHERE path = 'u/bob/my_flow' AND workspace_id = 'test-workspace';
|
||||
UPDATE flow SET versions = ARRAY[1003::bigint] WHERE path = 'f/shared/shared_flow' AND workspace_id = 'test-workspace';
|
||||
|
||||
-- ============================================
|
||||
-- RESOURCES
|
||||
-- ============================================
|
||||
|
||||
-- Alice's personal resource
|
||||
INSERT INTO resource (workspace_id, path, value, description, resource_type, extra_perms, created_by)
|
||||
VALUES ('test-workspace', 'u/alice/my_resource', '{"key": "alice_value"}',
|
||||
'Alice resource', 'object', '{}', 'alice');
|
||||
|
||||
-- Bob's personal resource
|
||||
INSERT INTO resource (workspace_id, path, value, description, resource_type, extra_perms, created_by)
|
||||
VALUES ('test-workspace', 'u/bob/my_resource', '{"key": "bob_value"}',
|
||||
'Bob resource', 'object', '{}', 'bob');
|
||||
|
||||
-- ============================================
|
||||
-- VARIABLES
|
||||
-- ============================================
|
||||
|
||||
-- Alice's personal variable (non-secret for testing permissions, not encryption)
|
||||
INSERT INTO variable (workspace_id, path, value, is_secret, description, extra_perms)
|
||||
VALUES ('test-workspace', 'u/alice/my_variable', 'alice_value', false,
|
||||
'Alice variable', '{}');
|
||||
|
||||
-- Bob's personal variable (non-secret for testing permissions, not encryption)
|
||||
INSERT INTO variable (workspace_id, path, value, is_secret, description, extra_perms)
|
||||
VALUES ('test-workspace', 'u/bob/my_variable', 'bob_value', false,
|
||||
'Bob variable', '{}');
|
||||
|
||||
-- ============================================
|
||||
-- SCHEDULES
|
||||
-- ============================================
|
||||
|
||||
-- Alice's personal schedule
|
||||
INSERT INTO schedule (workspace_id, path, edited_by, edited_at, schedule, enabled, script_path, args, is_flow, email, timezone, extra_perms)
|
||||
VALUES ('test-workspace', 'u/alice/my_schedule', 'alice', NOW(), '0 * * * *', false,
|
||||
'u/alice/my_script', '{}', false, 'alice@windmill.dev', 'UTC', '{}');
|
||||
|
||||
-- Bob's personal schedule
|
||||
INSERT INTO schedule (workspace_id, path, edited_by, edited_at, schedule, enabled, script_path, args, is_flow, email, timezone, extra_perms)
|
||||
VALUES ('test-workspace', 'u/bob/my_schedule', 'bob', NOW(), '0 * * * *', false,
|
||||
'u/bob/my_script', '{}', false, 'bob@windmill.dev', 'UTC', '{}');
|
||||
|
||||
-- ============================================
|
||||
-- APPS (with app_versions)
|
||||
-- ============================================
|
||||
|
||||
-- Alice's personal app
|
||||
INSERT INTO app (id, workspace_id, path, summary, versions, policy, extra_perms)
|
||||
VALUES (2001, 'test-workspace', 'u/alice/my_app', 'Alice app', '{}',
|
||||
'{"on_behalf_of": "u/alice", "on_behalf_of_email": "alice@windmill.dev", "execution_mode": "viewer"}', '{}');
|
||||
|
||||
-- Shared folder app
|
||||
INSERT INTO app (id, workspace_id, path, summary, versions, policy, extra_perms)
|
||||
VALUES (2002, 'test-workspace', 'f/shared/shared_app', 'Shared app', '{}',
|
||||
'{"on_behalf_of": "u/admin", "on_behalf_of_email": "admin@windmill.dev", "execution_mode": "viewer"}', '{}');
|
||||
|
||||
-- Create app versions
|
||||
INSERT INTO app_version (id, app_id, value, created_by, created_at)
|
||||
VALUES
|
||||
(2001, 2001, '{"grid": []}', 'alice', NOW()),
|
||||
(2002, 2002, '{"grid": []}', 'admin', NOW());
|
||||
|
||||
-- Update apps with version references
|
||||
UPDATE app SET versions = ARRAY[2001::bigint] WHERE id = 2001;
|
||||
UPDATE app SET versions = ARRAY[2002::bigint] WHERE id = 2002;
|
||||
69
backend/windmill-api-integration-tests/tests/fixtures/resources_test.sql
vendored
Normal file
69
backend/windmill-api-integration-tests/tests/fixtures/resources_test.sql
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
-- Combined fixture for resource endpoint tests
|
||||
|
||||
-- === resource type test data ===
|
||||
|
||||
INSERT INTO resource_type (workspace_id, name, schema, description, created_by)
|
||||
VALUES ('test-workspace', 'test_db', '{"type": "object", "properties": {"host": {"type": "string"}}}',
|
||||
'Test DB type', 'test-user');
|
||||
|
||||
-- === get_value_interpolated test data ===
|
||||
|
||||
INSERT INTO resource (workspace_id, path, value, description, resource_type, extra_perms, created_by)
|
||||
VALUES ('test-workspace', 'u/test-user/simple_resource', '{"host": "localhost", "port": 5432}',
|
||||
'Simple resource', 'object', '{}', 'test-user');
|
||||
|
||||
INSERT INTO variable (workspace_id, path, value, is_secret, description, extra_perms)
|
||||
VALUES ('test-workspace', 'u/test-user/db_password', 'hunter2', false, 'DB password', '{}');
|
||||
|
||||
INSERT INTO resource (workspace_id, path, value, description, resource_type, extra_perms, created_by)
|
||||
VALUES ('test-workspace', 'u/test-user/resource_with_var', '{"host": "localhost", "password": "$var:u/test-user/db_password"}',
|
||||
'Resource with var ref', 'object', '{}', 'test-user');
|
||||
|
||||
INSERT INTO resource (workspace_id, path, value, description, resource_type, extra_perms, created_by)
|
||||
VALUES ('test-workspace', 'u/test-user/db_credentials', '{"user": "admin", "password": "secret123"}',
|
||||
'DB credentials', 'object', '{}', 'test-user');
|
||||
|
||||
INSERT INTO resource (workspace_id, path, value, description, resource_type, extra_perms, created_by)
|
||||
VALUES ('test-workspace', 'u/test-user/resource_with_res', '{"host": "localhost", "credentials": "$res:u/test-user/db_credentials"}',
|
||||
'Resource with res ref', 'object', '{}', 'test-user');
|
||||
|
||||
INSERT INTO resource (workspace_id, path, value, description, resource_type, extra_perms, created_by)
|
||||
VALUES ('test-workspace', 'u/test-user/resource_mixed', '{"host": "localhost", "password": "$var:u/test-user/db_password", "credentials": "$res:u/test-user/db_credentials"}',
|
||||
'Resource with mixed refs', 'object', '{}', 'test-user');
|
||||
|
||||
INSERT INTO resource (workspace_id, path, value, description, resource_type, extra_perms, created_by)
|
||||
VALUES ('test-workspace', 'u/test-user/null_resource', null,
|
||||
'Null resource', 'object', '{}', 'test-user');
|
||||
|
||||
INSERT INTO variable (workspace_id, path, value, is_secret, description, extra_perms)
|
||||
VALUES ('test-workspace', 'u/test-user/api_key', 'sk-abc123', false, 'API key', '{}');
|
||||
|
||||
INSERT INTO resource (workspace_id, path, value, description, resource_type, extra_perms, created_by)
|
||||
VALUES ('test-workspace', 'u/test-user/inner_resource', '{"key": "$var:u/test-user/api_key"}',
|
||||
'Inner resource', 'object', '{}', 'test-user');
|
||||
|
||||
INSERT INTO resource (workspace_id, path, value, description, resource_type, extra_perms, created_by)
|
||||
VALUES ('test-workspace', 'u/test-user/chained_resource', '{"service": "myapi", "auth": "$res:u/test-user/inner_resource"}',
|
||||
'Chained resource', 'object', '{}', 'test-user');
|
||||
|
||||
INSERT INTO resource (workspace_id, path, value, description, resource_type, extra_perms, created_by)
|
||||
VALUES ('test-workspace', 'u/test-user/resource_with_array', '{"hosts": ["host1", "host2"], "port": 5432}',
|
||||
'Resource with array', 'object', '{}', 'test-user');
|
||||
|
||||
INSERT INTO resource (workspace_id, path, value, description, resource_type, extra_perms, created_by)
|
||||
VALUES ('test-workspace', 'u/test-user/scalar_var_resource', '"$var:u/test-user/db_password"',
|
||||
'Scalar var ref', 'string', '{}', 'test-user');
|
||||
|
||||
-- === mcp_tools test data ===
|
||||
|
||||
INSERT INTO resource (workspace_id, path, value, description, resource_type, extra_perms, created_by)
|
||||
VALUES ('test-workspace', 'u/test-user/mcp_valid', '{"name": "test-mcp", "url": "http://127.0.0.1:19999/mcp"}',
|
||||
'Valid MCP resource (unreachable)', 'mcp_server', '{}', 'test-user');
|
||||
|
||||
INSERT INTO resource (workspace_id, path, value, description, resource_type, extra_perms, created_by)
|
||||
VALUES ('test-workspace', 'u/test-user/mcp_invalid_format', '{"host": "localhost", "port": 5432}',
|
||||
'Not an MCP resource', 'object', '{}', 'test-user');
|
||||
|
||||
INSERT INTO resource (workspace_id, path, value, description, resource_type, extra_perms, created_by)
|
||||
VALUES ('test-workspace', 'u/test-user/mcp_null', null,
|
||||
'Null MCP resource', 'mcp_server', '{}', 'test-user');
|
||||
10
backend/windmill-api-integration-tests/tests/fixtures/variables_test.sql
vendored
Normal file
10
backend/windmill-api-integration-tests/tests/fixtures/variables_test.sql
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
-- Fixture for variable endpoint tests
|
||||
|
||||
INSERT INTO variable (workspace_id, path, value, is_secret, description, extra_perms)
|
||||
VALUES ('test-workspace', 'u/test-user/plain_var', 'hello world', false, 'A plain variable', '{}');
|
||||
|
||||
INSERT INTO variable (workspace_id, path, value, is_secret, description, extra_perms)
|
||||
VALUES ('test-workspace', 'u/test-user/secret_var', 'supersecret', true, 'A secret variable', '{}');
|
||||
|
||||
INSERT INTO variable (workspace_id, path, value, is_secret, description, extra_perms)
|
||||
VALUES ('test-workspace', 'u/test-user/another_var', 'foobar', false, 'Another variable', '{}');
|
||||
@@ -1,8 +1,7 @@
|
||||
use serde_json::json;
|
||||
use sqlx::{Pool, Postgres};
|
||||
|
||||
mod common;
|
||||
use common::*;
|
||||
use windmill_test_utils::*;
|
||||
|
||||
fn flow_url(port: u16, endpoint: &str, path: &str) -> String {
|
||||
format!("http://localhost:{port}/api/w/test-workspace/flows/{endpoint}/{path}")
|
||||
@@ -40,7 +39,7 @@ fn new_flow(path: &str, summary: &str) -> serde_json::Value {
|
||||
})
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_flow_endpoints(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
initialize_tracing().await;
|
||||
let server = ApiServer::start(db.clone()).await?;
|
||||
@@ -1,8 +1,7 @@
|
||||
use serde_json::json;
|
||||
use sqlx::{Pool, Postgres};
|
||||
|
||||
mod common;
|
||||
use common::*;
|
||||
use windmill_test_utils::*;
|
||||
|
||||
fn folder_url(port: u16, endpoint: &str, name: &str) -> String {
|
||||
format!("http://localhost:{port}/api/w/test-workspace/folders/{endpoint}/{name}")
|
||||
@@ -16,7 +15,7 @@ fn authed(builder: reqwest::RequestBuilder) -> reqwest::RequestBuilder {
|
||||
builder.header("Authorization", "Bearer SECRET_TOKEN")
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_folder_endpoints(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
initialize_tracing().await;
|
||||
let server = ApiServer::start(db.clone()).await?;
|
||||
@@ -1,8 +1,7 @@
|
||||
use serde_json::json;
|
||||
use sqlx::{Pool, Postgres};
|
||||
|
||||
mod common;
|
||||
use common::*;
|
||||
use windmill_test_utils::*;
|
||||
|
||||
fn group_url(port: u16, endpoint: &str, name: &str) -> String {
|
||||
format!("http://localhost:{port}/api/w/test-workspace/groups/{endpoint}/{name}")
|
||||
@@ -16,7 +15,7 @@ fn authed(builder: reqwest::RequestBuilder) -> reqwest::RequestBuilder {
|
||||
builder.header("Authorization", "Bearer SECRET_TOKEN")
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_group_endpoints(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
initialize_tracing().await;
|
||||
let server = ApiServer::start(db.clone()).await?;
|
||||
@@ -1,10 +1,13 @@
|
||||
#[cfg(feature = "deno_core")]
|
||||
use serde_json::json;
|
||||
#[cfg(feature = "deno_core")]
|
||||
use sqlx::{Pool, Postgres};
|
||||
|
||||
mod common;
|
||||
use common::*;
|
||||
#[cfg(feature = "deno_core")]
|
||||
use windmill_test_utils::*;
|
||||
|
||||
/// Helper to create a client authenticated as a specific user
|
||||
#[cfg(feature = "deno_core")]
|
||||
async fn create_client_for_user(_port: u16, token: &str) -> reqwest::Client {
|
||||
let mut headers = reqwest::header::HeaderMap::new();
|
||||
headers.insert(
|
||||
@@ -18,12 +21,14 @@ async fn create_client_for_user(_port: u16, token: &str) -> reqwest::Client {
|
||||
}
|
||||
|
||||
/// Test helper to check if a GET request succeeds
|
||||
#[cfg(feature = "deno_core")]
|
||||
async fn can_read(client: &reqwest::Client, url: &str) -> bool {
|
||||
let resp = client.get(url).send().await.unwrap();
|
||||
resp.status().is_success()
|
||||
}
|
||||
|
||||
/// Test helper to check if a POST request succeeds (for write operations)
|
||||
#[cfg(feature = "deno_core")]
|
||||
async fn can_write(client: &reqwest::Client, url: &str, body: serde_json::Value) -> bool {
|
||||
let resp = client.post(url).json(&body).send().await.unwrap();
|
||||
let status = resp.status();
|
||||
@@ -44,7 +49,7 @@ async fn can_write(client: &reqwest::Client, url: &str, body: serde_json::Value)
|
||||
/// `cargo test --features deno_core permissions -- --ignored`
|
||||
#[ignore]
|
||||
#[cfg(feature = "deno_core")]
|
||||
#[sqlx::test(fixtures("base", "permissions_test"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base", "permissions_test"))]
|
||||
async fn test_permissions_exhaustive(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
initialize_tracing().await;
|
||||
let server = ApiServer::start(db.clone()).await?;
|
||||
@@ -477,7 +482,7 @@ async fn test_permissions_exhaustive(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
/// Additional test for verifying group permission inheritance
|
||||
#[ignore]
|
||||
#[cfg(feature = "deno_core")]
|
||||
#[sqlx::test(fixtures("base", "permissions_test"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base", "permissions_test"))]
|
||||
async fn test_group_permission_inheritance(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
initialize_tracing().await;
|
||||
let server = ApiServer::start(db.clone()).await?;
|
||||
@@ -547,7 +552,7 @@ async fn test_group_permission_inheritance(db: Pool<Postgres>) -> anyhow::Result
|
||||
/// Test that permissions work correctly for all item types
|
||||
#[ignore]
|
||||
#[cfg(feature = "deno_core")]
|
||||
#[sqlx::test(fixtures("base", "permissions_test"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base", "permissions_test"))]
|
||||
async fn test_all_item_types_permissions(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
initialize_tracing().await;
|
||||
let server = ApiServer::start(db.clone()).await?;
|
||||
@@ -588,7 +593,7 @@ async fn test_all_item_types_permissions(db: Pool<Postgres>) -> anyhow::Result<(
|
||||
/// Operators have limited permissions - they can execute but cannot manage resources
|
||||
#[ignore]
|
||||
#[cfg(feature = "deno_core")]
|
||||
#[sqlx::test(fixtures("base", "permissions_test"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base", "permissions_test"))]
|
||||
async fn test_operator_cannot_create_update(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
initialize_tracing().await;
|
||||
let server = ApiServer::start(db.clone()).await?;
|
||||
@@ -7,8 +7,7 @@ use serde_json::json;
|
||||
use sqlx::{Pool, Postgres};
|
||||
use windmill_common::workspaces::invalidate_protection_rules_cache;
|
||||
|
||||
mod common;
|
||||
use common::*;
|
||||
use windmill_test_utils::*;
|
||||
|
||||
fn client() -> reqwest::Client {
|
||||
reqwest::Client::new()
|
||||
@@ -51,7 +50,7 @@ fn new_flow(path: &str, summary: &str) -> serde_json::Value {
|
||||
|
||||
/// Comprehensive test for protection rules functionality.
|
||||
/// Tests all essential cases in a single test to avoid cache interference.
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_protection_rules(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
initialize_tracing().await;
|
||||
invalidate_protection_rules_cache("test-workspace");
|
||||
@@ -1,8 +1,7 @@
|
||||
use serde_json::json;
|
||||
use sqlx::{Pool, Postgres};
|
||||
|
||||
mod common;
|
||||
use common::*;
|
||||
use windmill_test_utils::*;
|
||||
|
||||
fn resource_url(port: u16, endpoint: &str, path: &str) -> String {
|
||||
format!("http://localhost:{port}/api/w/test-workspace/resources/{endpoint}/{path}")
|
||||
@@ -23,7 +22,7 @@ async fn authed_get(port: u16, endpoint: &str, path: &str) -> reqwest::Response
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base", "resources_test"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base", "resources_test"))]
|
||||
async fn test_resource_endpoints(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
initialize_tracing().await;
|
||||
let server = ApiServer::start(db.clone()).await?;
|
||||
@@ -400,7 +399,7 @@ async fn test_resource_endpoints(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
}
|
||||
|
||||
#[cfg(feature = "mcp")]
|
||||
#[sqlx::test(fixtures("base", "resources_test"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base", "resources_test"))]
|
||||
async fn test_mcp_tools(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
initialize_tracing().await;
|
||||
let server = ApiServer::start(db.clone()).await?;
|
||||
@@ -1,8 +1,7 @@
|
||||
use serde_json::json;
|
||||
use sqlx::{Pool, Postgres};
|
||||
|
||||
mod common;
|
||||
use common::*;
|
||||
use windmill_test_utils::*;
|
||||
|
||||
fn schedule_url(port: u16, endpoint: &str, path: &str) -> String {
|
||||
format!("http://localhost:{port}/api/w/test-workspace/schedules/{endpoint}/{path}")
|
||||
@@ -23,7 +22,7 @@ async fn authed_get(port: u16, endpoint: &str, path: &str) -> reqwest::Response
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_schedule_endpoints(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
initialize_tracing().await;
|
||||
let server = ApiServer::start(db.clone()).await?;
|
||||
@@ -1,8 +1,7 @@
|
||||
use serde_json::json;
|
||||
use sqlx::{Pool, Postgres};
|
||||
|
||||
mod common;
|
||||
use common::*;
|
||||
use windmill_test_utils::*;
|
||||
|
||||
fn script_url(port: u16, endpoint: &str, path: &str) -> String {
|
||||
format!("http://localhost:{port}/api/w/test-workspace/scripts/{endpoint}/{path}")
|
||||
@@ -39,7 +38,7 @@ fn new_script(path: &str, summary: &str, content: &str) -> serde_json::Value {
|
||||
})
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_script_endpoints(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
initialize_tracing().await;
|
||||
let server = ApiServer::start(db.clone()).await?;
|
||||
@@ -24,8 +24,7 @@ use serde_json::json;
|
||||
use sqlx::{Pool, Postgres};
|
||||
use std::time::Duration;
|
||||
|
||||
mod common;
|
||||
use common::*;
|
||||
use windmill_test_utils::*;
|
||||
|
||||
// ============================================================================
|
||||
// Helpers
|
||||
@@ -137,7 +136,7 @@ async fn insert_resource(
|
||||
/// -- --ignored --nocapture
|
||||
/// ```
|
||||
#[ignore = "requires running MQTT broker on localhost:1883"]
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_mqtt_e2e(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
initialize_tracing().await;
|
||||
|
||||
@@ -230,7 +229,7 @@ async fn test_mqtt_e2e(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
/// -- --ignored --nocapture
|
||||
/// ```
|
||||
#[ignore = "requires running WebSocket echo server on localhost:8765"]
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_websocket_e2e(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
initialize_tracing().await;
|
||||
|
||||
@@ -286,7 +285,7 @@ async fn test_websocket_e2e(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
/// -- --ignored --nocapture
|
||||
/// ```
|
||||
#[ignore = "requires PostgreSQL with wal_level=logical"]
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_postgres_e2e(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
initialize_tracing().await;
|
||||
|
||||
@@ -387,7 +386,7 @@ async fn test_postgres_e2e(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
/// ```
|
||||
#[cfg(all(feature = "enterprise", feature = "private"))]
|
||||
#[ignore = "requires running Kafka broker on localhost:9092"]
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_kafka_e2e(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
initialize_tracing().await;
|
||||
|
||||
@@ -478,7 +477,7 @@ async fn test_kafka_e2e(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
/// ```
|
||||
#[cfg(all(feature = "enterprise", feature = "private"))]
|
||||
#[ignore = "requires running NATS server on localhost:4222"]
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_nats_e2e(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
initialize_tracing().await;
|
||||
|
||||
@@ -553,7 +552,7 @@ async fn test_nats_e2e(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
/// ```
|
||||
#[cfg(all(feature = "enterprise", feature = "private"))]
|
||||
#[ignore = "requires LocalStack SQS on localhost:4566"]
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_sqs_e2e(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
initialize_tracing().await;
|
||||
|
||||
@@ -641,7 +640,7 @@ async fn test_sqs_e2e(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
/// ```
|
||||
#[cfg(all(feature = "enterprise", feature = "private"))]
|
||||
#[ignore = "requires GCP Pub/Sub emulator on localhost:8085"]
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_gcp_e2e(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
initialize_tracing().await;
|
||||
|
||||
@@ -12,14 +12,13 @@ use serde::Deserialize;
|
||||
use serde_json::json;
|
||||
use sqlx::{Pool, Postgres};
|
||||
|
||||
mod common;
|
||||
use common::*;
|
||||
use windmill_test_utils::*;
|
||||
|
||||
// ============================================================================
|
||||
// Capture Config Tests (direct DB)
|
||||
// ============================================================================
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_capture_config_insert_and_query(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
sqlx::query!(
|
||||
r#"
|
||||
@@ -56,7 +55,7 @@ async fn test_capture_config_insert_and_query(db: Pool<Postgres>) -> anyhow::Res
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_capture_config_upsert(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
sqlx::query!(
|
||||
r#"
|
||||
@@ -104,7 +103,7 @@ async fn test_capture_config_upsert(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_capture_config_ping_updates_timestamp(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
sqlx::query!(
|
||||
r#"
|
||||
@@ -159,7 +158,7 @@ async fn test_capture_config_ping_updates_timestamp(db: Pool<Postgres>) -> anyho
|
||||
// Capture Payload Tests (direct DB)
|
||||
// ============================================================================
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_capture_insert_and_list(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
for i in 0..2 {
|
||||
sqlx::query!(
|
||||
@@ -192,7 +191,7 @@ async fn test_capture_insert_and_list(db: Pool<Postgres>) -> anyhow::Result<()>
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_capture_delete(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
let id = sqlx::query_scalar!(
|
||||
r#"
|
||||
@@ -227,7 +226,7 @@ async fn test_capture_delete(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_capture_filter_by_trigger_kind(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
sqlx::query!(
|
||||
r#"
|
||||
@@ -304,7 +303,7 @@ struct CaptureResponse {
|
||||
main_args: serde_json::Value,
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_capture_api_set_config_and_list(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
initialize_tracing().await;
|
||||
|
||||
@@ -348,7 +347,7 @@ async fn test_capture_api_set_config_and_list(db: Pool<Postgres>) -> anyhow::Res
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_capture_api_list_captures(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
initialize_tracing().await;
|
||||
|
||||
@@ -394,7 +393,7 @@ async fn test_capture_api_list_captures(db: Pool<Postgres>) -> anyhow::Result<()
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_capture_api_get_single(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
initialize_tracing().await;
|
||||
|
||||
@@ -441,7 +440,7 @@ async fn test_capture_api_get_single(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_capture_api_delete(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
initialize_tracing().await;
|
||||
|
||||
@@ -493,7 +492,7 @@ async fn test_capture_api_delete(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_capture_api_pagination(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
initialize_tracing().await;
|
||||
|
||||
@@ -555,7 +554,7 @@ async fn test_capture_api_pagination(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
// HTTP Trigger Tests (direct DB)
|
||||
// ============================================================================
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_http_trigger_insert_and_query(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
sqlx::query!(
|
||||
r#"
|
||||
@@ -610,7 +609,7 @@ async fn test_http_trigger_insert_and_query(db: Pool<Postgres>) -> anyhow::Resul
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_http_trigger_multiple_methods(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
let methods = ["get", "post", "put", "delete", "patch"];
|
||||
|
||||
@@ -657,7 +656,7 @@ async fn test_http_trigger_multiple_methods(db: Pool<Postgres>) -> anyhow::Resul
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_http_trigger_authentication_methods(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
let auth_methods = ["none", "windmill", "api_key", "basic_http", "signature"];
|
||||
|
||||
@@ -708,7 +707,7 @@ async fn test_http_trigger_authentication_methods(db: Pool<Postgres>) -> anyhow:
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_http_trigger_update(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
sqlx::query!(
|
||||
r#"
|
||||
@@ -761,7 +760,7 @@ async fn test_http_trigger_update(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_http_trigger_delete(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
sqlx::query!(
|
||||
r#"
|
||||
@@ -813,7 +812,7 @@ async fn test_http_trigger_delete(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_http_trigger_mode_filtering(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
let modes = ["enabled", "disabled", "suspended"];
|
||||
|
||||
@@ -870,7 +869,7 @@ async fn test_http_trigger_mode_filtering(db: Pool<Postgres>) -> anyhow::Result<
|
||||
// Other Trigger Types Tests (DB schema validation)
|
||||
// ============================================================================
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_websocket_trigger_insert(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
sqlx::query!(
|
||||
r#"
|
||||
@@ -909,7 +908,7 @@ async fn test_websocket_trigger_insert(db: Pool<Postgres>) -> anyhow::Result<()>
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_kafka_trigger_insert(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
sqlx::query!(
|
||||
r#"
|
||||
@@ -952,7 +951,7 @@ async fn test_kafka_trigger_insert(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_postgres_trigger_insert(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
sqlx::query!(
|
||||
r#"
|
||||
@@ -995,7 +994,7 @@ async fn test_postgres_trigger_insert(db: Pool<Postgres>) -> anyhow::Result<()>
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_nats_trigger_insert(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
sqlx::query!(
|
||||
r#"
|
||||
@@ -1038,7 +1037,7 @@ async fn test_nats_trigger_insert(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_sqs_trigger_insert(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
sqlx::query!(
|
||||
r#"
|
||||
@@ -1089,7 +1088,7 @@ async fn test_sqs_trigger_insert(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
// Cross-trigger tests
|
||||
// ============================================================================
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_trigger_server_state_tracking(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
sqlx::query!(
|
||||
r#"
|
||||
@@ -1144,7 +1143,7 @@ async fn test_trigger_server_state_tracking(db: Pool<Postgres>) -> anyhow::Resul
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_trigger_mode_filtering(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
let modes = ["enabled", "disabled", "enabled"];
|
||||
|
||||
@@ -1191,7 +1190,7 @@ async fn test_trigger_mode_filtering(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_multiple_capture_configs_per_path(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
let trigger_kinds = ["webhook", "email", "kafka"];
|
||||
|
||||
@@ -1229,7 +1228,7 @@ async fn test_multiple_capture_configs_per_path(db: Pool<Postgres>) -> anyhow::R
|
||||
// Schedule Tests (DB-level)
|
||||
// ============================================================================
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_schedule_insert_and_query(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
sqlx::query!(
|
||||
r#"
|
||||
@@ -1277,7 +1276,7 @@ async fn test_schedule_insert_and_query(db: Pool<Postgres>) -> anyhow::Result<()
|
||||
// MQTT Trigger Tests (DB-level)
|
||||
// ============================================================================
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_mqtt_trigger_insert(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
sqlx::query(
|
||||
r#"
|
||||
@@ -1321,7 +1320,7 @@ async fn test_mqtt_trigger_insert(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_mqtt_trigger_update(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
sqlx::query(
|
||||
r#"
|
||||
@@ -1366,7 +1365,7 @@ async fn test_mqtt_trigger_update(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_mqtt_trigger_delete(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
sqlx::query(
|
||||
r#"
|
||||
@@ -1414,7 +1413,7 @@ async fn test_mqtt_trigger_delete(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
// GCP Trigger Tests (DB-level)
|
||||
// ============================================================================
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_gcp_trigger_insert_pull(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
sqlx::query(
|
||||
r#"
|
||||
@@ -1465,7 +1464,7 @@ async fn test_gcp_trigger_insert_pull(db: Pool<Postgres>) -> anyhow::Result<()>
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_gcp_trigger_insert_push(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
sqlx::query(
|
||||
r#"
|
||||
@@ -1515,7 +1514,7 @@ async fn test_gcp_trigger_insert_push(db: Pool<Postgres>) -> anyhow::Result<()>
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_gcp_trigger_unique_constraint(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
let insert_query = r#"
|
||||
INSERT INTO gcp_trigger (
|
||||
@@ -1569,7 +1568,7 @@ async fn test_gcp_trigger_unique_constraint(db: Pool<Postgres>) -> anyhow::Resul
|
||||
// Email Trigger Tests (DB-level)
|
||||
// ============================================================================
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_email_trigger_insert(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
sqlx::query!(
|
||||
r#"
|
||||
@@ -1612,7 +1611,7 @@ async fn test_email_trigger_insert(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_email_trigger_update(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
sqlx::query!(
|
||||
r#"
|
||||
@@ -1658,7 +1657,7 @@ async fn test_email_trigger_update(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_email_trigger_delete(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
sqlx::query!(
|
||||
r#"
|
||||
@@ -1,8 +1,7 @@
|
||||
use serde_json::json;
|
||||
use sqlx::{Pool, Postgres};
|
||||
|
||||
mod common;
|
||||
use common::*;
|
||||
use windmill_test_utils::*;
|
||||
|
||||
fn user_url(port: u16, endpoint: &str, name: &str) -> String {
|
||||
format!("http://localhost:{port}/api/w/test-workspace/users/{endpoint}/{name}")
|
||||
@@ -16,7 +15,7 @@ fn authed(builder: reqwest::RequestBuilder) -> reqwest::RequestBuilder {
|
||||
builder.header("Authorization", "Bearer SECRET_TOKEN")
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_user_endpoints(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
initialize_tracing().await;
|
||||
let server = ApiServer::start(db.clone()).await?;
|
||||
@@ -1,8 +1,7 @@
|
||||
use serde_json::json;
|
||||
use sqlx::{Pool, Postgres};
|
||||
|
||||
mod common;
|
||||
use common::*;
|
||||
use windmill_test_utils::*;
|
||||
|
||||
fn variable_url(port: u16, endpoint: &str, path: &str) -> String {
|
||||
format!("http://localhost:{port}/api/w/test-workspace/variables/{endpoint}/{path}")
|
||||
@@ -23,7 +22,7 @@ async fn authed_get(port: u16, endpoint: &str, path: &str) -> reqwest::Response
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base", "variables_test"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base", "variables_test"))]
|
||||
async fn test_variable_endpoints(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
initialize_tracing().await;
|
||||
let server = ApiServer::start(db.clone()).await?;
|
||||
@@ -1,8 +1,7 @@
|
||||
use serde_json::json;
|
||||
use sqlx::{Pool, Postgres};
|
||||
|
||||
mod common;
|
||||
use common::*;
|
||||
use windmill_test_utils::*;
|
||||
|
||||
/// Comprehensive integration test for the compare_workspaces endpoint.
|
||||
///
|
||||
@@ -12,7 +11,7 @@ use common::*;
|
||||
/// 3. Making various changes in both workspaces (new items, modifications, conflicts, deletions, renames)
|
||||
/// 4. Populating the workspace_diff table to simulate Git sync tracking
|
||||
/// 5. Calling compare_workspaces and verifying all aspects of the comparison
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_compare_workspaces_comprehensive(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
initialize_tracing().await;
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
use serde_json::json;
|
||||
use sqlx::{Pool, Postgres};
|
||||
|
||||
mod common;
|
||||
use common::*;
|
||||
use windmill_test_utils::*;
|
||||
|
||||
fn client() -> reqwest::Client {
|
||||
reqwest::Client::new()
|
||||
@@ -12,7 +11,7 @@ fn authed(builder: reqwest::RequestBuilder) -> reqwest::RequestBuilder {
|
||||
builder.header("Authorization", "Bearer SECRET_TOKEN")
|
||||
}
|
||||
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
|
||||
async fn test_workspace_endpoints(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
initialize_tracing().await;
|
||||
let server = ApiServer::start(db.clone()).await?;
|
||||
21
backend/windmill-api-npm-proxy/Cargo.toml
Normal file
21
backend/windmill-api-npm-proxy/Cargo.toml
Normal file
@@ -0,0 +1,21 @@
|
||||
[package]
|
||||
name = "windmill-api-npm-proxy"
|
||||
version.workspace = true
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
[lib]
|
||||
name = "windmill_api_npm_proxy"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
windmill-api-auth.workspace = true
|
||||
windmill-common = { workspace = true, default-features = false }
|
||||
axum.workspace = true
|
||||
flate2.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
sqlx.workspace = true
|
||||
tar.workspace = true
|
||||
tower-http.workspace = true
|
||||
tracing.workspace = true
|
||||
@@ -18,7 +18,8 @@ use windmill_common::{
|
||||
utils::StripPath,
|
||||
};
|
||||
|
||||
use crate::{db::ApiAuthed, HTTP_CLIENT};
|
||||
use windmill_api_auth::ApiAuthed;
|
||||
use windmill_common::utils::HTTP_CLIENT_PERMISSIVE as HTTP_CLIENT;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct ProxyQuery {
|
||||
26
backend/windmill-api-openapi/Cargo.toml
Normal file
26
backend/windmill-api-openapi/Cargo.toml
Normal file
@@ -0,0 +1,26 @@
|
||||
[package]
|
||||
name = "windmill-api-openapi"
|
||||
version.workspace = true
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
[lib]
|
||||
name = "windmill_api_openapi"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
windmill-api-auth.workspace = true
|
||||
windmill-common = { workspace = true, default-features = false }
|
||||
windmill-store.workspace = true
|
||||
windmill-trigger-http.workspace = true
|
||||
anyhow.workspace = true
|
||||
axum.workspace = true
|
||||
http.workspace = true
|
||||
indexmap.workspace = true
|
||||
itertools.workspace = true
|
||||
lazy_static.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
serde_yml.workspace = true
|
||||
sqlx.workspace = true
|
||||
url.workspace = true
|
||||
@@ -20,13 +20,11 @@ use windmill_common::{
|
||||
utils::{deserialize_url, empty_as_none, is_empty, RunnableKind},
|
||||
DB,
|
||||
};
|
||||
use windmill_store::resources::try_get_resource_from_db_as;
|
||||
|
||||
use crate::{
|
||||
db::ApiAuthed,
|
||||
resources::try_get_resource_from_db_as,
|
||||
triggers::http::{
|
||||
http_trigger_auth::ApiKeyAuthentication, AuthenticationMethod, HttpMethod, RequestType,
|
||||
},
|
||||
use windmill_api_auth::ApiAuthed;
|
||||
use windmill_trigger_http::{
|
||||
http_trigger_auth::ApiKeyAuthentication, AuthenticationMethod, HttpMethod, RequestType,
|
||||
};
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
29
backend/windmill-api-schedule/Cargo.toml
Normal file
29
backend/windmill-api-schedule/Cargo.toml
Normal file
@@ -0,0 +1,29 @@
|
||||
[package]
|
||||
name = "windmill-api-schedule"
|
||||
version.workspace = true
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
[lib]
|
||||
name = "windmill_api_schedule"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
enterprise = []
|
||||
|
||||
[dependencies]
|
||||
windmill-api-auth.workspace = true
|
||||
windmill-api-settings.workspace = true
|
||||
windmill-common = { workspace = true, default-features = false }
|
||||
windmill-audit.workspace = true
|
||||
windmill-git-sync.workspace = true
|
||||
windmill-queue.workspace = true
|
||||
axum.workspace = true
|
||||
chrono.workspace = true
|
||||
chrono-tz.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
sql-builder.workspace = true
|
||||
sqlx.workspace = true
|
||||
tracing.workspace = true
|
||||
@@ -6,12 +6,8 @@
|
||||
* LICENSE-AGPL for a copy of the license.
|
||||
*/
|
||||
|
||||
use crate::{
|
||||
db::{ApiAuthed, DB},
|
||||
settings::{delete_global_setting, set_global_setting_internal},
|
||||
users::maybe_refresh_folders,
|
||||
utils::{check_scopes, require_super_admin},
|
||||
};
|
||||
use windmill_api_auth::{check_scopes, maybe_refresh_folders, require_super_admin, ApiAuthed};
|
||||
use windmill_common::DB;
|
||||
use axum::{
|
||||
extract::{Extension, Path, Query},
|
||||
routing::{delete, get, post},
|
||||
@@ -922,9 +918,9 @@ async fn set_default_error_handler(
|
||||
};
|
||||
|
||||
if let Some(value_content) = value {
|
||||
set_global_setting_internal(&db, key, value_content).await?;
|
||||
windmill_api_settings::set_global_setting_internal(&db, key, value_content).await?;
|
||||
} else {
|
||||
delete_global_setting(&db, key.as_str()).await?;
|
||||
windmill_api_settings::delete_global_setting(&db, key.as_str()).await?;
|
||||
}
|
||||
|
||||
if payload.override_existing {
|
||||
@@ -6,5 +6,4 @@
|
||||
* LICENSE-AGPL for a copy of the license.
|
||||
*/
|
||||
|
||||
pub mod flows;
|
||||
pub mod scripts;
|
||||
|
||||
38
backend/windmill-api-settings/Cargo.toml
Normal file
38
backend/windmill-api-settings/Cargo.toml
Normal file
@@ -0,0 +1,38 @@
|
||||
[package]
|
||||
name = "windmill-api-settings"
|
||||
version.workspace = true
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
[lib]
|
||||
name = "windmill_api_settings"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
enterprise = []
|
||||
private = ["windmill-common/private"]
|
||||
parquet = ["dep:object_store", "windmill-common/parquet"]
|
||||
license = ["dep:rsa"]
|
||||
|
||||
[dependencies]
|
||||
windmill-alerting.workspace = true
|
||||
windmill-api-auth.workspace = true
|
||||
windmill-common = { workspace = true, default-features = false }
|
||||
axum.workspace = true
|
||||
anyhow.workspace = true
|
||||
bytes.workspace = true
|
||||
chrono.workspace = true
|
||||
futures.workspace = true
|
||||
lazy_static.workspace = true
|
||||
regex.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
sqlx.workspace = true
|
||||
tokio.workspace = true
|
||||
tracing.workspace = true
|
||||
uuid.workspace = true
|
||||
base64.workspace = true
|
||||
sha2.workspace = true
|
||||
rsa = { workspace = true, optional = true }
|
||||
object_store = { workspace = true, optional = true }
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user