Compare commits

..

34 Commits

Author SHA1 Message Date
Ruben Fiszel
0afb1a58cb remove cache 2024-12-18 13:10:48 +01:00
Ruben Fiszel
833547a6fb downgrade images 2024-12-18 13:09:25 +01:00
Ruben Fiszel
1693f14fe6 ci improvements 2024-12-17 19:56:47 +01:00
Ruben Fiszel
977a33b397 ci improvements 2024-12-17 19:44:33 +01:00
Ruben Fiszel
c1ba227ae4 ci improvements 2024-12-17 19:39:40 +01:00
Ruben Fiszel
7558572d23 ci improvements 2024-12-17 19:32:46 +01:00
Ruben Fiszel
4f57d9d121 ci improvements 2024-12-17 18:51:39 +01:00
Ruben Fiszel
e3413f8ff8 add uv 2024-12-17 17:25:53 +01:00
Ruben Fiszel
84a45166aa all 2024-12-17 17:05:26 +01:00
Ruben Fiszel
07159ea062 all 2024-12-17 16:53:56 +01:00
Ruben Fiszel
eb8ffbdedb all 2024-12-17 16:49:46 +01:00
Ruben Fiszel
2a9620338f all 2024-12-17 16:48:47 +01:00
Ruben Fiszel
2d58b2c5bc all 2024-12-17 16:46:00 +01:00
Ruben Fiszel
67377a8c63 all 2024-12-17 16:40:07 +01:00
Ruben Fiszel
3d1af4cdb9 all 2024-12-17 16:37:43 +01:00
Ruben Fiszel
2faa929d37 all 2024-12-17 16:31:25 +01:00
Ruben Fiszel
862405e90b all 2024-12-17 16:27:29 +01:00
Ruben Fiszel
6c274849a5 all 2024-12-17 16:26:42 +01:00
Ruben Fiszel
1da8dcc655 all 2024-12-17 16:23:40 +01:00
Ruben Fiszel
bc8c6abd00 all 2024-12-17 16:16:56 +01:00
Ruben Fiszel
ab9481c4c5 all 2024-12-17 15:57:52 +01:00
Ruben Fiszel
191db2b739 all 2024-12-17 15:53:46 +01:00
Ruben Fiszel
c6e06da611 all 2024-12-17 15:44:19 +01:00
Ruben Fiszel
ad81499f8d all 2024-12-17 15:37:55 +01:00
Ruben Fiszel
16ce09fd1b all 2024-12-17 15:36:14 +01:00
Ruben Fiszel
6bcaa73af5 all 2024-12-17 15:26:18 +01:00
Ruben Fiszel
5fb68cf28f all 2024-12-17 15:11:10 +01:00
Ruben Fiszel
204ca7ea46 all 2024-12-17 14:52:38 +01:00
Ruben Fiszel
e9eb49b999 all 2024-12-17 14:49:50 +01:00
Ruben Fiszel
7c8040cc16 all 2024-12-17 14:43:10 +01:00
Ruben Fiszel
fd9a4183d3 all 2024-12-17 14:38:44 +01:00
Ruben Fiszel
1846c8795d all 2024-12-17 14:12:12 +01:00
Ruben Fiszel
9194d20bc1 all 2024-12-17 14:08:27 +01:00
Ruben Fiszel
db90705d41 all 2024-12-17 13:00:51 +01:00
286 changed files with 3917 additions and 13477 deletions

View File

@@ -48,9 +48,7 @@ jobs:
- name: cargo check
working-directory: ./backend
timeout-minutes: 16
run: |
mkdir -p fake_frontend_build
FRONTEND_BUILD_DIR=$(pwd)/fake_frontend_build SQLX_OFFLINE=true cargo check --all-features
run: SQLX_OFFLINE=true cargo check --all-features
check_ee:
runs-on: ubicloud-standard-8
@@ -127,8 +125,6 @@ jobs:
- name: cargo check
timeout-minutes: 16
working-directory: ./backend
run: |
mkdir -p fake_frontend_build
FRONTEND_BUILD_DIR=$(pwd)/fake_frontend_build SQLX_OFFLINE=true cargo check --all-features
run: SQLX_OFFLINE=true cargo check --all-features

View File

@@ -47,14 +47,14 @@ jobs:
python-version: 3.11
- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.1.40
bun-version: 1.1.38
- uses: astral-sh/setup-uv@v4
with:
version: "0.4.18"
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
cache-workspaces: backend
toolchain: 1.82.0
toolchain: 1.80.0
- uses: Swatinem/rust-cache@v2
with:
workspaces: backend
@@ -67,4 +67,4 @@ jobs:
DISABLE_EMBEDDING=true RUST_LOG=info PYTHON_PATH=$(which python)
DENO_PATH=$(which deno) BUN_PATH=$(which bun) GO_PATH=$(which go)
UV_PATH=$(which uv) cargo test --features
enterprise,deno_core,license,python,rust,scoped_cache --all -- --nocapture
enterprise,deno_core,license,python,rust --all -- --nocapture

View File

@@ -64,7 +64,7 @@ jobs:
platforms: linux/amd64
push: true
build-args: |
features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,deno_core,license,http_trigger,zip,oauth2,kafka,nats,php,mysql,mssql,bigquery,websocket,python,smtp,csharp,static_frontend,rust
features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,deno_core,license,http_trigger,zip,oauth2,kafka,php,mysql,mssql,bigquery,websocket,python,smtp,csharp,static_frontend,rust
secrets: |
rh_username=${{ secrets.RH_USERNAME }}
rh_password=${{ secrets.RH_PASSWORD }}
@@ -81,7 +81,7 @@ jobs:
platforms: linux/arm64
push: true
build-args: |
features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,deno_core,license,http_trigger,zip,oauth2,kafka,nats,php,mysql,mssql,bigquery,websocket,python,smtp,csharp,static_frontend,rust
features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,deno_core,license,http_trigger,zip,oauth2,kafka,php,mysql,mssql,bigquery,websocket,python,smtp,csharp,static_frontend,rust
secrets: |
rh_username=${{ secrets.RH_USERNAME }}
rh_password=${{ secrets.RH_PASSWORD }}

View File

@@ -45,7 +45,7 @@ jobs:
$env:OPENSSL_DIR="${Env:VCPKG_INSTALLATION_ROOT}\installed\x64-windows-static"
mkdir frontend/build && cd backend
New-Item -Path . -Name "windmill-api/openapi-deref.yaml" -ItemType "File" -Force
cargo build --release --features=enterprise,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy,deno_core,license,http_trigger,zip,oauth2,kafka,nats,php,mysql,mssql,bigquery,websocket,python,smtp,csharp,static_frontend,rust
cargo build --release --features=enterprise,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy,deno_core,license,http_trigger,zip,oauth2,kafka,php,mysql,mssql,bigquery,websocket,python,smtp,csharp,static_frontend,rust
- name: Rename binary with corresponding architecture
run: |

View File

@@ -1,9 +1,12 @@
env:
REGISTRY: ghcr.io
IMAGE_NAME:
${{ github.event_name != 'pull_request' && github.event_name != 'workflow_dispatch' && github.repository || 'windmill-labs/windmill-test' }}
${{ github.event_name != 'pull_request' && github.event_name !=
'workflow_dispatch' && github.repository || 'windmill-labs/windmill-test' }}
DEV_SHA:
${{ github.event_name != 'pull_request' && github.event_name != 'workflow_dispatch' && 'dev' || github.event.inputs.tag || github.sha }}
${{ github.event_name != 'pull_request' && github.event_name !=
'workflow_dispatch' && 'dev' || github.event.inputs.tag || 'test' }}
name: Build windmill:main
on:
push:
@@ -16,14 +19,14 @@ on:
workflow_dispatch:
inputs:
ee:
description: 'Build EE image (true, false)'
description: "Build EE image (true, false)"
required: false
default: false
type: boolean
tag:
description: 'Tag the image'
description: "Tag the image"
required: true
default: 'test'
default: "test"
concurrency:
group: ${{ github.ref }}
@@ -33,8 +36,8 @@ permissions: write-all
jobs:
build:
runs-on: ubicloud
if: (github.event_name != 'workflow_dispatch') || (github.event.inputs && !github.event.inputs.ee)
runs-on: ubicloud-standard-8
if: (github.event_name != 'workflow_dispatch') || (inputs.ee == false)
steps:
- uses: actions/checkout@v4
with:
@@ -52,9 +55,9 @@ jobs:
token: ${{ secrets.WINDMILL_EE_PRIVATE_ACCESS }}
fetch-depth: 0
# - name: Set up Docker Buildx
# uses: docker/setup-buildx-action@v2
- uses: depot/setup-action@v1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
# - uses: depot/setup-action@v1
- name: Login to registry
uses: docker/login-action@v3
@@ -80,10 +83,9 @@ jobs:
type=semver,pattern={{major}}.{{minor}}
- name: Build and push publicly
uses: depot/build-push-action@v1
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
build-args: |
features=embedding,parquet,openidconnect,jemalloc,deno_core,license,http_trigger,zip,oauth2,dind,php,mysql,mssql,bigquery,websocket,python,smtp,csharp,static_frontend,rust
@@ -94,10 +96,10 @@ jobs:
${{ steps.meta-public.outputs.labels }}
org.opencontainers.image.licenses=AGPLv3
build_ee:
runs-on: ubicloud
if:
(github.event_name != 'workflow_dispatch') || (github.event.inputs.ee)
build_arm:
runs-on: ubicloud-standard-8-arm
if: (github.event_name != 'workflow_dispatch') || (inputs.ee == false)
steps:
- uses: actions/checkout@v4
with:
@@ -115,9 +117,70 @@ jobs:
token: ${{ secrets.WINDMILL_EE_PRIVATE_ACCESS }}
fetch-depth: 0
# - name: Set up Docker Buildx
# uses: docker/setup-buildx-action@v2
- uses: depot/setup-action@v1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
# - uses: depot/setup-action@v1
- name: Login to registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Substitute EE code (EE logic is behind feature flag)
run: |
./backend/substitute_ee_code.sh --copy --dir ./windmill-ee-private
- name: Docker meta
id: meta-public
uses: docker/metadata-action@v5
with:
images: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
flavor: |
latest=false
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
- name: Build and push publicly
uses: docker/build-push-action@v6
with:
context: .
push: true
build-args: |
features=embedding,parquet,openidconnect,jemalloc,deno_core,license,http_trigger,zip,oauth2,dind,php,mysql,mssql,bigquery,websocket,python,smtp,csharp,static_frontend,rust
tags: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.DEV_SHA }}
${{ steps.meta-public.outputs.tags }}
labels: |
${{ steps.meta-public.outputs.labels }}
org.opencontainers.image.licenses=AGPLv3
build_ee:
runs-on: ubicloud
if: (github.event_name != 'workflow_dispatch') || (inputs.ee == true)
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Read EE repo commit hash
run: |
echo "ee_repo_ref=$(cat ./backend/ee-repo-ref.txt)" >> "$GITHUB_ENV"
- uses: actions/checkout@v4
with:
repository: windmill-labs/windmill-ee-private
path: ./windmill-ee-private
ref: ${{ env.ee_repo_ref }}
token: ${{ secrets.WINDMILL_EE_PRIVATE_ACCESS }}
fetch-depth: 0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
# - uses: depot/setup-action@v1
- name: Docker meta
id: meta-ee-public
@@ -143,20 +206,85 @@ jobs:
./backend/substitute_ee_code.sh --copy --dir ./windmill-ee-private
- name: Build and push publicly ee
uses: depot/build-push-action@v1
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64
# platforms: linux/amd64,linux/arm64
push: true
build-args: |
features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy,deno_core,license,http_trigger,zip,oauth2,kafka,nats,otel,dind,php,mysql,mssql,bigquery,websocket,python,smtp,csharp,static_frontend,rust
features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy,deno_core,license,http_trigger,zip,oauth2,kafka,otel,dind,php,mysql,mssql,bigquery,websocket,python,smtp,csharp,static_frontend,rust
tags: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee:${{ env.DEV_SHA }}
${{ steps.meta-ee-public.outputs.tags }}
labels: |
${{ steps.meta-ee-public.outputs.labels }}
org.opencontainers.image.licenses=Windmill-Enterprise-License
cache-from: type=gha
cache-to: type=gha
build_ee_arm:
runs-on: ubicloud
if: (github.event_name != 'workflow_dispatch') || (inputs.ee == true)
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Read EE repo commit hash
run: |
echo "ee_repo_ref=$(cat ./backend/ee-repo-ref.txt)" >> "$GITHUB_ENV"
- uses: actions/checkout@v4
with:
repository: windmill-labs/windmill-ee-private
path: ./windmill-ee-private
ref: ${{ env.ee_repo_ref }}
token: ${{ secrets.WINDMILL_EE_PRIVATE_ACCESS }}
fetch-depth: 0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
# - uses: depot/setup-action@v1
- name: Docker meta
id: meta-ee-public
uses: docker/metadata-action@v5
with:
images: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee
flavor: |
latest=false
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
- name: Login to registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Substitute EE code
run: |
./backend/substitute_ee_code.sh --copy --dir ./windmill-ee-private
- name: Build and push publicly ee
uses: docker/build-push-action@v6
with:
context: .
# platforms: linux/amd64,linux/arm64
push: true
build-args: |
features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy,deno_core,license,http_trigger,zip,oauth2,kafka,otel,dind,php,mysql,mssql,bigquery,websocket,python,smtp,csharp,static_frontend,rust
tags: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee:${{ env.DEV_SHA }}
${{ steps.meta-ee-public.outputs.tags }}
labels: |
${{ steps.meta-ee-public.outputs.labels }}
org.opencontainers.image.licenses=Windmill-Enterprise-License
cache-from: type=gha
cache-to: type=gha
build_ee_312:
runs-on: ubicloud
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
@@ -177,9 +305,9 @@ jobs:
token: ${{ secrets.WINDMILL_EE_PRIVATE_ACCESS }}
fetch-depth: 0
# - name: Set up Docker Buildx
# uses: docker/setup-buildx-action@v2
- uses: depot/setup-action@v1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
# - uses: depot/setup-action@v1
- name: Docker meta
id: meta-ee-public-py312
@@ -205,19 +333,21 @@ jobs:
./backend/substitute_ee_code.sh --copy --dir ./windmill-ee-private
- name: Build and push publicly ee
uses: depot/build-push-action@v1
uses: docker/build-push-action@v1
with:
context: .
platforms: linux/amd64
# platforms: linux/amd64
push: true
build-args: |
features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy,deno_core,license,http_trigger,zip,oauth2,kafka,nats,otel,dind,php,mysql,mssql,bigquery,websocket,python,smtp,csharp,static_frontend,rust
features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy,deno_core,license,http_trigger,zip,oauth2,kafka,otel,dind,php,mysql,mssql,bigquery,websocket,python,smtp,csharp,static_frontend,rust
PYTHON_IMAGE=python:3.12.2-slim-bookworm
tags: |
${{ steps.meta-ee-public-py312.outputs.tags }}
labels: |
${{ steps.meta-ee-public-py312.outputs.labels }}
org.opencontainers.image.licenses=Windmill-Enterprise-License
cache-from: type=gha
cache-to: type=gha
# disabled until we make it 100% reliable and add more meaningful tests
# playwright:
@@ -341,7 +471,7 @@ jobs:
# ${{ steps.extract-ee.outputs.destination }}/*
run_integration_test:
runs-on: ubicloud
runs-on: ubicloud-standard-8
needs: [build_ee]
steps:
- uses: actions/checkout@v4
@@ -352,7 +482,7 @@ jobs:
run: cd integration_tests && ./build.sh
- name: Test run
if: ${{ ! startsWith(github.ref, 'refs/tags/v') }}
timeout-minutes: 15
timeout-minutes: 16
env:
LICENSE_KEY: ${{ secrets.WM_LICENSE_KEY_CI }}
run: cd integration_tests && ./run.sh
@@ -452,16 +582,17 @@ jobs:
needs: [build_ee]
runs-on: ubicloud
if:
(github.event_name != 'pull_request') && (github.event_name != 'workflow_dispatch')
(github.event_name != 'pull_request') && (github.event_name !=
'workflow_dispatch')
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
# - name: Set up Docker Buildx
# uses: docker/setup-buildx-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- uses: depot/setup-action@v1
# - uses: depot/setup-action@v1
- name: Docker meta
id: meta-ee-public
@@ -486,10 +617,61 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push publicly ee
uses: depot/build-push-action@v1
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64
# platforms: linux/amd64,linux/arm64
push: true
file: "./docker/DockerfileNsjail"
tags: |
${{ steps.meta-ee-public.outputs.tags }}
labels: |
${{ steps.meta-ee-public.outputs.labels }}
org.opencontainers.image.licenses=Windmill-Enterprise-License
build_ee_nsjail_arm:
needs: [build_ee_arm]
runs-on: ubicloud
if:
(github.event_name != 'pull_request') && (github.event_name !=
'workflow_dispatch')
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
# - uses: depot/setup-action@v1
- name: Docker meta
id: meta-ee-public
uses: docker/metadata-action@v5
with:
images: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee-nsjail
flavor: |
latest=false
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha,enable=true,priority=100,prefix=,suffix=,format=short
type=ref,event=branch
type=ref,event=pr
- name: Login to registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push publicly ee
uses: docker/build-push-action@v6
with:
context: .
# platforms: linux/amd64,linux/arm64
push: true
file: "./docker/DockerfileNsjail"
tags: |
@@ -506,10 +688,10 @@ jobs:
- uses: actions/checkout@v4
with:
fetch-depth: 0
# - name: Set up Docker Buildx
# uses: docker/setup-buildx-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- uses: depot/setup-action@v1
# - uses: depot/setup-action@v1
- name: Login to registry
uses: docker/login-action@v3
@@ -530,10 +712,54 @@ jobs:
type=sha,enable=true,priority=100,prefix=,suffix=,format=short
- name: Build and push publicly ee reports
uses: depot/build-push-action@v1
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64
# platforms: linux/amd64,linux/arm64
push: true
file: "./docker/DockerfileReports"
tags: |
${{ steps.meta-ee-public.outputs.tags }}
labels: |
${{ steps.meta-ee-public.outputs.labels }}
org.opencontainers.image.licenses=Windmill-Enterprise-License
build_ee_reports_privately_arm:
needs: [build_ee_nsjail_arm]
runs-on: ubicloud
if: github.event_name != 'pull_request'
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
# - uses: depot/setup-action@v1
- name: Login to registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Docker meta
id: meta-ee-public
uses: docker/metadata-action@v5
with:
images: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee-reports
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha,enable=true,priority=100,prefix=,suffix=,format=short
- name: Build and push publicly ee reports
uses: docker/build-push-action@v6
with:
context: .
# platforms: linux/amd64,linux/arm64
push: true
file: "./docker/DockerfileReports"
tags: |
@@ -543,9 +769,11 @@ jobs:
org.opencontainers.image.licenses=Windmill-Enterprise-License
publish_ecr_s3:
needs: [build_ee_nsjail]
needs: [build_ee_nsjail_arm]
runs-on: ubicloud-standard-2-arm
if: (github.event_name != 'pull_request') && (github.event_name != 'workflow_dispatch')
if:
(github.event_name != 'pull_request') && (github.event_name !=
'workflow_dispatch')
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
@@ -589,16 +817,16 @@ jobs:
build_ee_cuda:
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
needs: [build_ee]
runs-on: ubicloud
runs-on: ubicloud-standard-16
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
# - name: Set up Docker Buildx
# uses: docker/setup-buildx-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- uses: depot/setup-action@v1
# - uses: depot/setup-action@v1
- name: Docker meta
id: meta-ee-public
@@ -618,10 +846,10 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push publicly ee
uses: depot/build-push-action@v1
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64
# platforms: linux/amd64
push: true
file: "./docker/DockerfileCuda"
tags: |
@@ -639,10 +867,10 @@ jobs:
with:
fetch-depth: 0
# - name: Set up Docker Buildx
# uses: docker/setup-buildx-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- uses: depot/setup-action@v1
# - uses: depot/setup-action@v1
- name: Docker meta
id: meta-ee-public
@@ -662,10 +890,10 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push publicly ee
uses: depot/build-push-action@v1
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64
# platforms: linux/amd64
push: true
file: "./docker/DockerfileSlim"
tags: |
@@ -682,10 +910,10 @@ jobs:
with:
fetch-depth: 0
# - name: Set up Docker Buildx
# uses: docker/setup-buildx-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- uses: depot/setup-action@v1
# - uses: depot/setup-action@v1
- name: Docker meta
id: meta-ee-public
@@ -705,10 +933,10 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push publicly ee
uses: depot/build-push-action@v1
uses: docker/build-push-action@v1
with:
context: .
platforms: linux/amd64
# platforms: linux/amd64
push: true
file: "./docker/DockerfileSlimEe"
tags: |
@@ -726,10 +954,10 @@ jobs:
with:
fetch-depth: 0
# - name: Set up Docker Buildx
# uses: docker/setup-buildx-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- uses: depot/setup-action@v1
# - uses: depot/setup-action@v1
- name: Docker meta
id: meta-public
@@ -749,10 +977,53 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push publicly
uses: depot/build-push-action@v1
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64
# platforms: linux/amd64,linux/arm64
push: true
file: "./docker/DockerfileFull"
tags: |
${{ steps.meta-public.outputs.tags }}
labels: |
${{ steps.meta-public.outputs.labels }}
build_full_arm:
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
needs: [build_arm]
runs-on: ubicloud
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
# - uses: depot/setup-action@v1
- name: Docker meta
id: meta-public
uses: docker/metadata-action@v5
with:
images: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-full
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
- name: Login to registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push publicly
uses: docker/build-push-action@v6
with:
context: .
# platforms: linux/amd64,linux/arm64
push: true
file: "./docker/DockerfileFull"
tags: |
@@ -769,10 +1040,8 @@ jobs:
with:
fetch-depth: 0
# - name: Set up Docker Buildx
# uses: docker/setup-buildx-action@v2
- uses: depot/setup-action@v1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Docker meta
id: meta-ee-public
@@ -792,10 +1061,52 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push publicly ee
uses: depot/build-push-action@v1
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64
# platforms: linux/amd64,linux/arm64
push: true
file: "./docker/DockerfileFullEe"
tags: |
${{ steps.meta-ee-public.outputs.tags }}
labels: |
${{ steps.meta-ee-public.outputs.labels }}
org.opencontainers.image.licenses=Windmill-Enterprise-License
build_ee_full_arm:
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
needs: [build_ee_arm]
runs-on: ubicloud
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Docker meta
id: meta-ee-public
uses: docker/metadata-action@v5
with:
images: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee-full
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
- name: Login to registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push publicly ee
uses: docker/build-push-action@v6
with:
context: .
# platforms: linux/amd64,linux/arm64
push: true
file: "./docker/DockerfileFullEe"
tags: |

