Skip to main content

lfsx_server/config/
forges.rs

1use super::{Auth, Provider, allowed, anonymous_read, api_url_from};
2use crate::auth::Namespaces;
3use crate::namespace::is_forge_name;
4
5#[derive(Debug, Clone)]
6pub struct Forge {
7    pub name: String,
8    pub auth: Auth,
9}
10
11pub(super) fn from_env(primary: &Auth) -> Vec<Forge> {
12    let Some(names) = std::env::var("LFSX_FORGES")
13        .ok()
14        .filter(|names| !names.trim().is_empty())
15    else {
16        return Vec::new();
17    };
18
19    parse(&names, primary, |variable| std::env::var(variable).ok())
20}
21
22pub(super) fn parse(
23    names: &str,
24    primary: &Auth,
25    read: impl Fn(&str) -> Option<String>,
26) -> Vec<Forge> {
27    let Auth::Forge {
28        cache_ttl,
29        rejection_ttl,
30        lookup_budget,
31        ..
32    } = primary
33    else {
34        panic!(
35            "LFSX_FORGES is set and LFSX_AUTH=disabled: with authentication off there is nothing to \
36             ask the other forges about"
37        );
38    };
39
40    let mut forges: Vec<Forge> = Vec::new();
41    for name in names
42        .split(',')
43        .map(str::trim)
44        .filter(|name| !name.is_empty())
45    {
46        if !is_forge_name(name) {
47            panic!(
48                "LFSX_FORGES names {name}: a forge name is 1 to 32 lowercase letters, digits or \
49                 dashes, and not api or dashboard"
50            );
51        }
52        if forges.iter().any(|forge| forge.name == name) {
53            panic!("LFSX_FORGES names {name} twice");
54        }
55
56        let prefix = format!("LFSX_FORGE_{}_", name.to_uppercase().replace('-', "_"));
57        let variable = |suffix: &str| format!("{prefix}{suffix}");
58        let value = |suffix: &str| read(&variable(suffix));
59
60        let provider = match value("AUTH").as_deref() {
61            Some("github") => Provider::Github,
62            Some("gitlab") => Provider::Gitlab,
63            Some("gitea") | Some("forgejo") => Provider::Gitea,
64            _ => panic!(
65                "{} must be github, gitlab, gitea or forgejo",
66                variable("AUTH")
67            ),
68        };
69
70        forges.push(Forge {
71            name: name.to_owned(),
72            auth: Auth::Forge {
73                provider,
74                api_url: api_url_from(provider, &variable("API_URL"), value("API_URL").as_deref()),
75                cache_ttl: *cache_ttl,
76                rejection_ttl: *rejection_ttl,
77                lookup_budget: *lookup_budget,
78                github_app: None,
79                anonymous_read: anonymous_read(value("ANONYMOUS_READ").as_deref()),
80                restricted: Namespaces::parse(
81                    &variable("RESTRICTED"),
82                    value("RESTRICTED").as_deref(),
83                ),
84                allowed: allowed(&variable("ALLOWED"), value("ALLOWED").as_deref()),
85            },
86        });
87    }
88
89    forges
90}
91
92#[cfg(test)]
93mod tests;