Skip to main content

helm_schema_cli/cli/
k8s_args.rs

1use std::path::PathBuf;
2
3use clap::Args;
4
5/// `--k8s-version-fallback` accepts either `auto` or a window size `<n>`.
6#[derive(Debug, Clone, PartialEq, Eq)]
7pub enum K8sVersionFallback {
8    /// Auto-extend the single explicit `--k8s-version` with a default
9    /// sliding window of older minors below it.
10    Auto,
11    /// Explicit window size. `0` is equivalent to no fallback.
12    Window(u32),
13}
14
15impl std::str::FromStr for K8sVersionFallback {
16    type Err = String;
17
18    fn from_str(s: &str) -> Result<Self, Self::Err> {
19        if s.eq_ignore_ascii_case("auto") {
20            Ok(K8sVersionFallback::Auto)
21        } else {
22            s.parse::<u32>()
23                .map(K8sVersionFallback::Window)
24                .map_err(|err| format!("expected `auto` or a non-negative integer: {err}"))
25        }
26    }
27}
28
29/// Kubernetes schema versions, mirrors, cache, and network options.
30#[derive(Args, Debug, Clone)]
31pub struct K8sArgs {
32    /// Kubernetes minor version directory(s) to consult, in
33    /// user-supplied priority order. The first value is the primary;
34    /// any further values are explicit fallbacks.
35    #[arg(long = "k8s-version", default_values_t = vec![String::from("v1.35.0")])]
36    pub k8s_version: Vec<String>,
37
38    /// Auto-extend the (single explicit) `--k8s-version` with older
39    /// minors. `auto` uses the default window; `<n>` selects an
40    /// explicit window size.
41    #[arg(long = "k8s-version-fallback", conflicts_with = "strict_k8s_version")]
42    pub k8s_version_fallback: Option<K8sVersionFallback>,
43
44    /// Additional upstream K8s schema mirror URL. Repeatable. Per-source
45    /// cache namespacing keeps mirror entries from masking the default.
46    #[arg(long = "k8s-schema-mirror")]
47    pub k8s_schema_mirror: Vec<String>,
48
49    /// Managed cache root for K8s schemas. Subject to the cache
50    /// invalidation contract.
51    #[arg(long = "k8s-schema-cache-dir")]
52    pub k8s_schema_cache_dir: Option<PathBuf>,
53
54    /// Bypass K8s schema cache reads and re-check upstream directly.
55    ///
56    /// Successful responses and authoritative 404s still refresh cache
57    /// state, so this can repair stale local entries.
58    #[arg(long = "no-cache")]
59    pub no_cache: bool,
60
61    /// Suppress auto-fallback version semantics. Conflicts only with
62    /// `--k8s-version-fallback`; orthogonal to `--k8s-schema-mirror`.
63    #[arg(long = "strict-k8s-version")]
64    pub strict_k8s_version: bool,
65
66    /// Force offline. Equivalent to setting `HELM_SCHEMA_ALLOW_NET=0`.
67    #[arg(long)]
68    pub offline: bool,
69
70    /// Skip K8s upstream schemas entirely.
71    #[arg(long = "no-k8s-schemas")]
72    pub no_k8s_schemas: bool,
73}
74
75impl K8sArgs {
76    /// Resolved fallback window after applying strict mode + sanity
77    /// checks. Returns `None` when no auto-fallback should apply (either
78    /// because strict is set, the flag is absent, or `Window(0)`).
79    ///
80    /// # Errors
81    ///
82    /// Returns an error when automatic fallback is combined with more than
83    /// one explicitly configured Kubernetes version.
84    pub fn resolved_fallback_window(&self) -> Result<Option<u32>, String> {
85        if self.strict_k8s_version {
86            return Ok(None);
87        }
88        match &self.k8s_version_fallback {
89            None | Some(K8sVersionFallback::Window(0)) => Ok(None),
90            Some(K8sVersionFallback::Window(n)) => Ok(Some(*n)),
91            Some(K8sVersionFallback::Auto) => {
92                if self.k8s_version.len() != 1 {
93                    return Err(
94                        "--k8s-version-fallback=auto requires exactly one --k8s-version"
95                            .to_string(),
96                    );
97                }
98                Ok(Some(DEFAULT_AUTO_WINDOW))
99            }
100        }
101    }
102}
103
104/// Default auto-fallback reach when `--k8s-version-fallback=auto` is set.
105///
106/// Sized to cover the realistic K8s deprecation horizon: charts in the
107/// wild still ship `policy/v1beta1` (PSP / PDB) and
108/// `networking.k8s.io/v1beta1` (Ingress) — both removed in v1.25 — so
109/// a primary of the current default (`v1.35.0`) must be able to fall
110/// back at least to `v1.24.0` to find a schema. 15 leaves headroom for
111/// the next few K8s releases without churning this constant.
112pub const DEFAULT_AUTO_WINDOW: u32 = 15;