Skip to content

Conversation

@VivekVinushanth
Copy link
Contributor

@VivekVinushanth VivekVinushanth commented Dec 9, 2025

Purpose

Describe the problems, issues, or needs driving this feature/fix and include links to related issues in the following format: Resolves issue1, issue2, etc.

Goals

Describe the solutions that this feature/fix will introduce to resolve the problems described above

Approach

Describe how you are implementing the solutions. Include an animated GIF or screenshot if the change affects the UI (email [email protected] to review all UI text). Include a link to a Markdown file or Google doc if the feature write-up is too long to paste here.

User stories

Summary of user stories addressed by this change>

Release note

Brief description of the new feature or bug fix as it will appear in the release notes

Documentation

Link(s) to product documentation that addresses the changes of this PR. If no doc impact, enter “N/A” plus brief explanation of why there’s no doc impact

Training

Link to the PR for changes to the training content in https://github.com/wso2/WSO2-Training, if applicable

Certification

Type “Sent” when you have provided new/updated certification questions, plus four answers for each question (correct answer highlighted in bold), based on this change. Certification questions/answers should be sent to [email protected] and NOT pasted in this PR. If there is no impact on certification exams, type “N/A” and explain why.

Marketing

Link to drafts of marketing content that will describe and promote this feature, including product page changes, technical articles, blog posts, videos, etc., if applicable

Automation tests

  • Unit tests

    Code coverage information

  • Integration tests

    Details about the test cases and coverage

Security checks

Samples

Provide high-level details about the samples related to this feature

Related PRs

List any other related PRs

Migrations (if applicable)

Describe migration steps and platforms on which migration has been tested

Test environment

List all JDK versions, operating systems, databases, and browser/versions on which this feature/fix was tested

Learning

Describe the research phase and any blog posts, patterns, libraries, or add-ons you used to solve the problem.

Summary by CodeRabbit

  • Refactor

    • Profile schema attribute creation now requires explicit org/tenant context.
    • Schema sync now reacts to add/update/delete/local-attribute events; CDS-gated init/sync flows enforce enablement.
  • Bug Fixes

    • Profile lookup treats "profile not found" as non-error during creation flows.
  • New Utilities

    • Added helper to detect client error codes and a CDS_NOT_ENABLED error.
  • Tests

    • Integration tests updated to pass org context and perform runtime cleanup.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Dec 9, 2025

Walkthrough

Adds orgId propagation to profile-schema attribute creation (handler→service→store), changes ProfileSchemaSync payload tags for OrgId, replaces SchemaInitEvent with SCIM/local attribute events, broadens SyncProfileSchema event handling, adds CDS enablement guards and CDS_NOT_ENABLED error, introduces HasClientErrorCode, and updates tests and test cleanup.

Changes

