Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
d02d6b5
Add enterprise config support via env vars & Windows registry
SommerEngineering May 31, 2025
ea3271b
Fixed the Unix implementation
SommerEngineering May 31, 2025
1fb04a7
Refactor enterprise config functions to return String instead of Option
SommerEngineering May 31, 2025
86f5255
Fixed config plugins action column
SommerEngineering Jun 1, 2025
f4b2038
Added delete endpoint for enterprise config ID
SommerEngineering Jun 1, 2025
ed006f3
Added SettingsLocker service and implementation
SommerEngineering Jun 1, 2025
03bf288
Refactor TemporaryChatService for cleaner logging and improvements
SommerEngineering Jun 1, 2025
944f4a8
Add method to remove enterprise config ID
SommerEngineering Jun 1, 2025
72ea91d
Add EnterpriseEnvironmentService and plugin management
SommerEngineering Jun 1, 2025
3f97264
Disable update frequency when locked via SettingsLocker
SommerEngineering Jun 1, 2025
f1fcae3
Inject SettingsLocker into SettingsPanelBase
SommerEngineering Jun 1, 2025
ab84cf1
Add enterprise configuration handling in SettingsPanelProviders
SommerEngineering Jun 1, 2025
9404e83
Manage IsEnterpriseConfiguration for manual providers
SommerEngineering Jun 1, 2025
c320d05
Add enterprise environment details to About page
SommerEngineering Jun 1, 2025
fa48dd8
Added example config plugin
SommerEngineering Jun 1, 2025
a44eaa4
Update IsPluginEnabled to include configuration plugins
SommerEngineering Jun 1, 2025
28484da
Added config plugin class
SommerEngineering Jun 1, 2025
d51093b
Remove enterprise environment configuration logging
SommerEngineering Jun 1, 2025
e1478d9
Mark configuration plugins as partially implemented
SommerEngineering Jun 1, 2025
7903f13
Add enterprise config plugin support in Provider
SommerEngineering Jun 1, 2025
85fcb4a
Refactor hot reload system to improve event handling & monitor delete…
SommerEngineering Jun 1, 2025
f1d0549
Log warning on plugin load cancellation due to timeout
SommerEngineering Jun 1, 2025
e573b4d
Remove unavailable enterprise configuration plugins and reset related…
SommerEngineering Jun 1, 2025
0077875
Add support for configuration plugins in PluginFactory
SommerEngineering Jun 1, 2025
83d7ab6
Refactored startup code of the plugin factory & handle config plugins…
SommerEngineering Jun 1, 2025
a8d96c9
Add EnterpriseEnvironment record struct to manage configuration state
SommerEngineering Jun 1, 2025
98aaea4
Updated I18M
SommerEngineering Jun 1, 2025
441cc0f
Updated changelog
SommerEngineering Jun 1, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Add enterprise config support via env vars & Windows registry
  • Loading branch information
SommerEngineering committed May 31, 2025
commit d02d6b5870eafb6f9951ef2b612337ecf78534df
24 changes: 24 additions & 0 deletions app/MindWork AI Studio/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,30 @@ public static async Task Main()
await rust.AppIsReady();
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) =>
{
programLogger.LogError(taskArgs.Exception, $"Unobserved task exception by sender '{sender ?? "n/a"}'.");
Expand Down
44 changes: 44 additions & 0 deletions app/MindWork AI Studio/Tools/Services/RustService.Enterprise.cs
Original file line number Diff line number Diff line change
@@ -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;
}
}
30 changes: 26 additions & 4 deletions runtime/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ file-format = "0.27.0"
calamine = "0.27.0"
pdfium-render = "0.8.31"
sys-locale = "0.3.2"
cfg-if = "1.0.0"

# Fixes security vulnerability downstream, where the upstream is not fixed yet:
url = "2.5"
Expand All @@ -50,5 +51,8 @@ reqwest = { version = "0.12.15", features = ["native-tls-vendored"] }
# Fixes security vulnerability downstream, where the upstream is not fixed yet:
openssl = "0.10.72"

[target.'cfg(target_os = "windows")'.dependencies]
windows-registry = "0.5.2"

[features]
custom-protocol = ["tauri/custom-protocol"]
96 changes: 96 additions & 0 deletions runtime/src/environment.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use std::env;
use std::sync::OnceLock;
use log::info;
use rocket::get;
use sys_locale::get_locale;
use crate::api_token::APIToken;
Expand Down Expand Up @@ -43,4 +45,98 @@ pub fn read_user_language(_token: APIToken) -> String {
log::warn!("Could not determine the system language. Use default '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()
}
}
}
2 changes: 2 additions & 0 deletions runtime/src/runtime_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ pub fn start_runtime_api() {
crate::environment::get_data_directory,
crate::environment::get_config_directory,
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::read_pdf,
crate::log::get_log_paths,
Expand Down