pub fn is_chart_maintainer_name_shape(s: &str) -> Result<(), String>Expand description
Predicate: assert that s is a valid chart-maintainer-name shape.
The :autores axis is a per-entry maintainer identifier that lands
in the rendered lareira-<nome> Helm chart’s Chart.yaml
maintainers: [{name: …, email: null}] array via
[caixa-helm]’s build_chart_yaml (caixa-helm/src/lib.rs:251);
each entry becomes the name: value of a single Maintainer
record (a YAML scalar consumed by helm list, helm search,
Artifact Hub’s maintainer index, and every chart-aware UI). The
contract — modeled on the same YAML 1.2 plain-style scalar
grammar is_chart_description_shape enforces on the sibling
:descricao axis, with a tighter length cap for the per-entry
identifier class:
- 1..=
CHART_MAINTAINER_NAME_MAX_LEN(128) bytes; - no leading whitespace (paste-from-aligned-doc footgun —
YAML plain-style scalars round-trip trim-and-restore on
leading whitespace, so an authored
" pleme-io"lands as"pleme-io"in the rendered Chart.yaml and the round-trip back throughcaixa.lispsilently drops the space); - no trailing whitespace (paste-from-doc footgun — every YAML
dumper trims trailing whitespace from plain-style scalars,
so an authored
"pleme-io "round-trips inconsistently); - no ASCII control characters anywhere (
0x00..=0x1Fplus0x7FDEL) — tabs, newlines, carriage returns, and every other control byte break the single-line YAML scalar shape and thehelm list/helm search/ Artifact Hub maintainer-column rendering. The newline / CR arms are the canonical paste-from-multiline-doc footgun (the author pasted a multi-line block of author records into one:autoresentry instead of splitting them into one entry per author); 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; - non-ASCII bytes (UTF-8 continuation sequences) are accepted
— realistic maintainer names carry Unicode (
"François","日本語","naïve") 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+202BRLE, U+202CPDF, U+202DLRO, U+202ERLO, U+2066LRI, U+2067RLI, U+2068FSI, U+2069PDI) — the nine codepoints UAX #9 names as the structural prerequisite of the “Trojan Source” attack class (CVE-2021-42574). A maintainer-name with an embeddedRLOflips the visual order of every trailing byte, so an:autores "alice\u{202E}example.com<bob@"(the paste-from-attacker-crafted-doc footgun) renders inhelm list’s maintainer column / Artifact Hub asalice<@bob>moc.elpmaxebut rides verbatim into the rendered Chart.yamlmaintainers:array — same Trojan Source classis_chart_description_shapecloses on the sibling:descricaoaxis. Routed through the same lifted [find_unicode_bidi_override] helper so the nine-codepoint accepted set is shared, structurally consistent. - no non-ASCII Unicode line-break codepoints (U+0085
NEL, U+2028LS, U+2029PS) — the three codepoints UAX #14 (Unicode Line Breaking Algorithm) and YAML 1.1 §4.1 b-char production both treat as line terminators outside the ASCII\n/\rarms above. YAML 1.2 §5.4 retired them per UTR #20 so the cross-parser line-break disagreement (go-yaml v2 / YAML 1.1 still splits; YAML 1.2-strict parsers preserve) breaks the THEORY.md §V.2 render- determinism contract on the same axis the per-byte\n/\rarms close for ASCII. A maintainer-name with an embedded U+2028 parses as one entry through a YAML 1.2 parser and as twomaintainers:array entries through a YAML 1.1 parser — same paste-from-multiline-doc class the\narm above closes, extended to the non-ASCII line-break codepoints the per-byte non-ASCII pass deliberately admits for Unicode letters. Routed through the same lifted [find_unicode_line_break] helper so the three-codepoint accepted set is shared withis_chart_description_shapeon the sibling YAML-plain-style-scalar surface, structurally consistent. - no Unicode invisible-format codepoints (U+00AD
SHY, U+200BZWSP, U+2060WJ, U+2061FAFUNCTION APPLICATION, U+2062ITINVISIBLE TIMES, U+2063ISINVISIBLE SEPARATOR, U+2064IPINVISIBLE PLUS, U+FEFFZWNBSP/ BOM) — the eight BMP Cf-category zero-width codepoints with no visible glyph. A maintainer-name with an embedded U+200B ("alice\u{200B}") renders identically to"alice"inhelm list/ Artifact Hub’s maintainer column, yet the byte sequence is distinct — the Artifact Hub maintainer-index lookup misses the authored"alice"entry, and a future CLA-signer lookup matches a visually- identical-but-byte-distinct identity (the canonical invisible-codepoint homograph footgun on the maintainer- identity axis). Closes the canonical paste-from-Microsoft- Word (SHY), paste-from-text-editor-saved-as-UTF-8-with-BOM (BOM), paste-from-typesetting-doc (ZWSP / WJ), and paste-from-MathJax/LaTeX-rendered-formula (FUNCTION APPLICATION / INVISIBLE TIMES / INVISIBLE SEPARATOR / INVISIBLE PLUS — math-formula invisible operators MathJax / LaTeX2RTF / InDesign emit between symbols for screen-reader operator semantics) footguns. Routed through the same lifted [find_unicode_invisible_format] helper so the eight-codepoint accepted set is shared withis_chart_description_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+200CZWNJ/ U+200DZWJ(emoji ZWJ sequences are canonical for modern maintainer-display names) and U+200ELRM/ U+200FRLM(mixed-script direction hints are canonical for “Arabic name with embedded ASCII email” shapes).
Same structural single-line printable-UTF-8 floor as
is_chart_description_shape — both :descricao and :autores
land as YAML plain-style scalars in the same Chart.yaml and
share every paste-from-doc footgun the YAML 1.2 grammar refuses
at parse time. The two predicates differ only on the byte
length cap: 512 bytes for :descricao (multi-sentence prose
shape) vs 128 bytes for :autores entries (short-identifier
shape). Returns the parser-shaped reason on rejection (without
wrapping in any error variant) so each per-axis caller —
crate::Caixa::validate_autores for the universal :autores
axis at validate time, every future per-maintainer-name axis (a
future caixa-registry maintainer-index entry, a future
chart-author CLA-signer lookup) — wraps the same reason in its
own typed *Invalid { <axis>, reason } variant.
Empty input is rejected here (defensively) and at each call
site via the narrower crate::ManifestError::AutorEmpty
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, is_spdx_expression_shape, and
is_chart_description_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), without wrapping in any error
variant — every caller maps the same String into its own typed
*Invalid { <axis>, reason } enum variant.