Skip to content

fix(scripts): prevent nested scaffolding and fix target resolution - #15

Merged
menil merged 1 commit into
mainfrom
fix/scaffolding-target-resolution
Oct 19, 2026
Merged

menil merged 1 commit into
mainfrom
fix/scaffolding-target-resolution

Conversation

@menil

@menil menil commented Oct 19, 2026

Copy link
Copy Markdown
Owner

🧠 AI Decision Record: View Architecture & Reasoning on GitHub

Summary

When scripts/create-project.sh was invoked from within the template repository with a bare project name (e.g. ./scripts/create-project.sh wisprflow-muteme-ptt-bridge), it resolved target destinations relative to $PWD, creating downstream repositories nested directly inside the template repository.

This created stray nested .git repositories (such as ./sandbox), which broke subsequent Copier invocations: Copier's VCS cloning logic attempted to stage dirty changes via git add -A, adding untracked nested repos as gitlinks without .gitmodules entries, fatally crashing on git submodule update:

fatal: No url found for submodule path '<path>' in .gitmodules

Key Changes

  1. Bare-Name Sibling Resolution:
    • When executed from within the template repository with a bare project name (excluding . and ..), automatically resolves the target to a sibling directory (../<name>), aligning with standard multi-repo workspace structures.
    • Normalizes trailing slashes (e.g. my-app/ -> my-app).
  2. Pure Pre-Validation Without Directory Mutation:
    • Walks up to the deepest existing ancestor directory to validate that the prospective target does not resolve inside the template repository before calling mkdir -p.
    • Completely eliminates directory leaks (e.g. ./nested/sub) on invalid target paths without relying on post-creation rollback.
  3. Pre-Flight Nested Repository Scan:
    • Moved before filesystem creation and template cloning.
    • Supports regular repositories, Git worktrees, and submodules (-e "$TEMPLATE_SRC/.git").
    • Uses -prune for .git, .direnv, .venv, and node_modules to avoid deep object graph traversals.
  4. Enhanced Test Suite & Documentation:
    • Expanded Justfile (test-template recipe) to verify rejection of ., shallow paths, and multi-level paths inside the template repository without leaving disk artifacts, and verified that pre-flight scans catch nested .git folders.
    • Updated CLI --help text and README.md to document sibling resolution behavior.

Verification

  • nix-shell --run "just validate" passed all linters, formatting, and Copier generation tests.
  • Tested end-to-end with ./scripts/create-project.sh --dry-run wisprflow-muteme-ptt-bridge.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review Summary

Needs Attention (1 issue)

  1. [Correctness] Bash pattern matching bug in path resolution condition - scripts/create-project.sh:177
    The condition uses quoted glob pattern "$TEMPLATE_REAL_DIR"/* which prevents bash from recognizing it as a pattern. The second part of the OR condition will never match. Change to unquoted pattern: $CURRENT_DIR == $TEMPLATE_REAL_DIR/* for proper glob expansion.

Suggestions (3 items)

  1. [Maintainability] Extract path validation logic into separate functions (HIGH impact, MED effort)
    Lines 145-219 contain complex interrelated validation logic. Breaking this into functions like validate_nested_git(), resolve_target_path(), and validate_target_containment() would improve readability and testability.

  2. [Simplification] Reconsider necessity of dual-stage validation (MED impact, MED effort)
    The combination of pre-validation (lines 181-205) and post-creation fallback check (lines 211-219) adds complexity. Evaluate whether the post-creation check is actually necessary given the thorough pre-validation logic, or if it could be consolidated.

  3. [Documentation] Add comments clarifying the exact scenarios being prevented (LOW impact, LOW effort)
    While comments explain the technical issues (Git submodule errors, nested git corruption), a brief note about the specific user scenarios (e.g., accidental scaffolding inside template repo) would help maintainers understand the threat model.

All Clear

  • Pass 1 (Correctness & Logic): Nested git detection, sibling resolution logic, and ancestor validation are sound (modulo the pattern matching issue).
  • Pass 4 (Security): No credentials, injection vulnerabilities, or sensitive information leaks detected. Path validation prevents directory traversal.
  • Pass 6 (Test Quality): Good edge case coverage including filesystem mutation prevention and nested git detection.
  • Pass 7 (Performance): Appropriate use of find exclusions and bounded loop logic.
  • Pass 10 (PII Detection): No personally identifiable information found.

Verdict: Needs Work

The bash pattern matching bug on line 177 is a correctness issue that will cause the sibling directory resolution feature to fail silently in its intended use case (when running from within the template directory). This must be fixed before merging.

Comment thread scripts/create-project.sh Resolved
When create-project.sh was executed from within the template directory
with a bare project name (e.g. 'wisprflow-muteme-ptt-bridge'), it
resolved the target path directly inside the template repository. This
left stray nested git repositories that caused Copier to fail on
subsequent invocations with 'fatal: No url found for submodule path in
.gitmodules'.

This change:
- Resolves bare target names to the template's sibling directory.
- Excludes '.' and '..' and normalizes target path formatting.
- Validates target containment prior to creating directories on disk.
- Runs pre-flight checks with pruning for nested git repos.
- Expands Justfile test assertions and updates README and CLI help.

AI-Reasoning: https://github.com/menil/project-template/blob/ai-reasoning/fix-scaffolding-target-resolution.md
@menil
menil force-pushed the fix/scaffolding-target-resolution branch from 19b0ac4 to c7eec26 Compare October 19, 2026 05:49
@menil

menil commented Oct 19, 2026

Copy link
Copy Markdown
Owner Author

Addressed review feedback: the glob pattern matching on line 177 has been fixed in commit c7eec26. Sibling resolution and path containment validation are tested and verified via just validate.

@menil
menil merged commit 14eca85 into main Oct 19, 2026
1 check passed
@menil
menil deleted the fix/scaffolding-target-resolution branch October 19, 2026 05:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant