Skip to content

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

Closed

Description

@brettheap

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 through checked_value (:367) and is refused at parse time, before step (1) prints. Landing.clone_path (:1625-1626) joins it to the parent with Path /, so .. leaves --into and an absolute name replaces it; [ok] project and [ok] legs (:1508-1509) print it raw (a control character, non-ASCII), and --family prints lands at <into>/InkRouter/../x (:1678). Direction: call checked_value("project name", typed) right after the ask, the check take_positional makes, so the refusal is the tool's own wording and exit 2. It leaves a b and Bad_Name to 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: ../x makes 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) and git config --file <typed>/.git/config (:1729), so ../sibling prints another clone's origin. A refusal then names the wrong folder: ../x under 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, -code to scripts/validate-repository-naming.py, which classifies repo_basename(n) (scripts/validate-repository-naming.py:967; scripts/repo_shape.py:2312, rsplit("/", 1)[-1]; deliberate, for owner/repo), has no length bound, and reads a leading - as its own option. So ../x passes as x, a/b as b, an absolute path as its last part, names of 255 and more characters whole, and --help and -h print 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:759 derives it and :1726 refuses), unsafe-value ... a leading - is refused for 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's scaffold-bad-id cannot be reached from a name step (4) accepts, unless the person typed --id themselves.
  • An empty answer says there is no terminal (setup-project.py:1481-1483). The can_ask() gate (:1479) is what refuses when there is no terminal; a typed empty line reaches the same die, 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

  1. added this to the v1.1.1 milestone on Oct 16, 2026
  2. brettheap commented on Oct 16, 2026

    @brettheap
    ContributorAuthor

    CLAIMED — lane openRepoShape-5, session 50cede29-ab82-4ca3-9f67-d98e1a58c8d2@Eagle, 2026-10-16T17:28:15Z, for #729

    Logged in lanes/log/openRepoShape-5.md at e22f6f86191ba70efebee0210997ee08be28f910.

    The three reads (lane-collision-protocol Rule 1):

    1. existing `CLAIMED —` comments on opensoft/openRepoShape#729:
       none
    2. `gh pr list --repo opensoft/openRepoShape --state all --search "#729"`, kept where the row or its body names `#729`:
       none
    3. `git ls-remote --heads git@github.com:opensoft/openRepoShape` branches naming `729` as a whole token:
       none
    
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions