From 43a24d997e697a69ecd24bfadf79773859ca54b0 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Thu, 23 May 2024 11:12:51 +0200 Subject: [PATCH] Revert "feat: improve premissioned audit logs (#3793)" (#3798) This reverts commit 21a077ecfaa2dfabe6a46e425214182845b5259e. --- ...fd9222aa707ee76de6ce348337c3e403eb955.json | 15 -- ...21f4722bbc93d52e05656b82cb42ba9803ef6.json | 23 ++ ...a5f7360008e082e2fb8d58faff4461e18c83a.json | 23 ++ backend/ee-repo-ref.txt | 2 +- backend/src/monitor.rs | 7 +- backend/windmill-api/openapi.yaml | 21 -- backend/windmill-api/src/apps.rs | 6 +- backend/windmill-api/src/configs.rs | 4 +- backend/windmill-api/src/db.rs | 23 -- backend/windmill-api/src/flows.rs | 8 +- backend/windmill-api/src/folders.rs | 10 +- backend/windmill-api/src/groups.rs | 20 +- backend/windmill-api/src/jobs.rs | 214 +++++++---------- backend/windmill-api/src/openai.rs | 2 +- backend/windmill-api/src/raw_apps.rs | 10 +- backend/windmill-api/src/resources.rs | 27 +-- backend/windmill-api/src/schedule.rs | 10 +- backend/windmill-api/src/scripts.rs | 12 +- backend/windmill-api/src/users.rs | 224 +++++++----------- backend/windmill-api/src/variables.rs | 16 +- backend/windmill-api/src/workspaces.rs | 118 +++++---- backend/windmill-audit/src/audit_ee.rs | 29 +-- backend/windmill-queue/src/jobs.rs | 18 +- backend/windmill-worker/src/worker.rs | 10 +- .../auditLogs/AuditLogsTable.svelte | 7 +- 25 files changed, 349 insertions(+), 510 deletions(-) delete mode 100644 backend/.sqlx/query-3da14e6c89a33871e4bd40524e2fd9222aa707ee76de6ce348337c3e403eb955.json create mode 100644 backend/.sqlx/query-62cd69e3dc0f8757db3481d078921f4722bbc93d52e05656b82cb42ba9803ef6.json create mode 100644 backend/.sqlx/query-da5da57ea48ddc6ab271b6c18baa5f7360008e082e2fb8d58faff4461e18c83a.json diff --git a/backend/.sqlx/query-3da14e6c89a33871e4bd40524e2fd9222aa707ee76de6ce348337c3e403eb955.json b/backend/.sqlx/query-3da14e6c89a33871e4bd40524e2fd9222aa707ee76de6ce348337c3e403eb955.json deleted file mode 100644 index 3c2cee1de4..0000000000 --- a/backend/.sqlx/query-3da14e6c89a33871e4bd40524e2fd9222aa707ee76de6ce348337c3e403eb955.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "DELETE FROM usr WHERE email = $1 AND workspace_id = $2", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Text", - "Text" - ] - }, - "nullable": [] - }, - "hash": "3da14e6c89a33871e4bd40524e2fd9222aa707ee76de6ce348337c3e403eb955" -} diff --git a/backend/.sqlx/query-62cd69e3dc0f8757db3481d078921f4722bbc93d52e05656b82cb42ba9803ef6.json b/backend/.sqlx/query-62cd69e3dc0f8757db3481d078921f4722bbc93d52e05656b82cb42ba9803ef6.json new file mode 100644 index 0000000000..68c8af06ea --- /dev/null +++ b/backend/.sqlx/query-62cd69e3dc0f8757db3481d078921f4722bbc93d52e05656b82cb42ba9803ef6.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "DELETE FROM usr WHERE email = $1 AND workspace_id = $2 RETURNING username", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "username", + "type_info": "Varchar" + } + ], + "parameters": { + "Left": [ + "Text", + "Text" + ] + }, + "nullable": [ + false + ] + }, + "hash": "62cd69e3dc0f8757db3481d078921f4722bbc93d52e05656b82cb42ba9803ef6" +} diff --git a/backend/.sqlx/query-da5da57ea48ddc6ab271b6c18baa5f7360008e082e2fb8d58faff4461e18c83a.json b/backend/.sqlx/query-da5da57ea48ddc6ab271b6c18baa5f7360008e082e2fb8d58faff4461e18c83a.json new file mode 100644 index 0000000000..c4c166cd80 --- /dev/null +++ b/backend/.sqlx/query-da5da57ea48ddc6ab271b6c18baa5f7360008e082e2fb8d58faff4461e18c83a.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT username FROM usr WHERE workspace_id = $1 AND email = $2", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "username", + "type_info": "Varchar" + } + ], + "parameters": { + "Left": [ + "Text", + "Text" + ] + }, + "nullable": [ + false + ] + }, + "hash": "da5da57ea48ddc6ab271b6c18baa5f7360008e082e2fb8d58faff4461e18c83a" +} diff --git a/backend/ee-repo-ref.txt b/backend/ee-repo-ref.txt index 97efd815c6..df0f445015 100644 --- a/backend/ee-repo-ref.txt +++ b/backend/ee-repo-ref.txt @@ -1 +1 @@ -cb38edaf31affeda48317433d10903245aa518f2 \ No newline at end of file +229b7acc60691f7e6577c44f782676d6871defdd \ No newline at end of file diff --git a/backend/src/monitor.rs b/backend/src/monitor.rs index 23b1fadd60..a01856b668 100644 --- a/backend/src/monitor.rs +++ b/backend/src/monitor.rs @@ -1079,16 +1079,11 @@ async fn handle_zombie_jobs mpsc::channel::(1); let (send_result_never_used, _send_result_rx_never_used) = mpsc::channel::(1); - let label = if job.permissioned_as != format!("u/{}", job.created_by) && job.permissioned_as != job.created_by { - format!("ephemeral-script-end-user-{}", job.created_by) - } else { - "ephemeral-script".to_string() - }; let token = create_token_for_owner( &db, &job.workspace_id, &job.permissioned_as, - &label, + "ephemeral-script", *SCRIPT_TOKEN_EXPIRY, &job.email, &job.id, diff --git a/backend/windmill-api/openapi.yaml b/backend/windmill-api/openapi.yaml index 51ea7e3697..b28af9f502 100644 --- a/backend/windmill-api/openapi.yaml +++ b/backend/windmill-api/openapi.yaml @@ -2025,27 +2025,6 @@ paths: items: type: string - /w/{workspace}/users/email_from_username/{username}: - get: - summary: get email from username - operationId: emailFromUsername - tags: - - user - parameters: - - $ref: "#/components/parameters/WorkspaceId" - - name: username - in: path - required: true - schema: - type: string - responses: - "200": - description: email - content: - text/plain: - schema: - type: string - /users/tokens/create: post: summary: create token diff --git a/backend/windmill-api/src/apps.rs b/backend/windmill-api/src/apps.rs index 34bde7be47..e6844f4ae8 100644 --- a/backend/windmill-api/src/apps.rs +++ b/backend/windmill-api/src/apps.rs @@ -585,7 +585,7 @@ async fn create_app( audit_log( &mut tx, - &authed, + &authed.username, "apps.create", ActionKind::Create, &w_id, @@ -701,7 +701,7 @@ async fn delete_app( audit_log( &mut *tx, - &authed, + &authed.username, "apps.delete", ActionKind::Delete, &w_id, @@ -873,7 +873,7 @@ async fn update_app( audit_log( &mut tx, - &authed, + &authed.username, "apps.update", ActionKind::Update, &w_id, diff --git a/backend/windmill-api/src/configs.rs b/backend/windmill-api/src/configs.rs index adeb7e9fbe..1e86f34890 100644 --- a/backend/windmill-api/src/configs.rs +++ b/backend/windmill-api/src/configs.rs @@ -122,7 +122,7 @@ async fn update_config( audit_log( &mut *tx, - &authed, + &authed.username, "worker_config.update", ActionKind::Update, "global", @@ -149,7 +149,7 @@ async fn delete_config( audit_log( &mut *tx, - &authed, + &authed.username, "worker_config.delete", ActionKind::Delete, "global", diff --git a/backend/windmill-api/src/db.rs b/backend/windmill-api/src/db.rs index 45ac404165..a854be7d37 100644 --- a/backend/windmill-api/src/db.rs +++ b/backend/windmill-api/src/db.rs @@ -15,7 +15,6 @@ use sqlx::{ pool::PoolConnection, PgConnection, Pool, Postgres, }; -use windmill_audit::audit_ee::{AuditAuthor, AuditAuthorable}; use windmill_common::{ db::{Authable, Authed}, error::Error, @@ -247,34 +246,12 @@ impl From for Authed { } } -impl From<&ApiAuthed> for AuditAuthor { - fn from(value: &ApiAuthed) -> Self { - Self { - email: value.email.clone(), - username: value.username.clone(), - username_override: value.username_override.clone(), - } - } -} - impl ApiAuthed { pub fn display_username(&self) -> &str { self.username_override.as_ref().unwrap_or(&self.username) } } -impl AuditAuthorable for ApiAuthed { - fn username(&self) -> &str { - self.username.as_str() - } - fn email(&self) -> &str { - self.email.as_str() - } - fn username_override(&self) -> Option<&str> { - self.username_override.as_deref() - } -} - impl Authable for ApiAuthed { fn is_admin(&self) -> bool { self.is_admin diff --git a/backend/windmill-api/src/flows.rs b/backend/windmill-api/src/flows.rs index 74b199a485..fb23cf87ee 100644 --- a/backend/windmill-api/src/flows.rs +++ b/backend/windmill-api/src/flows.rs @@ -348,7 +348,7 @@ async fn create_flow( audit_log( &mut tx, - &authed, + &authed.username, "flows.create", ActionKind::Create, &w_id, @@ -553,7 +553,7 @@ async fn update_flow( audit_log( &mut tx, - &authed, + &authed.username, "flows.update", ActionKind::Create, &w_id, @@ -746,7 +746,7 @@ async fn archive_flow_by_path( audit_log( &mut *tx, - &authed, + &authed.username, "flows.archive", ActionKind::Delete, &w_id, @@ -813,7 +813,7 @@ async fn delete_flow_by_path( audit_log( &mut *tx, - &authed, + &authed.username, "flows.delete", ActionKind::Delete, &w_id, diff --git a/backend/windmill-api/src/folders.rs b/backend/windmill-api/src/folders.rs index fc671b0c88..ac68c1318f 100644 --- a/backend/windmill-api/src/folders.rs +++ b/backend/windmill-api/src/folders.rs @@ -223,7 +223,7 @@ async fn create_folder( audit_log( &mut *tx, - &authed, + &authed.username, "folder.create", ActionKind::Create, &w_id, @@ -356,7 +356,7 @@ async fn update_folder( audit_log( &mut *tx, - &authed, + &authed.username, "folder.update", ActionKind::Update, &w_id, @@ -522,7 +522,7 @@ async fn delete_folder( audit_log( &mut *tx, - &authed, + &authed.username, "folder.delete", ActionKind::Delete, &w_id, @@ -585,7 +585,7 @@ async fn add_owner( audit_log( &mut *tx, - &authed, + &authed.username, "folder.add_owner", ActionKind::Update, &w_id, @@ -664,7 +664,7 @@ async fn remove_owner( audit_log( &mut *tx, - &authed, + &authed.username, "folder.remove_owner", ActionKind::Update, &w_id, diff --git a/backend/windmill-api/src/groups.rs b/backend/windmill-api/src/groups.rs index 3d36cb34c5..e7d8063ea7 100644 --- a/backend/windmill-api/src/groups.rs +++ b/backend/windmill-api/src/groups.rs @@ -252,7 +252,7 @@ async fn create_group( audit_log( &mut *tx, - &authed, + &authed.username, "group.create", ActionKind::Create, &w_id, @@ -296,7 +296,7 @@ async fn create_igroup( audit_log( &mut *tx, - &authed, + &authed.username, "igroup.create", ActionKind::Create, "global", @@ -337,7 +337,7 @@ async fn update_igroup( audit_log( &mut *tx, - &authed, + &authed.username, "igroup.updated", ActionKind::Delete, "global", @@ -367,7 +367,7 @@ async fn delete_igroup( audit_log( &mut *tx, - &authed, + &authed.username, "igroup.delete", ActionKind::Delete, "global", @@ -472,7 +472,7 @@ async fn delete_group( .await?; audit_log( &mut *tx, - &authed, + &authed.username, "group.delete", ActionKind::Delete, &w_id, @@ -522,7 +522,7 @@ async fn update_group( audit_log( &mut *tx, - &authed, + &authed.username, "group.edit", ActionKind::Update, &w_id, @@ -573,7 +573,7 @@ async fn add_user( audit_log( &mut *tx, - &authed, + &authed.username, "group.adduser", ActionKind::Update, &w_id, @@ -624,7 +624,7 @@ async fn add_user_igroup( audit_log( &mut *tx, - &authed, + &authed.username, "igroup.adduser", ActionKind::Update, "global", @@ -693,7 +693,7 @@ async fn remove_user_igroup( audit_log( &mut *tx, - &authed, + &authed.username, "igroup.removeuser", ActionKind::Update, "global", @@ -733,7 +733,7 @@ async fn remove_user( audit_log( &mut *tx, - &authed, + &authed.username, "group.removeuser", ActionKind::Update, &w_id, diff --git a/backend/windmill-api/src/jobs.rs b/backend/windmill-api/src/jobs.rs index c737809e66..897dea8b1b 100644 --- a/backend/windmill-api/src/jobs.rs +++ b/backend/windmill-api/src/jobs.rs @@ -51,7 +51,7 @@ use sqlx::types::JsonRawValue; use sqlx::{types::Uuid, FromRow, Postgres, Transaction}; use tower_http::cors::{Any, CorsLayer}; use urlencoding::encode; -use windmill_audit::audit_ee::{audit_log, AuditAuthor}; +use windmill_audit::audit_ee::audit_log; use windmill_audit::ActionKind; use windmill_common::worker::{to_raw_value, CUSTOM_TAGS_PER_WORKSPACE, SERVER_CONFIG}; use windmill_common::{ @@ -317,31 +317,18 @@ async fn cancel_job_api( ) -> error::Result { let tx = db.begin().await?; - let audit_author = match opt_authed { - Some(authed) => (&authed).into(), - None => AuditAuthor { - email: "anonymous".to_string(), - username: "anonymous".to_string(), - username_override: None, - }, + let username = match opt_authed { + Some(authed) => authed.username, + None => "anonymous".to_string(), }; - let (mut tx, job_option) = windmill_queue::cancel_job( - &audit_author.username, - reason, - id, - &w_id, - tx, - &db, - rsmq, - false, - ) - .await?; + let (mut tx, job_option) = + windmill_queue::cancel_job(&username, reason, id, &w_id, tx, &db, rsmq, false).await?; if let Some(id) = job_option { audit_log( &mut *tx, - &audit_author, + &username, "jobs.cancel", ActionKind::Delete, &w_id, @@ -371,17 +358,13 @@ async fn cancel_persistent_script_api( Path((w_id, script_path)): Path<(String, StripPath)>, Json(CancelJob { reason }): Json, ) -> error::Result<()> { - let audit_author = match opt_authed { - Some(authed) => (&authed).into(), - None => AuditAuthor { - email: "anonymous".to_string(), - username: "anonymous".to_string(), - username_override: None, - }, + let username = match opt_authed { + Some(authed) => authed.username, + None => "anonymous".to_string(), }; let cancelled_job_ids = windmill_queue::cancel_persistent_script_jobs( - &audit_author.username, + &username, reason, script_path.to_path(), &w_id, @@ -392,7 +375,7 @@ async fn cancel_persistent_script_api( audit_log( &db, - &audit_author, + &username, "jobs.cancel_persistent", ActionKind::Delete, &w_id, @@ -423,31 +406,18 @@ async fn force_cancel( ) -> error::Result { let tx = db.begin().await?; - let audit_author = match opt_authed { - Some(authed) => (&authed).into(), - None => AuditAuthor { - email: "anonymous".to_string(), - username: "anonymous".to_string(), - username_override: None, - }, + let username = match opt_authed { + Some(authed) => authed.username, + None => "anonymous".to_string(), }; - let (mut tx, job_option) = windmill_queue::cancel_job( - &audit_author.username, - reason, - id, - &w_id, - tx, - &db, - rsmq, - true, - ) - .await?; + let (mut tx, job_option) = + windmill_queue::cancel_job(&username, reason, id, &w_id, tx, &db, rsmq, true).await?; if let Some(id) = job_option { audit_log( &mut *tx, - &audit_author, + &username, "jobs.force_cancel", ActionKind::Delete, &w_id, @@ -963,6 +933,7 @@ impl From for ListQueueQuery { } } + pub fn filter_list_queue_query( mut sqlb: SqlBuilder, lq: &ListQueueQuery, @@ -1425,7 +1396,7 @@ async fn resume_suspended_job_internal( { approver.approver } else { - authed.as_ref().map(|x| x.username.clone()) + authed.map(|x| x.username) }; insert_resume_job( resume_id, @@ -1448,17 +1419,9 @@ async fn resume_suspended_job_internal( } else { resume_immediately_if_relevant(parent_flow_info, job_id, &mut tx).await?; } - - let audit_author = match authed { - Some(authed) => (&authed).into(), - None => { - let approver = approver.unwrap_or_else(|| "anonymous".to_string()); - AuditAuthor { email: approver.clone(), username: approver, username_override: None } - } - }; audit_log( &mut *tx, - &audit_author, + &approver.unwrap_or_else(|| "anonymous".to_string()), "jobs.approved", ActionKind::Update, &w_id, @@ -2084,75 +2047,76 @@ pub struct UnifiedJob { } const CJ_FIELDS: &[&str] = &[ - "'CompletedJob' as typ", - "id", - "workspace_id", - "parent_job", - "created_by", - "created_at", - "started_at", - "null as scheduled_for", - "null as running", - "script_hash", - "script_path", - "null as args", - "duration_ms", - "success", - "deleted", - "canceled", - "canceled_by", - "job_kind", - "schedule_path", - "permissioned_as", - "is_flow_step", - "language", - "is_skipped", - "email", - "visible_to_owner", - "null as suspend", - "mem_peak", - "tag", - "null as concurrent_limit", - "null as concurrency_time_window_s", - "priority", - "result->'wm_labels' as labels", -]; + "'CompletedJob' as typ", + "id", + "workspace_id", + "parent_job", + "created_by", + "created_at", + "started_at", + "null as scheduled_for", + "null as running", + "script_hash", + "script_path", + "null as args", + "duration_ms", + "success", + "deleted", + "canceled", + "canceled_by", + "job_kind", + "schedule_path", + "permissioned_as", + "is_flow_step", + "language", + "is_skipped", + "email", + "visible_to_owner", + "null as suspend", + "mem_peak", + "tag", + "null as concurrent_limit", + "null as concurrency_time_window_s", + "priority", + "result->'wm_labels' as labels", + ]; const QJ_FIELDS: &[&str] = &[ - "'QueuedJob' as typ", - "id", - "workspace_id", - "parent_job", - "created_by", - "created_at", - "started_at", - "scheduled_for", - "running", - "script_hash", - "script_path", - "null as args", - "null as duration_ms", - "null as success", - "false as deleted", - "canceled", - "canceled_by", - "job_kind", - "schedule_path", - "permissioned_as", - "is_flow_step", - "language", - "false as is_skipped", - "email", - "visible_to_owner", - "suspend", - "mem_peak", - "tag", - "concurrent_limit", - "concurrency_time_window_s", - "priority", - "null as labels", -]; + "'QueuedJob' as typ", + "id", + "workspace_id", + "parent_job", + "created_by", + "created_at", + "started_at", + "scheduled_for", + "running", + "script_hash", + "script_path", + "null as args", + "null as duration_ms", + "null as success", + "false as deleted", + "canceled", + "canceled_by", + "job_kind", + "schedule_path", + "permissioned_as", + "is_flow_step", + "language", + "false as is_skipped", + "email", + "visible_to_owner", + "suspend", + "mem_peak", + "tag", + "concurrent_limit", + "concurrency_time_window_s", + "priority", + "null as labels", + ]; impl UnifiedJob { + pub fn completed_job_fields() -> &'static [&'static str] { CJ_FIELDS } @@ -4354,7 +4318,7 @@ async fn delete_completed_job<'a>( audit_log( &mut *tx, - &authed, + &authed.username, "jobs.delete", ActionKind::Delete, &w_id, diff --git a/backend/windmill-api/src/openai.rs b/backend/windmill-api/src/openai.rs index 41962791f9..5e23bf05ad 100644 --- a/backend/windmill-api/src/openai.rs +++ b/backend/windmill-api/src/openai.rs @@ -317,7 +317,7 @@ async fn proxy( let mut tx = db.begin().await?; audit_log( &mut *tx, - &authed, + &authed.username, "openai.request", ActionKind::Execute, &w_id, diff --git a/backend/windmill-api/src/raw_apps.rs b/backend/windmill-api/src/raw_apps.rs index 35f3b9d708..5ec84a1c7e 100644 --- a/backend/windmill-api/src/raw_apps.rs +++ b/backend/windmill-api/src/raw_apps.rs @@ -134,7 +134,9 @@ async fn get_data( let app = not_found_if_none(app_o, "App", path)?; let res = Response::builder().header(header::CONTENT_TYPE, "text/javascript"); - Ok(res.body(Body::from(app)).unwrap()) + Ok(res + .body(Body::from(app)) + .unwrap()) } async fn create_app( @@ -179,7 +181,7 @@ async fn create_app( audit_log( &mut *tx, - &authed, + &authed.username, "apps.create", ActionKind::Create, &w_id, @@ -215,7 +217,7 @@ async fn delete_app( .await?; audit_log( &mut *tx, - &authed, + &authed.username, "apps.delete", ActionKind::Delete, &w_id, @@ -292,7 +294,7 @@ async fn update_app( let npath = app.path.clone().unwrap_or_else(|| path.to_owned()); audit_log( &mut *tx, - &authed, + &authed.username, "apps.update", ActionKind::Update, &w_id, diff --git a/backend/windmill-api/src/resources.rs b/backend/windmill-api/src/resources.rs index b2a1e76419..4cf69725ef 100644 --- a/backend/windmill-api/src/resources.rs +++ b/backend/windmill-api/src/resources.rs @@ -24,7 +24,7 @@ use serde_json::{value::RawValue, Value}; use sql_builder::{bind::Bind, quote, SqlBuilder}; use sqlx::{FromRow, Postgres, Transaction}; use uuid::Uuid; -use windmill_audit::audit_ee::{audit_log, AuditAuthor}; +use windmill_audit::audit_ee::audit_log; use windmill_audit::ActionKind; use windmill_common::{ db::UserDB, @@ -473,20 +473,15 @@ pub async fn transform_json_value<'c>( let path = y.strip_prefix("$var:").unwrap(); let tx: Transaction<'_, Postgres> = authed_transaction_or_default(authed, user_db.clone(), db).await?; - let v = crate::variables::get_value_internal( tx, db, workspace, path, - &user_db + user_db .clone() - .map(|_| authed.into()) - .unwrap_or(AuditAuthor { - email: "backend".to_string(), - username: "backend".to_string(), - username_override: None, - }), + .map(|_| authed.username.as_str()) + .unwrap_or("backend"), ) .await?; Ok(Value::String(v)) @@ -655,7 +650,7 @@ async fn create_resource( .await?; audit_log( &mut *tx, - &authed, + &authed.username, "resources.create", ActionKind::Create, &w_id, @@ -715,7 +710,7 @@ async fn delete_resource( .await?; audit_log( &mut *tx, - &authed, + &authed.username, "resources.delete", ActionKind::Delete, &w_id, @@ -801,7 +796,7 @@ async fn update_resource( audit_log( &mut *tx, - &authed, + &authed.username, "resources.update", ActionKind::Update, &w_id, @@ -862,7 +857,7 @@ async fn update_resource_value( .await?; audit_log( &mut *tx, - &authed, + &authed.username, "resources.update", ActionKind::Update, &w_id, @@ -1006,7 +1001,7 @@ async fn create_resource_type( audit_log( &mut *tx, - &authed, + &authed.username, "resource_types.create", ActionKind::Create, &w_id, @@ -1070,7 +1065,7 @@ async fn delete_resource_type( .await?; audit_log( &mut *tx, - &authed, + &authed.username, "resource_types.delete", ActionKind::Delete, &w_id, @@ -1126,7 +1121,7 @@ async fn update_resource_type( sqlx::query(&sql).execute(&mut *tx).await?; audit_log( &mut *tx, - &authed, + &authed.username, "resource_types.update", ActionKind::Update, &w_id, diff --git a/backend/windmill-api/src/schedule.rs b/backend/windmill-api/src/schedule.rs index b869cc352b..e084530fb1 100644 --- a/backend/windmill-api/src/schedule.rs +++ b/backend/windmill-api/src/schedule.rs @@ -201,7 +201,7 @@ async fn create_schedule( audit_log( &mut tx, - &authed, + &authed.username, "schedule.create", ActionKind::Create, &w_id, @@ -284,7 +284,7 @@ async fn edit_schedule( audit_log( &mut tx, - &authed, + &authed.username, "schedule.edit", ActionKind::Update, &w_id, @@ -496,7 +496,7 @@ pub async fn set_enabled( audit_log( &mut tx, - &authed, + &authed.username, "schedule.setenabled", ActionKind::Update, &w_id, @@ -544,7 +544,7 @@ pub async fn set_enabled( // audit_log( // &mut tx, -// &authed, +// &authed.username, // "schedule.setenabled", // ActionKind::Update, // &w_id, @@ -621,7 +621,7 @@ async fn delete_schedule( audit_log( &mut *tx, - &authed, + &authed.username, "schedule.delete", ActionKind::Delete, &w_id, diff --git a/backend/windmill-api/src/scripts.rs b/backend/windmill-api/src/scripts.rs index 9afeb8503e..f45cf13360 100644 --- a/backend/windmill-api/src/scripts.rs +++ b/backend/windmill-api/src/scripts.rs @@ -663,7 +663,7 @@ async fn create_script_internal<'c>( if p_hashes.is_some() && !p_hashes.unwrap().is_empty() { audit_log( &mut tx, - &authed, + &authed.username, "scripts.update", ActionKind::Update, &w_id, @@ -682,7 +682,7 @@ async fn create_script_internal<'c>( } else { audit_log( &mut tx, - &authed, + &authed.username, "scripts.create", ActionKind::Create, &w_id, @@ -1163,7 +1163,7 @@ async fn archive_script_by_path( .map_err(|e| Error::InternalErr(format!("archiving script in {w_id}: {e}")))?; audit_log( &mut *tx, - &authed, + &authed.username, "scripts.archive", ActionKind::Delete, &w_id, @@ -1215,7 +1215,7 @@ async fn archive_script_by_hash( audit_log( &mut *tx, - &authed, + &authed.username, "scripts.archive", ActionKind::Delete, &w_id, @@ -1255,7 +1255,7 @@ async fn delete_script_by_hash( audit_log( &mut *tx, - &authed, + &authed.username, "scripts.delete", ActionKind::Delete, &w_id, @@ -1322,7 +1322,7 @@ async fn delete_script_by_path( audit_log( &mut *tx, - &authed, + &authed.username, "scripts.delete", ActionKind::Delete, &w_id, diff --git a/backend/windmill-api/src/users.rs b/backend/windmill-api/src/users.rs index 83c34d0a88..ee3a8a66f5 100644 --- a/backend/windmill-api/src/users.rs +++ b/backend/windmill-api/src/users.rs @@ -40,7 +40,7 @@ use sqlx::FromRow; use time::OffsetDateTime; use tower_cookies::{Cookie, Cookies}; use tracing::{Instrument, Span}; -use windmill_audit::audit_ee::{audit_log, AuditAuthor}; +use windmill_audit::audit_ee::audit_log; use windmill_audit::ActionKind; use windmill_common::global_settings::AUTOMATE_USERNAME_CREATION_SETTING; use windmill_common::users::truncate_token; @@ -72,7 +72,6 @@ pub fn workspaced_service() -> Router { .route("/whois/:username", get(whois)) .route("/whoami", get(whoami)) .route("/leave", post(leave_workspace)) - .route("/email_from_username/:username", get(email_from_username)) } pub fn global_service() -> Router { @@ -119,16 +118,6 @@ pub fn make_unauthed_service() -> Router { fn username_override_from_label(label: Option) -> Option { if label.as_ref().is_some_and(|x| x.starts_with("webhook-")) { label - } else if label - .as_ref() - .is_some_and(|x| x.starts_with("ephemeral-script-end-user-")) - { - Some( - label - .unwrap() - .trim_start_matches("ephemeral-script-end-user-") - .to_string(), - ) } else { None } @@ -930,10 +919,9 @@ async fn logout( .fetch_optional(&mut *tx) .await?; if let Some(email) = email { - let email = email.unwrap_or("noemail".to_string()); audit_log( &mut *tx, - &AuditAuthor { email: email.clone(), username: email, username_override: None }, + &email.unwrap_or("noemail".to_string()), "users.logout", ActionKind::Delete, "global", @@ -1287,7 +1275,7 @@ async fn whois( // } async fn decline_invite( - authed: ApiAuthed, + ApiAuthed { email, .. }: ApiAuthed, Extension(db): Extension, Json(nu): Json, ) -> Result<(StatusCode, String)> { @@ -1296,18 +1284,18 @@ async fn decline_invite( let is_admin = sqlx::query_scalar!( "DELETE FROM workspace_invite WHERE workspace_id = $1 AND email = $2 RETURNING is_admin", nu.workspace_id, - authed.email, + email, ) .fetch_optional(&mut *tx) .await?; audit_log( &mut *tx, - &authed, + &email, "users.decline_invite", ActionKind::Delete, &nu.workspace_id, - Some(&authed.email), + Some(&email), None, ) .await?; @@ -1318,14 +1306,11 @@ async fn decline_invite( StatusCode::OK, format!( "user {} declined invite to workspace {}", - &authed.email, nu.workspace_id + &email, nu.workspace_id ), )) } else { - Err(Error::NotFound(format!( - "invite for {} not found", - authed.email - ))) + Err(Error::NotFound(format!("invite for {email} not found"))) } } @@ -1334,7 +1319,7 @@ lazy_static! { } async fn accept_invite( - authed: ApiAuthed, + ApiAuthed { email, .. }: ApiAuthed, Extension(webhook): Extension, Extension(db): Extension, Extension(rsmq): Extension>, @@ -1345,7 +1330,7 @@ async fn accept_invite( let r = sqlx::query!( "DELETE FROM workspace_invite WHERE workspace_id = $1 AND email = $2 RETURNING is_admin, operator", nu.workspace_id, - authed.email, + email, ) .fetch_optional(&mut *tx) .await?; @@ -1354,7 +1339,7 @@ async fn accept_invite( let already_in_workspace = sqlx::query_scalar!( "SELECT EXISTS(SELECT 1 FROM usr WHERE workspace_id = $1 AND email = $2)", &nu.workspace_id, - &authed.email, + &email, ) .fetch_one(&mut *tx) .await? @@ -1366,14 +1351,14 @@ async fn accept_invite( StatusCode::CREATED, format!( "user {} accepted invite to workspace {}", - &authed.email, nu.workspace_id + &email, nu.workspace_id ), )); } let username; - (tx, username) = join_workspace( + (tx, username) = add_user_to_workspace( &nu.workspace_id, - &authed, + &email, nu.username, r.is_admin, r.operator, @@ -1383,29 +1368,29 @@ async fn accept_invite( audit_log( &mut *tx, - &ApiAuthed { username: username.clone(), ..authed.clone() }, + &username, "users.accept_invite", ActionKind::Create, &nu.workspace_id, - Some(&authed.email), + Some(&email), None, ) .await?; tx.commit().await?; handle_deployment_metadata( - &authed.email, + &email, &username, &db, &nu.workspace_id, - windmill_git_sync::DeployedObject::User { email: authed.email.clone() }, - Some(format!("User '{}' accepted invite", &authed.email)), + windmill_git_sync::DeployedObject::User { email: email.clone() }, + Some(format!("User '{}' accepted invite", &email)), rsmq, true, ) .await?; webhook.send_instance_event(InstanceEvent::UserJoinedWorkspace { - email: authed.email.clone(), + email: email.clone(), workspace: nu.workspace_id.clone(), username: username, }); @@ -1413,20 +1398,17 @@ async fn accept_invite( StatusCode::CREATED, format!( "user {} accepted invite to workspace {}", - &authed.email, nu.workspace_id + &email, nu.workspace_id ), )) } else { - Err(Error::NotFound(format!( - "invite for {} not found", - authed.email - ))) + Err(Error::NotFound(format!("invite for {email} not found"))) } } -async fn join_workspace<'c>( +async fn add_user_to_workspace<'c>( w_id: &str, - authed: &ApiAuthed, + email: &str, username: Option, is_admin: bool, operator: bool, @@ -1448,7 +1430,7 @@ async fn join_workspace<'c>( "username is not allowed when username creation is automated".to_string(), )); } - get_instance_username_or_create_pending(&mut tx, &authed.email).await? + get_instance_username_or_create_pending(&mut tx, &email).await? } else { let username = username.ok_or(Error::BadRequest("username is required".to_string()))?; let already_exists_username = sqlx::query_scalar!( @@ -1478,7 +1460,7 @@ async fn join_workspace<'c>( let already_exists_email = sqlx::query_scalar!( "SELECT EXISTS(SELECT 1 FROM usr WHERE workspace_id = $1 AND email = $2)", &w_id, - authed.email, + username, ) .fetch_one(&mut *tx) .await? @@ -1487,7 +1469,7 @@ async fn join_workspace<'c>( if already_exists_email { return Err(Error::BadRequest(format!( "user with email {} already exists in workspace {}", - authed.email, w_id + email, w_id ))); } @@ -1496,7 +1478,7 @@ async fn join_workspace<'c>( (workspace_id, email, username, is_admin, operator) VALUES ($1, $2, $3, $4, $5)", &w_id, - authed.email, + email, username, is_admin, operator @@ -1514,30 +1496,33 @@ async fn join_workspace<'c>( .await?; audit_log( &mut *tx, - &AuditAuthor { username: username.clone(), ..authed.into() }, + &username, "users.add_to_workspace", ActionKind::Create, &w_id, - Some(&authed.email), + Some(email), None, ) .await?; Ok((tx, username)) } -async fn leave_instance(Extension(db): Extension, authed: ApiAuthed) -> Result { +async fn leave_instance( + Extension(db): Extension, + ApiAuthed { email, username, .. }: ApiAuthed, +) -> Result { let mut tx = db.begin().await?; - sqlx::query!("DELETE FROM password WHERE email = $1", &authed.email) + sqlx::query!("DELETE FROM password WHERE email = $1", &email) .execute(&mut *tx) .await?; audit_log( &mut *tx, - &authed, + &username, "workspaces.leave", ActionKind::Delete, "global", - Some(&authed.email), + Some(&email), None, ) .await?; @@ -1568,7 +1553,7 @@ async fn get_workspace_user( } async fn update_workspace_user( - authed: ApiAuthed, + ApiAuthed { username, email, is_admin, .. }: ApiAuthed, Extension(db): Extension, Extension(rsmq): Extension>, Path((w_id, username_to_update)): Path<(String, String)>, @@ -1576,7 +1561,7 @@ async fn update_workspace_user( ) -> Result { let mut tx = db.begin().await?; - require_admin(authed.is_admin, &authed.username)?; + require_admin(is_admin, &username)?; if let Some(a) = eu.is_admin { sqlx::query_scalar!( @@ -1613,7 +1598,7 @@ async fn update_workspace_user( audit_log( &mut *tx, - &authed, + &username, "users.update", ActionKind::Update, &w_id, @@ -1633,8 +1618,8 @@ async fn update_workspace_user( tx.commit().await?; handle_deployment_metadata( - &authed.email, - &authed.username, + &email, + &username, &db, &w_id, windmill_git_sync::DeployedObject::User { email: user_email.clone() }, @@ -1648,12 +1633,12 @@ async fn update_workspace_user( } async fn update_user( - authed: ApiAuthed, + ApiAuthed { email, .. }: ApiAuthed, Path(email_to_update): Path, Extension(db): Extension, Json(eu): Json, ) -> Result { - require_super_admin(&db, &authed.email).await?; + require_super_admin(&db, &email).await?; let mut tx = db.begin().await?; if let Some(sa) = eu.is_super_admin { @@ -1668,7 +1653,7 @@ async fn update_user( audit_log( &mut *tx, - &authed, + &email, "users.update", ActionKind::Update, "global", @@ -1681,11 +1666,11 @@ async fn update_user( } async fn delete_user( - authed: ApiAuthed, + ApiAuthed { email, .. }: ApiAuthed, Path(email_to_delete): Path, Extension(db): Extension, ) -> Result { - require_super_admin(&db, &authed.email).await?; + require_super_admin(&db, &email).await?; let mut tx = db.begin().await?; sqlx::query!("DELETE FROM password WHERE email = $1", &email_to_delete) @@ -1717,7 +1702,7 @@ async fn delete_user( } audit_log( &mut *tx, - &authed, + &email, "users.delete", ActionKind::Delete, "global", @@ -1735,14 +1720,14 @@ lazy_static::lazy_static! { } async fn create_user( - authed: ApiAuthed, + ApiAuthed { email, .. }: ApiAuthed, Extension(db): Extension, Extension(webhook): Extension, Extension(argon2): Extension>>, Extension(rsmq): Extension>, Json(mut nu): Json, ) -> Result<(StatusCode, String)> { - require_super_admin(&db, &authed.email).await?; + require_super_admin(&db, &email).await?; let mut tx = db.begin().await?; nu.email = nu.email.to_lowercase(); @@ -1802,7 +1787,7 @@ async fn create_user( audit_log( &mut *tx, - &authed, + &email, "users.add_global", ActionKind::Create, "global", @@ -1810,20 +1795,19 @@ async fn create_user( None, ) .await?; - tx = add_to_demo_if_exists(tx, &nu.email).await?; + tx = add_to_demo_if_exists(tx, &email).await?; tx.commit().await?; - invite_user_to_all_auto_invite_worspaces(&db, &nu.email, rsmq, &authed).await?; + invite_user_to_all_auto_invite_worspaces(&db, &nu.email, rsmq).await?; send_email_if_possible( "Invited to Windmill", &format!( - "You have been granted access to Windmill by {}. + "You have been granted access to Windmill by {email}. Log in and change your password: {}/user/login?email={}&password={}&rd=%2F%23user-settings You can then join or create a workspace. Happy building!", - authed.email, BASE_URL.read().await.clone(), &nu.email, &nu.password @@ -1853,14 +1837,14 @@ pub async fn send_email_if_possible_intern(subject: &str, content: &str, to: Str } async fn delete_workspace_user( - authed: ApiAuthed, + ApiAuthed { username, email, is_admin, .. }: ApiAuthed, Extension(db): Extension, Extension(rsmq): Extension>, Path((w_id, username_to_delete)): Path<(String, String)>, ) -> Result { let mut tx = db.begin().await?; - require_admin(authed.is_admin, &authed.username)?; + require_admin(is_admin, &username)?; let email_to_delete_o = sqlx::query_scalar!( "SELECT email FROM usr where username = $1 AND workspace_id = $2", @@ -1872,17 +1856,17 @@ async fn delete_workspace_user( let email_to_delete = not_found_if_none(email_to_delete_o, "User", &username_to_delete)?; - sqlx::query_scalar!( - "DELETE FROM usr WHERE email = $1 AND workspace_id = $2", + let username = sqlx::query_scalar!( + "DELETE FROM usr WHERE email = $1 AND workspace_id = $2 RETURNING username", email_to_delete, &w_id ) - .execute(&mut *tx) + .fetch_one(&mut *tx) .await?; sqlx::query!( "DELETE FROM usr_to_group WHERE usr = $1 AND workspace_id = $2", - &username_to_delete, + &username, &w_id ) .execute(&mut *tx) @@ -1890,7 +1874,7 @@ async fn delete_workspace_user( audit_log( &mut *tx, - &authed, + &username, "users.delete", ActionKind::Delete, &w_id, @@ -1901,8 +1885,8 @@ async fn delete_workspace_user( tx.commit().await?; handle_deployment_metadata( - &authed.email, - &authed.username, + &email, + &username, &db, &w_id, windmill_git_sync::DeployedObject::User { email: email_to_delete.clone() }, @@ -1921,14 +1905,14 @@ async fn delete_workspace_user( async fn set_password( Extension(db): Extension, Extension(argon2): Extension>>, - authed: ApiAuthed, + ApiAuthed { username, email, .. }: ApiAuthed, Json(EditPassword { password }): Json, ) -> Result { let mut tx = db.begin().await?; let custom_type = sqlx::query_scalar!( "SELECT login_type::TEXT FROM password WHERE email = $1", - &authed.email + &email ) .fetch_one(&mut *tx) .await @@ -1937,32 +1921,31 @@ async fn set_password( if custom_type != "password".to_string() { return Err(Error::BadRequest(format!( - "login type for {} is of type {custom_type}. Cannot set password.", - authed.email + "login type for {email} is of type {custom_type}. Cannot set password." ))); } sqlx::query!( "UPDATE password SET password_hash = $1 WHERE email = $2", &hash_password(argon2, password)?, - &authed.email, + &email, ) .execute(&mut *tx) .await?; audit_log( &mut *tx, - &authed, + &username, "users.setpassword", ActionKind::Update, "global", - Some(&authed.email), + Some(&email), None, ) .await?; tx.commit().await?; - Ok(format!("password of {} updated", authed.email)) + Ok(format!("password of {} updated", email)) } pub fn hash_password(argon2: Arc, password: String) -> Result { @@ -2158,11 +2141,7 @@ async fn login( audit_log( &mut *tx, - &AuditAuthor { - username: email.clone(), - email: email.clone(), - username_override: None, - }, + &email, "users.login", ActionKind::Create, "global", @@ -2236,25 +2215,23 @@ pub async fn create_session_token<'c>( async fn create_token( Extension(db): Extension, - authed: ApiAuthed, + ApiAuthed { email, .. }: ApiAuthed, Json(new_token): Json, ) -> Result<(StatusCode, String)> { let token = rd_string(30); let mut tx = db.begin().await?; - let is_super_admin = sqlx::query_scalar!( - "SELECT super_admin FROM password WHERE email = $1", - authed.email - ) - .fetch_optional(&mut *tx) - .await? - .unwrap_or(false); + let is_super_admin = + sqlx::query_scalar!("SELECT super_admin FROM password WHERE email = $1", email) + .fetch_optional(&mut *tx) + .await? + .unwrap_or(false); sqlx::query!( "INSERT INTO token (token, email, label, expiration, super_admin, scopes) VALUES ($1, $2, $3, $4, $5, $6)", token, - authed.email, + email, new_token.label, new_token.expiration, is_super_admin, @@ -2265,14 +2242,14 @@ async fn create_token( audit_log( &mut *tx, - &authed, + &email, "users.token.create", ActionKind::Create, &"global", Some(&token[0..10]), None, ) - .instrument(tracing::info_span!("token", email = &authed.email)) + .instrument(tracing::info_span!("token", email = &email)) .await?; tx.commit().await?; Ok((StatusCode::CREATED, token)) @@ -2280,11 +2257,11 @@ async fn create_token( async fn impersonate( Extension(db): Extension, - authed: ApiAuthed, + ApiAuthed { email, username, .. }: ApiAuthed, Json(new_token): Json, ) -> Result<(StatusCode, String)> { let token = rd_string(30); - require_super_admin(&db, &authed.email).await?; + require_super_admin(&db, &email).await?; if new_token.impersonate_email.is_none() { return Err(Error::BadRequest( @@ -2318,7 +2295,7 @@ async fn impersonate( audit_log( &mut *tx, - &authed, + &username, "users.impersonate", ActionKind::Delete, &"global", @@ -2367,7 +2344,7 @@ async fn list_tokens( async fn delete_token( Extension(db): Extension, - authed: ApiAuthed, + ApiAuthed { email, .. }: ApiAuthed, Path(token_prefix): Path, ) -> Result { let mut tx = db.begin().await?; @@ -2378,14 +2355,14 @@ async fn delete_token( AND token LIKE concat($2::text, '%') RETURNING concat(substring(token for 10), '*****')", ) - .bind(&authed.email) + .bind(&email) .bind(&token_prefix) .fetch_all(&mut *tx) .await?; audit_log( &mut *tx, - &authed, + &email, "users.token.delete", ActionKind::Delete, &"global", @@ -2406,20 +2383,20 @@ async fn delete_token( async fn leave_workspace( Extension(db): Extension, Path(w_id): Path, - authed: ApiAuthed, + ApiAuthed { username, .. }: ApiAuthed, ) -> Result { let mut tx = db.begin().await?; sqlx::query!( "DELETE FROM usr WHERE workspace_id = $1 AND username = $2", &w_id, - authed.username + username ) .execute(&mut *tx) .await?; audit_log( &mut *tx, - &authed, + &username, "users.leave_workspace", ActionKind::Delete, &w_id, @@ -2607,35 +2584,18 @@ async fn get_instance_username_info( })) } -async fn email_from_username( - Path((w_id, username)): Path<(String, String)>, - Extension(db): Extension, -) -> Result { - let email = sqlx::query_scalar!( - "SELECT email FROM usr WHERE username = $1 AND workspace_id = $2", - &username, - &w_id - ) - .fetch_optional(&db) - .await?; - - let email = not_found_if_none(email, "user", username)?; - - Ok(email) -} - #[derive(Deserialize)] struct RenameUser { new_username: String, } async fn rename_user( - authed: ApiAuthed, + ApiAuthed { email, .. }: ApiAuthed, Path(user_email): Path, Extension(db): Extension, Json(ru): Json, ) -> Result { - require_super_admin(&db, &authed.email).await?; + require_super_admin(&db, &email).await?; let mut tx = db.begin().await?; @@ -2692,7 +2652,7 @@ async fn rename_user( audit_log( &mut *tx, - &authed, + &email, "users.rename", ActionKind::Update, "global", diff --git a/backend/windmill-api/src/variables.rs b/backend/windmill-api/src/variables.rs index 1733d8d539..61dfa5f695 100644 --- a/backend/windmill-api/src/variables.rs +++ b/backend/windmill-api/src/variables.rs @@ -20,7 +20,7 @@ use axum::{ }; use hyper::StatusCode; use serde_json::Value; -use windmill_audit::audit_ee::{audit_log, AuditAuthorable}; +use windmill_audit::audit_ee::audit_log; use windmill_audit::ActionKind; use windmill_common::{ db::UserDB, @@ -151,7 +151,7 @@ async fn get_variable( if decrypt_secret { audit_log( &mut *tx, - &authed, + &authed.username, "variables.decrypt_secret", ActionKind::Execute, &w_id, @@ -192,7 +192,7 @@ async fn get_value( ) -> JsonResult { let path = path.to_path(); let tx = user_db.begin(&authed).await?; - return get_value_internal(tx, &db, &w_id, &path, &authed) + return get_value_internal(tx, &db, &w_id, &path, &authed.username) .await .map(Json); } @@ -315,7 +315,7 @@ async fn create_variable( audit_log( &mut *tx, - &authed, + &authed.username, "variables.create", ActionKind::Create, &w_id, @@ -391,7 +391,7 @@ async fn delete_variable( .await?; audit_log( &mut *tx, - &authed, + &authed.username, "variables.delete", ActionKind::Delete, &w_id, @@ -547,7 +547,7 @@ async fn update_variable( audit_log( &mut *tx, - &authed, + &authed.username, "variables.update", ActionKind::Update, &w_id, @@ -603,7 +603,7 @@ pub async fn get_value_internal<'c>( db: &DB, w_id: &str, path: &str, - audit_author: &impl AuditAuthorable, + username: &str, ) -> Result { let variable_o = sqlx::query!( "SELECT value, account, (now() > account.expires_at) as is_expired, is_secret, path from variable @@ -622,7 +622,7 @@ pub async fn get_value_internal<'c>( let r = if variable.is_secret { audit_log( &mut *tx, - audit_author, + username, "variables.decrypt_secret", ActionKind::Execute, &w_id, diff --git a/backend/windmill-api/src/workspaces.rs b/backend/windmill-api/src/workspaces.rs index 5c97d03adb..7558214adb 100644 --- a/backend/windmill-api/src/workspaces.rs +++ b/backend/windmill-api/src/workspaces.rs @@ -34,7 +34,7 @@ use itertools::Itertools; use regex::Regex; use uuid::Uuid; -use windmill_audit::audit_ee::{audit_log, AuditAuthor, AuditAuthorable}; +use windmill_audit::audit_ee::audit_log; use windmill_audit::ActionKind; use windmill_common::db::UserDB; use windmill_common::s3_helpers::LargeFileStorage; @@ -448,7 +448,7 @@ async fn edit_slack_command( audit_log( &mut *tx, - &authed, + &authed.username, "workspaces.edit_command_script", ActionKind::Update, &w_id, @@ -533,7 +533,7 @@ async fn edit_deploy_to( audit_log( &mut *tx, - &authed, + &authed.username, "workspaces.edit_deploy_to", ActionKind::Update, &w_id, @@ -571,8 +571,7 @@ async fn auto_add_user( w_id: &str, operator: &bool, tx: &mut Transaction<'_, Postgres>, - authorable: &impl AuditAuthorable, -) -> Result { +) -> Result<()> { let automate_username_creation = sqlx::query_scalar!( "SELECT value FROM global_settings WHERE name = $1", AUTOMATE_USERNAME_CREATION_SETTING, @@ -646,24 +645,9 @@ async fn auto_add_user( ) .execute(&mut **tx) .await?; - let audit_author = if authorable.username() == authorable.email() && authorable.email() == email - { - // if the user is auto adding themselves (e.g. by joining the instance), we use their newly created workspace username for audit logs - AuditAuthor { - username: username.clone(), - email: email.to_string(), - username_override: None, - } - } else { - AuditAuthor { - username: authorable.username().to_string(), - email: authorable.email().to_string(), - username_override: authorable.username_override().map(|x| x.to_string()), - } - }; audit_log( &mut **tx, - &audit_author, + &username, "users.auto_invite_add", ActionKind::Create, &w_id, @@ -671,7 +655,7 @@ async fn auto_add_user( None, ) .await?; - Ok(username) + Ok(()) } async fn edit_auto_invite( @@ -736,7 +720,7 @@ async fn edit_auto_invite( .fetch_all(&mut *tx).await?); for user in users_to_auto_add.as_ref().unwrap() { - auto_add_user(&user.email, &w_id, &operator, &mut tx, &authed).await?; + auto_add_user(&user.email, &w_id, &operator, &mut tx).await?; send_email_if_possible( &format!("Added to Windmill's workspace: {w_id}"), &format!( @@ -773,7 +757,7 @@ async fn edit_auto_invite( } audit_log( &mut *tx, - &authed, + &authed.username, "workspaces.edit_auto_invite_domain", ActionKind::Update, &w_id, @@ -834,7 +818,7 @@ async fn edit_webhook( } audit_log( &mut *tx, - &authed, + &authed.username, "workspaces.edit_webhook", ActionKind::Update, &w_id, @@ -878,7 +862,7 @@ async fn edit_copilot_config( } audit_log( &mut *tx, - &authed, + &authed.username, "workspaces.edit_copilot_config", ActionKind::Update, &w_id, @@ -942,7 +926,7 @@ async fn edit_large_file_storage_config( let args_for_audit = format!("{:?}", new_config.large_file_storage); audit_log( &mut *tx, - &authed, + &authed.username, "workspaces.edit_large_file_storage_config", ActionKind::Update, &w_id, @@ -1010,7 +994,7 @@ async fn edit_git_sync_config( let args_for_audit = format!("{:?}", new_config.git_sync_settings); audit_log( &mut *tx, - &authed, + &authed.username, "workspaces.edit_git_sync_config", ActionKind::Update, &w_id, @@ -1074,7 +1058,7 @@ async fn edit_default_scripts( audit_log( &mut *tx, - &authed, + &authed.username, "workspaces.edit_default_scripts", ActionKind::Update, &w_id, @@ -1144,7 +1128,7 @@ async fn edit_default_app( let args_for_audit = format!("{:?}", new_config.default_app_path); audit_log( &mut *tx, - &authed, + &authed.username, "workspaces.edit_default_app", ActionKind::Update, &w_id, @@ -1237,7 +1221,7 @@ async fn edit_error_handler( } audit_log( &mut *tx, - &authed, + &authed.username, "workspaces.edit_error_handler", ActionKind::Update, &w_id, @@ -1279,7 +1263,7 @@ async fn set_environment_variable( audit_log( &mut *tx, - &authed, + &authed.username, "workspace.set_environment_variable", ActionKind::Create, &w_id, @@ -1301,7 +1285,7 @@ async fn set_environment_variable( audit_log( &mut *tx, - &authed, + &authed.username, "workspace.delete_environment_variable", ActionKind::Delete, &w_id, @@ -1627,7 +1611,7 @@ async fn create_workspace( audit_log( &mut *tx, - &authed, + &authed.username, "workspaces.create", ActionKind::Create, &nw.id, @@ -1659,7 +1643,7 @@ async fn edit_workspace( audit_log( &mut *tx, - &authed, + &authed.username, "workspaces.update", ActionKind::Update, &w_id, @@ -1675,9 +1659,9 @@ async fn edit_workspace( async fn archive_workspace( Extension(db): Extension, Path(w_id): Path, - authed: ApiAuthed, + ApiAuthed { is_admin, username, email, .. }: ApiAuthed, ) -> Result { - require_admin(authed.is_admin, &authed.username)?; + require_admin(is_admin, &username)?; let mut tx = db.begin().await?; sqlx::query!("UPDATE workspace SET deleted = true WHERE id = $1", &w_id) .execute(&mut *tx) @@ -1685,11 +1669,11 @@ async fn archive_workspace( audit_log( &mut *tx, - &authed, + &username, "workspaces.archive", ActionKind::Update, &w_id, - Some(&authed.email), + Some(&email), None, ) .await?; @@ -1701,24 +1685,24 @@ async fn archive_workspace( async fn leave_workspace( Extension(db): Extension, Path(w_id): Path, - authed: ApiAuthed, + ApiAuthed { email, username, .. }: ApiAuthed, ) -> Result { let mut tx = db.begin().await?; sqlx::query!( "DELETE FROM usr WHERE workspace_id = $1 AND email = $2", &w_id, - &authed.email + &email ) .execute(&mut *tx) .await?; audit_log( &mut *tx, - &authed, + &username, "workspaces.leave", ActionKind::Delete, &w_id, - Some(&authed.email), + Some(&email), None, ) .await?; @@ -1730,9 +1714,9 @@ async fn leave_workspace( async fn unarchive_workspace( Extension(db): Extension, Path(w_id): Path, - authed: ApiAuthed, + ApiAuthed { is_admin, username, email, .. }: ApiAuthed, ) -> Result { - require_admin(authed.is_admin, &authed.username)?; + require_admin(is_admin, &username)?; let mut tx = db.begin().await?; sqlx::query!("UPDATE workspace SET deleted = false WHERE id = $1", &w_id) .execute(&mut *tx) @@ -1740,11 +1724,11 @@ async fn unarchive_workspace( audit_log( &mut *tx, - &authed, + &username, "workspaces.unarchive", ActionKind::Update, &w_id, - Some(&authed.email), + Some(&email), None, ) .await?; @@ -1756,7 +1740,7 @@ async fn unarchive_workspace( async fn delete_workspace( Extension(db): Extension, Path(w_id): Path, - authed: ApiAuthed, + ApiAuthed { username, email, .. }: ApiAuthed, ) -> Result { let w_id = match w_id.as_str() { "starter" => Err(Error::BadRequest( @@ -1768,7 +1752,7 @@ async fn delete_workspace( _ => Ok(w_id), }?; let mut tx = db.begin().await?; - require_super_admin(&db, &authed.email).await?; + require_super_admin(&db, &email).await?; sqlx::query!("DELETE FROM dependency_map WHERE workspace_id = $1", &w_id) .execute(&mut *tx) @@ -1875,11 +1859,11 @@ async fn delete_workspace( audit_log( &mut *tx, - &authed, + &username, "workspaces.delete", ActionKind::Delete, &w_id, - Some(&authed.email), + Some(&email), None, ) .await?; @@ -1892,7 +1876,6 @@ pub async fn invite_user_to_all_auto_invite_worspaces( db: &DB, email: &str, rsmq: Option, - authorable: &impl AuditAuthorable, ) -> Result<()> { let mut tx = db.begin().await?; let domain = email.split('@').last().unwrap(); @@ -1907,8 +1890,14 @@ pub async fn invite_user_to_all_auto_invite_worspaces( for r in workspaces { if r.auto_add.is_some() && r.auto_add.unwrap() { let operator = r.auto_invite_operator.unwrap_or(false); - let username = - auto_add_user(email, &r.workspace_id, &operator, &mut tx, authorable).await?; + auto_add_user(email, &r.workspace_id, &operator, &mut tx).await?; + let username = sqlx::query_scalar!( + "SELECT username FROM usr WHERE workspace_id = $1 AND email = $2", + r.workspace_id, + email + ) + .fetch_one(&mut *tx) + .await?; auto_added_workspace_usernames.push((r.workspace_id, username)); } else { sqlx::query!( @@ -2010,14 +1999,14 @@ If you do not have an account on {}, login with SSO or ask an admin to create an } async fn add_user( - authed: ApiAuthed, + ApiAuthed { username, email, is_admin, .. }: ApiAuthed, Extension(db): Extension, Extension(webhook): Extension, Extension(rsmq): Extension>, Path(w_id): Path, Json(mut nu): Json, ) -> Result<(StatusCode, String)> { - require_admin(authed.is_admin, &authed.username)?; + require_admin(is_admin, &username)?; nu.email = nu.email.to_lowercase(); let mut tx = db.begin().await?; @@ -2034,7 +2023,7 @@ async fn add_user( if already_exists_email { return Err(Error::BadRequest(format!( "user with email {} already exists in workspace {}", - nu.email, w_id + email, w_id ))); } @@ -2102,11 +2091,11 @@ async fn add_user( audit_log( &mut *tx, - &authed, + &username, "users.add_to_workspace", ActionKind::Create, &w_id, - Some(&nu.email), + Some(&email), None, ) .await?; @@ -2114,8 +2103,8 @@ async fn add_user( tx.commit().await?; handle_deployment_metadata( - &authed.email, - &authed.username, + &email, + &username, &db, &w_id, windmill_git_sync::DeployedObject::User { email: nu.email.clone() }, @@ -2128,10 +2117,9 @@ async fn add_user( send_email_if_possible( &format!("Added to Windmill's workspace: {w_id}"), &format!( - "You have been granted access to Windmill's workspace {w_id} by {} + "You have been granted access to Windmill's workspace {w_id} by {email} If you do not have an account on {}, login with SSO or ask an admin to create an account for you.", - authed.email, BASE_URL.read().await.clone() ), &nu.email, @@ -2822,7 +2810,7 @@ async fn change_workspace_name( audit_log( &mut *tx, - &authed, + &authed.username, "workspace.change_workspace_name", ActionKind::Update, &w_id, @@ -3147,7 +3135,7 @@ async fn change_workspace_id( audit_log( &mut *tx, - &authed, + &authed.username, "workspace.change_workspace_id", ActionKind::Update, &rw.new_id, diff --git a/backend/windmill-audit/src/audit_ee.rs b/backend/windmill-audit/src/audit_ee.rs index 3520eb10ac..5bb52e7b3f 100644 --- a/backend/windmill-audit/src/audit_ee.rs +++ b/backend/windmill-audit/src/audit_ee.rs @@ -15,37 +15,10 @@ use windmill_common::{ use crate::{ActionKind, AuditLog, ListAuditLogQuery}; use sqlx::{Postgres, Transaction}; -#[derive(Clone)] -pub struct AuditAuthor { - pub username: String, - pub email: String, - pub username_override: Option, -} - -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, - _authorable: &impl AuditAuthorable, + _username: &str, mut _operation: &str, _action_kind: ActionKind, _w_id: &str, diff --git a/backend/windmill-queue/src/jobs.rs b/backend/windmill-queue/src/jobs.rs index 0d5f6fc720..bcef225647 100644 --- a/backend/windmill-queue/src/jobs.rs +++ b/backend/windmill-queue/src/jobs.rs @@ -40,7 +40,7 @@ use tokio::{sync::RwLock, time::sleep}; use tracing::{instrument, Instrument}; use ulid::Ulid; use uuid::Uuid; -use windmill_audit::audit_ee::{audit_log, AuditAuthor}; +use windmill_audit::audit_ee::audit_log; use windmill_audit::ActionKind; #[cfg(not(feature = "enterprise"))] use windmill_common::worker::PriorityTags; @@ -3600,23 +3600,9 @@ pub async fn push<'c, R: rsmq_async::RsmqConnection + Send + 'c>( JobKind::DeploymentCallback => "jobs.run.deployment_callback", }; - let audit_author = if format!("u/{user}") != permissioned_as && user != permissioned_as { - AuditAuthor { - email: email.to_string(), - username: permissioned_as.trim_start_matches("u/").to_string(), - username_override: Some(user.to_string()), - } - } else { - AuditAuthor { - email: email.to_string(), - username: user.to_string(), - username_override: None, - } - }; - audit_log( &mut tx, - &audit_author, + &user, operation_name, ActionKind::Execute, workspace_id, diff --git a/backend/windmill-worker/src/worker.rs b/backend/windmill-worker/src/worker.rs index 2a7a6da1d4..103a3d0610 100644 --- a/backend/windmill-worker/src/worker.rs +++ b/backend/windmill-worker/src/worker.rs @@ -127,20 +127,12 @@ pub async fn create_token_for_owner_in_bg( let owner = job.permissioned_as.clone(); let email = job.email.clone(); let job_id = job.id.clone(); - - let label = if job.permissioned_as != format!("u/{}", job.created_by) - && job.permissioned_as != job.created_by - { - format!("ephemeral-script-end-user-{}", job.created_by) - } else { - "ephemeral-script".to_string() - }; tokio::spawn(async move { let token = create_token_for_owner( &db.clone(), &w_id, &owner, - &label, + "ephemeral-script", *SCRIPT_TOKEN_EXPIRY, &email, &job_id, diff --git a/frontend/src/lib/components/auditLogs/AuditLogsTable.svelte b/frontend/src/lib/components/auditLogs/AuditLogsTable.svelte index 4ca682a1d0..8da641beac 100644 --- a/frontend/src/lib/components/auditLogs/AuditLogsTable.svelte +++ b/frontend/src/lib/components/auditLogs/AuditLogsTable.svelte @@ -92,7 +92,7 @@ {date} - {#each logsByDay as { id, timestamp, username, operation: op, action_kind, resource, parameters }} + {#each logsByDay as { id, timestamp, username, operation: op, action_kind, resource }}
-
+
{username} - {#if parameters && 'end_user' in parameters} - (end user: {parameters.end_user}) - {/if}