Skip to content

feat(dashboard-api): add Ory user profile provider and auth middleware fix#2840

Merged
ben-fornefeld merged 16 commits into
mainfrom
ory-userprofile
May 30, 2026
Merged

feat(dashboard-api): add Ory user profile provider and auth middleware fix#2840
ben-fornefeld merged 16 commits into
mainfrom
ory-userprofile

Conversation

@ben-fornefeld
Copy link
Copy Markdown
Member

@ben-fornefeld ben-fornefeld commented May 28, 2026

Summary

  • Add Ory-backed userprofile.Provider with dual Supabase/Ory mode, IaC wiring (ORY_*, USER_PROFILE_PROVIDER), and team member enrichment (name, picture, providers).
  • Route Supabase bootstrap through the profile provider instead of direct auth metadata reads.
  • Fix auth middleware to report per-scheme header misses as span events instead of WARN logs during OR-of-AND negotiation.

Stack

This is PR 1 of 2 for the Ory dashboard auth migration. PR 2 (ory-bootstrap) adds the OIDC admin bootstrap endpoint and stacks on this branch.

…e fix

Wire dual Supabase/Ory profile resolution, enrich team member responses,
and silence per-scheme auth negotiation noise so Ory mode can deploy
independently of OIDC bootstrap provisioning.
@cursor
Copy link
Copy Markdown

cursor Bot commented May 28, 2026

PR Summary

Medium Risk
Touches authentication middleware status handling and identity-to-user mapping for Ory; misconfigured issuer or missing identity rows can break provisioning and profile display until bootstrap is in place.

Overview
This PR adds a pluggable dashboard-api user profile layer (Supabase, Ory, or dual fallback), wires Ory and USER_PROFILE_PROVIDER through GCP/Nomad with a managed API-token secret, and uses that provider for team bootstrap and richer team members (name, profilePictureUrl, providers). Shared auth middleware now records missing credentials as span events and sets 401 on the Gin writer so failed multi-scheme auth can surface as unauthorized instead of 400. Startup validates Ory settings and checks ORY_ISSUER_URL against JWT issuer config so user_identities lookups stay aligned.

In supabase-ory-fallback, profile-by-ID always queries Supabase and Ory. Ory resolution depends on public.user_identities for the configured issuer; rows are expected from the follow-up bootstrap work. A wrong ORY_ISSUER_URL yields empty Ory profiles without failing requests.

Reviewed by Cursor Bugbot for commit 24c13e8. Bugbot is set up for automated code reviews on this repo. Configure here.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 28, 2026

❌ 4 Tests Failed:

Tests completed Failed Passed Skipped
2695 4 2691 7
View the full list of 5 ❄️ flaky test(s)
github.com/e2b-dev/infra/tests/integration/internal/tests/api/sandboxes::TestSandboxListPaginationRunningLargerLimit

Flake rate in main: 42.83% (Passed 726 times, Failed 544 times)

Stack Traces | 95.6s run time
=== RUN   TestSandboxListPaginationRunningLargerLimit
    sandbox_list_test.go:327: Created sandbox 1/12: iha7scrq5s7ug0wwarkt3
    sandbox_list_test.go:327: Created sandbox 2/12: i622fv66yipvr5f2fblq2
    sandbox_list_test.go:327: Created sandbox 3/12: ionsku2s9bgtrhqd9egvp
    sandbox_list_test.go:327: Created sandbox 4/12: i6sfuhe8i4gf18j5be3f8
    sandbox_list_test.go:327: Created sandbox 5/12: izz5thux3eqqyeb889cr1
    sandbox_list_test.go:327: Created sandbox 6/12: ii3dopovl96h5plzpuq5h
    sandbox_list_test.go:327: Created sandbox 7/12: i21emniqdxnzod9osxsr5
    sandbox_list_test.go:327: Created sandbox 8/12: igwhqkthzhy60zpkx5q84
    sandbox_list_test.go:327: Created sandbox 9/12: ii52fncjowas6h9rym8mb
    sandbox_list_test.go:327: Created sandbox 10/12: iywadyongrx9gxvpcmwam
    sandbox_list_test.go:327: Created sandbox 11/12: ias3u9dhiq89ntp39p9ku
    sandbox_list_test.go:327: Created sandbox 12/12: i4uedfssllv7x53hjro97
    sandbox_list_test.go:330: 
        	Error Trace:	.../api/sandboxes/sandbox_list_test.go:340
        	            				.../hostedtoolcache/go/1.26.3.../src/runtime/asm_amd64.s:1771
        	Error:      	"[]" should have 12 item(s), but has 0
    sandbox_list_test.go:330: 
        	Error Trace:	.../api/sandboxes/sandbox_list_test.go:330
        	Error:      	Condition never satisfied
        	Test:       	TestSandboxListPaginationRunningLargerLimit
