Skip to content

fix: replace <PACK> placeholders, harden path traversal checks, strengthen empty-list tests#52

Open
Copilot wants to merge 2 commits intomainfrom
copilot/update-pack-variable-reference
Open

fix: replace <PACK> placeholders, harden path traversal checks, strengthen empty-list tests#52
Copilot wants to merge 2 commits intomainfrom
copilot/update-pack-variable-reference

Conversation

Copy link
Copy Markdown

Copilot AI commented Apr 22, 2026

Several issues across the agent script, CLI validation, and tests: literal <PACK> placeholders in the pack-validator agent rendered commands non-functional; .. path components were not blocked in spec/project name validation; and empty-list tests for hooks/validations lacked subprocess mock assertions.

.claude/agents/pack-validator.md

  • Wrap the validation chain in a for PACK in $(git diff ...) loop — <PACK> was a literal string, making every nboot apply/diff call invalid
  • Update pack_snake=$(echo "$PACK" | ...) to use the loop variable
  • Remove 2>/dev/null stderr suppression from the first pytest invocation

src/navi_bootstrap/cli.py

  • Spec name (apply/diff): replace exact {".", ".."} membership check with ".." in stripped_name substring check; add startswith(".") guard; apply consistent name.strip() normalization
  • Project name (new): add ".." in name substring check; apply name.strip() normalization — both sites now use identical rules
# Before — misses "foo..bar", "foo/../bar", "  .."
if not name or "/" in name or "\\" in name:  # spec
if not name or "/" in name or "\\" in name or name.startswith("."):  # project

# After — consistent substring + strip across both sites
stripped_name = name.strip() if isinstance(name, str) else ""
if not stripped_name or "/" in stripped_name or "\\" in stripped_name
        or ".." in stripped_name or stripped_name.startswith("."):

Tests

  • test_empty_hooks / test_empty_validations: add @patch + mock_run.assert_not_called() — previously the tests only checked the return value, not that no subprocess was spawned
  • test_detects_async_test_functions: add assert result["test_framework"] == "pytest" to cover the previously untested field
Original prompt
Please apply the following diffs and create a pull request.
Once the PR is ready, give it a title based on the messages of the fixes being applied.

