FROM ghcr.io/windmill-labs/windmill:dev # Rust COPY --from=rust:1.97.0 /usr/local/cargo /usr/local/cargo COPY --from=rust:1.97.0 /usr/local/rustup /usr/local/rustup RUN RUSTUP_HOME=/usr/local/rustup CARGO_HOME=/usr/local/cargo /usr/local/cargo/bin/cargo install cargo-sweep --version ^0.7 # Ansible # UV_PYTHON_INSTALL_DIR defaults to /tmp/windmill/cache/py_runtime, which is an # ephemeral runtime cache (fresh volume/tmpfs, and pruned by the worker). Installing # ansible there leaves its venv interpreter as a dangling symlink at runtime, so every # ansible-* executable fails with ENOENT ("ansible-galaxy not found"). Pin the tool's # interpreter to a persistent image path so the install stays self-contained. RUN UV_PYTHON_INSTALL_DIR=/usr/local/uv/py uv tool install ansible && [ -d "$(uv tool dir)/ansible/bin/" ] && find "$(uv tool dir)/ansible/bin/" -mindepth 1 -maxdepth 1 -type f -executable -regextype posix-extended -regex '^((.+/)?)[^.]+' -print0 | xargs -0 ln -sf -t "$UV_TOOL_BIN_DIR/" || true # C# RUN wget https://dot.net/v1/dotnet-install.sh -O dotnet-install.sh \ && chmod +x dotnet-install.sh \ && ./dotnet-install.sh --channel 9.0 --install-dir /usr/share/dotnet \ && ln -s /usr/share/dotnet/dotnet /usr/bin/dotnet \ && rm dotnet-install.sh # Nushell COPY --from=ghcr.io/nushell/nushell:0.101.0-bookworm /usr/bin/nu /usr/bin/nu # Java RUN apt-get -y update && apt-get install -y default-jdk ARG COURSIER_VERSION=2.1.24 # The released coursier launcher downloads its own JARs from Maven Central on first run, so java # jobs break on air-gapped networks; a build-time cache pre-warm cannot fix that because the cache # the worker reads lives under WINDMILL_DIR, which deployments mount over. Hence a self-contained # assembly, smoke-tested below: `about` must succeed and leave the cache it is given empty. RUN curl -fLo /tmp/coursier-launcher https://github.com/coursier/coursier/releases/download/v${COURSIER_VERSION}/coursier \ && COURSIER_CACHE=/tmp/coursier-build-cache /usr/bin/java -jar /tmp/coursier-launcher \ bootstrap io.get-coursier:coursier-cli_2.13:${COURSIER_VERSION} --assembly -o /usr/bin/coursier \ && chmod +x /usr/bin/coursier \ && mkdir -p /tmp/coursier-verify \ && COURSIER_CACHE=/tmp/coursier-verify /usr/bin/java -jar /usr/bin/coursier about \ && [ -z "$(ls -A /tmp/coursier-verify)" ] \ && rm -rf /tmp/coursier-launcher /tmp/coursier-build-cache /tmp/coursier-verify /root/.cache/coursier # Ruby RUN apt-get install -y ruby ruby-bundler # R RUN apt-get install -y r-base-dev \ && Rscript -e 'install.packages("renv", lib="/usr/lib/R/library", repos="https://cloud.r-project.org")' # dbt # NO dbt engine is baked in. Fusion may not be: its license grants only a # non-transferable, non-sublicensable redistribution right. dbt-core 1.x cannot # be, because its adapter is a Python package chosen per project. dbt-core 2.x # could be — one adapter-agnostic binary — but shipping a pre-release nobody is # defaulted onto costs a layer in every image and a version pinned in two places # that nothing keeps in step. The worker fetches whichever engine a project asks # for on first use and caches it (docs/dbt-runtime.md, decision 1). # # An operator who wants one pre-staged — an air-gapped instance, or a fleet that # should not fetch per worker — populates `DBT_BUNDLED_DIR` (default # /usr/local/dbt) with `core2x-/dbt-sa-cli` in their own image layer. # Fix UV cache permissions for non-root user support (uid 1000, etc.) # The uv tool install ansible command populates the UV cache with root-owned files RUN chmod -R a+rw /tmp/windmill/cache/uv && \ find /tmp/windmill/cache/uv -type d -exec chmod 777 {} +