systemprompt_cloud/profile_authoring/
local_builder.rs1use std::path::Path;
7
8use systemprompt_identifiers::{Email, TenantId};
9use systemprompt_loader::ExtensionLoader;
10use systemprompt_manifest::profile::{
11 ProfileResult, SecretsConfig, SecretsSource, SecretsValidationMode,
12};
13use systemprompt_manifest::services::SystemAdminConfig;
14use systemprompt_manifest::{
15 CloudConfig, CloudValidationMode, ExtensionsConfig, HostingProvider, PathsConfig, Profile,
16 ProfileDatabaseConfig, ProfileType, RateLimitsConfig, ServerConfig, SiteConfig,
17};
18
19use super::{generate_display_name, local_runtime_config, security_config, webhook_governance};
20use crate::constants::profile as consts;
21use crate::paths::ProjectContext;
22
23#[derive(Debug)]
24pub struct LocalProfileBuilder {
25 name: String,
26 tenant_id: Option<TenantId>,
27 secrets_path: String,
28 services_path: String,
29}
30
31impl LocalProfileBuilder {
32 pub fn new(
33 name: impl Into<String>,
34 secrets_path: impl AsRef<Path>,
35 services_path: impl AsRef<Path>,
36 ) -> Self {
37 Self {
38 name: name.into(),
39 tenant_id: None,
40 secrets_path: secrets_path.as_ref().to_string_lossy().to_string(),
41 services_path: services_path.as_ref().to_string_lossy().to_string(),
42 }
43 }
44
45 #[must_use]
46 pub fn with_tenant_id(mut self, tenant_id: TenantId) -> Self {
47 self.tenant_id = Some(tenant_id);
48 self
49 }
50
51 pub fn build(self) -> ProfileResult<Profile> {
52 let ctx = ProjectContext::discover();
53 let root = ctx.root();
54 let system_path = root.to_string_lossy().to_string();
55 let display_name = generate_display_name(&self.name);
56 let local_url = format!("http://localhost:{}", consts::DEFAULT_PORT);
57
58 let mut profile = Profile {
59 storage: systemprompt_manifest::profile::StorageConfig::default(),
60 observability: systemprompt_manifest::profile::ObservabilityConfig::default(),
61 config_planes: systemprompt_manifest::profile::ConfigPlanesConfig::default(),
62 licence: systemprompt_manifest::profile::LicenceConfig::default(),
63 name: self.name,
64 display_name,
65 target: ProfileType::Local,
66 site: SiteConfig {
67 name: "systemprompt.io".to_owned(),
68 github_link: None,
69 },
70 database: ProfileDatabaseConfig {
71 db_type: consts::DEFAULT_DB_TYPE.to_owned(),
72 external_db_access: false,
73 migrate_on_boot: true,
74 pool: None,
75 },
76 security: security_config(Vec::new(), true),
77 server: local_server_config(local_url),
78 paths: PathsConfig {
79 root: None,
80 system: system_path,
81 services: self.services_path,
82 bin: ExtensionLoader::resolve_bin_directory(root, None)
83 .to_string_lossy()
84 .to_string(),
85 storage: Some(ctx.storage_dir().to_string_lossy().to_string()),
86 geoip_database: None,
87 data: None,
88 web_path: None,
89 shipped_files: None,
90 },
91 rate_limits: RateLimitsConfig {
92 disabled: true,
93 ..Default::default()
94 },
95 runtime: local_runtime_config(),
96 cloud: Some(CloudConfig {
97 tenant_id: self.tenant_id,
98 provider: HostingProvider::DockerLocal,
99 validation: CloudValidationMode::Warn,
100 deploy: None,
101 operator: None,
102 }),
103 secrets: Some(SecretsConfig {
104 secrets_path: Some(self.secrets_path),
105 validation: SecretsValidationMode::Warn,
106 source: SecretsSource::File,
107 vault: None,
108 external: None,
109 refresh_secs: None,
110 }),
111 extensions: ExtensionsConfig::default(),
112 governance: Some(webhook_governance()),
113 services: systemprompt_manifest::profile::ServicesProfileConfig::default(),
114 judge: systemprompt_manifest::profile::JudgeProfile::default(),
115 retention: systemprompt_manifest::profile::RetentionConfig::default(),
116 system_admin: SystemAdminConfig {
117 username: "admin".to_owned(),
118 email: Some(Email::local_admin()),
119 },
120 };
121 profile.derive_fields()?;
122 Ok(profile)
123 }
124}
125
126fn local_server_config(local_url: String) -> ServerConfig {
127 let mut server = ServerConfig::new(consts::LOCAL_HOST, consts::DEFAULT_PORT, local_url);
128 server.extra_cors_origins = vec!["http://localhost:5173".to_owned()];
129 server.role = systemprompt_manifest::profile::NodeRole::All;
130 server.trusted_proxies =
131 crate::trusted_proxies::default_trusted_proxies(HostingProvider::DockerLocal);
132 server
133}