H-6771: Prevent additional emails at signup, only use verified emails when fetching org invites - #9245
H-6771: Prevent additional emails at signup, only use verified emails when fetching org invites#9245CiaranMn wants to merge 6 commits into
Conversation
…ly accept verified emails for pending invites
|
The latest updates on your projects. Learn more about Vercel for GitHub. 4 Skipped Deployments
|
PR SummaryMedium Risk Overview Pending org invitations are listed only when they match verified Kratos emails (plus shortname when set), via Reviewed by Cursor Bugbot for commit 2946358. Bugbot is set up for automated code reviews on this repo. Configure here. |
There was a problem hiding this comment.
Pull request overview
Enforces single-email signup and restricts pending email invitations to verified addresses.
Changes:
- Limits Kratos identities to one email.
- Rejects and cleans up malformed registrations.
- Filters invitation lookup by verified emails and adds integration coverage.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
infra/compose/kratos/identity.schema.json |
Enforces exactly one email. |
apps/hash-api/src/auth/create-auth-handlers.ts |
Rejects malformed registrations. |
apps/hash-api/src/graph/knowledge/system-types/user.ts |
Uses verified emails for invitation lookup. |
tests/hash-backend-integration/src/tests/graph/knowledge/system-types/user.test.ts |
Covers signup and invitation protections. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #9245 +/- ##
==========================================
- Coverage 59.63% 59.63% -0.01%
==========================================
Files 1420 1420
Lines 138767 138775 +8
Branches 6555 6557 +2
==========================================
Hits 82753 82753
- Misses 54950 54958 +8
Partials 1064 1064
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated no new comments.
Suppressed comments (2)
apps/hash-api/src/graph/knowledge/system-types/user.ts:662
- There is no test for the newly introduced verified-email filtering. The existing
getUserPendingInvitationscoverage attests/hash-backend-integration/src/tests/graph/knowledge/system-types/org-invitation-email-casing.test.ts:150-168creates an identity withverifyEmails: true, so it would still pass if this code regressed touser.emails. Add a case with an unverified Kratos email and a matching email invitation that asserts the invitation is omitted (ideally alongside the verified case).
const verifiedEmails = await getUserVerifiedEmails(context, _authentication, {
user,
});
infra/compose/kratos/identity.schema.json:13
- The new
maxItems: 1runtime contract is not reflected in the TypeScript contracts that represent this schema:apps/hash-api/src/auth/ory-kratos.ts:21-24still permits[string, ...string[]], andapps/hash-frontend/src/pages/shared/ory-kratos.ts:30-35still declaresstring[]. As a result,createKratosIdentityand trait-update callers can compile with multiple emails and then fail only at Kratos. Please change these schema-facing types to an exactly-one tuple (and update affected callers) so the application contract matches the enforced schema.
"maxItems": 1,
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated no new comments.
Suppressed comments (1)
apps/hash-api/src/graph/knowledge/system-types/user.ts:662
- The changed filtering has no regression test for its core case: an invitation addressed to an email that exists on the user's Kratos identity but is still unverified. The existing invitation test only creates an identity with
verifyEmails: true(tests/hash-backend-integration/src/tests/graph/knowledge/system-types/org-invitation-email-casing.test.ts:85-88), so it would still pass if this code reverted touser.emails. Add an integration case that creates an unverified identity and assertsgetUserPendingInvitationsexcludes its email invitation (while preserving any shortname behavior).
const verifiedEmails = await getUserVerifiedEmails(context, _authentication, {
user,
});
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.
Suppressed comments (1)
tests/hash-backend-integration/src/tests/graph/knowledge/system-types/user.test.ts:459
deleteKratosIdentityremoves only the Kratos record, but bothattackerandinviterwere also persisted as graph users (createUserabove andcreateTestUserintests/.../util.ts:131-139). This therefore leaves dangling graph users (and the inviter's actor-group role) in the shared integration graph after the test. Track both created users outside thetryand clean them up withdeleteUser({ userId: ... }), falling back to deleting the standalone identity only when user creation did not complete.
await deleteKratosIdentity({ kratosIdentityId: identity.id });
if (inviter) {
await deleteKratosIdentity({
kratosIdentityId: inviter.kratosIdentityId,
});
🌟 What is the purpose of this PR?
Pre-Merge Checklist 🚀
🚢 Has this modified a publishable library?
This PR:
📜 Does this require a change to the docs?
The changes in this PR:
🕸️ Does this require a change to the Turbo Graph?
The changes in this PR:
🛡 What tests cover this?