From 22f02eed590825f922c6dc98804a78691278f383 Mon Sep 17 00:00:00 2001 From: Jakub Zych Date: Thu, 17 Sep 2026 13:36:30 +0200 Subject: [PATCH] fix(02-03): mask OAuth client_id and unix issued_at RFC 7591 registration returns a string client_id and unix client_id_issued_at; treating those as Carbon/integer foreign keys would fail PHP self-replay of MCP OAuth. Co-authored-by: Cursor --- tide/normalize.go | 7 +++++-- tide/normalize_test.go | 6 ++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/tide/normalize.go b/tide/normalize.go index b847447..dbfee0b 100644 --- a/tide/normalize.go +++ b/tide/normalize.go @@ -55,16 +55,19 @@ func maskLeaf(path string, val any, step Step, diffs *[]Diff) any { if key == "slug" || disabledPath(step, path, key) { return val } - if key == "collection_key" { + if key == "collection_key" || key == "client_id" { if val == nil { return nil } if _, ok := val.(string); !ok { - *diffs = append(*diffs, Diff{Path: path, Expected: "string collection_key", Actual: formatValue(val)}) + *diffs = append(*diffs, Diff{Path: path, Expected: "string " + key, Actual: formatValue(val)}) return val } return maskID } + if strings.HasSuffix(key, "_issued_at") { + return maskIDValue(path, val, diffs) + } if isDateKey(key) { return maskDate(path, val, diffs) } diff --git a/tide/normalize_test.go b/tide/normalize_test.go index bc59445..9133a9f 100644 --- a/tide/normalize_test.go +++ b/tide/normalize_test.go @@ -41,6 +41,12 @@ func TestNormalizeDateIDAndDisable(t *testing.T) { t.Fatalf("slug must stay exact: %+v", slugDiffs) } + issuedA := []byte(`{"client_id":"aaa","client_id_issued_at":111}`) + issuedB := []byte(`{"client_id":"bbb","client_id_issued_at":222}`) + if diffs := compareBodies(Response{Headers: jsonCT(), Body: Body(issuedA)}, Response{Headers: jsonCT(), Body: Body(issuedB)}, step); len(diffs) != 0 { + t.Fatalf("oauth client_id/issued_at must mask: %+v", diffs) + } + disabled := Step{ID: "n", Normalize: []NormalizeRule{{Path: "created_at", Disable: true}}} dDiffs := compareBodies(Response{Headers: jsonCT(), Body: Body(want)}, Response{Headers: jsonCT(), Body: Body(gotOK)}, disabled) if len(dDiffs) == 0 {