Skip to main content

xbp_cli/oci/
mod.rs

1//! CLI OCI surface (`xbp oci`, `xbp config oci`).
2//!
3//! Registry math lives in `xbp-oci`; this module wires auth sources and clap.
4
5mod commands;
6
7pub use commands::{run_config_oci, run_oci};
8pub use xbp_oci::{
9    parse_image_ref, resolve_auth_from_candidates, DefaultOciPromoter, DefaultOciResolver,
10    OciAuth, OciAuthRequest, OciClient, OciPromoter, OciRef, OciResolver,
11};
12
13use crate::config::SshConfig;
14use crate::strategies::XbpConfig;
15use std::env;
16
17/// Build ordered (source, username?, token) candidates for a registry.
18pub fn auth_candidates_for_registry(
19    registry: &str,
20    project: &XbpConfig,
21) -> Vec<(String, Option<String>, String)> {
22    let mut out = Vec::new();
23
24    if let (Ok(user), Ok(token)) = (env::var("XBP_OCI_USERNAME"), env::var("XBP_OCI_TOKEN")) {
25        if !token.trim().is_empty() {
26            out.push(("env:XBP_OCI_*".into(), Some(user), token));
27        }
28    }
29
30    let registry_cfg = project
31        .oci
32        .as_ref()
33        .and_then(|o| o.registries.get(registry));
34    let username = registry_cfg.and_then(|r| r.username.clone());
35
36    let wants_github = registry.contains("ghcr.io")
37        || registry_cfg
38            .and_then(|r| r.token_source.as_deref())
39            .map(|s| s.eq_ignore_ascii_case("github"))
40            .unwrap_or(false);
41
42    if wants_github {
43        for key in ["XBP_GITHUB_TOKEN", "GH_TOKEN", "GITHUB_TOKEN"] {
44            if let Ok(token) = env::var(key) {
45                if !token.trim().is_empty() {
46                    out.push((
47                        format!("env:{key}"),
48                        username
49                            .clone()
50                            .or_else(|| Some("x-access-token".into())),
51                        token,
52                    ));
53                }
54            }
55        }
56        if let Ok(cfg) = SshConfig::load() {
57            if let Some(token) = cfg.github_oauth2_key.filter(|t| !t.trim().is_empty()) {
58                out.push((
59                    "global:github".into(),
60                    username.clone().or_else(|| Some("x-access-token".into())),
61                    token,
62                ));
63            }
64            if let Some(oci) = cfg.oci {
65                if let Some(cred) = oci.registries.get(registry) {
66                    if let Some(token) = cred.token.clone().filter(|t| !t.trim().is_empty()) {
67                        out.push((
68                            format!("global:oci:{registry}"),
69                            cred.username.clone().or(username.clone()),
70                            token,
71                        ));
72                    }
73                }
74            }
75        }
76    } else if let Ok(cfg) = SshConfig::load() {
77        if let Some(oci) = cfg.oci {
78            if let Some(cred) = oci.registries.get(registry) {
79                if let Some(token) = cred.token.clone().filter(|t| !t.trim().is_empty()) {
80                    out.push((
81                        format!("global:oci:{registry}"),
82                        cred.username.clone().or(username),
83                        token,
84                    ));
85                }
86            }
87        }
88    }
89
90    out
91}