fix(handlers): restore OFFSEC-001 mcp.go scrub after Tier-2e rebase
sop-checklist / all-items-acked (pull_request) [soft-fail tier:low] acked: 0/7 — missing: comprehensive-testing, local-postgres-e2e, staging-smoke, +4 — body-unfilled: 7
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 23s
CI / Detect changes (pull_request) Successful in 48s
E2E API Smoke Test / detect-changes (pull_request) Successful in 48s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 46s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 51s
Lint curl status-code capture / Scan workflows for curl status-capture pollution (pull_request) Successful in 17s
Harness Replays / detect-changes (pull_request) Successful in 28s
lint-continue-on-error-tracking / lint-continue-on-error-tracking (pull_request) Failing after 1m35s
Runtime PR-Built Compatibility / detect-changes (pull_request) Successful in 39s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 1m28s
Lint pre-flip continue-on-error / Verify continue-on-error flips have run-log proof (pull_request) Successful in 2m0s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 24s
Lint workflow YAML (Gitea-1.22.6-hostile shapes) / Lint workflow YAML for Gitea-1.22.6-hostile shapes (pull_request) Failing after 1m36s
gate-check-v3 / gate-check (pull_request) Failing after 32s
qa-review / approved (pull_request) Failing after 20s
security-review / approved (pull_request) Failing after 14s
sop-checklist-gate / gate (pull_request) Successful in 15s
sop-tier-check / tier-check (pull_request) Successful in 16s
CI / Platform (Go) (pull_request) Successful in 15s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 12s
CI / Python Lint & Test (pull_request) Successful in 14s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 12s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 10s
Harness Replays / Harness Replays (pull_request) Successful in 8s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (pull_request) Successful in 8s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 10m9s
CI / Canvas (Next.js) (pull_request) Successful in 16m16s
CI / Canvas Deploy Reminder (pull_request) Has been skipped
CI / all-required (pull_request) Successful in 5s

The rebase of test/settings-tab-coverage onto current main dropped the
duplicate Tier-2e lint files (already in main via PR#689) but
replayed the mcp.go revert from the pre-OFFSEC-001 Tier-2e branch.
Restore the fix:
- mcp.go: constant error message, no req.Method echo
- mcp_test.go: OFFSEC-001 scrub-contract assertions

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-12 09:43:12 +00:00
parent f76b35a5a0
commit c5c1ab5031
2 changed files with 14 additions and 1 deletions
+2 -1
View File
@@ -434,7 +434,8 @@ func (h *MCPHandler) dispatchRPC(ctx context.Context, workspaceID string, req mc
}
default:
base.Error = &mcpRPCError{Code: -32601, Message: "method not found: " + req.Method}
// Per OFFSEC-001: error message must not include user-controlled req.Method.
base.Error = &mcpRPCError{Code: -32601, Message: "method not found"}
}
return base
@@ -9,6 +9,7 @@ import (
"net/http"
"net/http/httptest"
"os"
"strings"
"testing"
"errors"
@@ -204,6 +205,9 @@ func TestMCPHandler_NotificationsInitialized_Returns200(t *testing.T) {
// Unknown method
// ─────────────────────────────────────────────────────────────────────────────
// TestMCPHandler_UnknownMethod_Returns32601 verifies dispatchRPC returns
// -32601 for an unknown method. Per OFFSEC-001: the error message must be
// constant — req.Method is user-controlled and must NOT appear in the response.
func TestMCPHandler_UnknownMethod_Returns32601(t *testing.T) {
h, _ := newMCPHandler(t)
@@ -224,6 +228,14 @@ func TestMCPHandler_UnknownMethod_Returns32601(t *testing.T) {
if resp.Error.Code != -32601 {
t.Errorf("expected code -32601, got %d", resp.Error.Code)
}
// Message must be constant — no user-controlled method name leak.
if resp.Error.Message != "method not found" {
t.Errorf("error message should be constant 'method not found', got: %q", resp.Error.Message)
}
// Double-check the method name never appears in the message (defence-in-depth).
if strings.Contains(resp.Error.Message, "not/a/real/method") {
t.Error("error message must not echo the user-controlled method name")
}
}
// ─────────────────────────────────────────────────────────────────────────────