steid

@jamesgill /

2.8 KBCode·Blame·Raw
0d12f7dfeat: config from env and SQLite pool in app context1mo
1use std::path::PathBuf;
2
3use serde::Deserialize;
4
5/// Application configuration, read from `STEID_`-prefixed environment variables.
6///
7/// The bind address is deliberately absent: Topcoat owns it via `HOST` and `PORT`.
8#[derive(Debug, Clone, Deserialize)]
9pub struct AppConfig {
10 /// SQLite connection string. Needs `mode=rwc` to create the file on first boot.
11 #[serde(default = "default_database_url")]
12 pub database_url: String,
13
02eb2e4feat: GitStorage port and DiskGitStorage24d
14 /// Root directory for bare git repositories, laid out as
15 /// `{data_dir}/{handle}/{name}.git`.
0d12f7dfeat: config from env and SQLite pool in app context1mo
16 ///
02eb2e4feat: GitStorage port and DiskGitStorage24d
17 /// Keyed by handle rather than `OrgId` so the directory is legible to anyone
18 /// debugging it; the cost is that renaming a handle becomes a directory move.
0d12f7dfeat: config from env and SQLite pool in app context1mo
19 #[serde(default = "default_data_dir")]
20 pub data_dir: PathBuf,
264c436fix: session cookie survives plain-HTTP localhost in dev1mo
21
22 /// Drops `Secure` and the `__Host-` prefix from the session cookie so it survives
23 /// plain-HTTP `localhost`.
24 ///
25 /// Development only. With this on, the session cookie travels unencrypted and
26 /// anyone on the path can lift it.
27 #[serde(default)]
28 pub insecure_cookies: bool,
0d12f7dfeat: config from env and SQLite pool in app context1mo
29}
30
31fn default_database_url() -> String {
32 "sqlite:steid.db?mode=rwc".to_owned()
33}
34
35fn default_data_dir() -> PathBuf {
36 PathBuf::from("./data")
37}
38
39impl AppConfig {
40 /// Loads configuration from the environment, applying defaults for anything unset.
41 pub fn from_env() -> Result<Self, envy::Error> {
42 envy::prefixed("STEID_").from_env()
43 }
44}
45
46#[cfg(test)]
47mod tests {
48 use super::*;
49
50 /// Builds a config from an explicit iterator rather than the process environment,
51 /// so tests don't race on shared global state.
52 fn from_pairs(pairs: &[(&str, &str)]) -> Result<AppConfig, envy::Error> {
1e1ae56feat: identity domain model1mo
53 envy::prefixed("STEID_").from_iter(
54 pairs
55 .iter()
56 .map(|(k, v)| ((*k).to_owned(), (*v).to_owned())),
57 )
0d12f7dfeat: config from env and SQLite pool in app context1mo
58 }
59
60 #[test]
61 fn applies_defaults_when_environment_is_empty() {
62 let config = from_pairs(&[]).expect("defaults should satisfy every field");
63
64 assert_eq!(config.database_url, "sqlite:steid.db?mode=rwc");
65 assert_eq!(config.data_dir, PathBuf::from("./data"));
66 }
67
68 #[test]
69 fn reads_prefixed_variables() {
70 let config = from_pairs(&[
71 ("STEID_DATABASE_URL", "sqlite:custom.db?mode=rwc"),
72 ("STEID_DATA_DIR", "/srv/steid/repos"),
73 ])
74 .expect("explicit values should parse");
75
76 assert_eq!(config.database_url, "sqlite:custom.db?mode=rwc");
77 assert_eq!(config.data_dir, PathBuf::from("/srv/steid/repos"));
78 }
79
80 #[test]
81 fn ignores_unprefixed_variables() {
82 let config = from_pairs(&[("DATA_DIR", "/should/be/ignored")])
83 .expect("unprefixed keys should not interfere");
84
85 assert_eq!(config.data_dir, PathBuf::from("./data"));
86 }
87}