Compare commits
106 Commits
rf/cliImpr
...
rf/oidcIns
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
649872ab0d | ||
|
|
b7ad19bb75 | ||
|
|
45bf59ba32 | ||
|
|
1466da3999 | ||
|
|
3174024d8e | ||
|
|
4e6c0d1e80 | ||
|
|
6abb346013 | ||
|
|
79100f8d0a | ||
|
|
28f6f6b067 | ||
|
|
d24e153065 | ||
|
|
8df2cec40a | ||
|
|
a8c4ea2334 | ||
|
|
20e8be15fe | ||
|
|
c3b536b1b8 | ||
|
|
c06c42a1ed | ||
|
|
01b95ebd8d | ||
|
|
99814c7ab0 | ||
|
|
10414df4a7 | ||
|
|
91a3d06529 | ||
|
|
f38b3d14e8 | ||
|
|
e736572db1 | ||
|
|
7126ba12c7 | ||
|
|
29cb954639 | ||
|
|
411bce7e13 | ||
|
|
99c5b3ecda | ||
|
|
9eb1ecc9f3 | ||
|
|
dcdbf1afb4 | ||
|
|
34c39ce0ab | ||
|
|
288dfe7c70 | ||
|
|
8867260e43 | ||
|
|
4112eb6072 | ||
|
|
9d2cb91f9c | ||
|
|
a323d2b29a | ||
|
|
fa642c8db1 | ||
|
|
42fe31f804 | ||
|
|
242a251ab1 | ||
|
|
7a92a152d1 | ||
|
|
fad4785b0a | ||
|
|
296aa97bd8 | ||
|
|
d77412cef6 | ||
|
|
685eb5d471 | ||
|
|
fcdf82af36 | ||
|
|
d2c4d3fa20 | ||
|
|
e06c845ed4 | ||
|
|
f82f091290 | ||
|
|
9f7edbaf1a | ||
|
|
2dab068fd3 | ||
|
|
7e754a1e50 | ||
|
|
be112408e7 | ||
|
|
568cc66932 | ||
|
|
0915968eba | ||
|
|
982dde2b9d | ||
|
|
7db74eecb9 | ||
|
|
81b0ff1ad1 | ||
|
|
b133f19333 | ||
|
|
d9bdc5a5b0 | ||
|
|
ba17dfc841 | ||
|
|
7ca5bf2fae | ||
|
|
cf8d443603 | ||
|
|
0e61f8db78 | ||
|
|
c3a5736641 | ||
|
|
26b11a0015 | ||
|
|
7dbe49b77b | ||
|
|
2e9312216e | ||
|
|
7b0503332d | ||
|
|
25e417538f | ||
|
|
6280ed3524 | ||
|
|
ffaf756e9a | ||
|
|
21cd7a63ae | ||
|
|
d90d6c2b89 | ||
|
|
111bfc6a65 | ||
|
|
257f0971f8 | ||
|
|
f831b9b1fe | ||
|
|
b579db61ec | ||
|
|
e44decb9c2 | ||
|
|
644dd87c50 | ||
|
|
0c66dcab3a | ||
|
|
386eef9779 | ||
|
|
284cb4069c | ||
|
|
e1e8c814e5 | ||
|
|
da50e40010 | ||
|
|
289ad51374 | ||
|
|
c86ce483ca | ||
|
|
b034b070c0 | ||
|
|
fa7ca405c2 | ||
|
|
4da02a54ba | ||
|
|
19c62ba195 | ||
|
|
26659ce37d | ||
|
|
b96cc19718 | ||
|
|
1dabb1591b | ||
|
|
c84e6fd05d | ||
|
|
a630acc5fc | ||
|
|
32e4a74524 | ||
|
|
794c4cde3c | ||
|
|
b54c9ee657 | ||
|
|
f5c4727274 | ||
|
|
1d8e361612 | ||
|
|
642f3876fa | ||
|
|
92f61f07ed | ||
|
|
b69bbceedb | ||
|
|
f25eb3455f | ||
|
|
45ccd45e30 | ||
|
|
48a85e1732 | ||
|
|
a4a59ef21e | ||
|
|
8e58e4320a | ||
|
|
3134f79ced |
30
.github/DockerfileBackendTests
vendored
30
.github/DockerfileBackendTests
vendored
@@ -1,22 +1,6 @@
|
||||
ARG DEBIAN_IMAGE=debian:bookworm-slim
|
||||
ARG RUST_IMAGE=rust:1.80-slim-bookworm
|
||||
ARG PYTHON_IMAGE=python:3.11.4-slim-bookworm
|
||||
|
||||
FROM ${DEBIAN_IMAGE} as downloader
|
||||
|
||||
ARG TARGETPLATFORM
|
||||
|
||||
SHELL ["/bin/bash", "-c"]
|
||||
|
||||
RUN apt update -y
|
||||
RUN apt install -y unzip curl
|
||||
|
||||
RUN [ "$TARGETPLATFORM" == "linux/amd64" ] && curl -Lsf https://github.com/denoland/deno/releases/download/v1.46.3/deno-x86_64-unknown-linux-gnu.zip -o deno.zip || true
|
||||
RUN [ "$TARGETPLATFORM" == "linux/arm64" ] && curl -Lsf https://github.com/denoland/deno/releases/download/v1.46.3/deno-aarch64-unknown-linux-gnu.zip -o deno.zip || true
|
||||
|
||||
|
||||
RUN unzip deno.zip && rm deno.zip
|
||||
|
||||
|
||||
FROM ${RUST_IMAGE} as builder
|
||||
|
||||
@@ -31,7 +15,7 @@ ENV SQLX_OFFLINE=true
|
||||
|
||||
RUN mkdir -p /frontend/build
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y ca-certificates tzdata libpq5 cmake\
|
||||
&& apt-get install -y ca-certificates tzdata libpq5 cmake unzip\
|
||||
make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev \
|
||||
libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev xz-utils tk-dev libxml2-dev \
|
||||
libxmlsec1-dev libffi-dev liblzma-dev mecab-ipadic-utf8 libgdbm-dev libc6-dev git libprotobuf-dev libnl-route-3-dev \
|
||||
@@ -43,6 +27,9 @@ RUN wget https://golang.org/dl/go1.21.5.linux-amd64.tar.gz && tar -C /usr/local
|
||||
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.4.18/uv-installer.sh | sh && mv /usr/local/cargo/bin/uv /usr/local/bin/uv
|
||||
|
||||
ENV TZ=Etc/UTC
|
||||
|
||||
ENV PYTHON_VERSION 3.11.4
|
||||
@@ -53,13 +40,14 @@ RUN wget https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VER
|
||||
|
||||
RUN /usr/local/bin/python3 -m pip install pip-tools
|
||||
|
||||
COPY --from=oven/bun:1.1.27 /usr/local/bin/bun /usr/bin/bun
|
||||
COPY --from=oven/bun:1.1.30 /usr/local/bin/bun /usr/bin/bun
|
||||
|
||||
ARG TARGETPLATFORM
|
||||
|
||||
RUN [ "$TARGETPLATFORM" == "linux/amd64" ] && curl -Lsf https://github.com/denoland/deno/releases/download/v1.41.0/deno-x86_64-unknown-linux-gnu.zip -o deno.zip || true
|
||||
RUN [ "$TARGETPLATFORM" == "linux/arm64" ] && curl -Lsf https://github.com/denoland/deno/releases/download/v1.41.0/deno-aarch64-unknown-linux-gnu.zip -o deno.zip || true
|
||||
RUN curl -Lsf https://github.com/denoland/deno/releases/download/v2.0.0/deno-x86_64-unknown-linux-gnu.zip -o deno.zip
|
||||
# RUN [ "$TARGETPLATFORM" == "linux/arm64" ] && curl -Lsf https://github.com/denoland/deno/releases/download/v2.0.0/deno-aarch64-unknown-linux-gnu.zip -o deno.zip || true
|
||||
|
||||
COPY --from=downloader --chmod=755 /deno /usr/bin/deno
|
||||
RUN unzip deno.zip && rm deno.zip && mv deno /usr/bin/deno
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y postgresql-client --allow-unauthenticated
|
||||
|
||||
8
.github/workflows/backend-test.yml
vendored
8
.github/workflows/backend-test.yml
vendored
@@ -41,8 +41,12 @@ jobs:
|
||||
- name: cargo test
|
||||
timeout-minutes: 15
|
||||
run:
|
||||
/usr/bin/deno --version &&
|
||||
/usr/bin/bun -v &&
|
||||
go version &&
|
||||
/usr/local/bin/python3 --version &&
|
||||
mkdir frontend/build && cd backend && touch
|
||||
windmill-api/openapi-deref.yaml &&
|
||||
DATABASE_URL=postgres://postgres:changeme@postgres:5432/windmill
|
||||
DISABLE_EMBEDDING=true RUST_LOG=info cargo test --features enterprise
|
||||
--all -- --nocapture
|
||||
DISABLE_EMBEDDING=true RUST_LOG=info cargo test --features
|
||||
enterprise,deno_core --all -- --nocapture
|
||||
|
||||
128
.github/workflows/build-publish-rh-image.yml
vendored
Normal file
128
.github/workflows/build-publish-rh-image.yml
vendored
Normal file
@@ -0,0 +1,128 @@
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: ${{ github.repository }}
|
||||
|
||||
name: Build and publish windmill for RHEL9
|
||||
on:
|
||||
workflow_dispatch
|
||||
|
||||
permissions: write-all
|
||||
|
||||
jobs:
|
||||
build_ee:
|
||||
runs-on: ubicloud
|
||||
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-rhel9
|
||||
flavor: |
|
||||
latest=false
|
||||
tags: |
|
||||
type=sha
|
||||
|
||||
- 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: Copy RHEL9 Dockerfile
|
||||
run: |
|
||||
cp ./docker/RHEL9/Dockerfile ./Dockerfile
|
||||
|
||||
- name: Build and push publicly ee amd64
|
||||
uses: depot/build-push-action@v1
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64
|
||||
push: true
|
||||
build-args: |
|
||||
features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,deno_core
|
||||
secrets: |
|
||||
rh_username=${{ secrets.RH_USERNAME }}
|
||||
rh_password=${{ secrets.RH_PASSWORD }}
|
||||
tags: |
|
||||
${{ steps.meta-ee-public.outputs.tags }}-amd64
|
||||
labels: |
|
||||
${{ steps.meta-ee-public.outputs.labels }}-amd64
|
||||
org.opencontainers.image.licenses=Windmill-Enterprise-License
|
||||
|
||||
- name: Build and push publicly ee arm64
|
||||
uses: depot/build-push-action@v1
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/arm64
|
||||
push: true
|
||||
build-args: |
|
||||
features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,deno_core
|
||||
secrets: |
|
||||
rh_username=${{ secrets.RH_USERNAME }}
|
||||
rh_password=${{ secrets.RH_PASSWORD }}
|
||||
tags: |
|
||||
${{ steps.meta-ee-public.outputs.tags }}-arm64
|
||||
labels: |
|
||||
${{ steps.meta-ee-public.outputs.labels }}-arm64
|
||||
org.opencontainers.image.licenses=Windmill-Enterprise-License
|
||||
|
||||
- uses: shrink/actions-docker-extract@v3
|
||||
id: extract-ee-amd64
|
||||
with:
|
||||
image: ${{ steps.meta-ee-public.outputs.tags}}-amd64
|
||||
path: "/windmill/target/release/windmill"
|
||||
|
||||
- uses: shrink/actions-docker-extract@v3
|
||||
id: extract-ee-arm64
|
||||
with:
|
||||
image: ${{ steps.meta-ee-public.outputs.tags}}-arm64
|
||||
path: "/windmill/target/release/windmill"
|
||||
|
||||
- name: Rename binary with corresponding architecture
|
||||
run: |
|
||||
mv "${{ steps.extract-ee-amd64.outputs.destination }}/windmill" "${{ steps.extract-ee-amd64.outputs.destination }}/windmill-ee-amd64-rhel9"
|
||||
mv "${{ steps.extract-ee-arm64.outputs.destination }}/windmill" "${{ steps.extract-ee-arm64.outputs.destination }}/windmill-ee-arm64-rhel9"
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: RHEL9-amd64 build
|
||||
path: ${{ steps.extract-ee-amd64.outputs.destination }}/windmill-ee-amd64-rhel9
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: RHEL9-arm64 build
|
||||
path: ${{ steps.extract-ee-arm64.outputs.destination }}/windmill-ee-arm64-rhel9
|
||||
|
||||
# - name: Attach binary to release
|
||||
# uses: softprops/action-gh-release@v2
|
||||
# if: startsWith(github.ref, 'refs/tags/')
|
||||
# with:
|
||||
# files: |
|
||||
# ${{ steps.extract-ee-arm64.outputs.destination }}/windmill-ee-arm64-rhel9
|
||||
# ${{ steps.extract-ee-amd64.outputs.destination }}/windmill-ee-amd64-rhel9
|
||||
2
.github/workflows/build-staging-image.yml
vendored
2
.github/workflows/build-staging-image.yml
vendored
@@ -62,7 +62,7 @@ jobs:
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
build-args: |
|
||||
features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc
|
||||
features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,deno_core
|
||||
tags: |
|
||||
${{ steps.meta-ee-public.outputs.tags }}
|
||||
labels: |
|
||||
|
||||
60
.github/workflows/build_windows_worker.yml
vendored
Normal file
60
.github/workflows/build_windows_worker.yml
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
name: Build and Publish Windows Worker
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
|
||||
env:
|
||||
CARGO_INCREMENTAL: 0
|
||||
SQLX_OFFLINE: true
|
||||
DISABLE_EMBEDDING: true
|
||||
RUST_LOG: info
|
||||
|
||||
jobs:
|
||||
cargo_build_windows:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Read EE repo commit hash
|
||||
shell: pwsh
|
||||
run: |
|
||||
$ee_repo_ref = Get-Content .\backend\ee-repo-ref.txt
|
||||
echo "ee_repo_ref=$ee_repo_ref" | Out-File -FilePath $env:GITHUB_ENV -Append
|
||||
|
||||
- name: Checkout windmill-ee-private repository
|
||||
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: Substitute EE code
|
||||
shell: bash
|
||||
run: |
|
||||
./backend/substitute_ee_code.sh --copy --dir ./windmill-ee-private
|
||||
|
||||
- name: Cargo build windows
|
||||
timeout-minutes: 90
|
||||
run: |
|
||||
vcpkg.exe install openssl-windows:x64-windows
|
||||
vcpkg.exe install openssl:x64-windows-static
|
||||
vcpkg.exe integrate install
|
||||
$env:VCPKGRS_DYNAMIC=1
|
||||
$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
|
||||
|
||||
- name: Rename binary with corresponding architecture
|
||||
run: |
|
||||
Rename-Item -Path ".\backend\target\release\windmill.exe" -NewName "windmill-ee.exe"
|
||||
|
||||
- name: Attach binary to release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
files: |
|
||||
./backend/target/release/windmill-ee.exe
|
||||
2
.github/workflows/docker-image-rpi4.yml
vendored
2
.github/workflows/docker-image-rpi4.yml
vendored
@@ -67,7 +67,7 @@ jobs:
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
build-args: |
|
||||
features=embedding,parquet,openidconnect
|
||||
features=embedding,parquet,openidconnect,deno_core
|
||||
tags: |
|
||||
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:dev
|
||||
${{ steps.meta-public.outputs.tags }}
|
||||
|
||||
24
.github/workflows/docker-image.yml
vendored
24
.github/workflows/docker-image.yml
vendored
@@ -1,8 +1,10 @@
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: ${{ github.event_name != 'pull_request' && github.repository ||
|
||||
IMAGE_NAME:
|
||||
${{ github.event_name != 'pull_request' && github.repository ||
|
||||
'windmill-labs/windmill-test' }}
|
||||
DEV_SHA: ${{ github.event_name != 'pull_request' && 'dev' || format('pr-{0}',
|
||||
DEV_SHA:
|
||||
${{ github.event_name != 'pull_request' && 'dev' || format('pr-{0}',
|
||||
github.event.number) }}
|
||||
|
||||
name: Build windmill:main
|
||||
@@ -75,7 +77,7 @@ jobs:
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
build-args: |
|
||||
features=embedding,parquet,openidconnect,jemalloc
|
||||
features=embedding,parquet,openidconnect,jemalloc,deno_core
|
||||
tags: |
|
||||
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.DEV_SHA }}
|
||||
${{ steps.meta-public.outputs.tags }}
|
||||
@@ -136,7 +138,7 @@ jobs:
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
build-args: |
|
||||
features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy
|
||||
features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy,deno_core
|
||||
tags: |
|
||||
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee:${{ env.DEV_SHA }}
|
||||
${{ steps.meta-ee-public.outputs.tags }}
|
||||
@@ -198,7 +200,7 @@ jobs:
|
||||
platforms: linux/amd64
|
||||
push: true
|
||||
build-args: |
|
||||
features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy
|
||||
features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy,deno_core
|
||||
PYTHON_IMAGE=python:3.12.2-slim-bookworm
|
||||
tags: |
|
||||
${{ steps.meta-ee-public-py312.outputs.tags }}
|
||||
@@ -392,7 +394,7 @@ jobs:
|
||||
verify_ee_image_vulnerabilities:
|
||||
runs-on: ubicloud
|
||||
needs: [tag_latest_ee]
|
||||
# if: ${{ startsWith(github.ref, 'refs/tags/') }}
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/') }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
@@ -587,8 +589,6 @@ jobs:
|
||||
with:
|
||||
images: |
|
||||
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee-cuda
|
||||
flavor: |
|
||||
latest=false
|
||||
tags: |
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
@@ -633,8 +633,6 @@ jobs:
|
||||
with:
|
||||
images: |
|
||||
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-slim
|
||||
flavor: |
|
||||
latest=false
|
||||
tags: |
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
@@ -678,8 +676,6 @@ jobs:
|
||||
with:
|
||||
images: |
|
||||
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee-slim
|
||||
flavor: |
|
||||
latest=false
|
||||
tags: |
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
@@ -724,8 +720,6 @@ jobs:
|
||||
with:
|
||||
images: |
|
||||
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-full
|
||||
flavor: |
|
||||
latest=false
|
||||
tags: |
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
@@ -769,8 +763,6 @@ jobs:
|
||||
with:
|
||||
images: |
|
||||
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee-full
|
||||
flavor: |
|
||||
latest=false
|
||||
tags: |
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
|
||||
168
CHANGELOG.md
168
CHANGELOG.md
@@ -1,5 +1,173 @@
|
||||
# Changelog
|
||||
|
||||
## [1.409.2](https://github.com/windmill-labs/windmill/compare/v1.409.1...v1.409.2) (2024-10-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add extra args support for exception to bun scripts ([1466da3](https://github.com/windmill-labs/windmill/commit/1466da3999add0238b9c42ca13df52194f082fc0))
|
||||
* fix script persistence in url + add support for extra error args in python ([3174024](https://github.com/windmill-labs/windmill/commit/3174024d8e6ecbe9f8c9e1ea055d611f652c0057))
|
||||
|
||||
## [1.409.1](https://github.com/windmill-labs/windmill/compare/v1.409.0...v1.409.1) (2024-10-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **apidocs:** fix generated openapi files ([d24e153](https://github.com/windmill-labs/windmill/commit/d24e1530655d27ffda9bb4c19471dc1431124cc2))
|
||||
* **git-sync:** propagate update of folders with git sync ([6abb346](https://github.com/windmill-labs/windmill/commit/6abb346013da4a907a860713a8a67642985b8025))
|
||||
|
||||
## [1.409.0](https://github.com/windmill-labs/windmill/compare/v1.408.1...v1.409.0) (2024-10-16)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **frontend:** unify all triggers UX and simplify flow settings ([#4259](https://github.com/windmill-labs/windmill/issues/4259)) ([91a3d06](https://github.com/windmill-labs/windmill/commit/91a3d065298cce7a882464fa0cd31d8f1ae9dda2))
|
||||
* Scroll to element in virtual list when clicking on graph point ([#4532](https://github.com/windmill-labs/windmill/issues/4532)) ([7126ba1](https://github.com/windmill-labs/windmill/commit/7126ba12c7eb52d2cfbe8d83311b5592a5707bce))
|
||||
* **sso:** adding the ability to define a custom display name for sso ([#4529](https://github.com/windmill-labs/windmill/issues/4529)) ([99c5b3e](https://github.com/windmill-labs/windmill/commit/99c5b3ecdacb1158c2cba5b891c4c3b8b70c3b6a))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Add indexer backup lock to fit the deployment model ([#4531](https://github.com/windmill-labs/windmill/issues/4531)) ([411bce7](https://github.com/windmill-labs/windmill/commit/411bce7e13aabfa53db80d55261ea4511f6d1ae9))
|
||||
* **app:** accept connecting to non yet existing state output for convenience ([9eb1ecc](https://github.com/windmill-labs/windmill/commit/9eb1ecc9f3017e2f4284a827a2bcd21f36b1b8ac))
|
||||
* **app:** improve absolute url handling in download button and downloadFile ([dcdbf1a](https://github.com/windmill-labs/windmill/commit/dcdbf1afb4d5a18e00b9bbb1eb0bef129ea5667f))
|
||||
* **app:** make s3 uploads persistent across tabs change ([c3b536b](https://github.com/windmill-labs/windmill/commit/c3b536b1b8069898131768867a187b186b21e537))
|
||||
* canceled jobs button reporting 0 jobs cancelled ([#4534](https://github.com/windmill-labs/windmill/issues/4534)) ([e736572](https://github.com/windmill-labs/windmill/commit/e736572db10929ae5e123c4f6cef73b8e90fc29b))
|
||||
* **python-client:** improve get_job_status for running jobs ([a8c4ea2](https://github.com/windmill-labs/windmill/commit/a8c4ea2334d2535fa7d5d43f58d65565afe8f3e5))
|
||||
* **ui:** dark mode support for queue metrics based critical alert ([#4535](https://github.com/windmill-labs/windmill/issues/4535)) ([f38b3d1](https://github.com/windmill-labs/windmill/commit/f38b3d14e8092ae58817511aea91a4e77725ead6))
|
||||
|
||||
## [1.408.1](https://github.com/windmill-labs/windmill/compare/v1.408.0...v1.408.1) (2024-10-12)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix deno cache --allow-import on deno 2 ([42fe31f](https://github.com/windmill-labs/windmill/commit/42fe31f804c9e6643cd90167494e45270831e013))
|
||||
|
||||
## [1.408.0](https://github.com/windmill-labs/windmill/compare/v1.407.2...v1.408.0) (2024-10-12)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **app builder:** file download helper ([#4511](https://github.com/windmill-labs/windmill/issues/4511)) ([f82f091](https://github.com/windmill-labs/windmill/commit/f82f09129096cfff975370d8bb7b6d832a2b8f9f))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **cli:** handle case where 'toString' is a schema field ([568cc66](https://github.com/windmill-labs/windmill/commit/568cc66932fb0470f5e89de7b02d94dba4050638))
|
||||
* **frontend:** s3 file uploader works on public apps too ([982dde2](https://github.com/windmill-labs/windmill/commit/982dde2b9dfe6d9eda300c683af729d97a03cb4d))
|
||||
* **frontend:** set unused schema property fields to null ([be11240](https://github.com/windmill-labs/windmill/commit/be112408e7c4601314726e9517c37daaeaa1bf09))
|
||||
* improve workflow as code row-lock on db to handle more concurrency ([d2c4d3f](https://github.com/windmill-labs/windmill/commit/d2c4d3fa207379cb0b8ac180f6ccc759045580e8))
|
||||
|
||||
## [1.407.2](https://github.com/windmill-labs/windmill/compare/v1.407.1...v1.407.2) (2024-10-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* improve default properties of new nodes of flows (suspend, branchone, branchall) ([d9bdc5a](https://github.com/windmill-labs/windmill/commit/d9bdc5a5b08dd4d0381304656af097315398c9d4))
|
||||
|
||||
## [1.407.1](https://github.com/windmill-labs/windmill/compare/v1.407.0...v1.407.1) (2024-10-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* improve handling of empty lock files on deno 2.0 ([7ca5bf2](https://github.com/windmill-labs/windmill/commit/7ca5bf2faeff44a7543b1afa9369c140fcb71dfc))
|
||||
|
||||
## [1.407.0](https://github.com/windmill-labs/windmill/compare/v1.406.0...v1.407.0) (2024-10-10)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* upgrade to deno 2 ([26b11a0](https://github.com/windmill-labs/windmill/commit/26b11a00150acbe101abe4bb542f24379da0cc56))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* update internal deno runtime to latest (deno 2.0) ([c3a5736](https://github.com/windmill-labs/windmill/commit/c3a57366419882ea2de1938bea592c795b1a1d03))
|
||||
|
||||
## [1.406.0](https://github.com/windmill-labs/windmill/compare/v1.405.5...v1.406.0) (2024-10-09)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **frontend:** components can be moved inside containers by holding ctrl/cmd ([111bfc6](https://github.com/windmill-labs/windmill/commit/111bfc6a659037ae7029e8f557256e2fffcf979b))
|
||||
* **monitoring:** Critical Alerts for Jobs Waiting in Queue [enterprise] ([#4491](https://github.com/windmill-labs/windmill/issues/4491)) ([d90d6c2](https://github.com/windmill-labs/windmill/commit/d90d6c2b896c5f99e00681656f376b180901f272))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **cli:** instance sync push does not require sync pull ([257f097](https://github.com/windmill-labs/windmill/commit/257f0971f86938da71b879f32d93473976eaa920))
|
||||
* remove monaco-editor for app preview code path for faster app loads ([7b05033](https://github.com/windmill-labs/windmill/commit/7b0503332d1bdd7f5999a5ef99150f8c9f6f18be))
|
||||
|
||||
## [1.405.5](https://github.com/windmill-labs/windmill/compare/v1.405.4...v1.405.5) (2024-10-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* windows.exe build with github workflow doesn't have openssl.dll bundled in ([#4489](https://github.com/windmill-labs/windmill/issues/4489)) ([284cb40](https://github.com/windmill-labs/windmill/commit/284cb4069c97efe59b5caf3effb68c8b30e02b73))
|
||||
|
||||
## [1.405.4](https://github.com/windmill-labs/windmill/compare/v1.405.3...v1.405.4) (2024-10-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **frontend:** correctly initialize step inputs on new inline script ([289ad51](https://github.com/windmill-labs/windmill/commit/289ad51374f0344582372572fc521f3b2bf12b33))
|
||||
|
||||
## [1.405.3](https://github.com/windmill-labs/windmill/compare/v1.405.2...v1.405.3) (2024-10-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix id save on apps ([b034b07](https://github.com/windmill-labs/windmill/commit/b034b070c075a0fab74678bec1fd8b829d55b204))
|
||||
|
||||
## [1.405.2](https://github.com/windmill-labs/windmill/compare/v1.405.1...v1.405.2) (2024-10-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **cli:** fix opts.yes for instance sync ([26659ce](https://github.com/windmill-labs/windmill/commit/26659ce37d2887d5b98dbdbdbba27bab85d4fe3f))
|
||||
* fix uv path ([19c62ba](https://github.com/windmill-labs/windmill/commit/19c62ba195b1df85c38c748dab7d9f137696a5c3))
|
||||
|
||||
## [1.405.1](https://github.com/windmill-labs/windmill/compare/v1.405.0...v1.405.1) (2024-10-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* flow picker of flows + precache hub scripts as bundles ([c84e6fd](https://github.com/windmill-labs/windmill/commit/c84e6fd05de2bea426cae61fa25db0323b8770f5))
|
||||
|
||||
## [1.405.0](https://github.com/windmill-labs/windmill/compare/v1.404.1...v1.405.0) (2024-10-03)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Replace `pip-compile` with `uv` ([#4460](https://github.com/windmill-labs/windmill/issues/4460)) ([b54c9ee](https://github.com/windmill-labs/windmill/commit/b54c9ee657cc88fabe694cae39dc0d3c1918fcbb))
|
||||
* **worker:** support workers to run natively on windows ([#4446](https://github.com/windmill-labs/windmill/issues/4446)) ([f5c4727](https://github.com/windmill-labs/windmill/commit/f5c472727465dd95f5378bc08ee9bbb983f4d259))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **cli:** fix set client of instance when passing token and base url ([794c4cd](https://github.com/windmill-labs/windmill/commit/794c4cde3cd47042472dccdf4b60a012014dd26d))
|
||||
|
||||
## [1.404.1](https://github.com/windmill-labs/windmill/compare/v1.404.0...v1.404.1) (2024-10-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* flow picker of flows ([92f61f0](https://github.com/windmill-labs/windmill/commit/92f61f07ed6d354407d26843e3a270b95bae90bc))
|
||||
|
||||
## [1.404.0](https://github.com/windmill-labs/windmill/compare/v1.403.1...v1.404.0) (2024-10-03)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **frontend:** add quick access menu in flow editor ([#4415](https://github.com/windmill-labs/windmill/issues/4415)) ([45ccd45](https://github.com/windmill-labs/windmill/commit/45ccd45e306c66931880a9b8fd48bfe684c774ac))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **cli:** improve schedule path handling on windows ([9ac3b6b](https://github.com/windmill-labs/windmill/commit/9ac3b6b1d5d64d7467dd80506f8a8d772c4630bd))
|
||||
* fix id editor for app ([8e58e43](https://github.com/windmill-labs/windmill/commit/8e58e4320a31d71c40a5ed352416a4c2dd3adb26))
|
||||
* **frontend:** disable runnable field on route editor from detail panel ([#4469](https://github.com/windmill-labs/windmill/issues/4469)) ([3134f79](https://github.com/windmill-labs/windmill/commit/3134f79ced80aab86912643ab7a60dcf909ab104))
|
||||
|
||||
## [1.403.1](https://github.com/windmill-labs/windmill/compare/v1.403.0...v1.403.1) (2024-10-01)
|
||||
|
||||
|
||||
|
||||
@@ -158,6 +158,9 @@ RUN set -eux; \
|
||||
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.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 nodejs awscli && apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
@@ -172,9 +175,9 @@ RUN /usr/local/bin/python3 -m pip install pip-tools
|
||||
COPY --from=builder /frontend/build /static_frontend
|
||||
COPY --from=builder /windmill/target/release/windmill ${APP}/windmill
|
||||
|
||||
COPY --from=denoland/deno:1.46.3 --chmod=755 /usr/bin/deno /usr/bin/deno
|
||||
COPY --from=denoland/deno:2.0.0 --chmod=755 /usr/bin/deno /usr/bin/deno
|
||||
|
||||
COPY --from=oven/bun:1.1.27 /usr/local/bin/bun /usr/bin/bun
|
||||
COPY --from=oven/bun:1.1.30 /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
|
||||
|
||||
14
backend/.sqlx/query-0ee63ef2dd5c88edba2a1f56d31f29876724922f148dad7af35b36efbf70207a.json
generated
Normal file
14
backend/.sqlx/query-0ee63ef2dd5c88edba2a1f56d31f29876724922f148dad7af35b36efbf70207a.json
generated
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "DELETE FROM healthchecks WHERE check_type = $1",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "0ee63ef2dd5c88edba2a1f56d31f29876724922f148dad7af35b36efbf70207a"
|
||||
}
|
||||
15
backend/.sqlx/query-14abf759dae7ba5c38017ba6001927c6df0653a02b87bcea939066e39ebcf24d.json
generated
Normal file
15
backend/.sqlx/query-14abf759dae7ba5c38017ba6001927c6df0653a02b87bcea939066e39ebcf24d.json
generated
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO concurrency_locks (id, last_locked_at, owner)\n VALUES ($1, now(), $2)\n ON CONFLICT (id)\n DO UPDATE SET\n last_locked_at = now(),\n owner = $2",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar",
|
||||
"Varchar"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "14abf759dae7ba5c38017ba6001927c6df0653a02b87bcea939066e39ebcf24d"
|
||||
}
|
||||
24
backend/.sqlx/query-1ca5bc2d35c0498b587fd0618434def64233dc4f8fc3344d8d74be8e96ded659.json
generated
Normal file
24
backend/.sqlx/query-1ca5bc2d35c0498b587fd0618434def64233dc4f8fc3344d8d74be8e96ded659.json
generated
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT COUNT(*) FROM schedule 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": "1ca5bc2d35c0498b587fd0618434def64233dc4f8fc3344d8d74be8e96ded659"
|
||||
}
|
||||
12
backend/.sqlx/query-2041526bc58872d71f91f7698144039bd67f8e37895befa94a15b7e4019e114b.json
generated
Normal file
12
backend/.sqlx/query-2041526bc58872d71f91f7698144039bd67f8e37895befa94a15b7e4019e114b.json
generated
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "DELETE FROM healthchecks WHERE healthy = true AND created_at < NOW() - INTERVAL '14 days'",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "2041526bc58872d71f91f7698144039bd67f8e37895befa94a15b7e4019e114b"
|
||||
}
|
||||
14
backend/.sqlx/query-27920aaa55666ffc14a36a247f89ff7994ee40d3953b9f772d0e0ab999bccb7b.json
generated
Normal file
14
backend/.sqlx/query-27920aaa55666ffc14a36a247f89ff7994ee40d3953b9f772d0e0ab999bccb7b.json
generated
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO healthchecks (check_type, healthy) VALUES ($1, false)",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "27920aaa55666ffc14a36a247f89ff7994ee40d3953b9f772d0e0ab999bccb7b"
|
||||
}
|
||||
24
backend/.sqlx/query-31bc3dcea29be9cc0242771d25a232f173446d29c08fc29ddb8d55294f2c070e.json
generated
Normal file
24
backend/.sqlx/query-31bc3dcea29be9cc0242771d25a232f173446d29c08fc29ddb8d55294f2c070e.json
generated
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT COUNT(*) FROM http_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": "31bc3dcea29be9cc0242771d25a232f173446d29c08fc29ddb8d55294f2c070e"
|
||||
}
|
||||
22
backend/.sqlx/query-34a45763bb4d14162f4cd3fa07cd8020f1f6085f4ee85f5eab3458637edf26cd.json
generated
Normal file
22
backend/.sqlx/query-34a45763bb4d14162f4cd3fa07cd8020f1f6085f4ee85f5eab3458637edf26cd.json
generated
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT created_at FROM healthchecks WHERE check_type = $1 ORDER BY created_at DESC LIMIT 1",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "created_at",
|
||||
"type_info": "Timestamptz"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "34a45763bb4d14162f4cd3fa07cd8020f1f6085f4ee85f5eab3458637edf26cd"
|
||||
}
|
||||
29
backend/.sqlx/query-3ecb25b05d6c14b499f9b00af42ae74134728899f6b59c68b246979bc5143e30.json
generated
Normal file
29
backend/.sqlx/query-3ecb25b05d6c14b499f9b00af42ae74134728899f6b59c68b246979bc5143e30.json
generated
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT COUNT(*) as count, \n MIN(scheduled_for) as oldest_job\n FROM queue \n WHERE tag = $1 \n AND scheduled_for <= NOW() - $2::interval \n AND running = false\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "count",
|
||||
"type_info": "Int8"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "oldest_job",
|
||||
"type_info": "Timestamptz"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Interval"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
null,
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "3ecb25b05d6c14b499f9b00af42ae74134728899f6b59c68b246979bc5143e30"
|
||||
}
|
||||
15
backend/.sqlx/query-57e270e032e8c04dda7b5c1ca949861756b3ad367a4a500728332a7cb91560a4.json
generated
Normal file
15
backend/.sqlx/query-57e270e032e8c04dda7b5c1ca949861756b3ad367a4a500728332a7cb91560a4.json
generated
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE concurrency_locks SET\n last_locked_at = now()\n WHERE id = $1 AND owner = $2",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "57e270e032e8c04dda7b5c1ca949861756b3ad367a4a500728332a7cb91560a4"
|
||||
}
|
||||
23
backend/.sqlx/query-5fc6b4a4dbb7875bdec76f876c18543435a95b019b20081f52f6ed6f4457e3c7.json
generated
Normal file
23
backend/.sqlx/query-5fc6b4a4dbb7875bdec76f876c18543435a95b019b20081f52f6ed6f4457e3c7.json
generated
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT COUNT(*) FROM token WHERE label LIKE 'webhook-%' AND workspace_id = $1 AND scopes @> ARRAY['run:' || $2]::text[]",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "count",
|
||||
"type_info": "Int8"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "5fc6b4a4dbb7875bdec76f876c18543435a95b019b20081f52f6ed6f4457e3c7"
|
||||
}
|
||||
22
backend/.sqlx/query-5fd70c70ce52cbc51fa9124cb05f82b5951f17d1b7eade53c6d89253d55f8b9f.json
generated
Normal file
22
backend/.sqlx/query-5fd70c70ce52cbc51fa9124cb05f82b5951f17d1b7eade53c6d89253d55f8b9f.json
generated
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT owner FROM concurrency_locks WHERE id = $1",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "owner",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "5fd70c70ce52cbc51fa9124cb05f82b5951f17d1b7eade53c6d89253d55f8b9f"
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO windmill_migrations (name) VALUES ('bypassrls_1-2')",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "722a3096f03d25ef94292d53801d41037de4bc69dd434232029c731cbbcbc22f"
|
||||
}
|
||||
14
backend/.sqlx/query-900ac59515e4283f4b57516210575dfe92f74a7220ed69e61899a6e0f053d9cd.json
generated
Normal file
14
backend/.sqlx/query-900ac59515e4283f4b57516210575dfe92f74a7220ed69e61899a6e0f053d9cd.json
generated
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO concurrency_locks (id, last_locked_at) VALUES ($1, NOW()) ON CONFLICT (id) DO NOTHING",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "900ac59515e4283f4b57516210575dfe92f74a7220ed69e61899a6e0f053d9cd"
|
||||
}
|
||||
23
backend/.sqlx/query-a7f5431e3b8960e9dc46fae69dd4391516d8b169186548ec44528c84078b80d8.json
generated
Normal file
23
backend/.sqlx/query-a7f5431e3b8960e9dc46fae69dd4391516d8b169186548ec44528c84078b80d8.json
generated
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT COUNT(*) FROM token WHERE label LIKE 'email-%' AND workspace_id = $1 AND scopes @> ARRAY['run:flow/' || $2]::text[]",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "count",
|
||||
"type_info": "Int8"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "a7f5431e3b8960e9dc46fae69dd4391516d8b169186548ec44528c84078b80d8"
|
||||
}
|
||||
14
backend/.sqlx/query-ad42118ccf6a9d2d1e072c4df064ddf964a5b3cd088fc162d0d8222325d4a5ea.json
generated
Normal file
14
backend/.sqlx/query-ad42118ccf6a9d2d1e072c4df064ddf964a5b3cd088fc162d0d8222325d4a5ea.json
generated
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE healthchecks SET healthy = true WHERE check_type = $1",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "ad42118ccf6a9d2d1e072c4df064ddf964a5b3cd088fc162d0d8222325d4a5ea"
|
||||
}
|
||||
@@ -18,8 +18,8 @@
|
||||
"Left": []
|
||||
},
|
||||
"nullable": [
|
||||
true,
|
||||
false
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "b3dbdfb50ee8118bdaed3164b210cb549a34b96554ae1872355b90304f5dcb76"
|
||||
|
||||
@@ -52,7 +52,8 @@
|
||||
"trigger",
|
||||
"failure",
|
||||
"command",
|
||||
"approval"
|
||||
"approval",
|
||||
"preprocessor"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
24
backend/.sqlx/query-c060b8bbc5af7d2e7d0aaff64f0f62ec9db58611a99b0ba7f0375638b128ab89.json
generated
Normal file
24
backend/.sqlx/query-c060b8bbc5af7d2e7d0aaff64f0f62ec9db58611a99b0ba7f0375638b128ab89.json
generated
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT schedule FROM schedule WHERE path = $1 AND script_path = $1 AND is_flow = $2 AND workspace_id = $3",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "schedule",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Bool",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "c060b8bbc5af7d2e7d0aaff64f0f62ec9db58611a99b0ba7f0375638b128ab89"
|
||||
}
|
||||
23
backend/.sqlx/query-c4e1873bfc7b905e7299a021f4baa2a97e95f4797c5e11f37822e19828422b7e.json
generated
Normal file
23
backend/.sqlx/query-c4e1873bfc7b905e7299a021f4baa2a97e95f4797c5e11f37822e19828422b7e.json
generated
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE concurrency_locks SET last_locked_at = NOW() WHERE id = $1 AND last_locked_at < NOW() - INTERVAL '1 second' * $2 RETURNING 1",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "?column?",
|
||||
"type_info": "Int4"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Float8"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "c4e1873bfc7b905e7299a021f4baa2a97e95f4797c5e11f37822e19828422b7e"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO token\n (token, email, label, expiration, super_admin, scopes)\n VALUES ($1, $2, $3, $4, $5, $6)",
|
||||
"query": "INSERT INTO token\n (token, email, label, expiration, super_admin, scopes, workspace_id)\n VALUES ($1, $2, $3, $4, $5, $6, $7)",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -10,10 +10,11 @@
|
||||
"Varchar",
|
||||
"Timestamptz",
|
||||
"Bool",
|
||||
"TextArray"
|
||||
"TextArray",
|
||||
"Varchar"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "34ad8a2a5bd89b9b8e25847a7e5e94ef99e35a178ad6328c1bcde2a6d6f88cb5"
|
||||
"hash": "c624f15f3e321b1eecf123da9bf0b18e8c1d16ef25ffb9d04e5447d0d583d55c"
|
||||
}
|
||||
59
backend/.sqlx/query-c7ee7ce64686cef41cebd99ad7ef31572fc1bf12e6ae473fd58fafb025989965.json
generated
Normal file
59
backend/.sqlx/query-c7ee7ce64686cef41cebd99ad7ef31572fc1bf12e6ae473fd58fafb025989965.json
generated
Normal file
@@ -0,0 +1,59 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT label, concat(substring(token for 10)) as token_prefix, expiration, created_at, last_used_at, scopes, email FROM token WHERE workspace_id = $1 AND scopes @> ARRAY['run:script/' || $2]::text[]",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "label",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "token_prefix",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "expiration",
|
||||
"type_info": "Timestamptz"
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "created_at",
|
||||
"type_info": "Timestamptz"
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "last_used_at",
|
||||
"type_info": "Timestamptz"
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"name": "scopes",
|
||||
"type_info": "TextArray"
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"name": "email",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
true,
|
||||
null,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "c7ee7ce64686cef41cebd99ad7ef31572fc1bf12e6ae473fd58fafb025989965"
|
||||
}
|
||||
22
backend/.sqlx/query-cecf1addc4aecb087a14786b2a9165895ca61ef042947c7314f66514d7f29edc.json
generated
Normal file
22
backend/.sqlx/query-cecf1addc4aecb087a14786b2a9165895ca61ef042947c7314f66514d7f29edc.json
generated
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT last_locked_at\n FROM concurrency_locks\n WHERE id = $1\n FOR UPDATE",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "last_locked_at",
|
||||
"type_info": "Timestamp"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "cecf1addc4aecb087a14786b2a9165895ca61ef042947c7314f66514d7f29edc"
|
||||
}
|
||||
23
backend/.sqlx/query-d7a0f19f9e18d2ea49316012375ad78b69292ba091d69880945e42bebe890d66.json
generated
Normal file
23
backend/.sqlx/query-d7a0f19f9e18d2ea49316012375ad78b69292ba091d69880945e42bebe890d66.json
generated
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT COUNT(*) FROM token WHERE label LIKE 'webhook-%' AND workspace_id = $1 AND scopes @> ARRAY['run:flow/' || $2]::text[]",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "count",
|
||||
"type_info": "Int8"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "d7a0f19f9e18d2ea49316012375ad78b69292ba091d69880945e42bebe890d66"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT EXISTS(SELECT name FROM windmill_migrations WHERE name = 'bypassrls_1-2')",
|
||||
"query": "SELECT EXISTS(SELECT 1 FROM healthchecks WHERE check_type = $1 AND healthy = false)",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -10,11 +10,13 @@
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
"Left": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "eb1f916f9beea3eea83ce359f5305d0cfb0d6cdba9cc56c6139f57e46345f843"
|
||||
"hash": "eb932b613a6dbb2cdff97e5512d42b538ba83115c0ea798be00b01659600f45a"
|
||||
}
|
||||
59
backend/.sqlx/query-eff32aeac25a75d06f73e08c26dd3fd25f6b85cbea870505751c6a82457ae1da.json
generated
Normal file
59
backend/.sqlx/query-eff32aeac25a75d06f73e08c26dd3fd25f6b85cbea870505751c6a82457ae1da.json
generated
Normal file
@@ -0,0 +1,59 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT label, concat(substring(token for 10)) as token_prefix, expiration, created_at, last_used_at, scopes, email FROM token WHERE workspace_id = $1 AND scopes @> ARRAY['run:flow/' || $2]::text[]",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "label",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "token_prefix",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "expiration",
|
||||
"type_info": "Timestamptz"
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "created_at",
|
||||
"type_info": "Timestamptz"
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "last_used_at",
|
||||
"type_info": "Timestamptz"
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"name": "scopes",
|
||||
"type_info": "TextArray"
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"name": "email",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
true,
|
||||
null,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "eff32aeac25a75d06f73e08c26dd3fd25f6b85cbea870505751c6a82457ae1da"
|
||||
}
|
||||
23
backend/.sqlx/query-f06e0e4fa358b26792df22fff48b71a6fcfa1e5603ea472892917c1accd1aafb.json
generated
Normal file
23
backend/.sqlx/query-f06e0e4fa358b26792df22fff48b71a6fcfa1e5603ea472892917c1accd1aafb.json
generated
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT COUNT(*) FROM token WHERE label LIKE 'email-%' AND workspace_id = $1 AND scopes @> ARRAY['run:script/' || $2]::text[]",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "count",
|
||||
"type_info": "Int8"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "f06e0e4fa358b26792df22fff48b71a6fcfa1e5603ea472892917c1accd1aafb"
|
||||
}
|
||||
950
backend/Cargo.lock
generated
950
backend/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "windmill"
|
||||
version = "1.403.1"
|
||||
version = "1.409.2"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
@@ -27,7 +27,7 @@ members = [
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "1.403.1"
|
||||
version = "1.409.2"
|
||||
authors = ["Ruben Fiszel <ruben@windmill.dev>"]
|
||||
edition = "2021"
|
||||
|
||||
@@ -39,6 +39,9 @@ path = "./src/main.rs"
|
||||
opt-level = 0
|
||||
incremental = true
|
||||
|
||||
[profile.release]
|
||||
lto = "thin"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
enterprise = ["windmill-worker/enterprise", "windmill-queue/enterprise", "windmill-api/enterprise", "windmill-git-sync/enterprise", "windmill-common/prometheus", "windmill-common/enterprise", "windmill-indexer/enterprise"]
|
||||
@@ -47,16 +50,16 @@ stripe = ["windmill-api/stripe"]
|
||||
benchmark = ["windmill-api/benchmark", "windmill-worker/benchmark", "windmill-queue/benchmark", "windmill-common/benchmark"]
|
||||
flamegraph = ["windmill-common/flamegraph", "windmill-worker/flamegraph"]
|
||||
loki = ["windmill-common/loki"]
|
||||
pg_embed = ["dep:pg-embed"]
|
||||
embedding = ["windmill-api/embedding"]
|
||||
parquet = ["windmill-api/parquet", "windmill-common/parquet", "windmill-worker/parquet", "windmill-indexer/parquet", "dep:object_store"]
|
||||
prometheus = ["windmill-common/prometheus", "windmill-api/prometheus", "windmill-worker/prometheus", "windmill-queue/prometheus"]
|
||||
flow_testing = ["windmill-worker/flow_testing"]
|
||||
openidconnect = ["windmill-api/openidconnect"]
|
||||
openidconnect = ["windmill-api/openidconnect", "windmill-common/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"]
|
||||
sqlx = ["windmill-worker/sqlx"]
|
||||
deno_core = ["windmill-worker/deno_core", "dep:deno_core"]
|
||||
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
@@ -85,9 +88,8 @@ uuid.workspace = true
|
||||
gethostname.workspace = true
|
||||
serde_json.workspace = true
|
||||
serde.workspace = true
|
||||
deno_core.workspace = true
|
||||
deno_core = { workspace = true, optional = true }
|
||||
object_store = { workspace = true, optional = true }
|
||||
pg-embed = {git = "https://github.com/faokunega/pg-embed", optional = true, default-features = false, features = ['rt_tokio']}
|
||||
quote.workspace = true
|
||||
|
||||
|
||||
@@ -105,6 +107,7 @@ serde.workspace = true
|
||||
windmill-api-client.workspace = true
|
||||
deno_core = { workspace = true, features = ["include_js_files_for_snapshotting", "unsafe_use_unprotected_platform"] }
|
||||
|
||||
|
||||
[workspace.dependencies]
|
||||
windmill-api = { path = "./windmill-api", default-features = false }
|
||||
windmill-queue = { path = "./windmill-queue" }
|
||||
@@ -172,20 +175,24 @@ tokio-util = { version = "^0", features = ["io"] }
|
||||
json-pointer = "^0"
|
||||
itertools = "^0"
|
||||
regex = "^1"
|
||||
deno_fetch = "0.187.0"
|
||||
deno_tls = "0.150.0"
|
||||
deno_console = "0.163.0"
|
||||
deno_url = "0.163.0"
|
||||
deno_webidl = "0.163.0"
|
||||
deno_web = "0.194.0"
|
||||
deno_net = "0.155.0"
|
||||
deno_core = "0.299.0"
|
||||
deno_ast = { version = "=0.40.0", features = ["transpiling"] }
|
||||
|
||||
deno_fetch = "0.195.0"
|
||||
deno_tls = "0.158.0"
|
||||
deno_console = "0.171.0"
|
||||
deno_url = "0.171.0"
|
||||
deno_webidl = "0.171.0"
|
||||
deno_web = "0.202.0"
|
||||
deno_net = "0.163.0"
|
||||
deno_core = "0.311.0"
|
||||
deno_ast = { version = "=0.42.2", features = ["transpiling"] }
|
||||
|
||||
swc_common = "=0.37.5"
|
||||
swc_ecma_parser = "=0.149.1"
|
||||
swc_ecma_ast = "=0.118.2"
|
||||
swc_ecma_visit = "=0.104.8"
|
||||
|
||||
async-recursion = "^1"
|
||||
swc_common = "=0.33.26"
|
||||
swc_ecma_parser = "=0.144.3"
|
||||
swc_ecma_ast = "=0.113.7"
|
||||
swc_ecma_visit = "=0.99.1"
|
||||
|
||||
base64 = "0.21.0"
|
||||
base32 = "^0"
|
||||
hmac = "0.12.1"
|
||||
@@ -270,8 +277,7 @@ tikv-jemallocator = { version = "0.5" }
|
||||
tikv-jemalloc-sys = { version = "^0.5" }
|
||||
tikv-jemalloc-ctl = { version = "^0.5" }
|
||||
|
||||
# 0.1.12 broken (nested dependency of swc_common)
|
||||
triomphe = "<0.1.12"
|
||||
triomphe = "^0"
|
||||
|
||||
tantivy = "0.22.0"
|
||||
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
CREATE POLICY admin_policy ON account TO windmill_admin USING (true);
|
||||
CREATE POLICY admin_policy ON app TO windmill_admin USING (true);
|
||||
CREATE POLICY admin_policy ON audit TO windmill_admin USING (true);
|
||||
CREATE POLICY admin_policy ON capture TO windmill_admin USING (true);
|
||||
CREATE POLICY admin_policy ON completed_job TO windmill_admin USING (true);
|
||||
CREATE POLICY admin_policy ON flow TO windmill_admin USING (true);
|
||||
CREATE POLICY admin_policy ON folder TO windmill_admin USING (true);
|
||||
CREATE POLICY admin_policy ON queue TO windmill_admin USING (true);
|
||||
CREATE POLICY admin_policy ON raw_app TO windmill_admin USING (true);
|
||||
CREATE POLICY admin_policy ON resource TO windmill_admin USING (true);
|
||||
CREATE POLICY admin_policy ON schedule TO windmill_admin USING (true);
|
||||
CREATE POLICY admin_policy ON script TO windmill_admin USING (true);
|
||||
CREATE POLICY admin_policy ON usr_to_group TO windmill_admin USING (true);
|
||||
CREATE POLICY admin_policy ON variable TO windmill_admin USING (true);
|
||||
@@ -1 +1 @@
|
||||
0f5f42d2f8f5f1af05c8086f3dc7ad38d83750df
|
||||
0428068e4fbbd1380a4d8bbaab5c8e7955decdb8
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
-- Add down migration script here
|
||||
@@ -0,0 +1,2 @@
|
||||
-- Add up migration script here
|
||||
ALTER TYPE SCRIPT_KIND ADD VALUE IF NOT EXISTS 'preprocessor';
|
||||
1
backend/migrations/20241006144414_admin_policy.down.sql
Normal file
1
backend/migrations/20241006144414_admin_policy.down.sql
Normal file
@@ -0,0 +1 @@
|
||||
-- Add down migration script here
|
||||
24
backend/migrations/20241006144414_admin_policy.up.sql
Normal file
24
backend/migrations/20241006144414_admin_policy.up.sql
Normal file
@@ -0,0 +1,24 @@
|
||||
-- Add up migration script here
|
||||
DO
|
||||
$$
|
||||
DECLARE
|
||||
tbl_name text;
|
||||
policy_exists boolean;
|
||||
tbl_names text[] := ARRAY['account', 'app', 'audit', 'capture', 'completed_job', 'flow', 'folder', 'http_trigger', 'queue', 'raw_app', 'resource', 'schedule', 'script', 'usr_to_group', 'variable'];
|
||||
BEGIN
|
||||
FOR tbl_name IN SELECT unnest(tbl_names)
|
||||
LOOP
|
||||
SELECT EXISTS (
|
||||
SELECT 1
|
||||
FROM pg_policies
|
||||
WHERE schemaname = 'public'
|
||||
AND tablename = tbl_name
|
||||
AND policyname = 'admin_policy'
|
||||
) INTO policy_exists;
|
||||
|
||||
IF NOT policy_exists THEN
|
||||
EXECUTE format('CREATE POLICY admin_policy ON %I TO windmill_admin USING (true);', tbl_name);
|
||||
END IF;
|
||||
END LOOP;
|
||||
END;
|
||||
$$;
|
||||
@@ -0,0 +1,2 @@
|
||||
-- Drop the alert_locks table
|
||||
DROP TABLE IF EXISTS concurrency_locks;
|
||||
@@ -0,0 +1,6 @@
|
||||
-- Create the alert_locks table
|
||||
CREATE TABLE concurrency_locks (
|
||||
id VARCHAR PRIMARY KEY,
|
||||
last_locked_at TIMESTAMP NOT NULL,
|
||||
owner VARCHAR NULL
|
||||
);
|
||||
@@ -15,13 +15,13 @@ use windmill_parser::{
|
||||
|
||||
use swc_common::{sync::Lrc, FileName, SourceMap, SourceMapper, Span, Spanned};
|
||||
use swc_ecma_ast::{
|
||||
ArrayLit, AssignPat, BigInt, BindingIdent, Bool, Decl, ExportDecl, Expr, FnDecl, Ident, Lit,
|
||||
MemberExpr, MemberProp, ModuleDecl, ModuleItem, Number, ObjectLit, ObjectPat, Param, Pat, Str,
|
||||
TsArrayType, TsEntityName, TsKeywordType, TsKeywordTypeKind, TsLit, TsLitType, TsOptionalType,
|
||||
TsParenthesizedType, TsPropertySignature, TsType, TsTypeAnn, TsTypeElement, TsTypeLit,
|
||||
TsTypeRef, TsUnionOrIntersectionType, TsUnionType,
|
||||
ArrayLit, AssignPat, BigInt, BindingIdent, Bool, Decl, ExportDecl, Expr, FnDecl, Ident,
|
||||
IdentName, Lit, MemberExpr, MemberProp, ModuleDecl, ModuleItem, Number, ObjectLit, ObjectPat,
|
||||
Param, Pat, Str, TsArrayType, TsEntityName, TsKeywordType, TsKeywordTypeKind, TsLit, TsLitType,
|
||||
TsOptionalType, TsParenthesizedType, TsPropertySignature, TsType, TsTypeAnn, TsTypeElement,
|
||||
TsTypeLit, TsTypeRef, TsUnionOrIntersectionType, TsUnionType,
|
||||
};
|
||||
use swc_ecma_parser::{lexer::Lexer, EsConfig, Parser, StringInput, Syntax, TsConfig};
|
||||
use swc_ecma_parser::{lexer::Lexer, EsSyntax, Parser, StringInput, Syntax, TsSyntax};
|
||||
|
||||
use regex::Regex;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
@@ -48,9 +48,9 @@ impl Visit for ImportsFinder {
|
||||
|
||||
pub fn parse_expr_for_imports(code: &str) -> anyhow::Result<Vec<String>> {
|
||||
let cm: Lrc<SourceMap> = Default::default();
|
||||
let fm = cm.new_source_file(FileName::Custom("main.d.ts".into()), code.into());
|
||||
let fm = cm.new_source_file(FileName::Custom("main.d.ts".into()).into(), code.into());
|
||||
let lexer = Lexer::new(
|
||||
Syntax::Typescript(TsConfig::default()),
|
||||
Syntax::Typescript(TsSyntax::default()),
|
||||
// EsVersion defaults to es5
|
||||
Default::default(),
|
||||
StringInput::from(&*fm),
|
||||
@@ -69,7 +69,7 @@ pub fn parse_expr_for_imports(code: &str) -> anyhow::Result<Vec<String>> {
|
||||
})?;
|
||||
|
||||
let mut visitor = ImportsFinder { imports: HashSet::new() };
|
||||
swc_ecma_visit::visit_module(&mut visitor, &expr);
|
||||
visitor.visit_module(&expr);
|
||||
|
||||
Ok(visitor.imports.into_iter().collect())
|
||||
}
|
||||
@@ -87,7 +87,7 @@ impl Visit for OutputFinder {
|
||||
c.visit_with(self);
|
||||
}
|
||||
match m {
|
||||
MemberExpr { obj, prop: MemberProp::Ident(Ident { sym, .. }), .. } => {
|
||||
MemberExpr { obj, prop: MemberProp::Ident(IdentName { sym, .. }), .. } => {
|
||||
match *obj.to_owned() {
|
||||
Expr::Ident(Ident { sym: sym_i, .. }) => {
|
||||
self.idents.insert((sym_i.to_string(), sym.to_string()));
|
||||
@@ -102,10 +102,10 @@ impl Visit for OutputFinder {
|
||||
|
||||
pub fn parse_expr_for_ids(code: &str) -> anyhow::Result<Vec<(String, String)>> {
|
||||
let cm: Lrc<SourceMap> = Default::default();
|
||||
let fm = cm.new_source_file(FileName::Custom("main.ts".into()), code.into());
|
||||
let fm = cm.new_source_file(FileName::Custom("main.ts".into()).into(), code.into());
|
||||
let lexer = Lexer::new(
|
||||
// We want to parse ecmascript
|
||||
Syntax::Es(EsConfig { jsx: false, ..Default::default() }),
|
||||
Syntax::Es(EsSyntax { jsx: false, ..Default::default() }),
|
||||
// EsVersion defaults to es5
|
||||
Default::default(),
|
||||
StringInput::from(&*fm),
|
||||
@@ -124,7 +124,7 @@ pub fn parse_expr_for_ids(code: &str) -> anyhow::Result<Vec<(String, String)>> {
|
||||
})?;
|
||||
|
||||
let mut visitor = OutputFinder { idents: HashSet::new() };
|
||||
swc_ecma_visit::visit_module(&mut visitor, &expr);
|
||||
visitor.visit_module(&expr);
|
||||
|
||||
Ok(visitor.idents.into_iter().collect())
|
||||
}
|
||||
@@ -135,10 +135,10 @@ pub fn parse_deno_signature(
|
||||
main_override: Option<String>,
|
||||
) -> anyhow::Result<MainArgSignature> {
|
||||
let cm: Lrc<SourceMap> = Default::default();
|
||||
let fm = cm.new_source_file(FileName::Custom("main.ts".into()), code.into());
|
||||
let fm = cm.new_source_file(FileName::Custom("main.ts".into()).into(), code.into());
|
||||
let lexer = Lexer::new(
|
||||
// We want to parse ecmascript
|
||||
Syntax::Typescript(TsConfig::default()),
|
||||
Syntax::Typescript(TsSyntax::default()),
|
||||
// EsVersion defaults to es5
|
||||
Default::default(),
|
||||
StringInput::from(&*fm),
|
||||
|
||||
@@ -399,15 +399,11 @@ fn parse_ansible_options(opts: &Vec<Yaml>) -> AnsiblePlaybookOptions {
|
||||
if c > 0 && c <= 6 {
|
||||
ret.verbosity = Some("v".repeat(c.min(6)));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
_ => ()
|
||||
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -422,10 +418,10 @@ fn count_consecutive_vs(s: &str) -> usize {
|
||||
if c == 'v' {
|
||||
current_count += 1;
|
||||
if current_count == 6 {
|
||||
return 6; // Stop early if we reach 6
|
||||
return 6; // Stop early if we reach 6
|
||||
}
|
||||
} else {
|
||||
current_count = 0; // Reset count if the character is not 'v'
|
||||
current_count = 0; // Reset count if the character is not 'v'
|
||||
}
|
||||
max_count = max_count.max(current_count);
|
||||
}
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
use anyhow::anyhow;
|
||||
#[cfg(feature = "enterprise")]
|
||||
use windmill_common::error::{Error, Result};
|
||||
|
||||
pub async fn set_license_key(_license_key: String) -> anyhow::Result<()> {
|
||||
// Implementation is not open source
|
||||
Err(anyhow!("License cannot be set in Windmill CE"))
|
||||
}
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
pub async fn verify_license_key() -> Result<()> {
|
||||
// Implementation is not open source
|
||||
Err(Error::InternalErr(
|
||||
"License always invalid in Windmill CE".to_string(),
|
||||
))
|
||||
}
|
||||
1
backend/src/ee.rs
Symbolic link
1
backend/src/ee.rs
Symbolic link
@@ -0,0 +1 @@
|
||||
/git/windmill/../windmill-ee-private/src/ee.rs
|
||||
@@ -67,7 +67,7 @@ use windmill_worker::{
|
||||
get_hub_script_content_and_requirements, BUN_BUNDLE_CACHE_DIR, BUN_CACHE_DIR,
|
||||
BUN_DEPSTAR_CACHE_DIR, DENO_CACHE_DIR, DENO_CACHE_DIR_DEPS, DENO_CACHE_DIR_NPM,
|
||||
GO_BIN_CACHE_DIR, GO_CACHE_DIR, LOCK_CACHE_DIR, PIP_CACHE_DIR, POWERSHELL_CACHE_DIR,
|
||||
RUST_CACHE_DIR, TAR_PIP_CACHE_DIR, TMP_LOGS_DIR,
|
||||
RUST_CACHE_DIR, TAR_PIP_CACHE_DIR, TMP_LOGS_DIR, UV_CACHE_DIR,
|
||||
};
|
||||
|
||||
use crate::monitor::{
|
||||
@@ -92,9 +92,6 @@ const DEFAULT_SERVER_BIND_ADDR: Ipv4Addr = Ipv4Addr::new(0, 0, 0, 0);
|
||||
mod ee;
|
||||
mod monitor;
|
||||
|
||||
#[cfg(feature = "pg_embed")]
|
||||
mod pg_embed;
|
||||
|
||||
#[inline(always)]
|
||||
fn create_and_run_current_thread_inner<F, R>(future: F) -> R
|
||||
where
|
||||
@@ -118,7 +115,8 @@ where
|
||||
}
|
||||
|
||||
pub fn main() -> anyhow::Result<()> {
|
||||
deno_core::JsRuntime::init_platform(None);
|
||||
#[cfg(feature = "deno_core")]
|
||||
deno_core::JsRuntime::init_platform(None, false);
|
||||
create_and_run_current_thread_inner(windmill_main())
|
||||
}
|
||||
|
||||
@@ -137,6 +135,7 @@ async fn cache_hub_scripts(file_path: Option<String>) -> anyhow::Result<()> {
|
||||
})?;
|
||||
|
||||
create_dir_all(HUB_CACHE_DIR).await?;
|
||||
create_dir_all(BUN_BUNDLE_CACHE_DIR).await?;
|
||||
|
||||
for path in paths.values() {
|
||||
tracing::info!("Caching hub script at {path}");
|
||||
@@ -168,7 +167,7 @@ async fn cache_hub_scripts(file_path: Option<String>) -> anyhow::Result<()> {
|
||||
create_dir_all(&job_dir).await?;
|
||||
if let Some(lockfile) = res.lockfile {
|
||||
let _ = windmill_worker::prepare_job_dir(&lockfile, &job_dir).await?;
|
||||
|
||||
let envs = windmill_worker::get_common_bun_proc_envs(None).await;
|
||||
let _ = windmill_worker::install_bun_lockfile(
|
||||
&mut 0,
|
||||
&mut None,
|
||||
@@ -177,11 +176,31 @@ async fn cache_hub_scripts(file_path: Option<String>) -> anyhow::Result<()> {
|
||||
None,
|
||||
&job_dir,
|
||||
"cache_init",
|
||||
windmill_worker::get_common_bun_proc_envs(None).await,
|
||||
envs.clone(),
|
||||
false,
|
||||
&mut None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let _ = windmill_common::worker::write_file(&job_dir, "main.js", &res.content)?;
|
||||
|
||||
if let Err(e) = windmill_worker::prebundle_bun_script(
|
||||
&res.content,
|
||||
Some(lockfile),
|
||||
&path,
|
||||
&job_id,
|
||||
"admins",
|
||||
None,
|
||||
&job_dir,
|
||||
"",
|
||||
"cache_init",
|
||||
"",
|
||||
&mut None,
|
||||
)
|
||||
.await
|
||||
{
|
||||
panic!("Error prebundling bun script: {e:#}");
|
||||
}
|
||||
} else {
|
||||
tracing::warn!("No lockfile found for bun script {path}, skipping...");
|
||||
}
|
||||
@@ -341,14 +360,6 @@ async fn windmill_main() -> anyhow::Result<()> {
|
||||
config
|
||||
});
|
||||
|
||||
#[cfg(feature = "pg_embed")]
|
||||
let _pg = {
|
||||
let (db_url, pg) = pg_embed::start().await.expect("pg embed");
|
||||
tracing::info!("Use embedded pg: {db_url}");
|
||||
std::env::set_var("DATABASE_URL", db_url);
|
||||
pg
|
||||
};
|
||||
|
||||
tracing::info!("Connecting to database...");
|
||||
let db = windmill_common::connect_db(server_mode, indexer_mode).await?;
|
||||
tracing::info!("Database connected");
|
||||
@@ -373,8 +384,16 @@ async fn windmill_main() -> anyhow::Result<()> {
|
||||
let is_agent = mode == Mode::Agent;
|
||||
|
||||
if !is_agent {
|
||||
// migration code to avoid break
|
||||
windmill_api::migrate_db(&db).await?;
|
||||
let skip_migration = std::env::var("SKIP_MIGRATION")
|
||||
.map(|val| val == "true")
|
||||
.unwrap_or(false);
|
||||
|
||||
if !skip_migration {
|
||||
// migration code to avoid break
|
||||
windmill_api::migrate_db(&db).await?;
|
||||
} else {
|
||||
tracing::info!("SKIP_MIGRATION set, skipping db migration...")
|
||||
}
|
||||
}
|
||||
|
||||
let (killpill_tx, mut killpill_rx) = tokio::sync::broadcast::channel::<()>(2);
|
||||
@@ -457,7 +476,7 @@ Windmill Community Edition {GIT_VERSION}
|
||||
|
||||
#[cfg(feature = "tantivy")]
|
||||
let (index_reader, index_writer) = if should_index_jobs {
|
||||
let (r, w) = windmill_indexer::indexer_ee::init_index().await?;
|
||||
let (r, w) = windmill_indexer::indexer_ee::init_index(&db).await?;
|
||||
(Some(r), Some(w))
|
||||
} else {
|
||||
(None, None)
|
||||
@@ -874,6 +893,7 @@ pub async fn run_workers<R: rsmq_async::RsmqConnection + Send + Sync + Clone + '
|
||||
LOCK_CACHE_DIR,
|
||||
TMP_LOGS_DIR,
|
||||
PIP_CACHE_DIR,
|
||||
UV_CACHE_DIR,
|
||||
TAR_PIP_CACHE_DIR,
|
||||
DENO_CACHE_DIR,
|
||||
DENO_CACHE_DIR_DEPS,
|
||||
|
||||
@@ -27,7 +27,7 @@ use windmill_api::{
|
||||
DEFAULT_BODY_LIMIT, IS_SECURE, OAUTH_CLIENTS, REQUEST_SIZE_LIMIT, SAML_METADATA, SCIM_TOKEN,
|
||||
};
|
||||
#[cfg(feature = "enterprise")]
|
||||
use windmill_common::ee::worker_groups_alerts;
|
||||
use windmill_common::ee::{worker_groups_alerts, jobs_waiting_alerts};
|
||||
use windmill_common::{
|
||||
auth::JWT_SECRET,
|
||||
ee::CriticalErrorChannel,
|
||||
@@ -1061,12 +1061,20 @@ pub async fn monitor_db(
|
||||
}
|
||||
};
|
||||
|
||||
let jobs_waiting_alerts_f = async {
|
||||
#[cfg(feature = "enterprise")]
|
||||
if server_mode {
|
||||
jobs_waiting_alerts(&db).await;
|
||||
}
|
||||
};
|
||||
|
||||
join!(
|
||||
expired_items_f,
|
||||
zombie_jobs_f,
|
||||
expose_queue_metrics_f,
|
||||
verify_license_key_f,
|
||||
worker_groups_alerts_f
|
||||
worker_groups_alerts_f,
|
||||
jobs_waiting_alerts_f,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
use pg_embed::pg_enums::PgAuthMethod;
|
||||
use pg_embed::pg_fetch::PgFetchSettings;
|
||||
use pg_embed::postgres::{PgEmbed, PgSettings};
|
||||
use std::path::PathBuf;
|
||||
use std::time::Duration;
|
||||
|
||||
pub async fn start() -> anyhow::Result<(String, PgEmbed)> {
|
||||
let pg_settings = PgSettings {
|
||||
database_dir: PathBuf::from("/tmp/db"),
|
||||
port: 6543,
|
||||
user: "postgres".to_string(),
|
||||
password: "password".to_string(),
|
||||
auth_method: PgAuthMethod::Plain,
|
||||
persistent: false,
|
||||
timeout: Some(Duration::from_secs(15)),
|
||||
migration_dir: None,
|
||||
};
|
||||
|
||||
let fetch_settings = PgFetchSettings {
|
||||
version: pg_embed::pg_fetch::PostgresVersion("15.3.0"),
|
||||
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
tracing::info!(
|
||||
"Fetch settings: {:?} {:?}",
|
||||
fetch_settings.operating_system,
|
||||
fetch_settings.architecture
|
||||
);
|
||||
|
||||
let mut pg = PgEmbed::new(pg_settings, fetch_settings).await?;
|
||||
|
||||
pg.setup().await.expect("pg setup");
|
||||
|
||||
pg.start_db().await.expect("pg start db");
|
||||
|
||||
//TODO: re-enable this to make it work
|
||||
// if !pg.database_exists("windmill").await.expect("db exists") {
|
||||
// pg.create_database("windmill")
|
||||
// .await
|
||||
// .expect("pg create database");
|
||||
// }
|
||||
|
||||
let uri = pg.full_db_uri("windmill");
|
||||
Ok((uri, pg))
|
||||
}
|
||||
@@ -2745,7 +2745,7 @@ async fn test_flow_lock_all(db: Pool<Postgres>) {
|
||||
"lock": null,
|
||||
"path": null,
|
||||
"type": "rawscript",
|
||||
"content": "import * as wmill from \"https://deno.land/x/windmill@v1.50.0/mod.ts\"\n\nexport async function main() {\n return \"Hello\"\n}\n",
|
||||
"content": "import * as wmill from \"https://deno.land/x/windmill@v1.50.0/mod.ts\"\n\nexport async function main() {\n return wmill\n}\n",
|
||||
"language": "deno",
|
||||
"input_transforms": {}
|
||||
},
|
||||
|
||||
@@ -17,7 +17,7 @@ benchmark = []
|
||||
embedding = ["dep:tinyvector", "dep:hf-hub", "dep:tokenizers", "dep:candle-core", "dep:candle-transformers", "dep:candle-nn"]
|
||||
parquet = ["dep:datafusion", "dep:object_store", "dep:url", "windmill-common/parquet"]
|
||||
prometheus = ["windmill-common/prometheus", "windmill-queue/prometheus", "dep:prometheus"]
|
||||
openidconnect = ["dep:openidconnect"]
|
||||
openidconnect = ["dep:openidconnect", "windmill-common/openidconnect"]
|
||||
tantivy = ["dep:windmill-indexer"]
|
||||
|
||||
[dependencies]
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
openapi: "3.0.3"
|
||||
|
||||
info:
|
||||
version: 1.403.1
|
||||
version: 1.409.2
|
||||
title: Windmill API
|
||||
|
||||
contact:
|
||||
@@ -2789,7 +2789,14 @@ paths:
|
||||
oauth:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
type: string
|
||||
display_name:
|
||||
type: string
|
||||
required:
|
||||
- type
|
||||
saml:
|
||||
type: string
|
||||
required:
|
||||
@@ -4013,6 +4020,42 @@ paths:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Script"
|
||||
|
||||
/w/{workspace}/scripts/get_triggers_count/{path}:
|
||||
get:
|
||||
summary: get triggers count of script
|
||||
operationId: getTriggersCountOfScript
|
||||
tags:
|
||||
- script
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/WorkspaceId"
|
||||
- $ref: "#/components/parameters/ScriptPath"
|
||||
responses:
|
||||
"200":
|
||||
description: triggers count
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/TriggersCount"
|
||||
|
||||
/w/{workspace}/scripts/list_tokens/{path}:
|
||||
get:
|
||||
summary: get tokens with script scope
|
||||
operationId: listTokensOfScript
|
||||
tags:
|
||||
- script
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/WorkspaceId"
|
||||
- $ref: "#/components/parameters/ScriptPath"
|
||||
responses:
|
||||
"200":
|
||||
description: tokens list
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/TruncatedToken"
|
||||
|
||||
/w/{workspace}/scripts/get/draft/{path}:
|
||||
get:
|
||||
summary: get script by path with draft
|
||||
@@ -4617,6 +4660,43 @@ paths:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Flow"
|
||||
|
||||
/w/{workspace}/flows/get_triggers_count/{path}:
|
||||
get:
|
||||
summary: get triggers count of flow
|
||||
operationId: getTriggersCountOfFlow
|
||||
tags:
|
||||
- flow
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/WorkspaceId"
|
||||
- $ref: "#/components/parameters/ScriptPath"
|
||||
responses:
|
||||
"200":
|
||||
description: triggers count
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/TriggersCount"
|
||||
|
||||
/w/{workspace}/flows/list_tokens/{path}:
|
||||
get:
|
||||
summary: get tokens with flow scope
|
||||
operationId: listTokensOfFlow
|
||||
tags:
|
||||
- flow
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/WorkspaceId"
|
||||
- $ref: "#/components/parameters/ScriptPath"
|
||||
responses:
|
||||
"200":
|
||||
description: tokens list
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/TruncatedToken"
|
||||
|
||||
|
||||
/w/{workspace}/flows/toggle_workspace_error_handler/{path}:
|
||||
post:
|
||||
summary: Toggle ON and OFF the workspace error handler for a given flow
|
||||
@@ -10247,6 +10327,8 @@ components:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
email:
|
||||
type: string
|
||||
required:
|
||||
- token_prefix
|
||||
- created_at
|
||||
@@ -10264,6 +10346,8 @@ components:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
workspace_id:
|
||||
type: string
|
||||
|
||||
NewTokenImpersonate:
|
||||
type: object
|
||||
@@ -10275,6 +10359,8 @@ components:
|
||||
format: date-time
|
||||
impersonate_email:
|
||||
type: string
|
||||
workspace_id:
|
||||
type: string
|
||||
required:
|
||||
- impersonate_email
|
||||
|
||||
@@ -11111,6 +11197,23 @@ components:
|
||||
- requires_auth
|
||||
- http_method
|
||||
|
||||
TriggersCount:
|
||||
type: object
|
||||
properties:
|
||||
primary_schedule:
|
||||
type: object
|
||||
properties:
|
||||
schedule:
|
||||
type: string
|
||||
schedule_count:
|
||||
type: number
|
||||
http_routes_count:
|
||||
type: number
|
||||
webhook_count:
|
||||
type: number
|
||||
email_count:
|
||||
type: number
|
||||
|
||||
Group:
|
||||
type: object
|
||||
properties:
|
||||
|
||||
@@ -199,11 +199,6 @@ pub async fn migrate(db: &DB) -> Result<(), Error> {
|
||||
Err(err) => Err(err),
|
||||
}?;
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
if let Err(e) = windmill_migrations(&mut custom_migrator, db).await {
|
||||
tracing::error!("Could not apply windmill custom migrations: {e:#}")
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -497,33 +492,6 @@ async fn fix_job_completed_index(db: &DB) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
async fn windmill_migrations(migrator: &mut CustomMigrator, db: &DB) -> Result<(), Error> {
|
||||
if std::env::var("MIGRATION_NO_BYPASSRLS").is_ok() {
|
||||
migrator.lock().await?;
|
||||
let has_done_migration = sqlx::query_scalar!(
|
||||
"SELECT EXISTS(SELECT name FROM windmill_migrations WHERE name = 'bypassrls_1-2')",
|
||||
)
|
||||
.fetch_one(db)
|
||||
.await?
|
||||
.unwrap_or(false);
|
||||
|
||||
if !has_done_migration {
|
||||
let query = include_str!("../../custom_migrations/bypassrls_1.sql");
|
||||
tracing::info!("Applying bypassrls_1.sql");
|
||||
let mut tx: sqlx::Transaction<'_, Postgres> = db.begin().await?;
|
||||
tx.execute(query).await?;
|
||||
tracing::info!("Applied bypassrls_1.sql");
|
||||
sqlx::query!("INSERT INTO windmill_migrations (name) VALUES ('bypassrls_1-2')")
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
tx.commit().await?;
|
||||
}
|
||||
migrator.unlock().await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ApiAuthed {
|
||||
pub email: String,
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
use anyhow::anyhow;
|
||||
#[cfg(feature = "enterprise")]
|
||||
use std::sync::Arc;
|
||||
#[cfg(feature = "enterprise")]
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
pub async fn validate_license_key(_license_key: String) -> anyhow::Result<String> {
|
||||
// Implementation is not open source
|
||||
Err(anyhow!("License can't be validated in Windmill CE"))
|
||||
}
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
pub async fn jwt_ext_auth(
|
||||
_w_id: Option<&String>,
|
||||
_token: &str,
|
||||
_external_jwks: Option<Arc<RwLock<ExternalJwks>>>,
|
||||
) -> anyhow::Result<(crate::db::ApiAuthed, usize)> {
|
||||
// Implementation is not open source
|
||||
|
||||
Err(anyhow!("External JWT auth is not open source"))
|
||||
}
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
pub struct ExternalJwks;
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
impl ExternalJwks {
|
||||
pub async fn load() -> Option<Arc<RwLock<Self>>> {
|
||||
// Implementation is not open source
|
||||
None
|
||||
}
|
||||
}
|
||||
1
backend/windmill-api/src/ee.rs
Symbolic link
1
backend/windmill-api/src/ee.rs
Symbolic link
@@ -0,0 +1 @@
|
||||
/git/windmill/../windmill-ee-private/windmill-api/src/ee.rs
|
||||
@@ -9,6 +9,9 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::db::ApiAuthed;
|
||||
use crate::triggers::{
|
||||
get_triggers_count_internal, list_tokens_internal, TriggersCount, TruncatedTokenWithEmail,
|
||||
};
|
||||
use crate::utils::WithStarredInfoQuery;
|
||||
use crate::{
|
||||
db::DB,
|
||||
@@ -53,6 +56,8 @@ pub fn workspaced_service() -> Router {
|
||||
.route("/update/*path", post(update_flow))
|
||||
.route("/archive/*path", post(archive_flow_by_path))
|
||||
.route("/delete/*path", delete(delete_flow_by_path))
|
||||
.route("/get_triggers_count/*path", get(get_triggers_count))
|
||||
.route("/list_tokens/*path", get(list_tokens))
|
||||
.route("/get/*path", get(get_flow_by_path))
|
||||
.route("/get/draft/*path", get(get_flow_by_path_w_draft))
|
||||
.route("/exists/*path", get(exists_flow_by_path))
|
||||
@@ -874,6 +879,22 @@ async fn update_flow(
|
||||
Ok(nf.path.to_string())
|
||||
}
|
||||
|
||||
async fn get_triggers_count(
|
||||
Extension(db): Extension<DB>,
|
||||
Path((w_id, path)): Path<(String, StripPath)>,
|
||||
) -> JsonResult<TriggersCount> {
|
||||
let path = path.to_path();
|
||||
get_triggers_count_internal(&db, &w_id, &path, true).await
|
||||
}
|
||||
|
||||
async fn list_tokens(
|
||||
Extension(db): Extension<DB>,
|
||||
Path((w_id, path)): Path<(String, StripPath)>,
|
||||
) -> JsonResult<Vec<TruncatedTokenWithEmail>> {
|
||||
let path = path.to_path();
|
||||
list_tokens_internal(&db, &w_id, &path, true).await
|
||||
}
|
||||
|
||||
async fn get_flow_by_path(
|
||||
authed: ApiAuthed,
|
||||
Extension(user_db): Extension<UserDB>,
|
||||
|
||||
@@ -275,8 +275,10 @@ pub fn require_is_owner(authed: &ApiAuthed, name: &str) -> Result<()> {
|
||||
|
||||
async fn update_folder(
|
||||
authed: ApiAuthed,
|
||||
Extension(db): Extension<DB>,
|
||||
Extension(user_db): Extension<UserDB>,
|
||||
Extension(webhook): Extension<WebhookShared>,
|
||||
Extension(rsmq): Extension<Option<rsmq_async::MultiplexedRsmq>>,
|
||||
Path((w_id, name)): Path<(String, String)>,
|
||||
Json(mut ng): Json<UpdateFolder>,
|
||||
) -> Result<String> {
|
||||
@@ -367,6 +369,18 @@ async fn update_folder(
|
||||
}
|
||||
}
|
||||
|
||||
handle_deployment_metadata(
|
||||
&authed.email,
|
||||
&authed.username,
|
||||
&db,
|
||||
&w_id,
|
||||
DeployedObject::Folder { path: format!("f/{}", name) },
|
||||
Some(format!("Folder '{}' updated", name)),
|
||||
rsmq,
|
||||
true,
|
||||
)
|
||||
.await?;
|
||||
|
||||
audit_log(
|
||||
&mut *tx,
|
||||
&authed,
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
use axum::Router;
|
||||
|
||||
pub fn workspaced_service() -> Router {
|
||||
Router::new()
|
||||
}
|
||||
1
backend/windmill-api/src/indexer_ee.rs
Symbolic link
1
backend/windmill-api/src/indexer_ee.rs
Symbolic link
@@ -0,0 +1 @@
|
||||
/git/windmill/../windmill-ee-private/windmill-api/src/indexer_ee.rs
|
||||
@@ -1,5 +0,0 @@
|
||||
use axum::Router;
|
||||
|
||||
pub fn workspaced_service() -> Router {
|
||||
Router::new()
|
||||
}
|
||||
1
backend/windmill-api/src/job_helpers_ee.rs
Symbolic link
1
backend/windmill-api/src/job_helpers_ee.rs
Symbolic link
@@ -0,0 +1 @@
|
||||
/git/windmill/../windmill-ee-private/windmill-api/src/job_helpers_ee.rs
|
||||
@@ -11,7 +11,6 @@ use axum::http::HeaderValue;
|
||||
use quick_cache::sync::Cache;
|
||||
use serde_json::value::RawValue;
|
||||
use sqlx::Pool;
|
||||
use windmill_common::error::JsonResult;
|
||||
use std::collections::HashMap;
|
||||
#[cfg(feature = "prometheus")]
|
||||
use std::sync::atomic::Ordering;
|
||||
@@ -19,12 +18,13 @@ use tokio::io::AsyncReadExt;
|
||||
#[cfg(feature = "prometheus")]
|
||||
use tokio::time::Instant;
|
||||
use tower::ServiceBuilder;
|
||||
use windmill_common::error::JsonResult;
|
||||
use windmill_common::flow_status::{JobResult, RestartedFrom};
|
||||
use windmill_common::jobs::{
|
||||
format_completed_job_result, format_result, CompletedJobWithFormattedResult, FormattedResult,
|
||||
ENTRYPOINT_OVERRIDE,
|
||||
};
|
||||
use windmill_common::worker::TMP_DIR;
|
||||
use windmill_common::worker::{CLOUD_HOSTED, TMP_DIR};
|
||||
|
||||
#[cfg(all(feature = "enterprise", feature = "parquet"))]
|
||||
use windmill_common::scripts::PREVIEW_IS_CODEBASE_HASH;
|
||||
@@ -81,7 +81,7 @@ use windmill_common::{METRICS_DEBUG_ENABLED, METRICS_ENABLED};
|
||||
use windmill_common::{get_latest_deployed_hash_for_path, BASE_URL};
|
||||
use windmill_queue::{
|
||||
cancel_job, get_queued_job, get_result_by_id_from_running_flow, job_is_complete, push,
|
||||
DecodeQueries, PushArgs, PushArgsOwned, PushIsolationLevel, QueueTransaction,
|
||||
DecodeQueries, PushArgs, PushArgsOwned, PushIsolationLevel,
|
||||
};
|
||||
|
||||
#[cfg(feature = "prometheus")]
|
||||
@@ -293,11 +293,8 @@ pub fn workspace_unauthed_service() -> Router {
|
||||
|
||||
pub fn global_root_service() -> Router {
|
||||
Router::new()
|
||||
.route("/db_clock", get(get_db_clock))
|
||||
.route(
|
||||
"/completed/count_by_tag",
|
||||
get(count_by_tag),
|
||||
)
|
||||
.route("/db_clock", get(get_db_clock))
|
||||
.route("/completed/count_by_tag", get(count_by_tag))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
@@ -547,8 +544,8 @@ pub async fn get_path_for_hash<'c>(
|
||||
Ok(path)
|
||||
}
|
||||
|
||||
pub async fn get_path_tag_limits_cache_for_hash<'c, R: rsmq_async::RsmqConnection + Send>(
|
||||
tx: &mut QueueTransaction<'c, R>,
|
||||
pub async fn get_path_tag_limits_cache_for_hash(
|
||||
tx: &DB,
|
||||
w_id: &str,
|
||||
hash: i64,
|
||||
) -> error::Result<(
|
||||
@@ -1472,6 +1469,8 @@ async fn cancel_jobs(
|
||||
}
|
||||
}
|
||||
|
||||
uuids.extend(trivial_jobs);
|
||||
|
||||
Ok(Json(uuids))
|
||||
}
|
||||
|
||||
@@ -2813,7 +2812,6 @@ pub async fn run_flow_by_path_inner(
|
||||
let flow_path = flow_path.to_path();
|
||||
check_scopes(&authed, || format!("run:flow/{flow_path}"))?;
|
||||
|
||||
let mut tx: QueueTransaction<'_, _> = (rsmq, user_db.begin(&authed).await?).into();
|
||||
|
||||
let (tag, dedicated_worker, has_preprocessor) = sqlx::query!(
|
||||
"SELECT tag, dedicated_worker, flow_version.value->>'preprocessor_module' IS NOT NULL as has_preprocessor
|
||||
@@ -2824,7 +2822,7 @@ pub async fn run_flow_by_path_inner(
|
||||
flow_path,
|
||||
w_id
|
||||
)
|
||||
.fetch_optional(&mut tx)
|
||||
.fetch_optional(&db)
|
||||
.await?
|
||||
.map(|x| (x.tag, x.dedicated_worker, x.has_preprocessor))
|
||||
.ok_or_else(|| {
|
||||
@@ -2837,7 +2835,7 @@ pub async fn run_flow_by_path_inner(
|
||||
|
||||
check_tag_available_for_workspace(&w_id, &tag).await?;
|
||||
let scheduled_for = run_query.get_scheduled_for(&db).await?;
|
||||
let tx = PushIsolationLevel::Transaction(tx);
|
||||
let tx = PushIsolationLevel::Isolated(user_db, authed.clone().into(), rsmq);
|
||||
let (uuid, tx) = push(
|
||||
&db,
|
||||
tx,
|
||||
@@ -2909,14 +2907,13 @@ pub async fn restart_flow(
|
||||
) -> error::Result<(StatusCode, String)> {
|
||||
check_license_key_valid().await?;
|
||||
|
||||
let mut tx: QueueTransaction<'_, _> = (rsmq, user_db.begin(&authed).await?).into();
|
||||
|
||||
let completed_job = sqlx::query_as::<_, CompletedJob>(
|
||||
"SELECT *, result->'wm_labels' as labels from completed_job WHERE id = $1 and workspace_id = $2",
|
||||
)
|
||||
.bind(job_id)
|
||||
.bind(&w_id)
|
||||
.fetch_optional(&mut tx)
|
||||
.fetch_optional(&db)
|
||||
.await?
|
||||
.with_context(|| "Unable to find completed job with the given job UUID")?;
|
||||
|
||||
@@ -2934,7 +2931,7 @@ pub async fn restart_flow(
|
||||
|
||||
let scheduled_for = run_query.get_scheduled_for(&db).await?;
|
||||
|
||||
let tx = PushIsolationLevel::Transaction(tx);
|
||||
let tx = PushIsolationLevel::Isolated(user_db, authed.clone().into(), rsmq);
|
||||
|
||||
let (uuid, tx) = push(
|
||||
&db,
|
||||
@@ -3010,16 +3007,16 @@ pub async fn run_script_by_path_inner(
|
||||
|
||||
check_scopes(&authed, || format!("run:script/{script_path}"))?;
|
||||
|
||||
let mut tx: QueueTransaction<'_, _> = (rsmq, user_db.begin(&authed).await?).into();
|
||||
|
||||
let (job_payload, tag, _delete_after_use, timeout) =
|
||||
script_path_to_payload(script_path, &mut tx, &w_id, run_query.skip_preprocessor).await?;
|
||||
script_path_to_payload(script_path, &db, &w_id, run_query.skip_preprocessor).await?;
|
||||
let scheduled_for = run_query.get_scheduled_for(&db).await?;
|
||||
|
||||
let tag = run_query.tag.clone().or(tag);
|
||||
check_tag_available_for_workspace(&w_id, &tag).await?;
|
||||
|
||||
let tx = PushIsolationLevel::Transaction(tx);
|
||||
|
||||
let tx = PushIsolationLevel::Isolated(user_db, authed.clone().into(), rsmq);
|
||||
|
||||
let (uuid, tx) = push(
|
||||
&db,
|
||||
@@ -3052,6 +3049,11 @@ pub async fn run_script_by_path_inner(
|
||||
Ok((StatusCode::CREATED, uuid.to_string()))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct WorkflowAsCodeQuery {
|
||||
pub skip_update: Option<bool>,
|
||||
}
|
||||
|
||||
pub async fn run_workflow_as_code(
|
||||
authed: ApiAuthed,
|
||||
Extension(db): Extension<DB>,
|
||||
@@ -3059,15 +3061,38 @@ pub async fn run_workflow_as_code(
|
||||
Extension(rsmq): Extension<Option<rsmq_async::MultiplexedRsmq>>,
|
||||
Path((w_id, job_id, entrypoint)): Path<(String, Uuid, String)>,
|
||||
Query(run_query): Query<RunJobQuery>,
|
||||
Query(wkflow_query): Query<WorkflowAsCodeQuery>,
|
||||
Json(task): Json<WorkflowTask>,
|
||||
) -> error::Result<(StatusCode, String)> {
|
||||
|
||||
let mut i = 1;
|
||||
|
||||
if *CLOUD_HOSTED {
|
||||
tracing::info!("workflow_as_code_tracing id {i} ");
|
||||
i += 1;
|
||||
}
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
check_license_key_valid().await?;
|
||||
check_tag_available_for_workspace(&w_id, &run_query.tag).await?;
|
||||
|
||||
let mut tx: QueueTransaction<'_, _> = (rsmq, user_db.begin(&authed).await?).into();
|
||||
|
||||
if *CLOUD_HOSTED {
|
||||
tracing::info!("workflow_as_code_tracing id {i} ");
|
||||
i += 1;
|
||||
}
|
||||
|
||||
|
||||
let job = get_queued_job(&job_id, &w_id, &db).await?;
|
||||
|
||||
|
||||
|
||||
if *CLOUD_HOSTED {
|
||||
tracing::info!("workflow_as_code_tracing id {i} ");
|
||||
i += 1;
|
||||
}
|
||||
|
||||
|
||||
let job = not_found_if_none(job, "Queued Job", &job_id.to_string())?;
|
||||
let (job_payload, tag, _delete_after_use, timeout) = match job.job_kind {
|
||||
JobKind::Preview => (
|
||||
@@ -3092,7 +3117,7 @@ pub async fn run_workflow_as_code(
|
||||
JobKind::Script => {
|
||||
script_path_to_payload(
|
||||
job.script_path(),
|
||||
&mut tx,
|
||||
&db,
|
||||
&w_id,
|
||||
run_query.skip_preprocessor,
|
||||
)
|
||||
@@ -3101,6 +3126,12 @@ pub async fn run_workflow_as_code(
|
||||
_ => return Err(anyhow::anyhow!("Not supported").into()),
|
||||
};
|
||||
|
||||
|
||||
if *CLOUD_HOSTED {
|
||||
tracing::info!("workflow_as_code_tracing id {i} ");
|
||||
i += 1;
|
||||
}
|
||||
|
||||
let mut extra = HashMap::new();
|
||||
extra.insert(ENTRYPOINT_OVERRIDE.to_string(), to_raw_value(&entrypoint));
|
||||
|
||||
@@ -3109,7 +3140,21 @@ pub async fn run_workflow_as_code(
|
||||
|
||||
let tag = run_query.tag.clone().or(tag).or(Some(job.tag));
|
||||
|
||||
let tx = PushIsolationLevel::Transaction(tx);
|
||||
|
||||
if *CLOUD_HOSTED {
|
||||
tracing::info!("workflow_as_code_tracing id {i} ");
|
||||
i += 1;
|
||||
}
|
||||
|
||||
|
||||
let tx = PushIsolationLevel::Isolated(user_db, authed.clone().into(), rsmq);
|
||||
|
||||
|
||||
if *CLOUD_HOSTED {
|
||||
tracing::info!("workflow_as_code_tracing id {i} ");
|
||||
i += 1;
|
||||
}
|
||||
|
||||
|
||||
let (uuid, mut tx) = push(
|
||||
&db,
|
||||
@@ -3136,14 +3181,39 @@ pub async fn run_workflow_as_code(
|
||||
Some(&authed.clone().into()),
|
||||
)
|
||||
.await?;
|
||||
sqlx::query!(
|
||||
"UPDATE queue SET flow_status = jsonb_set(COALESCE(flow_status, '{}'::jsonb), array[$1], jsonb_set(jsonb_set('{}'::jsonb, '{scheduled_for}', to_jsonb(now()::text)), '{name}', to_jsonb($4::text))) WHERE id = $2 AND workspace_id = $3",
|
||||
uuid.to_string(),
|
||||
job_id,
|
||||
w_id,
|
||||
entrypoint
|
||||
).execute(&mut tx).await?;
|
||||
|
||||
|
||||
if *CLOUD_HOSTED {
|
||||
tracing::info!("workflow_as_code_tracing id {i} ");
|
||||
i += 1;
|
||||
}
|
||||
|
||||
if !wkflow_query.skip_update.unwrap_or(false) {
|
||||
sqlx::query!(
|
||||
"UPDATE queue SET flow_status = jsonb_set(COALESCE(flow_status, '{}'::jsonb), array[$1], jsonb_set(jsonb_set('{}'::jsonb, '{scheduled_for}', to_jsonb(now()::text)), '{name}', to_jsonb($4::text))) WHERE id = $2 AND workspace_id = $3",
|
||||
uuid.to_string(),
|
||||
job_id,
|
||||
w_id,
|
||||
entrypoint
|
||||
).execute(&mut tx).await?;
|
||||
} else {
|
||||
tracing::info!("Skipping update of flow status for job {job_id} in workspace {w_id}");
|
||||
}
|
||||
|
||||
|
||||
if *CLOUD_HOSTED {
|
||||
tracing::info!("workflow_as_code_tracing id {i} ");
|
||||
i += 1;
|
||||
}
|
||||
|
||||
|
||||
tx.commit().await?;
|
||||
|
||||
|
||||
if *CLOUD_HOSTED {
|
||||
tracing::info!("workflow_as_code_tracing id {i} ");
|
||||
}
|
||||
|
||||
Ok((StatusCode::CREATED, uuid.to_string()))
|
||||
}
|
||||
|
||||
@@ -3507,15 +3577,13 @@ pub async fn run_wait_result_job_by_path_get(
|
||||
let script_path = script_path.to_path();
|
||||
check_scopes(&authed, || format!("run:script/{script_path}"))?;
|
||||
|
||||
let mut tx: QueueTransaction<'_, _> = (rsmq, user_db.begin(&authed).await?).into();
|
||||
|
||||
let (job_payload, tag, delete_after_use, timeout) =
|
||||
script_path_to_payload(script_path, &mut tx, &w_id, run_query.skip_preprocessor).await?;
|
||||
script_path_to_payload(script_path, &db, &w_id, run_query.skip_preprocessor).await?;
|
||||
|
||||
let tag = run_query.tag.clone().or(tag);
|
||||
check_tag_available_for_workspace(&w_id, &tag).await?;
|
||||
|
||||
let tx = PushIsolationLevel::Transaction(tx);
|
||||
let tx = PushIsolationLevel::Isolated(user_db, authed.clone().into(), rsmq);
|
||||
|
||||
let (uuid, tx) = push(
|
||||
&db,
|
||||
@@ -3632,15 +3700,13 @@ pub async fn run_wait_result_script_by_path_internal(
|
||||
let script_path = script_path.to_path();
|
||||
check_scopes(&authed, || format!("run:script/{script_path}"))?;
|
||||
|
||||
let mut tx: QueueTransaction<'_, _> = (rsmq, user_db.begin(&authed).await?).into();
|
||||
|
||||
let (job_payload, tag, delete_after_use, timeout) =
|
||||
script_path_to_payload(script_path, &mut tx, &w_id, run_query.skip_preprocessor).await?;
|
||||
script_path_to_payload(script_path, &db, &w_id, run_query.skip_preprocessor).await?;
|
||||
|
||||
let tag = run_query.tag.clone().or(tag);
|
||||
check_tag_available_for_workspace(&w_id, &tag).await?;
|
||||
|
||||
let tx = PushIsolationLevel::Transaction(tx);
|
||||
let tx = PushIsolationLevel::Isolated(user_db, authed.clone().into(), rsmq);
|
||||
|
||||
let (uuid, tx) = push(
|
||||
&db,
|
||||
@@ -3692,8 +3758,6 @@ pub async fn run_wait_result_script_by_hash(
|
||||
|
||||
check_queue_too_long(&db, run_query.queue_limit).await?;
|
||||
|
||||
let mut tx: QueueTransaction<'_, _> = (rsmq, user_db.begin(&authed).await?).into();
|
||||
|
||||
let hash = script_hash.0;
|
||||
let (
|
||||
path,
|
||||
@@ -3708,7 +3772,7 @@ pub async fn run_wait_result_script_by_hash(
|
||||
delete_after_use,
|
||||
timeout,
|
||||
has_preprocessor,
|
||||
) = get_path_tag_limits_cache_for_hash(&mut tx, &w_id, hash).await?;
|
||||
) = get_path_tag_limits_cache_for_hash(&db, &w_id, hash).await?;
|
||||
if let Some(run_query_cache_ttl) = run_query.cache_ttl {
|
||||
cache_ttl = Some(run_query_cache_ttl);
|
||||
}
|
||||
@@ -3717,7 +3781,7 @@ pub async fn run_wait_result_script_by_hash(
|
||||
let tag = run_query.tag.clone().or(tag);
|
||||
check_tag_available_for_workspace(&w_id, &tag).await?;
|
||||
|
||||
let tx = PushIsolationLevel::Transaction(tx);
|
||||
let tx = PushIsolationLevel::Isolated(user_db, authed.clone().into(), rsmq);
|
||||
|
||||
let (uuid, tx) = push(
|
||||
&db,
|
||||
@@ -3799,7 +3863,6 @@ pub async fn run_wait_result_flow_by_path_internal(
|
||||
let flow_path = flow_path.to_path();
|
||||
check_scopes(&authed, || format!("run:flow/{flow_path}"))?;
|
||||
|
||||
let mut tx: QueueTransaction<'_, _> = (rsmq, user_db.begin(&authed).await?).into();
|
||||
|
||||
let scheduled_for = run_query.get_scheduled_for(&db).await?;
|
||||
|
||||
@@ -3812,7 +3875,7 @@ pub async fn run_wait_result_flow_by_path_internal(
|
||||
flow_path,
|
||||
w_id
|
||||
)
|
||||
.fetch_optional(&mut tx)
|
||||
.fetch_optional(&db)
|
||||
.await?
|
||||
.map(|x| (x.tag, x.dedicated_worker, x.early_return, x.has_preprocessor))
|
||||
.ok_or_else(|| {
|
||||
@@ -3824,7 +3887,7 @@ pub async fn run_wait_result_flow_by_path_internal(
|
||||
let tag = run_query.tag.clone().or(tag);
|
||||
check_tag_available_for_workspace(&w_id, &tag).await?;
|
||||
|
||||
let tx = PushIsolationLevel::Transaction(tx);
|
||||
let tx = PushIsolationLevel::Isolated(user_db, authed.clone().into(), rsmq);
|
||||
|
||||
let (uuid, tx) = push(
|
||||
&db,
|
||||
@@ -4130,7 +4193,7 @@ async fn run_dependencies_job(
|
||||
JsonRawValue::from_string("true".to_string()).unwrap(),
|
||||
);
|
||||
if language == ScriptLang::Bun {
|
||||
let annotation = windmill_common::worker::get_annotation(&raw_code);
|
||||
let annotation = windmill_common::worker::get_annotation_ts(&raw_code);
|
||||
hm.insert(
|
||||
"npm_mode".to_string(),
|
||||
JsonRawValue::from_string(annotation.npm_mode.to_string()).unwrap(),
|
||||
@@ -4296,7 +4359,6 @@ async fn add_batch_jobs(
|
||||
}
|
||||
}
|
||||
"flow" => {
|
||||
let mut tx = PushIsolationLevel::IsolatedRoot(db.clone(), rsmq);
|
||||
|
||||
let mut uuids: Vec<Uuid> = Vec::new();
|
||||
let payload = if let Some(ref fv) = batch_info.flow_value {
|
||||
@@ -4314,6 +4376,7 @@ async fn add_batch_jobs(
|
||||
))?
|
||||
}
|
||||
};
|
||||
let mut tx = PushIsolationLevel::IsolatedRoot(db.clone(), rsmq);
|
||||
for _ in 0..n {
|
||||
let ehm = HashMap::new();
|
||||
let (uuid, ntx) = push(
|
||||
@@ -4514,7 +4577,6 @@ pub async fn run_job_by_hash_inner(
|
||||
#[cfg(feature = "enterprise")]
|
||||
check_license_key_valid().await?;
|
||||
|
||||
let mut tx: QueueTransaction<'_, _> = (rsmq, user_db.begin(&authed).await?).into();
|
||||
|
||||
let hash = script_hash.0;
|
||||
let (
|
||||
@@ -4530,7 +4592,7 @@ pub async fn run_job_by_hash_inner(
|
||||
_delete_after_use, // not taken into account in async endpoints
|
||||
timeout,
|
||||
has_preprocessor,
|
||||
) = get_path_tag_limits_cache_for_hash(&mut tx, &w_id, hash).await?;
|
||||
) = get_path_tag_limits_cache_for_hash(&db, &w_id, hash).await?;
|
||||
check_scopes(&authed, || format!("run:script/{path}"))?;
|
||||
if let Some(run_query_cache_ttl) = run_query.cache_ttl {
|
||||
cache_ttl = Some(run_query_cache_ttl);
|
||||
@@ -4539,7 +4601,7 @@ pub async fn run_job_by_hash_inner(
|
||||
let tag = run_query.tag.clone().or(tag);
|
||||
|
||||
check_tag_available_for_workspace(&w_id, &tag).await?;
|
||||
let tx = PushIsolationLevel::Transaction(tx);
|
||||
let tx = PushIsolationLevel::Isolated(user_db, authed.clone().into(), rsmq);
|
||||
|
||||
let (uuid, tx) = push(
|
||||
&db,
|
||||
@@ -4683,8 +4745,8 @@ async fn get_job_update(
|
||||
.fetch_optional(&db)
|
||||
.await?;
|
||||
|
||||
let progress: Option<i32> = if get_progress == Some(true){
|
||||
sqlx::query_scalar!(
|
||||
let progress: Option<i32> = if get_progress == Some(true) {
|
||||
sqlx::query_scalar!(
|
||||
"SELECT scalar_int FROM job_stats WHERE workspace_id = $1 AND job_id = $2 AND metric_id = $3",
|
||||
&w_id,
|
||||
job_id,
|
||||
@@ -5115,8 +5177,6 @@ async fn get_completed_job_result(
|
||||
Ok(Json(result).into_response())
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct CountByTagQuery {
|
||||
horizon_secs: Option<i64>,
|
||||
@@ -5130,7 +5190,7 @@ struct TagCount {
|
||||
}
|
||||
|
||||
async fn count_by_tag(
|
||||
ApiAuthed { email, ..}: ApiAuthed,
|
||||
ApiAuthed { email, .. }: ApiAuthed,
|
||||
Extension(db): Extension<DB>,
|
||||
Query(query): Query<CountByTagQuery>,
|
||||
) -> JsonResult<Vec<TagCount>> {
|
||||
|
||||
@@ -82,6 +82,7 @@ pub mod smtp_server_ee;
|
||||
mod static_assets;
|
||||
mod stripe_ee;
|
||||
mod tracing_init;
|
||||
mod triggers;
|
||||
mod users;
|
||||
mod utils;
|
||||
mod variables;
|
||||
|
||||
@@ -1,188 +0,0 @@
|
||||
/*
|
||||
* Author: Ruben Fiszel
|
||||
* Copyright: Windmill Labs, Inc 2022
|
||||
* This file and its contents are licensed under the AGPLv3 License.
|
||||
* Please see the included NOTICE for copyright information and
|
||||
* LICENSE-AGPL for a copy of the license.
|
||||
*/
|
||||
|
||||
use std::{collections::HashMap, fmt::Debug};
|
||||
|
||||
use axum::{routing::get, Json, Router};
|
||||
use hmac::Mac;
|
||||
use hyper::HeaderMap;
|
||||
|
||||
use itertools::Itertools;
|
||||
use oauth2::{Client as OClient, *};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::{Postgres, Transaction};
|
||||
use windmill_common::more_serde::maybe_number_opt;
|
||||
|
||||
use crate::OAUTH_CLIENTS;
|
||||
use windmill_common::error;
|
||||
use windmill_common::oauth2::*;
|
||||
|
||||
use crate::db::DB;
|
||||
use std::str;
|
||||
|
||||
pub fn global_service() -> Router {
|
||||
Router::new()
|
||||
.route("/list_supabase", get(list_supabase))
|
||||
.route("/list_logins", get(list_logins))
|
||||
.route("/list_connects", get(list_connects))
|
||||
}
|
||||
|
||||
pub fn workspaced_service() -> Router {
|
||||
Router::new()
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(tag = "type")]
|
||||
pub enum InstanceEvent {
|
||||
UserAdded { email: String },
|
||||
// UserDeleted { email: String },
|
||||
// UserDeletedWorkspace { workspace: String, email: String },
|
||||
UserAddedWorkspace { workspace: String, email: String },
|
||||
UserInvitedWorkspace { workspace: String, email: String },
|
||||
UserJoinedWorkspace { workspace: String, email: String, username: String },
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ClientWithScopes {
|
||||
_client: OClient,
|
||||
_scopes: Vec<String>,
|
||||
_extra_params: Option<HashMap<String, String>>,
|
||||
_extra_params_callback: Option<HashMap<String, String>>,
|
||||
_allowed_domains: Option<Vec<String>>,
|
||||
_userinfo_url: Option<String>,
|
||||
}
|
||||
|
||||
pub type BasicClientsMap = HashMap<String, ClientWithScopes>;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct OAuthConfig {
|
||||
auth_url: String,
|
||||
token_url: String,
|
||||
userinfo_url: Option<String>,
|
||||
scopes: Option<Vec<String>>,
|
||||
extra_params: Option<HashMap<String, String>>,
|
||||
extra_params_callback: Option<HashMap<String, String>>,
|
||||
req_body_auth: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct OAuthClient {
|
||||
id: String,
|
||||
secret: String,
|
||||
allowed_domains: Option<Vec<String>>,
|
||||
connect_config: Option<OAuthConfig>,
|
||||
login_config: Option<OAuthConfig>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AllClients {
|
||||
pub logins: BasicClientsMap,
|
||||
pub connects: BasicClientsMap,
|
||||
pub slack: Option<OClient>,
|
||||
}
|
||||
|
||||
pub fn build_oauth_clients(
|
||||
_base_url: &str,
|
||||
_oauths_from_config: Option<HashMap<String, OAuthClient>>,
|
||||
) -> anyhow::Result<AllClients> {
|
||||
// Implementation is not open source
|
||||
return Ok(AllClients {
|
||||
logins: HashMap::default(),
|
||||
connects: HashMap::default(),
|
||||
slack: None,
|
||||
});
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct TokenResponse {
|
||||
access_token: AccessToken,
|
||||
#[serde(deserialize_with = "maybe_number_opt")]
|
||||
#[serde(default)]
|
||||
expires_in: Option<u64>,
|
||||
refresh_token: Option<RefreshToken>,
|
||||
#[serde(deserialize_with = "helpers::deserialize_space_delimited_vec")]
|
||||
#[serde(serialize_with = "helpers::serialize_space_delimited_vec")]
|
||||
#[serde(default)]
|
||||
scope: Option<Vec<Scope>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct Logins {
|
||||
oauth: Vec<String>,
|
||||
saml: Option<String>,
|
||||
}
|
||||
async fn list_logins() -> error::JsonResult<Logins> {
|
||||
// Implementation is not open source
|
||||
return Ok(Json(Logins { oauth: vec![], saml: None }));
|
||||
}
|
||||
|
||||
async fn list_connects() -> error::JsonResult<Vec<String>> {
|
||||
Ok(Json(
|
||||
(&OAUTH_CLIENTS.read().await.connects)
|
||||
.keys()
|
||||
.map(|x| x.to_owned())
|
||||
.collect_vec(),
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn _refresh_token<'c>(
|
||||
_tx: Transaction<'c, Postgres>,
|
||||
_path: &str,
|
||||
_w_id: &str,
|
||||
_id: i32,
|
||||
_db: &DB,
|
||||
) -> error::Result<String> {
|
||||
// Implementation is not open source
|
||||
Err(error::Error::BadRequest(
|
||||
"Not implemented in Windmill's Open Source repository".to_string(),
|
||||
))
|
||||
}
|
||||
|
||||
async fn list_supabase(_headers: HeaderMap) -> error::Result<String> {
|
||||
// Implementation is not open source
|
||||
Err(error::Error::BadRequest(
|
||||
"Not implemented in Windmill's Open Source repository".to_string(),
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn check_nb_of_user(db: &DB) -> error::Result<()> {
|
||||
let nb_users_sso =
|
||||
sqlx::query_scalar!("SELECT COUNT(*) FROM password WHERE login_type != 'password'",)
|
||||
.fetch_one(db)
|
||||
.await?;
|
||||
if nb_users_sso.unwrap_or(0) >= 10 {
|
||||
return Err(error::Error::BadRequest(
|
||||
"You have reached the maximum number of oauth users accounts (10) without an enterprise license"
|
||||
.to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
let nb_users = sqlx::query_scalar!("SELECT COUNT(*) FROM password",)
|
||||
.fetch_one(db)
|
||||
.await?;
|
||||
if nb_users.unwrap_or(0) >= 50 {
|
||||
return Err(error::Error::BadRequest(
|
||||
"You have reached the maximum number of accounts (50) without an enterprise license"
|
||||
.to_string(),
|
||||
));
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SlackVerifier {
|
||||
_mac: HmacSha256,
|
||||
}
|
||||
|
||||
impl SlackVerifier {
|
||||
pub fn new<S: AsRef<[u8]>>(secret: S) -> anyhow::Result<SlackVerifier> {
|
||||
HmacSha256::new_from_slice(secret.as_ref())
|
||||
.map(|mac| SlackVerifier { _mac: mac })
|
||||
.map_err(|_| anyhow::anyhow!("invalid secret"))
|
||||
}
|
||||
}
|
||||
1
backend/windmill-api/src/oauth2_ee.rs
Symbolic link
1
backend/windmill-api/src/oauth2_ee.rs
Symbolic link
@@ -0,0 +1 @@
|
||||
/git/windmill/../windmill-ee-private/windmill-api/src/oauth2_ee.rs
|
||||
@@ -1,17 +0,0 @@
|
||||
/*
|
||||
* Author: Ruben Fiszel
|
||||
* Copyright: Windmill Labs, Inc 2023
|
||||
* This file and its contents are licensed under the AGPLv3 License.
|
||||
* Please see the included NOTICE for copyright information and
|
||||
* LICENSE-AGPL for a copy of the license.
|
||||
*/
|
||||
|
||||
use axum::Router;
|
||||
|
||||
pub fn global_service() -> Router {
|
||||
Router::new()
|
||||
}
|
||||
|
||||
pub fn workspaced_service() -> Router {
|
||||
Router::new()
|
||||
}
|
||||
1
backend/windmill-api/src/oidc_ee.rs
Symbolic link
1
backend/windmill-api/src/oidc_ee.rs
Symbolic link
@@ -0,0 +1 @@
|
||||
/git/windmill/../windmill-ee-private/windmill-api/src/oidc_ee.rs
|
||||
@@ -58,7 +58,10 @@ pub fn workspaced_service() -> Router {
|
||||
.route("/type/exists/:name", get(exists_resource_type))
|
||||
.route("/type/update/:name", post(update_resource_type))
|
||||
.route("/type/delete/:name", delete(delete_resource_type))
|
||||
.route("/file_resource_type_to_file_ext_map", get(file_resource_ext_to_resource_type))
|
||||
.route(
|
||||
"/file_resource_type_to_file_ext_map",
|
||||
get(file_resource_ext_to_resource_type),
|
||||
)
|
||||
.route("/type/create", post(create_resource_type))
|
||||
}
|
||||
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Author: Ruben Fiszel
|
||||
* Copyright: Windmill Labs, Inc 2023
|
||||
* This file and its contents are licensed under the AGPLv3 License.
|
||||
* Please see the included NOTICE for copyright information and
|
||||
* LICENSE-AGPL for a copy of the license.
|
||||
*/
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use axum::{routing::post, Router};
|
||||
|
||||
pub struct ServiceProviderExt();
|
||||
|
||||
pub async fn build_sp_extension() -> anyhow::Result<ServiceProviderExt> {
|
||||
return Ok(ServiceProviderExt());
|
||||
}
|
||||
|
||||
pub fn global_service() -> Router {
|
||||
Router::new().route("/acs", post(acs))
|
||||
}
|
||||
|
||||
pub async fn acs() -> String {
|
||||
// Implementation is not open source as it is a Windmill Enterprise Edition feature
|
||||
"SAML available only in enterprise version".to_string()
|
||||
}
|
||||
1
backend/windmill-api/src/saml_ee.rs
Symbolic link
1
backend/windmill-api/src/saml_ee.rs
Symbolic link
@@ -0,0 +1 @@
|
||||
/git/windmill/../windmill-ee-private/windmill-api/src/saml_ee.rs
|
||||
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
* Author: Ruben Fiszel
|
||||
* Copyright: Windmill Labs, Inc 2023
|
||||
* This file and its contents are licensed under the AGPLv3 License.
|
||||
* Please see the included NOTICE for copyright information and
|
||||
* LICENSE-AGPL for a copy of the license.
|
||||
*/
|
||||
|
||||
use axum::{middleware::Next, response::Response, routing::get, Router};
|
||||
use hyper::Request;
|
||||
|
||||
pub fn global_service() -> Router {
|
||||
Router::new().route("/ee", get(ee))
|
||||
}
|
||||
|
||||
pub async fn ee() -> String {
|
||||
return "Enterprise Edition".to_string();
|
||||
}
|
||||
|
||||
pub async fn has_scim_token<B>(_request: Request<B>, _next: Next) -> Response {
|
||||
//Not implemented in open-source version
|
||||
todo!()
|
||||
}
|
||||
1
backend/windmill-api/src/scim_ee.rs
Symbolic link
1
backend/windmill-api/src/scim_ee.rs
Symbolic link
@@ -0,0 +1 @@
|
||||
/git/windmill/../windmill-ee-private/windmill-api/src/scim_ee.rs
|
||||
@@ -9,6 +9,9 @@
|
||||
use crate::{
|
||||
db::{ApiAuthed, DB},
|
||||
schedule::clear_schedule,
|
||||
triggers::{
|
||||
get_triggers_count_internal, list_tokens_internal, TriggersCount, TruncatedTokenWithEmail,
|
||||
},
|
||||
users::{maybe_refresh_folders, require_owner_of_path, AuthCache},
|
||||
utils::WithStarredInfoQuery,
|
||||
webhook_util::{WebhookMessage, WebhookShared},
|
||||
@@ -53,7 +56,7 @@ use windmill_common::{
|
||||
utils::{
|
||||
not_found_if_none, paginate, query_elems_from_hub, require_admin, Pagination, StripPath,
|
||||
},
|
||||
worker::{get_annotation, to_raw_value},
|
||||
worker::{get_annotation_ts, to_raw_value},
|
||||
HUB_BASE_URL,
|
||||
};
|
||||
use windmill_git_sync::{handle_deployment_metadata, DeployedObject};
|
||||
@@ -132,6 +135,8 @@ pub fn workspaced_service() -> Router {
|
||||
.route("/archive/p/*path", post(archive_script_by_path))
|
||||
.route("/get/draft/*path", get(get_script_by_path_w_draft))
|
||||
.route("/get/p/*path", get(get_script_by_path))
|
||||
.route("/get_triggers_count/*path", get(get_triggers_count))
|
||||
.route("/list_tokens/*path", get(list_tokens))
|
||||
.route("/raw/p/*path", get(raw_script_by_path))
|
||||
.route("/raw_unpinned/p/*path", get(raw_script_by_path_unpinned))
|
||||
.route("/exists/p/*path", get(exists_script_by_path))
|
||||
@@ -601,7 +606,7 @@ async fn create_script_internal<'c>(
|
||||
};
|
||||
|
||||
let lang = if &ns.language == &ScriptLang::Bun || &ns.language == &ScriptLang::Bunnative {
|
||||
let anns = get_annotation(&ns.content);
|
||||
let anns = get_annotation_ts(&ns.content);
|
||||
if anns.native_mode {
|
||||
ScriptLang::Bunnative
|
||||
} else {
|
||||
@@ -874,6 +879,22 @@ async fn get_script_by_path(
|
||||
Ok(Json(script))
|
||||
}
|
||||
|
||||
async fn list_tokens(
|
||||
Extension(db): Extension<DB>,
|
||||
Path((w_id, path)): Path<(String, StripPath)>,
|
||||
) -> JsonResult<Vec<TruncatedTokenWithEmail>> {
|
||||
let path = path.to_path();
|
||||
list_tokens_internal(&db, &w_id, &path, false).await
|
||||
}
|
||||
|
||||
async fn get_triggers_count(
|
||||
Extension(db): Extension<DB>,
|
||||
Path((w_id, path)): Path<(String, StripPath)>,
|
||||
) -> JsonResult<TriggersCount> {
|
||||
let path = path.to_path();
|
||||
get_triggers_count_internal(&db, &w_id, &path, false).await
|
||||
}
|
||||
|
||||
async fn get_script_by_path_w_draft(
|
||||
authed: ApiAuthed,
|
||||
Extension(user_db): Extension<UserDB>,
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
use crate::{db::DB, users::AuthCache};
|
||||
use std::{net::SocketAddr, sync::Arc};
|
||||
use windmill_common::db::UserDB;
|
||||
|
||||
pub struct SmtpServer {
|
||||
pub auth_cache: Arc<AuthCache>,
|
||||
pub db: DB,
|
||||
pub user_db: UserDB,
|
||||
pub rsmq: Option<rsmq_async::MultiplexedRsmq>,
|
||||
pub base_internal_url: String,
|
||||
}
|
||||
|
||||
impl SmtpServer {
|
||||
pub async fn start_listener_thread(self: Arc<Self>, _addr: SocketAddr) -> anyhow::Result<()> {
|
||||
Err(anyhow::anyhow!("Implementation not open source"))
|
||||
}
|
||||
}
|
||||
1
backend/windmill-api/src/smtp_server_ee.rs
Symbolic link
1
backend/windmill-api/src/smtp_server_ee.rs
Symbolic link
@@ -0,0 +1 @@
|
||||
/git/windmill/../windmill-ee-private/windmill-api/src/smtp_server_ee.rs
|
||||
@@ -1,7 +0,0 @@
|
||||
#[cfg(feature = "stripe")]
|
||||
use axum::Router;
|
||||
|
||||
#[cfg(feature = "stripe")]
|
||||
pub fn add_stripe_routes(router: Router) -> Router {
|
||||
return router;
|
||||
}
|
||||
1
backend/windmill-api/src/stripe_ee.rs
Symbolic link
1
backend/windmill-api/src/stripe_ee.rs
Symbolic link
@@ -0,0 +1 @@
|
||||
/git/windmill/../windmill-ee-private/windmill-api/src/stripe_ee.rs
|
||||
@@ -9,6 +9,7 @@
|
||||
use ::tracing::{field, Span};
|
||||
use hyper::Response;
|
||||
use tower_http::trace::{MakeSpan, OnFailure, OnResponse};
|
||||
use uuid::Uuid;
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref LOG_REQUESTS: bool = std::env::var("LOG_REQUESTS")
|
||||
@@ -45,17 +46,28 @@ impl<B> OnFailure<B> for MyOnFailure {
|
||||
// tracing::error!(latency = latency.as_millis(), "response")
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref TRACING_HEADER: String = std::env::var("TRACING_HEADER")
|
||||
.ok().unwrap_or_else(|| "x-tracing-id".to_string());
|
||||
}
|
||||
#[derive(Clone)]
|
||||
pub struct MyMakeSpan {}
|
||||
|
||||
impl<B> MakeSpan<B> for MyMakeSpan {
|
||||
fn make_span(&mut self, request: &hyper::Request<B>) -> Span {
|
||||
let tracing_id = request
|
||||
.headers()
|
||||
.get(TRACING_HEADER.as_str())
|
||||
.and_then(|x| x.to_str().map(|x| x.to_string()).ok())
|
||||
.unwrap_or(Uuid::new_v4().to_string());
|
||||
tracing::info_span!(
|
||||
"request",
|
||||
method = %request.method(),
|
||||
uri = %request.uri(),
|
||||
username = field::Empty,
|
||||
workspace_id = field::Empty,
|
||||
trace_id = tracing_id,
|
||||
email = field::Empty,
|
||||
)
|
||||
}
|
||||
|
||||
131
backend/windmill-api/src/triggers.rs
Normal file
131
backend/windmill-api/src/triggers.rs
Normal file
@@ -0,0 +1,131 @@
|
||||
use axum::Json;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::FromRow;
|
||||
use windmill_common::error::JsonResult;
|
||||
|
||||
use crate::db::DB;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct TriggerPrimarySchedule {
|
||||
schedule: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct TriggersCount {
|
||||
primary_schedule: Option<TriggerPrimarySchedule>,
|
||||
schedule_count: i64,
|
||||
http_routes_count: i64,
|
||||
webhook_count: i64,
|
||||
email_count: i64,
|
||||
}
|
||||
pub(crate) async fn get_triggers_count_internal(
|
||||
db: &DB,
|
||||
w_id: &str,
|
||||
path: &str,
|
||||
is_flow: bool,
|
||||
) -> JsonResult<TriggersCount> {
|
||||
let primary_schedule = sqlx::query_scalar!(
|
||||
"SELECT schedule FROM schedule WHERE path = $1 AND script_path = $1 AND is_flow = $2 AND workspace_id = $3",
|
||||
path,
|
||||
is_flow,
|
||||
w_id
|
||||
)
|
||||
.fetch_optional(db)
|
||||
.await?;
|
||||
|
||||
let schedule_count = sqlx::query_scalar!(
|
||||
"SELECT COUNT(*) FROM schedule WHERE script_path = $1 AND is_flow = $2 AND workspace_id = $3",
|
||||
path,
|
||||
is_flow,
|
||||
w_id
|
||||
)
|
||||
.fetch_one(db)
|
||||
.await?
|
||||
.unwrap_or(0);
|
||||
|
||||
let http_routes_count = sqlx::query_scalar!(
|
||||
"SELECT COUNT(*) FROM http_trigger WHERE script_path = $1 AND is_flow = $2 AND workspace_id = $3",
|
||||
path,
|
||||
is_flow,
|
||||
w_id
|
||||
)
|
||||
.fetch_one(db)
|
||||
.await?
|
||||
.unwrap_or(0);
|
||||
|
||||
let webhook_count = (if is_flow {
|
||||
sqlx::query_scalar!(
|
||||
"SELECT COUNT(*) FROM token WHERE label LIKE 'webhook-%' AND workspace_id = $1 AND scopes @> ARRAY['run:flow/' || $2]::text[]",
|
||||
w_id,
|
||||
path,
|
||||
)
|
||||
|
||||
} else {
|
||||
sqlx::query_scalar!(
|
||||
"SELECT COUNT(*) FROM token WHERE label LIKE 'webhook-%' AND workspace_id = $1 AND scopes @> ARRAY['run:' || $2]::text[]",
|
||||
w_id,
|
||||
path,
|
||||
)
|
||||
}).fetch_one(db)
|
||||
.await?
|
||||
.unwrap_or(0);
|
||||
|
||||
let email_count = (if is_flow {
|
||||
sqlx::query_scalar!(
|
||||
"SELECT COUNT(*) FROM token WHERE label LIKE 'email-%' AND workspace_id = $1 AND scopes @> ARRAY['run:flow/' || $2]::text[]",
|
||||
w_id,
|
||||
path,
|
||||
)
|
||||
|
||||
} else {
|
||||
sqlx::query_scalar!(
|
||||
"SELECT COUNT(*) FROM token WHERE label LIKE 'email-%' AND workspace_id = $1 AND scopes @> ARRAY['run:script/' || $2]::text[]",
|
||||
w_id,
|
||||
path,
|
||||
)
|
||||
}).fetch_one(db)
|
||||
.await?
|
||||
.unwrap_or(0);
|
||||
|
||||
Ok(Json(TriggersCount {
|
||||
primary_schedule: primary_schedule.map(|s| TriggerPrimarySchedule { schedule: s }),
|
||||
schedule_count,
|
||||
http_routes_count,
|
||||
webhook_count,
|
||||
email_count,
|
||||
}))
|
||||
}
|
||||
|
||||
#[derive(FromRow, Serialize)]
|
||||
pub struct TruncatedTokenWithEmail {
|
||||
pub label: Option<String>,
|
||||
pub token_prefix: Option<String>,
|
||||
pub expiration: Option<chrono::DateTime<chrono::Utc>>,
|
||||
pub created_at: chrono::DateTime<chrono::Utc>,
|
||||
pub last_used_at: chrono::DateTime<chrono::Utc>,
|
||||
pub scopes: Option<Vec<String>>,
|
||||
pub email: Option<String>,
|
||||
}
|
||||
|
||||
pub async fn list_tokens_internal(
|
||||
db: &DB,
|
||||
w_id: &str,
|
||||
path: &str,
|
||||
is_flow: bool,
|
||||
) -> JsonResult<Vec<TruncatedTokenWithEmail>> {
|
||||
let tokens = if is_flow {
|
||||
sqlx::query_as!(
|
||||
TruncatedTokenWithEmail,
|
||||
"SELECT label, concat(substring(token for 10)) as token_prefix, expiration, created_at, last_used_at, scopes, email FROM token WHERE workspace_id = $1 AND scopes @> ARRAY['run:flow/' || $2]::text[]",
|
||||
w_id, path).fetch_all(db)
|
||||
.await?
|
||||
} else {
|
||||
sqlx::query_as!(
|
||||
TruncatedTokenWithEmail,
|
||||
"SELECT label, concat(substring(token for 10)) as token_prefix, expiration, created_at, last_used_at, scopes, email FROM token WHERE workspace_id = $1 AND scopes @> ARRAY['run:script/' || $2]::text[]",
|
||||
w_id, path)
|
||||
.fetch_all(db)
|
||||
.await?
|
||||
};
|
||||
Ok(Json(tokens))
|
||||
}
|
||||
@@ -128,7 +128,13 @@ pub fn make_unauthed_service() -> Router {
|
||||
|
||||
fn username_override_from_label(label: Option<String>) -> Option<String> {
|
||||
match label {
|
||||
Some(label) if label.starts_with("webhook-") => Some(label),
|
||||
Some(label)
|
||||
if label.starts_with("webhook-")
|
||||
|| label.starts_with("http-")
|
||||
|| label.starts_with("email-") =>
|
||||
{
|
||||
Some(label)
|
||||
}
|
||||
Some(label) if label.starts_with("ephemeral-script-end-user-") => Some(
|
||||
label
|
||||
.trim_start_matches("ephemeral-script-end-user-")
|
||||
@@ -270,9 +276,10 @@ impl AuthCache {
|
||||
_ => {
|
||||
let user_o = sqlx::query_as::<_, (Option<String>, Option<String>, bool, Option<Vec<String>>, Option<String>)>(
|
||||
"UPDATE token SET last_used_at = now() WHERE token = $1 AND (expiration > NOW() \
|
||||
OR expiration IS NULL) RETURNING owner, email, super_admin, scopes, label",
|
||||
OR expiration IS NULL) AND (workspace_id IS NULL OR workspace_id = $2) RETURNING owner, email, super_admin, scopes, label",
|
||||
)
|
||||
.bind(token)
|
||||
.bind(w_id.as_ref())
|
||||
.fetch_optional(&self.db)
|
||||
.await
|
||||
.ok()
|
||||
@@ -837,6 +844,7 @@ pub struct NewToken {
|
||||
pub expiration: Option<chrono::DateTime<chrono::Utc>>,
|
||||
pub impersonate_email: Option<String>,
|
||||
pub scopes: Option<Vec<String>>,
|
||||
pub workspace_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
@@ -2389,14 +2397,15 @@ async fn create_token(
|
||||
.unwrap_or(false);
|
||||
sqlx::query!(
|
||||
"INSERT INTO token
|
||||
(token, email, label, expiration, super_admin, scopes)
|
||||
VALUES ($1, $2, $3, $4, $5, $6)",
|
||||
(token, email, label, expiration, super_admin, scopes, workspace_id)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7)",
|
||||
token,
|
||||
authed.email,
|
||||
new_token.label,
|
||||
new_token.expiration,
|
||||
is_super_admin,
|
||||
new_token.scopes.as_ref().map(|x| x.as_slice())
|
||||
new_token.scopes.as_ref().map(|x| x.as_slice()),
|
||||
new_token.workspace_id,
|
||||
)
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
* Author: Ruben Fiszel
|
||||
* Copyright: Windmill Labs, Inc 2022
|
||||
* This file and its contents are licensed under the AGPLv3 License.
|
||||
* Please see the included NOTICE for copyright information and
|
||||
* LICENSE-AGPL for a copy of the license.
|
||||
*/
|
||||
use std::collections::HashMap;
|
||||
|
||||
use windmill_common::{
|
||||
error::{Error, Result},
|
||||
utils::Pagination,
|
||||
};
|
||||
|
||||
use crate::{ActionKind, AuditLog, ListAuditLogQuery};
|
||||
use sqlx::{Postgres, Transaction};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AuditAuthor {
|
||||
pub username: String,
|
||||
pub email: String,
|
||||
pub username_override: Option<String>,
|
||||
}
|
||||
|
||||
impl AuditAuthorable for AuditAuthor {
|
||||
fn email(&self) -> &str {
|
||||
&self.email
|
||||
}
|
||||
|
||||
fn username(&self) -> &str {
|
||||
&self.username
|
||||
}
|
||||
|
||||
fn username_override(&self) -> Option<&str> {
|
||||
self.username_override.as_deref()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait AuditAuthorable {
|
||||
fn username(&self) -> &str;
|
||||
fn email(&self) -> &str;
|
||||
fn username_override(&self) -> Option<&str>;
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "trace", skip_all)]
|
||||
pub async fn audit_log<'c, E: sqlx::Executor<'c, Database = Postgres>>(
|
||||
_db: E,
|
||||
_author: &impl AuditAuthorable,
|
||||
mut _operation: &str,
|
||||
_action_kind: ActionKind,
|
||||
_w_id: &str,
|
||||
mut _resource: Option<&str>,
|
||||
_parameters: Option<HashMap<&str, &str>>,
|
||||
) -> Result<()> {
|
||||
// Implementation is not open source as Audit logs is a Windmill Enterprise Edition feature
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn list_audit(
|
||||
_tx: Transaction<'_, Postgres>,
|
||||
_w_id: String,
|
||||
_pagination: Pagination,
|
||||
_lq: ListAuditLogQuery,
|
||||
) -> Result<Vec<AuditLog>> {
|
||||
// Implementation is not open source as Audit logs is a Windmill Enterprise Edition feature
|
||||
return Ok(vec![]);
|
||||
}
|
||||
|
||||
pub async fn get_audit(tx: Transaction<'_, Postgres>, _id: i32, _w_id: &str) -> Result<AuditLog> {
|
||||
// Implementation is not open source as Audit logs is a Windmill Enterprise Edition feature
|
||||
tx.commit().await?;
|
||||
Err(Error::NotFound(
|
||||
"Audit log not not available in Windmill Community edition".to_string(),
|
||||
))
|
||||
}
|
||||
1
backend/windmill-audit/src/audit_ee.rs
Symbolic link
1
backend/windmill-audit/src/audit_ee.rs
Symbolic link
@@ -0,0 +1 @@
|
||||
/git/windmill/../windmill-ee-private/windmill-audit/src/audit_ee.rs
|
||||
@@ -13,6 +13,7 @@ flamegraph = ["dep:tracing-flame"]
|
||||
loki = ["dep:tracing-loki"]
|
||||
benchmark = []
|
||||
parquet = ["dep:object_store", "dep:aws-config", "dep:aws-sdk-sts"]
|
||||
openidconnect = ["dep:openidconnect"]
|
||||
|
||||
[lib]
|
||||
name = "windmill_common"
|
||||
@@ -57,6 +58,7 @@ futures-core.workspace = true
|
||||
async-stream.workspace = true
|
||||
const_format.workspace = true
|
||||
crc.workspace = true
|
||||
openidconnect = { workspace = true, optional = true}
|
||||
|
||||
[target.'cfg(not(target_env = "msvc"))'.dependencies]
|
||||
tikv-jemalloc-ctl = { optional = true, workspace = true }
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
#[cfg(feature = "enterprise")]
|
||||
use crate::db::DB;
|
||||
use crate::ee::LicensePlan::Community;
|
||||
#[cfg(feature = "enterprise")]
|
||||
use crate::error;
|
||||
use serde::Deserialize;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
pub static ref LICENSE_KEY_VALID: Arc<RwLock<bool>> = Arc::new(RwLock::new(true));
|
||||
pub static ref LICENSE_KEY_ID: Arc<RwLock<String>> = Arc::new(RwLock::new("".to_string()));
|
||||
pub static ref LICENSE_KEY: Arc<RwLock<String>> = Arc::new(RwLock::new("".to_string()));
|
||||
}
|
||||
|
||||
pub enum LicensePlan {
|
||||
Community,
|
||||
Pro,
|
||||
Enterprise,
|
||||
}
|
||||
|
||||
pub async fn get_license_plan() -> LicensePlan {
|
||||
// Implementation is not open source
|
||||
return Community;
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum CriticalErrorChannel {
|
||||
Email { email: String },
|
||||
Slack { slack_channel: String },
|
||||
}
|
||||
|
||||
pub enum CriticalAlertKind {
|
||||
#[cfg(feature = "enterprise")]
|
||||
CriticalError,
|
||||
#[cfg(feature = "enterprise")]
|
||||
RecoveredCriticalError,
|
||||
}
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
pub async fn send_critical_alert(
|
||||
_error_message: String,
|
||||
_db: &DB,
|
||||
_kind: CriticalAlertKind,
|
||||
_channels: Option<Vec<CriticalErrorChannel>>,
|
||||
) {
|
||||
}
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
pub async fn schedule_key_renewal(_http_client: &reqwest::Client, _db: &crate::db::DB) -> () {
|
||||
// Implementation is not open source
|
||||
}
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
pub enum RenewReason {
|
||||
Manual,
|
||||
Schedule,
|
||||
OnStart,
|
||||
}
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
pub async fn renew_license_key(
|
||||
_http_client: &reqwest::Client,
|
||||
_db: &crate::db::DB,
|
||||
_key: Option<String>,
|
||||
_reason: RenewReason,
|
||||
) -> String {
|
||||
// Implementation is not open source
|
||||
"".to_string()
|
||||
}
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
pub async fn create_customer_portal_session(
|
||||
_http_client: &reqwest::Client,
|
||||
_key: Option<String>,
|
||||
) -> error::Result<String> {
|
||||
// Implementation is not open source
|
||||
Ok("".to_string())
|
||||
}
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
pub async fn worker_groups_alerts(_db: &DB) {}
|
||||
1
backend/windmill-common/src/ee.rs
Symbolic link
1
backend/windmill-common/src/ee.rs
Symbolic link
@@ -0,0 +1 @@
|
||||
/git/windmill/../windmill-ee-private/windmill-common/src/ee.rs
|
||||
@@ -1,73 +0,0 @@
|
||||
#[cfg(feature = "enterprise")]
|
||||
use crate::db::DB;
|
||||
use crate::ee::LicensePlan::Community;
|
||||
#[cfg(feature = "enterprise")]
|
||||
use crate::error;
|
||||
use serde::Deserialize;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
pub static ref LICENSE_KEY_VALID: Arc<RwLock<bool>> = Arc::new(RwLock::new(true));
|
||||
pub static ref LICENSE_KEY_ID: Arc<RwLock<String>> = Arc::new(RwLock::new("".to_string()));
|
||||
pub static ref LICENSE_KEY: Arc<RwLock<String>> = Arc::new(RwLock::new("".to_string()));
|
||||
}
|
||||
|
||||
pub enum LicensePlan {
|
||||
Community,
|
||||
Pro,
|
||||
Enterprise,
|
||||
}
|
||||
|
||||
pub async fn get_license_plan() -> LicensePlan {
|
||||
// Implementation is not open source
|
||||
return Community;
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum CriticalErrorChannel {}
|
||||
|
||||
pub enum CriticalAlertKind {
|
||||
#[cfg(feature = "enterprise")]
|
||||
CriticalError,
|
||||
#[cfg(feature = "enterprise")]
|
||||
RecoveredCriticalError,
|
||||
}
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
pub async fn send_critical_alert(
|
||||
_error_message: String,
|
||||
_db: &DB,
|
||||
_kind: CriticalAlertKind,
|
||||
_channels: Option<Vec<CriticalErrorChannel>>,
|
||||
) {
|
||||
}
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
pub async fn schedule_key_renewal(_http_client: &reqwest::Client, _db: &crate::db::DB) -> () {
|
||||
// Implementation is not open source
|
||||
}
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
pub async fn renew_license_key(
|
||||
_http_client: &reqwest::Client,
|
||||
_db: &crate::db::DB,
|
||||
_key: Option<String>,
|
||||
_manual: bool,
|
||||
) -> String {
|
||||
// Implementation is not open source
|
||||
"".to_string()
|
||||
}
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
pub async fn create_customer_portal_session(
|
||||
_http_client: &reqwest::Client,
|
||||
_key: Option<String>,
|
||||
) -> error::Result<String> {
|
||||
// Implementation is not open source
|
||||
Ok("".to_string())
|
||||
}
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
pub async fn worker_groups_alerts(_db: &DB) {}
|
||||
@@ -1,76 +0,0 @@
|
||||
#[cfg(feature = "enterprise")]
|
||||
use crate::db::DB;
|
||||
use crate::ee::LicensePlan::Community;
|
||||
#[cfg(feature = "enterprise")]
|
||||
use crate::error;
|
||||
use serde::Deserialize;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
pub static ref LICENSE_KEY_VALID: Arc<RwLock<bool>> = Arc::new(RwLock::new(true));
|
||||
pub static ref LICENSE_KEY_ID: Arc<RwLock<String>> = Arc::new(RwLock::new("".to_string()));
|
||||
pub static ref LICENSE_KEY: Arc<RwLock<String>> = Arc::new(RwLock::new("".to_string()));
|
||||
}
|
||||
|
||||
pub enum LicensePlan {
|
||||
Community,
|
||||
Pro,
|
||||
Enterprise,
|
||||
}
|
||||
|
||||
pub async fn get_license_plan() -> LicensePlan {
|
||||
// Implementation is not open source
|
||||
return Community;
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum CriticalErrorChannel {
|
||||
Email { email: String },
|
||||
Slack { slack_channel: String },
|
||||
}
|
||||
|
||||
pub enum CriticalAlertKind {
|
||||
#[cfg(feature = "enterprise")]
|
||||
CriticalError,
|
||||
#[cfg(feature = "enterprise")]
|
||||
RecoveredCriticalError,
|
||||
}
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
pub async fn send_critical_alert(
|
||||
_error_message: String,
|
||||
_db: &DB,
|
||||
_kind: CriticalAlertKind,
|
||||
_channels: Option<Vec<CriticalErrorChannel>>,
|
||||
) {
|
||||
}
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
pub async fn schedule_key_renewal(_http_client: &reqwest::Client, _db: &crate::db::DB) -> () {
|
||||
// Implementation is not open source
|
||||
}
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
pub async fn renew_license_key(
|
||||
_http_client: &reqwest::Client,
|
||||
_db: &crate::db::DB,
|
||||
_key: Option<String>,
|
||||
_manual: bool,
|
||||
) -> String {
|
||||
// Implementation is not open source
|
||||
"".to_string()
|
||||
}
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
pub async fn create_customer_portal_session(
|
||||
_http_client: &reqwest::Client,
|
||||
_key: Option<String>,
|
||||
) -> error::Result<String> {
|
||||
// Implementation is not open source
|
||||
Ok("".to_string())
|
||||
}
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
pub async fn worker_groups_alerts(_db: &DB) {}
|
||||
@@ -1,18 +0,0 @@
|
||||
use std::future::Future;
|
||||
|
||||
use crate::{
|
||||
error::Error,
|
||||
s3_helpers::{ObjectStoreResource, StorageResourceType},
|
||||
};
|
||||
|
||||
pub async fn get_s3_resource_internal<'c, F, Fut>(
|
||||
_resource_type: StorageResourceType,
|
||||
_s3_resource_value_raw: serde_json::Value,
|
||||
_gen_token: F,
|
||||
) -> crate::error::Result<ObjectStoreResource>
|
||||
where
|
||||
F: FnOnce(String) -> Fut,
|
||||
Fut: Future<Output = Result<String, Error>> + Send + 'static,
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
1
backend/windmill-common/src/job_s3_helpers_ee.rs
Symbolic link
1
backend/windmill-common/src/job_s3_helpers_ee.rs
Symbolic link
@@ -0,0 +1 @@
|
||||
/git/windmill/../windmill-ee-private/windmill-common/src/job_s3_helpers_ee.rs
|
||||
@@ -32,6 +32,8 @@ pub mod job_s3_helpers_ee;
|
||||
pub mod jobs;
|
||||
pub mod more_serde;
|
||||
pub mod oauth2;
|
||||
#[cfg(feature = "openidconnect")]
|
||||
pub mod oidc_ee;
|
||||
pub mod s3_helpers;
|
||||
|
||||
pub mod auth;
|
||||
|
||||
170
backend/windmill-common/src/oidc_ee.rs
Normal file
170
backend/windmill-common/src/oidc_ee.rs
Normal file
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Author: Ruben Fiszel
|
||||
* Copyright: Windmill Labs, Inc 2023
|
||||
* This file and its contents are licensed under the AGPLv3 License.
|
||||
* Please see the included NOTICE for copyright information and
|
||||
* LICENSE-AGPL for a copy of the license.
|
||||
*/
|
||||
|
||||
#[cfg(feature = "openidconnect")]
|
||||
use anyhow;
|
||||
#[cfg(feature = "openidconnect")]
|
||||
use std::process::Command;
|
||||
|
||||
#[cfg(feature = "openidconnect")]
|
||||
use openidconnect::{
|
||||
core::{CoreJwsSigningAlgorithm, CoreRsaPrivateSigningKey},
|
||||
IssuerUrl, JsonWebKeyId,
|
||||
};
|
||||
|
||||
#[cfg(all(feature = "enterprise", feature = "openidconnect"))]
|
||||
use openidconnect::{
|
||||
core::{
|
||||
CoreClaimName, CoreJsonWebKeySet, CoreProviderMetadata, CoreResponseType,
|
||||
CoreSubjectIdentifierType,
|
||||
},
|
||||
AuthUrl, EmptyAdditionalProviderMetadata, JsonWebKeySetUrl, ResponseTypes,
|
||||
};
|
||||
|
||||
#[cfg(feature = "openidconnect")]
|
||||
use openidconnect::AdditionalClaims;
|
||||
|
||||
#[cfg(feature = "openidconnect")]
|
||||
use crate::db::DB;
|
||||
|
||||
#[cfg(all(feature = "enterprise", feature = "openidconnect"))]
|
||||
use axum::extract::Path;
|
||||
#[cfg(all(feature = "enterprise", feature = "openidconnect"))]
|
||||
use axum::routing::{get, post};
|
||||
#[cfg(all(feature = "enterprise", feature = "openidconnect"))]
|
||||
use axum::Extension;
|
||||
#[cfg(all(feature = "enterprise", feature = "openidconnect"))]
|
||||
use axum::Json;
|
||||
|
||||
use axum::Router;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[cfg(all(feature = "enterprise", feature = "openidconnect"))]
|
||||
pub async fn generate_id_token<T: AdditionalClaims>(
|
||||
db: &DB,
|
||||
claim: T,
|
||||
audience: String,
|
||||
identifier: String,
|
||||
email: Option<String>,
|
||||
) -> crate::error::Result<String> {
|
||||
use chrono::{Duration, Utc};
|
||||
use openidconnect::{
|
||||
core::{CoreGenderClaim, CoreJsonWebKeyType, CoreJweContentEncryptionAlgorithm},
|
||||
Audience, EndUserEmail, IdToken, IdTokenClaims, StandardClaims, SubjectIdentifier,
|
||||
};
|
||||
|
||||
let private_key = get_private_key(&db).await?;
|
||||
let issue_url = format!("{}/api/oidc/", crate::BASE_URL.read().await.clone());
|
||||
|
||||
let id_token = IdToken::<
|
||||
T,
|
||||
CoreGenderClaim,
|
||||
CoreJweContentEncryptionAlgorithm,
|
||||
CoreJwsSigningAlgorithm,
|
||||
CoreJsonWebKeyType,
|
||||
>::new(
|
||||
IdTokenClaims::<T, CoreGenderClaim>::new(
|
||||
// Specify the issuer URL for the OpenID Connect Provider.
|
||||
IssuerUrl::new(issue_url)
|
||||
.map_err(|e| anyhow::anyhow!("Failed to generate IssueUrl: {}", e))?,
|
||||
// The audience is usually a single entry with the client ID of the client for whom
|
||||
// the ID token is intended. This is a required claim.
|
||||
vec![Audience::new(audience)],
|
||||
// The ID token expiration is usually much shorter than that of the access or refresh
|
||||
// tokens issued to clients.
|
||||
Utc::now() + Duration::try_hours(48).unwrap(),
|
||||
// The issue time is usually the current time.
|
||||
Utc::now(),
|
||||
// Set the standard claims defined by the OpenID Connect Core spec.
|
||||
StandardClaims::new(
|
||||
// Stable subject identifiers are recommended in place of e-mail addresses or other
|
||||
// potentially unstable identifiers. This is the only required claim.
|
||||
SubjectIdentifier::new(identifier),
|
||||
)
|
||||
// Optional: specify the user's e-mail address. This should only be provided if the
|
||||
// client has been granted the 'profile' or 'email' scopes.
|
||||
.set_email(email.map(|x| EndUserEmail::new(x)))
|
||||
// Optional: specify whether the provider has verified the user's e-mail address.
|
||||
.set_email_verified(Some(true)),
|
||||
// OpenID Connect Providers may supply custom claims by providing a struct that
|
||||
// implements the AdditionalClaims trait. This requires manually using the
|
||||
// generic IdTokenClaims struct rather than the CoreIdTokenClaims type alias,
|
||||
// however.
|
||||
claim,
|
||||
),
|
||||
// The private key used for signing the ID token. For confidential clients (those able
|
||||
// to maintain a client secret), a CoreHmacKey can also be used, in conjunction
|
||||
// with one of the CoreJwsSigningAlgorithm::HmacSha* signing algorithms. When using an
|
||||
// HMAC-based signing algorithm, the UTF-8 representation of the client secret should
|
||||
// be used as the HMAC key.
|
||||
&CoreRsaPrivateSigningKey::from_pem(
|
||||
&private_key,
|
||||
Some(JsonWebKeyId::new("windmill".to_string())),
|
||||
)
|
||||
.map_err(|e| anyhow::anyhow!("Invalid private key: {}", e))?,
|
||||
// Uses the RS256 signature algorithm. This crate supports any RS*, PS*, or HS*
|
||||
// signature algorithm.
|
||||
CoreJwsSigningAlgorithm::RsaSsaPkcs1V15Sha256,
|
||||
// When returning the ID token alongside an access token (e.g., in the Authorization Code
|
||||
// flow), it is recommended to pass the access token here to set the `at_hash` claim
|
||||
// automatically.
|
||||
None,
|
||||
// When returning the ID token alongside an authorization code (e.g., in the implicit
|
||||
// flow), it is recommended to pass the authorization code here to set the `c_hash` claim
|
||||
// automatically.
|
||||
None,
|
||||
)
|
||||
.map_err(|e| anyhow::anyhow!("Failed to generate token: {}", e))?;
|
||||
Ok(id_token.to_string())
|
||||
}
|
||||
|
||||
#[cfg(feature = "openidconnect")]
|
||||
pub async fn get_private_key(db: &DB) -> anyhow::Result<String> {
|
||||
let key = sqlx::query_scalar!(
|
||||
"SELECT value->>'private_key' FROM global_settings WHERE name = 'rsa_keys'",
|
||||
)
|
||||
.fetch_optional(db)
|
||||
.await?
|
||||
.flatten();
|
||||
|
||||
if let Some(key) = key {
|
||||
return Ok(key);
|
||||
} else {
|
||||
let keys = gen_pems(db).await?;
|
||||
return Ok(keys.private_key);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "openidconnect")]
|
||||
async fn gen_pems(db: &DB) -> anyhow::Result<Keys> {
|
||||
let private_key_cmd = Command::new("openssl")
|
||||
.arg("genrsa")
|
||||
.arg("--traditional")
|
||||
.arg("2048")
|
||||
.output()
|
||||
.expect("failed to execute process");
|
||||
|
||||
let private_key = String::from_utf8(private_key_cmd.stdout).unwrap();
|
||||
|
||||
tracing::debug!("Generated private key: {}", private_key);
|
||||
let keys = Keys { private_key };
|
||||
|
||||
sqlx::query!(
|
||||
"INSERT INTO global_settings (name, value) VALUES ('rsa_keys', $1)",
|
||||
serde_json::to_value(&keys).unwrap()
|
||||
)
|
||||
.execute(db)
|
||||
.await?;
|
||||
|
||||
Ok(keys)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize)]
|
||||
struct Keys {
|
||||
private_key: String,
|
||||
}
|
||||
@@ -22,6 +22,7 @@ use tokio::sync::RwLock;
|
||||
lazy_static::lazy_static! {
|
||||
|
||||
pub static ref OBJECT_STORE_CACHE_SETTINGS: Arc<RwLock<Option<Arc<dyn ObjectStore>>>> = Arc::new(RwLock::new(None));
|
||||
pub static ref OBJECT_STORE_OIDC_SETTINGS: Arc<RwLock<Option<Arc<S3AwsOidcResource>>>> = Arc::new(RwLock::new(None));
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
@@ -356,18 +357,42 @@ pub enum ObjectStoreSettings {
|
||||
pub enum ObjectSettings {
|
||||
S3(S3Settings),
|
||||
Azure(AzureBlobResource),
|
||||
AwsOidc(S3AwsOidcResource),
|
||||
}
|
||||
|
||||
#[cfg(feature = "parquet")]
|
||||
pub async fn build_object_store_from_settings(
|
||||
settings: ObjectSettings,
|
||||
) -> error::Result<Arc<dyn ObjectStore>> {
|
||||
use crate::oidc_ee::generate_id_token;
|
||||
|
||||
match settings {
|
||||
ObjectSettings::S3(s3_settings) => build_s3_client_from_settings(s3_settings).await,
|
||||
ObjectSettings::Azure(azure_settings) => {
|
||||
let azure_blob_resource = azure_settings;
|
||||
build_azure_blob_client(&azure_blob_resource)
|
||||
}
|
||||
ObjectSettings::AwsOidc(aws_oidc_settings) => {
|
||||
#[cfg(feature = "openidconnect")]
|
||||
{
|
||||
let token_fn = |audience: String| async move {
|
||||
generate_id_token(
|
||||
db,
|
||||
claim,
|
||||
aws_oidc_settings.audience,
|
||||
"windmill_instance",
|
||||
"instance_storage@windmill.dev",
|
||||
)
|
||||
};
|
||||
todo!()
|
||||
}
|
||||
#[cfg(not(feature = "openidconnect"))]
|
||||
{
|
||||
return Err(error::Error::InternalErr(
|
||||
"OpenID Connect is not enabled".to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
use sqlx::Postgres;
|
||||
|
||||
use crate::{error::Result, scripts::ScriptLang, DB};
|
||||
|
||||
pub async fn get_disable_stats_setting(_db: &DB) -> bool {
|
||||
// stats details are closed source
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
pub async fn schedule_stats(_db: &DB, _http_client: &reqwest::Client) -> () {
|
||||
// stats details are closed source
|
||||
}
|
||||
|
||||
#[derive(Debug, sqlx::FromRow, serde::Serialize)]
|
||||
struct JobsUsage {
|
||||
language: Option<ScriptLang>,
|
||||
total_duration: i64,
|
||||
count: i64,
|
||||
}
|
||||
|
||||
pub enum SendStatsReason {
|
||||
Manual,
|
||||
Schedule,
|
||||
OnStart,
|
||||
}
|
||||
|
||||
pub async fn send_stats(
|
||||
_http_client: &reqwest::Client,
|
||||
_db: &DB,
|
||||
_skip_job_usage: bool,
|
||||
_reason: SendStatsReason,
|
||||
) -> Result<()> {
|
||||
// stats details are closed source
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub struct ActiveUserUsage {
|
||||
pub author_count: Option<i32>,
|
||||
pub operator_count: Option<i32>,
|
||||
}
|
||||
|
||||
pub async fn get_user_usage<'c, E: sqlx::Executor<'c, Database = Postgres>>(
|
||||
_db: E,
|
||||
) -> Result<ActiveUserUsage> {
|
||||
let usage = ActiveUserUsage { author_count: None, operator_count: None };
|
||||
Ok(usage)
|
||||
}
|
||||
1
backend/windmill-common/src/stats_ee.rs
Symbolic link
1
backend/windmill-common/src/stats_ee.rs
Symbolic link
@@ -0,0 +1 @@
|
||||
/git/windmill/../windmill-ee-private/windmill-common/src/stats_ee.rs
|
||||
@@ -303,14 +303,14 @@ fn parse_file<T: FromStr>(path: &str) -> Option<T> {
|
||||
.flatten()
|
||||
}
|
||||
|
||||
pub struct Annotations {
|
||||
pub struct TypeScriptAnnotations {
|
||||
pub npm_mode: bool,
|
||||
pub nodejs_mode: bool,
|
||||
pub native_mode: bool,
|
||||
pub nobundling: bool,
|
||||
}
|
||||
|
||||
pub fn get_annotation(inner_content: &str) -> Annotations {
|
||||
pub fn get_annotation_ts(inner_content: &str) -> TypeScriptAnnotations {
|
||||
let annotations = inner_content
|
||||
.lines()
|
||||
.take_while(|x| x.starts_with("//"))
|
||||
@@ -324,7 +324,25 @@ pub fn get_annotation(inner_content: &str) -> Annotations {
|
||||
let nobundling: bool =
|
||||
annotations.contains(&"nobundling".to_string()) || nodejs_mode || *DISABLE_BUNDLING;
|
||||
|
||||
Annotations { npm_mode, nodejs_mode, native_mode, nobundling }
|
||||
TypeScriptAnnotations { npm_mode, nodejs_mode, native_mode, nobundling }
|
||||
}
|
||||
|
||||
pub struct PythonAnnotations {
|
||||
pub no_uv: bool,
|
||||
pub no_cache: bool,
|
||||
}
|
||||
|
||||
pub fn get_annotation_python(inner_content: &str) -> PythonAnnotations {
|
||||
let annotations = inner_content
|
||||
.lines()
|
||||
.take_while(|x| x.starts_with("#"))
|
||||
.map(|x| x.to_string().replace("#", "").trim().to_string())
|
||||
.collect_vec();
|
||||
|
||||
let no_uv: bool = annotations.contains(&"no_uv".to_string());
|
||||
let no_cache: bool = annotations.contains(&"no_cache".to_string());
|
||||
|
||||
PythonAnnotations { no_uv, no_cache }
|
||||
}
|
||||
|
||||
pub struct SqlAnnotations {
|
||||
@@ -449,10 +467,13 @@ pub async fn save_cache(
|
||||
fn write_binary_file(main_path: &str, byts: &mut bytes::Bytes) -> error::Result<()> {
|
||||
use std::fs::{File, Permissions};
|
||||
use std::io::Write;
|
||||
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
|
||||
let mut file = File::create(main_path)?;
|
||||
file.write_all(byts)?;
|
||||
#[cfg(unix)]
|
||||
file.set_permissions(Permissions::from_mode(0o755))?;
|
||||
file.flush()?;
|
||||
Ok(())
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user