1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
use helm_schema_core::{ApiPresenceQuery, ProviderOrigin, ResourceRef, YamlPath};
use crate::diagnostic::Diagnostic;
use crate::inference::candidate::ApiVersionCandidate;
use super::provider_result::ProviderLookupResult;
use super::trace::{LookupTrace, TracedApiPresenceOutcome};
/// Provides JSON Schema fragments for Kubernetes resource fields.
///
/// Implementations typically own one source of schemas (local files,
/// upstream HTTP catalog, etc.) and delegate to shared `fetch`, `cache`,
/// and `lookup` primitives.
pub trait K8sSchemaProvider: Send + Sync + std::fmt::Debug {
/// Identifier of the layer this provider implements. Drives chain
/// precedence and origin-specific diagnostic rules.
fn origin(&self) -> ProviderOrigin;
/// Typed lookup: distinguish ownership, doc presence, and path
/// presence so the chain can attribute diagnostics correctly.
///
fn lookup(&self, resource: &ResourceRef, path: &YamlPath) -> ProviderLookupResult;
/// Cheap check for "does this provider own this resource type?".
/// MUST NOT issue network requests — providers answer from local
/// cache + per-process negative cache only.
fn has_resource(&self, resource: &ResourceRef) -> bool;
/// Contribute apiVersion candidates for a kind whose apiVersion
/// the caller couldn't pin AFTER `api_version_candidates` has been
/// exhausted. Returns ALL candidates the provider knows about; the
/// caller aggregates across providers and decides Resolved vs
/// Ambiguous. Default returns an empty list.
fn infer_api_version_candidates(&self, _kind: &str) -> Vec<ApiVersionCandidate> {
Vec::new()
}
/// Primary K8s version this provider holds (for
/// `ResolvedFromFallbackVersion`). Non-K8s providers leave the
/// default `None`.
fn primary_k8s_version(&self) -> Option<&str> {
None
}
/// Full K8s version chain (for `MissingSchema` payload). Non-K8s
/// providers leave the default `None`.
fn k8s_version_chain(&self) -> Option<Vec<String>> {
None
}
/// K8s versions *outside* the configured chain that happen to have
/// the resource's file cached. Used by the chain layer to populate
/// `Diagnostic::MissingSchema.available_in_cache_versions`. Default
/// returns empty (CRD / local-override providers don't carry a K8s
/// version concept).
fn cache_versions_holding(&self, _resource: &ResourceRef) -> Vec<String> {
Vec::new()
}
/// Provider-side diagnostics the chain should commit on a final
/// miss. Providers MUST NOT emit these themselves; the chain calls
/// this method only after exhausting all candidates and providers,
/// so speculative candidate probing in provider-schema lookup
/// never leaks per-candidate misses.
///
/// Default returns an empty list (the openapi and local-override
/// providers don't contribute miss-side diagnostics beyond what the
/// chain itself emits).
fn missing_schema_provider_diagnostics(&self, _resource: &ResourceRef) -> Vec<Diagnostic> {
Vec::new()
}
/// Authoritative answer to a typed `.Capabilities.APIVersions.Has ...`
/// query against this provider's primary K8s version.
///
/// [`ApiPresenceQuery::Resource`] probes an exact kind;
/// [`ApiPresenceQuery::GroupVersion`] asks whether the API group/version is
/// present.
///
/// Returns:
/// - `Some(true)` when the api (and kind, if specified) exists
/// in the primary K8s version's schema bundle,
/// - `Some(false)` when the bundle exists but does not contain
/// the api/kind,
/// - `None` when this provider can't answer (e.g. no primary
/// version configured, unknown probe target, fetch failure).
///
/// Cache is fetch-on-miss: when the file isn't in the local
/// cache, the provider MAY fetch from upstream to give an
/// authoritative answer. This is the upstream-first contract; the
/// cache is a speed optimisation, never the sole oracle.
///
/// Default returns `None` (providers that don't carry a K8s
/// version concept — `LocalOverride`, `DefaultCatalog` — abstain).
fn capability_has_query_at_primary_version(&self, _query: &ApiPresenceQuery) -> Option<bool> {
None
}
/// Same answer as [`Self::capability_has_query_at_primary_version`], plus
/// the executed provider-side knowledge probes.
fn capability_has_query_at_primary_version_traced(
&self,
query: &ApiPresenceQuery,
) -> TracedApiPresenceOutcome {
let answer = self.capability_has_query_at_primary_version(query);
let mut trace = LookupTrace::default();
trace.record_api_presence_provider(self.origin(), answer);
TracedApiPresenceOutcome { answer, trace }
}
}