--- FAIL: TestSandboxListPaginationRunningLargerLimit (95.56s)
github.com/e2b-dev/infra/tests/integration/internal/tests/orchestrator::TestSandboxMemoryIntegrity

Flake rate in main: 57.88% (Passed 719 times, Failed 988 times)

Stack Traces | 62.2s run time
=== RUN   TestSandboxMemoryIntegrity
=== PAUSE TestSandboxMemoryIntegrity
=== CONT  TestSandboxMemoryIntegrity
    sandbox_memory_integrity_test.go:27: Build completed successfully
--- FAIL: TestSandboxMemoryIntegrity (62.21s)
github.com/e2b-dev/infra/tests/integration/internal/tests/orchestrator::TestSandboxMemoryIntegrity/tmpfs_hash

Flake rate in main: 58.00% (Passed 709 times, Failed 979 times)

Stack Traces | 188s run time
=== RUN   TestSandboxMemoryIntegrity/tmpfs_hash
=== PAUSE TestSandboxMemoryIntegrity/tmpfs_hash
=== CONT  TestSandboxMemoryIntegrity/tmpfs_hash
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{start:{pid:1259}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stdout:"Total memory: 985 MB\nUsed memory before tmpfs mount: 190 MB\nFree memory before tmpfs mount: 794 MB\nMemory to use in integrity test (60% of free, min 64MB): 476 MB\n"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"476+0 records in\n476+0 records out\n499122176 bytes (499 MB, 476 MiB) copied, 2.42182 s, 206 MB/s\n"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"\tCommand being timed: \""}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"dd if=/dev/urandom of=/mnt/testfile bs=1M count=476\""}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"\n\tUser tim"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"e (seco"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"nds): "}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"0.00"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"\n"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"\t"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"S"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"y"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"s"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"t"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"e"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"m"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:" "}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"t"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"i"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"m"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"e"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:" "}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"("}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"s"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"e"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"c"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"o"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"n"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"d"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"s"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:")"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:":"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:" "}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"2.41"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"\n"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"\t"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"P"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"e"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"r"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"c"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"e"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"n"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"t"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:" "}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"o"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"f"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:" "}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"C"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"P"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"U"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:" "}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"t"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"h"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"i"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"s"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:" "}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"j"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"o"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"b"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:" "}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"g"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"o"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"t"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:":"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:" "}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"99%"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"\n"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"\t"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:"Elapsed (wall clock) time (h:mm:ss or m:ss): 0:02.42\n\tAverage shared text size (kbytes): 0\n\tAverage unshared data size (kbytes): 0\n\tAverage stack size (kbytes): 0\n\tAverage total size (kbytes): 0\n\tMaximum resident set size (kbytes): 2724\n\tAverage resident set size (kbytes): 0\n\tMajor (requiring I/O) page faults: 3\n\tMinor (reclaiming a frame) page faults: 345\n\tVoluntary context switches: 4\n\tInvoluntary context switches: 10\n\tSwaps: 0\n\tFile system inputs: 176\n\tFile system outputs: 0\n\tSocket messages sent: 0\n\tSocket messages received:"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stderr:" 0\n\tSignals delivered: 0\n\tPage size (bytes): 4096\n\tExit status: 0\n"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{data:{stdout:"Used memory after tmpfs mount and file fill: 670 MB\n"}}
    sandbox_memory_integrity_test.go:70: Command [bash] output: event:{end:{exited:true  status:"exit status 0"}}
    sandbox_memory_integrity_test.go:70: Command [bash] completed successfully in sandbox izzz1j27tjjz3p0v33aqj
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
    sandbox_memory_integrity_test.go:80: Command [bash] output: event:{start:{pid:1275}}
Executing command bash in sandbox i53zycuj70y56fp6doysj (user: root)
    sandbox_memory_integrity_test.go:80: Command [bash] output: event:{data:{stdout:"3504557ba456361c60511576fb25b8397998469bb52e7807f69fe7e6f0b3e7fb\n"}}
    sandbox_memory_integrity_test.go:80: Command [bash] output: event:{end:{exited:true  status:"exit status 0"}}
    sandbox_memory_integrity_test.go:80: Command [bash] completed successfully in sandbox izzz1j27tjjz3p0v33aqj
    sandbox_memory_integrity_test.go:80: Command [bash] output: event:{start:{pid:1278}}
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
Executing command bash in sandbox izzz1j27tjjz3p0v33aqj (user: root)
    sandbox_memory_integrity_test.go:110: 
        	Error Trace:	.../tests/orchestrator/sandbox_memory_integrity_test.go:81
        	            				.../hostedtoolcache/go/1.26.3.../src/runtime/asm_amd64.s:1771
        	Error:      	Received unexpected error:
        	            	failed to execute command bash in sandbox izzz1j27tjjz3p0v33aqj: unavailable: HTTP status 502 Bad Gateway
    sandbox_memory_integrity_test.go:110: 
        	Error Trace:	.../tests/orchestrator/sandbox_memory_integrity_test.go:78
        	            				.../tests/orchestrator/sandbox_memory_integrity_test.go:110
        	Error:      	Condition never satisfied
        	Test:       	TestSandboxMemoryIntegrity/tmpfs_hash
