#![allow(clippy::module_name_repetitions)]
use std::collections::BTreeMap;
use caixa_core::{
Caixa, CaixaKind, FLEET_PROGRAMS_KEY_APLICACAO, FLEET_PROGRAMS_KEY_NAME,
FLEET_PROGRAMS_KEY_VERSAO, GATEWAY_API_DEFAULT_HTTP_LISTENER_NAME,
GATEWAY_API_DEFAULT_HTTP_LISTENER_PORT, GATEWAY_API_KEY_NAME, LABEL_APLICACAO, LABEL_CONTRATO,
M3_KEY_PLACEMENT, MappingExt, SequenceExt, WitContract, WitTarget, aplicacao::AplicacaoSpec,
kube_resource_skeleton, label_selector, pleme_program_in_aplicacao_selector,
pleme_program_selector, single_field_overlay,
};
use thiserror::Error;
#[derive(Debug, Error)]
pub enum Error {
#[error("{0}")]
NotAnAplicacao(#[from] caixa_core::KindMismatch),
#[error("aplicacao typed shape violation: {0}")]
InvalidAplicacao(#[from] caixa_core::AplicacaoError),
#[error("yaml: {0}")]
Yaml(#[from] serde_yaml::Error),
}
pub fn programs_for_aplicacao(caixa: &Caixa) -> Result<Vec<serde_yaml::Value>, Error> {
let spec = typed_view(caixa)?;
let placement_value = serde_yaml::to_value(spec.placement())?;
let mut out = Vec::with_capacity(spec.membros().len());
for m in spec.membros() {
let mut entry = serde_yaml::Mapping::new();
entry.insert_string(FLEET_PROGRAMS_KEY_NAME, m.nome().to_string());
entry.insert_string(
FLEET_PROGRAMS_KEY_VERSAO,
m.versao_requirement().to_string(),
);
entry.insert_string(FLEET_PROGRAMS_KEY_APLICACAO, caixa.nome().to_string());
entry.insert_str_key(M3_KEY_PLACEMENT, placement_value.clone());
out.push_mapping(entry);
}
Ok(out)
}
pub fn typed_view(caixa: &Caixa) -> Result<AplicacaoSpec, Error> {
caixa_core::require_aplicacao_view::<Error>(caixa)
}
pub use caixa_core::DEFAULT_NAMESPACE;
pub use caixa_core::GATEWAY_API_API_VERSION;
pub use caixa_core::CILIUM_API_VERSION;
pub use caixa_core::CILIUM_KIND_NETWORK_POLICY;
pub use caixa_core::CILIUM_KEY_TO_PORTS;
pub use caixa_core::CILIUM_KEY_ENDPOINT_SELECTOR;
pub use caixa_core::CILIUM_KEY_INGRESS;
pub use caixa_core::CILIUM_KEY_FROM_ENDPOINTS;
pub use caixa_core::CILIUM_KEY_PORTS;
pub use caixa_core::CILIUM_KEY_AUTHENTICATION;
pub use caixa_core::CILIUM_KEY_MODE;
pub use caixa_core::CILIUM_AUTH_MODE_REQUIRED;
pub use caixa_core::CILIUM_AUTH_MODE_DISABLED;
pub use caixa_core::cilium_auth_mode;
pub use caixa_core::CONTRATO_EDGE_LABEL_SEPARATOR;
pub use caixa_core::contrato_edge_label;
pub use caixa_core::cilium_network_policy_name;
pub use caixa_core::gateway_api_http_route_name;
pub use caixa_core::M3_PLACEMENT_ESTRATEGIA_SINGLE_NODE;
pub use caixa_core::M3_PLACEMENT_ESTRATEGIA_REPLICATED;
pub use caixa_core::M3_PLACEMENT_ESTRATEGIA_SHARDED;
pub use caixa_core::CILIUM_KEY_HTTP;
pub use caixa_core::CILIUM_KEY_PATH;
pub use caixa_core::GATEWAY_API_KIND_GATEWAY;
pub use caixa_core::GATEWAY_API_KIND_HTTP_ROUTE;
pub use caixa_core::GATEWAY_API_PROTOCOL_HTTP;
pub use caixa_core::GATEWAY_API_PATH_MATCH_TYPE_PATH_PREFIX;
pub use caixa_core::GATEWAY_API_KEY_PARENT_REFS;
pub use caixa_core::GATEWAY_API_KEY_SECTION_NAME;
pub use caixa_core::GATEWAY_API_KEY_BACKEND_REFS;
pub use caixa_core::GATEWAY_API_KEY_MATCHES;
pub use caixa_core::GATEWAY_API_KEY_PATH;
pub use caixa_core::GATEWAY_API_KEY_VALUE;
pub use caixa_core::GATEWAY_API_KEY_LISTENERS;
pub use caixa_core::GATEWAY_API_KEY_HOSTNAME;
pub use caixa_core::GATEWAY_API_KEY_HOSTNAMES;
pub use caixa_core::KUBE_KEY_SPEC;
pub use caixa_core::DEFAULT_GATEWAY_CLASS_NAME;
pub use caixa_core::GATEWAY_API_KEY_GATEWAY_CLASS_NAME;
pub use caixa_core::KUBE_KEY_METADATA;
pub use caixa_core::KUBE_KEY_KIND;
pub use caixa_core::KUBE_KEY_API_VERSION;
pub use caixa_core::KUBE_KEY_NAMESPACE;
pub use caixa_core::KUBE_KEY_LABELS;
pub use caixa_core::KUBE_KEY_NAME;
pub use caixa_core::KUBE_KEY_MATCH_LABELS;
pub use caixa_core::KUBE_KEY_RULES;
pub use caixa_core::KUBE_KEY_PORT;
pub use caixa_core::KUBE_KEY_PROTOCOL;
pub use caixa_core::KUBE_KEY_TYPE;
pub use caixa_core::KUBE_PROTOCOL_TCP;
pub use caixa_core::GATEWAY_API_KEY_TIMEOUTS;
pub use caixa_core::GATEWAY_API_KEY_RETRY;
pub use caixa_core::GATEWAY_API_KEY_ATTEMPTS;
pub use caixa_core::GATEWAY_API_KEY_REQUEST;
pub fn cilium_network_policies(caixa: &Caixa) -> Result<Vec<serde_yaml::Value>, Error> {
let spec = typed_view(caixa)?;
let namespace = DEFAULT_NAMESPACE; let mtls_overlay = single_field_overlay(
spec.politicas().mtls_required(),
CILIUM_KEY_MODE,
|required| serde_yaml::Value::String(cilium_auth_mode(required).into()),
);
let mut groups: BTreeMap<(&str, &str), Vec<&WitContract>> = BTreeMap::new();
for c in spec.contratos() {
groups
.entry((c.source(), c.destination()))
.or_default()
.push(c);
}
let mut out = Vec::with_capacity(groups.len());
for ((de, para), edges) in &groups {
let mut labels = BTreeMap::new();
labels.insert(LABEL_APLICACAO, caixa.nome().to_string());
labels.insert(LABEL_CONTRATO, contrato_edge_label(de, para));
let mut policy = kube_resource_skeleton(
CILIUM_API_VERSION,
CILIUM_KIND_NETWORK_POLICY,
&cilium_network_policy_name(caixa.nome(), de, para),
namespace,
labels,
);
let endpoint_selector = label_selector(pleme_program_selector(para));
let from_endpoint = label_selector(pleme_program_in_aplicacao_selector(de, caixa.nome()));
let mut ingress_rule = serde_yaml::Mapping::new();
ingress_rule.insert_sequence(CILIUM_KEY_FROM_ENDPOINTS, vec![from_endpoint]);
let mut to_ports_seq = Vec::with_capacity(edges.len());
for c in edges {
let mut to_port = serde_yaml::Mapping::new();
let mut port_entry = serde_yaml::Mapping::new();
let port = spec.port_for_destination(c.destination());
port_entry.insert_string(KUBE_KEY_PORT, port.to_string());
port_entry.insert_string(KUBE_KEY_PROTOCOL, KUBE_PROTOCOL_TCP);
to_port.insert_singleton_mapping_sequence(CILIUM_KEY_PORTS, port_entry);
if let WitTarget::Http { endpoint } = c.target().expect("validated by typed_view") {
let mut http_rule = serde_yaml::Mapping::new();
http_rule.insert_string(CILIUM_KEY_PATH, endpoint.to_string());
let mut rules = serde_yaml::Mapping::new();
rules.insert_singleton_mapping_sequence(CILIUM_KEY_HTTP, http_rule);
to_port.insert_mapping(KUBE_KEY_RULES, rules);
}
to_ports_seq.push_mapping(to_port);
}
ingress_rule.insert_sequence(CILIUM_KEY_TO_PORTS, to_ports_seq);
ingress_rule.insert_str_key_if_some(CILIUM_KEY_AUTHENTICATION, mtls_overlay.as_ref());
let mut policy_spec = serde_yaml::Mapping::new();
policy_spec.insert_str_key(CILIUM_KEY_ENDPOINT_SELECTOR, endpoint_selector);
policy_spec.insert_singleton_mapping_sequence(CILIUM_KEY_INGRESS, ingress_rule);
policy.insert_mapping(KUBE_KEY_SPEC, policy_spec);
out.push_mapping(policy);
}
Ok(out)
}
pub fn gateway_routes(caixa: &Caixa) -> Result<Vec<serde_yaml::Value>, Error> {
let spec = typed_view(caixa)?;
let entrada = match spec.entrada() {
Some(e) => e,
None => return Ok(Vec::new()),
};
let namespace = DEFAULT_NAMESPACE;
let mut gateway = kube_resource_skeleton(
GATEWAY_API_API_VERSION,
GATEWAY_API_KIND_GATEWAY,
caixa.nome(),
namespace,
BTreeMap::new(),
);
let mut listener = serde_yaml::Mapping::new();
listener.insert_string(GATEWAY_API_KEY_NAME, GATEWAY_API_DEFAULT_HTTP_LISTENER_NAME);
listener.insert_number(KUBE_KEY_PORT, GATEWAY_API_DEFAULT_HTTP_LISTENER_PORT);
listener.insert_string(KUBE_KEY_PROTOCOL, GATEWAY_API_PROTOCOL_HTTP);
listener.insert_string(GATEWAY_API_KEY_HOSTNAME, entrada.hostname().to_string());
let mut g_spec = serde_yaml::Mapping::new();
g_spec.insert_string(
GATEWAY_API_KEY_GATEWAY_CLASS_NAME,
DEFAULT_GATEWAY_CLASS_NAME,
);
g_spec.insert_singleton_mapping_sequence(GATEWAY_API_KEY_LISTENERS, listener);
gateway.insert_mapping(KUBE_KEY_SPEC, g_spec);
let mut route = kube_resource_skeleton(
GATEWAY_API_API_VERSION,
GATEWAY_API_KIND_HTTP_ROUTE,
&gateway_api_http_route_name(caixa.nome(), entrada.destination()),
namespace,
BTreeMap::new(),
);
let mut parent_ref = serde_yaml::Mapping::new();
parent_ref.insert_string(GATEWAY_API_KEY_NAME, caixa.nome().to_string());
parent_ref.insert_string(
GATEWAY_API_KEY_SECTION_NAME,
GATEWAY_API_DEFAULT_HTTP_LISTENER_NAME,
);
let paths: Vec<&str> = entrada.resolved_paths();
let timeout_overlay =
single_field_overlay(spec.politicas().timeout(), GATEWAY_API_KEY_REQUEST, |d| {
serde_yaml::Value::String(caixa_core::supervisor::duration_codec::render(d))
});
let retry_overlay = single_field_overlay(
spec.politicas().retries(),
GATEWAY_API_KEY_ATTEMPTS,
|attempts| serde_yaml::Value::Number(attempts.into()),
);
let mut rules = Vec::with_capacity(paths.len());
for path in paths {
let mut path_match = serde_yaml::Mapping::new();
path_match.insert_string(KUBE_KEY_TYPE, GATEWAY_API_PATH_MATCH_TYPE_PATH_PREFIX);
path_match.insert_string(GATEWAY_API_KEY_VALUE, path.to_string());
let mut match_entry = serde_yaml::Mapping::new();
match_entry.insert_mapping(GATEWAY_API_KEY_PATH, path_match);
let mut backend_ref = serde_yaml::Mapping::new();
backend_ref.insert_string(GATEWAY_API_KEY_NAME, entrada.destination().to_string());
backend_ref.insert_number(
KUBE_KEY_PORT,
spec.port_for_destination(entrada.destination()),
);
let mut rule = serde_yaml::Mapping::new();
rule.insert_singleton_mapping_sequence(GATEWAY_API_KEY_MATCHES, match_entry);
rule.insert_singleton_mapping_sequence(GATEWAY_API_KEY_BACKEND_REFS, backend_ref);
rule.insert_str_key_if_some(GATEWAY_API_KEY_TIMEOUTS, timeout_overlay.as_ref());
rule.insert_str_key_if_some(GATEWAY_API_KEY_RETRY, retry_overlay.as_ref());
rules.push_mapping(rule);
}
let mut r_spec = serde_yaml::Mapping::new();
r_spec.insert_singleton_mapping_sequence(GATEWAY_API_KEY_PARENT_REFS, parent_ref);
r_spec.insert_sequence(
GATEWAY_API_KEY_HOSTNAMES,
entrada
.hostnames()
.into_iter()
.map(|h| serde_yaml::Value::String(h.to_string()))
.collect(),
);
r_spec.insert_sequence(KUBE_KEY_RULES, rules);
route.insert_mapping(KUBE_KEY_SPEC, r_spec);
Ok(vec![
serde_yaml::Value::Mapping(gateway),
serde_yaml::Value::Mapping(route),
])
}
pub fn render_all(caixa: &Caixa) -> Result<Vec<serde_yaml::Value>, Error> {
let mut out = Vec::new();
out.extend(programs_for_aplicacao(caixa)?);
out.extend(cilium_network_policies(caixa)?);
out.extend(gateway_routes(caixa)?);
Ok(out)
}
#[cfg(test)]
mod tests {
use super::*;
use caixa_core::{
Caixa, CaixaKind, DEFAULT_SERVICO_PORT, Entrada, GATEWAY_API_DEFAULT_HTTP_ROUTE_PATH,
LABEL_PROGRAM, M3_PLACEMENT_KEY_AFFINITY, M3_PLACEMENT_KEY_CLUSTERS,
M3_PLACEMENT_KEY_ESTRATEGIA, M3_PLACEMENT_KEY_SHARD_KEY, Membro, MeshPolicy, Placement,
PlacementStrategy, WitContract, find_by_kind, kube_kind_is, kube_metadata_str_field,
kube_root_str_field,
};
use std::time::Duration;
fn aplicacao_caixa() -> Caixa {
Caixa {
nome: "checkout".into(),
versao: "0.1.0".into(),
kind: CaixaKind::Aplicacao,
edicao: Some("2026".into()),
descricao: Some("Checkout flow.".into()),
repositorio: Some("github:pleme-io/checkout".into()),
licenca: Some("MIT".into()),
autores: vec!["pleme-io".into()],
etiquetas: vec!["checkout".into()],
deps: vec![],
deps_dev: vec![],
exe: vec![],
bibliotecas: vec![],
servicos: vec![],
limits: None,
behavior: None,
upgrade_from: vec![],
estrategia: None,
max_restarts: None,
restart_window: None,
children: vec![],
membros: vec![
Membro {
caixa: "catalog".into(),
versao: "^0.1".into(),
},
Membro {
caixa: "cart".into(),
versao: "^0.1".into(),
},
Membro {
caixa: "payment".into(),
versao: "^0.2".into(),
},
],
contratos: vec![
WitContract {
de: "cart".into(),
para: "catalog".into(),
wit: "wasi:http/proxy".into(),
endpoint: Some("/products/:id".into()),
subject: None,
slot: None,
},
WitContract {
de: "cart".into(),
para: "payment".into(),
wit: "wasi:http/proxy".into(),
endpoint: Some("/charge".into()),
subject: None,
slot: None,
},
],
politicas: Some(MeshPolicy {
timeout: Some(Duration::from_secs(30)),
retries: Some(3),
mtls_required: Some(true),
..Default::default()
}),
placement: Some(Placement {
estrategia: PlacementStrategy::Replicated,
clusters: vec!["rio".into(), "mar".into()],
affinity: Some("data-locality".into()),
shard_key: None,
}),
entrada: Some(Entrada {
host: "checkout.quero.cloud".into(),
para: "cart".into(),
paths: vec!["/api/cart".into()],
port: 8080,
}),
ci: None,
}
}
#[test]
fn default_namespace_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"DEFAULT_NAMESPACE",
DEFAULT_NAMESPACE,
caixa_core::DEFAULT_NAMESPACE,
);
}
#[test]
fn contrato_edge_label_separator_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"CONTRATO_EDGE_LABEL_SEPARATOR",
CONTRATO_EDGE_LABEL_SEPARATOR,
caixa_core::CONTRATO_EDGE_LABEL_SEPARATOR,
);
}
#[test]
fn contrato_edge_label_re_export_matches_caixa_core_canonical_output() {
assert_eq!(
contrato_edge_label("cart", "catalog"),
caixa_core::contrato_edge_label("cart", "catalog"),
);
assert_eq!(contrato_edge_label("cart", "catalog"), "cart-to-catalog");
}
#[test]
fn cilium_network_policy_name_re_export_matches_caixa_core_canonical_output() {
assert_eq!(
cilium_network_policy_name("checkout", "cart", "catalog"),
caixa_core::cilium_network_policy_name("checkout", "cart", "catalog"),
);
assert_eq!(
cilium_network_policy_name("checkout", "cart", "catalog"),
"checkout-cart-to-catalog",
);
}
#[test]
fn cilium_network_policy_metadata_name_uses_lifted_composer() {
let policies = cilium_network_policies(&aplicacao_caixa()).unwrap();
let names: Vec<String> = policies
.iter()
.map(|p| {
kube_metadata_str_field(p, KUBE_KEY_NAME)
.expect("policy metadata.name")
.to_string()
})
.collect();
assert!(
names.contains(&cilium_network_policy_name("checkout", "cart", "catalog")),
"CNP metadata.name for (cart, catalog) must match lifted composer output; \
got names {names:?}",
);
assert!(
names.contains(&cilium_network_policy_name("checkout", "cart", "payment")),
"CNP metadata.name for (cart, payment) must match lifted composer output; \
got names {names:?}",
);
}
#[test]
fn cilium_network_policy_label_contrato_value_uses_lifted_composer() {
let policies = cilium_network_policies(&aplicacao_caixa()).unwrap();
let contrato_values: Vec<String> = policies
.iter()
.filter_map(|p| {
p.get(KUBE_KEY_METADATA)
.and_then(|m| m.get(KUBE_KEY_LABELS))
.and_then(|l| l.get(LABEL_CONTRATO))
.and_then(|v| v.as_str())
.map(String::from)
})
.collect();
assert!(
contrato_values.contains(&contrato_edge_label("cart", "catalog")),
"CNP LABEL_CONTRATO value for (cart, catalog) must match lifted composer output; \
got values {contrato_values:?}",
);
assert!(
contrato_values.contains(&contrato_edge_label("cart", "payment")),
"CNP LABEL_CONTRATO value for (cart, payment) must match lifted composer output; \
got values {contrato_values:?}",
);
}
#[test]
fn gateway_api_http_route_name_re_export_matches_caixa_core_canonical_output() {
assert_eq!(
gateway_api_http_route_name("checkout", "cart"),
caixa_core::gateway_api_http_route_name("checkout", "cart"),
);
assert_eq!(
gateway_api_http_route_name("checkout", "cart"),
"checkout-cart",
);
}
#[test]
fn gateway_api_http_route_metadata_name_uses_lifted_composer() {
let docs = gateway_routes(&aplicacao_caixa()).unwrap();
let route = find_by_kind(&docs, GATEWAY_API_KIND_HTTP_ROUTE).expect("HTTPRoute present");
assert_eq!(
kube_metadata_str_field(route, KUBE_KEY_NAME),
Some(gateway_api_http_route_name("checkout", "cart").as_str()),
"HTTPRoute metadata.name must match lifted composer output",
);
}
#[test]
fn gateway_api_api_version_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"GATEWAY_API_API_VERSION",
GATEWAY_API_API_VERSION,
caixa_core::GATEWAY_API_API_VERSION,
);
}
#[test]
fn cilium_api_version_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"CILIUM_API_VERSION",
CILIUM_API_VERSION,
caixa_core::CILIUM_API_VERSION,
);
}
#[test]
fn kube_key_spec_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"KUBE_KEY_SPEC",
KUBE_KEY_SPEC,
caixa_core::KUBE_KEY_SPEC,
);
}
#[test]
fn kube_key_metadata_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"KUBE_KEY_METADATA",
KUBE_KEY_METADATA,
caixa_core::KUBE_KEY_METADATA,
);
}
#[test]
fn kube_key_kind_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"KUBE_KEY_KIND",
KUBE_KEY_KIND,
caixa_core::KUBE_KEY_KIND,
);
}
#[test]
fn kube_key_api_version_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"KUBE_KEY_API_VERSION",
KUBE_KEY_API_VERSION,
caixa_core::KUBE_KEY_API_VERSION,
);
}
#[test]
fn kube_key_namespace_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"KUBE_KEY_NAMESPACE",
KUBE_KEY_NAMESPACE,
caixa_core::KUBE_KEY_NAMESPACE,
);
}
#[test]
fn kube_key_labels_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"KUBE_KEY_LABELS",
KUBE_KEY_LABELS,
caixa_core::KUBE_KEY_LABELS,
);
}
#[test]
fn kube_key_name_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"KUBE_KEY_NAME",
KUBE_KEY_NAME,
caixa_core::KUBE_KEY_NAME,
);
}
#[test]
fn gateway_api_key_name_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"GATEWAY_API_KEY_NAME",
GATEWAY_API_KEY_NAME,
caixa_core::GATEWAY_API_KEY_NAME,
);
assert_eq!(GATEWAY_API_KEY_NAME, "name");
}
#[test]
fn kube_key_match_labels_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"KUBE_KEY_MATCH_LABELS",
KUBE_KEY_MATCH_LABELS,
caixa_core::KUBE_KEY_MATCH_LABELS,
);
}
#[test]
fn kube_key_rules_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"KUBE_KEY_RULES",
KUBE_KEY_RULES,
caixa_core::KUBE_KEY_RULES,
);
}
#[test]
fn kube_key_port_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"KUBE_KEY_PORT",
KUBE_KEY_PORT,
caixa_core::KUBE_KEY_PORT,
);
}
#[test]
fn kube_key_protocol_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"KUBE_KEY_PROTOCOL",
KUBE_KEY_PROTOCOL,
caixa_core::KUBE_KEY_PROTOCOL,
);
}
#[test]
fn kube_protocol_tcp_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"KUBE_PROTOCOL_TCP",
KUBE_PROTOCOL_TCP,
caixa_core::KUBE_PROTOCOL_TCP,
);
}
#[test]
fn cilium_port_tuple_carries_lifted_kube_protocol_tcp() {
let policies = cilium_network_policies(&aplicacao_caixa()).unwrap();
let port_tuple = policies
.first()
.and_then(|p| p.get(KUBE_KEY_SPEC))
.and_then(|s| s.get(CILIUM_KEY_INGRESS))
.and_then(|i| i.as_sequence())
.and_then(|s| s.first())
.and_then(|i| i.get(CILIUM_KEY_TO_PORTS))
.and_then(|p| p.as_sequence())
.and_then(|s| s.first())
.and_then(|tp| tp.get(CILIUM_KEY_PORTS))
.and_then(|p| p.as_sequence())
.and_then(|s| s.first())
.expect("spec.ingress[0].toPorts[0].ports[0] port-tuple");
assert_eq!(
port_tuple.get(KUBE_KEY_PROTOCOL).and_then(|v| v.as_str()),
Some(KUBE_PROTOCOL_TCP),
"per-`toPorts[].ports[]` port-tuple `protocol:` scalar must be \
the lifted `KUBE_PROTOCOL_TCP` (`\"TCP\"`) verbatim — the \
load-bearing K8s core `Protocol` OpenAPI schema enum value \
the Cilium data plane's per-tuple bpf policy dispatch loop \
compares against the observed L4 header protocol"
);
}
#[test]
fn gateway_api_key_timeouts_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"GATEWAY_API_KEY_TIMEOUTS",
GATEWAY_API_KEY_TIMEOUTS,
caixa_core::GATEWAY_API_KEY_TIMEOUTS,
);
}
#[test]
fn gateway_api_key_retry_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"GATEWAY_API_KEY_RETRY",
GATEWAY_API_KEY_RETRY,
caixa_core::GATEWAY_API_KEY_RETRY,
);
}
#[test]
fn gateway_api_key_attempts_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"GATEWAY_API_KEY_ATTEMPTS",
GATEWAY_API_KEY_ATTEMPTS,
caixa_core::GATEWAY_API_KEY_ATTEMPTS,
);
}
#[test]
fn gateway_api_key_request_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"GATEWAY_API_KEY_REQUEST",
GATEWAY_API_KEY_REQUEST,
caixa_core::GATEWAY_API_KEY_REQUEST,
);
}
#[test]
fn cilium_kind_network_policy_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"CILIUM_KIND_NETWORK_POLICY",
CILIUM_KIND_NETWORK_POLICY,
caixa_core::CILIUM_KIND_NETWORK_POLICY,
);
}
#[test]
fn cilium_key_to_ports_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"CILIUM_KEY_TO_PORTS",
CILIUM_KEY_TO_PORTS,
caixa_core::CILIUM_KEY_TO_PORTS,
);
}
#[test]
fn cilium_key_endpoint_selector_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"CILIUM_KEY_ENDPOINT_SELECTOR",
CILIUM_KEY_ENDPOINT_SELECTOR,
caixa_core::CILIUM_KEY_ENDPOINT_SELECTOR,
);
}
#[test]
fn cilium_key_ingress_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"CILIUM_KEY_INGRESS",
CILIUM_KEY_INGRESS,
caixa_core::CILIUM_KEY_INGRESS,
);
}
#[test]
fn cilium_key_from_endpoints_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"CILIUM_KEY_FROM_ENDPOINTS",
CILIUM_KEY_FROM_ENDPOINTS,
caixa_core::CILIUM_KEY_FROM_ENDPOINTS,
);
}
#[test]
fn cilium_key_ports_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"CILIUM_KEY_PORTS",
CILIUM_KEY_PORTS,
caixa_core::CILIUM_KEY_PORTS,
);
}
#[test]
fn cilium_key_authentication_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"CILIUM_KEY_AUTHENTICATION",
CILIUM_KEY_AUTHENTICATION,
caixa_core::CILIUM_KEY_AUTHENTICATION,
);
}
#[test]
fn cilium_key_mode_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"CILIUM_KEY_MODE",
CILIUM_KEY_MODE,
caixa_core::CILIUM_KEY_MODE,
);
}
#[test]
fn cilium_auth_mode_required_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"CILIUM_AUTH_MODE_REQUIRED",
CILIUM_AUTH_MODE_REQUIRED,
caixa_core::CILIUM_AUTH_MODE_REQUIRED,
);
}
#[test]
fn cilium_auth_mode_disabled_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"CILIUM_AUTH_MODE_DISABLED",
CILIUM_AUTH_MODE_DISABLED,
caixa_core::CILIUM_AUTH_MODE_DISABLED,
);
}
#[test]
fn m3_placement_estrategia_single_node_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"M3_PLACEMENT_ESTRATEGIA_SINGLE_NODE",
M3_PLACEMENT_ESTRATEGIA_SINGLE_NODE,
caixa_core::M3_PLACEMENT_ESTRATEGIA_SINGLE_NODE,
);
}
#[test]
fn m3_placement_estrategia_replicated_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"M3_PLACEMENT_ESTRATEGIA_REPLICATED",
M3_PLACEMENT_ESTRATEGIA_REPLICATED,
caixa_core::M3_PLACEMENT_ESTRATEGIA_REPLICATED,
);
}
#[test]
fn m3_placement_estrategia_sharded_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"M3_PLACEMENT_ESTRATEGIA_SHARDED",
M3_PLACEMENT_ESTRATEGIA_SHARDED,
caixa_core::M3_PLACEMENT_ESTRATEGIA_SHARDED,
);
}
#[test]
fn cilium_key_http_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"CILIUM_KEY_HTTP",
CILIUM_KEY_HTTP,
caixa_core::CILIUM_KEY_HTTP,
);
}
#[test]
fn cilium_key_path_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"CILIUM_KEY_PATH",
CILIUM_KEY_PATH,
caixa_core::CILIUM_KEY_PATH,
);
}
#[test]
fn cilium_key_path_and_gateway_api_key_path_stay_independent_axes() {
assert_eq!(CILIUM_KEY_PATH, GATEWAY_API_KEY_PATH);
assert_eq!(CILIUM_KEY_PATH, caixa_core::CILIUM_KEY_PATH);
assert_eq!(GATEWAY_API_KEY_PATH, caixa_core::GATEWAY_API_KEY_PATH);
}
#[test]
fn cilium_l7_rule_list_carries_lifted_cilium_key_http() {
let policies = cilium_network_policies(&aplicacao_caixa()).unwrap();
let rules = policies
.iter()
.find_map(|p| {
p.get(KUBE_KEY_SPEC)
.and_then(|s| s.get(CILIUM_KEY_INGRESS))
.and_then(|i| i.as_sequence())
.and_then(|s| s.first())
.and_then(|i| i.get(CILIUM_KEY_TO_PORTS))
.and_then(|p| p.as_sequence())
.and_then(|s| s.iter().find(|tp| tp.get(KUBE_KEY_RULES).is_some()))
.and_then(|tp| tp.get(KUBE_KEY_RULES))
})
.expect(
"at least one per-`toPorts[]` entry emits a `rules` \
L7-rule-list-container block on the aplicacao fixture's \
HTTP-shaped `:contratos` edges",
);
assert!(
rules.get(CILIUM_KEY_HTTP).is_some(),
"per-`toPorts[]` `rules` L7-rule-list-container must carry \
the lifted `CILIUM_KEY_HTTP` (`\"http\"`) L7-HTTP-rule-list-\
discriminator key verbatim — the load-bearing Cilium CRD \
per-`toPorts[]` L7-HTTP-rule-list-discriminator container-\
axis key the Cilium data plane's per-`toPorts[]` L7 dispatch \
pass reads to source the per-`toPorts[]` L7 URL-path-prefix \
predicate list, got rules = {rules:?}"
);
}
#[test]
fn kube_key_type_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"KUBE_KEY_TYPE",
KUBE_KEY_TYPE,
caixa_core::KUBE_KEY_TYPE,
);
}
#[test]
fn httproute_path_match_carries_lifted_kube_key_type() {
let docs = gateway_routes(&aplicacao_caixa()).unwrap();
let rules = httproute_rules(&docs);
assert!(
!rules.is_empty(),
"HTTPRoute must carry at least one rule the per-match path-\
selection-predicate discriminator scalar-key nests under"
);
for rule in &rules {
let matches = rule
.get(caixa_core::GATEWAY_API_KEY_MATCHES)
.and_then(|m| m.as_sequence())
.expect("HTTPRoute per-rule spec.rules[].matches sequence");
for m in matches {
let path = m
.get(caixa_core::GATEWAY_API_KEY_PATH)
.and_then(|p| p.as_mapping())
.expect(
"HTTPRoute per-match spec.rules[].matches[].path must be \
navigable through the lifted GATEWAY_API_KEY_PATH constant",
);
assert!(
path.get(KUBE_KEY_TYPE).is_some(),
"per-`HTTPRouteMatch` `path` block must carry \
the lifted `KUBE_KEY_TYPE` (`\"type\"`) path-\
selection-predicate discriminator scalar-key \
verbatim — the load-bearing Gateway API v1 \
HTTPPathMatch canonical discriminator-key axis \
the gateway-class-controller's per-rule L7 \
dispatch pass reads to source the path-match \
strategy, got path = {path:?}"
);
}
}
}
#[test]
fn gateway_api_kind_gateway_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"GATEWAY_API_KIND_GATEWAY",
GATEWAY_API_KIND_GATEWAY,
caixa_core::GATEWAY_API_KIND_GATEWAY,
);
}
#[test]
fn gateway_api_kind_http_route_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"GATEWAY_API_KIND_HTTP_ROUTE",
GATEWAY_API_KIND_HTTP_ROUTE,
caixa_core::GATEWAY_API_KIND_HTTP_ROUTE,
);
}
#[test]
fn gateway_api_protocol_http_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"GATEWAY_API_PROTOCOL_HTTP",
GATEWAY_API_PROTOCOL_HTTP,
caixa_core::GATEWAY_API_PROTOCOL_HTTP,
);
}
#[test]
fn gateway_api_path_match_type_path_prefix_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"GATEWAY_API_PATH_MATCH_TYPE_PATH_PREFIX",
GATEWAY_API_PATH_MATCH_TYPE_PATH_PREFIX,
caixa_core::GATEWAY_API_PATH_MATCH_TYPE_PATH_PREFIX,
);
}
#[test]
fn default_gateway_class_name_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"DEFAULT_GATEWAY_CLASS_NAME",
DEFAULT_GATEWAY_CLASS_NAME,
caixa_core::DEFAULT_GATEWAY_CLASS_NAME,
);
}
#[test]
fn gateway_api_key_gateway_class_name_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"GATEWAY_API_KEY_GATEWAY_CLASS_NAME",
GATEWAY_API_KEY_GATEWAY_CLASS_NAME,
caixa_core::GATEWAY_API_KEY_GATEWAY_CLASS_NAME,
);
}
#[test]
fn gateway_api_key_parent_refs_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"GATEWAY_API_KEY_PARENT_REFS",
GATEWAY_API_KEY_PARENT_REFS,
caixa_core::GATEWAY_API_KEY_PARENT_REFS,
);
}
#[test]
fn gateway_api_key_section_name_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"GATEWAY_API_KEY_SECTION_NAME",
GATEWAY_API_KEY_SECTION_NAME,
caixa_core::GATEWAY_API_KEY_SECTION_NAME,
);
assert_eq!(GATEWAY_API_KEY_SECTION_NAME, "sectionName");
}
#[test]
fn gateway_api_key_backend_refs_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"GATEWAY_API_KEY_BACKEND_REFS",
GATEWAY_API_KEY_BACKEND_REFS,
caixa_core::GATEWAY_API_KEY_BACKEND_REFS,
);
}
#[test]
fn gateway_api_key_matches_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"GATEWAY_API_KEY_MATCHES",
GATEWAY_API_KEY_MATCHES,
caixa_core::GATEWAY_API_KEY_MATCHES,
);
}
#[test]
fn gateway_api_key_path_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"GATEWAY_API_KEY_PATH",
GATEWAY_API_KEY_PATH,
caixa_core::GATEWAY_API_KEY_PATH,
);
}
#[test]
fn gateway_api_key_listeners_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"GATEWAY_API_KEY_LISTENERS",
GATEWAY_API_KEY_LISTENERS,
caixa_core::GATEWAY_API_KEY_LISTENERS,
);
}
#[test]
fn gateway_api_key_hostname_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"GATEWAY_API_KEY_HOSTNAME",
GATEWAY_API_KEY_HOSTNAME,
caixa_core::GATEWAY_API_KEY_HOSTNAME,
);
}
#[test]
fn gateway_api_key_hostnames_re_export_points_at_caixa_core_canonical() {
caixa_core::assert_str_reexport_identity(
"GATEWAY_API_KEY_HOSTNAMES",
GATEWAY_API_KEY_HOSTNAMES,
caixa_core::GATEWAY_API_KEY_HOSTNAMES,
);
}
#[test]
fn cilium_network_policies_use_lifted_cilium_kind_network_policy() {
let policies = cilium_network_policies(&aplicacao_caixa()).unwrap();
assert!(
!policies.is_empty(),
"the aplicacao fixture must emit at least one CiliumNetworkPolicy \
— drift here masks the lifted-uses assertion below"
);
for p in &policies {
assert_eq!(
kube_root_str_field(p, KUBE_KEY_KIND),
Some(CILIUM_KIND_NETWORK_POLICY),
"every rendered CiliumNetworkPolicy must declare the lifted \
[`CILIUM_KIND_NETWORK_POLICY`] constant on its top-level kind \
axis — drift here means the per-policy skeleton call no \
longer threads the lifted constant through"
);
}
}
#[test]
fn cilium_network_policies_use_lifted_cilium_api_version() {
let policies = cilium_network_policies(&aplicacao_caixa()).unwrap();
assert!(
!policies.is_empty(),
"the aplicacao fixture must emit at least one CiliumNetworkPolicy \
— drift here masks the lifted-uses assertion below"
);
for p in &policies {
assert_eq!(
kube_root_str_field(p, KUBE_KEY_API_VERSION),
Some(CILIUM_API_VERSION),
"every rendered CiliumNetworkPolicy must declare the lifted \
[`CILIUM_API_VERSION`] constant on its top-level apiVersion \
axis — drift here means the per-policy skeleton call no \
longer threads the lifted constant through"
);
}
}
#[test]
fn programs_for_aplicacao_emits_one_entry_per_member() {
let entries = programs_for_aplicacao(&aplicacao_caixa()).unwrap();
assert_eq!(entries.len(), 3);
let names: Vec<_> = entries
.iter()
.map(|e| {
e.get(FLEET_PROGRAMS_KEY_NAME)
.and_then(|n| n.as_str())
.unwrap()
.to_string()
})
.collect();
assert_eq!(names, vec!["catalog", "cart", "payment"]);
}
#[test]
fn programs_for_aplicacao_annotates_with_parent_nome() {
let entries = programs_for_aplicacao(&aplicacao_caixa()).unwrap();
for e in &entries {
assert_eq!(
e.get(FLEET_PROGRAMS_KEY_APLICACAO).and_then(|v| v.as_str()),
Some("checkout")
);
}
}
#[test]
fn fleet_programs_key_aplicacao_pins_canonical_value() {
assert_eq!(FLEET_PROGRAMS_KEY_APLICACAO, "aplicacao");
}
#[test]
fn fleet_programs_key_aplicacao_re_export_static_identity() {
assert!(
std::ptr::eq(
FLEET_PROGRAMS_KEY_APLICACAO.as_ptr(),
caixa_core::FLEET_PROGRAMS_KEY_APLICACAO.as_ptr(),
),
"FLEET_PROGRAMS_KEY_APLICACAO must resolve to the canonical \
caixa_core::FLEET_PROGRAMS_KEY_APLICACAO static, not a sibling \
`pub const` — the aggregator/emitter drift footgun the lift closes."
);
}
#[test]
fn fleet_programs_key_versao_pins_canonical_value() {
assert_eq!(FLEET_PROGRAMS_KEY_VERSAO, "versao");
}
#[test]
fn fleet_programs_key_versao_re_export_static_identity() {
assert!(
std::ptr::eq(
FLEET_PROGRAMS_KEY_VERSAO.as_ptr(),
caixa_core::FLEET_PROGRAMS_KEY_VERSAO.as_ptr(),
),
"FLEET_PROGRAMS_KEY_VERSAO must resolve to the canonical \
caixa_core::FLEET_PROGRAMS_KEY_VERSAO static, not a sibling \
`pub const` — the resolver/emitter drift footgun the lift closes."
);
}
#[test]
fn programs_for_aplicacao_carries_lifted_fleet_programs_key_versao() {
let entries = programs_for_aplicacao(&aplicacao_caixa()).unwrap();
let versoes: Vec<_> = entries
.iter()
.map(|e| {
e.get(FLEET_PROGRAMS_KEY_VERSAO)
.and_then(|v| v.as_str())
.unwrap()
.to_string()
})
.collect();
assert_eq!(versoes, vec!["^0.1", "^0.1", "^0.2"]);
}
#[test]
fn programs_for_aplicacao_entry_name_routes_through_membro_nome_accessor() {
let c = aplicacao_caixa();
let membros = &c
.aplicacao_view()
.expect("Aplicacao view for fixture")
.membros;
let entries = programs_for_aplicacao(&c).unwrap();
assert_eq!(entries.len(), membros.len());
for (m, entry) in membros.iter().zip(entries.iter()) {
let emitted = entry
.get(FLEET_PROGRAMS_KEY_NAME)
.and_then(|v| v.as_str())
.expect("programs.yaml entry carries name: as a string");
assert_eq!(
emitted,
m.nome(),
"programs.yaml entry `name:` must byte-equal Membro::nome() — \
emit path must route through the typed accessor, not the \
raw `.caixa` field"
);
}
}
#[test]
fn programs_for_aplicacao_entry_versao_routes_through_membro_versao_requirement_accessor() {
let c = aplicacao_caixa();
let membros = &c
.aplicacao_view()
.expect("Aplicacao view for fixture")
.membros;
let entries = programs_for_aplicacao(&c).unwrap();
assert_eq!(entries.len(), membros.len());
for (m, entry) in membros.iter().zip(entries.iter()) {
let emitted = entry
.get(FLEET_PROGRAMS_KEY_VERSAO)
.and_then(|v| v.as_str())
.expect("programs.yaml entry carries versao: as a string");
assert_eq!(
emitted,
m.versao_requirement(),
"programs.yaml entry `versao:` must byte-equal \
Membro::versao_requirement() — emit path must route \
through the typed accessor, not the raw `.versao` field"
);
}
}
#[test]
fn programs_for_aplicacao_entry_aplicacao_routes_through_caixa_nome_accessor() {
let c = aplicacao_caixa();
let entries = programs_for_aplicacao(&c).unwrap();
assert!(!entries.is_empty());
for entry in &entries {
let emitted = entry
.get(FLEET_PROGRAMS_KEY_APLICACAO)
.and_then(|v| v.as_str())
.expect("programs.yaml entry carries aplicacao: as a string");
assert_eq!(
emitted,
c.nome(),
"programs.yaml entry `aplicacao:` must byte-equal \
Caixa::nome() — emit path must route through the typed \
accessor, not the raw `.nome` field"
);
}
}
#[test]
fn cilium_network_policies_label_aplicacao_routes_through_caixa_nome_accessor() {
let c = aplicacao_caixa();
let policies = cilium_network_policies(&c).unwrap();
assert!(!policies.is_empty());
for policy in &policies {
let emitted = policy
.get(KUBE_KEY_METADATA)
.and_then(|m| m.get(KUBE_KEY_LABELS))
.and_then(|l| l.get(LABEL_APLICACAO))
.and_then(|v| v.as_str())
.expect("CNP metadata.labels carries LABEL_APLICACAO as a string");
assert_eq!(
emitted,
c.nome(),
"CNP `metadata.labels.{LABEL_APLICACAO}` must byte-equal \
Caixa::nome() — emit path must route through the typed \
accessor, not the raw `.nome` field"
);
}
}
#[test]
fn gateway_routes_parent_ref_name_routes_through_caixa_nome_accessor() {
let c = aplicacao_caixa();
let routes = gateway_routes(&c).unwrap();
let route = routes
.iter()
.find(|r| {
r.get(KUBE_KEY_KIND)
.and_then(|k| k.as_str())
.is_some_and(|k| k == GATEWAY_API_KIND_HTTP_ROUTE)
})
.expect("gateway_routes emits at least one HTTPRoute for the fixture Aplicacao");
let emitted = route
.get(KUBE_KEY_SPEC)
.and_then(|s| s.get(GATEWAY_API_KEY_PARENT_REFS))
.and_then(|p| p.as_sequence())
.and_then(|s| s.first())
.and_then(|p| p.get(GATEWAY_API_KEY_NAME))
.and_then(|v| v.as_str())
.expect("HTTPRoute spec.parentRefs[0].name is a string");
assert_eq!(
emitted,
c.nome(),
"HTTPRoute `spec.parentRefs[0].{GATEWAY_API_KEY_NAME}` must \
byte-equal Caixa::nome() — emit path must route through the \
typed accessor, not the raw `.nome` field"
);
}
#[test]
fn cilium_network_policy_metadata_name_routes_through_caixa_nome_accessor() {
let c = aplicacao_caixa();
let policies = cilium_network_policies(&c).unwrap();
assert!(!policies.is_empty());
for policy in &policies {
let emitted = kube_metadata_str_field(policy, KUBE_KEY_NAME)
.expect("CNP metadata.name scalar present");
let stripped = emitted
.strip_prefix(&format!("{}-", c.nome()))
.expect("CNP metadata.name carries the accessor-derived aplicacao prefix");
let (de, para) = stripped
.split_once(CONTRATO_EDGE_LABEL_SEPARATOR)
.expect("CNP metadata.name carries the canonical `-to-` edge separator");
assert_eq!(
emitted,
cilium_network_policy_name(c.nome(), de, para),
"CNP `metadata.name` must derive from the typed \
`caixa_core::Caixa::nome` accessor through \
`caixa_core::cilium_network_policy_name` byte-for-byte \
— a regression that re-inlines \
`cilium_network_policy_name(&caixa.nome, de, para)` at \
the emit site silently splits the per-CNP \
`metadata.name` axis (the operator-side `kubectl -n \
tatara-system get cnp <aplicacao>-<de>-to-<para>` \
grep-by-name lookup key) from every future accessor \
extension that lands on the accessor"
);
}
}
#[test]
fn cilium_network_policy_from_endpoints_aplicacao_scope_routes_through_caixa_nome_accessor() {
let c = aplicacao_caixa();
let policies = cilium_network_policies(&c).unwrap();
assert!(!policies.is_empty());
for policy in &policies {
let selector = policy
.get(KUBE_KEY_SPEC)
.and_then(|s| s.get(CILIUM_KEY_INGRESS))
.and_then(|i| i.as_sequence())
.and_then(|s| s.first())
.and_then(|i| i.get(CILIUM_KEY_FROM_ENDPOINTS))
.and_then(|e| e.as_sequence())
.and_then(|s| s.first())
.and_then(|e| e.get(KUBE_KEY_MATCH_LABELS))
.and_then(|m| m.as_mapping())
.expect("CNP spec.ingress[0].fromEndpoints[0].matchLabels mapping present");
let emitted = selector
.get(LABEL_APLICACAO)
.and_then(|v| v.as_str())
.expect("fromEndpoints selector carries LABEL_APLICACAO as a string");
assert_eq!(
emitted,
c.nome(),
"CNP `spec.ingress[0].fromEndpoints[0].matchLabels.{LABEL_APLICACAO}` \
must byte-equal Caixa::nome() — emit path must route \
through the typed accessor, not the raw `.nome` field, \
so a future accessor extension that rewrites the \
parent-Aplicacao identity reaches this aplicacao-scope \
axis by construction and preserves the load-bearing \
safety property that a same-named program in a \
different Aplicacao cannot satisfy the ingress rule"
);
}
}
#[test]
fn gateway_routes_gateway_metadata_name_routes_through_caixa_nome_accessor() {
let c = aplicacao_caixa();
let docs = gateway_routes(&c).unwrap();
let gateway = find_by_kind(&docs, GATEWAY_API_KIND_GATEWAY)
.expect("Gateway present under a `:entrada`-carrying fixture Aplicacao");
let emitted = kube_metadata_str_field(gateway, KUBE_KEY_NAME)
.expect("Gateway metadata.name scalar present");
assert_eq!(
emitted,
c.nome(),
"Gateway `metadata.name` must derive from the typed \
`caixa_core::Caixa::nome` accessor byte-for-byte — a \
regression that re-inlines \
`kube_resource_skeleton(..., &caixa.nome, ...)` at the emit \
site silently splits the Gateway `metadata.name` axis (the \
operator-side `kubectl -n tatara-system get gateway \
<aplicacao>` grep-by-name lookup key and the peer sibling \
HTTPRoute `spec.parentRefs[0].name` binding) from every \
future accessor extension that lands on the accessor"
);
}
#[test]
fn gateway_routes_httproute_metadata_name_routes_through_caixa_nome_accessor() {
let c = aplicacao_caixa();
let docs = gateway_routes(&c).unwrap();
let route = find_by_kind(&docs, GATEWAY_API_KIND_HTTP_ROUTE)
.expect("HTTPRoute present under a `:entrada`-carrying fixture Aplicacao");
let emitted = kube_metadata_str_field(route, KUBE_KEY_NAME)
.expect("HTTPRoute metadata.name scalar present");
let entrada = c
.entrada
.as_ref()
.expect("aplicacao_caixa carries a typed `:entrada` block");
assert_eq!(
emitted,
gateway_api_http_route_name(c.nome(), entrada.destination()),
"HTTPRoute `metadata.name` must derive from the typed \
`caixa_core::Caixa::nome` accessor through \
`caixa_core::gateway_api_http_route_name` byte-for-byte — \
a regression that re-inlines \
`gateway_api_http_route_name(&caixa.nome, \
entrada.destination())` at the emit site silently splits \
the per-HTTPRoute `metadata.name` axis (the operator-side \
`kubectl -n tatara-system get httproute \
<aplicacao>-<destination>` grep-by-name lookup key) from \
every future accessor extension that lands on the accessor"
);
}
#[test]
fn programs_for_aplicacao_rejects_non_aplicacao_kinds() {
let mut c = aplicacao_caixa();
c.kind = CaixaKind::Servico;
c.servicos = vec!["servicos/x.computeunit.yaml".into()];
let err = programs_for_aplicacao(&c).unwrap_err();
assert!(matches!(err, Error::NotAnAplicacao(_)));
}
#[test]
fn kind_mismatch_error_names_offending_caixa_nome() {
let mut c = aplicacao_caixa();
c.kind = CaixaKind::Servico;
c.servicos = vec!["servicos/x.computeunit.yaml".into()];
let err = programs_for_aplicacao(&c).unwrap_err();
let msg = format!("{err}");
assert!(
msg.contains("checkout"),
"kind-mismatch diagnostic must name the offending caixa nome \
(got: {msg:?})"
);
assert!(
msg.contains("Aplicacao"),
"diagnostic must name the expected kind (got: {msg:?})"
);
assert!(
msg.contains("Servico"),
"diagnostic must name the actual kind (got: {msg:?})"
);
}
#[test]
fn typed_view_kind_mismatch_names_offending_caixa_nome() {
let mut c = aplicacao_caixa();
c.kind = CaixaKind::Supervisor;
c.servicos = vec![];
c.children = vec![];
let err = typed_view(&c).unwrap_err();
let msg = format!("{err}");
assert!(
msg.contains("checkout"),
"typed_view's kind-mismatch must also name the caixa nome \
(got: {msg:?})"
);
match err {
Error::NotAnAplicacao(km) => {
assert_eq!(km.nome, "checkout");
assert_eq!(km.expected, CaixaKind::Aplicacao);
assert_eq!(km.actual, CaixaKind::Supervisor);
}
other => panic!("expected Error::NotAnAplicacao, got {other:?}"),
}
}
#[test]
fn programs_for_aplicacao_validates_typed_shape() {
let mut c = aplicacao_caixa();
c.contratos.push(WitContract {
de: "cart".into(),
para: "phantom".into(),
wit: "wasi:http/proxy".into(),
endpoint: Some("/x".into()),
subject: None,
slot: None,
});
let err = programs_for_aplicacao(&c).unwrap_err();
assert!(matches!(err, Error::InvalidAplicacao(_)));
}
#[test]
fn programs_for_aplicacao_routes_entry_gate_through_typed_view() {
let mut c = aplicacao_caixa();
c.contratos.push(WitContract {
de: "cart".into(),
para: "phantom".into(),
wit: "wasi:http/proxy".into(),
endpoint: Some("/x".into()),
subject: None,
slot: None,
});
let programs_err = programs_for_aplicacao(&c).unwrap_err();
let typed_view_err = typed_view(&c).unwrap_err();
assert_eq!(
format!("{programs_err}"),
format!("{typed_view_err}"),
"programs_for_aplicacao must surface the same entry-gate \
diagnostic as typed_view — a divergence here means the \
renderer skipped the shared cascade"
);
assert!(
matches!(programs_err, Error::InvalidAplicacao(_)),
"programs_for_aplicacao must surface the AplicacaoSpec::validate \
failure through the same Error::InvalidAplicacao variant \
typed_view raises"
);
assert!(
matches!(typed_view_err, Error::InvalidAplicacao(_)),
"typed_view must raise the same variant so a future divergence \
on either path is a compile-time signal, not a silent \
renderer-side drift"
);
}
#[test]
fn programs_for_aplicacao_kind_mismatch_matches_typed_view() {
let mut c = aplicacao_caixa();
c.kind = CaixaKind::Supervisor;
c.servicos = vec![];
c.children = vec![];
let programs_err = programs_for_aplicacao(&c).unwrap_err();
let typed_view_err = typed_view(&c).unwrap_err();
assert_eq!(
format!("{programs_err}"),
format!("{typed_view_err}"),
"programs_for_aplicacao and typed_view must agree on the \
kind-mismatch diagnostic — divergence indicates one path \
skipped the shared `require_kind` gate"
);
}
#[test]
fn typed_view_routes_through_caixa_core_require_aplicacao_view_helper() {
let ok_cases: Vec<Caixa> = vec![aplicacao_caixa()];
for c in ok_cases {
let via_wrapper = typed_view(&c).expect("valid aplicacao passes typed_view");
let via_primitive = caixa_core::require_aplicacao_view::<Error>(&c)
.expect("valid aplicacao passes require_aplicacao_view");
assert_eq!(
serde_yaml::to_string(&via_wrapper).expect("typed_view spec serializes"),
serde_yaml::to_string(&via_primitive)
.expect("require_aplicacao_view spec serializes"),
"typed_view's Ok-arm AplicacaoSpec must equal \
caixa_core::require_aplicacao_view's Ok-arm AplicacaoSpec \
byte-for-byte on the same fixture — otherwise typed_view \
has drifted from the substrate primitive"
);
}
let mut c = aplicacao_caixa();
c.kind = CaixaKind::Supervisor;
c.servicos = vec![];
c.children = vec![];
let wrapper_err = typed_view(&c).unwrap_err();
let primitive_err = caixa_core::require_aplicacao_view::<Error>(&c).unwrap_err();
assert_eq!(
format!("{wrapper_err}"),
format!("{primitive_err}"),
"typed_view's kind-mismatch Display bytes must equal \
caixa_core::require_aplicacao_view's kind-mismatch Display \
bytes — a future format edit lands in exactly one place \
(caixa-core::render), not duplicated across every \
per-Aplicacao renderer"
);
assert!(
matches!(wrapper_err, Error::NotAnAplicacao(_)),
"typed_view must forward the KindMismatch through the \
Error::NotAnAplicacao #[from] arm"
);
assert!(
matches!(primitive_err, Error::NotAnAplicacao(_)),
"caixa_core::require_aplicacao_view must forward the \
KindMismatch through the Error::NotAnAplicacao #[from] arm \
— same discipline as the sibling require_v0_servico_shape \
`E: From<KindMismatch>` bound"
);
let mut c = aplicacao_caixa();
c.contratos.push(WitContract {
de: "cart".into(),
para: "phantom".into(),
wit: "wasi:http/proxy".into(),
endpoint: Some("/x".into()),
subject: None,
slot: None,
});
let wrapper_err = typed_view(&c).unwrap_err();
let primitive_err = caixa_core::require_aplicacao_view::<Error>(&c).unwrap_err();
assert_eq!(
format!("{wrapper_err}"),
format!("{primitive_err}"),
"typed_view's invalid-aplicacao Display bytes must equal \
caixa_core::require_aplicacao_view's invalid-aplicacao \
Display bytes on the same non-member `:contratos :para` \
fixture"
);
assert!(
matches!(wrapper_err, Error::InvalidAplicacao(_)),
"typed_view must forward the AplicacaoError through the \
Error::InvalidAplicacao #[from] arm"
);
assert!(
matches!(primitive_err, Error::InvalidAplicacao(_)),
"caixa_core::require_aplicacao_view must forward the \
AplicacaoError through the Error::InvalidAplicacao \
#[from] arm"
);
}
fn placement_blocks(entries: &[serde_yaml::Value]) -> Vec<&serde_yaml::Mapping> {
entries
.iter()
.map(|e| {
e.get(M3_KEY_PLACEMENT)
.and_then(|p| p.as_mapping())
.expect("every member entry must carry a placement mapping")
})
.collect()
}
#[test]
fn programs_entry_carries_placement_block() {
let entries = programs_for_aplicacao(&aplicacao_caixa()).unwrap();
assert!(!entries.is_empty());
for e in &entries {
assert!(
e.get(M3_KEY_PLACEMENT).is_some(),
"every member entry must carry a `placement:` block"
);
}
}
#[test]
fn programs_entry_placement_carries_strategy() {
let entries = programs_for_aplicacao(&aplicacao_caixa()).unwrap();
for p in placement_blocks(&entries) {
assert_eq!(
p.get(M3_PLACEMENT_KEY_ESTRATEGIA).and_then(|v| v.as_str()),
Some(M3_PLACEMENT_ESTRATEGIA_REPLICATED),
"placement.estrategia must round-trip the typed PlacementStrategy variant"
);
}
}
#[test]
fn programs_entry_placement_carries_clusters_list() {
let entries = programs_for_aplicacao(&aplicacao_caixa()).unwrap();
for p in placement_blocks(&entries) {
let clusters = p
.get(M3_PLACEMENT_KEY_CLUSTERS)
.and_then(|c| c.as_sequence())
.expect("placement.clusters sequence");
let names: Vec<&str> = clusters.iter().filter_map(|v| v.as_str()).collect();
assert_eq!(names, vec!["rio", "mar"]);
}
}
#[test]
fn programs_entry_placement_carries_affinity_when_set() {
let entries = programs_for_aplicacao(&aplicacao_caixa()).unwrap();
for p in placement_blocks(&entries) {
assert_eq!(
p.get(M3_PLACEMENT_KEY_AFFINITY).and_then(|v| v.as_str()),
Some("data-locality")
);
}
}
#[test]
fn programs_entry_placement_omits_affinity_and_shard_key_when_unset() {
let mut c = aplicacao_caixa();
if let Some(p) = c.placement.as_mut() {
p.affinity = None;
p.shard_key = None;
}
let entries = programs_for_aplicacao(&c).unwrap();
for p in placement_blocks(&entries) {
assert!(
p.get(M3_PLACEMENT_KEY_AFFINITY).is_none(),
"placement.affinity must be absent when :affinity is None"
);
assert!(
p.get(M3_PLACEMENT_KEY_SHARD_KEY).is_none(),
"placement.shardKey must be absent when :shard-key is None"
);
assert_eq!(p.len(), 2);
}
}
#[test]
fn programs_entry_placement_carries_shard_key_when_sharded() {
let mut c = aplicacao_caixa();
if let Some(p) = c.placement.as_mut() {
p.estrategia = PlacementStrategy::Sharded;
p.shard_key = Some("$tenantId".into());
}
let entries = programs_for_aplicacao(&c).unwrap();
for p in placement_blocks(&entries) {
assert_eq!(
p.get(M3_PLACEMENT_KEY_ESTRATEGIA).and_then(|v| v.as_str()),
Some(M3_PLACEMENT_ESTRATEGIA_SHARDED)
);
assert_eq!(
p.get(M3_PLACEMENT_KEY_SHARD_KEY).and_then(|v| v.as_str()),
Some("$tenantId")
);
}
}
#[test]
fn programs_entry_placement_appears_on_every_member() {
let entries = programs_for_aplicacao(&aplicacao_caixa()).unwrap();
assert_eq!(entries.len(), 3);
let placements = placement_blocks(&entries);
assert_eq!(placements.len(), 3);
let first = placements[0];
for p in &placements[1..] {
assert_eq!(
p.get(M3_PLACEMENT_KEY_ESTRATEGIA),
first.get(M3_PLACEMENT_KEY_ESTRATEGIA),
"placement.estrategia must be identical across all members"
);
assert_eq!(
p.get(M3_PLACEMENT_KEY_CLUSTERS),
first.get(M3_PLACEMENT_KEY_CLUSTERS),
"placement.clusters must be identical across all members"
);
}
}
#[test]
fn programs_entry_placement_uses_lifted_canonical_key() {
assert_eq!(M3_KEY_PLACEMENT, "placement");
let entries = programs_for_aplicacao(&aplicacao_caixa()).unwrap();
for e in &entries {
let m = e.as_mapping().expect("entry mapping");
assert!(
m.contains_key(M3_KEY_PLACEMENT),
"entry must carry the M3_KEY_PLACEMENT key exactly"
);
}
}
#[test]
fn m3_placement_key_estrategia_pins_canonical_value() {
assert_eq!(M3_PLACEMENT_KEY_ESTRATEGIA, "estrategia");
}
#[test]
fn m3_placement_key_estrategia_matches_placement_serde_derive() {
let placement = Placement {
estrategia: PlacementStrategy::Replicated,
clusters: vec!["rio".to_string(), "mar".to_string()],
affinity: None,
shard_key: None,
};
let value = serde_yaml::to_value(&placement).expect("serialize Placement");
let mapping = value
.as_mapping()
.expect("Placement serializes to a mapping");
assert!(
mapping.contains_key(M3_PLACEMENT_KEY_ESTRATEGIA),
"Placement's serde derive must emit the estrategia axis under the exact key \
the lifted M3_PLACEMENT_KEY_ESTRATEGIA const carries; got mapping keys: {keys:?}",
keys = mapping
.keys()
.filter_map(|k| k.as_str().map(str::to_string))
.collect::<Vec<_>>()
);
}
#[test]
fn m3_placement_key_clusters_pins_canonical_value() {
assert_eq!(M3_PLACEMENT_KEY_CLUSTERS, "clusters");
}
#[test]
fn m3_placement_key_clusters_matches_placement_serde_derive() {
let placement = Placement {
estrategia: PlacementStrategy::Replicated,
clusters: vec!["rio".to_string(), "mar".to_string()],
affinity: None,
shard_key: None,
};
let value = serde_yaml::to_value(&placement).expect("serialize Placement");
let mapping = value
.as_mapping()
.expect("Placement serializes to a mapping");
assert!(
mapping.contains_key(M3_PLACEMENT_KEY_CLUSTERS),
"Placement's serde derive must emit the clusters axis under the exact key \
the lifted M3_PLACEMENT_KEY_CLUSTERS const carries; got mapping keys: {keys:?}",
keys = mapping
.keys()
.filter_map(|k| k.as_str().map(str::to_string))
.collect::<Vec<_>>()
);
}
#[test]
fn m3_placement_key_affinity_pins_canonical_value() {
assert_eq!(M3_PLACEMENT_KEY_AFFINITY, "affinity");
}
#[test]
fn m3_placement_key_affinity_matches_placement_serde_derive() {
let placement = Placement {
estrategia: PlacementStrategy::Replicated,
clusters: vec!["rio".to_string(), "mar".to_string()],
affinity: Some("data-locality".to_string()),
shard_key: None,
};
let value = serde_yaml::to_value(&placement).expect("serialize Placement");
let mapping = value
.as_mapping()
.expect("Placement serializes to a mapping");
assert!(
mapping.contains_key(M3_PLACEMENT_KEY_AFFINITY),
"Placement's serde derive must emit the affinity axis under the exact key \
the lifted M3_PLACEMENT_KEY_AFFINITY const carries when the typed slot \
resolves to `Some(_)`; got mapping keys: {keys:?}",
keys = mapping
.keys()
.filter_map(|k| k.as_str().map(str::to_string))
.collect::<Vec<_>>()
);
}
#[test]
fn m3_placement_key_shard_key_pins_canonical_value() {
assert_eq!(M3_PLACEMENT_KEY_SHARD_KEY, "shardKey");
}
#[test]
fn m3_placement_key_shard_key_matches_placement_serde_derive() {
let placement = Placement {
estrategia: PlacementStrategy::Sharded,
clusters: vec!["rio".to_string(), "mar".to_string()],
affinity: None,
shard_key: Some("$tenantId".to_string()),
};
let value = serde_yaml::to_value(&placement).expect("serialize Placement");
let mapping = value
.as_mapping()
.expect("Placement serializes to a mapping");
assert!(
mapping.contains_key(M3_PLACEMENT_KEY_SHARD_KEY),
"Placement's serde derive must emit the shard_key axis under the exact key \
the lifted M3_PLACEMENT_KEY_SHARD_KEY const carries when the typed slot \
resolves to `Some(_)`; got mapping keys: {keys:?}",
keys = mapping
.keys()
.filter_map(|k| k.as_str().map(str::to_string))
.collect::<Vec<_>>()
);
}
#[test]
fn typed_view_returns_validated_spec() {
let spec = typed_view(&aplicacao_caixa()).unwrap();
assert_eq!(spec.membros().len(), 3);
assert_eq!(spec.contratos().len(), 2);
assert!(spec.entrada().is_some());
assert_eq!(spec.placement().clusters().len(), 2);
}
#[test]
fn cilium_emits_one_policy_per_de_para_pair() {
let policies = cilium_network_policies(&aplicacao_caixa()).unwrap();
assert_eq!(policies.len(), 2);
let names: Vec<_> = policies
.iter()
.map(|p| {
kube_metadata_str_field(p, KUBE_KEY_NAME)
.unwrap()
.to_string()
})
.collect();
assert!(names.contains(&"checkout-cart-to-catalog".to_string()));
assert!(names.contains(&"checkout-cart-to-payment".to_string()));
}
#[test]
fn cilium_fans_same_de_para_edges_into_one_policy() {
let mut c = aplicacao_caixa();
c.contratos.push(WitContract {
de: "cart".into(),
para: "catalog".into(),
wit: "wasi:http/proxy".into(),
endpoint: Some("/search".into()),
subject: None,
slot: None,
});
let policies = cilium_network_policies(&c).unwrap();
let cart_to_catalog: Vec<_> = policies
.iter()
.filter(|p| {
kube_metadata_str_field(p, KUBE_KEY_NAME) == Some("checkout-cart-to-catalog")
})
.collect();
assert_eq!(
cart_to_catalog.len(),
1,
"two cart→catalog contratos must fan into one policy, not two \
colliding `checkout-cart-to-catalog` objects"
);
let to_ports = cart_to_catalog[0]
.get(KUBE_KEY_SPEC)
.and_then(|s| s.get(CILIUM_KEY_INGRESS))
.and_then(|i| i.as_sequence())
.and_then(|s| s.first())
.and_then(|i| i.get(CILIUM_KEY_TO_PORTS))
.and_then(|p| p.as_sequence())
.expect("ingress[0].toPorts sequence");
assert_eq!(
to_ports.len(),
2,
"each typed edge in the (cart, catalog) group contributes one toPorts entry"
);
let paths: Vec<&str> = to_ports
.iter()
.filter_map(|tp| {
tp.get(KUBE_KEY_RULES)
.and_then(|r| r.get(CILIUM_KEY_HTTP))
.and_then(|h| h.as_sequence())
.and_then(|s| s.first())
.and_then(|rule| rule.get(CILIUM_KEY_PATH))
.and_then(|v| v.as_str())
})
.collect();
assert!(
paths.contains(&"/products/:id") && paths.contains(&"/search"),
"both edges' L7 paths must survive the fan-in, got {paths:?}"
);
}
#[test]
fn cilium_policies_are_identity_based() {
let policies = cilium_network_policies(&aplicacao_caixa()).unwrap();
for p in &policies {
let endpoint = p
.get(KUBE_KEY_SPEC)
.and_then(|s| s.get(CILIUM_KEY_ENDPOINT_SELECTOR))
.and_then(|e| e.get(KUBE_KEY_MATCH_LABELS))
.unwrap();
assert!(endpoint.get(LABEL_PROGRAM).is_some());
let from = p
.get(KUBE_KEY_SPEC)
.and_then(|s| s.get(CILIUM_KEY_INGRESS))
.and_then(|i| i.as_sequence())
.and_then(|s| s.first())
.and_then(|i| i.get(CILIUM_KEY_FROM_ENDPOINTS))
.and_then(|e| e.as_sequence())
.and_then(|s| s.first())
.and_then(|e| e.get(KUBE_KEY_MATCH_LABELS))
.unwrap();
assert_eq!(
from.get(LABEL_APLICACAO).and_then(|v| v.as_str()),
Some("checkout")
);
let from_program = from.get(LABEL_PROGRAM).and_then(|v| v.as_str()).unwrap();
assert!(
from_program == "cart" || from_program == "payment",
"fromEndpoints.matchLabels.{LABEL_PROGRAM} = {from_program:?} \
must name the source caixa of one of the fixture's two contratos"
);
}
}
#[test]
fn cilium_policy_metadata_labels_use_lifted_consts() {
let policies = cilium_network_policies(&aplicacao_caixa()).unwrap();
for p in &policies {
let labels = p
.get(KUBE_KEY_METADATA)
.and_then(|m| m.get(KUBE_KEY_LABELS))
.and_then(|l| l.as_mapping())
.expect("policy metadata.labels mapping");
assert_eq!(
labels.get(LABEL_APLICACAO).and_then(|v| v.as_str()),
Some("checkout")
);
let contrato_val = labels
.get(LABEL_CONTRATO)
.and_then(|v| v.as_str())
.expect("contrato label present");
assert!(
contrato_val.starts_with("cart-to-"),
"contrato label {contrato_val:?} must follow `<de>-to-<para>` shape"
);
for (k, _) in labels {
if let Some(s) = k.as_str() {
if s.starts_with(caixa_core::PLEME_LABEL_PREFIX) {
assert!(
s == LABEL_APLICACAO || s == LABEL_CONTRATO,
"policy metadata.labels carries unexpected pleme-prefixed key {s:?} \
(only LABEL_APLICACAO + LABEL_CONTRATO are canonical here)"
);
}
}
}
}
}
#[test]
fn cilium_endpoint_selector_is_program_only() {
let policies = cilium_network_policies(&aplicacao_caixa()).unwrap();
for p in &policies {
let selector = p
.get(KUBE_KEY_SPEC)
.and_then(|s| s.get(CILIUM_KEY_ENDPOINT_SELECTOR))
.and_then(|e| e.get(KUBE_KEY_MATCH_LABELS))
.and_then(|m| m.as_mapping())
.expect("endpointSelector.matchLabels mapping");
assert_eq!(
selector.len(),
1,
"destination endpointSelector must be the program-only selector"
);
assert!(selector.get(LABEL_PROGRAM).is_some());
}
}
#[test]
fn cilium_from_endpoints_carries_aplicacao_scoped_selector() {
let policies = cilium_network_policies(&aplicacao_caixa()).unwrap();
for p in &policies {
let from = p
.get(KUBE_KEY_SPEC)
.and_then(|s| s.get(CILIUM_KEY_INGRESS))
.and_then(|i| i.as_sequence())
.and_then(|s| s.first())
.and_then(|i| i.get(CILIUM_KEY_FROM_ENDPOINTS))
.and_then(|e| e.as_sequence())
.and_then(|s| s.first())
.and_then(|e| e.get(KUBE_KEY_MATCH_LABELS))
.and_then(|m| m.as_mapping())
.expect("fromEndpoints[0].matchLabels mapping");
assert_eq!(
from.len(),
2,
"source fromEndpoints must be the program-in-aplicacao selector (2 axes)"
);
assert!(from.get(LABEL_PROGRAM).is_some());
assert!(from.get(LABEL_APLICACAO).is_some());
}
}
#[test]
fn cilium_http_contracts_emit_l7_rules() {
let policies = cilium_network_policies(&aplicacao_caixa()).unwrap();
let cart_to_catalog = policies
.iter()
.find(|p| kube_metadata_str_field(p, KUBE_KEY_NAME) == Some("checkout-cart-to-catalog"))
.unwrap();
let http_rules = cart_to_catalog
.get(KUBE_KEY_SPEC)
.and_then(|s| s.get(CILIUM_KEY_INGRESS))
.and_then(|i| i.as_sequence())
.and_then(|s| s.first())
.and_then(|i| i.get(CILIUM_KEY_TO_PORTS))
.and_then(|p| p.as_sequence())
.and_then(|s| s.first())
.and_then(|p| p.get(KUBE_KEY_RULES))
.and_then(|r| r.get(CILIUM_KEY_HTTP))
.and_then(|h| h.as_sequence())
.unwrap();
assert_eq!(http_rules.len(), 1);
assert_eq!(
http_rules[0].get(CILIUM_KEY_PATH).and_then(|v| v.as_str()),
Some("/products/:id")
);
}
#[test]
fn cilium_pubsub_contracts_skip_l7_rules() {
let mut c = aplicacao_caixa();
c.contratos.push(WitContract {
de: "payment".into(),
para: "cart".into(), wit: "nats:pub-sub".into(),
endpoint: None,
subject: Some("checkout.events.charge.failed".into()),
slot: None,
});
let policies = cilium_network_policies(&c).unwrap();
let nats_policy = policies
.iter()
.find(|p| kube_metadata_str_field(p, KUBE_KEY_NAME) == Some("checkout-payment-to-cart"))
.unwrap();
let to_ports = nats_policy
.get(KUBE_KEY_SPEC)
.and_then(|s| s.get(CILIUM_KEY_INGRESS))
.and_then(|i| i.as_sequence())
.and_then(|s| s.first())
.and_then(|i| i.get(CILIUM_KEY_TO_PORTS))
.and_then(|p| p.as_sequence())
.and_then(|s| s.first())
.unwrap();
assert!(to_ports.get(CILIUM_KEY_PORTS).is_some());
assert!(to_ports.get(KUBE_KEY_RULES).is_none());
}
#[test]
fn gateway_emits_gateway_plus_httproute_pair() {
let docs = gateway_routes(&aplicacao_caixa()).unwrap();
assert_eq!(docs.len(), 2);
let kinds: Vec<_> = docs
.iter()
.map(|d| {
d.get(KUBE_KEY_KIND)
.and_then(|k| k.as_str())
.unwrap()
.to_string()
})
.collect();
assert!(kinds.contains(&GATEWAY_API_KIND_GATEWAY.to_string()));
assert!(kinds.contains(&GATEWAY_API_KIND_HTTP_ROUTE.to_string()));
}
#[test]
fn gateway_listener_carries_aplicacao_host() {
let docs = gateway_routes(&aplicacao_caixa()).unwrap();
let gateway = find_by_kind(&docs, GATEWAY_API_KIND_GATEWAY).unwrap();
let listener = gateway
.get(KUBE_KEY_SPEC)
.and_then(|s| s.get(GATEWAY_API_KEY_LISTENERS))
.and_then(|l| l.as_sequence())
.and_then(|s| s.first())
.unwrap();
assert_eq!(
listener
.get(GATEWAY_API_KEY_HOSTNAME)
.and_then(|h| h.as_str()),
Some("checkout.quero.cloud")
);
assert_eq!(
listener.get(KUBE_KEY_PROTOCOL).and_then(|p| p.as_str()),
Some(GATEWAY_API_PROTOCOL_HTTP)
);
}
#[test]
fn gateway_listener_name_routes_through_lifted_default_http_listener_name() {
let docs = gateway_routes(&aplicacao_caixa()).unwrap();
let gateway = find_by_kind(&docs, GATEWAY_API_KIND_GATEWAY).expect("Gateway present");
let listener = gateway
.get(KUBE_KEY_SPEC)
.and_then(|s| s.get(GATEWAY_API_KEY_LISTENERS))
.and_then(|l| l.as_sequence())
.and_then(|s| s.first())
.expect("first listener present");
assert_eq!(
listener.get(GATEWAY_API_KEY_NAME).and_then(|n| n.as_str()),
Some(GATEWAY_API_DEFAULT_HTTP_LISTENER_NAME),
"the Gateway per-listener name-discriminator scalar must render \
the lifted GATEWAY_API_DEFAULT_HTTP_LISTENER_NAME constant \
verbatim — drift here means the constant lift no longer reaches \
this consumer and every downstream HTTPRoute `sectionName` \
selector authored against the substrate's canonical name would \
miss its listener at attachment time"
);
}
#[test]
fn httproute_parent_ref_pins_section_name_to_lifted_default_http_listener_name() {
let docs = gateway_routes(&aplicacao_caixa()).unwrap();
let route = find_by_kind(&docs, GATEWAY_API_KIND_HTTP_ROUTE).expect("HTTPRoute present");
let parent = route
.get(KUBE_KEY_SPEC)
.and_then(|s| s.get(GATEWAY_API_KEY_PARENT_REFS))
.and_then(|p| p.as_sequence())
.and_then(|s| s.first())
.expect("first parentRef present");
assert_eq!(
parent
.get(GATEWAY_API_KEY_SECTION_NAME)
.and_then(|n| n.as_str()),
Some(GATEWAY_API_DEFAULT_HTTP_LISTENER_NAME),
"the HTTPRoute per-parentRef listener-selector scalar must \
render the lifted GATEWAY_API_DEFAULT_HTTP_LISTENER_NAME \
constant verbatim — the Gateway listener-name emitter and \
this sectionName selector must move as a unit through one \
canonical caixa-core `&'static str`, else a future \
listener-name rebrand silently splits the per-listener \
identity pair and the emitted route reverts to the Gateway \
API v1 attach-to-every-listener default fan-out"
);
}
#[test]
fn gateway_listener_port_routes_through_lifted_default_http_listener_port() {
let docs = gateway_routes(&aplicacao_caixa()).unwrap();
let gateway = find_by_kind(&docs, GATEWAY_API_KIND_GATEWAY).expect("Gateway present");
let listener = gateway
.get(KUBE_KEY_SPEC)
.and_then(|s| s.get(GATEWAY_API_KEY_LISTENERS))
.and_then(|l| l.as_sequence())
.and_then(|s| s.first())
.expect("first listener present");
assert_eq!(
listener.get(KUBE_KEY_PORT).and_then(|p| p.as_u64()),
Some(u64::from(GATEWAY_API_DEFAULT_HTTP_LISTENER_PORT)),
"the Gateway per-listener HTTP-listener-port scalar must render \
the lifted GATEWAY_API_DEFAULT_HTTP_LISTENER_PORT constant \
verbatim — drift here means the constant lift no longer reaches \
this consumer"
);
}
#[test]
fn httproute_catch_all_path_routes_through_lifted_default_http_route_path() {
let mut caixa = aplicacao_caixa();
caixa.entrada.as_mut().unwrap().paths = Vec::new();
let docs = gateway_routes(&caixa).unwrap();
let route = find_by_kind(&docs, GATEWAY_API_KIND_HTTP_ROUTE).expect("HTTPRoute present");
let match_path_value = route
.get(KUBE_KEY_SPEC)
.and_then(|s| s.get(KUBE_KEY_RULES))
.and_then(|r| r.as_sequence())
.and_then(|s| s.first())
.and_then(|r| r.get(GATEWAY_API_KEY_MATCHES))
.and_then(|m| m.as_sequence())
.and_then(|s| s.first())
.and_then(|m| m.get(GATEWAY_API_KEY_PATH))
.and_then(|p| p.get(GATEWAY_API_KEY_VALUE))
.and_then(|v| v.as_str())
.expect("HTTPRoute rules[0].matches[0].path.value present");
assert_eq!(
match_path_value, GATEWAY_API_DEFAULT_HTTP_ROUTE_PATH,
"the HTTPRoute empty-`:entrada :paths` catch-all URL-path scalar \
must render the lifted GATEWAY_API_DEFAULT_HTTP_ROUTE_PATH \
constant verbatim — drift here means the constant lift no longer \
reaches this consumer and every external `:entrada` HTTP flow \
authored against a Servico with no per-path rule surface would \
drop at the first hop with no diagnostic naming the catch-all-path \
drift root cause"
);
}
#[test]
fn httproute_path_list_routes_through_lifted_entrada_resolved_paths() {
for paths in [
vec![],
vec!["/api/cart".to_string(), "/api/products".to_string()],
vec!["/only".to_string()],
] {
let mut caixa = aplicacao_caixa();
let expected: Vec<String> = caixa
.entrada
.as_mut()
.map(|e| {
e.paths.clone_from(&paths);
e.resolved_paths().iter().map(|&s| s.to_string()).collect()
})
.expect("aplicacao_caixa carries a typed `:entrada` block");
let docs = gateway_routes(&caixa).unwrap();
let route = find_by_kind(&docs, GATEWAY_API_KIND_HTTP_ROUTE)
.expect("HTTPRoute present under every :entrada permutation");
let rules = route
.get(KUBE_KEY_SPEC)
.and_then(|s| s.get(KUBE_KEY_RULES))
.and_then(|r| r.as_sequence())
.expect("HTTPRoute.spec.rules[] present");
let emitted: Vec<String> = rules
.iter()
.map(|r| {
r.get(GATEWAY_API_KEY_MATCHES)
.and_then(|m| m.as_sequence())
.and_then(|s| s.first())
.and_then(|m| m.get(GATEWAY_API_KEY_PATH))
.and_then(|p| p.get(GATEWAY_API_KEY_VALUE))
.and_then(|v| v.as_str())
.expect("each HTTPRoute rule carries a matches[0].path.value scalar")
.to_string()
})
.collect();
assert_eq!(
emitted, expected,
"HTTPRoute per-rule path list must render \
`Entrada::resolved_paths()` verbatim (in author-\
declared order for the non-empty arm, as the lifted \
catch-all singleton for the empty arm) — drift here \
means the emitter no longer routes through the \
substrate-primitive typed dispatch and a future \
resolver axis (:default-path override, per-cluster \
overlay) would silently disagree between caixa-core \
and caixa-mesh on which paths a given `:entrada` \
block resolves to. Input paths: {paths:?}"
);
}
}
#[test]
fn gateway_listener_hostname_routes_through_lifted_entrada_hostname() {
for host in ["checkout.quero.cloud", "shop.pleme.dev", "app.example.io"] {
let mut caixa = aplicacao_caixa();
let expected = caixa
.entrada
.as_mut()
.map(|e| {
e.host = host.into();
e.hostname().to_string()
})
.expect("aplicacao_caixa carries a typed `:entrada` block");
let docs = gateway_routes(&caixa).unwrap();
let gateway = find_by_kind(&docs, GATEWAY_API_KIND_GATEWAY)
.expect("Gateway present under every :entrada permutation");
let listener = gateway
.get(KUBE_KEY_SPEC)
.and_then(|s| s.get(GATEWAY_API_KEY_LISTENERS))
.and_then(|l| l.as_sequence())
.and_then(|s| s.first())
.expect("first listener present");
let emitted = listener
.get(GATEWAY_API_KEY_HOSTNAME)
.and_then(|h| h.as_str())
.expect("Gateway listener carries a hostname scalar");
assert_eq!(
emitted, expected,
"Gateway per-listener singular `hostname:` scalar must \
render `Entrada::hostname()` verbatim — drift here \
means the emitter no longer routes through the \
substrate-primitive typed dispatch and a future \
hostname-resolution axis (per-cluster :alt-hosts \
overlay, SNI fan-out) would silently disagree with \
the plural sibling. Input host: {host:?}"
);
}
}
#[test]
fn httproute_hostnames_routes_through_lifted_entrada_hostnames() {
for host in ["checkout.quero.cloud", "shop.pleme.dev", "app.example.io"] {
let mut caixa = aplicacao_caixa();
let expected: Vec<String> = caixa
.entrada
.as_mut()
.map(|e| {
e.host = host.into();
e.hostnames().into_iter().map(String::from).collect()
})
.expect("aplicacao_caixa carries a typed `:entrada` block");
let docs = gateway_routes(&caixa).unwrap();
let route = find_by_kind(&docs, GATEWAY_API_KIND_HTTP_ROUTE)
.expect("HTTPRoute present under every :entrada permutation");
let hostnames = route
.get(KUBE_KEY_SPEC)
.and_then(|s| s.get(GATEWAY_API_KEY_HOSTNAMES))
.and_then(|h| h.as_sequence())
.expect("HTTPRoute.spec.hostnames[] present");
let emitted: Vec<String> = hostnames
.iter()
.map(|v| {
v.as_str()
.expect("each HTTPRoute.spec.hostnames[] entry is a scalar string")
.to_string()
})
.collect();
assert_eq!(
emitted, expected,
"HTTPRoute per-route plural `spec.hostnames[]` list \
must render `Entrada::hostnames()` verbatim — drift \
here means the emitter no longer routes through the \
substrate-primitive typed dispatch and a future \
hostname-resolution axis (per-cluster :alt-hosts \
overlay, SNI fan-out) would silently disagree \
between caixa-core and caixa-mesh on which hostname \
set a given `:entrada` block resolves to. Input \
host: {host:?}"
);
}
}
#[test]
fn gateway_listener_hostname_and_httproute_hostnames_pair_invariant_at_emit_site() {
let docs = gateway_routes(&aplicacao_caixa()).unwrap();
let gateway = find_by_kind(&docs, GATEWAY_API_KIND_GATEWAY).expect("Gateway present");
let listener_hostname = gateway
.get(KUBE_KEY_SPEC)
.and_then(|s| s.get(GATEWAY_API_KEY_LISTENERS))
.and_then(|l| l.as_sequence())
.and_then(|s| s.first())
.and_then(|l| l.get(GATEWAY_API_KEY_HOSTNAME))
.and_then(|h| h.as_str())
.expect("Gateway listener carries a hostname scalar")
.to_string();
let route = find_by_kind(&docs, GATEWAY_API_KIND_HTTP_ROUTE).expect("HTTPRoute present");
let route_hostnames: Vec<String> = route
.get(KUBE_KEY_SPEC)
.and_then(|s| s.get(GATEWAY_API_KEY_HOSTNAMES))
.and_then(|h| h.as_sequence())
.expect("HTTPRoute.spec.hostnames[] present")
.iter()
.map(|v| {
v.as_str()
.expect("each HTTPRoute.spec.hostnames[] entry is a scalar string")
.to_string()
})
.collect();
assert_eq!(
route_hostnames,
vec![listener_hostname.clone()],
"The Gateway listener singular `hostname:` filter and the \
HTTPRoute plural `spec.hostnames[]` filter list must \
project as the pair `hostnames == vec![hostname]` at the \
gateway_routes emit site — Gateway API v1.x conformance \
requires the HTTPRoute's hostname filter to intersect \
the parent listener's hostname; drift breaks that at \
cluster-apply time. Emitted listener_hostname: {:?}, \
route_hostnames: {:?}",
listener_hostname,
route_hostnames,
);
}
#[test]
fn httproute_name_composer_destination_arg_routes_through_lifted_entrada_destination() {
for para in ["cart", "catalog", "payment"] {
let mut caixa = aplicacao_caixa();
let nome = caixa.nome().to_string();
let (expected_composed_name, expected_destination) = {
let entrada = caixa
.entrada
.as_mut()
.expect("aplicacao_caixa carries a typed `:entrada` block");
entrada.para = para.into();
(
gateway_api_http_route_name(&nome, entrada.destination()),
entrada.destination().to_string(),
)
};
let docs = gateway_routes(&caixa).unwrap();
let route = find_by_kind(&docs, GATEWAY_API_KIND_HTTP_ROUTE)
.expect("HTTPRoute present under every :entrada :para permutation");
let emitted = kube_metadata_str_field(route, KUBE_KEY_NAME)
.expect("HTTPRoute metadata.name scalar present");
assert_eq!(
emitted, expected_composed_name,
"HTTPRoute `metadata.name` must equal \
`gateway_api_http_route_name(caixa.nome, \
entrada.destination())` verbatim — drift means the \
composer no longer routes through the substrate-\
primitive typed dispatch. Input :entrada :para: \
{para:?}, expected destination: {expected_destination:?}"
);
}
}
#[test]
fn httproute_backend_ref_name_routes_through_lifted_entrada_destination() {
for para in ["cart", "catalog", "payment"] {
let mut caixa = aplicacao_caixa();
let expected = {
let entrada = caixa
.entrada
.as_mut()
.expect("aplicacao_caixa carries a typed `:entrada` block");
entrada.para = para.into();
entrada.destination().to_string()
};
let docs = gateway_routes(&caixa).unwrap();
let route = find_by_kind(&docs, GATEWAY_API_KIND_HTTP_ROUTE)
.expect("HTTPRoute present under every :entrada :para permutation");
let backend = route
.get(KUBE_KEY_SPEC)
.and_then(|s| s.get(KUBE_KEY_RULES))
.and_then(|r| r.as_sequence())
.and_then(|s| s.first())
.and_then(|r| r.get(GATEWAY_API_KEY_BACKEND_REFS))
.and_then(|b| b.as_sequence())
.and_then(|s| s.first())
.expect("first HTTPRoute rule's first backendRef present");
let emitted = backend
.get(GATEWAY_API_KEY_NAME)
.and_then(|n| n.as_str())
.expect("backendRef name scalar present");
assert_eq!(
emitted, expected,
"HTTPRoute per-rule `backendRefs[0].name` must render \
`Entrada::destination()` verbatim — drift here means \
the emitter no longer routes through the substrate-\
primitive typed dispatch and the per-rule backend \
would silently disagree with the `metadata.name` \
discriminator on which destination Servico the \
ingress fronts. Input :entrada :para: {para:?}"
);
}
}
#[test]
fn httproute_name_and_backend_ref_name_destination_pair_invariant_at_emit_site() {
let caixa = aplicacao_caixa();
let docs = gateway_routes(&caixa).unwrap();
let route = find_by_kind(&docs, GATEWAY_API_KIND_HTTP_ROUTE).expect("HTTPRoute present");
let route_name = kube_metadata_str_field(route, KUBE_KEY_NAME)
.expect("HTTPRoute metadata.name scalar present")
.to_string();
let backend_name = route
.get(KUBE_KEY_SPEC)
.and_then(|s| s.get(KUBE_KEY_RULES))
.and_then(|r| r.as_sequence())
.and_then(|s| s.first())
.and_then(|r| r.get(GATEWAY_API_KEY_BACKEND_REFS))
.and_then(|b| b.as_sequence())
.and_then(|s| s.first())
.and_then(|b| b.get(GATEWAY_API_KEY_NAME))
.and_then(|n| n.as_str())
.expect("first HTTPRoute rule's first backendRef.name scalar present")
.to_string();
assert_eq!(
route_name,
gateway_api_http_route_name(caixa.nome(), &backend_name),
"The HTTPRoute `metadata.name` discriminator and the per-\
rule `backendRefs[0].name` axis must project as the pair \
`metadata.name == gateway_api_http_route_name(caixa.nome, \
backendRefs[0].name)` at the gateway_routes emit site — \
Gateway API v1.x conformance requires the operator-side \
`kubectl get httproute -n <namespace> <aplicacao>-<destination>` \
grep-by-name lookup and the per-rule backend service reach \
to name the same destination Servico; drift breaks that \
lookup encoding at cluster-apply time. Emitted route_name: \
{route_name:?}, backend_name: {backend_name:?}"
);
}
#[test]
fn httproute_backend_ref_port_routes_through_lifted_port_for_destination_resolver() {
for (para, port) in [
("cart", 8080u16),
("catalog", 8443u16),
("payment", 9090u16),
] {
let mut caixa = aplicacao_caixa();
let expected_port = {
let entrada = caixa
.entrada
.as_mut()
.expect("aplicacao_caixa carries a typed `:entrada` block");
entrada.para = para.into();
entrada.port = port;
let spec =
typed_view(&caixa).expect("aplicacao_caixa fixture must be a valid Aplicacao");
let entrada_ref = spec.entrada().expect("entrada present in spec");
spec.port_for_destination(entrada_ref.destination())
};
let docs = gateway_routes(&caixa).unwrap();
let route = find_by_kind(&docs, GATEWAY_API_KIND_HTTP_ROUTE)
.expect("HTTPRoute present under every :entrada :para permutation");
let emitted_port = route
.get(KUBE_KEY_SPEC)
.and_then(|s| s.get(KUBE_KEY_RULES))
.and_then(|r| r.as_sequence())
.and_then(|s| s.first())
.and_then(|r| r.get(GATEWAY_API_KEY_BACKEND_REFS))
.and_then(|b| b.as_sequence())
.and_then(|s| s.first())
.and_then(|b| b.get(KUBE_KEY_PORT))
.and_then(|p| p.as_u64())
.expect("first HTTPRoute rule's first backendRef.port scalar present");
assert_eq!(
emitted_port,
u64::from(expected_port),
"HTTPRoute per-rule `backendRefs[0].port` must render \
`AplicacaoSpec::port_for_destination(entrada.destination())` \
verbatim — drift here means the emitter no longer routes \
through the substrate-primitive typed dispatch and the \
per-rule backend port would silently disagree with the \
peer CNP L4 whitelist port on which destination Servico's \
listener the ingress fronts. Input :entrada :para: \
{para:?}, :entrada :port: {port}"
);
}
}
#[test]
fn httproute_backend_ref_port_and_cnp_l4_port_share_port_for_destination_resolver_at_emit_site()
{
let caixa = aplicacao_caixa();
let spec = typed_view(&caixa).expect("aplicacao_caixa fixture must be a valid Aplicacao");
let apex_destination = spec
.entrada()
.expect("aplicacao_caixa carries a typed `:entrada` block")
.destination()
.to_string();
let expected_port = spec.port_for_destination(&apex_destination);
let gateway_docs = gateway_routes(&caixa).unwrap();
let route =
find_by_kind(&gateway_docs, GATEWAY_API_KIND_HTTP_ROUTE).expect("HTTPRoute present");
let httproute_port = route
.get(KUBE_KEY_SPEC)
.and_then(|s| s.get(KUBE_KEY_RULES))
.and_then(|r| r.as_sequence())
.and_then(|s| s.first())
.and_then(|r| r.get(GATEWAY_API_KEY_BACKEND_REFS))
.and_then(|b| b.as_sequence())
.and_then(|s| s.first())
.and_then(|b| b.get(KUBE_KEY_PORT))
.and_then(|p| p.as_u64())
.expect("HTTPRoute backendRef.port scalar present");
assert_eq!(
httproute_port,
u64::from(expected_port),
"HTTPRoute `backendRefs[0].port` must equal \
`spec.port_for_destination(entrada.destination())` at the \
gateway_routes emit site — this is one half of the two-\
renderer pair-invariant on the per-destination Servico L4 \
port axis."
);
let policies = cilium_network_policies(&caixa).unwrap();
for policy in &policies {
let cnp_name = kube_metadata_str_field(policy, KUBE_KEY_NAME)
.expect("every CNP has a metadata.name")
.to_string();
let Some(destination) = cnp_name.split("-to-").nth(1) else {
continue;
};
let cnp_port = policy
.get(KUBE_KEY_SPEC)
.and_then(|s| s.get(CILIUM_KEY_INGRESS))
.and_then(|i| i.as_sequence())
.and_then(|s| s.first())
.and_then(|i| i.get(CILIUM_KEY_TO_PORTS))
.and_then(|t| t.as_sequence())
.and_then(|s| s.first())
.and_then(|tp| tp.get(CILIUM_KEY_PORTS))
.and_then(|p| p.as_sequence())
.and_then(|s| s.first())
.and_then(|p| p.get(KUBE_KEY_PORT))
.and_then(|v| v.as_str())
.expect("CNP toPorts[0].ports[0].port present");
assert_eq!(
cnp_port,
spec.port_for_destination(destination).to_string(),
"CNP {cnp_name:?} toPorts[0].ports[0].port must equal \
`spec.port_for_destination({destination:?})` — drift here \
means the CNP emit-side path re-inlined the port \
resolution rule and would silently disagree with the \
HTTPRoute peer on the shared destination Servico's \
listener port."
);
}
}
#[test]
fn httproute_routes_to_entrada_para() {
let docs = gateway_routes(&aplicacao_caixa()).unwrap();
let route = find_by_kind(&docs, GATEWAY_API_KIND_HTTP_ROUTE).unwrap();
let backend = route
.get(KUBE_KEY_SPEC)
.and_then(|s| s.get(KUBE_KEY_RULES))
.and_then(|r| r.as_sequence())
.and_then(|s| s.first())
.and_then(|r| r.get(GATEWAY_API_KEY_BACKEND_REFS))
.and_then(|b| b.as_sequence())
.and_then(|s| s.first())
.unwrap();
assert_eq!(
backend.get(GATEWAY_API_KEY_NAME).and_then(|n| n.as_str()),
Some("cart")
);
assert_eq!(
backend.get(KUBE_KEY_PORT).and_then(|p| p.as_u64()),
Some(8080)
);
}
#[test]
fn gateway_skips_when_no_entrada() {
let mut c = aplicacao_caixa();
c.entrada = None;
let docs = gateway_routes(&c).unwrap();
assert!(docs.is_empty());
}
#[test]
fn cilium_policy_carries_canonical_kube_skeleton() {
let policies = cilium_network_policies(&aplicacao_caixa()).unwrap();
for p in &policies {
assert_eq!(
kube_root_str_field(p, KUBE_KEY_API_VERSION),
Some("cilium.io/v2")
);
assert_eq!(
kube_root_str_field(p, KUBE_KEY_KIND),
Some(CILIUM_KIND_NETWORK_POLICY)
);
let metadata = p
.get(KUBE_KEY_METADATA)
.and_then(|m| m.as_mapping())
.expect("metadata mapping");
assert_eq!(metadata.len(), 3);
assert!(
metadata
.get(KUBE_KEY_NAME)
.and_then(|v| v.as_str())
.is_some()
);
assert_eq!(
metadata.get(KUBE_KEY_NAMESPACE).and_then(|v| v.as_str()),
Some(DEFAULT_NAMESPACE)
);
assert!(metadata.get(KUBE_KEY_LABELS).is_some());
}
}
#[test]
fn gateway_carries_canonical_kube_skeleton_without_labels() {
let docs = gateway_routes(&aplicacao_caixa()).unwrap();
let gateway = find_by_kind(&docs, GATEWAY_API_KIND_GATEWAY).expect("Gateway present");
assert_eq!(
kube_root_str_field(gateway, KUBE_KEY_API_VERSION),
Some("gateway.networking.k8s.io/v1")
);
let metadata = gateway
.get(KUBE_KEY_METADATA)
.and_then(|m| m.as_mapping())
.expect("metadata mapping");
assert_eq!(metadata.len(), 2);
assert_eq!(
metadata.get(KUBE_KEY_NAME).and_then(|v| v.as_str()),
Some("checkout")
);
assert_eq!(
metadata.get(KUBE_KEY_NAMESPACE).and_then(|v| v.as_str()),
Some(DEFAULT_NAMESPACE)
);
assert!(
metadata.get(KUBE_KEY_LABELS).is_none(),
"Gateway must not carry metadata.labels (empty-labels-skip \
contract from kube_resource_skeleton)"
);
}
#[test]
fn httproute_carries_canonical_kube_skeleton_without_labels() {
let docs = gateway_routes(&aplicacao_caixa()).unwrap();
let route = find_by_kind(&docs, GATEWAY_API_KIND_HTTP_ROUTE).expect("HTTPRoute present");
assert_eq!(
kube_root_str_field(route, KUBE_KEY_API_VERSION),
Some("gateway.networking.k8s.io/v1")
);
let metadata = route
.get(KUBE_KEY_METADATA)
.and_then(|m| m.as_mapping())
.expect("metadata mapping");
assert_eq!(metadata.len(), 2);
assert_eq!(
metadata.get(KUBE_KEY_NAME).and_then(|v| v.as_str()),
Some(gateway_api_http_route_name("checkout", "cart").as_str())
);
assert!(metadata.get(KUBE_KEY_LABELS).is_none());
}
#[test]
fn gateway_routes_gateway_uses_lifted_gateway_api_api_version() {
let docs = gateway_routes(&aplicacao_caixa()).unwrap();
let gateway = find_by_kind(&docs, GATEWAY_API_KIND_GATEWAY).expect("Gateway present");
assert_eq!(
kube_root_str_field(gateway, KUBE_KEY_API_VERSION),
Some(caixa_core::GATEWAY_API_API_VERSION),
"Gateway's top-level apiVersion must equal the lifted \
caixa_core::GATEWAY_API_API_VERSION by value — drift here \
is the canonical footgun this lift closes"
);
}
#[test]
fn gateway_routes_gateway_uses_lifted_gateway_api_kind_gateway() {
let docs = gateway_routes(&aplicacao_caixa()).unwrap();
let gateway = find_by_kind(&docs, GATEWAY_API_KIND_GATEWAY).expect("Gateway present");
assert_eq!(
kube_root_str_field(gateway, KUBE_KEY_KIND),
Some(caixa_core::GATEWAY_API_KIND_GATEWAY),
"Gateway's top-level kind must equal the lifted \
caixa_core::GATEWAY_API_KIND_GATEWAY by value — drift here \
is the canonical footgun this lift closes"
);
}
#[test]
fn gateway_routes_httproute_uses_lifted_gateway_api_kind_http_route() {
let docs = gateway_routes(&aplicacao_caixa()).unwrap();
let route = find_by_kind(&docs, GATEWAY_API_KIND_HTTP_ROUTE).expect("HTTPRoute present");
assert_eq!(
kube_root_str_field(route, KUBE_KEY_KIND),
Some(caixa_core::GATEWAY_API_KIND_HTTP_ROUTE),
"HTTPRoute's top-level kind must equal the lifted \
caixa_core::GATEWAY_API_KIND_HTTP_ROUTE by value — drift here \
is the canonical footgun this lift closes"
);
}
#[test]
fn gateway_routes_httproute_uses_lifted_gateway_api_api_version() {
let docs = gateway_routes(&aplicacao_caixa()).unwrap();
let route = find_by_kind(&docs, GATEWAY_API_KIND_HTTP_ROUTE).expect("HTTPRoute present");
assert_eq!(
kube_root_str_field(route, KUBE_KEY_API_VERSION),
Some(caixa_core::GATEWAY_API_API_VERSION),
"HTTPRoute's top-level apiVersion must equal the lifted \
caixa_core::GATEWAY_API_API_VERSION by value — drift here \
is the canonical footgun this lift closes"
);
}
#[test]
fn gateway_gateway_class_name_uses_lifted_default_gateway_class_name() {
let docs = gateway_routes(&aplicacao_caixa()).unwrap();
let gateway = find_by_kind(&docs, GATEWAY_API_KIND_GATEWAY).expect("Gateway present");
let class_name = gateway
.get(KUBE_KEY_SPEC)
.and_then(|s| s.get(GATEWAY_API_KEY_GATEWAY_CLASS_NAME))
.and_then(|c| c.as_str())
.expect("Gateway spec.gatewayClassName present");
assert_eq!(
class_name,
caixa_core::DEFAULT_GATEWAY_CLASS_NAME,
"Gateway's spec.gatewayClassName must equal the lifted \
caixa_core::DEFAULT_GATEWAY_CLASS_NAME by value — drift here \
is the canonical footgun this lift closes"
);
}
#[test]
fn gateway_routes_gateway_uses_lifted_gateway_api_key_gateway_class_name() {
let docs = gateway_routes(&aplicacao_caixa()).unwrap();
let gateway = find_by_kind(&docs, GATEWAY_API_KIND_GATEWAY).expect("Gateway present");
let spec = gateway
.get(KUBE_KEY_SPEC)
.and_then(|s| s.as_mapping())
.expect("Gateway spec is a mapping");
assert!(
spec.contains_key(caixa_core::GATEWAY_API_KEY_GATEWAY_CLASS_NAME),
"Gateway spec must carry a key byte-identical to the lifted \
caixa_core::GATEWAY_API_KEY_GATEWAY_CLASS_NAME — drift here \
is the canonical footgun this lift closes"
);
}
#[test]
fn gateway_routes_httproute_uses_lifted_gateway_api_key_hostnames() {
let docs = gateway_routes(&aplicacao_caixa()).unwrap();
let route = find_by_kind(&docs, GATEWAY_API_KIND_HTTP_ROUTE).expect("HTTPRoute present");
let hostnames = route
.get(KUBE_KEY_SPEC)
.and_then(|s| s.get(caixa_core::GATEWAY_API_KEY_HOSTNAMES))
.and_then(|h| h.as_sequence())
.expect("HTTPRoute spec.hostnames must be navigable through the lifted constant");
assert_eq!(
hostnames.len(),
1,
"HTTPRoute spec.hostnames must carry exactly one entry — the \
typed `:entrada :host` seed"
);
assert_eq!(
hostnames[0].as_str(),
Some("checkout.quero.cloud"),
"HTTPRoute spec.hostnames[0] must carry the Aplicacao's \
`:entrada :host` slot — the same seed the sibling per-`Gateway` \
per-listener `hostname` axis threads through"
);
}
#[test]
fn gateway_routes_httproute_uses_lifted_gateway_api_key_matches() {
let docs = gateway_routes(&aplicacao_caixa()).unwrap();
let rules = httproute_rules(&docs);
assert!(
!rules.is_empty(),
"HTTPRoute must carry at least one rule the per-rule route-match \
axis nests under"
);
for rule in &rules {
let matches = rule
.get(caixa_core::GATEWAY_API_KEY_MATCHES)
.and_then(|m| m.as_sequence())
.expect(
"HTTPRoute per-rule spec.rules[].matches must be navigable \
through the lifted constant",
);
assert!(
!matches.is_empty(),
"per-rule matches sequence must carry at least one entry — the \
typed `:entrada :paths` seed",
);
}
}
#[test]
fn gateway_routes_httproute_uses_lifted_gateway_api_key_path() {
let docs = gateway_routes(&aplicacao_caixa()).unwrap();
let rules = httproute_rules(&docs);
assert!(
!rules.is_empty(),
"HTTPRoute must carry at least one rule the per-match path-matcher \
axis nests under"
);
for rule in &rules {
let matches = rule
.get(caixa_core::GATEWAY_API_KEY_MATCHES)
.and_then(|m| m.as_sequence())
.expect("HTTPRoute per-rule spec.rules[].matches sequence");
assert!(
!matches.is_empty(),
"per-rule matches sequence must carry at least one entry — the \
typed `:entrada :paths` seed the per-match path-matcher axis \
nests under",
);
for m in matches {
let path = m
.get(caixa_core::GATEWAY_API_KEY_PATH)
.and_then(|p| p.as_mapping())
.expect(
"HTTPRoute per-match spec.rules[].matches[].path must be \
navigable through the lifted constant",
);
assert!(
!path.is_empty(),
"per-match path-matcher mapping must carry the typed \
`{{type, value}}` path-selection predicate — the Gateway \
API v1 HTTPRouteMatch canonical path shape",
);
}
}
}
#[test]
fn cilium_policy_metadata_block_iterates_alphabetically() {
let policies = cilium_network_policies(&aplicacao_caixa()).unwrap();
for p in &policies {
let metadata = p
.get(KUBE_KEY_METADATA)
.and_then(|m| m.as_mapping())
.expect("metadata mapping");
let keys: Vec<&str> = metadata.iter().filter_map(|(k, _)| k.as_str()).collect();
assert_eq!(
keys,
vec![KUBE_KEY_LABELS, KUBE_KEY_NAME, KUBE_KEY_NAMESPACE],
"metadata block must iterate alphabetically (the kube \
skeleton's render-determinism contract)"
);
}
}
#[test]
fn render_all_includes_every_artifact_kind() {
let docs = render_all(&aplicacao_caixa()).unwrap();
assert_eq!(docs.len(), 7);
let kinds: Vec<_> = docs
.iter()
.filter_map(|d| {
d.get(KUBE_KEY_KIND)
.and_then(|k| k.as_str())
.map(|s| s.to_string())
})
.collect();
assert!(kinds.contains(&CILIUM_KIND_NETWORK_POLICY.to_string()));
assert!(kinds.contains(&GATEWAY_API_KIND_GATEWAY.to_string()));
assert!(kinds.contains(&GATEWAY_API_KIND_HTTP_ROUTE.to_string()));
}
fn httproute_rules(docs: &[serde_yaml::Value]) -> Vec<serde_yaml::Value> {
find_by_kind(docs, GATEWAY_API_KIND_HTTP_ROUTE)
.and_then(|d| d.get(KUBE_KEY_SPEC))
.and_then(|s| s.get(KUBE_KEY_RULES))
.and_then(|r| r.as_sequence())
.cloned()
.expect("HTTPRoute spec.rules sequence")
}
#[test]
fn httproute_carries_politicas_timeout_on_every_rule() {
let docs = gateway_routes(&aplicacao_caixa()).unwrap();
let rules = httproute_rules(&docs);
assert!(!rules.is_empty(), "HTTPRoute must carry at least one rule");
for rule in &rules {
let timeouts = rule
.get(GATEWAY_API_KEY_TIMEOUTS)
.and_then(|t| t.as_mapping())
.expect("rule must carry timeouts mapping when :politicas :timeout is set");
assert_eq!(
timeouts
.get(GATEWAY_API_KEY_REQUEST)
.and_then(|v| v.as_str()),
Some("30s")
);
}
}
#[test]
fn httproute_omits_timeouts_when_politicas_timeout_unset() {
let mut c = aplicacao_caixa();
c.politicas = Some(MeshPolicy::default());
let docs = gateway_routes(&c).unwrap();
let rules = httproute_rules(&docs);
assert!(!rules.is_empty());
for rule in &rules {
assert!(
rule.get(GATEWAY_API_KEY_TIMEOUTS).is_none(),
"rule must omit `timeouts:` when :politicas :timeout is None"
);
}
}
#[test]
fn httproute_timeout_renders_every_rule_independently() {
let mut c = aplicacao_caixa();
if let Some(e) = c.entrada.as_mut() {
e.paths = vec![
"/api/cart".into(),
"/api/products".into(),
"/healthz".into(),
];
}
let docs = gateway_routes(&c).unwrap();
let rules = httproute_rules(&docs);
assert_eq!(rules.len(), 3);
for rule in &rules {
let req = rule
.get(GATEWAY_API_KEY_TIMEOUTS)
.and_then(|t| t.get(GATEWAY_API_KEY_REQUEST))
.and_then(|v| v.as_str())
.expect("each of the 3 rules carries timeouts.request");
assert_eq!(req, "30s");
}
}
#[test]
fn httproute_timeout_uses_canonical_kube_duration_format() {
let mut c = aplicacao_caixa();
c.politicas = Some(MeshPolicy {
timeout: Some(Duration::from_secs(90)),
..Default::default()
});
let docs = gateway_routes(&c).unwrap();
let rules = httproute_rules(&docs);
for rule in &rules {
assert_eq!(
rule.get(GATEWAY_API_KEY_TIMEOUTS)
.and_then(|t| t.get(GATEWAY_API_KEY_REQUEST))
.and_then(|v| v.as_str()),
Some("90s")
);
}
}
#[test]
fn httproute_timeout_renders_minute_window_canonically() {
let mut c = aplicacao_caixa();
c.politicas = Some(MeshPolicy {
timeout: Some(Duration::from_secs(60)),
..Default::default()
});
let docs = gateway_routes(&c).unwrap();
let rules = httproute_rules(&docs);
for rule in &rules {
assert_eq!(
rule.get(GATEWAY_API_KEY_TIMEOUTS)
.and_then(|t| t.get(GATEWAY_API_KEY_REQUEST))
.and_then(|v| v.as_str()),
Some("1m")
);
}
}
#[test]
fn httproute_rule_keys_pin_overlay_position() {
let docs = gateway_routes(&aplicacao_caixa()).unwrap();
let rules = httproute_rules(&docs);
for rule in &rules {
let m = rule.as_mapping().expect("rule mapping");
assert_eq!(m.len(), 4);
assert!(m.contains_key(GATEWAY_API_KEY_MATCHES));
assert!(m.contains_key(GATEWAY_API_KEY_BACKEND_REFS));
assert!(m.contains_key(GATEWAY_API_KEY_TIMEOUTS));
assert!(m.contains_key(GATEWAY_API_KEY_RETRY));
}
}
#[test]
fn httproute_carries_politicas_retries_on_every_rule() {
let docs = gateway_routes(&aplicacao_caixa()).unwrap();
let rules = httproute_rules(&docs);
assert!(!rules.is_empty(), "HTTPRoute must carry at least one rule");
for rule in &rules {
let retry = rule
.get(GATEWAY_API_KEY_RETRY)
.and_then(|r| r.as_mapping())
.expect("rule must carry retry mapping when :politicas :retries is set");
assert_eq!(
retry.get(GATEWAY_API_KEY_ATTEMPTS).and_then(|v| v.as_u64()),
Some(3),
"retry.attempts must round-trip the typed :retries value"
);
}
}
#[test]
fn httproute_omits_retry_when_politicas_retries_unset() {
let mut c = aplicacao_caixa();
c.politicas = Some(MeshPolicy::default());
let docs = gateway_routes(&c).unwrap();
let rules = httproute_rules(&docs);
assert!(!rules.is_empty());
for rule in &rules {
assert!(
rule.get(GATEWAY_API_KEY_RETRY).is_none(),
"rule must omit `retry:` when :politicas :retries is None"
);
}
}
#[test]
fn httproute_retry_renders_every_rule_independently() {
let mut c = aplicacao_caixa();
if let Some(e) = c.entrada.as_mut() {
e.paths = vec![
"/api/cart".into(),
"/api/products".into(),
"/healthz".into(),
];
}
let docs = gateway_routes(&c).unwrap();
let rules = httproute_rules(&docs);
assert_eq!(rules.len(), 3);
for rule in &rules {
let attempts = rule
.get(GATEWAY_API_KEY_RETRY)
.and_then(|r| r.get(GATEWAY_API_KEY_ATTEMPTS))
.and_then(|v| v.as_u64())
.expect("each of the 3 rules carries retry.attempts");
assert_eq!(attempts, 3);
}
}
#[test]
fn httproute_retry_round_trips_typed_attempt_count() {
let mut c = aplicacao_caixa();
c.politicas = Some(MeshPolicy {
retries: Some(5),
..Default::default()
});
let docs = gateway_routes(&c).unwrap();
let rules = httproute_rules(&docs);
for rule in &rules {
assert_eq!(
rule.get(GATEWAY_API_KEY_RETRY)
.and_then(|r| r.get(GATEWAY_API_KEY_ATTEMPTS))
.and_then(|v| v.as_u64()),
Some(5),
"retry.attempts must round-trip the typed :retries value verbatim"
);
}
}
#[test]
fn httproute_retry_attempts_serialized_as_yaml_number() {
let docs = gateway_routes(&aplicacao_caixa()).unwrap();
let rules = httproute_rules(&docs);
for rule in &rules {
let attempts = rule
.get(GATEWAY_API_KEY_RETRY)
.and_then(|r| r.get(GATEWAY_API_KEY_ATTEMPTS))
.expect("retry.attempts present");
assert!(
attempts.is_u64() || attempts.is_i64(),
"retry.attempts must be a YAML integer (got: {attempts:?})"
);
}
}
#[test]
fn httproute_timeouts_and_retry_coexist_independently() {
let mut c = aplicacao_caixa();
c.politicas = Some(MeshPolicy {
timeout: Some(Duration::from_secs(15)),
retries: None,
..Default::default()
});
let docs = gateway_routes(&c).unwrap();
let rules = httproute_rules(&docs);
for rule in &rules {
assert_eq!(
rule.get(GATEWAY_API_KEY_TIMEOUTS)
.and_then(|t| t.get(GATEWAY_API_KEY_REQUEST))
.and_then(|v| v.as_str()),
Some("15s")
);
assert!(
rule.get(GATEWAY_API_KEY_RETRY).is_none(),
"retry: must be absent when only :timeout is set"
);
}
let mut c2 = aplicacao_caixa();
c2.politicas = Some(MeshPolicy {
timeout: None,
retries: Some(2),
..Default::default()
});
let docs = gateway_routes(&c2).unwrap();
let rules = httproute_rules(&docs);
for rule in &rules {
assert!(
rule.get(GATEWAY_API_KEY_TIMEOUTS).is_none(),
"timeouts: must be absent when only :retries is set"
);
assert_eq!(
rule.get(GATEWAY_API_KEY_RETRY)
.and_then(|r| r.get(GATEWAY_API_KEY_ATTEMPTS))
.and_then(|v| v.as_u64()),
Some(2)
);
}
}
fn cnp_ingress_rules(docs: &[serde_yaml::Value]) -> Vec<serde_yaml::Value> {
docs.iter()
.filter(|d| kube_kind_is(d, CILIUM_KIND_NETWORK_POLICY))
.filter_map(|d| {
d.get(KUBE_KEY_SPEC)
.and_then(|s| s.get(CILIUM_KEY_INGRESS))
.and_then(|i| i.as_sequence())
.and_then(|s| s.first())
.cloned()
})
.collect()
}
#[test]
fn cnp_carries_politicas_mtls_required_on_every_rule() {
let policies = cilium_network_policies(&aplicacao_caixa()).unwrap();
let rules = cnp_ingress_rules(&policies);
assert!(
!rules.is_empty(),
"CNPs must carry at least one ingress rule"
);
for rule in &rules {
let auth = rule
.get(CILIUM_KEY_AUTHENTICATION)
.and_then(|a| a.as_mapping())
.expect("rule must carry authentication mapping when :mtls-required is set");
assert_eq!(
auth.get(CILIUM_KEY_MODE).and_then(|v| v.as_str()),
Some(CILIUM_AUTH_MODE_REQUIRED)
);
}
}
#[test]
fn cnp_omits_authentication_when_mtls_required_unset() {
let mut c = aplicacao_caixa();
c.politicas = Some(MeshPolicy::default());
let policies = cilium_network_policies(&c).unwrap();
let rules = cnp_ingress_rules(&policies);
assert!(!rules.is_empty());
for rule in &rules {
assert!(
rule.get(CILIUM_KEY_AUTHENTICATION).is_none(),
"rule must omit `authentication:` when :mtls-required is None"
);
}
}
#[test]
fn cnp_explicit_mtls_required_false_emits_disabled_mode() {
let mut c = aplicacao_caixa();
c.politicas = Some(MeshPolicy {
mtls_required: Some(false),
..Default::default()
});
let policies = cilium_network_policies(&c).unwrap();
let rules = cnp_ingress_rules(&policies);
assert!(!rules.is_empty());
for rule in &rules {
let auth = rule
.get(CILIUM_KEY_AUTHENTICATION)
.and_then(|a| a.as_mapping())
.expect("rule must carry authentication mapping for explicit :mtls-required nil");
assert_eq!(
auth.get(CILIUM_KEY_MODE).and_then(|v| v.as_str()),
Some(CILIUM_AUTH_MODE_DISABLED)
);
}
}
#[test]
fn cnp_authentication_renders_every_policy_independently() {
let mut c = aplicacao_caixa();
c.contratos.push(WitContract {
de: "payment".into(),
para: "catalog".into(),
wit: "wasi:http/proxy".into(),
endpoint: Some("/inventory".into()),
subject: None,
slot: None,
});
let policies = cilium_network_policies(&c).unwrap();
assert_eq!(policies.len(), 3);
let rules = cnp_ingress_rules(&policies);
assert_eq!(rules.len(), 3);
for rule in &rules {
assert_eq!(
rule.get(CILIUM_KEY_AUTHENTICATION)
.and_then(|a| a.get(CILIUM_KEY_MODE))
.and_then(|v| v.as_str()),
Some(CILIUM_AUTH_MODE_REQUIRED),
"every CNP's ingress rule must carry the authentication overlay"
);
}
}
#[test]
fn cnp_authentication_position_is_rule_level_not_nested() {
let policies = cilium_network_policies(&aplicacao_caixa()).unwrap();
let rules = cnp_ingress_rules(&policies);
for rule in &rules {
let m = rule.as_mapping().expect("rule mapping");
assert_eq!(m.len(), 3);
assert!(m.contains_key(CILIUM_KEY_FROM_ENDPOINTS));
assert!(m.contains_key(CILIUM_KEY_TO_PORTS));
assert!(m.contains_key(CILIUM_KEY_AUTHENTICATION));
let from = m
.get(CILIUM_KEY_FROM_ENDPOINTS)
.and_then(|f| f.as_sequence())
.expect("fromEndpoints sequence");
for fe in from {
assert!(
fe.get(CILIUM_KEY_AUTHENTICATION).is_none(),
"authentication must not nest inside fromEndpoints[]"
);
}
let to = m
.get(CILIUM_KEY_TO_PORTS)
.and_then(|t| t.as_sequence())
.expect("toPorts sequence");
for tp in to {
assert!(
tp.get(CILIUM_KEY_AUTHENTICATION).is_none(),
"authentication must not nest inside toPorts[]"
);
}
}
}
#[test]
fn cnp_authentication_pubsub_contracts_carry_overlay_too() {
let mut c = aplicacao_caixa();
c.contratos.push(WitContract {
de: "payment".into(),
para: "cart".into(), wit: "nats:pub-sub".into(),
endpoint: None,
subject: Some("checkout.events.charge.failed".into()),
slot: None,
});
let policies = cilium_network_policies(&c).unwrap();
let nats_policy = policies
.iter()
.find(|p| kube_metadata_str_field(p, KUBE_KEY_NAME) == Some("checkout-payment-to-cart"))
.expect("pubsub CNP present");
let rule = nats_policy
.get(KUBE_KEY_SPEC)
.and_then(|s| s.get(CILIUM_KEY_INGRESS))
.and_then(|i| i.as_sequence())
.and_then(|s| s.first())
.expect("ingress[0]");
assert_eq!(
rule.get(CILIUM_KEY_AUTHENTICATION)
.and_then(|a| a.get(CILIUM_KEY_MODE))
.and_then(|v| v.as_str()),
Some(CILIUM_AUTH_MODE_REQUIRED)
);
}
#[test]
fn cnp_l4_fallback_port_routes_through_lifted_default_servico_port() {
let policies = cilium_network_policies(&aplicacao_caixa()).unwrap();
let cart_to_payment = policies
.iter()
.find(|p| kube_metadata_str_field(p, KUBE_KEY_NAME) == Some("checkout-cart-to-payment"))
.expect("cart→payment CNP present");
let port_value = cart_to_payment
.get(KUBE_KEY_SPEC)
.and_then(|s| s.get(CILIUM_KEY_INGRESS))
.and_then(|i| i.as_sequence())
.and_then(|s| s.first())
.and_then(|i| i.get(CILIUM_KEY_TO_PORTS))
.and_then(|t| t.as_sequence())
.and_then(|s| s.first())
.and_then(|tp| tp.get(CILIUM_KEY_PORTS))
.and_then(|p| p.as_sequence())
.and_then(|s| s.first())
.and_then(|p| p.get(KUBE_KEY_PORT))
.and_then(|v| v.as_str())
.expect("toPorts[0].ports[0].port present");
assert_eq!(
port_value,
DEFAULT_SERVICO_PORT.to_string(),
"the L4 fallback must render the lifted DEFAULT_SERVICO_PORT \
constant verbatim — drift here means the constant lift no \
longer reaches this consumer"
);
}
#[test]
fn cnp_l4_port_routes_through_lifted_port_for_destination_resolver() {
let caixa = aplicacao_caixa();
let spec = typed_view(&caixa).expect("aplicacao_caixa fixture must be a valid Aplicacao");
let policies = cilium_network_policies(&caixa).unwrap();
let cart_to_catalog = policies
.iter()
.find(|p| kube_metadata_str_field(p, KUBE_KEY_NAME) == Some("checkout-cart-to-catalog"))
.expect("cart→catalog CNP present");
let port_value = cart_to_catalog
.get(KUBE_KEY_SPEC)
.and_then(|s| s.get(CILIUM_KEY_INGRESS))
.and_then(|i| i.as_sequence())
.and_then(|s| s.first())
.and_then(|i| i.get(CILIUM_KEY_TO_PORTS))
.and_then(|t| t.as_sequence())
.and_then(|s| s.first())
.and_then(|tp| tp.get(CILIUM_KEY_PORTS))
.and_then(|p| p.as_sequence())
.and_then(|s| s.first())
.and_then(|p| p.get(KUBE_KEY_PORT))
.and_then(|v| v.as_str())
.expect("toPorts[0].ports[0].port present");
assert_eq!(
port_value,
spec.port_for_destination("catalog").to_string(),
"the per-CNP L4 port must match the port_for_destination \
resolver's scalar for the same destination — drift here \
means the emit-side path re-inlined the resolution rule"
);
}
#[test]
fn cnp_authentication_mode_serialized_as_yaml_string() {
let policies = cilium_network_policies(&aplicacao_caixa()).unwrap();
let rules = cnp_ingress_rules(&policies);
for rule in &rules {
let mode = rule
.get(CILIUM_KEY_AUTHENTICATION)
.and_then(|a| a.get(CILIUM_KEY_MODE))
.expect("authentication.mode present");
assert!(
mode.is_string(),
"authentication.mode must be a YAML string (got: {mode:?})"
);
}
}
#[test]
fn spec_entrada_accessor_byte_equal_to_raw_field_access() {
let spec = typed_view(&aplicacao_caixa()).expect("fixture is a valid Aplicacao");
let via_accessor: Option<&Entrada> = spec.entrada();
let via_raw: Option<&Entrada> = spec.entrada.as_ref();
assert_eq!(
via_accessor.is_some(),
via_raw.is_some(),
"AplicacaoSpec::entrada() must project the raw \
Option<Entrada> slot's presence bit byte-equal to \
self.entrada.as_ref() — drift would let the accessor's \
Some/None partition disagree with the raw field's on a \
fixture the substrate contract pins as Some(_)"
);
let acc = via_accessor.expect("accessor Some arm");
let raw = via_raw.expect("raw Some arm");
assert_eq!(
acc.hostname(),
raw.hostname(),
"accessor and raw must agree on Entrada::hostname()"
);
assert_eq!(
acc.destination(),
raw.destination(),
"accessor and raw must agree on Entrada::destination()"
);
assert_eq!(
acc.port(),
raw.port(),
"accessor and raw must agree on Entrada::port()"
);
assert_eq!(
acc.paths(),
raw.paths(),
"accessor and raw must agree on Entrada::paths()"
);
let mut no_entrada = aplicacao_caixa();
no_entrada.entrada = None;
let spec_none = typed_view(&no_entrada).expect("fixture without :entrada is still valid");
assert!(
spec_none.entrada().is_none(),
"accessor must project None on a fixture with no :entrada"
);
assert!(
spec_none.entrada.is_none(),
"raw field must project None on a fixture with no :entrada"
);
}
}