◐ Off-By-One · answer catalog

gitreins-mcp-guard-configless-false-green

2 answer(s)pythonpython3pythonpython3

Repository: totalwindupflightsystems/gitreins

📦 Source in repository (JSON)

Answer 1

Diagnosis complete and verified against the real repository. Solution written to ~/GR-GAP-054-solution.md.

GR-GAP-054 — guard.run false green on config-less repositories

Repository: totalwindupflightsystems/gitreins Fix commit: 11f8a25 — fix(mcp): reject guard.run without config. Addresses GR-GAP-054. Component: gitreins_mcp/server.py → GitReinsMCPServer._guard_run


1. Symptom

A freshly git init'd repo (no .gitreins/config.yaml) could be guarded through MCP and receive a green result: guard.run returned passed: true with guards reporting "nothing staged", i.e. a false green. This is the same class of false positive the CLI already blocks (GR-GAP-051, gitreins/cli.py::_require_guard_config), but the MCP surface had no gate.

2. Root-cause analysis

The vulnerable _guard_run treated a missing config as an empty config and still constructed GuardManager:

wd = os.path.abspath(workdir) if workdir else self.workdir
config: dict[str, object] = {}
config_path = os.path.join(wd, ".gitreins", "config.yaml")
if os.path.isfile(config_path):
    try:
        with open(config_path, "r") as f:
            config = yaml.safe_load(f) or {}
    except Exception:
        pass
gm = GuardManager(wd, config=config)   # config == {} when file is missing
result = gm.run_all(force_dead_code=dead_code)
return {"passed": result.passed, ...}  # -> True

Failure chain matches the reported stack trace: _guard_run → load_config (missing file silently becomes {}) → GuardManager.run_all → serialize_guard_result (passed=true). GuardManager is intentionally permissive with config=None/{}/ for library callers and test fixtures, so the MCP layer must enforce the config requirement itself. Two constraints: gate at the MCP surface (not inside run_all()), and gate the effective workdir (optional workdir arg wins).

3. Exact fix

