Skip to main content

is_chart_description_shape

Function is_chart_description_shape 

Source
pub fn is_chart_description_shape(s: &str) -> Result<(), String>
Expand description

Predicate: assert that s is a valid chart-description shape. The :descricao axis is a free-form prose summary that lands in the rendered lareira-<nome> Helm chart’s Chart.yaml description: field (a YAML scalar consumed by helm list, helm search, Artifact Hub, and every chart-aware UI) and in the chart’s README.md header paragraph (caixa-helm/src/lib.rs:232, caixa-helm/src/lib.rs:333). The contract — modeled on the YAML 1.2 plain-style scalar grammar and the Helm chart spec’s expectation that description: is a one-line summary:

  • 1..=CHART_DESCRIPTION_MAX_LEN (512) bytes;
  • no leading whitespace (paste-from-aligned-doc footgun — YAML plain-style scalars round-trip trim-and-restore on leading whitespace, so an authored " foo" lands as "foo" in the rendered Chart.yaml and the round-trip back through caixa.lisp silently drops the space);
  • no trailing whitespace (paste-from-doc footgun — every YAML dumper trims trailing whitespace from plain-style scalars, so an authored "foo " round-trips inconsistently);
  • no ASCII control characters anywhere (0x00..=0x1F plus 0x7F DEL) — tabs, newlines, carriage returns, and every other control byte break the single-line YAML scalar shape and the README header paragraph. The newline / CR arms are the canonical paste-from-multiline-doc footgun; the tab arm is the canonical paste-from-aligned-doc footgun; the other-control-byte arm catches every more-exotic paste-from-binary-blob shape (0x00 NUL, 0x07 BEL, 0x1B ESC) that would silently land in the rendered Chart.yaml as a YAML-illegal byte sequence and fail at helm lint time far from the source caixa.lisp;
  • non-ASCII bytes (UTF-8 continuation sequences) are accepted — the canonical author shapes ("Canonical Rust→wasm32-wasip2 caixa Servico.", "FIXME — describe this caixa") carry (U+2192) and (U+2014) and every downstream consumer (YAML 1.2, Helm v3, every chart-aware UI) round-trips Unicode losslessly;
  • no Unicode bidirectional-override / isolate format codepoints (U+202A LRE, U+202B RLE, U+202C PDF, U+202D LRO, U+202E RLO, U+2066 LRI, U+2067 RLI, U+2068 FSI, U+2069 PDI) — the nine codepoints UAX #9 names as the structural prerequisite of the “Trojan Source” attack class (CVE-2021-42574 / Boucher & Anderson 2021) that flip the rendered visual order of every following character until a matching pop. Routed through the lifted [find_unicode_bidi_override] helper so the same nine-codepoint accepted set is shared with is_chart_maintainer_name_shape on the sibling YAML-plain-style-scalar surface, structurally consistent. The non-ASCII byte arm above admits Unicode letters / em-dash / arrows because YAML 1.2 + Helm v3 + every chart-aware UI round-trip them losslessly; the bidi-override codepoints break that round-trip discipline by class (the byte sequence rides verbatim into the rendered Chart.yaml’s description: value but renders differently in helm show chart / Artifact Hub / helm list vs the author’s editor view of caixa.lisp), defeating the THEORY.md §V.2 render-determinism contract every typed slot carries on the same axis the per-byte CR/LF/control arms above close for ASCII.
  • no non-ASCII Unicode line-break codepoints (U+0085 NEL, U+2028 LS, U+2029 PS) — the three codepoints UAX #14 (Unicode Line Breaking Algorithm) and the YAML 1.1 §4.1 b-char production both treat as line terminators outside the ASCII \n / \r arms above. YAML 1.2 §5.4 retired them per UTR #20, so YAML 1.2-strict parsers preserve them verbatim while YAML 1.1 parsers (go-yaml v2 which Helm v3 / kubectl link, ruamel.yaml in compat mode) split the scalar on them — the same :descricao value parses as single-line through one consumer and multi-line through another, breaking cross-parser determinism on the same axis the per-byte \n / \r arms close for ASCII. Independently, every UAX #14 conformant text consumer (editors, terminals, helm list / Artifact Hub web UIs) breaks the visual line at these codepoints regardless of YAML version, so the author’s editor view of caixa.lisp and the chart-consumer’s rendered view diverge even when both YAML parsers agree on the byte-level shape. Routed through the lifted [find_unicode_line_break] helper so the same three-codepoint accepted set is shared with is_chart_maintainer_name_shape, peer of the [find_unicode_bidi_override] lift on the same two predicates one trajectory earlier.
  • no Unicode invisible-format codepoints (U+00AD SHY, U+200B ZWSP, U+2060 WJ, U+2061 FA FUNCTION APPLICATION, U+2062 IT INVISIBLE TIMES, U+2063 IS INVISIBLE SEPARATOR, U+2064 IP INVISIBLE PLUS, U+FEFF ZWNBSP / BOM) — the eight BMP Cf-category zero-width codepoints with no visible glyph in any conforming font. The author’s editor view of caixa.lisp and the chart- consumer’s helm list / Artifact Hub description column agree on the visible glyph sequence ("Canonical Servico" and "Canonical\u{200B}Servico" render identically), but the byte sequence the YAML-plain-style-scalar carries verbatim differs — every byte-level grep / diff / equality comparison and the Artifact Hub description-search index lookup disagree silently with the visible-glyph match. Closes the canonical paste-from-Microsoft-Word (SHY auto- inserted at hyphenation candidates), paste-from-text- editor-saved-as-UTF-8-with-BOM (leading BOM byte), paste-from-typesetting-doc (ZWSP / WJ invisible word-break hints), and paste-from-MathJax/LaTeX-rendered-formula (FUNCTION APPLICATION / INVISIBLE TIMES / INVISIBLE SEPARATOR / INVISIBLE PLUS — the four math-formula invisible operators MathJax / LaTeX export between adjacent symbols for screen-reader operator semantics) footguns. Routed through the lifted [find_unicode_invisible_format] helper so the same eight-codepoint accepted set is shared with is_chart_maintainer_name_shape, third lift in the UAX-driven render-determinism trio (peer of [find_unicode_bidi_override] on the visual-order axis and [find_unicode_line_break] on the single-line/multi- line axis). The eight-codepoint set excludes U+200C ZWNJ / U+200D ZWJ (legitimate compositional load in Indic / Persian scripts and emoji ZWJ sequences) and U+200E LRM / U+200F RLM (legitimate single-character direction hints in mixed-script prose); the visible-order risk on bidi overrides — not marks — is closed by the prior helper.

