pub struct Label(/* private fields */);Expand description
One GitHub runner label, normalised.
Normalisation is lower-casing, and it is not cosmetic. The v1 spike
registered a runner with ["rm-d18-spike","Windows","X64","self-hosted-rm"]
and GitHub returned windows and x64
(docs/spikes/d18-org-jit-verification.md, Point 3, finding 3). A label read
back from the API therefore never matches a mixed-case label held locally
unless both sides are folded first. Folding on construction makes every
comparison in this crate — Eq, Ord, Hash, set membership — case
insensitive for free, so no call site can forget.
The fold is ASCII, matching HostLabel and the target [Name] types.
The only case folding this crate has evidence for is GitHub’s, and the only
evidence is the spike above, which is entirely ASCII. Unicode
to_lowercase() would also make folding length-changing — İ (U+0130)
lowercases to two chars — which is how a 256-character label could exceed
Self::MAX_LEN after construction. ASCII folding is length-preserving,
so that class of bug cannot occur, and the length check below is applied to
the folded value regardless so the stored string is what was measured.
What the character rules are for. They are round-trippability rules, not
injection defences, and reading them as the latter is how a rule that
defends nothing gets added. A Label is never interpolated into a shell: it
travels as one element of the runner’s comma-separated --labels argument
and as a JSON string. So exactly two characters break the round trip — the
comma, which is the separator itself, and control characters, which break
both the argument and the JSON framing. Nothing else does, and a quote rule
in particular is neither necessary (no shell is involved) nor sufficient
(<, >, $, `, ;, |, & and whitespace would all still pass).
An explicit allow-list was considered and rejected: real GitHub labels
include c#, .net, x86_64 and similar, so any allow-list narrow enough
to be worth having would reject legitimate runs-on values and turn a
cosmetic concern into a demand-matching failure in
crate::policy::RunsOn::required_labels.
Implementations§
Source§impl Label
impl Label
Sourcepub fn new(raw: impl AsRef<str>) -> Result<Self, ValidationError>
pub fn new(raw: impl AsRef<str>) -> Result<Self, ValidationError>
§Errors
Empty, over-long, comma-bearing, or control-character-bearing input. A comma is rejected because it separates labels in the runner’s own configuration, so a label containing one is not round-trippable; control characters break the same argument and the JSON encoding around it. See the type documentation for why the list stops there.