From 3f1819f22a2b88eea3bc63c2a7a79d6c093a3997 Mon Sep 17 00:00:00 2001 From: Bikram Choudhury Date: Thu, 26 Mar 2026 12:59:15 +0530 Subject: [PATCH] upgrade RBAC permissions from read only to read-write --- .../ContainerCopy/ContainerCopyMessages.ts | 14 ++--- .../Context/CopyJobContext.test.tsx | 6 +-- .../ContainerCopy/Context/CopyJobContext.tsx | 2 +- .../AddManagedIdentity.test.tsx | 2 +- ...ddReadPermissionToDefaultIdentity.test.tsx | 32 ++++++------ ...dReadWritePermissionToDefaultIdentity.tsx} | 37 +++++++------ .../AssignPermissions.test.tsx | 14 ++--- .../PointInTimeRestore.test.tsx | 2 +- ...dPermissionToDefaultIdentity.test.tsx.snap | 40 +++++++------- .../AssignPermissions.test.tsx.snap | 12 ++--- .../hooks/usePermissionsSection.test.tsx | 50 ++++++++++-------- .../hooks/usePermissionsSection.tsx | 52 +++++++++++++------ .../AddCollectionPanelWrapper.test.tsx | 2 +- .../PreviewCopyJob/PreviewCopyJob.test.tsx | 4 +- .../Components/AccountDropdown.test.tsx | 2 +- .../Components/MigrationType.test.tsx | 2 +- .../SelectAccount/SelectAccount.test.tsx | 2 +- .../Events/DropDownChangeHandler.test.tsx | 6 +-- .../SelectSourceAndTargetContainers.test.tsx | 2 +- .../memoizedData.test.tsx | 2 +- .../ContainerCopy/Types/CopyJobTypes.ts | 2 +- src/Utils/arm/RbacUtils.ts | 2 +- 22 files changed, 157 insertions(+), 132 deletions(-) rename src/Explorer/ContainerCopy/CreateCopyJob/Screens/AssignPermissions/{AddReadPermissionToDefaultIdentity.tsx => AddReadWritePermissionToDefaultIdentity.tsx} (65%) diff --git a/src/Explorer/ContainerCopy/ContainerCopyMessages.ts b/src/Explorer/ContainerCopy/ContainerCopyMessages.ts index 8ccf368ec..c3eceeeed 100644 --- a/src/Explorer/ContainerCopy/ContainerCopyMessages.ts +++ b/src/Explorer/ContainerCopy/ContainerCopyMessages.ts @@ -66,7 +66,7 @@ export default { // Assign Permissions Screen assignPermissions: { crossAccountDescription: - "To copy data from the source to the destination container, ensure that the managed identity of the destination account has read access to the source account by completing the following steps.", + "To copy data from the source to the destination container, ensure that the managed identity of the destination account has read-write access to the source account by completing the following steps.", intraAccountOnlineDescription: (accountName: string) => `Follow the steps below to enable online copy on your "${accountName}" account.`, crossAccountConfiguration: { @@ -119,18 +119,18 @@ export default { popoverDescription: (accountName: string) => `Assign the system-assigned managed identity as the default for "${accountName}". To confirm, click the "Yes" button. `, }, - readPermissionAssigned: { - title: "Read permissions assigned to the default identity.", + readWritePermissionAssigned: { + title: "Read-write permissions assigned to the default identity.", description: - "To allow data copy from source to the destination container, provide read access of the source account to the default identity of the destination account.", + "To allow data copy from source to the destination container, provide read-write access on the source account to the default identity of the destination account.", tooltip: { content: "Learn more about", - hrefText: "Read permissions.", + hrefText: "Read-write permissions.", href: "https://learn.microsoft.com/azure/cosmos-db/nosql/how-to-connect-role-based-access-control", }, - popoverTitle: "Read permissions assigned to default identity.", + popoverTitle: "Assign read-write permissions to default identity.", popoverDescription: - "Assign read permissions of the source account to the default identity of the destination account. To confirm click the “Yes” button.", + 'Assign read-write permissions on the source account to the default identity of the destination account. To confirm, click the "Yes" button.', }, pointInTimeRestore: { title: "Point In Time Restore enabled", diff --git a/src/Explorer/ContainerCopy/Context/CopyJobContext.test.tsx b/src/Explorer/ContainerCopy/Context/CopyJobContext.test.tsx index c3383077d..f263f3cb3 100644 --- a/src/Explorer/ContainerCopy/Context/CopyJobContext.test.tsx +++ b/src/Explorer/ContainerCopy/Context/CopyJobContext.test.tsx @@ -75,7 +75,7 @@ describe("CopyJobContext", () => { databaseId: "", containerId: "", }, - sourceReadAccessFromTarget: false, + sourceReadWriteAccessFromTarget: false, }); expect(contextValue.flow).toBeNull(); expect(contextValue.contextError).toBeNull(); @@ -620,7 +620,7 @@ describe("CopyJobContext", () => { expect(contextValue.copyJobState.target.account).toBeNull(); }); - it("should initialize sourceReadAccessFromTarget as false", () => { + it("should initialize sourceReadWriteAccessFromTarget as false", () => { let contextValue: any; render( @@ -634,7 +634,7 @@ describe("CopyJobContext", () => { , ); - expect(contextValue.copyJobState.sourceReadAccessFromTarget).toBe(false); + expect(contextValue.copyJobState.sourceReadWriteAccessFromTarget).toBe(false); }); it("should initialize with empty database and container ids", () => { diff --git a/src/Explorer/ContainerCopy/Context/CopyJobContext.tsx b/src/Explorer/ContainerCopy/Context/CopyJobContext.tsx index 72cb59527..912ed0311 100644 --- a/src/Explorer/ContainerCopy/Context/CopyJobContext.tsx +++ b/src/Explorer/ContainerCopy/Context/CopyJobContext.tsx @@ -34,7 +34,7 @@ const getInitialCopyJobState = (): CopyJobContextState => { databaseId: "", containerId: "", }, - sourceReadAccessFromTarget: false, + sourceReadWriteAccessFromTarget: false, }; }; diff --git a/src/Explorer/ContainerCopy/CreateCopyJob/Screens/AssignPermissions/AddManagedIdentity.test.tsx b/src/Explorer/ContainerCopy/CreateCopyJob/Screens/AssignPermissions/AddManagedIdentity.test.tsx index 6022b98d4..dbf5301fa 100644 --- a/src/Explorer/ContainerCopy/CreateCopyJob/Screens/AssignPermissions/AddManagedIdentity.test.tsx +++ b/src/Explorer/ContainerCopy/CreateCopyJob/Screens/AssignPermissions/AddManagedIdentity.test.tsx @@ -67,7 +67,7 @@ describe("AddManagedIdentity", () => { databaseId: "target-db", containerId: "target-container", }, - sourceReadAccessFromTarget: false, + sourceReadWriteAccessFromTarget: false, }; const mockContextValue = { diff --git a/src/Explorer/ContainerCopy/CreateCopyJob/Screens/AssignPermissions/AddReadPermissionToDefaultIdentity.test.tsx b/src/Explorer/ContainerCopy/CreateCopyJob/Screens/AssignPermissions/AddReadPermissionToDefaultIdentity.test.tsx index 2aa90265a..4be27382f 100644 --- a/src/Explorer/ContainerCopy/CreateCopyJob/Screens/AssignPermissions/AddReadPermissionToDefaultIdentity.test.tsx +++ b/src/Explorer/ContainerCopy/CreateCopyJob/Screens/AssignPermissions/AddReadPermissionToDefaultIdentity.test.tsx @@ -4,7 +4,7 @@ import React from "react"; import ContainerCopyMessages from "../../../ContainerCopyMessages"; import { CopyJobContext } from "../../../Context/CopyJobContext"; import { CopyJobContextProviderType } from "../../../Types/CopyJobTypes"; -import AddReadPermissionToDefaultIdentity from "./AddReadPermissionToDefaultIdentity"; +import AddReadWritePermissionToDefaultIdentity from "./AddReadWritePermissionToDefaultIdentity"; jest.mock("../../../../../Common/Logger", () => ({ logError: jest.fn(), @@ -73,7 +73,7 @@ import { assignRole, RoleAssignmentType } from "../../../../../Utils/arm/RbacUti import { getAccountDetailsFromResourceId } from "../../../CopyJobUtils"; import useToggle from "./hooks/useToggle"; -describe("AddReadPermissionToDefaultIdentity Component", () => { +describe("AddReadWritePermissionToDefaultIdentity Component", () => { const mockUseToggle = useToggle as jest.MockedFunction; const mockAssignRole = assignRole as jest.MockedFunction; const mockGetAccountDetailsFromResourceId = getAccountDetailsFromResourceId as jest.MockedFunction< @@ -119,7 +119,7 @@ describe("AddReadPermissionToDefaultIdentity Component", () => { databaseId: "target-db", containerId: "target-container", }, - sourceReadAccessFromTarget: false, + sourceReadWriteAccessFromTarget: false, }, setCopyJobState: jest.fn(), setContextError: jest.fn(), @@ -133,7 +133,7 @@ describe("AddReadPermissionToDefaultIdentity Component", () => { const renderComponent = (contextValue = mockContextValue) => { return render( - + , ); }; @@ -164,12 +164,12 @@ describe("AddReadPermissionToDefaultIdentity Component", () => { expect(container).toMatchSnapshot(); }); - it("should render correctly when sourceReadAccessFromTarget is true", () => { + it("should render correctly when sourceReadWriteAccessFromTarget is true", () => { const contextWithAccess = { ...mockContextValue, copyJobState: { ...mockContextValue.copyJobState, - sourceReadAccessFromTarget: true, + sourceReadWriteAccessFromTarget: true, }, }; const { container } = renderComponent(contextWithAccess); @@ -180,7 +180,7 @@ describe("AddReadPermissionToDefaultIdentity Component", () => { describe("Component Structure", () => { it("should display the description text", () => { renderComponent(); - expect(screen.getByText(ContainerCopyMessages.readPermissionAssigned.description)).toBeInTheDocument(); + expect(screen.getByText(ContainerCopyMessages.readWritePermissionAssigned.description)).toBeInTheDocument(); }); it("should display the info tooltip", () => { @@ -212,10 +212,10 @@ describe("AddReadPermissionToDefaultIdentity Component", () => { expect(screen.getByTestId("popover-message")).toBeInTheDocument(); expect(screen.getByTestId("popover-title")).toHaveTextContent( - ContainerCopyMessages.readPermissionAssigned.popoverTitle, + ContainerCopyMessages.readWritePermissionAssigned.popoverTitle, ); expect(screen.getByTestId("popover-content")).toHaveTextContent( - ContainerCopyMessages.readPermissionAssigned.popoverDescription, + ContainerCopyMessages.readWritePermissionAssigned.popoverDescription, ); }); @@ -243,7 +243,7 @@ describe("AddReadPermissionToDefaultIdentity Component", () => { expect(mockOnToggle).toHaveBeenCalledWith(null, false); }); - it("should call handleAddReadPermission when primary button is clicked", async () => { + it("should call handleAddReadWritePermission when primary button is clicked", async () => { mockGetAccountDetailsFromResourceId.mockReturnValue({ subscriptionId: "source-sub-id", resourceGroup: "source-rg", @@ -264,7 +264,7 @@ describe("AddReadPermissionToDefaultIdentity Component", () => { }); }); - describe("handleAddReadPermission Function", () => { + describe("handleAddReadWritePermission Function", () => { beforeEach(() => { mockUseToggle.mockReturnValue([true, jest.fn()]); }); @@ -312,7 +312,7 @@ describe("AddReadPermissionToDefaultIdentity Component", () => { await waitFor(() => { expect(mockLogError).toHaveBeenCalledWith( "Permission denied", - "CopyJob/AddReadPermissionToDefaultIdentity.handleAddReadPermission", + "CopyJob/AddReadWritePermissionToDefaultIdentity.handleAddReadWritePermission", ); }); @@ -336,14 +336,14 @@ describe("AddReadPermissionToDefaultIdentity Component", () => { await waitFor(() => { expect(mockLogError).toHaveBeenCalledWith( - "Error assigning read permission to default identity. Please try again later.", - "CopyJob/AddReadPermissionToDefaultIdentity.handleAddReadPermission", + "Error assigning read-write permission to default identity. Please try again later.", + "CopyJob/AddReadWritePermissionToDefaultIdentity.handleAddReadWritePermission", ); }); await waitFor(() => { expect(mockContextValue.setContextError).toHaveBeenCalledWith( - "Error assigning read permission to default identity. Please try again later.", + "Error assigning read-write permission to default identity. Please try again later.", ); }); }); @@ -496,7 +496,7 @@ describe("AddReadPermissionToDefaultIdentity Component", () => { expect(updatedState).toEqual({ ...mockContextValue.copyJobState, - sourceReadAccessFromTarget: true, + sourceReadWriteAccessFromTarget: true, }); }); }); diff --git a/src/Explorer/ContainerCopy/CreateCopyJob/Screens/AssignPermissions/AddReadPermissionToDefaultIdentity.tsx b/src/Explorer/ContainerCopy/CreateCopyJob/Screens/AssignPermissions/AddReadWritePermissionToDefaultIdentity.tsx similarity index 65% rename from src/Explorer/ContainerCopy/CreateCopyJob/Screens/AssignPermissions/AddReadPermissionToDefaultIdentity.tsx rename to src/Explorer/ContainerCopy/CreateCopyJob/Screens/AssignPermissions/AddReadWritePermissionToDefaultIdentity.tsx index 5af5630d7..789bf87d1 100644 --- a/src/Explorer/ContainerCopy/CreateCopyJob/Screens/AssignPermissions/AddReadPermissionToDefaultIdentity.tsx +++ b/src/Explorer/ContainerCopy/CreateCopyJob/Screens/AssignPermissions/AddReadWritePermissionToDefaultIdentity.tsx @@ -12,27 +12,29 @@ import useToggle from "./hooks/useToggle"; const TooltipContent = ( - {ContainerCopyMessages.readPermissionAssigned.tooltip.content}   + {ContainerCopyMessages.readWritePermissionAssigned.tooltip.content}   - {ContainerCopyMessages.readPermissionAssigned.tooltip.hrefText} + {ContainerCopyMessages.readWritePermissionAssigned.tooltip.hrefText} ); -type AddReadPermissionToDefaultIdentityProps = Partial; -const AddReadPermissionToDefaultIdentity: React.FC = () => { +type AddReadWritePermissionToDefaultIdentityProps = Partial; + +const AddReadWritePermissionToDefaultIdentity: React.FC = () => { const [loading, setLoading] = React.useState(false); const { copyJobState, setCopyJobState, setContextError } = useCopyJobContext(); - const [readPermissionAssigned, onToggle] = useToggle(false); + const [readWritePermissionAssigned, onToggle] = useToggle(copyJobState.sourceReadWriteAccessFromTarget ?? false); - const handleAddReadPermission = async () => { + const handleAddReadWritePermission = async () => { const { source, target } = copyJobState; const selectedSourceAccount = source?.account; + try { const { subscriptionId: sourceSubscriptionId, @@ -47,16 +49,17 @@ const AddReadPermissionToDefaultIdentity: React.FC ({ ...prevState, - sourceReadAccessFromTarget: true, + sourceReadWriteAccessFromTarget: true, })); } } catch (error) { const errorMessage = - error.message || "Error assigning read permission to default identity. Please try again later."; - logError(errorMessage, "CopyJob/AddReadPermissionToDefaultIdentity.handleAddReadPermission"); + error.message || "Error assigning read-write permission to default identity. Please try again later."; + logError(errorMessage, "CopyJob/AddReadWritePermissionToDefaultIdentity.handleAddReadWritePermission"); setContextError(errorMessage); } finally { setLoading(false); @@ -66,12 +69,12 @@ const AddReadPermissionToDefaultIdentity: React.FC - {ContainerCopyMessages.readPermissionAssigned.description}  + {ContainerCopyMessages.readWritePermissionAssigned.description}  onToggle(null, false)} - onPrimary={handleAddReadPermission} + onPrimary={handleAddReadWritePermission} > - {ContainerCopyMessages.readPermissionAssigned.popoverDescription} + {ContainerCopyMessages.readWritePermissionAssigned.popoverDescription} ); }; -export default AddReadPermissionToDefaultIdentity; +export default AddReadWritePermissionToDefaultIdentity; diff --git a/src/Explorer/ContainerCopy/CreateCopyJob/Screens/AssignPermissions/AssignPermissions.test.tsx b/src/Explorer/ContainerCopy/CreateCopyJob/Screens/AssignPermissions/AssignPermissions.test.tsx index 1849a1385..da96b74ac 100644 --- a/src/Explorer/ContainerCopy/CreateCopyJob/Screens/AssignPermissions/AssignPermissions.test.tsx +++ b/src/Explorer/ContainerCopy/CreateCopyJob/Screens/AssignPermissions/AssignPermissions.test.tsx @@ -43,12 +43,12 @@ jest.mock("./AddManagedIdentity", () => { return MockAddManagedIdentity; }); -jest.mock("./AddReadPermissionToDefaultIdentity", () => { - const MockAddReadPermissionToDefaultIdentity = () => { - return
Add Read Permission Component
; +jest.mock("./AddReadWritePermissionToDefaultIdentity", () => { + const MockAddReadWritePermissionToDefaultIdentity = () => { + return
Add Read-Write Permission Component
; }; - MockAddReadPermissionToDefaultIdentity.displayName = "MockAddReadPermissionToDefaultIdentity"; - return MockAddReadPermissionToDefaultIdentity; + MockAddReadWritePermissionToDefaultIdentity.displayName = "MockAddReadWritePermissionToDefaultIdentity"; + return MockAddReadWritePermissionToDefaultIdentity; }); jest.mock("./DefaultManagedIdentity", () => { @@ -96,7 +96,7 @@ describe("AssignPermissions Component", () => { databaseId: "target-db", containerId: "target-container", }, - sourceReadAccessFromTarget: false, + sourceReadWriteAccessFromTarget: false, ...overrides, }); @@ -201,7 +201,7 @@ describe("AssignPermissions Component", () => { completed: true, }, { - id: "readPermissionAssigned", + id: "readWritePermissionAssigned", title: "Read Permission Assigned", Component: () =>
Add Read Permission Component
, disabled: false, diff --git a/src/Explorer/ContainerCopy/CreateCopyJob/Screens/AssignPermissions/PointInTimeRestore.test.tsx b/src/Explorer/ContainerCopy/CreateCopyJob/Screens/AssignPermissions/PointInTimeRestore.test.tsx index 58ab0745b..ee3e7859b 100644 --- a/src/Explorer/ContainerCopy/CreateCopyJob/Screens/AssignPermissions/PointInTimeRestore.test.tsx +++ b/src/Explorer/ContainerCopy/CreateCopyJob/Screens/AssignPermissions/PointInTimeRestore.test.tsx @@ -61,7 +61,7 @@ describe("PointInTimeRestore", () => { databaseId: "target-db", containerId: "target-container", }, - sourceReadAccessFromTarget: false, + sourceReadWriteAccessFromTarget: false, } as CopyJobContextState; const mockSetCopyJobState = jest.fn(); diff --git a/src/Explorer/ContainerCopy/CreateCopyJob/Screens/AssignPermissions/__snapshots__/AddReadPermissionToDefaultIdentity.test.tsx.snap b/src/Explorer/ContainerCopy/CreateCopyJob/Screens/AssignPermissions/__snapshots__/AddReadPermissionToDefaultIdentity.test.tsx.snap index e000b1285..88b5e6665 100644 --- a/src/Explorer/ContainerCopy/CreateCopyJob/Screens/AssignPermissions/__snapshots__/AddReadPermissionToDefaultIdentity.test.tsx.snap +++ b/src/Explorer/ContainerCopy/CreateCopyJob/Screens/AssignPermissions/__snapshots__/AddReadPermissionToDefaultIdentity.test.tsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`AddReadPermissionToDefaultIdentity Component Edge Cases should handle missing source account 1`] = ` +exports[`AddReadWritePermissionToDefaultIdentity Component Edge Cases should handle missing source account 1`] = `
- To allow data copy from source to the destination container, provide read access of the source account to the default identity of the destination account. + To allow data copy from source to the destination container, provide read-write access on the source account to the default identity of the destination account.  
- Read permissions. + Read-write permissions.
@@ -63,7 +63,7 @@ exports[`AddReadPermissionToDefaultIdentity Component Edge Cases should handle m
`; -exports[`AddReadPermissionToDefaultIdentity Component Edge Cases should handle missing target account identity 1`] = ` +exports[`AddReadWritePermissionToDefaultIdentity Component Edge Cases should handle missing target account identity 1`] = `
- To allow data copy from source to the destination container, provide read access of the source account to the default identity of the destination account. + To allow data copy from source to the destination container, provide read-write access on the source account to the default identity of the destination account.  
- Read permissions. + Read-write permissions.
@@ -126,7 +126,7 @@ exports[`AddReadPermissionToDefaultIdentity Component Edge Cases should handle m
`; -exports[`AddReadPermissionToDefaultIdentity Component Rendering should render correctly when sourceReadAccessFromTarget is true 1`] = ` +exports[`AddReadWritePermissionToDefaultIdentity Component Rendering should render correctly when sourceReadWriteAccessFromTarget is true 1`] = `
- To allow data copy from source to the destination container, provide read access of the source account to the default identity of the destination account. + To allow data copy from source to the destination container, provide read-write access on the source account to the default identity of the destination account.  
- Read permissions. + Read-write permissions.
@@ -189,7 +189,7 @@ exports[`AddReadPermissionToDefaultIdentity Component Rendering should render co
`; -exports[`AddReadPermissionToDefaultIdentity Component Rendering should render correctly when toggle is on 1`] = ` +exports[`AddReadWritePermissionToDefaultIdentity Component Rendering should render correctly when toggle is on 1`] = `
- To allow data copy from source to the destination container, provide read access of the source account to the default identity of the destination account. + To allow data copy from source to the destination container, provide read-write access on the source account to the default identity of the destination account.  
- Read permissions. + Read-write permissions.
@@ -255,12 +255,12 @@ exports[`AddReadPermissionToDefaultIdentity Component Rendering should render co
- Read permissions assigned to default identity. + Assign read-write permissions to default identity.
- Assign read permissions of the source account to the default identity of the destination account. To confirm click the “Yes” button. + Assign read-write permissions on the source account to the default identity of the destination account. To confirm, click the "Yes" button.