mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-05 08:02:18 +00:00
**The new-workspace username was never validated.** Step 2 shows the field when
the instance does not derive one, but neither the Continue gate nor
`planProblem` looked at it. `create_workspace` does not close that hole:
`nw.username.ok_or(...)` accepts `Some("")` and never runs the `VALID_USERNAME`
check `join_workspace` does, so a cleared field created a workspace whose owner
has an empty username, and a digit-first one was stored verbatim. Both now
refuse, using the same `validateUsername` the sibling creator has always run.
**The name length was unchecked**, so a >50-char name walked through two more
steps and failed at create. `WORKSPACE_NAME_MAX_LENGTH` sits next to the id
limit and `planProblem` checks it.
**Leaving mid-run did not stop the run.** The dialog promised "The import stops
where it is. Coming back to this link picks it up again", but navigating away
only unmounted the UI: the executor kept going, reached `done`, and called
`clearParkedImport()` — so returning to the link tried to create the workspace
again and failed with "already exists". Worse, the review drawer's teardown
resolved the pending review to `false`, meaning "skip the migrations", and the
orphan imported every item without the tables they need.
Nothing can abort a request already in flight — `installProject` takes no
signal — so `abandon()` stops the run at the next phase boundary and leaves the
workspace parked, and the teardown now resolves `'abort'`, which stops the
import rather than silently dropping the migrations.
Also drops a stale JSDoc above `hubAppIcon` still describing the fetch-and-
sanitize implementation that `ea31f73ed3` replaced.
Adds the coverage the review asked for: the parking decision at the end of a
run, and the two validation gates.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
43 lines
1.7 KiB
TypeScript
43 lines
1.7 KiB
TypeScript
/**
|
|
* What the backend accepts as a workspace id, in one place. Every screen that lets
|
|
* someone name a workspace validates against this — a laxer copy elsewhere only
|
|
* moves the rejection from the form to the create call, after the user has
|
|
* finished the whole flow.
|
|
*/
|
|
|
|
/** Letters, digits and underscores in dash-separated groups: no leading, trailing or doubled dash. */
|
|
export const WORKSPACE_ID_RE = /^\w+(-\w+)*$/
|
|
/** The DB column and the git branch name derived from it both stop here. */
|
|
export const WORKSPACE_ID_MAX_LENGTH = 50
|
|
|
|
/** `validate_workspace_name` (windmill-common/src/workspaces.rs:246) refuses a longer name. */
|
|
export const WORKSPACE_NAME_MAX_LENGTH = 50
|
|
|
|
/**
|
|
* The reason `id` is not a usable workspace id, or undefined when it is.
|
|
*
|
|
* `effectiveId` is what actually reaches the backend: a fork's id is submitted
|
|
* with a `wm-fork-` prefix, so the length limit applies to the prefixed form while
|
|
* the character rule still applies to what the user typed.
|
|
*/
|
|
export function validateWorkspaceId(id: string, effectiveId: string = id): string | undefined {
|
|
if (!WORKSPACE_ID_RE.test(id)) {
|
|
return 'ID can only contain letters, numbers and dashes and must not finish by a dash'
|
|
}
|
|
if (effectiveId.length > WORKSPACE_ID_MAX_LENGTH) {
|
|
return `ID '${effectiveId}' is too long (${effectiveId.length} chars). Maximum is ${WORKSPACE_ID_MAX_LENGTH}.`
|
|
}
|
|
return undefined
|
|
}
|
|
|
|
/** Slugifies free text into something `validateWorkspaceId` accepts, for a prefill. */
|
|
export function toWorkspaceId(raw: string): string {
|
|
return raw
|
|
.toLowerCase()
|
|
.replace(/[^a-z0-9-]+/g, '-')
|
|
.replace(/-{2,}/g, '-')
|
|
.replace(/^-+|-+$/g, '')
|
|
.slice(0, WORKSPACE_ID_MAX_LENGTH)
|
|
.replace(/-+$/, '')
|
|
}
|