[{"message":"The placeholder `<PACK>` should be replaced with an actual variable reference like `$PACK` or `${PACK}` for these commands to execute properly. Currently, these commands would attempt to use the literal string '<PACK>' as the pack name.","fixFiles":[{"filePath":".claude/agents/pack-validator.md","diff":"diff --git a/.claude/agents/pack-validator.md b/.claude/agents/pack-validator.md\n--- a/.claude/agents/pack-validator.md\n+++ b/.claude/agents/pack-validator.md\n@@ -17,17 +17,19 @@\n 2. For each changed pack, run the full validation chain:\n \n    ```bash\n-   uv run nboot validate --spec nboot-spec.json\n-   scratch=$(mktemp -d -t nboot-scratch-XXXX)\n-   uv run nboot new \"$scratch\"\n-   uv run nboot apply --spec nboot-spec.json --pack <PACK> --target \"$scratch\"\n-   uv run nboot diff  --spec nboot-spec.json --pack <PACK> --target \"$scratch\"\n+   for PACK in $(git diff --name-only origin/main...HEAD | grep '^packs/' | cut -d'/' -f2 | sort -u); do\n+     uv run nboot validate --spec nboot-spec.json\n+     scratch=$(mktemp -d -t nboot-scratch-XXXX)\n+     uv run nboot new \"$scratch\"\n+     uv run nboot apply --spec nboot-spec.json --pack \"$PACK\" --target \"$scratch\"\n+     uv run nboot diff  --spec nboot-spec.json --pack \"$PACK\" --target \"$scratch\"\n+   done\n    ```\n \n 3. Run the pack-specific test:\n \n    ```bash\n-   pack_snake=$(echo <PACK> | tr '-' '_')\n+   pack_snake=$(echo \"$PACK\" | tr '-' '_')\n    uv run pytest tests/test_${pack_snake}_pack.py -v 2>/dev/null || \\\n      uv run pytest tests/ -k \"$pack_snake\" -v\n    ```\n"}]},{"message":"The placeholder `<PACK>` should be replaced with an actual variable reference like `$PACK` or `${PACK}` for the command to work correctly. Using angle brackets makes this a literal string rather than a variable substitution.","fixFiles":[{"filePath":".claude/agents/pack-validator.md","diff":"diff --git a/.claude/agents/pack-validator.md b/.claude/agents/pack-validator.md\n--- a/.claude/agents/pack-validator.md\n+++ b/.claude/agents/pack-validator.md\n@@ -27,7 +27,7 @@\n 3. Run the pack-specific test:\n \n    ```bash\n-   pack_snake=$(echo <PACK> | tr '-' '_')\n+   pack_snake=$(echo \"$PACK\" | tr '-' '_')\n    uv run pytest tests/test_${pack_snake}_pack.py -v 2>/dev/null || \\\n      uv run pytest tests/ -k \"$pack_snake\" -v\n    ```\n"}]},{"message":"The stderr redirection `2>/dev/null` on line 31 silently suppresses error messages from the first pytest command. Consider documenting why errors are hidden here, or remove the redirection to ensure error visibility for debugging purposes.","fixFiles":[{"filePath":".claude/agents/pack-validator.md","diff":"diff --git a/.claude/agents/pack-validator.md b/.claude/agents/pack-validator.md\n--- a/.claude/agents/pack-validator.md\n+++ b/.claude/agents/pack-validator.md\n@@ -28,7 +28,7 @@\n \n    ```bash\n    pack_snake=$(echo <PACK> | tr '-' '_')\n-   uv run pytest tests/test_${pack_snake}_pack.py -v 2>/dev/null || \\\n+   uv run pytest tests/test_${pack_snake}_pack.py -v || \\\n      uv run pytest tests/ -k \"$pack_snake\" -v\n    ```\n \n"}]},{"message":"The validation for spec name does not check for other potentially dangerous path components such as '..' which could lead to directory traversal attacks. Consider using Path().resolve() to normalize the path and verify it stays within expected boundaries, or add explicit checks for '..' sequences.","fixFiles":[{"filePath":"src/navi_bootstrap/cli.py","diff":"diff --git a/src/navi_bootstrap/cli.py b/src/navi_bootstrap/cli.py\n--- a/src/navi_bootstrap/cli.py\n+++ b/src/navi_bootstrap/cli.py\n@@ -116,12 +116,19 @@\n \n     if out is None:\n         name = spec_data[\"name\"]\n-        if not name or \"/\" in name or \"\\\\\" in name:\n+        stripped_name = name.strip() if isinstance(name, str) else \"\"\n+        if (\n+            not stripped_name\n+            or \"/\" in stripped_name\n+            or \"\\\\\" in stripped_name\n+            or stripped_name in {\".\", \"..\"}\n+        ):\n             raise click.ClickException(\n                 f\"Unsafe spec name {name!r} cannot be used as output directory. \"\n+                \"Name must be a non-empty single path segment and not '.' or '..'. \"\n                 \"Use --out to specify an explicit output path.\"\n             )\n-        output_dir = Path(name)\n+        output_dir = Path(stripped_name)\n     else:\n         output_dir = out\n \n"}]},{"message":"The validation for project name does not check for '..' sequences which could lead to directory traversal. Consider adding a check for '..' or using Path().resolve() to ensure the resulting path is safe and within expected boundaries.","fixFiles":[{"filePath":"src/navi_bootstrap/cli.py","diff":"diff --git a/src/navi_bootstrap/cli.py b/src/navi_bootstrap/cli...

…ngthen empty-list tests

Agent-Logs-Url: https://github.com/Project-Navi/navi-bootstrap/sessions/604f9871-000e-4f48-b728-1c2a85fe6c4c

Co-authored-by: Fieldnote-Echo <202828230+Fieldnote-Echo@users.noreply.github.com>
Copilot AI requested review from Copilot and removed request for Copilot April 22, 2026 03:45
Copilot AI changed the title [WIP] Fix placeholder in pack validation commands fix: replace <PACK> placeholders, harden path traversal checks, strengthen empty-list tests Apr 22, 2026
@project-navi-bot Navi Bot (project-navi-bot) marked this pull request as ready for review April 22, 2026 04:09
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.

2 participants