Compare commits

...

10 Commits

Author SHA1 Message Date
Ruben Fiszel
649872ab0d all 2024-10-17 15:18:03 +02:00
Ruben Fiszel
b7ad19bb75 fix(nsjail): improve memory reading when using nsjail 2024-10-17 07:42:30 +02:00
Ruben Fiszel
45bf59ba32 chore(main): release 1.409.2 (#4541)
* chore(main): release 1.409.2

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <rubenfiszel@users.noreply.github.com>
2024-10-17 01:22:18 +02:00
Ruben Fiszel
1466da3999 fix: add extra args support for exception to bun scripts 2024-10-17 01:19:25 +02:00
Ruben Fiszel
3174024d8e fix: fix script persistence in url + add support for extra error args in python 2024-10-17 01:07:56 +02:00
Ruben Fiszel
4e6c0d1e80 chore(main): release 1.409.1 (#4540)
* chore(main): release 1.409.1

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <rubenfiszel@users.noreply.github.com>
2024-10-17 00:08:06 +02:00
Ruben Fiszel
6abb346013 fix(git-sync): propagate update of folders with git sync 2024-10-16 23:44:56 +02:00
Ruben Fiszel
79100f8d0a move to lto thin 2024-10-16 23:39:51 +02:00
Ruben Fiszel
28f6f6b067 chore: update bun to 1.30.0 2024-10-16 22:53:42 +02:00
Ruben Fiszel
d24e153065 fix(apidocs): fix generated openapi files 2024-10-16 22:11:56 +02:00
51 changed files with 7230 additions and 1928 deletions

View File

@@ -1,5 +1,21 @@
# 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)

View File

@@ -177,7 +177,7 @@ COPY --from=builder /windmill/target/release/windmill ${APP}/windmill
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

50
backend/Cargo.lock generated
View File

@@ -5541,9 +5541,9 @@ dependencies = [
[[package]]
name = "openssl"
version = "0.10.67"
version = "0.10.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b8cefcf97f41316955f9294cd61f639bdcfa9f2f230faac6cb896aa8ab64704"
checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5"
dependencies = [
"bitflags 2.6.0",
"cfg-if",
@@ -10358,7 +10358,7 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windmill"
version = "1.409.0"
version = "1.409.2"
dependencies = [
"anyhow",
"axum",
@@ -10399,7 +10399,7 @@ dependencies = [
[[package]]
name = "windmill-api"
version = "1.409.0"
version = "1.409.2"
dependencies = [
"anyhow",
"argon2",
@@ -10483,7 +10483,7 @@ dependencies = [
[[package]]
name = "windmill-api-client"
version = "1.409.0"
version = "1.409.2"
dependencies = [
"base64 0.21.7",
"chrono",
@@ -10501,7 +10501,7 @@ dependencies = [
[[package]]
name = "windmill-audit"
version = "1.409.0"
version = "1.409.2"
dependencies = [
"chrono",
"serde",
@@ -10514,7 +10514,7 @@ dependencies = [
[[package]]
name = "windmill-common"
version = "1.409.0"
version = "1.409.2"
dependencies = [
"anyhow",
"async-stream",
@@ -10538,6 +10538,7 @@ dependencies = [
"magic-crypt",
"mail-send",
"object_store",
"openidconnect",
"prometheus",
"rand 0.8.5",
"regex",
@@ -10559,7 +10560,7 @@ dependencies = [
[[package]]
name = "windmill-git-sync"
version = "1.409.0"
version = "1.409.2"
dependencies = [
"regex",
"rsmq_async",
@@ -10574,7 +10575,7 @@ dependencies = [
[[package]]
name = "windmill-indexer"
version = "1.409.0"
version = "1.409.2"
dependencies = [
"anyhow",
"bytes",
@@ -10596,7 +10597,7 @@ dependencies = [
[[package]]
name = "windmill-parser"
version = "1.409.0"
version = "1.409.2"
dependencies = [
"convert_case 0.6.0",
"serde",
@@ -10605,7 +10606,7 @@ dependencies = [
[[package]]
name = "windmill-parser-bash"
version = "1.409.0"
version = "1.409.2"
dependencies = [
"anyhow",
"lazy_static",
@@ -10617,7 +10618,7 @@ dependencies = [
[[package]]
name = "windmill-parser-go"
version = "1.409.0"
version = "1.409.2"
dependencies = [
"anyhow",
"gosyn",
@@ -10629,7 +10630,7 @@ dependencies = [
[[package]]
name = "windmill-parser-graphql"
version = "1.409.0"
version = "1.409.2"
dependencies = [
"anyhow",
"lazy_static",
@@ -10641,7 +10642,7 @@ dependencies = [
[[package]]
name = "windmill-parser-php"
version = "1.409.0"
version = "1.409.2"
dependencies = [
"anyhow",
"itertools 0.13.0",
@@ -10652,7 +10653,7 @@ dependencies = [
[[package]]
name = "windmill-parser-py"
version = "1.409.0"
version = "1.409.2"
dependencies = [
"anyhow",
"itertools 0.13.0",
@@ -10663,7 +10664,7 @@ dependencies = [
[[package]]
name = "windmill-parser-py-imports"
version = "1.409.0"
version = "1.409.2"
dependencies = [
"anyhow",
"async-recursion",
@@ -10681,7 +10682,7 @@ dependencies = [
[[package]]
name = "windmill-parser-rust"
version = "1.409.0"
version = "1.409.2"
dependencies = [
"anyhow",
"convert_case 0.6.0",
@@ -10698,7 +10699,7 @@ dependencies = [
[[package]]
name = "windmill-parser-sql"
version = "1.409.0"
version = "1.409.2"
dependencies = [
"anyhow",
"lazy_static",
@@ -10710,7 +10711,7 @@ dependencies = [
[[package]]
name = "windmill-parser-ts"
version = "1.409.0"
version = "1.409.2"
dependencies = [
"anyhow",
"lazy_static",
@@ -10728,7 +10729,7 @@ dependencies = [
[[package]]
name = "windmill-parser-wasm"
version = "1.409.0"
version = "1.409.2"
dependencies = [
"anyhow",
"getrandom 0.2.15",
@@ -10749,7 +10750,7 @@ dependencies = [
[[package]]
name = "windmill-parser-yaml"
version = "1.409.0"
version = "1.409.2"
dependencies = [
"anyhow",
"serde_json",
@@ -10759,7 +10760,7 @@ dependencies = [
[[package]]
name = "windmill-queue"
version = "1.409.0"
version = "1.409.2"
dependencies = [
"anyhow",
"async-recursion",
@@ -10792,7 +10793,7 @@ dependencies = [
[[package]]
name = "windmill-sql-datatype-parser-wasm"
version = "1.409.0"
version = "1.409.2"
dependencies = [
"wasm-bindgen",
"wasm-bindgen-test",
@@ -10802,7 +10803,7 @@ dependencies = [
[[package]]
name = "windmill-worker"
version = "1.409.0"
version = "1.409.2"
dependencies = [
"anyhow",
"async-recursion",
@@ -10836,7 +10837,6 @@ dependencies = [
"nix",
"object_store",
"once_cell",
"openidconnect",
"pem 3.0.4",
"postgres-native-tls",
"prometheus",

View File

@@ -1,6 +1,6 @@
[package]
name = "windmill"
version = "1.409.0"
version = "1.409.2"
authors.workspace = true
edition.workspace = true
@@ -27,7 +27,7 @@ members = [
]
[workspace.package]
version = "1.409.0"
version = "1.409.2"
authors = ["Ruben Fiszel <ruben@windmill.dev>"]
edition = "2021"
@@ -40,7 +40,7 @@ opt-level = 0
incremental = true
[profile.release]
lto = "fat"
lto = "thin"
[features]
default = []
@@ -54,7 +54,7 @@ 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"]

View File

@@ -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
View File

@@ -0,0 +1 @@
/git/windmill/../windmill-ee-private/src/ee.rs

View File

@@ -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

View File

@@ -1,7 +1,7 @@
openapi: "3.0.3"
info:
version: 1.409.0
version: 1.409.2
title: Windmill API
contact:

View File

@@ -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
}
}

View File

@@ -0,0 +1 @@
/git/windmill/../windmill-ee-private/windmill-api/src/ee.rs

View File

@@ -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,

View File

@@ -1,5 +0,0 @@
use axum::Router;
pub fn workspaced_service() -> Router {
Router::new()
}

View File

@@ -0,0 +1 @@
/git/windmill/../windmill-ee-private/windmill-api/src/indexer_ee.rs

View File

@@ -1,5 +0,0 @@
use axum::Router;
pub fn workspaced_service() -> Router {
Router::new()
}

View File

@@ -0,0 +1 @@
/git/windmill/../windmill-ee-private/windmill-api/src/job_helpers_ee.rs

View File

@@ -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"))
}
}

View File

@@ -0,0 +1 @@
/git/windmill/../windmill-ee-private/windmill-api/src/oauth2_ee.rs

View File

@@ -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()
}

View File

@@ -0,0 +1 @@
/git/windmill/../windmill-ee-private/windmill-api/src/oidc_ee.rs

View File

@@ -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()
}

View File

@@ -0,0 +1 @@
/git/windmill/../windmill-ee-private/windmill-api/src/saml_ee.rs

View File

@@ -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!()
}

View File

@@ -0,0 +1 @@
/git/windmill/../windmill-ee-private/windmill-api/src/scim_ee.rs

View File

@@ -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"))
}
}

View File

@@ -0,0 +1 @@
/git/windmill/../windmill-ee-private/windmill-api/src/smtp_server_ee.rs

View File

@@ -1,7 +0,0 @@
#[cfg(feature = "stripe")]
use axum::Router;
#[cfg(feature = "stripe")]
pub fn add_stripe_routes(router: Router) -> Router {
return router;
}

View File

@@ -0,0 +1 @@
/git/windmill/../windmill-ee-private/windmill-api/src/stripe_ee.rs

View File

@@ -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(),
))
}

View File

@@ -0,0 +1 @@
/git/windmill/../windmill-ee-private/windmill-audit/src/audit_ee.rs

View File

@@ -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 }

View File

@@ -1,86 +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) {}
#[cfg(feature = "enterprise")]
pub async fn jobs_waiting_alerts(_db: &DB) {}

View File

@@ -0,0 +1 @@
/git/windmill/../windmill-ee-private/windmill-common/src/ee.rs

View File

@@ -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) {}

View File

@@ -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) {}

View File

@@ -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!()
}

View File

@@ -0,0 +1 @@
/git/windmill/../windmill-ee-private/windmill-common/src/job_s3_helpers_ee.rs

View File

@@ -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;

View 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,
}

View File

@@ -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(),
));
}
}
}
}

View File

@@ -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)
}

View File

@@ -0,0 +1 @@
/git/windmill/../windmill-ee-private/windmill-common/src/stats_ee.rs

View File

@@ -1,17 +0,0 @@
use windmill_common::error::Result;
use crate::{DeployedObject, DB};
pub async fn handle_deployment_metadata<'c, R: rsmq_async::RsmqConnection + Send + Clone + 'c>(
_email: &str,
_created_by: &str,
_db: &DB,
_w_id: &str,
_obj: DeployedObject,
_deployment_message: Option<String>,
_rsmq: Option<R>,
_skip_db_insert: bool,
) -> Result<()> {
// Git sync is an enterprise feature and not part of the open-source version
return Ok(());
}

View File

@@ -0,0 +1 @@
/git/windmill/../windmill-ee-private/windmill-git-sync/src/git_sync_ee.rs

View File

@@ -1,21 +0,0 @@
use anyhow::anyhow;
use sqlx::{Pool, Postgres};
use windmill_common::error::Error;
#[derive(Clone)]
pub struct IndexReader;
#[derive(Clone)]
pub struct IndexWriter;
pub async fn init_index() -> Result<(IndexReader, IndexWriter), Error> {
Err(anyhow!("Cannot initialize index: not in EE").into())
}
pub async fn run_indexer(
_db: Pool<Postgres>,
mut _index_writer: IndexWriter,
mut _killpill_rx: tokio::sync::broadcast::Receiver<()>,
) {
tracing::error!("Cannot run indexer: not in EE");
}

View File

@@ -0,0 +1 @@
/git/windmill/../windmill-ee-private/windmill-indexer/src/indexer_ee.rs

View File

@@ -11,7 +11,7 @@ path = "src/lib.rs"
[features]
default = []
prometheus = ["dep:prometheus", "windmill-common/prometheus"]
enterprise = ["windmill-queue/enterprise", "windmill-git-sync/enterprise", "windmill-common/enterprise", "dep:gcp_auth", "dep:pem", "dep:tiberius", "dep:tokio-util", "dep:openidconnect"]
enterprise = ["windmill-queue/enterprise", "windmill-git-sync/enterprise", "windmill-common/enterprise", "dep:gcp_auth", "dep:pem", "dep:tiberius", "dep:tokio-util"]
benchmark = ["windmill-queue/benchmark", "windmill-common/benchmark"]
flamegraph = []
parquet = ["windmill-common/parquet", "dep:object_store"]
@@ -85,7 +85,6 @@ reqwest.workspace = true
hex.workspace = true
tiberius = { workspace = true, optional = true }
tokio-util = { workspace = true, optional = true }
openidconnect = { workspace = true, optional = true}
tar.workspace = true
object_store = { workspace = true, optional = true}
convert_case.workspace = true

View File

@@ -1105,6 +1105,16 @@ try {{
if (step_id) {{
err["step_id"] = step_id;
}}
const extra = {{}};
Object.getOwnPropertyNames(e).forEach((key) => {{
if (['line', 'name', 'stack', 'column', 'message', 'sourceURL', 'originalLine', 'originalColumn'].includes(key)) {{
return;
}}
extra[key] = e[key];
}});
if (Object.keys(extra).length > 0) {{
err["extra"] = extra;
}}
await fs.writeFile("result.json", JSON.stringify(err));
process.exit(1);
}}
@@ -1435,7 +1445,7 @@ try {{
mem_peak,
canceled_by,
child,
false,
!*DISABLE_NSJAIL,
worker_name,
&job.workspace_id,
"bun run",

View File

@@ -414,9 +414,30 @@ async fn get_mem_peak(pid: Option<u32>, nsjail: bool) -> i32 {
return -1;
}
let pid = if nsjail {
// This is a bit hacky, but the process id of the nsjail process is the pid of nsjail + 1.
// Ideally, we would get the number from fork() itself. This works in MOST cases.
pid.unwrap() + 1
// Read /proc/<nsjail_pid>/task/<nsjail_pid>/children and extract pid
let nsjail_pid = pid.unwrap();
let children_path = format!("/proc/{}/task/{}/children", nsjail_pid, nsjail_pid);
if let Ok(mut file) = File::open(children_path).await {
let mut contents = String::new();
if tokio::io::AsyncReadExt::read_to_string(&mut file, &mut contents)
.await
.is_ok()
{
if let Some(child_pid) = contents.split_whitespace().next() {
if let Ok(child_pid) = child_pid.parse::<u32>() {
child_pid
} else {
return -1;
}
} else {
return -1;
}
} else {
return -1;
}
} else {
return -1;
}
} else {
pid.unwrap()
};

View File

@@ -345,7 +345,7 @@ try {{
mem_peak,
canceled_by,
child,
false,
!*DISABLE_NSJAIL,
worker_name,
&job.workspace_id,
"php run",

View File

@@ -498,7 +498,10 @@ except BaseException as e:
exc_type, exc_value, exc_traceback = sys.exc_info()
tb = traceback.format_tb(exc_traceback)
with open(result_json, 'w') as f:
err = {{ "message": str(e), "name": e.__class__.__name__, "stack": '\n'.join(tb[1:]) }}
err = {{ "message": str(e), "name": e.__class__.__name__, "stack": '\n'.join(tb[1:]) }}
extra = e.__dict__
if extra and len(extra) > 0:
err['extra'] = extra
flow_node_id = os.environ.get('WM_FLOW_STEP_ID')
if flow_node_id:
err['step_id'] = flow_node_id

View File

@@ -2,7 +2,7 @@ import { sleep } from "https://deno.land/x/sleep@v1.2.1/mod.ts";
import * as windmill from "https://deno.land/x/windmill@v1.174.0/mod.ts";
import * as api from "https://deno.land/x/windmill@v1.174.0/windmill-api/index.ts";
export const VERSION = "v1.409.0";
export const VERSION = "v1.409.2";
export async function login(email: string, password: string): Promise<string> {
return await windmill.UserService.login({

View File

@@ -60,7 +60,7 @@ export {
// }
// });
export const VERSION = "1.409.0";
export const VERSION = "1.409.2";
const command = new Command()
.name("wmill")

View File

@@ -1,12 +1,12 @@
{
"name": "windmill-components",
"version": "1.409.0",
"version": "1.409.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "windmill-components",
"version": "1.409.0",
"version": "1.409.2",
"license": "AGPL-3.0",
"dependencies": {
"@aws-crypto/sha256-js": "^4.0.0",

View File

@@ -1,6 +1,6 @@
{
"name": "windmill-components",
"version": "1.409.0",
"version": "1.409.2",
"scripts": {
"dev": "vite dev",
"build": "vite build",

View File

@@ -559,6 +559,11 @@
<pre class="text-xs pt-2 whitespace-pre-wrap text-primary"
>{result.error.stack ?? ''}</pre
>
{#if result.error?.extra}
<pre class="text-xs pt-2 whitespace-pre-wrap text-primary"
>{JSON.stringify(result.error.extra, null, 4)}</pre
>
{/if}
<slot />
</div>
{#if language === 'bun'}

View File

@@ -197,7 +197,7 @@
}
$: !disableHistoryChange &&
replaceStateFn('#' + encodeState({ script, primarySchedule: $primaryScheduleStore }))
replaceStateFn('#' + encodeState({ ...script, primarySchedule: $primaryScheduleStore }))
if (script.content == '') {
initContent(script.language, script.kind, template)

View File

@@ -39,7 +39,7 @@
return decoded
} catch (e) {
console.error('Error decoding state', e)
return defaultScript
return defaultScript()
}
}

View File

@@ -4,8 +4,8 @@ verify_ssl = true
name = "pypi"
[packages]
wmill = ">=1.409.0"
wmill_pg = ">=1.409.0"
wmill = ">=1.409.2"
wmill_pg = ">=1.409.2"
sendgrid = "*"
mysql-connector-python = "*"
pymongo = "*"

View File

@@ -1,7 +1,7 @@
openapi: "3.0.3"
info:
version: 1.409.0
version: 1.409.2
title: OpenFlow Spec
contact:
name: Ruben Fiszel

View File

@@ -12,7 +12,7 @@
RootModule = 'WindmillClient.psm1'
# Version number of this module.
ModuleVersion = '1.409.0'
ModuleVersion = '1.409.2'
# Supported PSEditions
# CompatiblePSEditions = @()

View File

@@ -1,6 +1,6 @@
[tool.poetry]
name = "wmill"
version = "1.409.0"
version = "1.409.2"
description = "A client library for accessing Windmill server wrapping the Windmill client API"
license = "Apache-2.0"
homepage = "https://windmill.dev"

View File

@@ -1,6 +1,6 @@
[tool.poetry]
name = "wmill-pg"
version = "1.409.0"
version = "1.409.2"
description = "An extension client for the wmill client library focused on pg"
license = "Apache-2.0"
homepage = "https://windmill.dev"

View File

@@ -1,6 +1,6 @@
{
"name": "@windmill/windmill",
"version": "1.409.0",
"version": "1.409.2",
"exports": "./src/index.ts",
"publish": {
"exclude": ["!src", "./s3Types.ts", "./client.ts"]

View File

@@ -1,7 +1,7 @@
{
"name": "windmill-client",
"description": "Windmill SDK client for browsers and Node.js",
"version": "1.409.0",
"version": "1.409.2",
"author": "Ruben Fiszel",
"license": "Apache 2.0",
"devDependencies": {

View File

@@ -1 +1 @@
1.409.0
1.409.2