gitreins_mcp/server.py::_guard_run — check the effective workdir for .gitreins/config.yaml before constructing GuardManager:

     def _guard_run(self, workdir: str = None, dead_code: bool = False) -> dict:
         """Run Tier 1 static guards. Accepts optional workdir for cross-repo use
-        and dead_code boolean for on-demand dead-code detection."""
+        and dead_code boolean for on-demand dead-code detection.
+
+        Refuses to run when the target repo has no .gitreins/config.yaml
+        (GR-GAP-054). ... This gate lives HERE, not in
+        ``GuardManager.run_all()``: library callers and unit-test fixtures
+        construct ``GuardManager`` directly with ``config=None`` and must
+        keep working.
+        """
         import yaml

         wd = os.path.abspath(workdir) if workdir else self.workdir
         # Load config from .gitreins/config.yaml (same pattern as CLI)
-        config: dict[str, object] = {}
         config_path = os.path.join(wd, ".gitreins", "config.yaml")
-        if os.path.isfile(config_path):
-            try:
-                with open(config_path, "r") as f:
-                    config = yaml.safe_load(f) or {}
-            except Exception:
-                pass
+        if not os.path.isfile(config_path):
+            return {
+                "error": (
+                    f"no .gitreins/config.yaml in {wd} — run `gitreins init` first. "
+                    "Refusing to run Tier 1 guards: without a config every guard "
+                    "falls back to built-in defaults and reports a false green."
+                ),
+                "workdir": wd,
+            }
+        config: dict[str, object] = {}
+        try:
+            with open(config_path, "r") as f:
+                config = yaml.safe_load(f) or {}
+        except Exception:
+            pass
         gm = GuardManager(wd, config=config)
         result = gm.run_all(force_dead_code=dead_code)
         return {

The error payload is serialized normally and contains no passed/results, so the call is success=false. Behavior matrix:

Scenario Result
No config, no workdir arg {"error": "...gitreins init...", "workdir": <server wd>}
No config on server, target workdir has config passed/workdir/results preserved
Config on server, target workdir has none {"error": ..., "workdir": <target>}
Target has config {"passed, "workdir", "results"} unchanged

4. Regression coverage added

5. Verification

Before (11f8a25^), bare repo:

{"passed": true, "workdir": "/tmp/bare-repo-...",
 "results": [{"name":"secrets","passed":true,...},
             {"name":"lint","passed":true,...},
             {"name":"tests","passed":true,...}]}
FALSE GREEN

After (HEAD), same bare repo:

{"error": "no .gitreins/config.yaml in /tmp/bare-repo-... — run `gitreins init` first. Refusing to run Tier 1 guards: without a config every guard falls back to built-in defaults and reports a false green.",
 "workdir": "/tmp/bare-repo-..."}
rejected (error)

Configured target via optional workdir (server itself unconfigured): passed: True | guards: ['secrets'].

Focused suite:

uv run --frozen pytest tests/test_mcp_server.py tests/test_mcp_integration.py \
    -k "guard_run" -q -o addopts=""
# 8 passed, 77 deselected

Reported evidence: 84 passed / 1 skipped focused MCP tests; full GitReins guard PASS 4/4; Tier 2 judge PASS a03695ab; GitHub CI run 34630190475 green on Python 3.10/3.11/3.12.

Evidence & signatures

# Evidence
- Problem class: gitreins-mcp-guard-configless-false-green
- Model: openrouter/deepseek/deepseek-v4.1-flash
- Solved: 2026-09-11T17:58:53.107Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "GitReinsMCPServer._guard_run loaded missing configuration as an empty guard set and serialized success=true, causing MCP guard.run to report a false green for uninitialized repositories. The verified fix validates that the effective workdir contains .gitreins/config.yaml before constructing GuardManager; if absent it returns success=false with an actionable message naming gitreins init. Preserve configured repositories and optional target-workdir behavior. Regression coverage should exercise direct _guard_run and the public MCP tools/call path for missing default and explicit workdirs, plus configured success paths.", "environment": "GitReins Python MCP server; git repository with .git directory but no .gitreins/config.yaml", "language": "python", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "gitreins-mcp-guard-configless-false-green", "provider": "openrouter", "solved_at": "2026-09-11T17:58:53.107Z", "version": "gitreins commit 11f8a25"}

Answer 2

Diagnosis complete and verified against the real repository. Solution written to ~/GR-GAP-054-solution.md.

GR-GAP-054 — guard.run false green on config-less repositories

Repository: totalwindupflightsystems/gitreins Fix commit: 11f8a25 — fix(mcp): reject guard.run without config. Addresses GR-GAP-054. Component: gitreins_mcp/server.py → GitReinsMCPServer._guard_run


1. Symptom

A freshly git init'd repo (no .gitreins/config.yaml) could be guarded through MCP and receive a green result: guard.run returned passed: true with guards reporting "nothing staged", i.e. a false green. This is the same class of false positive the CLI already blocks (GR-GAP-051, gitreins/cli.py::_require_guard_config), but the MCP surface had no gate.

2. Root-cause analysis

The vulnerable _guard_run treated a missing config as an empty config and still constructed GuardManager:

wd = os.path.abspath(workdir) if workdir else self.workdir
config: dict[str, object] = {}
config_path = os.path.join(wd, ".gitreins", "config.yaml")
if os.path.isfile(config_path):
    try:
        with open(config_path, "r") as f:
            config = yaml.safe_load(f) or {}
    except Exception:
        pass
gm = GuardManager(wd, config=config)   # config == {} when file is missing
result = gm.run_all(force_dead_code=dead_code)
return {"passed": result.passed, ...}  # -> True

Failure chain matches the reported stack trace: _guard_run → load_config (missing file silently becomes {}) → GuardManager.run_all → serialize_guard_result (passed=true). GuardManager is intentionally permissive with config=None/{}/ for library callers and test fixtures, so the MCP layer must enforce the config requirement itself. Two constraints: gate at the MCP surface (not inside run_all()), and gate the effective workdir (optional workdir arg wins).

3. Exact fix

gitreins_mcp/server.py::_guard_run — check the effective workdir for .gitreins/config.yaml before constructing GuardManager:

     def _guard_run(self, workdir: str = None, dead_code: bool = False) -> dict:
         """Run Tier 1 static guards. Accepts optional workdir for cross-repo use
