fix(dashboard): cap env name at 32 chars + strip underscores (BUG-DASH-001/002)#147
Merged
Merged
Conversation
…H-001/002)
BUG-DASH-001 (P0): pre-fix the env-switcher's "+ new env…" input
accepted custom env names of arbitrary length and persisted them to
localStorage. A 67-char paste broke every subsequent /api/v1/* call:
- GET /api/v1/vault/<67-char> → 400 invalid_env
- GET /api/v1/resources?env=<67> → 200 with empty list (read-path
gap, BUG-DASH-007)
- GET /api/v1/deployments?env=<67> → 200 with empty list
There was no UI affordance to delete the bad env — users had to open
devtools and clear localStorage to recover.
BUG-DASH-002: the JS regex was `[^a-z0-9_-]`, permitting underscores.
The api regex is `^[a-z0-9-]{1,32}$` (no underscore), so a user typing
`my_env_name` would persist locally and then 400 on every API call —
same "client says yes, server says no" gap.
Fix in addEnv() (src/hooks/useDashboardCtx.ts):
1. Drop underscore from the char-class strip → underscore-bearing
input is silently scrubbed, matching the api regex.
2. .slice(0, 32) clips to the api's 32-char cap before any persist.
3. Final ENV_REGEX gate validates the post-strip-and-clip string. If
it doesn't match, return early WITHOUT touching state — the live
env stays on its previous valid value, so the user is never
locked into a broken state.
The existing UI plumbing in <EnvSwitcher /> (AppShell.tsx) already
gates addEnv behind a non-empty draft; no UI changes required.
Coverage block (per CLAUDE.md rule 17):
Symptom: /api/v1/vault/<too-long> → 400 invalid_env; user locked out
Enumeration: rg -n 'addEnv\|ENV_REGEX' src/hooks/ (1 hit pre-fix)
Sites found: 1 (addEnv export)
Sites touched: 1
Coverage test: 3 new test cases in useDashboardCtx.test.ts:
- addEnv clips an over-32-char input to the api cap
- addEnv strips underscores (api regex forbids them)
- addEnv leaves live env unchanged on all-invalid input
Existing tests ("sanitises ... My Env!!", "ignores
all-invalid") still pass — the contract is strictly
tightened, not changed.
Live verify: open /app, click env-switcher → "+ new env…", type
67 chars → input is clipped to 32, regex-validated,
persisted only if it matches; reload and confirm
localStorage["instanode.env"] is ≤32 chars + api-shape.
Test results: 14 tests pass in useDashboardCtx.test.ts (was 11); full
`npm run gate` passes (76 test files, 1072 tests, 0 failures).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
size-limit report 📦
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes BUG-DASH-001 (P0) and BUG-DASH-002 from the 2026-05-29 QA wave.
What broke
BUG-DASH-001 (P0) — env-switcher "+ new env…" accepted env names of arbitrary length, persisted them to localStorage, broke every subsequent API call:
GET /api/v1/vault/<67-char>→ 400invalid_envGET /api/v1/resources?env=<67>→ 200 with empty list (BUG-DASH-007 read-path gap)BUG-DASH-002 — the JS regex was
[^a-z0-9_-](permits underscores). The api regex is^[a-z0-9-]{1,32}$(no underscore). A user typingmy_env_namewould persist locally then 400 on every API call.What the fix does
In
addEnv()(src/hooks/useDashboardCtx.ts):.slice(0, 32)clips to the api's 32-char cap before any persist (BUG-DASH-001).ENV_REGEX = /^[a-z0-9-]{1,32}$/gate validates the post-strip-and-clip string; mismatch → bail out without touching state, so the live env stays on its previous valid value (the user can never get locked into a broken state).No UI plumbing changes — existing
<EnvSwitcher />gatesaddEnvbehind a non-empty draft already.Test coverage
3 new test cases in
useDashboardCtx.test.ts:addEnv clips an over-32-char input to the api capaddEnv strips underscores (api regex forbids them)addEnv leaves live env unchanged on all-invalid + over-cap inputExisting tests (
sanitises ' My Env!! '→myenv;ignores all-invalid '!!!') still pass — contract is strictly tightened, not changed.Local gate (
npm run gate— the EXACT mandatory gate per project memoryfeedback_coverage_measure_per_package_not_dotdotdot.md):Rule 22 surface checklist
instanode-web/src/hooks/useDashboardCtx.ts— addEnv regex + capinstanode-web/src/hooks/useDashboardCtx.test.ts— regression testsBackend API is unchanged — this PR brings the dashboard's client validation into line with the api's existing regex. CLAUDE.md + OpenAPI already reflect the api regex; no doc edits required.
Drift discipline
🤖 Generated with Claude Code