The predicate is a structural floor — it enforces the single-line printable-UTF-8 shape every realistic chart description carries, not a per-byte alphabet check (which would regress every non-ASCII canonical fixture). Same trajectory as is_spdx_expression_shape (the ASCII-alphabet floor on the :licenca axis) and is_git_repo_url (the URL-shape floor on the :repositorio axis): the typed validator refuses the downstream consumer’s would-also-refuse shapes at the source caixa.lisp boundary with the offending value named verbatim.

Returns the parser-shaped reason on rejection (without wrapping in any error variant) so each per-axis caller — crate::Caixa::validate_descricao for the universal :descricao axis at validate time, every future per-description axis (a future Aplicacao-level :descricao summary axis on mesh.pleme.io/v1alpha1/Caixa CRs, a future Servico-level per-:contratos edge :descricao annotation) — wraps the same reason in its own typed *Invalid { <axis>, reason } variant. The reason wording is axis-agnostic (“chart descriptions reject leading whitespace”) so every call site reading the same diagnostic points at the same rule; drift between any two axes’ rule enforcement is a build error visible at this predicate, not a per-renderer “this passed validate but helm lint rejected the Chart.yaml description: value” surprise.

Empty input is rejected here (defensively) and at each call site via the narrower crate::ManifestError::DescricaoEmpty variant — the same empty-first cascade is_dns_1123_label, is_gateway_api_http_path, is_wit_world_ref, is_nats_subject, is_wasi_keyvalue_slot, is_git_ref_name, is_git_oid, is_git_repo_url, is_cargo_feature_name, and is_spdx_expression_shape all carry.

§Errors

Returns the parser-shaped reason naming the specific violation (length / leading-whitespace / trailing-whitespace / tab / newline / carriage-return / other-control-byte / Unicode-bidi-override-codepoint / Unicode-line-break-codepoint), without wrapping in any error variant — every caller maps the same String into its own typed *Invalid { <axis>, reason } enum variant.