fix: resolve the app execution address uncached, it decides the job's authorization

This commit is contained in:
Ruben Fiszel
2026-08-01 16:40:13 +00:00
parent 058b48b850
commit fa08488088
3 changed files with 18 additions and 5 deletions
@@ -15,7 +15,7 @@
]
},
"nullable": [
null
true
]
},
"hash": "5a219a2532517869578c4504ff3153c43903f929ae5d62fbba12610f89c36d55"
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO schedule (\n workspace_id, path, schedule, timezone, edited_by, script_path,\n is_flow, enabled, email, permissioned_as, summary, tag, cron_version\n ) VALUES ($1, $2, $3, 'Etc/UTC', $4, $2, false, true, $5, $6, $7, 'duckdb', 'v2')\n ON CONFLICT (workspace_id, path) DO UPDATE SET\n schedule = EXCLUDED.schedule,\n timezone = EXCLUDED.timezone,\n edited_by = EXCLUDED.edited_by,\n edited_at = now(),\n script_path = EXCLUDED.script_path,\n is_flow = false,\n enabled = true,\n email = EXCLUDED.email,\n permissioned_as = EXCLUDED.permissioned_as,\n summary = EXCLUDED.summary,\n tag = EXCLUDED.tag,\n cron_version = EXCLUDED.cron_version,\n error = NULL",
"query": "INSERT INTO schedule (\n workspace_id, path, schedule, timezone, edited_by, script_path,\n is_flow, enabled, permissioned_as, email, summary, tag, cron_version\n ) VALUES ($1, $2, $3, 'Etc/UTC', $4, $2, false, true, $5, $6, $7, 'duckdb', 'v2')\n ON CONFLICT (workspace_id, path) DO UPDATE SET\n schedule = EXCLUDED.schedule,\n timezone = EXCLUDED.timezone,\n edited_by = EXCLUDED.edited_by,\n edited_at = now(),\n script_path = EXCLUDED.script_path,\n is_flow = false,\n enabled = true,\n permissioned_as = EXCLUDED.permissioned_as,\n email = EXCLUDED.email,\n summary = EXCLUDED.summary,\n tag = EXCLUDED.tag,\n cron_version = EXCLUDED.cron_version,\n error = NULL",
"describe": {
"columns": [],
"parameters": {
@@ -16,5 +16,5 @@
},
"nullable": []
},
"hash": "5323858a017814206179d35fdb708c547742851975163550ec4f3823057e91fe"
"hash": "b8aa3844c3ca027ba405a384118cafc9608ef34ad8a4dd462e125d9124df06ba"
}
+15 -2
View File
@@ -4741,6 +4741,15 @@ fn audited_on_behalf_of(policy: &Policy, authed: &ApiAuthed) -> Option<String> {
.map(str::to_string)
}
/// The identity an anonymous or publisher execution runs as.
///
/// The address is resolved **uncached**, and that is not optional: it becomes the job's
/// `permissioned_as_email`, from which `fetch_authed_from_permissioned_as` derives the
/// superadmin flag and the instance groups. `EMAIL_CACHE` has a 60s TTL and nothing evicts it,
/// so a cached read on a replica that did not handle an email change would enqueue jobs
/// carrying the pre-change authorization. It costs one indexed lookup per execution, against a
/// request that already does far more — and only for a `u/` principal, since `g/` and bare
/// addresses resolve without touching the database.
async fn get_on_behalf_of(policy: &Policy, w_id: &str, db: &DB) -> Result<(String, String)> {
let permissioned_as = policy
.on_behalf_of
@@ -4752,8 +4761,12 @@ async fn get_on_behalf_of(policy: &Policy, w_id: &str, db: &DB) -> Result<(Strin
)
})?
.to_string();
let email =
windmill_common::users::get_email_from_permissioned_as(&permissioned_as, w_id, db).await?;
let email = windmill_common::users::get_email_from_permissioned_as_uncached(
&permissioned_as,
w_id,
db,
)
.await?;
Ok((permissioned_as, email))
}