Repository navigation
setup-project.py: the project name typed at the prompt is checked as --project is, before step (3) builds the clone path from it, so ../x, a/b, .. and --help are refused by name and not by a probe folder, an --id hint or a usage dump (#459) #729
Description
Goal: a project name typed at the project name prompt is held to the check the same name gets as --project or as the positional, before step (3) asks the disk about a path built from it, so no typed name reaches a folder outside --into, step (4)'s validator or the scaffold's plan.
Filed by lane openRepoShape-5, from lane 4's L4-21 (HANDED; lane 4's #473 issuecomment-6217696859), which lane 4 wrote on #459 (issuecomment-6147244779, 2026-10-13): "A project name typed at the interactive prompt is not checked against the name pattern before step (3) builds the clone path from it. Step (3) only reads that path, and step (4) catches a bad name." Measured on main de926142 through a pty with the real gh unreachable: the first sentence holds, and the other two no longer do.
Lines (path:line at main de926142)
- L4-21, the typed name is not checked (
setup-project.py:1480).opts.project = ask(...)is used as typed. The same value as--project(VALUE_FLAGS:455) or as the positional (take_positional:531) goes throughchecked_value(:367) and is refused at parse time, before step (1) prints.Landing.clone_path(:1625-1626) joins it to the parent withPath /, so..leaves--intoand an absolute name replaces it;[ok] projectand[ok] legs(:1508-1509) print it raw (a control character, non-ASCII), and--familyprintslands at <into>/InkRouter/../x(:1678). Direction: callchecked_value("project name", typed)right after theask, the checktake_positionalmakes, so the refusal is the tool's own wording and exit 2. It leavesa bandBad_Nameto step (4):NAME_RE(:332) is deliberately permissive and the policy decides those. - "Step (3) only reads that path" has been false since setup-project.py: step (3) passes an unwritable parent or a missing drive, and step (4) shows a chain the plan verifies as
[declared-unverified]#608 (abb956e6).refuse_a_parent_nobody_can_write_in(:1894, probe :1929) makes and removes.openreposhape-write-probe-*in the nearest existing folder above the typed path. Measured:../xmakes it in the parent of--into; an absolute name in that name's own folder; both are removed, nothing stays. Step (3) also reads outside:os.listdir(:1778) andgit config --file <typed>/.git/config(:1729), so../siblingprints another clone'sorigin. A refusal then names the wrong folder:../xunder an unwritable parent says "<into>/..is a folder you cannot write in ... Choose another --into"...says "<into>/..already exists ... Move it", and.says "<into>... is an empty directory. Move or delete it". Direction: the check above closes all of these; nothing in step (3) needs to change. - Step (4) does not catch these.
check_names(:2098-2101) passes<project>,-spec,-codetoscripts/validate-repository-naming.py, which classifiesrepo_basename(n)(scripts/validate-repository-naming.py:967;scripts/repo_shape.py:2312,rsplit("/", 1)[-1]; deliberate, forowner/repo), has no length bound, and reads a leading-as its own option. So../xpasses asx,a/basb, an absolute path as its last part, names of 255 and more characters whole, and--helpand-hprint the validator's help and exit 0. The scaffold's plan refuses them at step (5), before anything is created, in words that do not fit:scaffold-bad-id: --id '../x' must match ... Remediation: pass an explicit lowercase --id(nobody passed--id;scaffold-project.py:759derives it and :1726 refuses),unsafe-value ... a leading - is refusedfor 256 characters and more (scripts/repo_shape.py:2218), and a usage dump for-h. Direction: the prompt check; leave the validator's basename rule alone. After it, the scaffold'sscaffold-bad-idcannot be reached from a name step (4) accepts, unless the person typed--idthemselves. - An empty answer says there is no terminal (
setup-project.py:1481-1483). Thecan_ask()gate (:1479) is what refuses when there is no terminal; a typed empty line reaches the samedie, after the full usage text, and says "no terminal to ask on". Direction: a typed empty line gets its own refusal ("no project name was typed; nothing was created", exit 2, no usage dump).
Verify: a new test file driving run_in_a_terminal (tests/conftest.py:1273) as tests/test_setup_project_py.py:2813-2825 does for Sample, POSIX only (PTY_SKIP). For each of ../x, a/b, an absolute path under tmp_path, .., ., -x, --help, a name with a control character (quoted with ^V), 256 characters and an empty line: exit 2, the refusal names project name and the value via ascii(), (4) naming policy is not printed, nothing exists under --into or its parent. For Bad_Name and a b: exit 1 at step (4), as now. A parity assertion that the refusal for a typed name is the --project refusal with project name as its subject. Run tests/test_setup_project_py.py, tests/test_setup_sh.py and the new file on Linux.
Overlaps. Branches on origin that touch setup-project.py: lane 4's fix/696-setup-family-folder (4054ffd, #696) edits family_folder_here (hunks at :1581 and :1613), disjoint from :1480. Nothing on origin touches tests/test_setup_project_py.py or tests/test_setup_sh.py; fix/645-fixture-copy-maintenance-race and fix/663-non-utf8-name-tests edit tests/conftest.py, which this issue does not need. No pinned file changes. No README or handbook sentence is made false (--project's help already says "Prompted for when omitted and a terminal is attached").
Milestone: v1.1.1. Nothing is created and nothing stays on disk, so it does not block v1.1.0; the probe write is the one piece new since v1.0.0 (#608), and it leaves nothing.
Mark L4-21 → this issue on #459, and tick it there when this closes.
🤖 Generated with Claude Code
Activity
brettheap commentedon Oct 16, 2026
CLAIMED — lane openRepoShape-5, session 50cede29-ab82-4ca3-9f67-d98e1a58c8d2@Eagle, 2026-10-16T17:28:15Z, for #729
Logged in
lanes/log/openRepoShape-5.mdate22f6f86191ba70efebee0210997ee08be28f910.The three reads (lane-collision-protocol Rule 1):
setup-project.py: the typed project name's prompt, empty-line refusal…
setup-project.py: a project name typed at the prompt is checked as `-…
scaffold-project.py, adopt-project.py and setup-project.py: the plan …