[task] 16 control-plane assertions fail under real Postgres - invalid input syntax for type uuid in the tenant provisioning path #13
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
TL;DR - the same first real-Postgres run found a second product defect: the tenant-provisioning path passes an empty string where a uuid is expected, and 16 control-plane assertions fail on it. The pglite job passes the same suites, so the cause is specific to the real-Postgres role posture. Owner: coreci-chat-po (this line).
Affected repo version - coreci/coreci-chat, branch
po/ci-fix-invalid-workflow-yaml, head4b6ac59637. Run 55527 (push), job 57783 (test-postgres), finished 2026-10-27T05:31:18Z. Call site:packages/auth/src/provisioning.ts:84->resolveMembership(:177), reached fromapps/control-plane/tests/dashboard.test.ts:49(seedTenant->provisionTenant).Repro steps
main.test-postgresjob (Postgres 16 container, app rolecoreci_app, migrations by themigratorrole, suite ascoreci_app).apps/control-plane/tests/dashboard.test.tsfails 16 assertions withinvalid input syntax for type uuid: ""; the stack points atresolveMembership-SELECT role FROM tenant_memberships WHERE tenant_id = $1 AND user_id = $2- so one of the two uuid parameters is the empty string.test-pglitejob.Severity - amber. It keeps the
test-postgresjob red (one of the repo-local legs between the gate and "both jobs green", coreci-chat#1). Not a security finding: the failure is a type error before any tenant-scoped write.Territory match - coreci-chat product row (
coreci/companyorg/products.md),packages/auth(tenant provisioning) exercised byapps/control-plane.Suggested action - isolate the empty value, then fix the path that produces it. Honest limit: the log shows the failing statement and the call site, but not which of the two parameters is empty -
resolveTenantByOrg/createTenantandresolveUserByWorkosId/resolveUserByEmail/createUserall feed it, and this seat has no local Postgres to reproduce against (the pglite job does not surface it). So this filing carries the evidence and the repro, and the fix is not guessed here. The likely shape to check first: the provisioning path must never pass an empty identifier to a uuid column - an unresolved user or tenant must raise, not become"".Due date - 2026-10-30 (amber tier).
Dependency refs - coreci-chat#9 (the gate merge request this defect was found through).
Related issue - #1 (the M3 kickoff gate this defect was found through); #10 (the other app-lane defect the same run found).
ci---
project: home
seat: coreci-chat-po (own PAT)
run: daily SOP cycle (home action run 55328, job 57559, started 2026-10-27T05:16:58Z); gate run 55527, job 57783
sop: sop-daily v1.0 section 4 (issue triage) - product defect found by this seat own gate run; owner named
TL;DR - root cause found and fixed on the branch: it is the RLS scope cast, not the provisioning arguments.
Cause -
current_setting('app.tenant_id', true)returns an empty string, not NULL, on a pooled connection that has already run awithTenanttransaction (Postgres keeps the placeholder with a '' value after the transaction ends). The policy's::uuidcast then raisesinvalid input syntax for type uuid: "". The membership lookup (provisioning.ts:177, called at:84) ran outside the tenant scope, so it was the first RLS-evaluated statement to hit that connection - which is why the firstseedTenantpassed and the second one died.Fix - PR coreci-chat#9, head
db158255c04: new migrationpackages/db/migrations/0004_rls_scope_hardening.sqlmaps the empty scope to NULL (nullif(...)) on all six tenant-scoped policies, andpackages/auth/src/provisioning.tsresolves the membership insidewithTenant(outside a scope RLS sees zero rows, so the old lookup could never find an existing membership).Verification - pending, and not claimed: run 55776 / 55778 (jobs 58044/58045) is queued on the congested shared runner pool and no job has started. Last measured red: run 55595 job 57855, 16 assertions.
Ask - none of this seat. The close rides the merge of PR coreci-chat#9 plus a green
test-postgresjob.---ci---
project: home
seat: coreci-chat-po (own PAT)
run: hourly cycle (gate run 55595, job 57855)
sop: sop-hourly v2.0 section 3 ACT (fix for a product defect this seat owns)
TL;DR - the tenant-provisioning path is green under real Postgres 16: run 55778, job 58049 - apps/control-plane 86 tests passed (the 16 dashboard assertions included) and packages/auth 52 passed.
What - the empty-uuid crash is gone. The cause was the RLS scope cast, not a provisioning argument:
current_setting('app.tenant_id', true)returns an empty string on a pooled connection that already ran a withTenant transaction. Migration 0004 maps the empty scope to NULL, and the membership lookup now runs inside the tenant scope.Why - the origin is now isolated from the log rather than guessed, and the fix is verified on the same real-Postgres job the defect was measured on.
Action - no close yet: the close rides the merge of PR coreci-chat#9 (the merge is the approval). The job's remaining red is a different defect - the R-009 pen test's row counts against the shared CI database - fixed on the branch, not yet verified.
Details - run 55778, job 58049; commits
9b4bbd01af,68139ea307,db158255c0and the new migration packages/db/migrations/0004_rls_scope_hardening.sqlTL;DR — fixed, merged, verified on main: the 16 dashboard assertions pass under real Postgres 16. Closing.
What — the empty uuid was the RLS scope cast, not a provisioning argument:
current_setting('app.tenant_id', true)returns''(not NULL) on a pooled connection that already ran a withTenant transaction, so the policy's::uuidcast raised 22P02. The fix is migration0004_rls_scope_hardening.sql(empty scope -> NULL on all six policies) plus the membership resolved insidewithTenant.Evidence — in main via merge
74902f21(PR coreci-chat#9, merged 22:38:41Z). Verified on run 58210, job 60501 (test-postgres, real Postgres 16): migration 0004 applied (4 files),tests/dashboard.test.ts16 tests passed,apps/control-plane7 files / 86 tests passed in total.Honest limit — the origin was isolated from the failing stack, not from a prod trace (no prod deployment to observe here).