--- FAIL: TestSandboxMemoryIntegrity/tmpfs_hash (188.07s)
github.com/e2b-dev/infra/tests/integration/internal/tests/proxies::TestEnvdAccessTokenAutoResumeViaProxy

Flake rate in main: 43.07% (Passed 715 times, Failed 541 times)

Stack Traces | 11.6s run time
=== RUN   TestEnvdAccessTokenAutoResumeViaProxy
=== PAUSE TestEnvdAccessTokenAutoResumeViaProxy
=== CONT  TestEnvdAccessTokenAutoResumeViaProxy
    traffic_access_token_test.go:357: 
        	Error Trace:	.../tests/proxies/traffic_access_token_test.go:357
        	Error:      	Received unexpected error:
        	            	Get "http://localhost:3002/health": context deadline exceeded (Client.Timeout exceeded while awaiting headers)
        	Test:       	TestEnvdAccessTokenAutoResumeViaProxy
--- FAIL: TestEnvdAccessTokenAutoResumeViaProxy (11.56s)
github.com/e2b-dev/infra/tests/integration/internal/tests/proxies::TestSandboxAutoResumeUsesInitialTimeoutNotUpdatedTimeout

Flake rate in main: 42.11% (Passed 715 times, Failed 520 times)

Stack Traces | 0.84s run time
=== RUN   TestSandboxAutoResumeUsesInitialTimeoutNotUpdatedTimeout
=== PAUSE TestSandboxAutoResumeUsesInitialTimeoutNotUpdatedTimeout
=== CONT  TestSandboxAutoResumeUsesInitialTimeoutNotUpdatedTimeout
    auto_resume_test.go:254: Command [ls] output: event:{start:{pid:1263}}
    auto_resume_test.go:255: 
        	Error Trace:	.../tests/proxies/auto_resume_test.go:255
        	Error:      	Received unexpected error:
        	            	failed to execute command ls in sandbox ia81vfr8irgl7ze5x7quo: invalid_argument: protocol error: incomplete envelope: unexpected EOF
        	Test:       	TestSandboxAutoResumeUsesInitialTimeoutNotUpdatedTimeout
--- FAIL: TestSandboxAutoResumeUsesInitialTimeoutNotUpdatedTimeout (0.84s)

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

In packages/dashboard-api/internal/userprofile/ory.go, the oidc.Config field in ory.IdentityCredentials is of type interface{} and cannot be indexed directly. Attempting to access oidc.Config["providers"] will cause a compile-time error, so oidc.Config must be type-asserted to map[string]any before retrieving the providers list.

Comment thread packages/dashboard-api/internal/userprofile/ory.go
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ddbe15f3b9

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/dashboard-api/internal/userprofile/ory.go
Ory's admin ListIdentities rejects an `ids` filter with more than 500
entries (400 Bad Request) and does not paginate id-filtered results, so
the previous batch size of 1000 would fail any profile lookup touching
more than 500 users in a single request. Chunk lookups at 500 and drop
the no-op PageSize call (ignored for the ids filter).

Also dedupe the two identity-resolver mappings into a generic
userIDsBySubject helper.
Fix the Ory identity id-filter batch size: the admin ListIdentities `ids`
filter rejects more than 500 entries (400) and is not paginated, so cap
batches at 500 instead of 1000.

Cleanups:
- dedupe the two identity-resolver mappings into a generic userIDsBySubject
- extract uniqueNonEmpty to drop the duplicated provider-dedup closures
  shared by oryLinkedProviders and supabaseLinkedProviders
- promote FirstNonEmpty to shared/pkg/utils and reuse it (removes the
  handlers -> userprofile coupling for a generic string helper)
- reuse utils.Map and Go 1.26 new(expr) in place of hand-rolled loops and
  pointer temporaries
- trim redundant/what-explaining comments
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

authUser, err := s.supabaseDB.Write.GetAuthUserByID(ctx, userID)

P1 Badge Use profile provider when creating Ory teams

