fix(08-09): match wristband OAuth byte contract to live-recorded PHP
Recording the full mcp-lifecycle fixture against real isolated PHP (08-09-PLAN.md Task 2) uncovered three byte-level gaps between wristband's assumed contract and actual production PHP behavior: - Every explicit "Cache-Control: no-store" PHP sets is actually delivered as "no-store, private" (Laravel's session-cookie default merges "private" onto any explicit value); wristband's own default for unheadered JSON error responses is "no-cache, private" (matching the house convention already used elsewhere), not empty. - PHP's redirect responses (authorize success and every error redirect) render Symfony's default HTML redirect body with Content-Type "text/html; charset=utf-8"; Go's bare 302 with no body never matched. wristband/redirect_html.go ports that exact byte template, including PHP's htmlspecialchars(ENT_QUOTES) escaping (Go's html.EscapeString uses different quote entities). tide/normalize.go: isIDKey now also masks "_ids" plural array fields (e.g. collection_ids), a latent parity-corpus gap no prior fixture had exercised with a literal, non-empty, non-placeholder array value.
This commit is contained in:
@@ -113,8 +113,8 @@ func TestPhase8RedAuthorize(t *testing.T) {
|
||||
if _, has := q["code"]; has {
|
||||
t.Fatalf("PHASE8_RED:authorize: Location %q leaks a code onto our own redirect", loc)
|
||||
}
|
||||
if cc := rec.Header().Get("Cache-Control"); cc != "no-store" {
|
||||
t.Fatalf("PHASE8_RED:authorize: Cache-Control = %q, want \"no-store\"", cc)
|
||||
if cc := rec.Header().Get("Cache-Control"); cc != "no-store, private" {
|
||||
t.Fatalf("PHASE8_RED:authorize: Cache-Control = %q, want \"no-store, private\"", cc)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,8 +152,8 @@ func TestAuthorizeUnknownClientReturnsLocal400NoLocation(t *testing.T) {
|
||||
if body := rec.Body.String(); body != "Unknown client." {
|
||||
t.Fatalf("body = %q, want %q", body, "Unknown client.")
|
||||
}
|
||||
if cc := rec.Header().Get("Cache-Control"); cc != "no-store" {
|
||||
t.Fatalf("Cache-Control = %q, want no-store", cc)
|
||||
if cc := rec.Header().Get("Cache-Control"); cc != "no-store, private" {
|
||||
t.Fatalf("Cache-Control = %q, want no-store, private", cc)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -278,8 +278,8 @@ func TestPKCEChallengeMethodMustBeS256(t *testing.T) {
|
||||
if q["iss"] != "https://plytarium.com" {
|
||||
t.Fatalf("iss = %q, want https://plytarium.com", q["iss"])
|
||||
}
|
||||
if cc := rec.Header().Get("Cache-Control"); cc != "no-store" {
|
||||
t.Fatalf("Cache-Control = %q, want no-store", cc)
|
||||
if cc := rec.Header().Get("Cache-Control"); cc != "no-store, private" {
|
||||
t.Fatalf("Cache-Control = %q, want no-store, private", cc)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -358,8 +358,8 @@ func TestAuthorizeValidRequestRedirectsToConnectWithOpaqueHandleOnly(t *testing.
|
||||
if _, has := q["client_secret"]; has {
|
||||
t.Fatal("Location leaks client_secret")
|
||||
}
|
||||
if cc := rec.Header().Get("Cache-Control"); cc != "no-store" {
|
||||
t.Fatalf("Cache-Control = %q, want no-store", cc)
|
||||
if cc := rec.Header().Get("Cache-Control"); cc != "no-store, private" {
|
||||
t.Fatalf("Cache-Control = %q, want no-store, private", cc)
|
||||
}
|
||||
|
||||
backend.mu.Lock()
|
||||
|
||||
Reference in New Issue
Block a user