View File

@@ -47,7 +47,7 @@ jobs:
$env:OPENSSL_DIR="${Env:VCPKG_INSTALLATION_ROOT}\installed\x64-windows-static"
mkdir frontend/build && cd backend
New-Item -Path . -Name "windmill-api/openapi-deref.yaml" -ItemType "File" -Force
cargo build --release --features=enterprise,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy,deno_core,license,http_trigger,zip,oauth2,kafka,nats,php,mysql,mssql,bigquery,websocket,python,smtp,csharp,static_frontend,rust
cargo build --release --features=enterprise,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy,deno_core,license,http_trigger,zip,oauth2,kafka,php,mysql,mssql,bigquery,websocket,python,smtp,csharp,static_frontend,rust
- name: Rename binary with corresponding architecture
run: |

View File

@@ -1,91 +1,5 @@
# Changelog
## [1.445.0](https://github.com/windmill-labs/windmill/compare/v1.444.0...v1.445.0) (2025-01-10)
### Features
* **frontend:** allow workspace admin to set workspace color ([#5032](https://github.com/windmill-labs/windmill/issues/5032)) ([0c39137](https://github.com/windmill-labs/windmill/commit/0c391372cca96da820e8438a3f685f9895dbff73))
* nats triggers ([#5039](https://github.com/windmill-labs/windmill/issues/5039)) ([e66fcf9](https://github.com/windmill-labs/windmill/commit/e66fcf927097cb56d90d9f95c6d1f8ef10f45ff7))
### Bug Fixes
* **backend:** multiple routes with same path but different methods ([#5040](https://github.com/windmill-labs/windmill/issues/5040)) ([7b808c3](https://github.com/windmill-labs/windmill/commit/7b808c39771efb7c6b440b2a15427b4b1a7700ab))
* support html in github markdown plugin ([#5031](https://github.com/windmill-labs/windmill/issues/5031)) ([53c62f2](https://github.com/windmill-labs/windmill/commit/53c62f2dbc4d43f02860fc9606a57996228be37c))
## [1.444.0](https://github.com/windmill-labs/windmill/compare/v1.443.0...v1.444.0) (2025-01-06)
### Features
* captures ([#4807](https://github.com/windmill-labs/windmill/issues/4807)) ([01c6f84](https://github.com/windmill-labs/windmill/commit/01c6f845206b70a37163b8e67ff769cd5ad181ce))
### Bug Fixes
* **backend:** fix `has_failure_module` only looking for `raw_flow` ([#5018](https://github.com/windmill-labs/windmill/issues/5018)) ([abf63a6](https://github.com/windmill-labs/windmill/commit/abf63a6560817cfd392d3df7a74ba937255cb507))
* recognize `forloop-<n>` in `use_flow_root_path` ([#5016](https://github.com/windmill-labs/windmill/issues/5016)) ([3eaef46](https://github.com/windmill-labs/windmill/commit/3eaef46a4fac92951e15a8e2177dbd25227c7250))
## [1.443.0](https://github.com/windmill-labs/windmill/compare/v1.442.0...v1.443.0) (2025-01-04)
### Features
* allow s3 file download/preview from inside apps ([#5004](https://github.com/windmill-labs/windmill/issues/5004)) ([0c19171](https://github.com/windmill-labs/windmill/commit/0c19171f579cdd5d2753bd58dcc87b326cb6c09e))
## [1.442.0](https://github.com/windmill-labs/windmill/compare/v1.441.2...v1.442.0) (2025-01-03)
### Features
* update git sync scripts with url redacted ([#5008](https://github.com/windmill-labs/windmill/issues/5008)) ([bbf7fd6](https://github.com/windmill-labs/windmill/commit/bbf7fd695b75403714eaa68764137a5fa560c92a))
### Bug Fixes
* **apps:** check for auth when executing as publisher ([#4979](https://github.com/windmill-labs/windmill/issues/4979)) ([f5c85d7](https://github.com/windmill-labs/windmill/commit/f5c85d7db994a269b63940a1445d1c2d659c3bc5))
* **backend:** allow multiple files per field when using multipart ([#5002](https://github.com/windmill-labs/windmill/issues/5002)) ([383ecf8](https://github.com/windmill-labs/windmill/commit/383ecf846754d40ceaee256360a042d881984690))
* handle `'flownode'` job kind where missing ([#4990](https://github.com/windmill-labs/windmill/issues/4990)) ([eeece84](https://github.com/windmill-labs/windmill/commit/eeece84a4b2f09cf50f7a04fac71912953f6e7f1))
* **python:** Cancel and Start again within 1s caused module not found [v2] ([#5007](https://github.com/windmill-labs/windmill/issues/5007)) ([c998d2c](https://github.com/windmill-labs/windmill/commit/c998d2c8c50cc8ec38fb771bd55743fa3e651bcd))
## [1.441.2](https://github.com/windmill-labs/windmill/compare/v1.441.1...v1.441.2) (2024-12-27)
### Bug Fixes
* **backend:** fix zombies left by the bash executor ([#4985](https://github.com/windmill-labs/windmill/issues/4985)) ([8db69ce](https://github.com/windmill-labs/windmill/commit/8db69ce15e25601d0ac2ac98b1e45c0c01c11967))
## [1.441.1](https://github.com/windmill-labs/windmill/compare/v1.441.0...v1.441.1) (2024-12-24)
### Bug Fixes
* **backend:** timeout for bigquery/graphql/snowflake ([#4965](https://github.com/windmill-labs/windmill/issues/4965)) ([1d20dea](https://github.com/windmill-labs/windmill/commit/1d20dea6630407840fd058a8b51c410fae3fbe78))
* windows compatibility for C# ([#4980](https://github.com/windmill-labs/windmill/issues/4980)) ([b12e9c3](https://github.com/windmill-labs/windmill/commit/b12e9c3005db10d15ee27894a819dbb556832a83))
* **windows&python:** Access is denied. (os error 5) ([#4969](https://github.com/windmill-labs/windmill/issues/4969)) ([6bd2dc3](https://github.com/windmill-labs/windmill/commit/6bd2dc38325388a55dd288b94e26ac6018622aaa))
## [1.441.0](https://github.com/windmill-labs/windmill/compare/v1.440.3...v1.441.0) (2024-12-20)
### Features
* interactive slack approvals ([#4942](https://github.com/windmill-labs/windmill/issues/4942)) ([6308bf0](https://github.com/windmill-labs/windmill/commit/6308bf0dcb1d6670e839a1a1e0b794bf3ce6520c))
## [1.440.3](https://github.com/windmill-labs/windmill/compare/v1.440.2...v1.440.3) (2024-12-19)
### Bug Fixes
* update bun from 1.1.38 to 1.1.40 ([c4fdd22](https://github.com/windmill-labs/windmill/commit/c4fdd2297efc43ce557cc9791151301377126c29))
## [1.440.2](https://github.com/windmill-labs/windmill/compare/v1.440.1...v1.440.2) (2024-12-18)
### Bug Fixes
* fix redeploying flows with attached schedules ([fb536df](https://github.com/windmill-labs/windmill/commit/fb536df0668d49d14f4aed98870caaad396d0389))
## [1.440.1](https://github.com/windmill-labs/windmill/compare/v1.440.0...v1.440.1) (2024-12-18)

View File

@@ -13,8 +13,6 @@ RUN apt-get -y update \
RUN rustup component add rustfmt
RUN CARGO_NET_GIT_FETCH_WITH_CLI=true cargo install cargo-chef --version ^0.1
RUN cargo install sccache --version ^0.8
ENV RUSTC_WRAPPER=sccache SCCACHE_DIR=/backend/sccache
WORKDIR /windmill
@@ -50,9 +48,7 @@ FROM rust_base AS planner
COPY ./openflow.openapi.yaml /openflow.openapi.yaml
COPY ./backend ./
RUN --mount=type=cache,target=/usr/local/cargo/registry \
--mount=type=cache,target=$SCCACHE_DIR,sharing=locked \
CARGO_NET_GIT_FETCH_WITH_CLI=true cargo chef prepare --recipe-path recipe.json
RUN CARGO_NET_GIT_FETCH_WITH_CLI=true cargo chef prepare --recipe-path recipe.json
FROM rust_base AS builder
ARG features=""
@@ -63,9 +59,7 @@ RUN apt-get update && apt-get install -y libxml2-dev=2.9.* libxmlsec1-dev=1.2.*
apt-get clean && \
rm -rf /var/lib/apt/lists/*
RUN --mount=type=cache,target=/usr/local/cargo/registry \
--mount=type=cache,target=$SCCACHE_DIR,sharing=locked \
CARGO_NET_GIT_FETCH_WITH_CLI=true RUST_BACKTRACE=1 cargo chef cook --release --features "$features" --recipe-path recipe.json
RUN CARGO_NET_GIT_FETCH_WITH_CLI=true RUST_BACKTRACE=1 cargo chef cook --release --features "$features" --recipe-path recipe.json
COPY ./openflow.openapi.yaml /openflow.openapi.yaml
COPY ./backend ./
@@ -76,9 +70,7 @@ COPY --from=frontend /frontend/build /frontend/build
COPY --from=frontend /backend/windmill-api/openapi-deref.yaml ./windmill-api/openapi-deref.yaml
COPY .git/ .git/
RUN --mount=type=cache,target=/usr/local/cargo/registry \
--mount=type=cache,target=$SCCACHE_DIR,sharing=locked \
CARGO_NET_GIT_FETCH_WITH_CLI=true cargo build --release --features "$features"
RUN CARGO_NET_GIT_FETCH_WITH_CLI=true cargo build --release --features "$features"
FROM ${PYTHON_IMAGE}
@@ -159,7 +151,7 @@ ENV PATH="${PATH}:/usr/local/go/bin"
ENV GO_PATH=/usr/local/go/bin/go
# Install UV
RUN curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/uv/releases/download/0.5.15/uv-installer.sh | sh && mv /root/.local/bin/uv /usr/local/bin/uv
RUN curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/uv/releases/download/0.4.18/uv-installer.sh | sh && mv /root/.cargo/bin/uv /usr/local/bin/uv
RUN curl -sL https://deb.nodesource.com/setup_20.x | bash -
RUN apt-get -y update && apt-get install -y curl procps nodejs awscli && apt-get clean \
@@ -177,7 +169,7 @@ COPY --from=builder /windmill/target/release/windmill ${APP}/windmill
COPY --from=denoland/deno:2.1.2 --chmod=755 /usr/bin/deno /usr/bin/deno
COPY --from=oven/bun:1.1.40 /usr/local/bin/bun /usr/bin/bun
COPY --from=oven/bun:1.1.38 /usr/local/bin/bun /usr/bin/bun
COPY --from=php:8.3.7-cli /usr/local/bin/php /usr/bin/php
COPY --from=composer:2.7.6 /usr/bin/composer /usr/bin/composer
@@ -196,21 +188,6 @@ COPY ./frontend/src/lib/hubPaths.json ${APP}/hubPaths.json
RUN windmill cache ${APP}/hubPaths.json && rm ${APP}/hubPaths.json && chmod -R 777 /tmp/windmill
# Create a non-root user 'windmill' with UID and GID 1000
RUN addgroup --gid 1000 windmill && \
adduser --disabled-password --gecos "" --uid 1000 --gid 1000 windmill
RUN cp -r /root/.cache /home/windmill/.cache
RUN mkdir -p /tmp/windmill/logs && \
mkdir -p /tmp/windmill/search
RUN chown -R windmill:windmill ${APP} && \
chown -R windmill:windmill /tmp/windmill && \
chown -R windmill:windmill /home/windmill/.cache
USER root
EXPOSE 8000
CMD ["windmill"]

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE kafka_trigger SET server_id = $1, last_server_ping = now(), error = 'Connecting...' WHERE enabled IS TRUE AND workspace_id = $2 AND path = $3 AND (last_server_ping IS NULL OR last_server_ping < now() - interval '15 seconds') RETURNING true",
"query": "UPDATE websocket_trigger SET server_id = $1, last_server_ping = now() WHERE enabled IS TRUE AND workspace_id = $2 AND path = $3 AND (server_id IS NULL OR last_server_ping IS NULL OR last_server_ping < now() - interval '15 seconds') RETURNING true",
"describe": {
"columns": [
{
@@ -20,5 +20,5 @@
null
]
},
"hash": "d78ecf85c1e1e95650c380c9488aa90d8d8c5c76f3971484e4c515ff60293d3b"
"hash": "02424907504848e983bfa89eec343061932dc5b4b17cf13d5cf8d833aedbe6d5"
}

View File

@@ -1,26 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE capture_config SET last_server_ping = now(), error = $1 WHERE workspace_id = $2 AND path = $3 AND is_flow = $4 AND trigger_kind = 'websocket' AND server_id = $5 AND last_client_ping > NOW() - INTERVAL '10 seconds' RETURNING 1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "?column?",
"type_info": "Int4"
}
],
"parameters": {
"Left": [
"Text",
"Text",
"Text",
"Bool",
"Text"
]
},
"nullable": [
null
]
},
"hash": "031d0d70b0aff52feaad487bddb74e5ef0aaa2505facbea8c764003dfc8fffb1"
}

View File

@@ -1,34 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO capture (workspace_id, path, is_flow, trigger_kind, payload, trigger_extra, created_by)\n VALUES ($1, $2, $3, $4, $5, $6, $7)",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Varchar",
"Bool",
{
"Custom": {
"name": "trigger_kind",
"kind": {
"Enum": [
"webhook",
"http",
"websocket",
"kafka",
"email",
"nats"
]
}
}
},
"Jsonb",
"Jsonb",
"Varchar"
]
},
"nullable": []
},
"hash": "07da723ce5c9ee2d7c236e8eabe254c783fc34b617c8a9a95a0eb0cda535dab5"
}

View File

@@ -0,0 +1,16 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO capture\n (workspace_id, path, created_by)\n VALUES ($1, $2, $3)\n ON CONFLICT (workspace_id, path)\n DO UPDATE SET created_at = now()\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Varchar",
"Varchar"
]
},
"nullable": []
},
"hash": "0a9a191273c735c41d56ea46a39ffca075a0550eada87df7162c5037164ad6bf"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE websocket_trigger SET url = $1, script_path = $2, path = $3, is_flow = $4, filters = $5, initial_messages = $6, url_runnable_args = $7, edited_by = $8, email = $9, edited_at = now(), server_id = NULL, error = NULL\n WHERE workspace_id = $10 AND path = $11",
"query": "UPDATE websocket_trigger SET url = $1, script_path = $2, path = $3, is_flow = $4, filters = $5, initial_messages = $6, url_runnable_args = $7, edited_by = $8, email = $9, edited_at = now(), server_id = NULL, last_server_ping = NULL, error = NULL\n WHERE workspace_id = $10 AND path = $11",
"describe": {
"columns": [],
"parameters": {
@@ -20,5 +20,5 @@
},
"nullable": []
},
"hash": "561b7935d687f6b9f3d6488f8489f55e6737ffa2d3716f803d32f8b68cc1e915"
"hash": "0b94bd4c98a11ca1b7e5e34dd1ee6fcb0b7a54ed4218fa3cf23cc929d009d50f"
}

View File

@@ -1,72 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT content AS \"content!: String\",\n lock AS \"lock: String\", language AS \"language: Option<ScriptLang>\", envs AS \"envs: Vec<String>\", codebase AS \"codebase: String\" FROM script WHERE hash = $1 LIMIT 1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "content!: String",
"type_info": "Text"
},
{
"ordinal": 1,
"name": "lock: String",
"type_info": "Text"
},
{
"ordinal": 2,
"name": "language: Option<ScriptLang>",
"type_info": {
"Custom": {
"name": "script_lang",
"kind": {
"Enum": [
"python3",
"deno",
"go",
"bash",
"postgresql",
"nativets",
"bun",
"mysql",
"bigquery",
"snowflake",
"graphql",
"powershell",
"mssql",
"php",
"bunnative",
"rust",
"ansible",
"csharp"
]
}
}
}
},
{
"ordinal": 3,
"name": "envs: Vec<String>",
"type_info": "VarcharArray"
},
{
"ordinal": 4,
"name": "codebase: String",
"type_info": "Varchar"
}
],
"parameters": {
"Left": [
"Int8"
]
},
"nullable": [
false,
true,
false,
true,
true
]
},
"hash": "0bf123446bebbc357c58a53a9319f4954dbf3225e91cbe999e5b264c1a747664"
}

View File

@@ -1,15 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "DELETE FROM capture_config WHERE path = $1 AND workspace_id = $2 AND is_flow IS TRUE",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text"
]
},
"nullable": []
},
"hash": "0dbd664c906ee3c65856520c22f0828357b36bbcdcc151bd97605d7d7a0489e8"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "SELECT path, script_path, is_flow, route_path, workspace_id, is_async, requires_auth, edited_by, email, static_asset_config as \"static_asset_config: _\" FROM http_trigger WHERE workspace_id = $1 AND http_method = $2",
"query": "SELECT path, script_path, is_flow, route_path, workspace_id, is_async, requires_auth, edited_by, email, http_method as \"http_method: _\", static_asset_config as \"static_asset_config: _\" FROM http_trigger",
"describe": {
"columns": [
{
@@ -50,14 +50,8 @@
},
{
"ordinal": 9,
"name": "static_asset_config: _",
"type_info": "Jsonb"
}
],
"parameters": {
"Left": [
"Text",
{
"name": "http_method: _",
"type_info": {
"Custom": {
"name": "http_method",
"kind": {
@@ -71,7 +65,15 @@
}
}
}
]
},
{
"ordinal": 10,
"name": "static_asset_config: _",
"type_info": "Jsonb"
}
],
"parameters": {
"Left": []
},
"nullable": [
false,
@@ -83,8 +85,9 @@
false,
false,
false,
false,
true
]
},
"hash": "a76be7f4e9e8b8c81afe50fcbf1f3d393ed0bb73314e5c430f32541c43bcac52"
"hash": "11b698f82a54aac68b3617047dfe2b18dd6da7d962118fee276af354218baac2"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE websocket_trigger SET enabled = $1, email = $2, edited_by = $3, edited_at = now(), server_id = NULL, error = NULL\n WHERE path = $4 AND workspace_id = $5 RETURNING 1",
"query": "UPDATE websocket_trigger SET enabled = $1, email = $2, edited_by = $3, edited_at = now(), server_id = NULL, last_server_ping = NULL, error = NULL\n WHERE path = $4 AND workspace_id = $5 RETURNING 1",
"describe": {
"columns": [
{
@@ -22,5 +22,5 @@
null
]
},
"hash": "25975935d59f88df117bae0fa5016cf95ad56f790f0eddb6e2fbe3d83d3accaa"
"hash": "12a86755706ce030a0a9142da78d035d0c7d361240b60005cc864e4345eb0bc7"
}

View File

@@ -122,11 +122,6 @@
"ordinal": 23,
"name": "mute_critical_alerts",
"type_info": "Bool"
},
{
"ordinal": 24,
"name": "color",
"type_info": "Varchar"
}
],
"parameters": {
@@ -158,7 +153,6 @@
false,
true,
true,
true,
true
]
},

View File

@@ -1,17 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE capture_config SET error = $1, server_id = NULL, last_server_ping = NULL WHERE workspace_id = $2 AND path = $3 AND is_flow = $4 AND trigger_kind = 'kafka'",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text",
"Text",
"Bool"
]
},
"nullable": []
},
"hash": "203fa78d423ec5a8c5ff6166aed591b28cbf9ea8f61d379b84ee6e14c033035d"
}

View File

@@ -1,77 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT id, created_at, trigger_kind as \"trigger_kind: _\", payload as \"payload: _\", trigger_extra as \"trigger_extra: _\"\n FROM capture\n WHERE workspace_id = $1\n AND path = $2 AND is_flow = $3\n AND ($4::trigger_kind IS NULL OR trigger_kind = $4)\n ORDER BY created_at DESC",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Int8"
},
{
"ordinal": 1,
"name": "created_at",
"type_info": "Timestamptz"
},
{
"ordinal": 2,
"name": "trigger_kind: _",
"type_info": {
"Custom": {
"name": "trigger_kind",
"kind": {
"Enum": [
"webhook",
"http",
"websocket",
"kafka",
"email",
"nats"
]
}
}
}
},
{
"ordinal": 3,
"name": "payload: _",
"type_info": "Jsonb"
},
{
"ordinal": 4,
"name": "trigger_extra: _",
"type_info": "Jsonb"
}
],
"parameters": {
"Left": [
"Text",
"Text",
"Bool",
{
"Custom": {
"name": "trigger_kind",
"kind": {
"Enum": [
"webhook",
"http",
"websocket",
"kafka",
"email",
"nats"
]
}
}
}
]
},
"nullable": [
false,
false,
false,
false,
true
]
},
"hash": "2f440ab6083764b49e309c1f8dde0c5508da110f54bc5f465f1892afdf851af0"
}

View File

@@ -1,25 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE queue SET flow_status = JSONB_SET(flow_status, ARRAY['user_states'], JSONB_SET(COALESCE(flow_status->'user_states', '{}'::jsonb), ARRAY[$1], $2))\n WHERE id = $3 AND workspace_id = $4 AND job_kind IN ('flow', 'flowpreview', 'flownode') RETURNING 1\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "?column?",
"type_info": "Int4"
}
],
"parameters": {
"Left": [
"Text",
"Jsonb",
"Uuid",
"Text"
]
},
"nullable": [
null
]
},
"hash": "364248db86a9228bba6ff522e811d68c5c902ee0a07ea69bff772ff10d0dc5aa"
}

View File

@@ -1,52 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT workspace.id, workspace.name, workspace.owner, workspace.deleted, workspace.premium, workspace_settings.color\n FROM workspace\n LEFT JOIN workspace_settings ON workspace.id = workspace_settings.workspace_id\n JOIN usr ON usr.workspace_id = workspace.id\n WHERE usr.email = $1 AND workspace.deleted = false",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "name",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "owner",
"type_info": "Varchar"
},
{
"ordinal": 3,
"name": "deleted",
"type_info": "Bool"
},
{
"ordinal": 4,
"name": "premium",
"type_info": "Bool"
},
{
"ordinal": 5,
"name": "color",
"type_info": "Varchar"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false,
false,
false,
false,
false,
true
]
},
"hash": "3651ed42be75d41ab0387f1551012d72c90235bb40d2f66e6fb235c990d78352"
}

View File

@@ -1,15 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "DELETE FROM capture_config WHERE path = $1 AND workspace_id = $2 AND is_flow IS FALSE",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text"
]
},
"nullable": []
},
"hash": "3b6ddfe4df620d5e34a01dbbc95067d7dee6a7108cb8a46a20f26236009481da"
}

View File

@@ -1,14 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "DELETE FROM capture_config WHERE workspace_id = $1",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text"
]
},
"nullable": []
},
"hash": "3c9fc4d8579767f3ce7c3633fca770e6341624e98117d21b9f01e68b4e0ce033"
}

View File

@@ -1,26 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE nats_trigger SET enabled = $1, email = $2, edited_by = $3, edited_at = now(), server_id = NULL, error = NULL\n WHERE path = $4 AND workspace_id = $5 RETURNING 1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "?column?",
"type_info": "Int4"
}
],
"parameters": {
"Left": [
"Bool",
"Varchar",
"Varchar",
"Text",
"Text"
]
},
"nullable": [
null
]
},
"hash": "3d8fdf7adf42b27808a5b223df3a660bfd5a8c0a451a0deac24632f0ccf66165"
}

View File

@@ -1,34 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT code AS \"raw_code: String\", lock AS \"raw_lock: String\", flow AS \"raw_flow: Json<Box<RawValue>>\" FROM flow_node WHERE id = $1 LIMIT 1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "raw_code: String",
"type_info": "Text"
},
{
"ordinal": 1,
"name": "raw_lock: String",
"type_info": "Text"
},
{
"ordinal": 2,
"name": "raw_flow: Json<Box<RawValue>>",
"type_info": "Jsonb"
}
],
"parameters": {
"Left": [
"Int8"
]
},
"nullable": [
true,
true,
true
]
},
"hash": "3ee2d60ca93eeaf02ab0ee96aca399ec055b044a06284c0ab19b67d97f803894"
}

View File

@@ -1,14 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "DELETE FROM capture WHERE id = $1",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Int8"
]
},
"nullable": []
},
"hash": "41e557e1b63b13c9fcc195901c0bd0de7e03c539ee046955543d9693551246f7"
}

View File

@@ -1,50 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT path, is_flow, workspace_id, trigger_config as \"trigger_config!: _\", owner, email FROM capture_config WHERE trigger_kind = 'nats' AND last_client_ping > NOW() - INTERVAL '10 seconds' AND trigger_config IS NOT NULL AND (last_server_ping IS NULL OR last_server_ping < now() - interval '15 seconds')",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "path",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "is_flow",
"type_info": "Bool"
},
{
"ordinal": 2,
"name": "workspace_id",
"type_info": "Varchar"
},
{
"ordinal": 3,
"name": "trigger_config!: _",
"type_info": "Jsonb"
},
{
"ordinal": 4,
"name": "owner",
"type_info": "Varchar"
},
{
"ordinal": 5,
"name": "email",
"type_info": "Varchar"
}
],
"parameters": {
"Left": []
},
"nullable": [
false,
false,
false,
true,
false,
false
]
},
"hash": "42030372693d8d6b8d03947bb6702024cfa226735eeeb720bbab46bd0e3cedcc"
}

View File

@@ -1,50 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT path, is_flow, workspace_id, trigger_config as \"trigger_config!: _\", owner, email FROM capture_config WHERE trigger_kind = 'websocket' AND last_client_ping > NOW() - INTERVAL '10 seconds' AND trigger_config IS NOT NULL AND (last_server_ping IS NULL OR last_server_ping < now() - interval '15 seconds')",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "path",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "is_flow",
"type_info": "Bool"
},
{
"ordinal": 2,
"name": "workspace_id",
"type_info": "Varchar"
},
{
"ordinal": 3,
"name": "trigger_config!: _",
"type_info": "Jsonb"
},
{
"ordinal": 4,
"name": "owner",
"type_info": "Varchar"
},
{
"ordinal": 5,
"name": "email",
"type_info": "Varchar"
}
],
"parameters": {
"Left": []
},
"nullable": [
false,
false,
false,
true,
false,
false
]
},
"hash": "47560aa3d3af93167663e763ad873088eb4f57785df3c383bbf6e5ceab268980"
}

View File

@@ -122,11 +122,6 @@
"ordinal": 23,
"name": "mute_critical_alerts",
"type_info": "Bool"
},
{
"ordinal": 24,
"name": "color",
"type_info": "Varchar"
}
],
"parameters": {
@@ -158,7 +153,6 @@
false,
true,
true,
true,
true
]
},

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE kafka_trigger SET kafka_resource_path = $1, group_id = $2, topics = $3, script_path = $4, path = $5, is_flow = $6, edited_by = $7, email = $8, edited_at = now(), server_id = NULL, error = NULL\n WHERE workspace_id = $9 AND path = $10",
"query": "UPDATE kafka_trigger SET kafka_resource_path = $1, group_id = $2, topics = $3, script_path = $4, path = $5, is_flow = $6, edited_by = $7, email = $8, edited_at = now(), server_id = NULL, last_server_ping = NULL, error = NULL\n WHERE workspace_id = $9 AND path = $10",
"describe": {
"columns": [],
"parameters": {
@@ -19,5 +19,5 @@
},
"nullable": []
},
"hash": "1c0f95a069891f7214505aaa9428e11e25c1d3a30294cbe78f01ed75edf68da4"
"hash": "5962733746c81480abe9ab3a6ccf5664130ae7500279055c08db42d67b2822f6"
}

View File

@@ -1,40 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT workspace.id, workspace.name, usr.username, workspace_settings.color\n FROM workspace\n JOIN usr ON usr.workspace_id = workspace.id\n JOIN workspace_settings ON workspace_settings.workspace_id = workspace.id\n WHERE usr.email = $1 AND workspace.deleted = false",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "name",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "username",
"type_info": "Varchar"
},
{
"ordinal": 3,
"name": "color",
"type_info": "Varchar"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false,
false,
false,
true
]
},
"hash": "6c845f168b6265e6cf92e4d33c5409edfdc1847d0348df2ea55504ddaaa67736"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE kafka_trigger SET enabled = $1, email = $2, edited_by = $3, edited_at = now(), server_id = NULL, error = NULL\n WHERE path = $4 AND workspace_id = $5 RETURNING 1",
"query": "UPDATE kafka_trigger SET enabled = $1, email = $2, edited_by = $3, edited_at = now(), server_id = NULL, last_server_ping = NULL, error = NULL\n WHERE path = $4 AND workspace_id = $5 RETURNING 1",
"describe": {
"columns": [
{
@@ -22,5 +22,5 @@
null
]
},
"hash": "eda1e5d1109a13feb14be254eaca630be29176bd5d1246c974642d40201782fc"
"hash": "6eb076afcf11dba0dfe35ee108c64814f95dbe5376f0539195d24a8ca96ca3e2"
}

View File

@@ -1,45 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT owner, email\n FROM capture_config\n WHERE workspace_id = $1 AND path = $2 AND is_flow = $3 AND trigger_kind = $4 AND last_client_ping > NOW() - INTERVAL '10 seconds'",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "owner",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "email",
"type_info": "Varchar"
}
],
"parameters": {
"Left": [
"Text",
"Text",
"Bool",
{
"Custom": {
"name": "trigger_kind",
"kind": {
"Enum": [
"webhook",
"http",
"websocket",
"kafka",
"email",
"nats"
]
}
}
}
]
},
"nullable": [
false,
false
]
},
"hash": "71d51bbc35da7b9930e3ea3a634451217ccb9f1bc35b1ad6e10d16bc19c41447"
}

View File

@@ -1,23 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT EXISTS(SELECT 1 FROM nats_trigger WHERE path = $1 AND workspace_id = $2)",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "exists",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text",
"Text"
]
},
"nullable": [
null
]
},
"hash": "746ee16a04267cd251d4cefbc44a37fcc985bf61978cc07167ed35d7dbf92d11"
}

View File

@@ -1,16 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE capture_config SET path = $1 WHERE path = $2 AND workspace_id = $3 AND is_flow IS FALSE",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Text",
"Text"
]
},
"nullable": []
},
"hash": "78b182167ba19d1dc103577bd3492736e7088ed69b543adbcfd3b3b7a4ece430"
}

View File

@@ -1,25 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE nats_trigger SET nats_resource_path = $1, subjects = $2, stream_name = $3, consumer_name = $4, use_jetstream = $5, script_path = $6, path = $7, is_flow = $8, edited_by = $9, email = $10, edited_at = now(), server_id = NULL, error = NULL\n WHERE workspace_id = $11 AND path = $12",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"VarcharArray",
"Varchar",
"Varchar",
"Bool",
"Varchar",
"Varchar",
"Bool",
"Varchar",
"Varchar",
"Text",
"Text"
]
},
"nullable": []
},
"hash": "7b36b58761cd459b808cc4f463dfc93f01fdbc19c66d7404f95e1f8444235a8e"
}

View File

@@ -1,34 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE queue SET running = false, started_at = null\n WHERE last_ping < now() - ($1 || ' seconds')::interval\n AND running = true AND job_kind NOT IN ('flow', 'flowpreview', 'flownode', 'singlescriptflow') AND same_worker = false RETURNING id, workspace_id, last_ping",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
},
{
"ordinal": 1,
"name": "workspace_id",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "last_ping",
"type_info": "Timestamptz"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false,
false,
true
]
},
"hash": "84576f6add15108ade2ed3a88185d67db17904859e5f01f1d578af4e1d062a85"
}

View File

@@ -1,15 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "DELETE FROM nats_trigger WHERE workspace_id = $1 AND path = $2",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text"
]
},
"nullable": []
},
"hash": "870b12a46f26c9e29889dd28a5c7832c5a674a5553674fd9762c981e0d03bb57"
}

View File

@@ -1,15 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "DELETE FROM capture WHERE path = $1 AND workspace_id = $2 AND is_flow IS TRUE",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text"
]
},
"nullable": []
},
"hash": "87e0bee8b78facc62d4c225dc51651d65b1135092067061e7f4050776b733b03"
}

View File

@@ -1,16 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE capture_config SET path = $1 WHERE path = $2 AND workspace_id = $3 AND is_flow IS TRUE",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Text",
"Text"
]
},
"nullable": []
},
"hash": "90ad280f6744937878b134142825ccb7d7071a80a3f5da59da8948c0106e959c"
}

View File

@@ -1,16 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE capture SET path = $1 WHERE path = $2 AND workspace_id = $3 AND is_flow IS FALSE",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Text",
"Text"
]
},
"nullable": []
},
"hash": "90e74c28b417e73924ed337f6634f574024e641e73072586aca88847259e8cfc"
}

View File

@@ -1,24 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE websocket_trigger SET server_id = $1, last_server_ping = now(), error = 'Connecting...' WHERE enabled IS TRUE AND workspace_id = $2 AND path = $3 AND (last_server_ping IS NULL OR last_server_ping < now() - interval '15 seconds') RETURNING true",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "?column?",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Varchar",
"Text",
"Text"
]
},
"nullable": [
null
]
},
"hash": "92e60af0d3ae8c73d74ae68d70e20ae18f79cc84626097b766307cd42722baa3"
}

View File

@@ -1,23 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT flow.versions[array_upper(flow.versions, 1)] AS \"version!: i64\"\n FROM flow WHERE path = $1 AND workspace_id = $2",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "version!: i64",
"type_info": "Int8"
}
],
"parameters": {
"Left": [
"Text",
"Text"
]
},
"nullable": [
null
]
},
"hash": "97048ce0bcabb9baecb80cde5ab3c989e1575fbd20ef22766d2887a86dce15e1"
}

View File

@@ -1,15 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "DELETE FROM capture\n WHERE workspace_id = $1\n AND created_at <=\n (\n SELECT created_at\n FROM capture\n WHERE workspace_id = $1\n ORDER BY created_at DESC\n OFFSET $2\n LIMIT 1\n )",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Int8"
]
},
"nullable": []
},
"hash": "97942578df746c8c8103b403cfc4e44ef5a0f082bdde854900064325adc4dd77"
}

View File

@@ -1,16 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE capture SET path = $1 WHERE path = $2 AND workspace_id = $3 AND is_flow IS TRUE",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Text",
"Text"
]
},
"nullable": []
},
"hash": "988b594f70ff7886985a0f90a095aeffac05016abc4dfed37d5ae2872e8da564"
}

View File

@@ -1,25 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE capture_config SET server_id = $1, last_server_ping = now(), error = 'Connecting...' WHERE last_client_ping > NOW() - INTERVAL '10 seconds' AND workspace_id = $2 AND path = $3 AND is_flow = $4 AND trigger_kind = 'websocket' AND (last_server_ping IS NULL OR last_server_ping < now() - interval '15 seconds') RETURNING true",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "?column?",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Varchar",
"Text",
"Text",
"Bool"
]
},
"nullable": [
null
]
},
"hash": "99a2c935acf5d6bbeb70ea1255679115b6e9042800d40899a36b3867049c5c46"
}

View File

@@ -1,15 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE capture_config SET workspace_id = $1 WHERE workspace_id = $2",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Text"
]
},
"nullable": []
},
"hash": "a17b1b8d4f58c58c253e63ec4c2fbb1df4bef54003b01fa901bfa782b5f83342"
}

View File

@@ -1,24 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT COUNT(*) FROM nats_trigger WHERE script_path = $1 AND is_flow = $2 AND workspace_id = $3",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "count",
"type_info": "Int8"
}
],
"parameters": {
"Left": [
"Text",
"Bool",
"Text"
]
},
"nullable": [
null
]
},
"hash": "ad07b57ad928a4e5260833f4fe2a4bf51211f2f73d78c546c894c8e147677ac7"
}

View File

@@ -1,16 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE nats_trigger SET enabled = FALSE, error = $1, server_id = NULL, last_server_ping = NULL WHERE workspace_id = $2 AND path = $3",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text",
"Text"
]
},
"nullable": []
},
"hash": "add48c8e7c6fa2c549ad6293cbee22889d35e919d3267c1d2a265d868fa8a7d1"
}

View File

@@ -1,72 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT content AS \"content!: String\",\n lock AS \"lock: String\", language AS \"language: Option<ScriptLang>\", envs AS \"envs: Vec<String>\", codebase AS \"codebase: String\" FROM script WHERE hash = $1 LIMIT 1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "content!: String",
"type_info": "Text"
},
{
"ordinal": 1,
"name": "lock: String",
"type_info": "Text"
},
{
"ordinal": 2,
"name": "language: Option<ScriptLang>",
"type_info": {
"Custom": {
"name": "script_lang",
"kind": {
"Enum": [
"python3",
"deno",
"go",
"bash",
"postgresql",
"nativets",
"bun",
"mysql",
"bigquery",
"snowflake",
"graphql",
"powershell",
"mssql",
"php",
"bunnative",
"rust",
"ansible",
"csharp"
]
}
}
}
},
{
"ordinal": 3,
"name": "envs: Vec<String>",
"type_info": "VarcharArray"
},
{
"ordinal": 4,
"name": "codebase: String",
"type_info": "Varchar"
}
],
"parameters": {
"Left": [
"Int8"
]
},
"nullable": [
false,
true,
false,
true,
true
]
},
"hash": "b7f2ed32e933b65fa5455928c71f61068ad7dfee8352a76122f5af893ffe6517"
}

View File

@@ -0,0 +1,16 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE capture\n SET payload = $3\n WHERE workspace_id = $1\n AND path = $2\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text",
"Jsonb"
]
},
"nullable": []
},
"hash": "b9468b9e16f55db11b33d8e9793e6e3ae6c5add6ca02414140adb724120a6800"
}

View File

@@ -1,67 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT\n queue.job_kind AS \"job_kind: JobKind\",\n queue.script_hash AS \"script_hash: ScriptHash\",\n queue.raw_flow AS \"raw_flow: sqlx::types::Json<Box<RawValue>>\",\n completed_job.parent_job AS \"parent_job: Uuid\"\n FROM queue\n JOIN completed_job ON completed_job.parent_job = queue.id\n WHERE completed_job.id = $1 AND completed_job.workspace_id = $2\n LIMIT 1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "job_kind: JobKind",
"type_info": {
"Custom": {
"name": "job_kind",
"kind": {
"Enum": [
"script",
"preview",
"flow",
"dependencies",
"flowpreview",
"script_hub",
"identity",
"flowdependencies",
"http",
"graphql",
"postgresql",
"noop",
"appdependencies",
"deploymentcallback",
"singlescriptflow",
"flowscript",
"flownode",
"appscript"
]
}
}
}
},
{
"ordinal": 1,
"name": "script_hash: ScriptHash",
"type_info": "Int8"
},
{
"ordinal": 2,
"name": "raw_flow: sqlx::types::Json<Box<RawValue>>",
"type_info": "Jsonb"
},
{
"ordinal": 3,
"name": "parent_job: Uuid",
"type_info": "Uuid"
}
],
"parameters": {
"Left": [
"Uuid",
"Text"
]
},
"nullable": [
false,
true,
true,
true
]
},
"hash": "bb6141ad0e93986b38ccdf4d027c486137d4fe79906e22842b711f4a9379b8c8"
}

View File

@@ -1,56 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT trigger_config as \"trigger_config: _\", trigger_kind as \"trigger_kind: _\", error, last_server_ping\n FROM capture_config\n WHERE workspace_id = $1 AND path = $2 AND is_flow = $3",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "trigger_config: _",
"type_info": "Jsonb"
},
{
"ordinal": 1,
"name": "trigger_kind: _",
"type_info": {
"Custom": {
"name": "trigger_kind",
"kind": {
"Enum": [
"webhook",
"http",
"websocket",
"kafka",
"email",
"nats"
]
}
}
}
},
{
"ordinal": 2,
"name": "error",
"type_info": "Text"
},
{
"ordinal": 3,
"name": "last_server_ping",
"type_info": "Timestamptz"
}
],
"parameters": {
"Left": [
"Text",
"Text",
"Bool"
]
},
"nullable": [
true,
false,
true,
true
]
},
"hash": "c223f8b7fa4ef1aa06e1ba2a56d677774aa237508d5610714efd2e9b8b93c7b8"
}

View File

@@ -1,31 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE capture_config SET last_client_ping = now() WHERE workspace_id = $1 AND path = $2 AND is_flow = $3 AND trigger_kind = $4",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text",
"Bool",
{
"Custom": {
"name": "trigger_kind",
"kind": {
"Enum": [
"webhook",
"http",
"websocket",
"kafka",
"email",
"nats"
]
}
}
}
]
},
"nullable": []
},
"hash": "c5270ee815689e42b65df507b850da43239c9a5aaea41c9aed7ed33a6219a534"
}

View File

@@ -1,23 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT 1 FROM app WHERE path = $1 AND workspace_id = $2 LIMIT 1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "?column?",
"type_info": "Int4"
}
],
"parameters": {
"Left": [
"Text",
"Text"
]
},
"nullable": [
null
]
},
"hash": "c73dd6226a154a54debe99f8ae64fd75f8d7ce551c5955aa6bdd8dab2dcbd7ff"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "SELECT path, script_path, is_flow, route_path, workspace_id, is_async, requires_auth, edited_by, email, static_asset_config as \"static_asset_config: _\" FROM http_trigger WHERE http_method = $1",
"query": "SELECT path, script_path, is_flow, route_path, workspace_id, is_async, requires_auth, edited_by, email, http_method as \"http_method: _\", static_asset_config as \"static_asset_config: _\" FROM http_trigger WHERE workspace_id = $1",
"describe": {
"columns": [
{
@@ -50,13 +50,8 @@
},
{
"ordinal": 9,
"name": "static_asset_config: _",
"type_info": "Jsonb"
}
],
"parameters": {
"Left": [
{
"name": "http_method: _",
"type_info": {
"Custom": {
"name": "http_method",
"kind": {
@@ -70,6 +65,16 @@
}
}
}
},
{
"ordinal": 10,
"name": "static_asset_config: _",
"type_info": "Jsonb"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
@@ -82,8 +87,9 @@
false,
false,
false,
false,
true
]
},
"hash": "28a389a93a3d2472b13d956ec55eb357c6147e186e00e371f7374d166903ef64"
"hash": "c9930fcfe79541af570eace58ba7e15a0816a6b4fd036cf7b991a210654b2633"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "SELECT \n EXISTS(SELECT 1 FROM websocket_trigger WHERE workspace_id = $1) as \"websocket_used!\", \n EXISTS(SELECT 1 FROM http_trigger WHERE workspace_id = $1) as \"http_routes_used!\",\n EXISTS(SELECT 1 FROM kafka_trigger WHERE workspace_id = $1) as \"kafka_used!\",\n EXISTS(SELECT 1 FROM nats_trigger WHERE workspace_id = $1) as \"nats_used!\"",
"query": "SELECT \n EXISTS(SELECT 1 FROM websocket_trigger WHERE workspace_id = $1) as \"websocket_used!\", \n EXISTS(SELECT 1 FROM http_trigger WHERE workspace_id = $1) as \"http_routes_used!\",\n EXISTS(SELECT 1 FROM kafka_trigger WHERE workspace_id = $1) as \"kafka_used!\"",
"describe": {
"columns": [
{
@@ -17,11 +17,6 @@
"ordinal": 2,
"name": "kafka_used!",
"type_info": "Bool"
},
{
"ordinal": 3,
"name": "nats_used!",
"type_info": "Bool"
}
],
"parameters": {
@@ -30,11 +25,10 @@
]
},
"nullable": [
null,
null,
null,
null
]
},
"hash": "1ef48cc430870ab6c062b046bdbf0a2db057141619e9818ddb904d7c242efec3"
"hash": "cc8a71abdeccf0787695af32aa21fe73aba65cfdc8329c02b4d257de4d2d168a"
}

View File

@@ -1,24 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE nats_trigger SET server_id = $1, last_server_ping = now(), error = 'Connecting...' WHERE enabled IS TRUE AND workspace_id = $2 AND path = $3 AND (last_server_ping IS NULL OR last_server_ping < now() - interval '15 seconds') RETURNING true",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "?column?",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Varchar",
"Text",
"Text"
]
},
"nullable": [
null
]
},
"hash": "cd5d62d456b74237b941bc72ea8de007185263167bf1dfa2e469d319cc4da674"
}

View File

@@ -1,25 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE capture_config SET server_id = $1, last_server_ping = now(), error = 'Connecting...' WHERE last_client_ping > NOW() - INTERVAL '10 seconds' AND workspace_id = $2 AND path = $3 AND is_flow = $4 AND trigger_kind = 'kafka' AND (last_server_ping IS NULL OR last_server_ping < now() - interval '15 seconds') RETURNING true",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "?column?",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Varchar",
"Text",
"Text",
"Bool"
]
},
"nullable": [
null
]
},
"hash": "d06efdc24706e0d7479bffc0b19a0c5976ee60125289e9f7b0b04090bce4a3a3"
}

View File

@@ -1,17 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE capture_config SET error = $1, server_id = NULL, last_server_ping = NULL WHERE workspace_id = $2 AND path = $3 AND is_flow = $4 AND trigger_kind = 'websocket'",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text",
"Text",
"Bool"
]
},
"nullable": []
},
"hash": "d08f34000c3d96ccd0f44ca8520f966d751a4dda554d8215eedb8f65be98e100"
}

View File

@@ -1,15 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE workspace_settings SET color = $1 WHERE workspace_id = $2",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Text"
]
},
"nullable": []
},
"hash": "d2668c2d4ece82a3617f098fe993d3e218fa224bd0bb311e7db776c7fd69cf0b"
}

View File

@@ -0,0 +1,24 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE kafka_trigger SET server_id = $1, last_server_ping = now() WHERE enabled IS TRUE AND workspace_id = $2 AND path = $3 AND (server_id IS NULL OR last_server_ping IS NULL OR last_server_ping < now() - interval '15 seconds') RETURNING true",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "?column?",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Varchar",
"Text",
"Text"
]
},
"nullable": [
null
]
},
"hash": "d6615719bf8db4b333ed55c9a3c160ad1962668fc3305d8e80ae91ef73614a80"
}

View File

@@ -1,50 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT path, is_flow, workspace_id, trigger_config as \"trigger_config!: _\", owner, email FROM capture_config WHERE trigger_kind = 'kafka' AND last_client_ping > NOW() - INTERVAL '10 seconds' AND trigger_config IS NOT NULL AND (last_server_ping IS NULL OR last_server_ping < now() - interval '15 seconds')",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "path",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "is_flow",
"type_info": "Bool"
},
{
"ordinal": 2,
"name": "workspace_id",
"type_info": "Varchar"
},
{
"ordinal": 3,
"name": "trigger_config!: _",
"type_info": "Jsonb"
},
{
"ordinal": 4,
"name": "owner",
"type_info": "Varchar"
},
{
"ordinal": 5,
"name": "email",
"type_info": "Varchar"
}
],
"parameters": {
"Left": []
},
"nullable": [
false,
false,
false,
true,
false,
false
]
},
"hash": "d8ea17fba0e417333e9c6cf82ad36a57830a791c8358e30e9be012b815f5e8e3"
}

View File

@@ -1,26 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE capture_config SET last_server_ping = now(), error = $1 WHERE workspace_id = $2 AND path = $3 AND is_flow = $4 AND trigger_kind = 'kafka' AND server_id = $5 AND last_client_ping > NOW() - INTERVAL '10 seconds' RETURNING 1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "?column?",
"type_info": "Int4"
}
],
"parameters": {
"Left": [
"Text",
"Text",
"Text",
"Bool",
"Text"
]
},
"nullable": [
null
]
},
"hash": "d9a6f75e4c4a1f61e55b313cc09bceffac637548841897341672da427a9140fc"
}

View File

@@ -1,91 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT\n queue.job_kind AS \"job_kind: JobKind\",\n queue.script_hash AS \"script_hash: ScriptHash\",\n queue.raw_flow AS \"raw_flow: sqlx::types::Json<Box<RawValue>>\",\n completed_job.parent_job AS \"parent_job: Uuid\",\n completed_job.created_at AS \"created_at: chrono::NaiveDateTime\",\n completed_job.created_by AS \"created_by!\",\n queue.script_path,\n queue.args AS \"args: sqlx::types::Json<Box<RawValue>>\"\n FROM queue\n JOIN completed_job ON completed_job.parent_job = queue.id\n WHERE completed_job.id = $1 AND completed_job.workspace_id = $2\n LIMIT 1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "job_kind: JobKind",
"type_info": {
"Custom": {
"name": "job_kind",
"kind": {
"Enum": [
"script",
"preview",
"flow",
"dependencies",
"flowpreview",
"script_hub",
"identity",
"flowdependencies",
"http",
"graphql",
"postgresql",
"noop",
"appdependencies",
"deploymentcallback",
"singlescriptflow",
"flowscript",
"flownode",
"appscript"
]
}
}
}
},
{
"ordinal": 1,
"name": "script_hash: ScriptHash",
"type_info": "Int8"
},
{
"ordinal": 2,
"name": "raw_flow: sqlx::types::Json<Box<RawValue>>",
"type_info": "Jsonb"
},
{
"ordinal": 3,
"name": "parent_job: Uuid",
"type_info": "Uuid"
},
{
"ordinal": 4,
"name": "created_at: chrono::NaiveDateTime",
"type_info": "Timestamptz"
},
{
"ordinal": 5,
"name": "created_by!",
"type_info": "Varchar"
},
{
"ordinal": 6,
"name": "script_path",
"type_info": "Varchar"
},
{
"ordinal": 7,
"name": "args: sqlx::types::Json<Box<RawValue>>",
"type_info": "Jsonb"
}
],
"parameters": {
"Left": [
"Uuid",
"Text"
]
},
"nullable": [
false,
true,
true,
true,
false,
false,
true,
true
]
},
"hash": "da9114fc6689ebc78422b3572de1ed44050bd28212540db50fe235463c15a900"
}

View File

@@ -1,25 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE nats_trigger SET last_server_ping = now(), error = $1 WHERE workspace_id = $2 AND path = $3 AND server_id = $4 AND enabled IS TRUE RETURNING 1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "?column?",
"type_info": "Int4"
}
],
"parameters": {
"Left": [
"Text",
"Text",
"Text",
"Text"
]
},
"nullable": [
null
]
},
"hash": "dcf03ff4b922b93be37d2be5da6884ae3e8c6cf7eaa2d9c62056366eb42f2276"
}

View File

@@ -1,15 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "DELETE FROM capture WHERE path = $1 AND workspace_id = $2 AND is_flow IS FALSE",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text"
]
},
"nullable": []
},
"hash": "de0735f0f5b59ebb72fd876f7f46156e26b352511f408fd6464303301383461f"
}

View File

@@ -1,24 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT EXISTS (\n SELECT 1 FROM completed_job \n WHERE workspace_id = $2 \n AND (job_kind = 'appscript' OR job_kind = 'preview')\n AND created_by = 'anonymous' \n AND started_at > now() - interval '3 hours'\n AND script_path LIKE $3 || '/%' \n AND result @> ('{\"s3\":\"' || $1 || '\"}')::jsonb \n )",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "exists",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text",
"Text",
"Text"
]
},
"nullable": [
null
]
},
"hash": "df0454f75e819d7d3d03fef0a7d5606940a089f6179e5443090afa9aba7c5b24"
}

View File

@@ -0,0 +1,16 @@
{
"db_name": "PostgreSQL",
"query": "\n DELETE FROM capture\n WHERE workspace_id = $1\n AND created_by = $2\n AND created_at <=\n ( SELECT created_at\n FROM capture\n WHERE workspace_id = $1\n AND created_by = $2\n ORDER BY created_at DESC\n OFFSET $3\n LIMIT 1 )\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text",
"Int8"
]
},
"nullable": []
},
"hash": "e02b99525cb1f8737acfec86809f59c8cff67bb1ec3926680fb691cc3573738a"
}

View File

@@ -1,51 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT trigger_config as \"trigger_config: _\", owner, email\n FROM capture_config\n WHERE workspace_id = $1 AND path = $2 AND is_flow = $3 AND trigger_kind = $4 AND last_client_ping > NOW() - INTERVAL '10 seconds'",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "trigger_config: _",
"type_info": "Jsonb"
},
{
"ordinal": 1,
"name": "owner",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "email",
"type_info": "Varchar"
}
],
"parameters": {
"Left": [
"Text",
"Text",
"Bool",
{
"Custom": {
"name": "trigger_kind",
"kind": {
"Enum": [
"webhook",
"http",
"websocket",
"kafka",
"email",
"nats"
]
}
}
}
]
},
"nullable": [
true,
false,
false
]
},
"hash": "e23e110e1f0438d21534fc4323e0e7bc1f0dbeca2e4f44ced05bae0ca5ca1039"
}

View File

@@ -1,26 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE capture_config SET last_server_ping = now(), error = $1 WHERE workspace_id = $2 AND path = $3 AND is_flow = $4 AND trigger_kind = 'nats' AND server_id = $5 AND last_client_ping > NOW() - INTERVAL '10 seconds' RETURNING 1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "?column?",
"type_info": "Int4"
}
],
"parameters": {
"Left": [
"Text",
"Text",
"Text",
"Bool",
"Text"
]
},
"nullable": [
null
]
},
"hash": "e37ba13aa3174931f0bfcff26dbc141fe8a346ab6a1a3bc924794bfe3c9af306"
}

View File

@@ -1,15 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO workspace_settings\n (workspace_id, color)\n VALUES ($1, $2)",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Varchar"
]
},
"nullable": []
},
"hash": "e54eb583f011cea6e4d533f4d2014cbf509b5afcc2647048c9bfc839d8f290ad"
}

View File

@@ -1,53 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT workspace.id, workspace.name, workspace.owner, workspace.deleted, workspace.premium, workspace_settings.color\n FROM workspace\n LEFT JOIN workspace_settings ON workspace.id = workspace_settings.workspace_id\n LIMIT $1 OFFSET $2",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "name",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "owner",
"type_info": "Varchar"
},
{
"ordinal": 3,
"name": "deleted",
"type_info": "Bool"
},
{
"ordinal": 4,
"name": "premium",
"type_info": "Bool"
},
{
"ordinal": 5,
"name": "color",
"type_info": "Varchar"
}
],
"parameters": {
"Left": [
"Int8",
"Int8"
]
},
"nullable": [
false,
false,
false,
false,
false,
true
]
},
"hash": "eed16e356f3f36183c3db13fcc1950295e0d0fbdabb38434534fb3430eeddc25"
}

View File

@@ -1,34 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO capture_config\n (workspace_id, path, is_flow, trigger_kind, trigger_config, owner, email)\n VALUES ($1, $2, $3, $4, $5, $6, $7)\n ON CONFLICT (workspace_id, path, is_flow, trigger_kind)\n DO UPDATE SET trigger_config = $5, owner = $6, email = $7, server_id = NULL, last_server_ping = NULL, error = NULL",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Varchar",
"Bool",
{
"Custom": {
"name": "trigger_kind",
"kind": {
"Enum": [
"webhook",
"http",
"websocket",
"kafka",
"email",
"nats"
]
}
}
},
"Jsonb",
"Varchar",
"Varchar"
]
},
"nullable": []
},
"hash": "ef299490c4674c4c76e18d84620a74407b78378d66d8a089407998074059e79b"
}

View File

@@ -1,25 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE capture_config SET server_id = $1, last_server_ping = now(), error = 'Connecting...' WHERE last_client_ping > NOW() - INTERVAL '10 seconds' AND workspace_id = $2 AND path = $3 AND is_flow = $4 AND trigger_kind = 'nats' AND (last_server_ping IS NULL OR last_server_ping < now() - interval '15 seconds') RETURNING true",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "?column?",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Varchar",
"Text",
"Text",
"Bool"
]
},
"nullable": [
null
]
},
"hash": "f16b00bad2880f896f4452e5894fe101cd5c2fe3e4c143c0b979668143d85dd2"
}

View File

@@ -1,28 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT usr.email, usage.executions\n FROM usr\n , LATERAL (\n SELECT COALESCE(SUM(duration_ms + 1000)/1000 , 0)::BIGINT executions\n FROM completed_job\n WHERE workspace_id = $1\n AND job_kind NOT IN ('flow', 'flowpreview', 'flownode')\n AND email = usr.email\n AND now() - '1 week'::interval < created_at \n ) usage\n WHERE workspace_id = $1\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "email",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "executions",
"type_info": "Int8"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false,
null
]
},
"hash": "f6a275ad8bc7dfec7f9a6b60c669f6f2ff93ce57b5afadabd618e1fb52951fef"
}

View File

@@ -1,17 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE capture_config SET error = $1, server_id = NULL, last_server_ping = NULL WHERE workspace_id = $2 AND path = $3 AND is_flow = $4 AND trigger_kind = 'nats'",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text",
"Text",
"Bool"
]
},
"nullable": []
},
"hash": "ffb6b2a40b605f9c55826a0e519af80b100d2ffa58ec567223e27099d364fcc8"
}

910
backend/Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
[package]
name = "windmill"
version = "1.445.0"
version = "1.440.1"
authors.workspace = true
edition.workspace = true
@@ -30,7 +30,7 @@ members = [
]
[workspace.package]
version = "1.445.0"
version = "1.440.1"
authors = ["Ruben Fiszel <ruben@windmill.dev>"]
edition = "2021"
@@ -48,8 +48,8 @@ lto = "thin"
[features]
default = []
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"]
enterprise_saml = ["windmill-api/enterprise_saml", "oauth2"]
stripe = ["windmill-api/stripe", "enterprise"]
enterprise_saml = ["windmill-api/enterprise_saml"]
stripe = ["windmill-api/stripe"]
benchmark = ["windmill-api/benchmark", "windmill-worker/benchmark", "windmill-queue/benchmark", "windmill-common/benchmark"]
loki = ["windmill-common/loki"]
embedding = ["windmill-api/embedding"]
@@ -59,11 +59,10 @@ flow_testing = ["windmill-worker/flow_testing"]
openidconnect = ["windmill-api/openidconnect"]
cloud = ["windmill-queue/cloud", "windmill-worker/cloud"]
jemalloc = ["windmill-common/jemalloc", "dep:tikv-jemallocator", "dep:tikv-jemalloc-sys", "dep:tikv-jemalloc-ctl"]
tantivy = ["dep:windmill-indexer", "windmill-api/tantivy", "windmill-indexer/enterprise", "windmill-indexer/parquet", "enterprise", "parquet"]
tantivy = ["dep:windmill-indexer", "windmill-api/tantivy", "windmill-indexer/enterprise", "windmill-indexer/parquet"]
sqlx = ["windmill-worker/sqlx"]
deno_core = ["windmill-worker/deno_core", "dep:deno_core"]
kafka = ["windmill-api/kafka"]
nats = ["windmill-api/nats"]
otel = ["windmill-common/otel", "windmill-worker/otel"]
dind = ["windmill-worker/dind"]
php = ["windmill-worker/php"]
@@ -80,7 +79,6 @@ oauth2 = ["windmill-api/oauth2"]
http_trigger = ["windmill-api/http_trigger"]
zip = ["windmill-api/zip"]
static_frontend = ["windmill-api/static_frontend"]
scoped_cache = ["windmill-common/scoped_cache"]
[dependencies]
@@ -261,7 +259,7 @@ getrandom = "0.2"
tokio-postgres = {version = "^0.7", features = ["array-impls", "with-serde_json-1", "with-chrono-0_4", "with-uuid-1", "with-bit-vec-0_6"]}
bit-vec = "=0.6.3"
mappable-rc = "^0"
mysql_async = { version = "*", default-features = false, features = ["minimal", "default", "native-tls-tls", "rust_decimal"]}
mysql_async = { version = "*", default-features = false, features = ["minimal", "default", "native-tls-tls"]}
postgres-native-tls = "^0"
native-tls = "^0"
# samael will break compilation on MacOS. Use this fork instead to make it work
@@ -286,8 +284,6 @@ openssl = "=0.10"
mail-parser = "^0"
matchit = "=0.7.3"
rdkafka = { version = "0.36.2", features = ["cmake-build", "ssl-vendored"] }
async-nats = "0.38.0"
nkeys = "0.4.4"
datafusion = "39.0.0"
object_store = { version = "0.10.0", features = ["aws", "azure"] }

View File

@@ -1 +1 @@
9cea7e44f1b6401662e22088b41e8a00d7e67b23
324617e19a5906fe57c911c8df4fb63786a1634a

View File

@@ -1,14 +0,0 @@
-- Add down migration script here
DROP TABLE capture_config;
DELETE FROM capture;
DROP POLICY see_from_allowed_runnables ON capture;
ALTER TABLE capture DROP CONSTRAINT capture_pkey;
ALTER TABLE capture DROP COLUMN is_flow, DROP COLUMN trigger_kind, DROP COLUMN trigger_extra, DROP COLUMN id;
ALTER TABLE capture ADD CONSTRAINT capture_pkey PRIMARY KEY (workspace_id, path);
DROP TYPE TRIGGER_KIND;
CREATE POLICY see_folder_extra_perms_user ON capture FOR ALL TO windmill_user
USING (SPLIT_PART(capture.path, '/', 1) = 'f' AND SPLIT_PART(capture.path, '/', 2) = any(regexp_split_to_array(current_setting('session.folders_read'), ',')::text[]))
WITH CHECK (SPLIT_PART(capture.path, '/', 1) = 'f' AND SPLIT_PART(capture.path, '/', 2) = any(regexp_split_to_array(current_setting('session.folders_write'), ',')::text[]));
CREATE POLICY see_member ON public.capture TO windmill_user USING (((split_part((path)::text, '/'::text, 1) = 'g'::text) AND (split_part((path)::text, '/'::text, 2) = ANY (regexp_split_to_array(current_setting('session.groups'::text), ','::text)))));
CREATE POLICY see_own ON public.capture TO windmill_user USING (((split_part((path)::text, '/'::text, 1) = 'u'::text) AND (split_part((path)::text, '/'::text, 2) = current_setting('session.user'::text))));

View File

@@ -1,65 +0,0 @@
-- Add up migration script here
CREATE TYPE TRIGGER_KIND AS ENUM ('webhook', 'http', 'websocket', 'kafka', 'email');
ALTER TABLE capture ADD COLUMN is_flow BOOLEAN NOT NULL DEFAULT TRUE, ADD COLUMN trigger_kind TRIGGER_KIND NOT NULL DEFAULT 'webhook', ADD COLUMN trigger_extra JSONB;
ALTER TABLE capture ALTER COLUMN is_flow DROP DEFAULT, ALTER COLUMN trigger_kind DROP DEFAULT;
ALTER TABLE capture DROP CONSTRAINT capture_pkey;
ALTER TABLE capture ADD COLUMN id BIGINT PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY;
DROP POLICY see_own ON capture;
DROP POLICY see_member ON capture;
DROP POLICY see_folder_extra_perms_user ON capture;
CREATE POLICY see_from_allowed_runnables ON capture FOR ALL TO windmill_user
USING (
(capture.is_flow AND EXISTS (
SELECT 1
FROM flow
WHERE flow.workspace_id = capture.workspace_id
AND flow.path = capture.path
))
OR (NOT capture.is_flow AND EXISTS (
SELECT 1
FROM script
WHERE script.workspace_id = capture.workspace_id
AND script.path = capture.path
))
);
CREATE TABLE capture_config (
workspace_id VARCHAR(50) NOT NULL,
path VARCHAR(255) NOT NULL,
is_flow BOOLEAN NOT NULL,
trigger_kind TRIGGER_KIND NOT NULL,
trigger_config JSONB NULL,
owner VARCHAR(50) NOT NULL,
email VARCHAR(255) NOT NULL,
server_id VARCHAR(50) NULL,
last_client_ping TIMESTAMPTZ NULL,
last_server_ping TIMESTAMPTZ NULL,
error TEXT NULL,
PRIMARY KEY (workspace_id, path, is_flow, trigger_kind),
FOREIGN KEY (workspace_id) REFERENCES workspace(id) ON DELETE CASCADE
);
ALTER TABLE capture_config ENABLE ROW LEVEL SECURITY;
CREATE POLICY see_from_allowed_runnables ON capture_config FOR ALL TO windmill_user
USING (
(capture_config.is_flow AND EXISTS (
SELECT 1
FROM flow
WHERE flow.workspace_id = capture_config.workspace_id
AND flow.path = capture_config.path
))
OR (NOT capture_config.is_flow AND EXISTS (
SELECT 1
FROM script
WHERE script.workspace_id = capture_config.workspace_id
AND script.path = capture_config.path
))
);
GRANT ALL ON capture_config TO windmill_user;
GRANT ALL ON capture_config TO windmill_admin;

View File

@@ -1 +0,0 @@
DROP TABLE nats_trigger;

View File

@@ -1,71 +0,0 @@
ALTER TYPE trigger_kind ADD VALUE IF NOT EXISTS 'nats';
CREATE TABLE nats_trigger (
path VARCHAR(255) NOT NULL,
nats_resource_path VARCHAR(255) NOT NULL,
subjects VARCHAR(255)[] NOT NULL,
stream_name VARCHAR(255) NULL,
consumer_name VARCHAR(255) NULL,
use_jetstream BOOLEAN NOT NULL,
script_path VARCHAR(255) NOT NULL,
is_flow BOOLEAN NOT NULL,
workspace_id VARCHAR(50) NOT NULL,
edited_by VARCHAR(50) NOT NULL,
email VARCHAR(255) NOT NULL,
edited_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
extra_perms JSONB NOT NULL DEFAULT '{}',
server_id VARCHAR(50) NULL,
last_server_ping TIMESTAMPTZ NULL,
error TEXT NULL,
enabled BOOLEAN NOT NULL,
PRIMARY KEY (path, workspace_id),
FOREIGN KEY (workspace_id) REFERENCES workspace(id) ON DELETE CASCADE
);
GRANT ALL ON nats_trigger TO windmill_user;
GRANT ALL ON nats_trigger TO windmill_admin;
ALTER TABLE nats_trigger ENABLE ROW LEVEL SECURITY;
CREATE POLICY admin_policy ON nats_trigger FOR ALL TO windmill_admin USING (true);
CREATE POLICY see_folder_extra_perms_user_select ON nats_trigger FOR SELECT TO windmill_user
USING (SPLIT_PART(nats_trigger.path, '/', 1) = 'f' AND SPLIT_PART(nats_trigger.path, '/', 2) = any(regexp_split_to_array(current_setting('session.folders_read'), ',')::text[]));
CREATE POLICY see_folder_extra_perms_user_insert ON nats_trigger FOR INSERT TO windmill_user
WITH CHECK (SPLIT_PART(nats_trigger.path, '/', 1) = 'f' AND SPLIT_PART(nats_trigger.path, '/', 2) = any(regexp_split_to_array(current_setting('session.folders_write'), ',')::text[]));
CREATE POLICY see_folder_extra_perms_user_update ON nats_trigger FOR UPDATE TO windmill_user
USING (SPLIT_PART(nats_trigger.path, '/', 1) = 'f' AND SPLIT_PART(nats_trigger.path, '/', 2) = any(regexp_split_to_array(current_setting('session.folders_write'), ',')::text[]));
CREATE POLICY see_folder_extra_perms_user_delete ON nats_trigger FOR DELETE TO windmill_user
USING (SPLIT_PART(nats_trigger.path, '/', 1) = 'f' AND SPLIT_PART(nats_trigger.path, '/', 2) = any(regexp_split_to_array(current_setting('session.folders_write'), ',')::text[]));
CREATE POLICY see_own ON nats_trigger FOR ALL TO windmill_user
USING (SPLIT_PART(nats_trigger.path, '/', 1) = 'u' AND SPLIT_PART(nats_trigger.path, '/', 2) = current_setting('session.user'));
CREATE POLICY see_member ON nats_trigger FOR ALL TO windmill_user
USING (SPLIT_PART(nats_trigger.path, '/', 1) = 'g' AND SPLIT_PART(nats_trigger.path, '/', 2) = any(regexp_split_to_array(current_setting('session.groups'), ',')::text[]));
CREATE POLICY see_extra_perms_user_select ON nats_trigger FOR SELECT TO windmill_user
USING (extra_perms ? CONCAT('u/', current_setting('session.user')));
CREATE POLICY see_extra_perms_user_insert ON nats_trigger FOR INSERT TO windmill_user
WITH CHECK ((extra_perms ->> CONCAT('u/', current_setting('session.user')))::boolean);
CREATE POLICY see_extra_perms_user_update ON nats_trigger FOR UPDATE TO windmill_user
USING ((extra_perms ->> CONCAT('u/', current_setting('session.user')))::boolean);
CREATE POLICY see_extra_perms_user_delete ON nats_trigger FOR DELETE TO windmill_user
USING ((extra_perms ->> CONCAT('u/', current_setting('session.user')))::boolean);
CREATE POLICY see_extra_perms_groups_select ON nats_trigger FOR SELECT TO windmill_user
USING (extra_perms ?| regexp_split_to_array(current_setting('session.pgroups'), ',')::text[]);
CREATE POLICY see_extra_perms_groups_insert ON nats_trigger FOR INSERT TO windmill_user
WITH CHECK (exists(
SELECT key, value FROM jsonb_each_text(extra_perms)
WHERE SPLIT_PART(key, '/', 1) = 'g' AND key = ANY(regexp_split_to_array(current_setting('session.pgroups'), ',')::text[])
AND value::boolean));
CREATE POLICY see_extra_perms_groups_update ON nats_trigger FOR UPDATE TO windmill_user
USING (exists(
SELECT key, value FROM jsonb_each_text(extra_perms)
WHERE SPLIT_PART(key, '/', 1) = 'g' AND key = ANY(regexp_split_to_array(current_setting('session.pgroups'), ',')::text[])
AND value::boolean));
CREATE POLICY see_extra_perms_groups_delete ON nats_trigger FOR DELETE TO windmill_user
USING (exists(
SELECT key, value FROM jsonb_each_text(extra_perms)
WHERE SPLIT_PART(key, '/', 1) = 'g' AND key = ANY(regexp_split_to_array(current_setting('session.pgroups'), ',')::text[])
AND value::boolean));

View File

@@ -1 +0,0 @@
ALTER TABLE workspace_settings DROP COLUMN color;

View File

@@ -1 +0,0 @@
ALTER TABLE workspace_settings ADD COLUMN color VARCHAR(7) DEFAULT NULL;

View File

@@ -344,7 +344,6 @@ pub async fn load_metrics_debug_enabled(db: &DB) -> error::Result<()> {
#[cfg(all(not(target_env = "msvc"), feature = "jemalloc"))]
#[derive(Debug, Clone)]
pub struct MallctlError {
#[allow(unused)]
pub code: i32,
}
@@ -1497,7 +1496,7 @@ async fn handle_zombie_jobs(db: &Pool<Postgres>, base_internal_url: &str, worker
let restarted = sqlx::query!(
"UPDATE queue SET running = false, started_at = null
WHERE last_ping < now() - ($1 || ' seconds')::interval
AND running = true AND job_kind NOT IN ('flow', 'flowpreview', 'flownode', 'singlescriptflow') AND same_worker = false RETURNING id, workspace_id, last_ping",
AND running = true AND job_kind NOT IN ('flow', 'flowpreview', 'singlescriptflow') AND same_worker = false RETURNING id, workspace_id, last_ping",
*ZOMBIE_JOB_TIMEOUT,
)
.fetch_all(db)
@@ -1534,7 +1533,7 @@ async fn handle_zombie_jobs(db: &Pool<Postgres>, base_internal_url: &str, worker
let mut timeout_query =
"SELECT * FROM queue WHERE last_ping < now() - ($1 || ' seconds')::interval
AND running = true AND job_kind NOT IN ('flow', 'flowpreview', 'flownode', 'singlescriptflow')"
AND running = true AND job_kind NOT IN ('flow', 'flowpreview', 'singlescriptflow')"
.to_string();
if *RESTART_ZOMBIE_JOBS {
timeout_query.push_str(" AND same_worker = true");
@@ -1618,7 +1617,7 @@ async fn handle_zombie_flows(db: &DB) -> error::Result<()> {
r#"
SELECT *
FROM queue
WHERE running = true AND suspend = 0 AND suspend_until IS null AND scheduled_for <= now() AND (job_kind = 'flow' OR job_kind = 'flowpreview' OR job_kind = 'flownode')
WHERE running = true AND suspend = 0 AND suspend_until IS null AND scheduled_for <= now() AND (job_kind = 'flow' OR job_kind = 'flowpreview')
AND last_ping IS NOT NULL AND last_ping < NOW() - ($1 || ' seconds')::interval AND canceled = false
"#,
).bind(FLOW_ZOMBIE_TRANSITION_TIMEOUT.as_str())

View File

@@ -145,10 +145,7 @@ impl ApiServer {
_port_rx.await.unwrap();
// clear the cache between tests
windmill_common::cache::clear();
Self { addr, tx, task }
return Self { addr, tx, task };
}
async fn close(self) -> anyhow::Result<()> {
@@ -3817,7 +3814,7 @@ mod job_payload {
let flow_data = cache::flow::fetch_version_lite(&db, 1443253234253454)
.await
.unwrap();
let flow_value = flow_data.value();
let flow_value = flow_data.value().unwrap();
let flow_scripts = {
async fn load(db: &Pool<Postgres>, modules: &[FlowModule]) -> Vec<FlowNodeId> {
let mut res = vec![];
@@ -3828,7 +3825,9 @@ mod job_payload {
FlowModuleValue::FlowScript { id, .. } => res.push(id),
FlowModuleValue::ForloopFlow { modules_node: Some(flow_node), .. } => {
let flow_data = cache::flow::fetch_flow(db, flow_node).await.unwrap();
res.extend(Box::pin(load(db, &flow_data.value().modules)).await);
res.extend(
Box::pin(load(db, &flow_data.value().unwrap().modules)).await,
);
}
_ => {}
}
@@ -3905,7 +3904,7 @@ mod job_payload {
let flow_data = cache::flow::fetch_version_lite(&db, 1443253234253454)
.await
.unwrap();
let flow_value = flow_data.value();
let flow_value = flow_data.value().unwrap();
let forloop_module =
serde_json::from_str::<FlowModuleValue>(flow_value.modules[0].value.get()).unwrap();
let FlowModuleValue::ForloopFlow { modules_node: Some(id), .. } = forloop_module else {

View File

@@ -20,14 +20,13 @@ prometheus = ["windmill-common/prometheus", "windmill-queue/prometheus", "dep:pr
openidconnect = ["dep:openidconnect"]
tantivy = ["dep:windmill-indexer"]
kafka = ["dep:rdkafka"]
nats = ["dep:async-nats", "dep:nkeys"]
websocket = ["dep:tokio-tungstenite"]
smtp = ["dep:mail-parser", "dep:openssl", "windmill-common/smtp"]
license = ["dep:rsa"]
zip = ["dep:async_zip"]
oauth2 = ["dep:async-oauth2"]
http_trigger = ["dep:matchit"]
static_frontend = ["dep:rust-embed"]
static_frontend = ["dep:rust-embed", "dep:mime_guess"]
[dependencies]
windmill-queue.workspace = true
@@ -62,7 +61,7 @@ base64.workspace = true
base32.workspace = true
serde_urlencoded.workspace = true
cron.workspace = true
mime_guess.workspace = true
mime_guess = { workspace = true, optional = true }
rust-embed = { workspace = true, optional = true }
tracing-subscriber.workspace = true
quick_cache.workspace = true
@@ -104,8 +103,6 @@ jsonwebtoken = { workspace = true }
matchit = { workspace = true, optional = true }
tokio-tungstenite = { workspace = true, optional = true}
rdkafka = { workspace = true, optional = true }
async-nats = { workspace = true, optional = true }
nkeys = { workspace = true, optional = true }
const_format.workspace = true
pin-project.workspace = true

View File

@@ -1,7 +1,7 @@
openapi: "3.0.3"
info:
version: 1.445.0
version: 1.440.1
title: Windmill API
contact:
@@ -1576,30 +1576,6 @@ paths:
schema:
type: string
/w/{workspace}/workspaces/change_workspace_color:
post:
summary: change workspace id
operationId: changeWorkspaceColor
tags:
- workspace
parameters:
- $ref: "#/components/parameters/WorkspaceId"
requestBody:
content:
application/json:
schema:
type: object
properties:
color:
type: string
responses:
"200":
description: status
content:
text/plain:
schema:
type: string
/w/{workspace}/users/whois/{username}:
get:
summary: whois
@@ -1746,8 +1722,6 @@ paths:
$ref: "#/components/schemas/WorkspaceDefaultScripts"
mute_critical_alerts:
type: boolean
color:
type: string
required:
- code_completion_enabled
- automatic_billing
@@ -2379,13 +2353,10 @@ paths:
type: boolean
kafka_used:
type: boolean
nats_used:
type: boolean
required:
- http_routes_used
- websocket_used
- kafka_used
- nats_used
/w/{workspace}/users/list:
get:
@@ -6972,52 +6943,6 @@ paths:
- resume
- cancel
/w/{workspace}/jobs/slack_approval/{id}:
get:
summary: generate interactive slack approval for suspended job
operationId: getSlackApprovalPayload
tags:
- job
parameters:
- $ref: "#/components/parameters/WorkspaceId"
- $ref: "#/components/parameters/JobId"
- name: approver
in: query
schema:
type: string
- name: message
in: query
schema:
type: string
- name: slack_resource_path
in: query
required: true
schema:
type: string
- name: channel_id
in: query
required: true
schema:
type: string
- name: flow_step_id
in: query
required: true
schema:
type: string
- name: default_args_json
in: query
required: false
schema:
type: string
- name: dynamic_enums_json
in: query
required: false
schema:
type: string
responses:
"200":
description: Interactive slack approval message sent successfully
/w/{workspace}/jobs_u/resume/{id}/{resume_id}/{signature}:
get:
summary: resume a job for a suspended flow
@@ -8021,169 +7946,6 @@ paths:
schema:
type: string
/w/{workspace}/nats_triggers/create:
post:
summary: create nats trigger
operationId: createNatsTrigger
tags:
- nats_trigger
parameters:
- $ref: "#/components/parameters/WorkspaceId"
requestBody:
description: new nats trigger
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/NewNatsTrigger"
responses:
"201":
description: nats trigger created
content:
text/plain:
schema:
type: string
/w/{workspace}/nats_triggers/update/{path}:
post:
summary: update nats trigger
operationId: updateNatsTrigger
tags:
- nats_trigger
parameters:
- $ref: "#/components/parameters/WorkspaceId"
- $ref: "#/components/parameters/Path"
requestBody:
description: updated trigger
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/EditNatsTrigger"
responses:
"200":
description: nats trigger updated
content:
text/plain:
schema:
type: string
/w/{workspace}/nats_triggers/delete/{path}:
delete:
summary: delete nats trigger
operationId: deleteNatsTrigger
tags:
- nats_trigger
parameters:
- $ref: "#/components/parameters/WorkspaceId"
- $ref: "#/components/parameters/Path"
responses:
"200":
description: nats trigger deleted
content:
text/plain:
schema:
type: string
/w/{workspace}/nats_triggers/get/{path}:
get:
summary: get nats trigger
operationId: getNatsTrigger
tags:
- nats_trigger
parameters:
- $ref: "#/components/parameters/WorkspaceId"
- $ref: "#/components/parameters/Path"
responses:
"200":
description: nats trigger deleted
content:
application/json:
schema:
$ref: "#/components/schemas/NatsTrigger"
/w/{workspace}/nats_triggers/list:
get:
summary: list nats triggers
operationId: listNatsTriggers
tags:
- nats_trigger
parameters:
- $ref: "#/components/parameters/WorkspaceId"
required: true
- $ref: "#/components/parameters/Page"
- $ref: "#/components/parameters/PerPage"
- name: path
description: filter by path
in: query
schema:
type: string
- name: is_flow
in: query
schema:
type: boolean
- name: path_start
in: query
schema:
type: string
responses:
"200":
description: nats trigger list
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/NatsTrigger"
/w/{workspace}/nats_triggers/exists/{path}:
get:
summary: does nats trigger exists
operationId: existsNatsTrigger
tags:
- nats_trigger
parameters:
- $ref: "#/components/parameters/WorkspaceId"
- $ref: "#/components/parameters/Path"
responses:
"200":
description: nats trigger exists
content:
application/json:
schema:
type: boolean
/w/{workspace}/nats_triggers/setenabled/{path}:
post:
summary: set enabled nats trigger
operationId: setNatsTriggerEnabled
tags:
- nats_trigger
parameters:
- $ref: "#/components/parameters/WorkspaceId"
- $ref: "#/components/parameters/Path"
requestBody:
description: updated nats trigger enable
required: true
content:
application/json:
schema:
type: object
properties:
enabled:
type: boolean
required:
- enabled
responses:
"200":
description: nats trigger enabled set
content:
text/plain:
schema:
type: string
/groups/list:
get:
@@ -9054,7 +8816,6 @@ paths:
http_trigger,
websocket_trigger,
kafka_trigger,
nats_trigger,
]
responses:
"200":
@@ -9094,7 +8855,6 @@ paths:
http_trigger,
websocket_trigger,
kafka_trigger,
nats_trigger,
]
requestBody:
description: acl to add
@@ -9145,7 +8905,6 @@ paths:
http_trigger,
websocket_trigger,
kafka_trigger,
nats_trigger,
]
requestBody:
description: acl to add
@@ -9166,119 +8925,47 @@ paths:
schema:
type: string
/w/{workspace}/capture/set_config:
/w/{workspace}/capture_u/{path}:
post:
summary: set capture config
operationId: setCaptureConfig
summary: update flow preview capture
operationId: updateCapture
tags:
- capture
parameters:
- $ref: "#/components/parameters/WorkspaceId"
requestBody:
description: capture config
required: true
content:
application/json:
schema:
type: object
properties:
trigger_kind:
$ref: "#/components/schemas/CaptureTriggerKind"
path:
type: string
is_flow:
type: boolean
trigger_config:
type: object
required:
- trigger_kind
- path
- is_flow
responses:
"200":
description: capture config set
/w/{workspace}/capture/ping_config/{trigger_kind}/{runnable_kind}/{path}:
post:
summary: ping capture config
operationId: pingCaptureConfig
tags:
- capture
parameters:
- $ref: "#/components/parameters/WorkspaceId"
- name: trigger_kind
in: path
required: true
schema:
$ref: "#/components/schemas/CaptureTriggerKind"
- $ref: "#/components/parameters/RunnableKind"
- $ref: "#/components/parameters/Path"
responses:
"200":
description: capture config pinged
"204":
description: flow preview captured
/w/{workspace}/capture/get_configs/{runnable_kind}/{path}:
/w/{workspace}/capture/{path}:
put:
summary: create flow preview capture
operationId: createCapture
tags:
- capture
parameters:
- $ref: "#/components/parameters/WorkspaceId"
- $ref: "#/components/parameters/Path"
responses:
"201":
description: flow preview capture created
get:
summary: get capture configs for a script or flow
operationId: getCaptureConfigs
summary: get flow preview capture
operationId: getCapture
tags:
- capture
parameters:
- $ref: "#/components/parameters/WorkspaceId"
- $ref: "#/components/parameters/RunnableKind"
- $ref: "#/components/parameters/Path"
responses:
"200":
description: capture configs for a script or flow
description: captured flow preview
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/CaptureConfig"
/w/{workspace}/capture/list/{runnable_kind}/{path}:
get:
summary: list captures for a script or flow
operationId: listCaptures
tags:
- capture
parameters:
- $ref: "#/components/parameters/WorkspaceId"
- $ref: "#/components/parameters/RunnableKind"
- $ref: "#/components/parameters/Path"
- name: trigger_kind
in: query
schema:
$ref: "#/components/schemas/CaptureTriggerKind"
responses:
"200":
description: list of captures for a script or flow
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Capture"
/w/{workspace}/capture/{id}:
delete:
summary: delete a capture
operationId: deleteCapture
tags:
- capture
parameters:
- $ref: "#/components/parameters/WorkspaceId"
- name: id
in: path
required: true
schema:
type: integer
responses:
"200":
description: capture deleted
schema: {}
"404":
description: capture does not exist for this flow
/w/{workspace}/favorites/star:
post:
@@ -10935,13 +10622,6 @@ components:
required: true
schema:
type: string
RunnableKind:
name: runnable_kind
in: path
required: true
schema:
type: string
enum: [script, flow]
schemas:
$ref: "../../openflow.openapi.yaml#/components/schemas"
@@ -12561,8 +12241,6 @@ components:
type: number
kafka_count:
type: number
nats_count:
type: number
WebsocketTrigger:
type: object
@@ -12627,6 +12305,8 @@ components:
- workspace_id
- enabled
- filters
- initial_messages
- url_runnable_args
NewWebsocketTrigger:
type: object
@@ -12665,6 +12345,8 @@ components:
- url
- is_flow
- filters
- initial_messages
- url_runnable_args
EditWebsocketTrigger:
type: object
@@ -12701,6 +12383,8 @@ components:
- url
- is_flow
- filters
- initial_messages
- url_runnable_args
WebsocketTriggerInitialMessage:
anyOf:
@@ -12836,126 +12520,6 @@ components:
- topics
- is_flow
NatsTrigger:
type: object
properties:
path:
type: string
edited_by:
type: string
edited_at:
type: string
format: date-time
script_path:
type: string
nats_resource_path:
type: string
use_jetstream:
type: boolean
stream_name:
type: string
consumer_name:
type: string
subjects:
type: array
items:
type: string
is_flow:
type: boolean
extra_perms:
type: object
additionalProperties:
type: boolean
email:
type: string
workspace_id:
type: string
server_id:
type: string
last_server_ping:
type: string
format: date-time
error:
type: string
enabled:
type: boolean
required:
- path
- edited_by
- edited_at
- script_path
- nats_resource_path
- use_jetstream
- subjects
- extra_perms
- is_flow
- email
- workspace_id
- enabled
NewNatsTrigger:
type: object
properties:
path:
type: string
script_path:
type: string
is_flow:
type: boolean
nats_resource_path:
type: string
use_jetstream:
type: boolean
stream_name:
type: string
consumer_name:
type: string
subjects:
type: array
items:
type: string
enabled:
type: boolean
required:
- path
- script_path
- is_flow
- nats_resource_path
- use_jetstream
- subjects
EditNatsTrigger:
type: object
properties:
nats_resource_path:
type: string
use_jetstream:
type: boolean
stream_name:
type: string
consumer_name:
type: string
subjects:
type: array
items:
type: string
path:
type: string
script_path:
type: string
is_flow:
type: boolean
required:
- path
- script_path
- nats_resource_path
- use_jetstream
- subjects
- is_flow
Group:
type: object
properties:
@@ -13082,13 +12646,10 @@ components:
type: string
username:
type: string
color:
type: string
required:
- id
- name
- username
- color
required:
- email
- workspaces
@@ -13102,8 +12663,6 @@ components:
type: string
username:
type: string
color:
type: string
required:
- id
- name
@@ -13119,8 +12678,6 @@ components:
type: string
domain:
type: string
color:
type: string
required:
- id
- name
@@ -13922,38 +13479,3 @@ components:
type: string
nullable: true
description: Workspace id if the alert is in the scope of a workspace
CaptureTriggerKind:
type: string
enum: [webhook, http, websocket, kafka, email, nats]
Capture:
type: object
properties:
trigger_kind:
$ref: "#/components/schemas/CaptureTriggerKind"
payload: {}
trigger_extra: {}
id:
type: integer
created_at:
type: string
format: date-time
required:
- trigger_kind
- payload
- id
- created_at
CaptureConfig:
type: object
properties:
trigger_config: {}
trigger_kind:
$ref: "#/components/schemas/CaptureTriggerKind"
error:
type: string
last_server_ping:
type: string
format: date-time
required:
- trigger_kind

View File

@@ -20,14 +20,11 @@ use crate::{
#[cfg(feature = "parquet")]
use crate::{
job_helpers_ee::{
download_s3_file_internal, get_random_file_name, get_s3_resource,
get_workspace_s3_resource, load_image_preview_internal, upload_file_from_req,
DownloadFileQuery, LoadImagePreviewQuery, UploadFileResponse,
get_random_file_name, get_s3_resource, get_workspace_s3_resource, upload_file_from_req,
UploadFileResponse,
},
users::fetch_api_authed_from_permissioned_as,
};
#[cfg(feature = "parquet")]
use axum::response::Response;
use axum::{
extract::{Extension, Json, Path, Query},
response::IntoResponse,
@@ -38,7 +35,6 @@ use futures::future::{FutureExt, TryFutureExt};
use hyper::StatusCode;
#[cfg(feature = "parquet")]
use itertools::Itertools;
use lazy_static::lazy_static;
use magic_crypt::MagicCryptTrait;
#[cfg(feature = "parquet")]
use object_store::{Attribute, Attributes};
@@ -96,11 +92,6 @@ pub fn unauthed_service() -> Router {
Router::new()
.route("/execute_component/*path", post(execute_component))
.route("/upload_s3_file/*path", post(upload_s3_file_from_app))
.route("/download_s3_file/*path", get(download_s3_file_from_app))
.route(
"/load_image_preview/*path",
get(load_s3_file_image_preview_from_app),
)
.route("/public_app/:secret", get(get_public_app_by_secret))
.route("/public_resource/*path", get(get_public_resource))
}
@@ -199,7 +190,7 @@ pub type StaticFields = HashMap<String, Box<RawValue>>;
pub type OneOfFields = HashMap<String, Vec<Box<RawValue>>>;
pub type AllowUserResources = Vec<String>;
#[derive(Serialize, Deserialize, Debug, PartialEq, Copy, Clone, Default)]
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Default)]
#[serde(rename_all = "lowercase")]
pub enum ExecutionMode {
#[default]
@@ -1331,7 +1322,10 @@ async fn execute_component(
// 2. Otherwise, always fetch the policy from the database.
let policy = if let Some(id) = payload.version {
let cache = cache::anon!({ u64 => Arc<Policy> } in "policy" <= 1000);
arc_policy = policy_fut.map_ok(Arc::new).cached(cache, id as u64).await?;
arc_policy = policy_fut
.map_ok(sqlx::types::Json) // cache as json.
.cached(cache, id as u64, |sqlx::types::Json(x)| Arc::new(x))
.await?;
&*arc_policy
} else {
policy = policy_fut.await?;
@@ -1358,8 +1352,8 @@ async fn execute_component(
)
.fetch_one(&db)
.map_err(Into::<Error>::into)
.map_ok(Arc::new)
.cached(cache, *id as u64)
.map_ok(sqlx::types::Json) // cache as json.
.cached(cache, *id as u64, |sqlx::types::Json(x)| Arc::new(x))
.await?
}
_ => unreachable!(),
@@ -1383,45 +1377,6 @@ async fn execute_component(
}
};
// Execution is publisher and an user is authenticated: check if the user is authorized to
// execute the app.
if let (ExecutionMode::Publisher, Some(authed)) = (policy.execution_mode, opt_authed.as_ref()) {
lazy_static! {
/// Cache for the permit to execute an app component.
static ref PERMIT_CACHE: cache::Cache<[u8; 32], bool> = cache::Cache::new(1000);
}
// Avoid allocation for the permit key using a sha256 hash of:
// - the user email,
// - the application path,
// - the workspace id.
let permit_key: [u8; 32] = [authed.email.as_bytes(), path.as_bytes(), &w_id.as_bytes()]
.iter()
.fold(Sha256::new(), |hasher, bytes| hasher.chain_update(bytes))
.finalize()
.into();
let permit_fut = PERMIT_CACHE.get_or_insert_async(&permit_key, async {
let mut tx = user_db.clone().begin(authed).await?;
// Permissions are checked by the database; just fetch a row from app using `user_db`:
let row = sqlx::query_scalar!(
"SELECT 1 FROM app WHERE path = $1 AND workspace_id = $2 LIMIT 1",
path,
&w_id,
)
.fetch_optional(&mut *tx)
.await?;
tx.commit().await?;
Result::Ok(row.is_some_and(|x| x.is_some()))
});
if !permit_fut.await? {
return Err(Error::NotAuthorized(format!(
"Missing read permissions on the `{}` app to execute `{}` runnable",
path, payload.component
)));
}
}
let (username, permissioned_as, email) =
get_on_behalf_details_from_policy_and_authed(&policy, &opt_authed).await?;
@@ -1448,7 +1403,7 @@ async fn execute_component(
),
_ => unreachable!(),
};
let tx = PushIsolationLevel::IsolatedRoot(db.clone());
let tx = windmill_queue::PushIsolationLevel::IsolatedRoot(db.clone());
let (uuid, tx) = push(
&db,
@@ -1726,128 +1681,6 @@ async fn upload_s3_file_from_app(
return Ok(Json(UploadFileResponse { file_key }));
}
#[cfg(not(feature = "parquet"))]
async fn download_s3_file_from_app() -> Result<()> {
return Err(Error::BadRequest(
"This endpoint requires the parquet feature to be enabled".to_string(),
));
}
#[cfg(feature = "parquet")]
async fn get_on_behalf_authed_from_app(
db: &DB,
path: &str,
w_id: &str,
opt_authed: &Option<ApiAuthed>,
) -> Result<ApiAuthed> {
let policy_o = sqlx::query_scalar!(
"SELECT policy from app WHERE path = $1 AND workspace_id = $2",
path,
w_id
)
.fetch_optional(db)
.await?;
let policy = policy_o
.map(|p| serde_json::from_value::<Policy>(p).map_err(to_anyhow))
.transpose()?
.unwrap_or_else(|| Policy {
execution_mode: ExecutionMode::Viewer,
triggerables: None,
triggerables_v2: None,
on_behalf_of: None,
on_behalf_of_email: None,
s3_inputs: None,
});
let (username, permissioned_as, email) =
get_on_behalf_details_from_policy_and_authed(&policy, &opt_authed).await?;
let on_behalf_authed =
fetch_api_authed_from_permissioned_as(permissioned_as, email, &w_id, &db, Some(username))
.await?;
Ok(on_behalf_authed)
}
#[cfg(feature = "parquet")]
async fn check_if_allowed_to_access_s3_file_from_app(
db: &DB,
opt_authed: &Option<ApiAuthed>,
file_key: &str,
w_id: &str,
path: &str,
) -> Result<()> {
// if anonymous, check that the file was the result of an app script ran by an anonymous user in the last 3 hours
// otherwise, if logged in, allow any file (TODO: change that when we implement better s3 policy)
let allowed = opt_authed.is_some()
|| sqlx::query_scalar!(
r#"SELECT EXISTS (
SELECT 1 FROM completed_job
WHERE workspace_id = $2
AND (job_kind = 'appscript' OR job_kind = 'preview')
AND created_by = 'anonymous'
AND started_at > now() - interval '3 hours'
AND script_path LIKE $3 || '/%'
AND result @> ('{"s3":"' || $1 || '"}')::jsonb
)"#,
file_key,
w_id,
path,
)
.fetch_one(db)
.await?
.unwrap_or(false);
if !allowed {
Err(Error::BadRequest("File restricted".to_string()))
} else {
Ok(())
}
}
#[cfg(feature = "parquet")]
async fn download_s3_file_from_app(
OptAuthed(opt_authed): OptAuthed,
Extension(db): Extension<DB>,
Path((w_id, path)): Path<(String, StripPath)>,
Query(query): Query<DownloadFileQuery>,
) -> Result<Response> {
let path = path.to_path();
let on_behalf_authed = get_on_behalf_authed_from_app(&db, &path, &w_id, &opt_authed).await?;
check_if_allowed_to_access_s3_file_from_app(&db, &opt_authed, &query.file_key, &w_id, &path)
.await?;
download_s3_file_internal(on_behalf_authed, &db, None, "", &w_id, query).await
}
#[cfg(not(feature = "parquet"))]
async fn load_s3_file_image_preview_from_app() -> Result<()> {
return Err(Error::BadRequest(
"This endpoint requires the parquet feature to be enabled".to_string(),
));
}
#[cfg(feature = "parquet")]
async fn load_s3_file_image_preview_from_app(
OptAuthed(opt_authed): OptAuthed,
Extension(db): Extension<DB>,
Path((w_id, path)): Path<(String, StripPath)>,
Query(query): Query<LoadImagePreviewQuery>,
) -> Result<Response> {
let path = path.to_path();
let on_behalf_authed = get_on_behalf_authed_from_app(&db, &path, &w_id, &opt_authed).await?;
check_if_allowed_to_access_s3_file_from_app(&db, &opt_authed, &query.file_key, &w_id, &path)
.await?;
load_image_preview_internal(on_behalf_authed, &db, "", &w_id, query).await
}
fn get_on_behalf_of(policy: &Policy) -> Result<(String, String)> {
let permissioned_as = policy
.on_behalf_of

View File

@@ -65,7 +65,6 @@ impl WebhookArgs {
let s3_client = build_object_store_client(&s3_resource).await?;
let mut body = HashMap::new();
let mut files = HashMap::new();
while let Some(field) = multipart.next_field().await.map_err(|e| {
Error::BadRequest(format!(
@@ -108,9 +107,12 @@ impl WebhookArgs {
)
.await?;
files.entry(name).or_insert(vec![]).push(serde_json::json!({
"s3": &file_key
}));
body.insert(
name,
to_raw_value(&serde_json::json!({
"s3": &file_key
})),
);
} else {
body.insert(
name,
@@ -120,10 +122,6 @@ impl WebhookArgs {
}
}
for (k, v) in files {
body.insert(k, to_raw_value(&v));
}
if self.wrap_body.unwrap_or(false) {
self.args
.args

View File

@@ -7,564 +7,138 @@
*/
use axum::{
extract::{Extension, Path, Query},
routing::{delete, get, head, post},
Json, Router,
extract::{Extension, Path},
routing::{get, post, put},
Router,
};
#[cfg(feature = "http_trigger")]
use http::HeaderMap;
use hyper::StatusCode;
#[cfg(feature = "http_trigger")]
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
use serde_json::value::RawValue;
use sqlx::types::Json as SqlxJson;
#[cfg(feature = "http_trigger")]
use std::collections::HashMap;
use std::fmt;
#[cfg(feature = "http_trigger")]
use windmill_common::error::Error;
use sqlx::types::Json;
use windmill_common::{
db::UserDB,
error::{JsonResult, Result},
utils::{not_found_if_none, StripPath},
worker::{to_raw_value, CLOUD_HOSTED},
};
use windmill_queue::{PushArgs, PushArgsOwned};
use windmill_queue::PushArgs;
#[cfg(feature = "http_trigger")]
use crate::http_triggers::{build_http_trigger_extra, HttpMethod};
#[cfg(all(feature = "enterprise", feature = "kafka"))]
use crate::kafka_triggers_ee::KafkaResourceSecurity;
#[cfg(all(feature = "enterprise", feature = "nats"))]
use crate::nats_triggers_ee::NatsResourceAuth;
use crate::{
args::WebhookArgs,
db::{ApiAuthed, DB},
users::fetch_api_authed,
};
const KEEP_LAST: i64 = 20;
const KEEP_LAST: i64 = 8;
pub fn workspaced_service() -> Router {
Router::new()
.route("/set_config", post(set_config))
.route(
"/ping_config/:trigger_kind/:runnable_kind/*path",
post(ping_config),
)
.route("/get_configs/:runnable_kind/*path", get(get_configs))
.route("/list/:runnable_kind/*path", get(list_captures))
.route("/:id", delete(delete_capture))
.route("/*path", put(new_payload))
.route("/*path", get(get_payload))
}
pub fn workspaced_unauthed_service() -> Router {
let router = Router::new().route(
"/webhook/:runnable_kind/*path",
head(|| async {}).post(webhook_payload),
);
#[cfg(feature = "http_trigger")]
{
router.route("/http/:runnable_kind/:path/*route_path", {
head(|| async {}).fallback(http_payload)
})
}
#[cfg(not(feature = "http_trigger"))]
{
router
}
pub fn global_service() -> Router {
Router::new().route("/*path", post(update_payload))
}
#[derive(sqlx::Type, Serialize, Deserialize)]
#[sqlx(type_name = "TRIGGER_KIND", rename_all = "lowercase")]
#[serde(rename_all = "lowercase")]
pub enum TriggerKind {
Webhook,
Http,
Websocket,
Kafka,
Email,
Nats,
}
impl fmt::Display for TriggerKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s = match self {
TriggerKind::Webhook => "webhook",
TriggerKind::Http => "http",
TriggerKind::Websocket => "websocket",
TriggerKind::Kafka => "kafka",
TriggerKind::Email => "email",
TriggerKind::Nats => "nats",
};
write!(f, "{}", s)
}
}
#[cfg(feature = "http_trigger")]
#[derive(Serialize, Deserialize)]
struct HttpTriggerConfig {
route_path: String,
http_method: HttpMethod,
}
#[cfg(all(feature = "enterprise", feature = "kafka"))]
#[derive(Serialize, Deserialize)]
#[serde(untagged)]
pub enum KafkaTriggerConfigConnection {
Resource { kafka_resource_path: String },
Static { brokers: Vec<String>, security: KafkaResourceSecurity },
}
#[cfg(all(feature = "enterprise", feature = "kafka"))]
#[derive(Serialize, Deserialize)]
pub struct KafkaTriggerConfig {
#[serde(flatten)]
pub connection: KafkaTriggerConfigConnection,
pub topics: Vec<String>,
pub group_id: String,
}
#[cfg(all(feature = "enterprise", feature = "nats"))]
#[derive(Serialize, Deserialize)]
#[serde(untagged)]
pub enum NatsTriggerConfigConnection {
Resource { nats_resource_path: String },
Static { servers: Vec<String>, auth: NatsResourceAuth, require_tls: bool },
}
#[cfg(all(feature = "enterprise", feature = "nats"))]
#[derive(Serialize, Deserialize)]
pub struct NatsTriggerConfig {
#[serde(flatten)]
pub connection: NatsTriggerConfigConnection,
pub subjects: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub stream_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub consumer_name: Option<String>,
pub use_jetstream: bool,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct WebsocketTriggerConfig {
pub url: String,
// have to use Value because RawValue is not supported inside untagged
pub url_runnable_args: Option<serde_json::Value>,
}
#[derive(Serialize, Deserialize)]
#[serde(untagged)]
enum TriggerConfig {
#[cfg(feature = "http_trigger")]
Http(HttpTriggerConfig),
Websocket(WebsocketTriggerConfig),
#[cfg(all(feature = "enterprise", feature = "kafka"))]
Kafka(KafkaTriggerConfig),
#[cfg(all(feature = "enterprise", feature = "nats"))]
Nats(NatsTriggerConfig),
}
#[derive(Serialize, Deserialize)]
struct NewCaptureConfig {
trigger_kind: TriggerKind,
path: String,
is_flow: bool,
trigger_config: Option<TriggerConfig>,
}
#[derive(Serialize, Deserialize)]
struct CaptureConfig {
trigger_config: Option<SqlxJson<Box<RawValue>>>,
trigger_kind: TriggerKind,
error: Option<String>,
last_server_ping: Option<chrono::DateTime<chrono::Utc>>,
}
async fn get_configs(
pub async fn new_payload(
authed: ApiAuthed,
Extension(user_db): Extension<UserDB>,
Path((w_id, runnable_kind, path)): Path<(String, RunnableKind, StripPath)>,
) -> JsonResult<Vec<CaptureConfig>> {
let mut tx = user_db.begin(&authed).await?;
let configs = sqlx::query_as!(
CaptureConfig,
r#"SELECT trigger_config as "trigger_config: _", trigger_kind as "trigger_kind: _", error, last_server_ping
FROM capture_config
WHERE workspace_id = $1 AND path = $2 AND is_flow = $3"#,
&w_id,
&path.to_path(),
matches!(runnable_kind, RunnableKind::Flow),
)
.fetch_all(&mut *tx)
.await?;
tx.commit().await?;
Ok(Json(configs))
}
async fn set_config(
authed: ApiAuthed,
Extension(user_db): Extension<UserDB>,
Path(w_id): Path<String>,
Json(nc): Json<NewCaptureConfig>,
) -> Result<()> {
Path((w_id, path)): Path<(String, StripPath)>,
) -> Result<StatusCode> {
let mut tx = user_db.begin(&authed).await?;
sqlx::query!(
"INSERT INTO capture_config
(workspace_id, path, is_flow, trigger_kind, trigger_config, owner, email)
VALUES ($1, $2, $3, $4, $5, $6, $7)
ON CONFLICT (workspace_id, path, is_flow, trigger_kind)
DO UPDATE SET trigger_config = $5, owner = $6, email = $7, server_id = NULL, last_server_ping = NULL, error = NULL",
"
INSERT INTO capture
(workspace_id, path, created_by)
VALUES ($1, $2, $3)
ON CONFLICT (workspace_id, path)
DO UPDATE SET created_at = now()
",
&w_id,
&nc.path,
nc.is_flow,
nc.trigger_kind as TriggerKind,
nc.trigger_config.map(|x| SqlxJson(to_raw_value(&x))) as Option<SqlxJson<Box<RawValue>>>,
&path.to_path(),
&authed.username,
&authed.email,
)
.execute(&mut *tx)
.await?;
tx.commit().await?;
Ok(())
}
async fn ping_config(
authed: ApiAuthed,
Extension(user_db): Extension<UserDB>,
Path((w_id, trigger_kind, runnable_kind, path)): Path<(
String,
TriggerKind,
RunnableKind,
StripPath,
)>,
) -> Result<()> {
let mut tx = user_db.begin(&authed).await?;
/* Retain only KEEP_LAST most recent captures by this user in this workspace. */
sqlx::query!(
"UPDATE capture_config SET last_client_ping = now() WHERE workspace_id = $1 AND path = $2 AND is_flow = $3 AND trigger_kind = $4",
"
DELETE FROM capture
WHERE workspace_id = $1
AND created_by = $2
AND created_at <=
( SELECT created_at
FROM capture
WHERE workspace_id = $1
AND created_by = $2
ORDER BY created_at DESC
OFFSET $3
LIMIT 1 )
",
&w_id,
&path.to_path(),
matches!(runnable_kind, RunnableKind::Flow),
trigger_kind as TriggerKind,
&authed.username,
KEEP_LAST,
)
.execute(&mut *tx)
.await?;
tx.commit().await?;
Ok(())
Ok(StatusCode::CREATED)
}
#[derive(Serialize, Deserialize)]
struct Capture {
id: i64,
created_at: chrono::DateTime<chrono::Utc>,
trigger_kind: TriggerKind,
payload: SqlxJson<Box<serde_json::value::RawValue>>,
trigger_extra: Option<SqlxJson<Box<serde_json::value::RawValue>>>,
}
pub async fn update_payload(
Extension(db): Extension<DB>,
Path((w_id, path)): Path<(String, StripPath)>,
args: WebhookArgs,
) -> Result<StatusCode> {
let args = args.args;
#[derive(Deserialize)]
#[serde(rename_all = "lowercase")]
enum RunnableKind {
Script,
Flow,
}
let mut tx = db.begin().await?;
#[derive(Deserialize)]
struct ListCapturesQuery {
trigger_kind: Option<TriggerKind>,
}
async fn list_captures(
authed: ApiAuthed,
Extension(user_db): Extension<UserDB>,
Path((w_id, runnable_kind, path)): Path<(String, RunnableKind, StripPath)>,
Query(query): Query<ListCapturesQuery>,
) -> JsonResult<Vec<Capture>> {
let mut tx = user_db.begin(&authed).await?;
let captures = sqlx::query_as!(
Capture,
r#"SELECT id, created_at, trigger_kind as "trigger_kind: _", payload as "payload: _", trigger_extra as "trigger_extra: _"
FROM capture
sqlx::query!(
"
UPDATE capture
SET payload = $3
WHERE workspace_id = $1
AND path = $2 AND is_flow = $3
AND ($4::trigger_kind IS NULL OR trigger_kind = $4)
ORDER BY created_at DESC"#,
AND path = $2
",
&w_id,
&path.to_path(),
matches!(runnable_kind, RunnableKind::Flow),
query.trigger_kind as Option<TriggerKind>,
Json(PushArgs { args: &args.args, extra: args.extra }) as Json<PushArgs>,
)
.fetch_all(&mut *tx)
.execute(&mut *tx)
.await?;
tx.commit().await?;
Ok(Json(captures))
Ok(StatusCode::NO_CONTENT)
}
async fn delete_capture(
#[derive(sqlx::FromRow)]
struct Payload {
payload: sqlx::types::Json<Box<serde_json::value::RawValue>>,
}
pub async fn get_payload(
authed: ApiAuthed,
Extension(user_db): Extension<UserDB>,
Path((_, id)): Path<(String, i64)>,
) -> Result<()> {
Path((w_id, path)): Path<(String, StripPath)>,
) -> JsonResult<Box<serde_json::value::RawValue>> {
let mut tx = user_db.begin(&authed).await?;
sqlx::query!("DELETE FROM capture WHERE id = $1", id)
.execute(&mut *tx)
.await?;
let payload = sqlx::query_as::<_, Payload>(
"
SELECT payload
FROM capture
WHERE workspace_id = $1
AND path = $2
",
)
.bind(&w_id)
.bind(&path.to_path())
.fetch_optional(&mut *tx)
.await?;
tx.commit().await?;
Ok(())
}
#[derive(Serialize, Deserialize)]
struct ActiveCaptureOwner {
owner: String,
email: String,
}
pub async fn get_active_capture_owner_and_email(
db: &DB,
w_id: &str,
path: &str,
is_flow: bool,
kind: &TriggerKind,
) -> Result<(String, String)> {
let capture_config = sqlx::query_as!(
ActiveCaptureOwner,
"SELECT owner, email
FROM capture_config
WHERE workspace_id = $1 AND path = $2 AND is_flow = $3 AND trigger_kind = $4 AND last_client_ping > NOW() - INTERVAL '10 seconds'",
&w_id,
&path,
is_flow,
kind as &TriggerKind,
)
.fetch_optional(db)
.await?;
let capture_config = not_found_if_none(
capture_config,
&format!("capture config for {} trigger", kind),
path,
)?;
Ok((capture_config.owner, capture_config.email))
}
#[cfg(feature = "http_trigger")]
async fn get_capture_trigger_config_and_owner<T: DeserializeOwned>(
db: &DB,
w_id: &str,
path: &str,
is_flow: bool,
kind: &TriggerKind,
) -> Result<(T, String, String)> {
#[derive(Deserialize)]
struct CaptureTriggerConfigAndOwner {
trigger_config: Option<SqlxJson<Box<RawValue>>>,
owner: String,
email: String,
}
let capture_config = sqlx::query_as!(
CaptureTriggerConfigAndOwner,
r#"SELECT trigger_config as "trigger_config: _", owner, email
FROM capture_config
WHERE workspace_id = $1 AND path = $2 AND is_flow = $3 AND trigger_kind = $4 AND last_client_ping > NOW() - INTERVAL '10 seconds'"#,
&w_id,
&path,
is_flow,
kind as &TriggerKind,
)
.fetch_optional(db)
.await?;
let capture_config = not_found_if_none(
capture_config,
&format!("capture config for {} trigger", kind),
path,
)?;
let trigger_config = not_found_if_none(
capture_config.trigger_config,
&format!("capture {} trigger config", kind),
path,
)?;
Ok((
serde_json::from_str(trigger_config.get()).map_err(|e| {
Error::InternalErr(format!(
"error parsing capture config for {} trigger: {}",
kind, e
))
})?,
capture_config.owner,
capture_config.email,
))
}
async fn clear_captures_history(db: &DB, w_id: &str) -> Result<()> {
if *CLOUD_HOSTED {
/* Retain only KEEP_LAST most recent captures in this workspace. */
sqlx::query!(
"DELETE FROM capture
WHERE workspace_id = $1
AND created_at <=
(
SELECT created_at
FROM capture
WHERE workspace_id = $1
ORDER BY created_at DESC
OFFSET $2
LIMIT 1
)",
&w_id,
KEEP_LAST,
)
.execute(db)
.await?;
}
Ok(())
}
pub async fn insert_capture_payload(
db: &DB,
w_id: &str,
path: &str,
is_flow: bool,
trigger_kind: &TriggerKind,
payload: PushArgsOwned,
trigger_extra: Option<Box<RawValue>>,
owner: &str,
) -> Result<()> {
sqlx::query!(
"INSERT INTO capture (workspace_id, path, is_flow, trigger_kind, payload, trigger_extra, created_by)
VALUES ($1, $2, $3, $4, $5, $6, $7)",
&w_id,
path,
is_flow,
trigger_kind as &TriggerKind,
SqlxJson(to_raw_value(&PushArgs {
args: &payload.args,
extra: payload.extra
})) as SqlxJson<Box<RawValue>>,
trigger_extra.map(SqlxJson) as Option<SqlxJson<Box<RawValue>>>,
owner,
)
.execute(db)
.await?;
clear_captures_history(db, &w_id).await?;
Ok(())
}
async fn webhook_payload(
Extension(db): Extension<DB>,
Path((w_id, runnable_kind, path)): Path<(String, RunnableKind, StripPath)>,
args: WebhookArgs,
) -> Result<StatusCode> {
let (owner, email) = get_active_capture_owner_and_email(
&db,
&w_id,
&path.to_path(),
matches!(runnable_kind, RunnableKind::Flow),
&TriggerKind::Webhook,
)
.await?;
let authed = fetch_api_authed(owner.clone(), email, &w_id, &db, None).await?;
let args = args.to_push_args_owned(&authed, &db, &w_id).await?;
insert_capture_payload(
&db,
&w_id,
&path.to_path(),
matches!(runnable_kind, RunnableKind::Flow),
&TriggerKind::Webhook,
args,
Some(to_raw_value(&serde_json::json!({
"wm_trigger": {
"kind": "webhook",
}
}))),
&owner,
)
.await?;
Ok(StatusCode::NO_CONTENT)
}
#[cfg(feature = "http_trigger")]
async fn http_payload(
Extension(db): Extension<DB>,
Path((w_id, kind, path, route_path)): Path<(String, RunnableKind, String, StripPath)>,
Query(query): Query<HashMap<String, String>>,
method: http::Method,
headers: HeaderMap,
args: WebhookArgs,
) -> Result<StatusCode> {
let route_path = route_path.to_path();
let path = path.replace(".", "/");
let (http_trigger_config, owner, email): (HttpTriggerConfig, _, _) =
get_capture_trigger_config_and_owner(
&db,
&w_id,
&path,
matches!(kind, RunnableKind::Flow),
&TriggerKind::Http,
)
.await?;
let authed = fetch_api_authed(owner.clone(), email, &w_id, &db, None).await?;
let args = args.to_push_args_owned(&authed, &db, &w_id).await?;
let mut router = matchit::Router::new();
router.insert(&http_trigger_config.route_path, ()).ok();
let match_ = router.at(route_path).ok();
let match_ = not_found_if_none(match_, "capture http trigger", &route_path)?;
let matchit::Match { params, .. } = match_;
let params: HashMap<String, String> = params
.iter()
.map(|(k, v)| (k.to_string(), v.to_string()))
.collect();
let extra: HashMap<String, Box<RawValue>> = HashMap::from_iter(vec![(
"wm_trigger".to_string(),
build_http_trigger_extra(
&http_trigger_config.route_path,
route_path,
&method,
&params,
&query,
&headers,
)
.await,
)]);
insert_capture_payload(
&db,
&w_id,
&path,
matches!(kind, RunnableKind::Flow),
&TriggerKind::Http,
args,
Some(to_raw_value(&extra)),
&owner,
)
.await?;
Ok(StatusCode::NO_CONTENT)
not_found_if_none(payload.map(|x| x.payload.0), "capture", path.to_path()).map(axum::Json)
}

View File

@@ -740,24 +740,6 @@ async fn update_flow(
"Error updating flow due to deleting old flow: {e:#}"
))
})?;
sqlx::query!(
"UPDATE capture_config SET path = $1 WHERE path = $2 AND workspace_id = $3 AND is_flow IS TRUE",
nf.path,
flow_path,
w_id
)
.execute(&mut *tx)
.await?;
sqlx::query!(
"UPDATE capture SET path = $1 WHERE path = $2 AND workspace_id = $3 AND is_flow IS TRUE",
nf.path,
flow_path,
w_id
)
.execute(&mut *tx)
.await?;
}
let version = sqlx::query_scalar!(
@@ -1141,22 +1123,6 @@ async fn delete_flow_by_path(
.execute(&mut *tx)
.await?;
sqlx::query!(
"DELETE FROM capture_config WHERE path = $1 AND workspace_id = $2 AND is_flow IS TRUE",
path,
&w_id
)
.execute(&mut *tx)
.await?;
sqlx::query!(
"DELETE FROM capture WHERE path = $1 AND workspace_id = $2 AND is_flow IS TRUE",
path,
&w_id
)
.execute(&mut *tx)
.await?;
audit_log(
&mut *tx,
&authed,

View File

@@ -23,7 +23,7 @@ use windmill_common::{
utils::{not_found_if_none, StripPath},
};
const KINDS: [&str; 13] = [
const KINDS: [&str; 12] = [
"script",
"group_",
"resource",
@@ -36,7 +36,6 @@ const KINDS: [&str; 13] = [
"http_trigger",
"websocket_trigger",
"kafka_trigger",
"nats_trigger",
];
pub fn workspaced_service() -> Router {

View File

@@ -77,7 +77,7 @@ pub fn workspaced_service() -> Router {
#[derive(Serialize, Deserialize, sqlx::Type)]
#[sqlx(type_name = "HTTP_METHOD", rename_all = "lowercase")]
#[serde(rename_all = "lowercase")]
pub enum HttpMethod {
enum HttpMethod {
Get,
Post,
Put,
@@ -85,16 +85,14 @@ pub enum HttpMethod {
Patch,
}
impl TryFrom<&http::Method> for HttpMethod {
type Error = error::Error;
fn try_from(method: &http::Method) -> Result<Self, Self::Error> {
impl From<HttpMethod> for http::Method {
fn from(method: HttpMethod) -> Self {
match method {
&http::Method::GET => Ok(HttpMethod::Get),
&http::Method::POST => Ok(HttpMethod::Post),
&http::Method::PUT => Ok(HttpMethod::Put),
&http::Method::DELETE => Ok(HttpMethod::Delete),
&http::Method::PATCH => Ok(HttpMethod::Patch),
_ => Err(error::Error::BadRequest("Invalid HTTP method".to_string())),
HttpMethod::Get => http::Method::GET,
HttpMethod::Post => http::Method::POST,
HttpMethod::Put => http::Method::PUT,
HttpMethod::Delete => http::Method::DELETE,
HttpMethod::Patch => http::Method::PATCH,
}
}
}
@@ -419,6 +417,7 @@ struct TriggerRoute {
requires_auth: bool,
edited_by: String,
email: String,
http_method: HttpMethod,
static_asset_config: Option<sqlx::types::Json<S3Object>>,
}
@@ -428,9 +427,7 @@ async fn get_http_route_trigger(
token: Option<&String>,
db: &DB,
user_db: UserDB,
method: &http::Method,
) -> error::Result<(TriggerRoute, String, HashMap<String, String>, ApiAuthed)> {
let http_method: HttpMethod = method.try_into()?;
let (mut triggers, route_path) = if *CLOUD_HOSTED {
let mut splitted = route_path.split("/");
let w_id = splitted.next().ok_or_else(|| {
@@ -439,9 +436,8 @@ async fn get_http_route_trigger(
let route_path = StripPath(splitted.collect::<Vec<_>>().join("/"));
let triggers = sqlx::query_as!(
TriggerRoute,
r#"SELECT path, script_path, is_flow, route_path, workspace_id, is_async, requires_auth, edited_by, email, static_asset_config as "static_asset_config: _" FROM http_trigger WHERE workspace_id = $1 AND http_method = $2"#,
w_id,
http_method as HttpMethod
r#"SELECT path, script_path, is_flow, route_path, workspace_id, is_async, requires_auth, edited_by, email, http_method as "http_method: _", static_asset_config as "static_asset_config: _" FROM http_trigger WHERE workspace_id = $1"#,
w_id
)
.fetch_all(db)
.await?;
@@ -449,8 +445,7 @@ async fn get_http_route_trigger(
} else {
let triggers = sqlx::query_as!(
TriggerRoute,
r#"SELECT path, script_path, is_flow, route_path, workspace_id, is_async, requires_auth, edited_by, email, static_asset_config as "static_asset_config: _" FROM http_trigger WHERE http_method = $1"#,
http_method as HttpMethod
r#"SELECT path, script_path, is_flow, route_path, workspace_id, is_async, requires_auth, edited_by, email, http_method as "http_method: _", static_asset_config as "static_asset_config: _" FROM http_trigger"#,
)
.fetch_all(db)
.await?;
@@ -528,32 +523,6 @@ async fn get_http_route_trigger(
Ok((trigger, route_path.0, params, authed))
}
pub async fn build_http_trigger_extra(
route_path: &str,
called_path: &str,
method: &http::Method,
params: &HashMap<String, String>,
query: &HashMap<String, String>,
headers: &HeaderMap,
) -> Box<serde_json::value::RawValue> {
let headers = headers
.iter()
.map(|(k, v)| (k.to_string(), v.to_str().unwrap_or("").to_string()))
.collect::<HashMap<String, String>>();
to_raw_value(&serde_json::json!({
"kind": "http",
"http": {
"route": route_path,
"path": called_path,
"method": method.to_string().to_lowercase(),
"params": params,
"query": query,
"headers": headers
},
}))
}
async fn route_job(
Extension(db): Extension<DB>,
Extension(user_db): Extension<UserDB>,
@@ -572,7 +541,6 @@ async fn route_job(
token.as_ref(),
&db,
user_db.clone(),
&method,
)
.await
{
@@ -671,23 +639,34 @@ async fn route_job(
}
}
let headers = headers
.iter()
.map(|(k, v)| (k.to_string(), v.to_str().unwrap_or("").to_string()))
.collect::<HashMap<String, String>>();
let extra = args.extra.get_or_insert_with(HashMap::new);
extra.insert(
"wm_trigger".to_string(),
build_http_trigger_extra(
&trigger.route_path,
&called_path,
&method,
&params,
&query,
&headers,
)
.await,
to_raw_value(&serde_json::json!({
"kind": "http",
"http": {
"route": trigger.route_path,
"path": called_path,
"method": method.to_string().to_lowercase(),
"params": params,
"query": query,
"headers": headers
},
})),
);
let http_method = http::Method::from(trigger.http_method);
if http_method != method {
return error::Error::BadRequest("Invalid HTTP method".to_string()).into_response();
}
let label_prefix = Some(format!(
"http-{}-{}-",
method.as_str().to_lowercase(),
http_method.as_str().to_lowercase(),
trigger.route_path
));

View File

@@ -12,32 +12,11 @@ use std::sync::Arc;
use windmill_common::error;
#[cfg(feature = "parquet")]
use windmill_common::{db::UserDB, s3_helpers::ObjectStoreResource};
#[cfg(feature = "parquet")]
use bytes::Bytes;
#[cfg(feature = "parquet")]
use futures::Stream;
#[cfg(feature = "parquet")]
use axum::response::Response;
#[cfg(feature = "parquet")]
use serde::Deserialize;
#[derive(Serialize)]
pub struct UploadFileResponse {
pub file_key: String,
}
#[derive(Deserialize)]
pub struct LoadImagePreviewQuery {
pub file_key: String,
}
#[derive(Deserialize)]
pub struct DownloadFileQuery {
pub file_key: String,
}
pub fn workspaced_service() -> Router {
Router::new()
}
@@ -56,7 +35,7 @@ pub async fn get_workspace_s3_resource<'c>(
}
pub fn get_random_file_name(_file_extension: Option<String>) -> String {
unimplemented!("Not implemented in Windmill's Open Source repository")
todo!()
}
pub async fn get_s3_resource<'c>(
@@ -69,58 +48,14 @@ pub async fn get_s3_resource<'c>(
_resource_type: Option<StorageResourceType>,
_job_id: Option<Uuid>,
) -> error::Result<ObjectStoreResource> {
Err(error::Error::InternalErr(
"Not implemented in Windmill's Open Source repository".to_string(),
))
todo!()
}
#[cfg(feature = "parquet")]
pub async fn upload_file_from_req(
_s3_client: Arc<dyn ObjectStore>,
_file_key: &str,
_req: axum::extract::Request,
_options: PutMultipartOpts,
) -> error::Result<()> {
Err(error::Error::InternalErr(
"Not implemented in Windmill's Open Source repository".to_string(),
))
}
#[cfg(feature = "parquet")]
pub async fn upload_file_internal(
_s3_client: Arc<dyn ObjectStore>,
_file_key: &str,
_stream: impl Stream<Item = Result<Bytes, std::io::Error>> + Unpin,
_request: axum::extract::Request,
_options: PutMultipartOpts,
) -> error::Result<()> {
Err(error::Error::InternalErr(
"Not implemented in Windmill's Open Source repository".to_string(),
))
}
#[cfg(feature = "parquet")]
pub async fn download_s3_file_internal(
_authed: ApiAuthed,
_db: &DB,
_user_db: Option<UserDB>,
_token: &str,
_w_id: &str,
_query: DownloadFileQuery,
) -> error::Result<Response> {
Err(error::Error::InternalErr(
"Not implemented in Windmill's Open Source repository".to_string(),
))
}
#[cfg(feature = "parquet")]
pub async fn load_image_preview_internal(
_authed: ApiAuthed,
_db: &DB,
_token: &str,
_w_id: &str,
_query: LoadImagePreviewQuery,
) -> error::Result<Response> {
Err(error::Error::InternalErr(
"Not implemented in Windmill's Open Source repository".to_string(),
))
todo!()
}

View File

@@ -2160,7 +2160,7 @@ pub struct SuspendedJobFlow {
pub approvers: Vec<Approval>,
}
#[derive(Deserialize, Debug)]
#[derive(Deserialize)]
pub struct QueryApprover {
pub approver: Option<String>,
}
@@ -2340,7 +2340,7 @@ pub async fn set_flow_user_state(
let r = sqlx::query_scalar!(
r#"
UPDATE queue SET flow_status = JSONB_SET(flow_status, ARRAY['user_states'], JSONB_SET(COALESCE(flow_status->'user_states', '{}'::jsonb), ARRAY[$1], $2))
WHERE id = $3 AND workspace_id = $4 AND job_kind IN ('flow', 'flowpreview', 'flownode') RETURNING 1
WHERE id = $3 AND workspace_id = $4 AND job_kind IN ('flow', 'flowpreview') RETURNING 1
"#,
key,
value,
@@ -2373,11 +2373,11 @@ fn create_signature(
}
#[allow(non_snake_case)]
#[derive(Serialize, Debug)]
#[derive(Serialize)]
pub struct ResumeUrls {
pub approvalPage: String,
pub cancel: String,
pub resume: String,
approvalPage: String,
cancel: String,
resume: String,
}
fn build_resume_url(
@@ -2397,14 +2397,6 @@ pub async fn get_resume_urls(
Extension(db): Extension<DB>,
Path((w_id, job_id, resume_id)): Path<(String, Uuid, u32)>,
Query(approver): Query<QueryApprover>,
) -> error::JsonResult<ResumeUrls> {
get_resume_urls_internal(Extension(db), Path((w_id, job_id, resume_id)), Query(approver)).await
}
pub async fn get_resume_urls_internal(
Extension(db): Extension<DB>,
Path((w_id, job_id, resume_id)): Path<(String, Uuid, u32)>,
Query(approver): Query<QueryApprover>,
) -> error::JsonResult<ResumeUrls> {
let key = get_workspace_key(&w_id, &db).await?;
let signature = create_signature(key, job_id, resume_id, approver.approver.clone())?;
@@ -5569,4 +5561,3 @@ async fn delete_completed_job<'a>(
let response = Json(cj).into_response();
Ok(response)
}

View File

@@ -1,9 +1,5 @@
use crate::db::DB;
use axum::Router;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
pub struct KafkaResourceSecurity {}
pub fn workspaced_service() -> Router {
Router::new()

Some files were not shown because too many files have changed in this diff Show More