mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-06 00:02:13 +00:00
fix: strip server-owned credential status and correct expiry copy
This commit is contained in:
+23
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT value FROM resource WHERE workspace_id = $1 AND path = $2 FOR UPDATE",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "value",
|
||||
"type_info": "Jsonb"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "0222c6722a85ba1a86a1535c4c8fde581934864199fa0a484c9a8b859f86ec7d"
|
||||
}
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n UPDATE workspace_settings\n SET git_sync = jsonb_set(git_sync, '{repositories}',\n (SELECT jsonb_agg(\n CASE WHEN elem->>'git_repo_resource_path' = $2\n THEN CASE WHEN $3::jsonb = 'null'::jsonb\n THEN elem - 'credential'\n ELSE jsonb_set(elem, '{credential}', $3) END\n ELSE elem END)\n FROM jsonb_array_elements(git_sync->'repositories') AS elem)\n )\n WHERE workspace_id = $1\n AND jsonb_typeof(git_sync->'repositories') = 'array'\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text",
|
||||
"Jsonb"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "45e23417d12e4623016f89efd5d0f24f52437daa796ee99eec77c2cef135c9f6"
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n UPDATE workspace_settings\n SET git_sync = jsonb_set(git_sync, '{repositories}',\n COALESCE((SELECT jsonb_agg(\n CASE WHEN elem->>'git_repo_resource_path' = $2\n THEN CASE WHEN $3::jsonb = 'null'::jsonb\n THEN elem - 'credential'\n ELSE jsonb_set(elem, '{credential}', $3) END\n ELSE elem END)\n FROM jsonb_array_elements(git_sync->'repositories') AS elem), '[]'::jsonb)\n )\n WHERE workspace_id = $1\n AND jsonb_typeof(git_sync->'repositories') = 'array'\n AND EXISTS (\n SELECT 1 FROM jsonb_array_elements(git_sync->'repositories') AS e\n WHERE e->>'git_repo_resource_path' = $2\n )\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text",
|
||||
"Jsonb"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "81e7f902c40d72937b494cd9f3f8c9fe4348d179add37361353fc9a02d96f2fa"
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT value FROM variable WHERE path = $1 AND workspace_id = $2 FOR UPDATE",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "value",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "8d9f10a4fed1f8422224d26a4e3b1eed51f6ad271f4c76d5b430690e0ae73c1b"
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
b342a1bdeda7ebba2da64c71ced6ef5dfac48663
|
||||
7d11df2f77c8af2da18269532fe276b307dd2a54
|
||||
|
||||
+12
-9
@@ -353,9 +353,7 @@ pub async fn initial_load(
|
||||
)
|
||||
}
|
||||
});
|
||||
pass.action(windmill_common::min_version::store_min_keep_alive_version(
|
||||
db,
|
||||
));
|
||||
pass.action(windmill_common::min_version::store_min_keep_alive_version(db));
|
||||
pass.setting(
|
||||
windmill_common::global_settings::INSTANCE_EVENTS_WEBHOOK_SETTING,
|
||||
false,
|
||||
@@ -701,6 +699,7 @@ pub async fn initial_load(
|
||||
pass.run(conn).await;
|
||||
}
|
||||
|
||||
|
||||
pub fn apply_metrics_enabled(value: Option<serde_json::Value>) {
|
||||
if let Some(serde_json::Value::Bool(t)) = value {
|
||||
METRICS_ENABLED.store(t, Ordering::Relaxed)
|
||||
@@ -1057,8 +1056,8 @@ pub fn apply_fork_workspace_tag_append_fork_suffix(value: Option<serde_json::Val
|
||||
}
|
||||
|
||||
pub async fn reload_critical_alert_mute_ui_setting(conn: &Connection) -> error::Result<()> {
|
||||
let v = load_value_from_global_settings_with_conn(conn, CRITICAL_ALERT_MUTE_UI_SETTING, true)
|
||||
.await?;
|
||||
let v =
|
||||
load_value_from_global_settings_with_conn(conn, CRITICAL_ALERT_MUTE_UI_SETTING, true).await?;
|
||||
apply_critical_alert_mute_ui_setting(v);
|
||||
Ok(())
|
||||
}
|
||||
@@ -2657,6 +2656,7 @@ pub async fn reload_timeout_wait_result_setting(conn: &Connection) {
|
||||
.await;
|
||||
}
|
||||
|
||||
|
||||
pub async fn reload_extra_pip_index_url_setting(conn: &Connection) {
|
||||
reload_option_setting_with_tracing(
|
||||
conn,
|
||||
@@ -2747,6 +2747,7 @@ pub async fn reload_bunfig_install_scopes_setting(conn: &Connection) {
|
||||
.await;
|
||||
}
|
||||
|
||||
|
||||
pub async fn reload_nuget_config_setting(conn: &Connection) {
|
||||
reload_option_setting_with_tracing(
|
||||
conn,
|
||||
@@ -2854,6 +2855,7 @@ pub async fn reload_ruby_repos_setting(conn: &Connection) {
|
||||
.await;
|
||||
}
|
||||
|
||||
|
||||
pub async fn reload_workspace_registries_setting(conn: &Connection) {
|
||||
match load_value_from_global_settings_with_conn(
|
||||
conn,
|
||||
@@ -3092,6 +3094,7 @@ pub async fn apply_job_isolation_setting(value: Option<serde_json::Value>) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async fn resolve_license_key_value(conn: &Connection, quiet: bool) -> anyhow::Result<String> {
|
||||
let q = load_value_from_global_settings_with_conn(conn, LICENSE_KEY_SETTING, true)
|
||||
.await
|
||||
@@ -3386,10 +3389,7 @@ impl<'a> SettingsPass<'a> {
|
||||
// on compile-time defaults until the next full reload. Only the single-query transport
|
||||
// can fail this way; over HTTP the batch already is the per-setting read.
|
||||
if matches!(conn, Connection::Sql(_)) && values.is_empty() && !names.is_empty() {
|
||||
tracing::warn!(
|
||||
"Falling back to per-setting reads for {} settings",
|
||||
names.len()
|
||||
);
|
||||
tracing::warn!("Falling back to per-setting reads for {} settings", names.len());
|
||||
values = fetch_settings_individually(conn, &names).await;
|
||||
}
|
||||
for (name, http) in &declared {
|
||||
@@ -3781,6 +3781,7 @@ pub fn parse_setting_value<T: FromStr + DeserializeOwned + Display>(
|
||||
value
|
||||
}
|
||||
|
||||
|
||||
#[cfg(feature = "prometheus")]
|
||||
pub async fn monitor_pool(db: &DB) {
|
||||
if METRICS_ENABLED.load(Ordering::Relaxed) {
|
||||
@@ -4717,6 +4718,7 @@ async fn maintain_git_credentials_inner(db: &Pool<Postgres>) -> error::Result<()
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "private")]
|
||||
#[cfg(feature = "private")]
|
||||
async fn poll_git_auto_pull_inner(db: &Pool<Postgres>) -> error::Result<()> {
|
||||
use windmill_common::workspaces::{AutoPullMode, WorkspaceGitSyncSettings};
|
||||
@@ -6614,6 +6616,7 @@ pub async fn reload_critical_alerts_on_db_oversize(conn: &DB) -> error::Result<(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
pub async fn reload_jwt_secret_setting(db: &DB) -> error::Result<()> {
|
||||
let v = load_value_from_global_settings(db, JWT_SECRET_SETTING).await?;
|
||||
apply_jwt_secret_setting(db, v).await
|
||||
|
||||
@@ -3937,6 +3937,7 @@ async fn edit_git_sync_config(
|
||||
clear_client_supplied_auto_pull_state(ap);
|
||||
}
|
||||
repo.open_pr_error = None;
|
||||
repo.credential = None;
|
||||
}
|
||||
reject_parent_only_git_sync_settings_on_fork(
|
||||
&db,
|
||||
@@ -4037,6 +4038,7 @@ async fn edit_git_sync_config(
|
||||
continue;
|
||||
};
|
||||
repo.open_pr_error = old.open_pr_error.clone();
|
||||
repo.credential = old.credential.clone();
|
||||
if let (Some(new_ap), Some(old_ap)) =
|
||||
(repo.auto_pull.as_mut(), old.auto_pull.as_ref())
|
||||
{
|
||||
@@ -4180,6 +4182,7 @@ async fn edit_git_sync_repository(
|
||||
clear_client_supplied_auto_pull_state(ap);
|
||||
}
|
||||
new_config.repository.open_pr_error = None;
|
||||
new_config.repository.credential = None;
|
||||
reject_parent_only_git_sync_settings_on_fork(
|
||||
&db,
|
||||
&w_id,
|
||||
@@ -4304,6 +4307,7 @@ async fn edit_git_sync_repository(
|
||||
// from the UI cannot revert what the poller/webhook layer wrote.
|
||||
let mut updated = new_config.repository;
|
||||
updated.open_pr_error = existing_repo.open_pr_error.clone();
|
||||
updated.credential = existing_repo.credential.clone();
|
||||
match (updated.auto_pull.as_mut(), existing_repo.auto_pull.as_ref()) {
|
||||
(Some(new_ap), Some(old_ap)) => {
|
||||
new_ap.last_synced_sha = old_ap.last_synced_sha.clone();
|
||||
@@ -6181,6 +6185,7 @@ async fn update_workspace_settings(
|
||||
r.auto_pull = None;
|
||||
r.fork_open_prs = false;
|
||||
r.open_pr_error = None;
|
||||
r.credential = None;
|
||||
r
|
||||
})
|
||||
.collect();
|
||||
@@ -8172,6 +8177,7 @@ async fn attach_dev_workspace(
|
||||
r.auto_pull = None;
|
||||
r.fork_open_prs = false;
|
||||
r.open_pr_error = None;
|
||||
r.credential = None;
|
||||
}
|
||||
let serialized =
|
||||
serde_json::to_value(&settings).map_err(|e| Error::internal_err(e.to_string()))?;
|
||||
|
||||
@@ -155,13 +155,20 @@
|
||||
const MS_PER_DAY = 86_400_000
|
||||
|
||||
/**
|
||||
* Days until the repository's own token expires, or undefined when it never
|
||||
* expires and when nothing has checked it yet.
|
||||
* Whole days until the repository's own token expires, or undefined when it
|
||||
* never expires and when nothing has checked it yet.
|
||||
*
|
||||
* Counted between calendar dates, not instants: GitLab expires a token on a
|
||||
* date, so measuring from "now" would call a token expiring later today
|
||||
* expired, and one expiring tomorrow today's problem.
|
||||
*/
|
||||
const credentialDaysLeft = $derived.by(() => {
|
||||
const expiresAt = repo.credential?.expires_at
|
||||
if (!expiresAt) return undefined
|
||||
return Math.floor((new Date(`${expiresAt}T00:00:00Z`).getTime() - Date.now()) / MS_PER_DAY)
|
||||
const expiry = new Date(`${expiresAt}T00:00:00Z`).getTime()
|
||||
const now = new Date()
|
||||
const today = Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate())
|
||||
return Math.round((expiry - today) / MS_PER_DAY)
|
||||
})
|
||||
|
||||
/**
|
||||
@@ -583,9 +590,12 @@
|
||||
<div class="text-xs text-secondary">
|
||||
{#if credentialDaysLeft === undefined}
|
||||
Repository token does not expire.
|
||||
{:else}
|
||||
{:else if repo.credential.rotatable}
|
||||
Repository token expires on {repo.credential.expires_at}, and Windmill renews it
|
||||
automatically.
|
||||
{:else}
|
||||
Repository token expires on {repo.credential.expires_at}. Give it the api or self_rotate
|
||||
scope to let Windmill renew it automatically.
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
Reference in New Issue
Block a user