systemprompt_cloud/profile_authoring/
local_builder.rs1use std::path::Path;
7
8use systemprompt_identifiers::{Email, TenantId};
9use systemprompt_loader::ExtensionLoader;
10use systemprompt_manifest::profile::{SecretsConfig, SecretsSource, SecretsValidationMode};
11use systemprompt_manifest::services::SystemAdminConfig;
12use systemprompt_manifest::{
13 CloudConfig, CloudValidationMode, ContentNegotiationConfig, ExtensionsConfig, PathsConfig,
14 Profile, ProfileDatabaseConfig, ProfileType, RateLimitsConfig, SecurityHeadersConfig,
15 ServerConfig, SiteConfig,
16};
17
18use super::{generate_display_name, local_runtime_config, security_config, webhook_governance};
19use crate::constants::profile as consts;
20use crate::paths::ProjectContext;
21
22#[derive(Debug)]
23pub struct LocalProfileBuilder {
24 name: String,
25 tenant_id: Option<TenantId>,
26 secrets_path: String,
27 services_path: String,
28}
29
30impl LocalProfileBuilder {
31 pub fn new(
32 name: impl Into<String>,
33 secrets_path: impl AsRef<Path>,
34 services_path: impl AsRef<Path>,
35 ) -> Self {
36 Self {
37 name: name.into(),
38 tenant_id: None,
39 secrets_path: secrets_path.as_ref().to_string_lossy().to_string(),
40 services_path: services_path.as_ref().to_string_lossy().to_string(),
41 }
42 }
43
44 #[must_use]
45 pub fn with_tenant_id(mut self, tenant_id: TenantId) -> Self {
46 self.tenant_id = Some(tenant_id);
47 self
48 }
49
50 #[must_use]
51 pub fn build(self) -> 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 let internal_url = local_url.clone();
58
59 Profile {
60 storage: systemprompt_manifest::profile::StorageConfig::default(),
61 observability: systemprompt_manifest::profile::ObservabilityConfig::default(),
62 config_planes: systemprompt_manifest::profile::ConfigPlanesConfig::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(&local_url, Vec::new(), true),
77 server: local_server_config(local_url),
78 paths: PathsConfig {
79 system: system_path,
80 services: self.services_path,
81 bin: ExtensionLoader::resolve_bin_directory(root, None)
82 .to_string_lossy()
83 .to_string(),
84 storage: Some(ctx.storage_dir().to_string_lossy().to_string()),
85 geoip_database: None,
86 data: None,
87 web_path: None,
88 shipped_files: None,
89 },
90 rate_limits: RateLimitsConfig {
91 disabled: true,
92 ..Default::default()
93 },
94 runtime: local_runtime_config(),
95 cloud: Some(CloudConfig {
96 tenant_id: self.tenant_id,
97 validation: CloudValidationMode::Warn,
98 }),
99 secrets: Some(SecretsConfig {
100 secrets_path: Some(self.secrets_path),
101 validation: SecretsValidationMode::Warn,
102 source: SecretsSource::File,
103 vault: None,
104 external: None,
105 refresh_secs: None,
106 }),
107 extensions: ExtensionsConfig::default(),
108 governance: Some(webhook_governance(&internal_url)),
109 services: systemprompt_manifest::profile::ServicesProfileConfig::default(),
110 judge: systemprompt_manifest::profile::JudgeProfile::default(),
111 retention: systemprompt_manifest::profile::RetentionConfig::default(),
112 system_admin: SystemAdminConfig {
113 username: "admin".to_owned(),
114 email: Some(Email::local_admin()),
115 },
116 }
117 }
118}
119
120fn local_server_config(local_url: String) -> ServerConfig {
121 ServerConfig {
122 host: consts::LOCAL_HOST.to_owned(),
123 port: consts::DEFAULT_PORT,
124 api_server_url: local_url.clone(),
125 api_internal_url: local_url.clone(),
126 api_external_url: local_url.clone(),
127 use_https: false,
128 cors_allowed_origins: vec![local_url, "http://localhost:5173".to_owned()],
129 content_negotiation: ContentNegotiationConfig::default(),
130 security_headers: SecurityHeadersConfig::default(),
131 instance_id: None,
132 metrics_port: None,
133 max_concurrent_streams: systemprompt_manifest::config::DEFAULT_MAX_CONCURRENT_STREAMS,
134 role: systemprompt_manifest::profile::NodeRole::All,
135 max_in_flight: None,
136 shutdown: systemprompt_manifest::profile::ShutdownConfig::default(),
137 trusted_proxies: crate::trusted_proxies::default_local_trusted_proxies(),
138 }
139}