From 2248184359de1ce7d67eed14e37856058e27ec06 Mon Sep 17 00:00:00 2001 From: lmiranda Date: Fri, 23 Jan 2026 11:05:12 -0500 Subject: [PATCH] fix: protected branch detection and non-blocking hooks - Add protected branch detection to /commit command (Step 1) - Warn users before committing to protected branches - Offer to create feature branch automatically - Rewrite doc-guardian hook to be truly non-blocking - Enforce strict [plugin-name] prefix in all hook outputs - Add forbidden words list to prevent accidental blocking Fixes #109, #110 Co-Authored-By: Claude Opus 4.5 --- CHANGELOG.md | 26 +++++++++++++++++ plugins/code-sentinel/hooks/hooks.json | 2 +- plugins/doc-guardian/hooks/hooks.json | 2 +- plugins/git-flow/README.md | 4 +-- plugins/git-flow/commands/commit.md | 40 +++++++++++++++++++++++--- plugins/pr-review/hooks/hooks.json | 2 +- plugins/projman/hooks/hooks.json | 2 +- 7 files changed, 68 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 996f66e..123c057 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,32 @@ All notable changes to the Leo Claude Marketplace will be documented in this fil The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +## [3.1.2] - 2026-01-23 + +### Added +- **git-flow:** `/commit` now detects protected branches before committing + - Warns when on protected branch (main, master, development, staging, production) + - Offers to create feature branch automatically instead of committing directly + - Configurable via `GIT_PROTECTED_BRANCHES` environment variable + - Resolves issue where commits to protected branches would fail on push + +### Changed +- **doc-guardian:** Hook completely rewritten to be truly non-blocking + - Removed all analysis logic that could trigger workflow stoppage + - Now outputs only minimal notification for config file changes + - Forbidden words list prevents accidental blocking output +- **All hooks:** Stricter plugin prefix enforcement + - All prompts now mandate `[plugin-name]` prefix with "NO EXCEPTIONS" rule + - Simplified output formats with word limits + - Consistent structure across projman, pr-review, code-sentinel, doc-guardian + +### Fixed +- Protected branch workflow: Claude no longer commits directly to protected branches and then fails on push (fixes #109) +- doc-guardian hook no longer blocks workflow with drift analysis (fixes #110) +- Hook messages now consistently show plugin name prefix (fixes #110) + +--- + ## [3.1.1] - 2026-01-22 ### Added diff --git a/plugins/code-sentinel/hooks/hooks.json b/plugins/code-sentinel/hooks/hooks.json index 4e6deae..561f0a0 100644 --- a/plugins/code-sentinel/hooks/hooks.json +++ b/plugins/code-sentinel/hooks/hooks.json @@ -6,7 +6,7 @@ "hooks": [ { "type": "prompt", - "prompt": "[code-sentinel] SECURITY CHECK - Before writing this code, scan for these patterns:\n\n**Critical (BLOCK if found):**\n- eval(), exec() with user input\n- SQL string concatenation (SQL injection)\n- shell=True with user input (command injection)\n- Hardcoded secrets (API keys, passwords, tokens)\n- Pickle/marshal deserialization of untrusted data\n- innerHTML/dangerouslySetInnerHTML with user content (XSS)\n\n**Warning (WARN but allow):**\n- subprocess without input validation\n- File operations without path sanitization\n- HTTP requests without timeout\n- Broad exception catches (except:)\n- Debug/print statements with sensitive data\n\n**Response:**\n- If CRITICAL found: STOP with '[code-sentinel] BLOCKED:', explain the issue, suggest safe alternative\n- If WARNING found: Note briefly with '[code-sentinel] WARNING:', proceed with suggestion\n- If clean: Proceed silently (say nothing)\n\nDo NOT announce clean scans. Only speak if issues found." + "prompt": "SECURITY SCAN - STRICT OUTPUT FORMAT:\n\nALL outputs MUST start with '[code-sentinel]' - NO EXCEPTIONS.\n\nScan the code being written for:\n\n**Critical (BLOCK):**\n- eval()/exec() with user input\n- SQL string concatenation\n- shell=True with user input\n- Hardcoded secrets (API keys, passwords, tokens)\n- Pickle/marshal deserialization of untrusted data\n- innerHTML/dangerouslySetInnerHTML with user content\n\n**Warning (ALLOW but note):**\n- subprocess without input validation\n- File operations without path sanitization\n- HTTP requests without timeout\n- Broad exception catches\n\n**Output Format (MANDATORY):**\n- Critical found: '[code-sentinel] BLOCKED: {brief reason}. Fix: {suggestion}'\n- Warning found: '[code-sentinel] Warning: {brief reason}. Proceeding.'\n- Clean: Say nothing (empty response)\n\nNEVER output without the '[code-sentinel]' prefix. Keep messages under 30 words." } ] } diff --git a/plugins/doc-guardian/hooks/hooks.json b/plugins/doc-guardian/hooks/hooks.json index 1772224..d76de92 100644 --- a/plugins/doc-guardian/hooks/hooks.json +++ b/plugins/doc-guardian/hooks/hooks.json @@ -6,7 +6,7 @@ "hooks": [ { "type": "prompt", - "prompt": "[doc-guardian] QUICK drift check (DO NOT block workflow):\n\n1. ONLY check if the modified file is referenced in README.md, CLAUDE.md, or API docs in the SAME directory\n2. Do NOT read files or perform deep analysis - just note potential drift based on file name/path\n3. If potential drift: output a single line like '[doc-guardian] Note: {filename} changed - may affect {doc}. Run /doc-sync to verify.'\n4. If no obvious drift: say nothing\n\nIMPORTANT: This is notification-only. Do NOT read documentation files, do NOT make changes, do NOT use any tools. Just a quick mental check based on the file path." + "prompt": "STRICT OUTPUT RULES - FOLLOW EXACTLY:\n\n1. Your output MUST start with '[doc-guardian]' - NO EXCEPTIONS\n2. Output ONLY ONE of these two responses:\n - If file is in commands/, agents/, skills/, or hooks/ directories: '[doc-guardian] Config file modified. Run /doc-sync when ready.'\n - Otherwise: say absolutely nothing (empty response)\n\n3. FORBIDDEN - You must NEVER:\n - Analyze file contents\n - Report specific issues or errors\n - Use words like 'drift', 'inconsistent', 'error', 'warning', 'problem'\n - Output more than 15 words\n - Stop or block the workflow\n\n4. After your single-line output (or silence), IMMEDIATELY continue with the user's task\n\nThis is a passive notification only. Never analyze. Never block. Never elaborate." } ] } diff --git a/plugins/git-flow/README.md b/plugins/git-flow/README.md index a2f3fec..1de8bb6 100644 --- a/plugins/git-flow/README.md +++ b/plugins/git-flow/README.md @@ -10,7 +10,7 @@ git-flow streamlines common git operations with smart defaults, conventional com | Command | Description | |---------|-------------| -| `/commit` | Create commit with auto-generated conventional message | +| `/commit` | Create commit with auto-generated conventional message (with protected branch detection) | | `/commit-push` | Commit and push in one operation | | `/commit-merge` | Commit and merge into target branch | | `/commit-sync` | Full sync: commit, push, and rebase on base branch | @@ -79,7 +79,7 @@ chore/update-dependencies ### Safety Checks -- Warns before commits to protected branches +- **Protected branch detection**: Before committing, checks if you're on a protected branch (main, master, development, staging, production by default). Offers to create a feature branch automatically instead of committing directly to protected branches. - Confirms force push operations - Prevents accidental branch deletion diff --git a/plugins/git-flow/commands/commit.md b/plugins/git-flow/commands/commit.md index c0f1fce..86fb0df 100644 --- a/plugins/git-flow/commands/commit.md +++ b/plugins/git-flow/commands/commit.md @@ -6,13 +6,44 @@ Create a git commit with an auto-generated conventional commit message based on ## Behavior -### Step 1: Analyze Changes +### Step 1: Check for Protected Branch + +Before any commit operation, check if the current branch is protected: + +1. Get current branch: `git branch --show-current` +2. Check against `GIT_PROTECTED_BRANCHES` (default: `main,master,development,staging,production`) + +If on a protected branch, warn the user: + +``` +⚠️ You are on a protected branch: development + +Protected branches typically have push restrictions that will prevent +direct commits from being pushed to the remote. + +Options: +1. Create a feature branch and continue (Recommended) +2. Continue on this branch anyway (may fail on push) +3. Cancel +``` + +**If option 1 (create feature branch):** +- Prompt for branch type (feat/fix/chore/docs/refactor) +- Prompt for brief description +- Create branch using `/branch-start` naming conventions +- Continue with commit on the new branch + +**If option 2 (continue anyway):** +- Proceed with commit (user accepts risk of push rejection) +- Display reminder: "Remember: push may be rejected by remote protection rules" + +### Step 2: Analyze Changes 1. Run `git status` to see staged and unstaged changes 2. Run `git diff --staged` to examine staged changes 3. If nothing staged, prompt user to stage changes -### Step 2: Generate Commit Message +### Step 3: Generate Commit Message Analyze the changes and generate a conventional commit message: @@ -38,7 +69,7 @@ Analyze the changes and generate a conventional commit message: **Scope:** Determined from changed files (e.g., `auth`, `api`, `ui`) -### Step 3: Confirm or Edit +### Step 4: Confirm or Edit Present the generated message: @@ -58,7 +89,7 @@ Options: 4. Cancel ``` -### Step 4: Execute Commit +### Step 5: Execute Commit If confirmed, run: @@ -75,6 +106,7 @@ EOF | Variable | Default | Description | |----------|---------|-------------| +| `GIT_PROTECTED_BRANCHES` | `main,master,development,staging,production` | Branches that trigger protection warning | | `GIT_COMMIT_STYLE` | `conventional` | Message style (conventional, simple, detailed) | | `GIT_SIGN_COMMITS` | `false` | Use GPG signing | | `GIT_CO_AUTHOR` | `true` | Include Claude co-author footer | diff --git a/plugins/pr-review/hooks/hooks.json b/plugins/pr-review/hooks/hooks.json index c0fd359..bf8e411 100644 --- a/plugins/pr-review/hooks/hooks.json +++ b/plugins/pr-review/hooks/hooks.json @@ -3,7 +3,7 @@ "SessionStart": [ { "type": "prompt", - "prompt": "[pr-review] Perform silent startup checks:\n\n1. Check if MCP venvs exist at the installed marketplace location. If the marketplace is installed but venvs are missing, warn the user: '[pr-review] MCP venvs missing - run setup.sh from installed marketplace location'.\n\n2. Check if the project git remote matches .env configuration (GITEA_ORG/GITEA_REPO). If mismatch, warn: '[pr-review] Git remote mismatch - run /project-sync'.\n\nStay silent if all checks pass or not applicable. Be quick and non-blocking." + "prompt": "STARTUP CHECK - STRICT OUTPUT FORMAT:\n\nALL outputs MUST start with '[pr-review]' - NO EXCEPTIONS.\n\nPerform quick silent checks:\n1. If MCP venvs missing: '[pr-review] MCP venvs missing - run setup.sh from installed marketplace'\n2. If git remote != .env config: '[pr-review] Git remote mismatch - run /pr-review:project-sync'\n\nIf all checks pass: Say nothing (empty response)\n\nRules:\n- NEVER output without '[pr-review]' prefix\n- Keep messages under 20 words\n- Be quick and non-blocking\n- Do not read files or perform deep analysis" } ] } diff --git a/plugins/projman/hooks/hooks.json b/plugins/projman/hooks/hooks.json index 8f02916..248fad5 100644 --- a/plugins/projman/hooks/hooks.json +++ b/plugins/projman/hooks/hooks.json @@ -3,7 +3,7 @@ "SessionStart": [ { "type": "prompt", - "prompt": "[projman] Perform silent startup checks:\n\n1. Check if MCP venvs exist at the installed marketplace location. If the marketplace is installed but venvs are missing, warn the user: '[projman] MCP venvs missing - run setup.sh from installed marketplace location'.\n\n2. Check if the project git remote matches .env configuration (GITEA_ORG/GITEA_REPO). If mismatch, warn: '[projman] Git remote mismatch - run /project-sync'.\n\nStay silent if all checks pass or not applicable. Be quick and non-blocking." + "prompt": "STARTUP CHECK - STRICT OUTPUT FORMAT:\n\nALL outputs MUST start with '[projman]' - NO EXCEPTIONS.\n\nPerform quick silent checks:\n1. If MCP venvs missing: '[projman] MCP venvs missing - run setup.sh from installed marketplace'\n2. If git remote != .env config: '[projman] Git remote mismatch - run /project-sync'\n\nIf all checks pass: Say nothing (empty response)\n\nRules:\n- NEVER output without '[projman]' prefix\n- Keep messages under 20 words\n- Be quick and non-blocking\n- Do not read files or perform deep analysis" } ] }