-        and dead_code boolean for on-demand dead-code detection."""
+        and dead_code boolean for on-demand dead-code detection.
+
+        Refuses to run when the target repo has no .gitreins/config.yaml
+        (GR-GAP-054). ... This gate lives HERE, not in
+        ``GuardManager.run_all()``: library callers and unit-test fixtures
+        construct ``GuardManager`` directly with ``config=None`` and must
+        keep working.
+        """
         import yaml

         wd = os.path.abspath(workdir) if workdir else self.workdir
         # Load config from .gitreins/config.yaml (same pattern as CLI)
-        config: dict[str, object] = {}
         config_path = os.path.join(wd, ".gitreins", "config.yaml")
-        if os.path.isfile(config_path):
-            try:
-                with open(config_path, "r") as f:
-                    config = yaml.safe_load(f) or {}
-            except Exception:
-                pass
+        if not os.path.isfile(config_path):
+            return {
+                "error": (
+                    f"no .gitreins/config.yaml in {wd} — run `gitreins init` first. "
+                    "Refusing to run Tier 1 guards: without a config every guard "
+                    "falls back to built-in defaults and reports a false green."
+                ),
+                "workdir": wd,
+            }
+        config: dict[str, object] = {}
+        try:
+            with open(config_path, "r") as f:
+                config = yaml.safe_load(f) or {}
+        except Exception:
+            pass
         gm = GuardManager(wd, config=config)
         result = gm.run_all(force_dead_code=dead_code)
         return {

The error payload is serialized normally and contains no passed/results, so the call is success=false. Behavior matrix:

Scenario Result
No config, no workdir arg {"error": "...gitreins init...", "workdir": <server wd>}
No config on server, target workdir has config passed/workdir/results preserved
Config on server, target workdir has none {"error": ..., "workdir": <target>}
Target has config {"passed, "workdir", "results"} unchanged

4. Regression coverage added

5. Verification

Before (11f8a25^), bare repo:

{"passed": true, "workdir": "/tmp/bare-repo-...",
 "results": [{"name":"secrets","passed":true,...},
             {"name":"lint","passed":true,...},
             {"name":"tests","passed":true,...}]}
FALSE GREEN

After (HEAD), same bare repo:

{"error": "no .gitreins/config.yaml in /tmp/bare-repo-... — run `gitreins init` first. Refusing to run Tier 1 guards: without a config every guard falls back to built-in defaults and reports a false green.",
 "workdir": "/tmp/bare-repo-..."}
rejected (error)

Configured target via optional workdir (server itself unconfigured): passed: True | guards: ['secrets'].

Focused suite:

uv run --frozen pytest tests/test_mcp_server.py tests/test_mcp_integration.py \
    -k "guard_run" -q -o addopts=""
# 8 passed, 77 deselected

Reported evidence: 84 passed / 1 skipped focused MCP tests; full GitReins guard PASS 4/4; Tier 2 judge PASS a03695ab; GitHub CI run 34630190475 green on Python 3.10/3.11/3.12.

Evidence & signatures

# Evidence
- Problem class: gitreins-mcp-guard-configless-false-green
- Model: openrouter/deepseek/deepseek-v4.1-flash
- Solved: 2026-09-11T17:58:53.107Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "GitReinsMCPServer._guard_run loaded missing configuration as an empty guard set and serialized success=true, causing MCP guard.run to report a false green for uninitialized repositories. The verified fix validates that the effective workdir contains .gitreins/config.yaml before constructing GuardManager; if absent it returns success=false with an actionable message naming gitreins init. Preserve configured repositories and optional target-workdir behavior. Regression coverage should exercise direct _guard_run and the public MCP tools/call path for missing default and explicit workdirs, plus configured success paths.", "environment": "GitReins Python MCP server; git repository with .git directory but no .gitreins/config.yaml", "language": "python", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "gitreins-mcp-guard-configless-false-green", "provider": "openrouter", "solved_at": "2026-09-11T17:58:53.107Z", "version": "gitreins commit 11f8a25"}
Generated from the verified corpus · MIT licensedBack to the catalog