Skip to content
Merged
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# PR_26179_OWNER_035-dev-auth-user-key-db-authority Branch Validation

Status: PASS

- Current branch: `PR_26179_OWNER_035-dev-auth-user-key-db-authority`
- Base branch: `main`
- Rebased onto latest synchronized main: PASS
- Worktree clean before validation: PASS
- Main excludes the fix until PR merge: PASS
- Branch ready to push/open PR: PASS
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# PR_26179_OWNER_035-dev-auth-user-key-db-authority Manual Validation Notes

Status: READY FOR OWNER VALIDATION

Manual checks after merge:

1. Run the approved DEV identity sync against DEV.
2. Confirm `qbytes.dq@gmail.com` exists in Supabase Auth.
3. Confirm `qbytes.dq@gmail.com` exists in the product `users` table.
4. Confirm product `users.authProviderUserId` equals Supabase Auth `auth.users.id`.
5. Sign in as `qbytes.dq@gmail.com` without changing password.
6. Confirm the resolved session uses the database `users.key`.

Packaging note:

- Read-only pre-package verification found the Auth user present but the product users row missing on the current DEV target.
- The mutating DEV identity sync was intentionally not run during this package/push step.
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# PR_26179_OWNER_035-dev-auth-user-key-db-authority

## Summary

This PR makes DEV account session resolution treat the database `users` row as authoritative.

Runtime sign-in now resolves a session only when the Supabase Auth user id matches `users.authProviderUserId`. Matching by email alone is not accepted for login/session resolution. Email remains valid only for the approved DEV identity sync step that locates the existing database `users` row before writing the real Supabase Auth id back to `users.authProviderUserId`.

## Branch Status

- Source branch: `PR_26179_OWNER_035-dev-auth-user-key-db-authority`
- Base branch: `main`
- Rebased onto main HEAD: `13cbe98955c1bcc014bff07480b7d3399386e72f`
- Main still excludes this fix until PR merge: yes

## Diagnostic Findings

### Where `users.key` comes from

- DEV seed setup still defines static fixture keys in `src/dev-runtime/seed/seed-db-keys.mjs` for seed/bootstrap data.
- Before this PR, DEV Supabase identity sync used those seed constants as the authoritative app user keys.
- After this PR, DEV sync locates existing database `users` rows by email and reads `users.key` from the database row. Missing or duplicate database rows are explicit setup errors.

### Where `authProviderUserId` is populated

- Account provisioning continues to write `authProviderUserId` in `src/dev-runtime/server/local-api-router.mjs` through the API/server path.
- DEV identity sync reads Supabase Auth `auth.users.id`, reads the existing product `users.key` from the database row found by email, then writes the real Auth id to `users.authProviderUserId`.

### Runtime resolution

- Supabase sign-in/session resolution now requires an active product `users` row whose `authProviderUserId` equals the Supabase Auth user id.
- If Auth succeeds but the product row is not linked, the API returns a controlled setup message directing the operator to run the approved DEV identity sync.
- Runtime login no longer hardcodes DavidQ/user keys and no longer uses display name as an identity key.

## Exact Fix

- Removed email fallback from Supabase sign-in session resolution.
- Added a Creator-safe setup failure when Auth succeeds but the matching email row has not been linked to the Auth id.
- Added a narrow server-side Postgres client injection hook for tests, with default runtime behavior unchanged.
- Refactored DEV creator identity sync so canonical identity definitions are email-based and database `users.key` is read from existing rows.
- Changed role assignment and cleanup repair logic to derive canonical user keys from database rows.
- Removed the Alfa toolbox tag/design/configuration helper behavior that upserted seed `users` rows over DEV account keys.
- Changed the DEV identity sync default so existing Supabase Auth users are updated without sending a password. Password updates now require explicit `--update-passwords`.
- Added regression tests for auth id matching, stale authProviderUserId handling, existing database key preservation, missing database rows, Tags API seeding not modifying `users`, and password-safe sync defaults.

## Current DEV Data Note

Read-only verification before packaging found:

- `qbytes.dq@gmail.com` exists in Supabase Auth.
- `qbytes.dq@gmail.com` is currently missing from the product `users` table.
- Therefore `users.authProviderUserId` is not synced for that account yet.

The mutating DEV identity sync was not run during this package/push step. Next action after this PR is merged: run the approved DEV identity sync against the current DEV database, then re-test sign-in.

## Files Changed

- `src/dev-runtime/server/local-api-router.mjs` - updated
- `src/dev-runtime/testing/supabase-dev-creator-identity-seed-sync.mjs` - updated
- `src/dev-runtime/toolbox-api/alfa-tool-services.mjs` - updated
- `dev/scripts/sync-supabase-dev-creator-identities.mjs` - updated
- `dev/tests/dev-runtime/SupabaseProviderContractStub.test.mjs` - updated
- `dev/tests/dev-runtime/SupabaseDevCreatorIdentitySeedSync.test.mjs` - updated
- `dev/tests/dev-runtime/TagsApiService.test.mjs` - updated

## Validation

PASS:

