fix(site): refuse a starter that does not exist instead of serving an empty root - #231
Merged
ralyodio merged 1 commit intoAug 3, 2026
Conversation
… empty root `site <name> --template <starter>` joined the value straight into a path under examples/templates. When that directory was not there — a typo, or `--template --install` reading the next flag as the name — fs.stat failed, the seed step was dropped, and the install carried on to the end reporting success with nothing in the root. That is the 404 the seeding exists to prevent, reached by the one route that also hides it: the run says the config is installed, so the empty page reads as a broken name rather than a mistyped flag. The name is also now checked for shape before it is joined into a path. templates.mjs already refuses to treat anything with a slash or a dot as a bundled name, for exactly this reason; site did not apply that rule, so a value with enough ../ in it named a copy source anywhere on the box, and that copy lands in a root a web server is about to publish.
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.
moshcode site <name> --template <starter>joins the value straight into apath under
examples/templates. When that directory turns out not to exist,fs.statfails,seedresolves tonull, the seed step is never added, andthe install runs to the end and reports success — with nothing in the root.
The file's own comment says why that matters:
So the one flag whose job is to prevent that outcome produces it silently
whenever it is wrong, and the success message makes the empty page look like
a name that never resolved rather than a starter that was misspelled by one
letter.
Reproduced
Driven through
serveCommandwith the write/mkdir/copy deps stubbed, sonothing touched this machine. Before:
The second one is the worse of the two:
--templatetakesrest[at + 1]with no check that a value was there, so
--template --installreads--installas the starter name — and still installs, becauserest.includes("--install")is a separate test.The path, not just the name
The same value is joined into a path with no shape check.
templates.mjsalready has that rule and says why:
sitedid not apply it, so a value with enough../in it names a copysource anywhere on the box:
To be clear about the scope: the value is typed by whoever runs the command,
the source has to be a directory containing a
site/child, and the copy onlyhappens when the root is empty. It is not a way in from outside. It is a
sharp edge on a command that runs as root and copies into a directory a web
server is about to publish, and
templates.mjshad already decided thisvalue should not be able to name a path.
The fix
One exported helper,
chooseTemplate, checked before anything is written:--emptystill wins, and no--templatestill means the default starter.--templatewith no value, or with a value that starts with-, is an errorrather than a starter name.
classifySourcefromtemplates.mjs— the existingrule, not a new one — before it goes anywhere near a path.
listTemplates(), and the error names the onesthat do exist, since the realistic case is off by one character:
I ran
moshcode template listand--emptybefore putting them in thatmessage; both do what it says.
Tests
Four added to
test/serve.test.mjs, including a control that a valid--template caddy-staticstill seeds from the right directory.Fail-before was checked with the import of the new export removed, so the
behaviour test ran against the unfixed source rather than failing to link:
test 11 fails before and passes after, with all ten controls green both ways.
Full suite: 909 tests, 720 pass, 0 fail, 189 skipped (main is 905/716/0/189
on 053ec57).
Touches
src/serve.mjsandtest/serve.test.mjsonly — no overlap with #223,#227, #228, #229 or #230.