fix(mcp): harden project context issue provider and prove shared audit path

- Share cursor decoding in foundation.decode_offset_cursor so both tools
  reject an invalid cursor identically, before any upstream call.
- Add regression coverage that a malformed repo slug (owner/repo/extra,
  missing owner, empty segment) is refused before any network call.
- Add evidence that BOTH project context tools inherit the shared MCP
  client audit record and untrusted-content fence, instead of each tool
  shipping its own. No audit subsystem is duplicated.
This commit is contained in:
thanhnv
2026-09-04 10:46:17 +09:00
parent 218ee29893
commit fecbe7cb25
4 changed files with 108 additions and 14 deletions
+17
View File
@@ -62,6 +62,23 @@ class ProviderError(RuntimeError):
self.retryable = retryable
def decode_offset_cursor(cursor: str | None) -> int:
"""Shared opaque-cursor decoding for every paginated provider.
Rejected before any backend call so an invalid cursor never costs an
upstream request.
"""
if cursor is None:
return 0
try:
offset = int(cursor)
except ValueError as exc:
raise ProviderError("INVALID_INPUT", "cursor is not valid.", retryable=False) from exc
if offset < 0:
raise ProviderError("INVALID_INPUT", "cursor is not valid.", retryable=False)
return offset
ToolHandler = Callable[[ContractModel, Any], dict[str, Any]]