Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions internal/api/recover_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,3 +151,44 @@ func (ts *RecoverTestSuite) TestRecover_NoSideChannelLeak() {
ts.API.handler.ServeHTTP(w, req)
assert.Equal(ts.T(), http.StatusOK, w.Code)
}

func (ts *RecoverTestSuite) TestRecover_WithApostropheEmail() {
// Apostrophes are valid in the local part of email addresses per RFC 5321.
// Irish/UK names commonly use them (O'Sullivan, O'Brien, etc.).
// See: https://github.com/supabase/auth/issues/2329
email := "joe.o'sullivan@example.com"

// Create user with apostrophe in email
u, err := models.NewUser("", email, "password", ts.Config.JWT.Aud, nil)
require.NoError(ts.T(), err, "Error creating test user model with apostrophe email")
require.NoError(ts.T(), ts.API.db.Create(u), "Error saving test user with apostrophe email")

u, err = models.FindUserByEmailAndAudience(ts.API.db, email, ts.Config.JWT.Aud)
require.NoError(ts.T(), err, "Error finding user with apostrophe email")
u.RecoverySentAt = &time.Time{}
require.NoError(ts.T(), ts.API.db.Update(u))

// Request body
var buffer bytes.Buffer
require.NoError(ts.T(), json.NewEncoder(&buffer).Encode(map[string]interface{}{
"email": email,
}))

// Setup request
req := httptest.NewRequest(http.MethodPost, "http://localhost/recover", &buffer)
req.Header.Set("Content-Type", "application/json")

// Setup response recorder
w := httptest.NewRecorder()
ts.API.handler.ServeHTTP(w, req)
assert.Equal(ts.T(), http.StatusOK, w.Code)

u, err = models.FindUserByEmailAndAudience(ts.API.db, email, ts.Config.JWT.Aud)
require.NoError(ts.T(), err)

assert.WithinDuration(ts.T(), time.Now(), *u.RecoverySentAt, 1*time.Second)

// Verify the one-time token was created successfully
_, err = models.FindUserByConfirmationOrRecoveryToken(ts.API.db, u.RecoveryToken)
require.NoError(ts.T(), err, "Recovery token should be retrievable for apostrophe email user")
}
27 changes: 27 additions & 0 deletions internal/hooks/hookshttp/hookshttp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,33 @@ func TestDispatch(t *testing.T) {
},
},

{
desc: "pass - email with apostrophe in payload",
req: M{
"user": M{
"email": "joe.o'sullivan@example.com",
},
},
exp: M{"success": true},
hr: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Verify the apostrophe email is correctly received in the JSON payload
var body M
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
user, _ := body["user"].(map[string]any)
email, _ := user["email"].(string)
if email != "joe.o'sullivan@example.com" {
http.Error(w, fmt.Sprintf("unexpected email: %q", email), http.StatusBadRequest)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(M{"success": true})
}),
},

{
desc: "pass - empty content type should not error 204 status",
exp: M{},
Expand Down
16 changes: 16 additions & 0 deletions internal/hooks/hookspgfunc/hookspgfunc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,22 @@ func TestDispatch(t *testing.T) {
end; $$ language plpgsql;`,
},

{
desc: "pass - email with apostrophe in jsonb payload",
cfg: conf.ExtensibilityPointConfiguration{
URI: `pg-functions://postgres/auth/v0pgfunc_test_return_input`,
HookName: `"auth"."v0pgfunc_test_return_input"`,
},
req: M{"user": M{"email": "joe.o'sullivan@example.com"}},
exp: M{"user": M{"email": "joe.o'sullivan@example.com"}},
sql: `
create or replace function v0pgfunc_test_return_input(input jsonb)
returns json as $
begin
return input;
end; $ language plpgsql;`,
Comment on lines +80 to +85
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

file="$(fd 'hookspgfunc_test.go' | head -n1)"

echo "New test case:"
nl -ba "$file" | sed -n '72,85p'

echo
echo "Adjacent valid cases for comparison:"
nl -ba "$file" | sed -n '47,52p;64,69p'

Repository: supabase/auth

Length of output: 131


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find the test file
file="$(find . -name 'hookspgfunc_test.go' -type f | head -n1)"

if [ -z "$file" ]; then
  echo "File not found"
  exit 1
fi

echo "=== New test case (lines 72-85) ==="
head -n 85 "$file" | tail -n 14 | cat -n

echo ""
echo "=== Adjacent valid case 1 (lines 47-52) ==="
head -n 52 "$file" | tail -n 6 | cat -n

echo ""
echo "=== Adjacent valid case 2 (lines 64-69) ==="
head -n 69 "$file" | tail -n 6 | cat -n

echo ""
echo "=== Test setup (around lines 250-253) ==="
head -n 255 "$file" | tail -n 10 | cat -n

Repository: supabase/auth

Length of output: 1481


Fix the malformed PL/pgSQL function body in the new test case.

The new test case uses as $ and end; $ (single dollar signs) instead of the correct $$ delimiters used in the adjacent test cases. PostgreSQL requires double dollar signs for function bodies. The setup query will fail with a syntax error before Dispatch is exercised, so the new coverage never executes.

Proposed fix
 			sql: `
 				create or replace function v0pgfunc_test_return_input(input jsonb)
-				returns json as $
+				returns json as $$
 				begin
 					return input;
-				end; $ language plpgsql;`,
+				end; $$ language plpgsql;`,
 		},
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
sql: `
create or replace function v0pgfunc_test_return_input(input jsonb)
returns json as $
begin
return input;
end; $ language plpgsql;`,
sql: `
create or replace function v0pgfunc_test_return_input(input jsonb)
returns json as $$
begin
return input;
end; $$ language plpgsql;`,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/hooks/hookspgfunc/hookspgfunc_test.go` around lines 80 - 85, The
PL/pgSQL function definition in the test SQL for v0pgfunc_test_return_input uses
single-dollar delimiters ("$") which is malformed; update the SQL string to use
double-dollar delimiters ("$$") around the function body (i.e. change the AS $ /
END; $ to AS $$ / END; $$) so PostgreSQL accepts the function and the test
proceeds to exercise Dispatch.

},

{
desc: "pass - small sleep of 50ms within timeout (100ms)",
cfg: conf.ExtensibilityPointConfiguration{
Expand Down