When USER_PROFILE_PROVIDER=ory and an authenticated Ory-only user calls POST /teams, this path still reads auth.users from the Supabase connection before creating the team. Those users are resolved through public.user_identities and may not have a Supabase auth.users row, so additional team creation fails with get auth user even though the same commit moved bootstrap/member profile lookups to s.userProfiles; fetch the email through the configured profile provider here as well.

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Use the SDK's recommended per-request token mechanism instead of a custom
RoundTripper that hand-set the Authorization header. The generated client
turns a ContextAccessToken value into the bearer header, so the custom
oryBearerTransport is removed and each call passes p.authCtx(ctx).

Keep the shallow copy of the injected http.Client so the SDK can never
mutate the caller's shared instance; the token now lives only in the
request context, never on the client.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 700b3e6a63

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +71 to +74
member.Name = new(profile.Name)
}
if profile.ProfilePictureURL != "" {
member.ProfilePictureUrl = new(profile.ProfilePictureURL)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Use addressable locals for optional profile fields

When a team member has a non-empty name or profile picture, these assignments call Go's new builtin with a value expression (profile.Name / profile.ProfilePictureURL), but new only accepts a type operand, so the dashboard-api package does not build. Store the string in a local variable and take its address, or use an existing pointer helper.

Useful? React with 👍 / 👎.

Drop what-restating prose and rely on symbol names; keep only the
non-obvious context (external Ory data shapes, the issuer/oidc_iss
invariant, the shared-client safety note).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

authUser, err := s.supabaseDB.Write.GetAuthUserByID(ctx, userID)
if err != nil {
return provisionedTeam{}, fmt.Errorf("get auth user: %w", err)

P1 Badge Resolve team creators through configured profile provider

When USER_PROFILE_PROVIDER=ory and an Ory-authenticated user calls POST /teams, this path still requires a matching row in Supabase auth.users, so Ory-only users who can authenticate and bootstrap their default team hit get auth user and cannot create additional teams. This should use s.userProfiles (as the bootstrap path now does) or otherwise avoid making Supabase the source of truth in Ory mode.

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

ben-fornefeld and others added 5 commits May 28, 2026 17:24
createTeam (POST /teams) read the creator's email straight from Supabase
auth.users, so in ory mode an Ory-only user with no auth.users row could
authenticate and bootstrap a default team but failed to create additional
teams with "get auth user". Resolve the profile through the configured
provider, matching the bootstrap path.

Extract the shared lookup into resolveProfile so bootstrap and team
creation use one provider-backed path, and set userProfiles in the
team-creation tests that previously only needed supabaseDB.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drop `picture` from the identity trait schema so it no longer renders on
Ory's self-service registration form, and read it from the identity's
metadata_public instead. The OIDC Jsonnet mapper continues to populate it
from the provider claims; only its destination moves from traits to
metadata_public.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 42d5fb6f74

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +199 to +200
Ids(batchIDs).
IncludeCredential([]string{"oidc"}),
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Request 500 identities for each Ory id batch

When a team has more than 250 Ory-backed members, this lookup sends up to 500 ids but leaves Ory's page_size at its documented default of 250 (max 500, and the ids filter does not support normal pagination: https://www.ory.com/docs/kratos/reference/api#tag/identity/operation/listIdentities). The remaining requested identities are omitted, so GetTeamsTeamIDMembers logs them as missing profiles and silently drops members from the response; set PageSize(oryListIDsBatchSize) on the id-filtered request.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: caf2a18744

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".


// stamp 401 so the ErrorHandler's max(writer, 400) resolves to 401
// when every security group fails. without this, auth failures become 400s.
ginCtx.Status(http.StatusUnauthorized)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Defer stamping 401 until all auth alternatives fail

For dashboard routes with two alternative security requirements (for example /builds in spec/openapi-dashboard.yml lists Supabase and AuthProvider as alternatives), a request that uses valid AuthProvider headers still first tries the Supabase group; this line leaves c.Writer.Status() at 401 when the Supabase header is missing. If that later-authenticated request then fails normal request validation, packages/dashboard-api/main.go uses max(c.Writer.Status(), statusCode), so a real 400 is returned as 401 even though auth succeeded. Only stamp 401 when the whole authentication validation fails, or reset the status after a successful alternative.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

no it's fine

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit b088383. Configure here.

Comment thread packages/dashboard-api/internal/userprofile/dual.go
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 14f9c33dfa

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread fixtures/ory/identity.v1.schema.json
@ben-fornefeld ben-fornefeld merged commit 30d40d2 into main May 30, 2026
51 checks passed
@ben-fornefeld ben-fornefeld deleted the ory-userprofile branch May 30, 2026 00:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants