bug(adminui): /scripts is a hard 500 when any Script.SourceHash is shorter than 12 chars #504
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found while live-gating #487 on the docker-dev rig.
Components/Pages/Scripts.razor:41renders the hash prefix as:SourceHashis a plainnvarchar(64)column with no length floor. Any row whose hash is shorter than 12 characters throwsArgumentOutOfRangeExceptionout ofBuildRenderTree, which is unhandled and takes the whole/scriptspage to a hard HTTP 500 — not just that row.Reproduction
The docker-dev seed itself trips it.
seed/seed-clusters.sqlinserts placeholder hashes:SC-gatevth-abs-hr200SC-cvalh1So on a stock docker-dev bring-up,
GET /scriptsis a 500 with:Severity
Lower than it first looks: scripts authored through
ScriptEdit.razor/UnsTreeService.HashSourcealways get a full 64-char SHA-256, so a fleet that only ever authored through the UI will not hit this. It matters because (a) the seeded dev rig hits it every time, and (b) a range operator applied to an unvalidated DB string is a latent whole-page crash — nothing enforces the length at the schema, entity, or render layer.Suggested fix
Truncate defensively rather than slice, e.g.
@(s.SourceHash.Length > 12 ? s.SourceHash[..12] + "…" : s.SourceHash). Worth a sweep for other[..n]range operators applied to DB-sourced strings in the AdminUI while in there. Optionally also fix the seed to insert real SHA-256 values so the dev rig stops shipping a broken page.Not related to #487 — filing separately so it is tracked rather than lost in that PR.
Correction to the reproduction section below — the docker-dev seed is not the source. I inferred that from the rig's data without checking
seed/seed-clusters.sql; it only insertsServerCluster,ClusterNode, andLdapGroupRoleMapping. The two short-hash rows on the rig (SC-gatevt=h-abs-hr200,SC-cval=h1) came from earlier live-gate authoring in past sessions, not from the seed. So a freshly seeded docker-dev does not have a broken/scriptspage — only a rig that has accumulated API- or SQL-authored Script rows does.That narrows the trigger but does not remove it: nothing enforces a minimum
SourceHashlength at the schema, entity, or render layer, so any row that did not go throughScriptEdit.razor/UnsTreeService.HashSource— REST-API authored, hand-inserted, migrated in from another system — still hard-500s the whole page.Fixed
New
Components/Shared/DisplayText.Abbreviate(string?, int)— null/blank-safe, never throws, and appends the ellipsis only when it actually truncated (so a 2-character hash rendersh1, noth1…, and no longer implies text that is not there). AmaxLength < 1is clamped rather than allowed to throw.Applied to every unguarded range-operator slice over a DB-sourced string found by sweeping the AdminUI for
[..N]:Components/Pages/Scripts.razor:41SourceHash— the reported crashComponents/Pages/Certificates.razor:84Thumbprint(read off the on-disk cert store)Components/Pages/Deployments.razor:58RevisionHashComponents/Pages/Deployments.razor:116RevisionHashin the dispatch bannerComponents/Pages/Clusters/ClusterOverview.razor:61RevisionHashThe rest of the
[..N]hits in the sweep are safe and were left alone:Guid.ToString("N")slices (always 32 chars) and theLength > 60 ? [..60] : …ternaries that already guard themselves.Merged + pushed —
origin/mastere3155fbb(fromfix/504-abbreviate-db-strings/47d148da).Merged tree builds clean (0 errors); AdminUI suite 739/739 (14 of them new in
DisplayTextTests, covering short / null / blank / clamped budgets plus a never-throws sweep over every value x budget combination).Live-verified on docker-dev (AdminUI has no bUnit, so this is the real check), same rig and same two short-hash rows, pre-fix image vs. rebuilt:
GET /scriptshash=h1andhash=h-abs-hr200, full, no misleading ellipsis/deployments/certificates,/clusters/MAIN