Cohort / File(s) Summary
Attribute workflow (handler → service → store)
internal/profile_schema/handler/profile_schema_handler.go, internal/profile_schema/service/profile_schema_service.go, internal/profile_schema/store/profile_schema_store.go
Signature changed: AddProfileSchemaAttributesForScope(..., scope string)AddProfileSchemaAttributesForScope(..., scope, orgId string). Handler forwards orgId; store uses provided orgId for DB inserts instead of attr.OrgId.
Model tag change
internal/profile_schema/model/profile_schema_api.go
ProfileSchemaSync.OrgId JSON/BSON tags renamed from tenantDomain to tenantId (json:"tenantId" bson:"tenantId").
Event constants and handler branching
internal/system/constants/constants.go, internal/profile_schema/handler/profile_schema_handler.go
Removed SchemaInitEvent; added SCIM/local event constants (POST_ADD_EXTERNAL_CLAIM, POST_UPDATE_EXTERNAL_CLAIM, POST_DELETE_EXTERNAL_CLAIM, POST_UPDATE_LOCAL_CLAIM). Sync handler now reacts to these events (calls SyncProfileSchema(orgId)) and returns 404 for unknown events.
CDS enablement and profile handler guards
internal/profile/handler/profile_handler.go, internal/system/errors/error_codes.go
Added isCDSEnabled(tenantId string) via AdminConfigService checks; InitProfile/SyncProfile paths now return CDS_NOT_ENABLED client error when CDS is disabled. New error CDS_NOT_ENABLED added.
Error utilities
internal/system/utils/error_utils.go
Added exported helper HasClientErrorCode(err error, code string) bool to detect CDS client error codes using errors.As.
Tests and test infra
test/integration/*
test/integration/main_test.go, test/integration/profile_schema_test.go, test/integration/profile_test.go, test/integration/profile_unification_test.go, test/integration/unification_rules_test.go
Integration tests updated to pass a third org argument (e.g., SuperTenantOrg) to AddProfileSchemaAttributesForScope; test cleanup now stops the test Postgres container and removes its image; import adjustments.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Client
    participant Handler as ProfileSchema Handler
    participant Admin as AdminConfigService
    participant Service as ProfileSchema Service
    participant Store as ProfileSchema Store

    Client->>Handler: POST ProfileSchemaSync {orgId, event, attributes}
    Handler->>Admin: isCDSEnabled(orgId)?
    alt CDS disabled
        Admin-->>Handler: false
        Handler-->>Client: 400 CDS_NOT_ENABLED
    else CDS enabled
        Handler->>Handler: inspect event type
        alt event is Add/Update/Delete SCIM or UpdateLocalAttribute
            Handler->>Service: SyncProfileSchema(orgId) / AddProfileSchemaAttributesForScope(attrs, scope, orgId)
            Service->>Store: insert/update/delete using provided orgId
            Store-->>Service: result
            Service-->>Handler: success
            Handler-->>Client: 200 "profile schema sync successful"
        else unknown event
            Handler-->>Client: 404 "Unknown sync event"
        end
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40–60 minutes

  • Pay attention to all call sites and tests updated to the new AddProfileSchemaAttributesForScope(..., orgId) signature.
  • Verify no remaining uses of the removed SchemaInitEvent constant.
  • Review DB value construction to ensure correct orgId is persisted for multi-tenant behavior.
  • Validate CDS gating logic in profile handler and correct use of CDS_NOT_ENABLED error codes.
  • Check JSON/BSON tag change for ProfileSchemaSync.OrgId (tenantId) and impact on serialization/deserialization.

Poem

🐇 I hopped through code with a twitch and a grin,

threaded orgIds where inserts begin.
Add, Update, Delete — the sync sings along,
I nibble tests clean and hum a small song. 🥕

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings, 1 inconclusive)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description contains only the template structure with no actual content filled in; all sections remain as empty placeholders with instruction text. Complete all required sections with concrete details: describe the problem being solved, the implementation approach, affected user stories, test coverage, security validations, and any necessary migration steps.
Docstring Coverage ⚠️ Warning Docstring coverage is 36.36% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'Support schema sync' is vague and generic; it doesn't convey specific details about what schema sync changes are being made or why. Provide a more descriptive title that specifies the key change, such as 'Add orgId parameter to profile schema sync operations' or 'Update schema sync to support org-scoped attribute operations'.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ba294e4 and cd42fd2.

📒 Files selected for processing (3)
  • internal/profile_schema/handler/profile_schema_handler.go (3 hunks)
  • internal/profile_schema/model/profile_schema_api.go (1 hunks)
  • internal/system/constants/constants.go (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
internal/profile_schema/handler/profile_schema_handler.go (2)
internal/profile_schema/store/profile_schema_store.go (1)
  • AddProfileSchemaAttributesForScope (36-103)
internal/system/constants/constants.go (4)
  • AddScimAttribute (34-34)
  • UpdateScimAttribute (35-35)
  • DeleteScimAttribute (36-36)
  • UpdateLocalAttribute (37-37)
🔇 Additional comments (4)
internal/profile_schema/handler/profile_schema_handler.go (2)

113-113: LGTM: orgId parameter properly propagated.

The addition of the orgId parameter to AddProfileSchemaAttributesForScope is correctly implemented. The orgId is extracted from the request path at line 56 and properly passed through the service layer to the store, enabling org-scoped schema attribute operations.


351-367: Verify event constant values match publisher expectations

The event handling logic has been correctly expanded from a single SchemaInitEvent to four SCIM-related events. Verification confirms:

  • SchemaInitEvent has been completely removed from the codebase
  • Event constants are properly defined and match standard WSO2 Identity Server event names: POST_ADD_EXTERNAL_CLAIM, POST_UPDATE_EXTERNAL_CLAIM, POST_DELETE_EXTERNAL_CLAIM, and POST_UPDATE_LOCAL_CLAIM
  • The implementation correctly checks for all four event types using OR conditions and triggers SyncProfileSchema for any matching event
  • Returns 404 with "Unknown sync event." for unrecognized events

The code is ready for integration with the upstream WSO2 Identity Server event publisher.

internal/system/constants/constants.go (1)

34-37: LGTM: Event constants updated to support granular SCIM operations.

The replacement of the single SchemaInitEvent with four granular SCIM attribute event constants is a good improvement that enables more precise event handling. The new constants follow the POST_<ACTION>_<CLAIM_TYPE> naming pattern, which appears consistent with WSO2 Identity Server conventions.

This change aligns properly with the expanded event handling logic in internal/profile_schema/handler/profile_schema_handler.go (lines 351-352).

internal/profile_schema/model/profile_schema_api.go (1)

22-22: Field naming inconsistency and missing backward compatibility strategy.

The OrgId field in ProfileSchemaSync uses JSON/BSON tags tenantId, while the related ProfileSchema struct uses org_id tags for the same logical field. Additionally, there is no documented migration strategy or API versioning approach to handle changes to field serialization names that external consumers or existing database documents may depend on. Ensure field naming is consistent across related structs and establish a clear backward compatibility plan before altering serialization tag names.

Likely an incorrect or invalid review comment.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
internal/profile_schema/store/profile_schema_store.go (1)

92-101: Inconsistent orgId reference in error message and log.

Lines 92 and 100-101 reference attrs[0].OrgId for error/log messages, but the actual insertion uses the orgId parameter. If these differ, the messages will be misleading.

 	if err != nil {
-		errorMsg := fmt.Sprintf("Failed to insert profile schema attributes for org: %s", attrs[0].OrgId)
+		errorMsg := fmt.Sprintf("Failed to insert profile schema attributes for org: %s", orgId)
 		logger.Debug(errorMsg, log.Error(err))
 		return errors.NewServerError(errors.ErrorMessage{
 			Code:        errors.ADD_PROFILE_SCHEMA.Code,
 			Message:     errors.ADD_PROFILE_SCHEMA.Message,
 			Description: errorMsg,
 		}, err)
 	}
 	logger.Info(fmt.Sprintf("Successfully added %d profile schema attributes for organization: %s",
-		len(attrs), attrs[0].OrgId))
+		len(attrs), orgId))
 	return nil
🧹 Nitpick comments (2)
internal/profile_schema/model/profile_schema_api.go (1)

21-25: Consider aligning field name with JSON tag for clarity.

The field OrgId serializes as tenantDomain in JSON/BSON. This mismatch may confuse developers—consider renaming the field to TenantDomain or changing the tag to orgId for consistency.

 type ProfileSchemaSync struct {
-	OrgId              string                   `json:"tenantDomain" bson:"tenantDomain"`
+	TenantDomain       string                   `json:"tenantDomain" bson:"tenantDomain"`
 	Event              string                   `json:"event" bson:"event"`
 	IdentityAttributes []ProfileSchemaAttribute `json:"identityAttributes" bson:"identityAttributes"`
 }
internal/profile_schema/handler/profile_schema_handler.go (1)

350-361: IdentityAttributes from request payload is unused.

The ProfileSchemaSync struct now includes IdentityAttributes, which is decoded at line 341, but the AddAttribute branch only uses schemaAtt.OrgId and calls SyncProfileSchema(orgId). The IdentityAttributes payload is ignored. If the intent is to use attributes from the request, this needs to be addressed.

Would you like me to propose an implementation that uses schemaAtt.IdentityAttributes instead of fetching from the identity server?

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1650f21 and e13eafc.

📒 Files selected for processing (5)
  • internal/profile_schema/handler/profile_schema_handler.go (2 hunks)
  • internal/profile_schema/model/profile_schema_api.go (1 hunks)
  • internal/profile_schema/service/profile_schema_service.go (3 hunks)
  • internal/profile_schema/store/profile_schema_store.go (2 hunks)
  • internal/system/constants/constants.go (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
internal/profile_schema/store/profile_schema_store.go (2)
internal/profile_schema/model/profile_schema.go (1)
  • ProfileSchemaAttribute (21-33)
internal/system/constants/constants.go (1)
  • ValueType (87-87)
internal/profile_schema/model/profile_schema_api.go (2)
internal/system/constants/constants.go (1)
  • IdentityAttributes (81-81)
internal/profile_schema/model/profile_schema.go (1)
  • ProfileSchemaAttribute (21-33)
internal/profile_schema/service/profile_schema_service.go (2)
internal/profile_schema/store/profile_schema_store.go (1)
  • AddProfileSchemaAttributesForScope (36-103)
internal/profile_schema/model/profile_schema.go (1)
  • ProfileSchemaAttribute (21-33)
🔇 Additional comments (7)
internal/system/constants/constants.go (1)

33-37: LGTM! New event constants are well-defined.

The granular attribute lifecycle events (AddAttribute, UpdateAttribute, DeleteAttribute) replace the single SchemaInitEvent. Note that the handler currently only handles AddAttribute—ensure UpdateAttribute and DeleteAttribute are implemented when needed.

internal/profile_schema/store/profile_schema_store.go (2)

36-36: Signature change looks correct.

The orgId parameter is now explicitly passed, aligning with the org-scoped attribute workflow.


83-85: LGTM on using explicit orgId for insertion.

Correctly uses the passed orgId parameter instead of attr.OrgId for the tenant identifier in the insert values.

internal/profile_schema/handler/profile_schema_handler.go (1)

112-112: LGTM on passing orgId to service layer.

The call now correctly propagates the organization identifier through to the service and store layers.

internal/profile_schema/service/profile_schema_service.go (3)

38-38: Interface signature updated correctly.

The AddProfileSchemaAttributesForScope method now includes orgId parameter, aligning with the org-scoped workflow.


59-59: Implementation signature matches interface.

The receiver method signature is correctly updated to accept orgId.


97-97: Store call correctly propagates orgId.

The orgId parameter is now passed through to the store layer, completing the org-scoped attribute creation flow.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
internal/profile/handler/profile_handler.go (1)

749-752: Good refinement, but apply consistently across similar patterns.

The error handling refinement is correct—ignoring PROFILE_NOT_FOUND errors allows the flow to continue and create a new profile for the user at line 754, which is the intended behavior for the POST_ADD_USER event.

However, similar patterns at lines 815–819 and 837–841 should apply the same logic for consistency.

Lines 815–819 (POST_DELETE_USER_WITH_ID event):
The code handles all errors from FindProfileByUserId, but checks existingProfile == nil at line 820. With the current logic, a PROFILE_NOT_FOUND error prevents reaching that nil check. Consider:

 existingProfile, err = profilesService.FindProfileByUserId(profileSync.UserId)
 if err != nil {
-    utils.HandleError(writer, err)
-    return
+    if !utils.HasClientErrorCode(err, errors2.PROFILE_NOT_FOUND.Code) {
+        utils.HandleError(writer, err)
+        return
+    }
 }
 if existingProfile == nil {
     logger.Debug("No profile found for user: " + profileSync.UserId)
     return
 }

Lines 837–841 (POST_SET_USER_CLAIM_VALUES_WITH_ID event):
Similarly, the code returns on all errors but checks existingProfile == nil at line 842 to create a new profile. Apply the same refinement:

 existingProfile, err = profilesService.FindProfileByUserId(profileSync.UserId)
 if err != nil {
-    utils.HandleError(writer, err)
-    return
+    if !utils.HasClientErrorCode(err, errors2.PROFILE_NOT_FOUND.Code) {
+        utils.HandleError(writer, err)
+        return
+    }
 }
 if existingProfile == nil {
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4c505d5 and 4c2bfe2.

📒 Files selected for processing (2)
  • internal/profile/handler/profile_handler.go (2 hunks)
  • internal/system/utils/error_utils.go (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
internal/profile/handler/profile_handler.go (3)
internal/system/utils/error_utils.go (1)
  • HasClientErrorCode (68-77)
internal/system/errors/error_codes.go (1)
  • PROFILE_NOT_FOUND (182-186)
internal/system/utils/http_utils.go (1)
  • HandleError (35-62)
internal/system/utils/error_utils.go (1)
internal/system/errors/error.go (2)
  • ClientError (30-33)
  • ErrorMessage (23-28)
🔇 Additional comments (2)
internal/system/utils/error_utils.go (2)

26-28: LGTM! Clean import addition.

The cdsErrors alias import is well-chosen for clarity and necessary for the new error checking utility.


67-77: LGTM! Well-implemented error utility.

The function correctly uses errors.As to detect wrapped ClientError instances and safely compares error codes. The nil check and fallback logic are both appropriate.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
test/integration/profile_unification_test.go (1)

57-78: Add validation to ensure attribute OrgId matches the orgId parameter.

The service layer validates attributes using attr.OrgId (line 82-87), but the store layer inserts using the orgId parameter (line 83-85 in store). There is no validation ensuring these two values match.

If they ever diverge, attributes could be inserted to the wrong organization while validation was performed against a different one. This creates a security and data integrity risk.

Add explicit validation in the service layer to ensure attr.OrgId == orgId before calling the store, or refactor to use a single authoritative source for the organization ID.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f7e141f and 4488cd3.

📒 Files selected for processing (3)
  • internal/profile/handler/profile_handler.go (5 hunks)
  • internal/system/errors/error_codes.go (1 hunks)
  • test/integration/profile_unification_test.go (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
internal/system/errors/error_codes.go (1)
internal/system/errors/error.go (1)
  • ErrorMessage (23-28)
test/integration/profile_unification_test.go (2)
internal/profile_schema/store/profile_schema_store.go (1)
  • AddProfileSchemaAttributesForScope (36-103)
internal/system/constants/constants.go (2)
  • IdentityAttributes (81-81)
  • Traits (82-82)
🔇 Additional comments (8)
internal/system/errors/error_codes.go (1)

388-392: LGTM - New error code for CDS enablement check.

The error definition is clear and follows existing patterns. Note: the code uses prefix 15xxx which elsewhere appears alongside server errors, while this is semantically a client/configuration error. Given existing inconsistencies in the file (e.g., mixed prefixes), this is acceptable, but consider standardizing error code prefixes in a future refactor.

internal/profile/handler/profile_handler.go (4)

28-30: LGTM - Import for admin config service.

The import is required for the new CDS enablement check functionality.


720-730: LGTM - CDS enablement guard for SyncProfile.

The early return pattern with appropriate error response is correct for gating CDS-dependent operations.


775-778: LGTM - Improved error handling for POST_ADD_USER flow.

Using HasClientErrorCode to specifically check for PROFILE_NOT_FOUND allows the flow to gracefully continue with profile creation for new users, while still propagating unexpected errors.


1053-1057: Error handling in AdminConfigService.IsCDSEnabled is correct.

The IsCDSEnabled implementation properly handles errors from store.GetAdminConfig() and defaults to false on failure, which is the safe default for a feature-flag check. It does not panic and maintains predictable behavior across database failures and config fetch errors.

test/integration/profile_unification_test.go (3)

24-25: LGTM! Required imports added correctly.

The testing and time imports are properly added to support the test infrastructure and unique organization identifier generation.


52-52: Good practice for test isolation.

Using time.Now().UnixNano() to generate unique organization identifiers ensures test isolation across runs. The nanosecond precision provides sufficient uniqueness for integration tests.


318-322: Same consistency concern applies here.

Similar to lines 76-78, the attribute at line 319 contains OrgId: OtherTenant, which is also passed as the third parameter to AddProfileSchemaAttributesForScope at line 322. Ensure consistency between these two values as mentioned in the earlier comment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants