1pub mod admin;
7pub mod answers_crypto;
8pub mod bundle;
9pub mod bundle_source;
10pub mod capabilities;
11pub mod card_setup;
12pub mod cli_args;
13pub mod cli_commands;
14pub mod cli_helpers;
15pub mod cli_i18n;
16pub mod config_envelope;
17pub mod deployment_targets;
18pub mod discovery;
19pub mod doctor;
20pub mod engine;
21pub mod flow;
22pub mod gtbundle;
23pub mod plan;
24pub mod platform_setup;
25pub mod reload;
26pub mod secret_name;
27pub mod secrets;
28pub mod setup_input;
29pub mod setup_to_formspec;
30pub mod tenant_config;
31pub mod webhook;
32
33#[cfg(feature = "ui")]
34pub mod ui;
35
36pub mod qa {
37 pub mod bridge;
40 pub mod persist;
41 pub mod prompts;
42 pub mod shared_questions;
43 pub mod wizard;
44}
45
46pub use bundle_source::BundleSource;
47pub use engine::SetupEngine;
48pub use plan::{SetupMode, SetupPlan, SetupStep, SetupStepKind};
49
50pub use qa::wizard::{
52 ProviderFormSpec, SHARED_QUESTION_IDS, SharedQuestionsResult, build_provider_form_specs,
53 collect_shared_questions, prompt_shared_questions, run_qa_setup_with_shared,
54};
55
56pub fn version() -> &'static str {
58 env!("CARGO_PKG_VERSION")
59}
60
61pub fn resolve_env(override_env: Option<&str>) -> String {
65 override_env
66 .map(|v| v.to_string())
67 .or_else(|| std::env::var("GREENTIC_ENV").ok())
68 .unwrap_or_else(|| "dev".to_string())
69}
70
71pub fn canonical_secret_uri(
73 env: &str,
74 tenant: &str,
75 team: Option<&str>,
76 provider: &str,
77 key: &str,
78) -> String {
79 let team_segment = canonical_team(team);
80 let provider_segment = if provider.is_empty() {
81 "messaging".to_string()
82 } else {
83 provider.to_string()
84 };
85 let normalized_key = secret_name::canonical_secret_name(key);
86 format!("secrets://{env}/{tenant}/{team_segment}/{provider_segment}/{normalized_key}")
87}
88
89fn canonical_team(team: Option<&str>) -> &str {
93 match team
94 .map(|v| v.trim())
95 .filter(|t| !t.is_empty() && !t.eq_ignore_ascii_case("default"))
96 {
97 Some(v) => v,
98 None => "_",
99 }
100}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105
106 #[test]
107 fn version_is_correct() {
108 assert!(version().starts_with("0.5"));
109 }
110
111 #[test]
112 fn secret_uri_basic() {
113 let uri = canonical_secret_uri("dev", "demo", None, "messaging-telegram", "bot_token");
114 assert_eq!(uri, "secrets://dev/demo/_/messaging-telegram/bot_token");
115 }
116
117 #[test]
118 fn secret_uri_with_team() {
119 let uri = canonical_secret_uri("dev", "acme", Some("ops"), "state-redis", "redis_url");
120 assert_eq!(uri, "secrets://dev/acme/ops/state-redis/redis_url");
121 }
122
123 #[test]
124 fn secret_uri_default_team_becomes_wildcard() {
125 let uri = canonical_secret_uri(
126 "dev",
127 "demo",
128 Some("default"),
129 "messaging-slack",
130 "bot_token",
131 );
132 assert_eq!(uri, "secrets://dev/demo/_/messaging-slack/bot_token");
133 }
134}