Conversation
Replace the Python-based zenable-mcp package (installed via uvx) with the compiled Zenable CLI binary from cli.zenable.app. The CLI is now auto-installed during cookiecutter generation using the official install script, with curl/wget fallback and non-interactive mode. Also fix trufflehog pre-commit hook to work in git worktrees by resolving the repo root via git-common-dir. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
I've got 2 comments for you to consider
Reviewed with 🤟 by Zenable
.pre-commit-config.yaml
Outdated
| # Resolve the repo root via git-common-dir so this works in both normal repos and worktrees | ||
| # (trufflehog doesn't support .git files used by worktrees) | ||
| language: system | ||
| entry: bash -c 'trufflehog git "file://$(cd "$(git rev-parse --git-common-dir)/.." && pwd)" --branch "$(git rev-parse --abbrev-ref HEAD)" --since-commit main~1 --no-verification --fail' |
There was a problem hiding this comment.
The --branch flag passed to trufflehog may not correctly scope the scan. When HEAD is detached (e.g., in CI), git rev-parse --abbrev-ref HEAD returns HEAD literally, which trufflehog may interpret incorrectly. Also, the --since-commit main~1 combined with --branch could cause issues if main doesn't exist in the current context (e.g., a fresh worktree or shallow clone).
Consider using --since-commit HEAD~1 instead of main~1 to avoid dependency on the main branch existing locally, or guard against detached HEAD:
Suggested change
| entry: bash -c 'trufflehog git "file://$(cd "$(git rev-parse --git-common-dir)/.." && pwd)" --branch "$(git rev-parse --abbrev-ref HEAD)" --since-commit main~1 --no-verification --fail' | |
| entry: bash -c 'BRANCH=$(git rev-parse --abbrev-ref HEAD); [ "$BRANCH" = "HEAD" ] && BRANCH=$(git rev-parse HEAD); trufflehog git "file://$(cd "$(git rev-parse --git-common-dir)/.." && pwd)" --branch "$BRANCH" --since-commit HEAD~1 --no-verification --fail' |
Why did I show this?
Category: bug
Comment Quality: high
Based on general best practices
Tools used:
get_file_lines,{'file_path': '.github/linters/lychee.toml', 'start_line': '1', 'end_line': '200'}get_file_lines,{'file_path': '.github/linters/cspell.config.js', 'start_line': '1', 'end_line': '200'}list_changed_files,{'pattern': '**/cookiecutter*'}list_changed_files,{'pattern': ''}get_file_lines,{'file_path': 'hooks/post_gen_project.py', 'start_line': '1', 'end_line': '200'}get_file_lines,{'file_path': 'hooks/post_gen_project.py', 'start_line': '201', 'end_line': '380'}
Guard against detached HEAD by falling back to commit SHA. Use HEAD~1 instead of main~1 to avoid dependency on main branch existing locally. Install trufflehog binary in CI bootstrap since language: system requires it in PATH. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add docstring note that cli.zenable.app/install.sh performs cosign signature verification and checksum validation of the downloaded binary. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add conftest, docstrings, and taskfile to both the root and template dictionaries to fix cspell lint failures in CI. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add a windows-latest job that generates a project from the template and verifies it renders correctly with all defaults. The bootstrap action is updated to handle Windows by skipping Unix-specific steps (Homebrew, trufflehog, sha256sum) and using PowerShell alternatives. The smoke test verifies: - Project directory is created - Key files exist (pyproject.toml, Taskfile.yml, Dockerfile, etc.) - No unrendered cookiecutter variables remain - Git repo is initialized with at least one commit Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The template directory name contains pipe and quote characters
({{cookiecutter.project_name|replace(" ", "")}}) which are invalid
on NTFS. Set core.protectNTFS=false before checkout to allow these
paths in the Windows smoke test.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
actions/checkout overrides HOME with a temp directory, so global git config set in a prior step is lost. Use system-level config instead which persists across HOME changes. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
actions/checkout overrides both HOME and system config. Use the GIT_CONFIG_GLOBAL environment variable to point at a custom gitconfig file that disables core.protectNTFS, which persists through all of checkout's internal git operations. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Actionlint flags github.head_ref as potentially untrusted in inline scripts. Pass it through an environment variable instead. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Cookiecutter internally runs git clone, which also fails on NTFS due to the template directory name containing quote characters. Use GIT_CONFIG_COUNT/KEY/VALUE environment variables to inject core.protectNTFS=false into all git invocations without needing a config file or HOME directory. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Double-quote characters in the template directory name are fundamentally illegal on NTFS — no git config can work around this. Use cookiecutter's zip URL support instead, which extracts via Python's zipfile module and avoids NTFS filesystem restrictions. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Cookiecutter's zip URL support still fails because Python's zipfile extraction on Windows cannot create paths with double-quote characters. Download the zip manually, extract with Python (which can handle the entries internally), then point cookiecutter at the extracted directory. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Python's zipfile.extractall() strips double-quote characters from paths on Windows since NTFS rejects them. Use the \\?\ extended-length path prefix when extracting, which bypasses NTFS filename validation and allows the template directory with quotes to be created. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The \\?\ extended-length path prefix requires backslashes and no trailing slashes. Zip entries use forward slashes which must be converted to OS-native separators before joining with the prefix. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Double quotes are fundamentally illegal in NTFS paths — even the \\?\
extended-length prefix cannot work around this. Replace " with ' during
zip extraction, which is safe because Jinja2 treats both quote types
identically: replace(" ", "") and replace(' ', '') produce the same
output.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use Git Bash (available on all Windows runners) for the zip download and extraction. Git Bash's unzip may handle NTFS-illegal characters differently than Python's os.makedirs through MSYS2's path translation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…tter
The template directory contains | and " which are illegal on NTFS.
Extract the zip with unzip (which handles these in MSYS2), then rename
the directory to {{cookiecutter.project_name}} which is NTFS-safe and
produces identical output for the default project name (no spaces).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
unzip silently skips entries with NTFS-illegal chars. Use Python's
zipfile to extract all entries, renaming any directory containing
{{cookiecutter. to {{cookiecutter.project_name}} which is NTFS-safe
and renders identically for the default project name.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fetch release metadata from cli.zenable.app/zenable/latest and verify the install.sh SHA-256 checksum before piping it to bash. Uses Python stdlib (urllib.request, hashlib) instead of curl/wget for downloading. The install script itself also performs cosign signature verification of the binary it downloads, providing defense in depth. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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.
Summary
uvx zenable-mcp@latestwith the compiled Zenable CLI binary fromcli.zenable.appgit-common-dirTest plan
zenable installruns and configures IDE integrationspre-commit run --all-filesto verify all hooks passzenablepre-installed to verify the install script flow🤖 Generated with Claude Code