Skip to content

Handle malformed glab MR metadata JSON in _fetch_mr_data with recovery, retry, and mr_id command safeguards#25

Open
Copilot wants to merge 9 commits intomainfrom
copilot/fix-fetch-mr-data-json-error
Open

Handle malformed glab MR metadata JSON in _fetch_mr_data with recovery, retry, and mr_id command safeguards#25
Copilot wants to merge 9 commits intomainfrom
copilot/fix-fetch-mr-data-json-error

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 18, 2026

_fetch_mr_data assumed glab mr view -F json always returned valid JSON and could raise an uncaught JSONDecodeError, crashing the MCP tool path. This change hardens that boundary by adding JSON recovery and a single retry before returning a structured parse error, and adds defense-in-depth safeguards for mr_id command construction.

  • Error handling

    • Attempt to parse MR metadata JSON normally.
    • If parsing fails, attempt JSON recovery from noisy output (e.g., prefixed/suffixed non-JSON text).
    • If still unrecoverable, retry glab mr view -F json once and parse/recover again.
    • Return a stable tool error payload only when unrecoverable after retry:
      • success: false
      • error_type: "parse_error"
      • error: "Failed to parse MR metadata JSON."
  • Security hardening

    • Route MR metadata command construction through a validator-backed helper before subprocess execution.
    • Reuse the validated command for both initial and retry metadata fetches.
    • Preserve structured validation_error handling if command construction fails validation.
  • Regression coverage

    • Add/update focused test cases in test_fetch_mr_data.py for:
      • malformed JSON on both attempts returning parse_error
      • recoverable noisy JSON succeeding without an unnecessary retry
      • injection-like mr_id input being rejected before any subprocess call
    • Assert call counts to ensure retry behavior is correct and bounded.

Copilot AI requested review from Copilot and removed request for Copilot April 18, 2026 07:56
Copilot AI linked an issue Apr 18, 2026 that may be closed by this pull request
3 tasks
Agent-Logs-Url: https://github.com/nexiouscaliver/OmniForge/sessions/c6a3be97-1717-43f0-96a7-61f840a35a1f

Co-authored-by: nexiouscaliver <66136088+nexiouscaliver@users.noreply.github.com>
Copilot AI requested review from Copilot and removed request for Copilot April 18, 2026 07:57
Agent-Logs-Url: https://github.com/nexiouscaliver/OmniForge/sessions/c6a3be97-1717-43f0-96a7-61f840a35a1f

Co-authored-by: nexiouscaliver <66136088+nexiouscaliver@users.noreply.github.com>
Copilot AI requested review from Copilot and removed request for Copilot April 18, 2026 07:58
Copilot AI changed the title [WIP] Fix json.JSONDecodeError in _fetch_mr_data Handle malformed glab MR metadata JSON in _fetch_mr_data Apr 18, 2026
Copilot AI requested a review from nexiouscaliver April 18, 2026 08:00
@nexiouscaliver nexiouscaliver requested a review from Copilot April 18, 2026 08:02
Copy link
Copy Markdown
Owner

@nexiouscaliver nexiouscaliver left a comment

Choose a reason for hiding this comment

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

Try json recovery incase of parsing error and retry then if not recoverable then return error.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Hardens _fetch_mr_data against malformed JSON output from glab mr view -F json to prevent uncaught JSONDecodeError crashes and instead return a stable, structured tool error response.

Changes:

  • Wrap MR metadata JSON deserialization in try/except json.JSONDecodeError and return a structured parse_error payload on failure.
  • Add a regression test that simulates malformed glab JSON output and asserts the function exits early without downstream subprocess calls.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
plugins/omniforge/tools/omniforge_mcp_server.py Adds JSON parsing guardrail and returns a structured parse_error response instead of raising.
plugins/omniforge/tests/test_fetch_mr_data.py Adds test coverage for malformed MR metadata JSON and ensures no further subprocess calls occur.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copilot AI and others added 2 commits April 18, 2026 08:05
Agent-Logs-Url: https://github.com/nexiouscaliver/OmniForge/sessions/7f1bc4d3-bffd-4fd0-a315-4cd2244413ba

Co-authored-by: nexiouscaliver <66136088+nexiouscaliver@users.noreply.github.com>
Agent-Logs-Url: https://github.com/nexiouscaliver/OmniForge/sessions/7f1bc4d3-bffd-4fd0-a315-4cd2244413ba

Co-authored-by: nexiouscaliver <66136088+nexiouscaliver@users.noreply.github.com>
Copilot AI requested review from Copilot and removed request for Copilot April 18, 2026 08:06
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 18, 2026

Try json recovery incase of parsing error and retry then if not recoverable then return error.