- `git diff --check`
- `npm run validate:canonical-structure`
- `node --check src/dev-runtime/server/local-api-router.mjs`
- `node --check src/dev-runtime/testing/supabase-dev-creator-identity-seed-sync.mjs`
- `node --check src/dev-runtime/toolbox-api/alfa-tool-services.mjs`
- `node --check dev/scripts/sync-supabase-dev-creator-identities.mjs`
- `node --check dev/tests/dev-runtime/SupabaseProviderContractStub.test.mjs`
- `node --check dev/tests/dev-runtime/SupabaseDevCreatorIdentitySeedSync.test.mjs`
- `node --check dev/tests/dev-runtime/TagsApiService.test.mjs`
- `node --test dev/tests/dev-runtime/SupabaseDevCreatorIdentitySeedSync.test.mjs`
- `node --test --test-name-pattern "Supabase sign-in resolves|Supabase sign-in does not" dev/tests/dev-runtime/SupabaseProviderContractStub.test.mjs`
- `node --test dev/tests/dev-runtime/TagsApiService.test.mjs`
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# PR_26179_OWNER_035-dev-auth-user-key-db-authority Requirement Checklist

Status: PASS

- Database `users` row is authoritative for `users.key`: PASS
- Runtime sign-in does not use hardcoded DavidQ/user keys: PASS
- Runtime sign-in does not use display name as identity key: PASS
- Supabase Auth id must match `users.authProviderUserId`: PASS
- Email is used only by DEV identity sync to locate existing DB rows: PASS
- DEV identity sync reads DB-owned `users.key`: PASS
- DEV identity sync writes Auth id to `users.authProviderUserId`: PASS
- Toolbox seed helper no longer upserts seed rows into `users`: PASS
- Existing Auth user password is not changed by default sync: PASS
- Required reports under `dev/reports/`: PASS
- Repo-structured ZIP under `dev/workspace/zips/`: PASS
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# PR_26179_OWNER_035-dev-auth-user-key-db-authority Validation Lane Report

Status: PASS

Lane: Owner auth identity authority and DEV sync guardrails.

Coverage:

- Supabase session resolution requires `users.authProviderUserId` to match Auth id.
- Stale `authProviderUserId` does not create a session by email fallback.
- DEV identity sync requires existing product users rows and preserves DB-owned keys.
- Tags API service seeding does not write seed user rows into `users`.
- Canonical repository structure remains valid.

Not run:

- Full workspace smoke. Not required for this package/push step; targeted auth and Tags guardrail validation passed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# PR_26179_OWNER_035-dev-auth-user-key-db-authority Validation Report

Status: PASS

Validated commands:

- `git diff --check` - PASS
- `npm run validate:canonical-structure` - PASS
- `node --check src/dev-runtime/server/local-api-router.mjs` - PASS
- `node --check src/dev-runtime/testing/supabase-dev-creator-identity-seed-sync.mjs` - PASS
- `node --check src/dev-runtime/toolbox-api/alfa-tool-services.mjs` - PASS
- `node --check dev/scripts/sync-supabase-dev-creator-identities.mjs` - PASS
- `node --check dev/tests/dev-runtime/SupabaseProviderContractStub.test.mjs` - PASS
- `node --check dev/tests/dev-runtime/SupabaseDevCreatorIdentitySeedSync.test.mjs` - PASS
- `node --check dev/tests/dev-runtime/TagsApiService.test.mjs` - PASS
- `node --test dev/tests/dev-runtime/SupabaseDevCreatorIdentitySeedSync.test.mjs` - PASS, 2 tests
- `node --test --test-name-pattern "Supabase sign-in resolves|Supabase sign-in does not" dev/tests/dev-runtime/SupabaseProviderContractStub.test.mjs` - PASS, 2 tests
- `node --test dev/tests/dev-runtime/TagsApiService.test.mjs` - PASS, 3 tests
Binary file modified dev/reports/codex_changed_files.txt
Binary file not shown.
Binary file modified dev/reports/codex_review.diff
Binary file not shown.
5 changes: 4 additions & 1 deletion dev/scripts/sync-supabase-dev-creator-identities.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -66,21 +66,24 @@ function formatRecordList(label, records, selector) {
const args = new Set(process.argv.slice(2));
const json = args.has("--json");
const dryRun = args.has("--dry-run");
const updatePasswords = args.has("--update-passwords");
const envLoad = loadEnvLocal();

try {
const result = await syncSupabaseDevCreatorIdentities({ dryRun });
const result = await syncSupabaseDevCreatorIdentities({ dryRun, updatePasswords });
if (json) {
console.log(JSON.stringify({
envLocalLoaded: envLoad.loaded,
envLocalLoadedKeys: envLoad.loadedKeys,
updatePasswords,
...result,
}, null, 2));
} else {
console.log(`Supabase DEV creator identity sync: ${result.status}`);
console.log(envLoad.loaded
? `.env.local loaded (${envLoad.loadedKeys} key(s) applied).`
: ".env.local was not found.");
console.log(`Password updates for existing Auth users: ${updatePasswords ? "enabled" : "disabled"}.`);
formatCounts("Before", result.beforeCounts);
formatCounts("After", result.afterCounts);
formatRecordList("Auth upserts", result.authUpsertRecords, (record) => `${record.email}: ${record.action}`);
Expand Down
Loading
Loading