Add enterprise config support via env vars & Windows registry

This commit is contained in:
Thorsten Sommer 2025-05-31 18:57:40 +02:00
parent b88b78a08e
commit d02d6b5870
No known key found for this signature in database
GPG Key ID: B0B7E2FC074BF1F5
6 changed files with 197 additions and 5 deletions

View File

@ -208,6 +208,30 @@ internal sealed class Program
await rust.AppIsReady(); await rust.AppIsReady();
programLogger.LogInformation("The AI Studio server is ready."); programLogger.LogInformation("The AI Studio server is ready.");
//
// Read the enterprise environment for the current user's configuration:
//
var enterpriseConfigServerUrl = await RUST_SERVICE.EnterpriseEnvConfigServerUrl();
var enterpriseConfigId = await RUST_SERVICE.EnterpriseEnvConfigId();
switch (enterpriseConfigServerUrl)
{
case null when enterpriseConfigId == Guid.Empty:
programLogger.LogInformation("AI Studio runs without an enterprise configuration.");
break;
case null:
programLogger.LogWarning($"AI Studio runs with an enterprise configuration id ('{enterpriseConfigId}'), but the configuration server URL is not set.");
break;
case not null when enterpriseConfigId == Guid.Empty:
programLogger.LogWarning($"AI Studio runs with an enterprise configuration server URL ('{enterpriseConfigServerUrl}'), but the configuration ID is not set.");
break;
default:
programLogger.LogInformation($"AI Studio runs with an enterprise configuration id ('{enterpriseConfigId}') and configuration server URL ('{enterpriseConfigServerUrl}').");
break;
}
TaskScheduler.UnobservedTaskException += (sender, taskArgs) => TaskScheduler.UnobservedTaskException += (sender, taskArgs) =>
{ {
programLogger.LogError(taskArgs.Exception, $"Unobserved task exception by sender '{sender ?? "n/a"}'."); programLogger.LogError(taskArgs.Exception, $"Unobserved task exception by sender '{sender ?? "n/a"}'.");

View File

@ -0,0 +1,44 @@
namespace AIStudio.Tools.Services;
public sealed partial class RustService
{
/// <summary>
/// Tries to read the enterprise environment for the current user's configuration ID.
/// </summary>
/// <returns>
/// Returns the empty Guid when the environment is not set or the request fails.
/// Otherwise, the configuration ID.
/// </returns>
public async Task<Guid> EnterpriseEnvConfigId()
{
var result = await this.http.GetAsync("/system/enterprise/config/id");
if (!result.IsSuccessStatusCode)
{
this.logger!.LogError($"Failed to query the enterprise configuration ID: '{result.StatusCode}'");
return Guid.Empty;
}
Guid.TryParse(await result.Content.ReadAsStringAsync(), out var configurationId);
return configurationId;
}
/// <summary>
/// Tries to read the enterprise environment for the current user's configuration server URL.
/// </summary>
/// <returns>
/// Returns null when the environment is not set or the request fails.
/// Otherwise, the configuration server URL.
/// </returns>
public async Task<string?> EnterpriseEnvConfigServerUrl()
{
var result = await this.http.GetAsync("/system/enterprise/config/server");
if (!result.IsSuccessStatusCode)
{
this.logger!.LogError($"Failed to query the enterprise configuration server URL: '{result.StatusCode}'");
return null;
}
var serverUrl = await result.Content.ReadAsStringAsync();
return string.IsNullOrWhiteSpace(serverUrl) ? null : serverUrl;
}
}

32
runtime/Cargo.lock generated
View File

@ -2632,6 +2632,7 @@ dependencies = [
"base64 0.22.1", "base64 0.22.1",
"calamine", "calamine",
"cbc", "cbc",
"cfg-if",
"cipher", "cipher",
"crossbeam-channel", "crossbeam-channel",
"file-format", "file-format",
@ -2660,6 +2661,7 @@ dependencies = [
"tokio", "tokio",
"tokio-stream", "tokio-stream",
"url", "url",
"windows-registry 0.5.2",
] ]
[[package]] [[package]]
@ -3978,7 +3980,7 @@ dependencies = [
"wasm-bindgen", "wasm-bindgen",
"wasm-bindgen-futures", "wasm-bindgen-futures",
"web-sys", "web-sys",
"windows-registry", "windows-registry 0.4.0",
] ]
[[package]] [[package]]
@ -5949,15 +5951,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3"
dependencies = [ dependencies = [
"windows-result", "windows-result",
"windows-strings", "windows-strings 0.3.1",
"windows-targets 0.53.0", "windows-targets 0.53.0",
] ]
[[package]] [[package]]
name = "windows-result" name = "windows-registry"
version = "0.3.2" version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" checksum = "b3bab093bdd303a1240bb99b8aba8ea8a69ee19d34c9e2ef9594e708a4878820"
dependencies = [
"windows-link",
"windows-result",
"windows-strings 0.4.2",
]
[[package]]
name = "windows-result"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
dependencies = [ dependencies = [
"windows-link", "windows-link",
] ]
@ -5971,6 +5984,15 @@ dependencies = [
"windows-link", "windows-link",
] ]
[[package]]
name = "windows-strings"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57"
dependencies = [
"windows-link",
]
[[package]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.42.0" version = "0.42.0"

View File

@ -37,6 +37,7 @@ file-format = "0.27.0"
calamine = "0.27.0" calamine = "0.27.0"
pdfium-render = "0.8.31" pdfium-render = "0.8.31"
sys-locale = "0.3.2" sys-locale = "0.3.2"
cfg-if = "1.0.0"
# Fixes security vulnerability downstream, where the upstream is not fixed yet: # Fixes security vulnerability downstream, where the upstream is not fixed yet:
url = "2.5" url = "2.5"
@ -50,5 +51,8 @@ reqwest = { version = "0.12.15", features = ["native-tls-vendored"] }
# Fixes security vulnerability downstream, where the upstream is not fixed yet: # Fixes security vulnerability downstream, where the upstream is not fixed yet:
openssl = "0.10.72" openssl = "0.10.72"
[target.'cfg(target_os = "windows")'.dependencies]
windows-registry = "0.5.2"
[features] [features]
custom-protocol = ["tauri/custom-protocol"] custom-protocol = ["tauri/custom-protocol"]

View File

@ -1,4 +1,6 @@
use std::env;
use std::sync::OnceLock; use std::sync::OnceLock;
use log::info;
use rocket::get; use rocket::get;
use sys_locale::get_locale; use sys_locale::get_locale;
use crate::api_token::APIToken; use crate::api_token::APIToken;
@ -44,3 +46,97 @@ pub fn read_user_language(_token: APIToken) -> String {
String::from("en-US") String::from("en-US")
}) })
} }
#[get("/system/enterprise/config/id")]
pub fn read_enterprise_env_config_id(_token: APIToken) -> Option<String> {
//
// When we are on a Windows machine, we try to read the enterprise config from
// the Windows registry. In case we can't find the registry key, or we are on a
// macOS or Linux machine, we try to read the enterprise config from the
// environment variables.
//
// The registry key is:
// HKEY_CURRENT_USER\Software\github\MindWork AI Studio\Enterprise IT
//
// In this registry key, we expect the following values:
// - config_id
//
// The environment variable is:
// MINDWORK_AI_STUDIO_ENTERPRISE_CONFIG_ID
//
get_enterprise_configuration(
"config_id",
"MINDWORK_AI_STUDIO_ENTERPRISE_CONFIG_ID",
)
}
#[get("/system/enterprise/config/server")]
pub fn read_enterprise_env_config_server_url(_token: APIToken) -> Option<String> {
//
// When we are on a Windows machine, we try to read the enterprise config from
// the Windows registry. In case we can't find the registry key, or we are on a
// macOS or Linux machine, we try to read the enterprise config from the
// environment variables.
//
// The registry key is:
// HKEY_CURRENT_USER\Software\github\MindWork AI Studio\Enterprise IT
//
// In this registry key, we expect the following values:
// - config_server_url
//
// The environment variable is:
// MINDWORK_AI_STUDIO_ENTERPRISE_CONFIG_SERVER_URL
//
get_enterprise_configuration(
"config_server_url",
"MINDWORK_AI_STUDIO_ENTERPRISE_CONFIG_SERVER_URL",
)
}
fn get_enterprise_configuration(reg_value: &str, env_name: &str) -> Option<String> {
info!("Trying to read the enterprise environment for some predefined configuration.");
cfg_if::cfg_if! {
if #[cfg(target_os = "windows")] {
info!(r"Detected a Windows machine, trying to read the registry key 'HKEY_CURRENT_USER\Software\github\MindWork AI Studio\Enterprise IT' or the environment variables");
use windows_registry::*;
let key_path = r"Software\github\MindWork AI Studio\Enterprise IT";
let key = match CURRENT_USER.open(key_path) {
Ok(key) => key,
Err(_) => {
info!(r"Could not read the registry key HKEY_CURRENT_USER\Software\github\MindWork AI Studio\Enterprise IT. Falling back to environment variables.");
return match env::var(env_name) {
Ok(val) => {
info!("Falling back to the environment variable '{}' was successful.", env_name);
Some(val)
},
Err(_) => {
info!("Falling back to the environment variable '{}' was not successful. It appears that this is not an enterprise environment.", env_name);
None
},
}
},
};
match key.get_string(reg_value) {
Ok(val) => Some(val),
Err(_) => {
info!(r"We could read the registry key 'HKEY_CURRENT_USER\Software\github\MindWork AI Studio\Enterprise IT', but the value '{}' could not be read. Falling back to environment variables.", reg_value);
match env::var(env_name) {
Ok(val) => {
info!("Falling back to the environment variable '{}' was successful.", env_name);
Some(val)
},
Err(_) => {
info!("Falling back to the environment variable '{}' was not successful. It appears that this is not an enterprise environment.", env_name);
None
}
}
},
}
} else {
// In the case of macOS or Linux, we just read the environment variable:
info!(r"Detected a Unix machine, trying to read the environment variable '{}'.", env_name)
env::var(env_name).ok()
}
}
}

View File

@ -78,6 +78,8 @@ pub fn start_runtime_api() {
crate::environment::get_data_directory, crate::environment::get_data_directory,
crate::environment::get_config_directory, crate::environment::get_config_directory,
crate::environment::read_user_language, crate::environment::read_user_language,
crate::environment::read_enterprise_env_config_id,
crate::environment::read_enterprise_env_config_server_url,
crate::file_data::extract_data, crate::file_data::extract_data,
crate::file_data::read_pdf, crate::file_data::read_pdf,
crate::log::get_log_paths, crate::log::get_log_paths,