Implemented in f99462c. _fetch_mr_data now attempts JSON recovery on parse failure, retries glab mr view -F json once if still not parseable, and only then returns parse_error when unrecoverable. Added tests for both retry-failure and recovery-success paths.

Copilot AI changed the title Handle malformed glab MR metadata JSON in _fetch_mr_data Handle malformed glab MR metadata JSON in _fetch_mr_data with recovery and retry Apr 18, 2026
Copilot AI requested a review from nexiouscaliver April 18, 2026 08:07
Copy link
Copy Markdown
Owner

@nexiouscaliver nexiouscaliver left a comment

Choose a reason for hiding this comment

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

In the recovery we inject mr_id (which is declared string) into cmd exec, kindly add safegards to prevent code injection using bash script in this variable and bypass security.

Copilot AI requested review from Copilot and removed request for Copilot April 18, 2026 08:15
Copilot AI requested review from Copilot and removed request for Copilot April 18, 2026 08:16
Agent-Logs-Url: https://github.com/nexiouscaliver/OmniForge/sessions/3dfb074c-b731-4c2e-a5f5-f3b750a91708

Co-authored-by: nexiouscaliver <66136088+nexiouscaliver@users.noreply.github.com>
Copilot AI requested review from Copilot and removed request for Copilot April 18, 2026 08:17
Agent-Logs-Url: https://github.com/nexiouscaliver/OmniForge/sessions/3dfb074c-b731-4c2e-a5f5-f3b750a91708

Co-authored-by: nexiouscaliver <66136088+nexiouscaliver@users.noreply.github.com>
Copilot AI requested review from Copilot and removed request for Copilot April 18, 2026 08:17
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 18, 2026

In the recovery we inject mr_id (which is declared string) into cmd exec, kindly add safegards to prevent code injection using bash script in this variable and bypass security.

Added in 54a5900 (with follow-up cleanup in 2c60c8b and typing/docs in 6a876e2). mr_id is now passed through a validator-backed command builder before glab mr view -F json execution, and there is a regression test (test_injection_like_mr_id_rejected_before_exec) proving injection-like IDs are rejected before any subprocess call.

Copilot AI changed the title Handle malformed glab MR metadata JSON in _fetch_mr_data with recovery and retry Handle malformed glab MR metadata JSON in _fetch_mr_data with recovery, retry, and mr_id command safeguards Apr 18, 2026
Copilot AI requested a review from nexiouscaliver April 18, 2026 08:19
@nexiouscaliver nexiouscaliver marked this pull request as ready for review April 18, 2026 08:24
Copilot AI review requested due to automatic review settings April 18, 2026 08:24
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +205 to +211
def parse_json_with_recovery(raw_json: str) -> tuple:
"""Parse JSON with recovery for prefixed/suffixed non-JSON text.

Returns:
tuple[bool, object | None]:
(True, parsed_json) when parsing succeeds, otherwise (False, None).
"""
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

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

parse_json_with_recovery advertises a structured return in the docstring (tuple[bool, object | None]) but the function signature is annotated as -> tuple, which loses the type information and is inconsistent with the rest of this module’s more specific annotations (e.g., list[str]). Consider updating the return annotation to the actual tuple shape (using Any for the JSON value if desired) so callers and type checkers can rely on it.

Copilot uses AI. Check for mistakes.
Comment on lines +268 to +271
try:
initial_cmd = build_mr_view_json_cmd(mr_id)
except ValueError as e:
return {"success": False, "error": str(e), "error_type": "validation_error"}
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

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

_fetch_mr_data already validates mr_id before this block, but build_mr_view_json_cmd() re-validates and the surrounding try/except ValueError becomes effectively unreachable. To reduce duplication and simplify control flow, either (a) make build_mr_view_json_cmd() assume an already-validated mr_id (no internal validation) and remove this try/except, or (b) stop validating mr_id earlier and rely on the helper once (keeping validation centralized in one place).

Copilot uses AI. Check for mistakes.
Comment on lines +279 to +283
metadata_ok, metadata = parse_json_with_recovery(mr_json.stdout)
if not metadata_ok:
mr_json_retry = await run_exec(initial_cmd, cwd=repo_root)
if mr_json_retry.returncode == 0:
metadata_ok, metadata = parse_json_with_recovery(mr_json_retry.stdout)
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

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

The retry-success path (first glab mr view -F json output unrecoverable, second attempt returns valid/recoverable JSON) isn’t covered by tests. Adding a focused test for “recover on retry” would validate the new bounded retry behavior and expected subprocess call count (auth + 2x mr view + remaining calls).

Copilot uses AI. Check for mistakes.
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.

[Copilot AI] _fetch_mr_data crashes on malformed JSON from glab

3 participants