upgrade RBAC permissions from read only to read-write

This commit is contained in:
Bikram Choudhury
2026-03-26 12:59:15 +05:30
committed by BChoudhury-ms
parent 8698c6a3e2
commit 3f1819f22a
22 changed files with 157 additions and 132 deletions

View File

@@ -66,7 +66,7 @@ export default {
// Assign Permissions Screen // Assign Permissions Screen
assignPermissions: { assignPermissions: {
crossAccountDescription: 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) => intraAccountOnlineDescription: (accountName: string) =>
`Follow the steps below to enable online copy on your "${accountName}" account.`, `Follow the steps below to enable online copy on your "${accountName}" account.`,
crossAccountConfiguration: { crossAccountConfiguration: {
@@ -119,18 +119,18 @@ export default {
popoverDescription: (accountName: string) => popoverDescription: (accountName: string) =>
`Assign the system-assigned managed identity as the default for "${accountName}". To confirm, click the "Yes" button. `, `Assign the system-assigned managed identity as the default for "${accountName}". To confirm, click the "Yes" button. `,
}, },
readPermissionAssigned: { readWritePermissionAssigned: {
title: "Read permissions assigned to the default identity.", title: "Read-write permissions assigned to the default identity.",
description: 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: { tooltip: {
content: "Learn more about", 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", 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: 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: { pointInTimeRestore: {
title: "Point In Time Restore enabled", title: "Point In Time Restore enabled",

View File

@@ -75,7 +75,7 @@ describe("CopyJobContext", () => {
databaseId: "", databaseId: "",
containerId: "", containerId: "",
}, },
sourceReadAccessFromTarget: false, sourceReadWriteAccessFromTarget: false,
}); });
expect(contextValue.flow).toBeNull(); expect(contextValue.flow).toBeNull();
expect(contextValue.contextError).toBeNull(); expect(contextValue.contextError).toBeNull();
@@ -620,7 +620,7 @@ describe("CopyJobContext", () => {
expect(contextValue.copyJobState.target.account).toBeNull(); expect(contextValue.copyJobState.target.account).toBeNull();
}); });
it("should initialize sourceReadAccessFromTarget as false", () => { it("should initialize sourceReadWriteAccessFromTarget as false", () => {
let contextValue: any; let contextValue: any;
render( render(
@@ -634,7 +634,7 @@ describe("CopyJobContext", () => {
</CopyJobContextProvider>, </CopyJobContextProvider>,
); );
expect(contextValue.copyJobState.sourceReadAccessFromTarget).toBe(false); expect(contextValue.copyJobState.sourceReadWriteAccessFromTarget).toBe(false);
}); });
it("should initialize with empty database and container ids", () => { it("should initialize with empty database and container ids", () => {

View File

@@ -34,7 +34,7 @@ const getInitialCopyJobState = (): CopyJobContextState => {
databaseId: "", databaseId: "",
containerId: "", containerId: "",
}, },
sourceReadAccessFromTarget: false, sourceReadWriteAccessFromTarget: false,
}; };
}; };

View File

@@ -67,7 +67,7 @@ describe("AddManagedIdentity", () => {
databaseId: "target-db", databaseId: "target-db",
containerId: "target-container", containerId: "target-container",
}, },
sourceReadAccessFromTarget: false, sourceReadWriteAccessFromTarget: false,
}; };
const mockContextValue = { const mockContextValue = {

View File

@@ -4,7 +4,7 @@ import React from "react";
import ContainerCopyMessages from "../../../ContainerCopyMessages"; import ContainerCopyMessages from "../../../ContainerCopyMessages";
import { CopyJobContext } from "../../../Context/CopyJobContext"; import { CopyJobContext } from "../../../Context/CopyJobContext";
import { CopyJobContextProviderType } from "../../../Types/CopyJobTypes"; import { CopyJobContextProviderType } from "../../../Types/CopyJobTypes";
import AddReadPermissionToDefaultIdentity from "./AddReadPermissionToDefaultIdentity"; import AddReadWritePermissionToDefaultIdentity from "./AddReadWritePermissionToDefaultIdentity";
jest.mock("../../../../../Common/Logger", () => ({ jest.mock("../../../../../Common/Logger", () => ({
logError: jest.fn(), logError: jest.fn(),
@@ -73,7 +73,7 @@ import { assignRole, RoleAssignmentType } from "../../../../../Utils/arm/RbacUti
import { getAccountDetailsFromResourceId } from "../../../CopyJobUtils"; import { getAccountDetailsFromResourceId } from "../../../CopyJobUtils";
import useToggle from "./hooks/useToggle"; import useToggle from "./hooks/useToggle";
describe("AddReadPermissionToDefaultIdentity Component", () => { describe("AddReadWritePermissionToDefaultIdentity Component", () => {
const mockUseToggle = useToggle as jest.MockedFunction<typeof useToggle>; const mockUseToggle = useToggle as jest.MockedFunction<typeof useToggle>;
const mockAssignRole = assignRole as jest.MockedFunction<typeof assignRole>; const mockAssignRole = assignRole as jest.MockedFunction<typeof assignRole>;
const mockGetAccountDetailsFromResourceId = getAccountDetailsFromResourceId as jest.MockedFunction< const mockGetAccountDetailsFromResourceId = getAccountDetailsFromResourceId as jest.MockedFunction<
@@ -119,7 +119,7 @@ describe("AddReadPermissionToDefaultIdentity Component", () => {
databaseId: "target-db", databaseId: "target-db",
containerId: "target-container", containerId: "target-container",
}, },
sourceReadAccessFromTarget: false, sourceReadWriteAccessFromTarget: false,
}, },
setCopyJobState: jest.fn(), setCopyJobState: jest.fn(),
setContextError: jest.fn(), setContextError: jest.fn(),
@@ -133,7 +133,7 @@ describe("AddReadPermissionToDefaultIdentity Component", () => {
const renderComponent = (contextValue = mockContextValue) => { const renderComponent = (contextValue = mockContextValue) => {
return render( return render(
<CopyJobContext.Provider value={contextValue}> <CopyJobContext.Provider value={contextValue}>
<AddReadPermissionToDefaultIdentity /> <AddReadWritePermissionToDefaultIdentity />
</CopyJobContext.Provider>, </CopyJobContext.Provider>,
); );
}; };
@@ -164,12 +164,12 @@ describe("AddReadPermissionToDefaultIdentity Component", () => {
expect(container).toMatchSnapshot(); expect(container).toMatchSnapshot();
}); });
it("should render correctly when sourceReadAccessFromTarget is true", () => { it("should render correctly when sourceReadWriteAccessFromTarget is true", () => {
const contextWithAccess = { const contextWithAccess = {
...mockContextValue, ...mockContextValue,
copyJobState: { copyJobState: {
...mockContextValue.copyJobState, ...mockContextValue.copyJobState,
sourceReadAccessFromTarget: true, sourceReadWriteAccessFromTarget: true,
}, },
}; };
const { container } = renderComponent(contextWithAccess); const { container } = renderComponent(contextWithAccess);
@@ -180,7 +180,7 @@ describe("AddReadPermissionToDefaultIdentity Component", () => {
describe("Component Structure", () => { describe("Component Structure", () => {
it("should display the description text", () => { it("should display the description text", () => {
renderComponent(); renderComponent();
expect(screen.getByText(ContainerCopyMessages.readPermissionAssigned.description)).toBeInTheDocument(); expect(screen.getByText(ContainerCopyMessages.readWritePermissionAssigned.description)).toBeInTheDocument();
}); });
it("should display the info tooltip", () => { it("should display the info tooltip", () => {
@@ -212,10 +212,10 @@ describe("AddReadPermissionToDefaultIdentity Component", () => {
expect(screen.getByTestId("popover-message")).toBeInTheDocument(); expect(screen.getByTestId("popover-message")).toBeInTheDocument();
expect(screen.getByTestId("popover-title")).toHaveTextContent( expect(screen.getByTestId("popover-title")).toHaveTextContent(
ContainerCopyMessages.readPermissionAssigned.popoverTitle, ContainerCopyMessages.readWritePermissionAssigned.popoverTitle,
); );
expect(screen.getByTestId("popover-content")).toHaveTextContent( expect(screen.getByTestId("popover-content")).toHaveTextContent(
ContainerCopyMessages.readPermissionAssigned.popoverDescription, ContainerCopyMessages.readWritePermissionAssigned.popoverDescription,
); );
}); });
@@ -243,7 +243,7 @@ describe("AddReadPermissionToDefaultIdentity Component", () => {
expect(mockOnToggle).toHaveBeenCalledWith(null, false); 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({ mockGetAccountDetailsFromResourceId.mockReturnValue({
subscriptionId: "source-sub-id", subscriptionId: "source-sub-id",
resourceGroup: "source-rg", resourceGroup: "source-rg",
@@ -264,7 +264,7 @@ describe("AddReadPermissionToDefaultIdentity Component", () => {
}); });
}); });
describe("handleAddReadPermission Function", () => { describe("handleAddReadWritePermission Function", () => {
beforeEach(() => { beforeEach(() => {
mockUseToggle.mockReturnValue([true, jest.fn()]); mockUseToggle.mockReturnValue([true, jest.fn()]);
}); });
@@ -312,7 +312,7 @@ describe("AddReadPermissionToDefaultIdentity Component", () => {
await waitFor(() => { await waitFor(() => {
expect(mockLogError).toHaveBeenCalledWith( expect(mockLogError).toHaveBeenCalledWith(
"Permission denied", "Permission denied",
"CopyJob/AddReadPermissionToDefaultIdentity.handleAddReadPermission", "CopyJob/AddReadWritePermissionToDefaultIdentity.handleAddReadWritePermission",
); );
}); });
@@ -336,14 +336,14 @@ describe("AddReadPermissionToDefaultIdentity Component", () => {
await waitFor(() => { await waitFor(() => {
expect(mockLogError).toHaveBeenCalledWith( expect(mockLogError).toHaveBeenCalledWith(
"Error assigning read permission to default identity. Please try again later.", "Error assigning read-write permission to default identity. Please try again later.",
"CopyJob/AddReadPermissionToDefaultIdentity.handleAddReadPermission", "CopyJob/AddReadWritePermissionToDefaultIdentity.handleAddReadWritePermission",
); );
}); });
await waitFor(() => { await waitFor(() => {
expect(mockContextValue.setContextError).toHaveBeenCalledWith( 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({ expect(updatedState).toEqual({
...mockContextValue.copyJobState, ...mockContextValue.copyJobState,
sourceReadAccessFromTarget: true, sourceReadWriteAccessFromTarget: true,
}); });
}); });
}); });

View File

@@ -12,27 +12,29 @@ import useToggle from "./hooks/useToggle";
const TooltipContent = ( const TooltipContent = (
<Text> <Text>
{ContainerCopyMessages.readPermissionAssigned.tooltip.content} &nbsp; {ContainerCopyMessages.readWritePermissionAssigned.tooltip.content} &nbsp;
<Link <Link
style={{ color: "var(--colorBrandForeground1)" }} style={{ color: "var(--colorBrandForeground1)" }}
href={ContainerCopyMessages.readPermissionAssigned.tooltip.href} href={ContainerCopyMessages.readWritePermissionAssigned.tooltip.href}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
> >
{ContainerCopyMessages.readPermissionAssigned.tooltip.hrefText} {ContainerCopyMessages.readWritePermissionAssigned.tooltip.hrefText}
</Link> </Link>
</Text> </Text>
); );
type AddReadPermissionToDefaultIdentityProps = Partial<PermissionSectionConfig>;
const AddReadPermissionToDefaultIdentity: React.FC<AddReadPermissionToDefaultIdentityProps> = () => { type AddReadWritePermissionToDefaultIdentityProps = Partial<PermissionSectionConfig>;
const AddReadWritePermissionToDefaultIdentity: React.FC<AddReadWritePermissionToDefaultIdentityProps> = () => {
const [loading, setLoading] = React.useState(false); const [loading, setLoading] = React.useState(false);
const { copyJobState, setCopyJobState, setContextError } = useCopyJobContext(); 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 { source, target } = copyJobState;
const selectedSourceAccount = source?.account; const selectedSourceAccount = source?.account;
try { try {
const { const {
subscriptionId: sourceSubscriptionId, subscriptionId: sourceSubscriptionId,
@@ -47,16 +49,17 @@ const AddReadPermissionToDefaultIdentity: React.FC<AddReadPermissionToDefaultIde
sourceAccountName, sourceAccountName,
target?.account?.identity?.principalId ?? "", target?.account?.identity?.principalId ?? "",
); );
if (assignedRole) { if (assignedRole) {
setCopyJobState((prevState) => ({ setCopyJobState((prevState) => ({
...prevState, ...prevState,
sourceReadAccessFromTarget: true, sourceReadWriteAccessFromTarget: true,
})); }));
} }
} catch (error) { } catch (error) {
const errorMessage = const errorMessage =
error.message || "Error assigning read permission to default identity. Please try again later."; error.message || "Error assigning read-write permission to default identity. Please try again later.";
logError(errorMessage, "CopyJob/AddReadPermissionToDefaultIdentity.handleAddReadPermission"); logError(errorMessage, "CopyJob/AddReadWritePermissionToDefaultIdentity.handleAddReadWritePermission");
setContextError(errorMessage); setContextError(errorMessage);
} finally { } finally {
setLoading(false); setLoading(false);
@@ -66,12 +69,12 @@ const AddReadPermissionToDefaultIdentity: React.FC<AddReadPermissionToDefaultIde
return ( return (
<Stack className="defaultManagedIdentityContainer" tokens={{ childrenGap: 15, padding: "0 0 0 20px" }}> <Stack className="defaultManagedIdentityContainer" tokens={{ childrenGap: 15, padding: "0 0 0 20px" }}>
<Text className="toggle-label"> <Text className="toggle-label">
{ContainerCopyMessages.readPermissionAssigned.description}&ensp; {ContainerCopyMessages.readWritePermissionAssigned.description}&ensp;
<InfoTooltip content={TooltipContent} /> <InfoTooltip content={TooltipContent} />
</Text> </Text>
<Toggle <Toggle
data-test="btn-toggle" data-test="btn-toggle"
checked={readPermissionAssigned} checked={readWritePermissionAssigned}
onText={ContainerCopyMessages.toggleBtn.onText} onText={ContainerCopyMessages.toggleBtn.onText}
offText={ContainerCopyMessages.toggleBtn.offText} offText={ContainerCopyMessages.toggleBtn.offText}
onChange={onToggle} onChange={onToggle}
@@ -83,15 +86,15 @@ const AddReadPermissionToDefaultIdentity: React.FC<AddReadPermissionToDefaultIde
/> />
<PopoverMessage <PopoverMessage
isLoading={loading} isLoading={loading}
visible={readPermissionAssigned} visible={readWritePermissionAssigned}
title={ContainerCopyMessages.readPermissionAssigned.popoverTitle} title={ContainerCopyMessages.readWritePermissionAssigned.popoverTitle}
onCancel={() => onToggle(null, false)} onCancel={() => onToggle(null, false)}
onPrimary={handleAddReadPermission} onPrimary={handleAddReadWritePermission}
> >
{ContainerCopyMessages.readPermissionAssigned.popoverDescription} {ContainerCopyMessages.readWritePermissionAssigned.popoverDescription}
</PopoverMessage> </PopoverMessage>
</Stack> </Stack>
); );
}; };
export default AddReadPermissionToDefaultIdentity; export default AddReadWritePermissionToDefaultIdentity;

View File

@@ -43,12 +43,12 @@ jest.mock("./AddManagedIdentity", () => {
return MockAddManagedIdentity; return MockAddManagedIdentity;
}); });
jest.mock("./AddReadPermissionToDefaultIdentity", () => { jest.mock("./AddReadWritePermissionToDefaultIdentity", () => {
const MockAddReadPermissionToDefaultIdentity = () => { const MockAddReadWritePermissionToDefaultIdentity = () => {
return <div data-testid="add-read-permission">Add Read Permission Component</div>; return <div data-testid="add-read-write-permission">Add Read-Write Permission Component</div>;
}; };
MockAddReadPermissionToDefaultIdentity.displayName = "MockAddReadPermissionToDefaultIdentity"; MockAddReadWritePermissionToDefaultIdentity.displayName = "MockAddReadWritePermissionToDefaultIdentity";
return MockAddReadPermissionToDefaultIdentity; return MockAddReadWritePermissionToDefaultIdentity;
}); });
jest.mock("./DefaultManagedIdentity", () => { jest.mock("./DefaultManagedIdentity", () => {
@@ -96,7 +96,7 @@ describe("AssignPermissions Component", () => {
databaseId: "target-db", databaseId: "target-db",
containerId: "target-container", containerId: "target-container",
}, },
sourceReadAccessFromTarget: false, sourceReadWriteAccessFromTarget: false,
...overrides, ...overrides,
}); });
@@ -201,7 +201,7 @@ describe("AssignPermissions Component", () => {
completed: true, completed: true,
}, },
{ {
id: "readPermissionAssigned", id: "readWritePermissionAssigned",
title: "Read Permission Assigned", title: "Read Permission Assigned",
Component: () => <div data-testid="add-read-permission">Add Read Permission Component</div>, Component: () => <div data-testid="add-read-permission">Add Read Permission Component</div>,
disabled: false, disabled: false,

View File

@@ -61,7 +61,7 @@ describe("PointInTimeRestore", () => {
databaseId: "target-db", databaseId: "target-db",
containerId: "target-container", containerId: "target-container",
}, },
sourceReadAccessFromTarget: false, sourceReadWriteAccessFromTarget: false,
} as CopyJobContextState; } as CopyJobContextState;
const mockSetCopyJobState = jest.fn(); const mockSetCopyJobState = jest.fn();

View File

@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // 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`] = `
<div> <div>
<div <div
class="ms-Stack defaultManagedIdentityContainer css-109" class="ms-Stack defaultManagedIdentityContainer css-109"
@@ -8,7 +8,7 @@ exports[`AddReadPermissionToDefaultIdentity Component Edge Cases should handle m
<span <span
class="toggle-label css-110" class="toggle-label css-110"
> >
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.
<div <div
data-testid="info-tooltip" data-testid="info-tooltip"
@@ -24,7 +24,7 @@ exports[`AddReadPermissionToDefaultIdentity Component Edge Cases should handle m
rel="noopener noreferrer" rel="noopener noreferrer"
target="_blank" target="_blank"
> >
Read permissions. Read-write permissions.
</a> </a>
</span> </span>
</div> </div>
@@ -63,7 +63,7 @@ exports[`AddReadPermissionToDefaultIdentity Component Edge Cases should handle m
</div> </div>
`; `;
exports[`AddReadPermissionToDefaultIdentity Component Edge Cases should handle missing target account identity 1`] = ` exports[`AddReadWritePermissionToDefaultIdentity Component Edge Cases should handle missing target account identity 1`] = `
<div> <div>
<div <div
class="ms-Stack defaultManagedIdentityContainer css-109" class="ms-Stack defaultManagedIdentityContainer css-109"
@@ -71,7 +71,7 @@ exports[`AddReadPermissionToDefaultIdentity Component Edge Cases should handle m
<span <span
class="toggle-label css-110" class="toggle-label css-110"
> >
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.
<div <div
data-testid="info-tooltip" data-testid="info-tooltip"
@@ -87,7 +87,7 @@ exports[`AddReadPermissionToDefaultIdentity Component Edge Cases should handle m
rel="noopener noreferrer" rel="noopener noreferrer"
target="_blank" target="_blank"
> >
Read permissions. Read-write permissions.
</a> </a>
</span> </span>
</div> </div>
@@ -126,7 +126,7 @@ exports[`AddReadPermissionToDefaultIdentity Component Edge Cases should handle m
</div> </div>
`; `;
exports[`AddReadPermissionToDefaultIdentity Component Rendering should render correctly when sourceReadAccessFromTarget is true 1`] = ` exports[`AddReadWritePermissionToDefaultIdentity Component Rendering should render correctly when sourceReadWriteAccessFromTarget is true 1`] = `
<div> <div>
<div <div
class="ms-Stack defaultManagedIdentityContainer css-109" class="ms-Stack defaultManagedIdentityContainer css-109"
@@ -134,7 +134,7 @@ exports[`AddReadPermissionToDefaultIdentity Component Rendering should render co
<span <span
class="toggle-label css-110" class="toggle-label css-110"
> >
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.
<div <div
data-testid="info-tooltip" data-testid="info-tooltip"
@@ -150,7 +150,7 @@ exports[`AddReadPermissionToDefaultIdentity Component Rendering should render co
rel="noopener noreferrer" rel="noopener noreferrer"
target="_blank" target="_blank"
> >
Read permissions. Read-write permissions.
</a> </a>
</span> </span>
</div> </div>
@@ -189,7 +189,7 @@ exports[`AddReadPermissionToDefaultIdentity Component Rendering should render co
</div> </div>
`; `;
exports[`AddReadPermissionToDefaultIdentity Component Rendering should render correctly when toggle is on 1`] = ` exports[`AddReadWritePermissionToDefaultIdentity Component Rendering should render correctly when toggle is on 1`] = `
<div> <div>
<div <div
class="ms-Stack defaultManagedIdentityContainer css-109" class="ms-Stack defaultManagedIdentityContainer css-109"
@@ -197,7 +197,7 @@ exports[`AddReadPermissionToDefaultIdentity Component Rendering should render co
<span <span
class="toggle-label css-110" class="toggle-label css-110"
> >
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.
<div <div
data-testid="info-tooltip" data-testid="info-tooltip"
@@ -213,7 +213,7 @@ exports[`AddReadPermissionToDefaultIdentity Component Rendering should render co
rel="noopener noreferrer" rel="noopener noreferrer"
target="_blank" target="_blank"
> >
Read permissions. Read-write permissions.
</a> </a>
</span> </span>
</div> </div>
@@ -255,12 +255,12 @@ exports[`AddReadPermissionToDefaultIdentity Component Rendering should render co
<div <div
data-testid="popover-title" data-testid="popover-title"
> >
Read permissions assigned to default identity. Assign read-write permissions to default identity.
</div> </div>
<div <div
data-testid="popover-content" data-testid="popover-content"
> >
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.
</div> </div>
<button <button
data-testid="popover-cancel" data-testid="popover-cancel"
@@ -277,7 +277,7 @@ exports[`AddReadPermissionToDefaultIdentity Component Rendering should render co
</div> </div>
`; `;
exports[`AddReadPermissionToDefaultIdentity Component Rendering should render correctly with default state 1`] = ` exports[`AddReadWritePermissionToDefaultIdentity Component Rendering should render correctly with default state 1`] = `
<div> <div>
<div <div
class="ms-Stack defaultManagedIdentityContainer css-109" class="ms-Stack defaultManagedIdentityContainer css-109"
@@ -285,7 +285,7 @@ exports[`AddReadPermissionToDefaultIdentity Component Rendering should render co
<span <span
class="toggle-label css-110" class="toggle-label css-110"
> >
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.
<div <div
data-testid="info-tooltip" data-testid="info-tooltip"
@@ -301,7 +301,7 @@ exports[`AddReadPermissionToDefaultIdentity Component Rendering should render co
rel="noopener noreferrer" rel="noopener noreferrer"
target="_blank" target="_blank"
> >
Read permissions. Read-write permissions.
</a> </a>
</span> </span>
</div> </div>
@@ -340,7 +340,7 @@ exports[`AddReadPermissionToDefaultIdentity Component Rendering should render co
</div> </div>
`; `;
exports[`AddReadPermissionToDefaultIdentity Component Rendering should render correctly with different context states 1`] = ` exports[`AddReadWritePermissionToDefaultIdentity Component Rendering should render correctly with different context states 1`] = `
<div> <div>
<div <div
class="ms-Stack defaultManagedIdentityContainer css-109" class="ms-Stack defaultManagedIdentityContainer css-109"
@@ -348,7 +348,7 @@ exports[`AddReadPermissionToDefaultIdentity Component Rendering should render co
<span <span
class="toggle-label css-110" class="toggle-label css-110"
> >
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.
<div <div
data-testid="info-tooltip" data-testid="info-tooltip"
@@ -364,7 +364,7 @@ exports[`AddReadPermissionToDefaultIdentity Component Rendering should render co
rel="noopener noreferrer" rel="noopener noreferrer"
target="_blank" target="_blank"
> >
Read permissions. Read-write permissions.
</a> </a>
</span> </span>
</div> </div>

View File

@@ -9,7 +9,7 @@ exports[`AssignPermissions Component Accordion Behavior should render accordion
<span <span
class="css-110" class="css-110"
> >
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.
</span> </span>
<div <div
class="ms-Stack css-111" class="ms-Stack css-111"
@@ -212,7 +212,7 @@ exports[`AssignPermissions Component Edge Cases should calculate correct indent
<span <span
class="css-110" class="css-110"
> >
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.
</span> </span>
<div <div
class="ms-Stack css-111" class="ms-Stack css-111"
@@ -618,7 +618,7 @@ exports[`AssignPermissions Component Edge Cases should handle missing account na
<span <span
class="css-110" class="css-110"
> >
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.
</span> </span>
<div <div
class="ms-Stack css-111" class="ms-Stack css-111"
@@ -1153,7 +1153,7 @@ exports[`AssignPermissions Component Permission Groups should render permission
<span <span
class="css-110" class="css-110"
> >
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.
</span> </span>
<div <div
class="ms-Stack css-111" class="ms-Stack css-111"
@@ -1307,7 +1307,7 @@ exports[`AssignPermissions Component Rendering should render without crashing wi
<span <span
class="css-110" class="css-110"
> >
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.
</span> </span>
<div <div
data-testid="shimmer-tree" data-testid="shimmer-tree"
@@ -1329,7 +1329,7 @@ exports[`AssignPermissions Component Rendering should render without crashing wi
<span <span
class="css-110" class="css-110"
> >
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.
</span> </span>
<div <div
data-testid="shimmer-tree" data-testid="shimmer-tree"

View File

@@ -13,7 +13,7 @@ import {
import { CopyJobContextState } from "../../../../Types/CopyJobTypes"; import { CopyJobContextState } from "../../../../Types/CopyJobTypes";
import * as CopyJobPrerequisitesCacheModule from "../../../Utils/useCopyJobPrerequisitesCache"; import * as CopyJobPrerequisitesCacheModule from "../../../Utils/useCopyJobPrerequisitesCache";
import usePermissionSections, { import usePermissionSections, {
checkTargetHasReaderRoleOnSource, checkTargetHasReadWriteRoleOnSource,
PermissionGroupConfig, PermissionGroupConfig,
SECTION_IDS, SECTION_IDS,
} from "./usePermissionsSection"; } from "./usePermissionsSection";
@@ -40,12 +40,12 @@ jest.mock("../AddManagedIdentity", () => {
return MockAddManagedIdentity; return MockAddManagedIdentity;
}); });
jest.mock("../AddReadPermissionToDefaultIdentity", () => { jest.mock("../AddReadWritePermissionToDefaultIdentity", () => {
const MockAddReadPermissionToDefaultIdentity = () => { const MockAddReadWritePermissionToDefaultIdentity = () => {
return <div data-testid="add-read-permission">AddReadPermissionToDefaultIdentity</div>; return <div data-testid="add-read-write-permission">AddReadWritePermissionToDefaultIdentity</div>;
}; };
MockAddReadPermissionToDefaultIdentity.displayName = "MockAddReadPermissionToDefaultIdentity"; MockAddReadWritePermissionToDefaultIdentity.displayName = "MockAddReadWritePermissionToDefaultIdentity";
return MockAddReadPermissionToDefaultIdentity; return MockAddReadWritePermissionToDefaultIdentity;
}); });
jest.mock("../DefaultManagedIdentity", () => { jest.mock("../DefaultManagedIdentity", () => {
@@ -193,7 +193,7 @@ describe("usePermissionsSection", () => {
expect(capturedResult[0].sections.map((s) => s.id)).toEqual([ expect(capturedResult[0].sections.map((s) => s.id)).toEqual([
SECTION_IDS.addManagedIdentity, SECTION_IDS.addManagedIdentity,
SECTION_IDS.defaultManagedIdentity, SECTION_IDS.defaultManagedIdentity,
SECTION_IDS.readPermissionAssigned, SECTION_IDS.readWritePermissionAssigned,
]); ]);
}); });
@@ -358,16 +358,17 @@ describe("usePermissionsSection", () => {
expect(defaultManagedIdentitySection?.completed).toBe(true); expect(defaultManagedIdentitySection?.completed).toBe(true);
}); });
it("should validate readPermissionAssigned section with reader role", async () => { it("should validate readWritePermissionAssigned section with contributor role", async () => {
const mockRoleDefinitions: RbacUtils.RoleDefinitionType[] = [ const mockRoleDefinitions: RbacUtils.RoleDefinitionType[] = [
{ {
id: "role-1", id: "role-1",
name: "Custom Role", name: "00000000-0000-0000-0000-000000000002",
permissions: [ permissions: [
{ {
dataActions: [ dataActions: [
"Microsoft.DocumentDB/databaseAccounts/readMetadata", "Microsoft.DocumentDB/databaseAccounts/readMetadata",
"Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/read", "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/read",
"Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/write",
], ],
}, },
], ],
@@ -407,7 +408,9 @@ describe("usePermissionsSection", () => {
render(<TestWrapper state={state} onResult={noop} />); render(<TestWrapper state={state} onResult={noop} />);
await waitFor(() => { await waitFor(() => {
expect(screen.getByTestId(`section-${SECTION_IDS.readPermissionAssigned}-completed`)).toHaveTextContent("true"); expect(screen.getByTestId(`section-${SECTION_IDS.readWritePermissionAssigned}-completed`)).toHaveTextContent(
"true",
);
}); });
expect(mockedRbacUtils.fetchRoleAssignments).toHaveBeenCalledWith( expect(mockedRbacUtils.fetchRoleAssignments).toHaveBeenCalledWith(
@@ -568,12 +571,12 @@ describe("usePermissionsSection", () => {
}); });
}); });
describe("checkTargetHasReaderRoleOnSource", () => { describe("checkTargetHasReadWriteRoleOnSource", () => {
it("should return true for built-in Reader role", () => { it("should return true for built-in Contributor role", () => {
const roleDefinitions: RbacUtils.RoleDefinitionType[] = [ const roleDefinitions: RbacUtils.RoleDefinitionType[] = [
{ {
id: "role-1", id: "role-1",
name: "00000000-0000-0000-0000-000000000001", name: "00000000-0000-0000-0000-000000000002",
permissions: [], permissions: [],
assignableScopes: [], assignableScopes: [],
resourceGroup: "", resourceGroup: "",
@@ -583,20 +586,21 @@ describe("checkTargetHasReaderRoleOnSource", () => {
}, },
]; ];
const result = checkTargetHasReaderRoleOnSource(roleDefinitions); const result = checkTargetHasReadWriteRoleOnSource(roleDefinitions);
expect(result).toBe(true); expect(result).toBe(true);
}); });
it("should return true for custom role with required data actions", () => { it("should return true for custom role with read-write data actions", () => {
const roleDefinitions: RbacUtils.RoleDefinitionType[] = [ const roleDefinitions: RbacUtils.RoleDefinitionType[] = [
{ {
id: "role-1", id: "role-1",
name: "Custom Reader Role", name: "Custom Contributor Role",
permissions: [ permissions: [
{ {
dataActions: [ dataActions: [
"Microsoft.DocumentDB/databaseAccounts/readMetadata", "Microsoft.DocumentDB/databaseAccounts/readMetadata",
"Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/read", "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/read",
"Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/write",
], ],
}, },
], ],
@@ -608,7 +612,7 @@ describe("checkTargetHasReaderRoleOnSource", () => {
}, },
]; ];
const result = checkTargetHasReaderRoleOnSource(roleDefinitions); const result = checkTargetHasReadWriteRoleOnSource(roleDefinitions);
expect(result).toBe(true); expect(result).toBe(true);
}); });
@@ -630,12 +634,12 @@ describe("checkTargetHasReaderRoleOnSource", () => {
}, },
]; ];
const result = checkTargetHasReaderRoleOnSource(roleDefinitions); const result = checkTargetHasReadWriteRoleOnSource(roleDefinitions);
expect(result).toBe(false); expect(result).toBe(false);
}); });
it("should return false for empty role definitions", () => { it("should return false for empty role definitions", () => {
const result = checkTargetHasReaderRoleOnSource([]); const result = checkTargetHasReadWriteRoleOnSource([]);
expect(result).toBe(false); expect(result).toBe(false);
}); });
@@ -653,11 +657,11 @@ describe("checkTargetHasReaderRoleOnSource", () => {
}, },
]; ];
const result = checkTargetHasReaderRoleOnSource(roleDefinitions); const result = checkTargetHasReadWriteRoleOnSource(roleDefinitions);
expect(result).toBe(false); expect(result).toBe(false);
}); });
it("should handle multiple roles and return true if any has sufficient permissions", () => { it("should handle multiple roles and return true if any has sufficient read-write permissions", () => {
const roleDefinitions: RbacUtils.RoleDefinitionType[] = [ const roleDefinitions: RbacUtils.RoleDefinitionType[] = [
{ {
id: "role-1", id: "role-1",
@@ -675,7 +679,7 @@ describe("checkTargetHasReaderRoleOnSource", () => {
}, },
{ {
id: "role-2", id: "role-2",
name: "00000000-0000-0000-0000-000000000001", name: "00000000-0000-0000-0000-000000000002",
permissions: [], permissions: [],
assignableScopes: [], assignableScopes: [],
resourceGroup: "", resourceGroup: "",
@@ -685,7 +689,7 @@ describe("checkTargetHasReaderRoleOnSource", () => {
}, },
]; ];
const result = checkTargetHasReaderRoleOnSource(roleDefinitions); const result = checkTargetHasReadWriteRoleOnSource(roleDefinitions);
expect(result).toBe(true); expect(result).toBe(true);
}); });
}); });

View File

@@ -12,7 +12,7 @@ import {
import { CopyJobContextState } from "../../../../Types/CopyJobTypes"; import { CopyJobContextState } from "../../../../Types/CopyJobTypes";
import { useCopyJobPrerequisitesCache } from "../../../Utils/useCopyJobPrerequisitesCache"; import { useCopyJobPrerequisitesCache } from "../../../Utils/useCopyJobPrerequisitesCache";
import AddManagedIdentity from "../AddManagedIdentity"; import AddManagedIdentity from "../AddManagedIdentity";
import AddReadPermissionToDefaultIdentity from "../AddReadPermissionToDefaultIdentity"; import AddReadWritePermissionToDefaultIdentity from "../AddReadWritePermissionToDefaultIdentity";
import DefaultManagedIdentity from "../DefaultManagedIdentity"; import DefaultManagedIdentity from "../DefaultManagedIdentity";
import OnlineCopyEnabled from "../OnlineCopyEnabled"; import OnlineCopyEnabled from "../OnlineCopyEnabled";
import PointInTimeRestore from "../PointInTimeRestore"; import PointInTimeRestore from "../PointInTimeRestore";
@@ -36,11 +36,13 @@ export interface PermissionGroupConfig {
export const SECTION_IDS = { export const SECTION_IDS = {
addManagedIdentity: "addManagedIdentity", addManagedIdentity: "addManagedIdentity",
defaultManagedIdentity: "defaultManagedIdentity", defaultManagedIdentity: "defaultManagedIdentity",
readPermissionAssigned: "readPermissionAssigned", readWritePermissionAssigned: "readWritePermissionAssigned",
pointInTimeRestore: "pointInTimeRestore", pointInTimeRestore: "pointInTimeRestore",
onlineCopyEnabled: "onlineCopyEnabled", onlineCopyEnabled: "onlineCopyEnabled",
} as const; } as const;
const COSMOS_DB_BUILT_IN_DATA_CONTRIBUTOR_ROLE_ID = "00000000-0000-0000-0000-000000000002";
const PERMISSION_SECTIONS_CONFIG: PermissionSectionConfig[] = [ const PERMISSION_SECTIONS_CONFIG: PermissionSectionConfig[] = [
{ {
id: SECTION_IDS.addManagedIdentity, id: SECTION_IDS.addManagedIdentity,
@@ -66,9 +68,9 @@ const PERMISSION_SECTIONS_CONFIG: PermissionSectionConfig[] = [
}, },
}, },
{ {
id: SECTION_IDS.readPermissionAssigned, id: SECTION_IDS.readWritePermissionAssigned,
title: ContainerCopyMessages.readPermissionAssigned.title, title: ContainerCopyMessages.readWritePermissionAssigned.title,
Component: AddReadPermissionToDefaultIdentity, Component: AddReadWritePermissionToDefaultIdentity,
disabled: true, disabled: true,
validate: async (state: CopyJobContextState) => { validate: async (state: CopyJobContextState) => {
const principalId = state?.target?.account?.identity?.principalId; const principalId = state?.target?.account?.identity?.principalId;
@@ -87,7 +89,7 @@ const PERMISSION_SECTIONS_CONFIG: PermissionSectionConfig[] = [
); );
const roleDefinitions = await fetchRoleDefinitions(rolesAssigned ?? []); const roleDefinitions = await fetchRoleDefinitions(rolesAssigned ?? []);
return checkTargetHasReaderRoleOnSource(roleDefinitions ?? []); return checkTargetHasReadWriteRoleOnSource(roleDefinitions ?? []);
}, },
}, },
]; ];
@@ -119,18 +121,34 @@ const PERMISSION_SECTIONS_FOR_ONLINE_JOBS: PermissionSectionConfig[] = [
]; ];
/** /**
* Checks if the user has the Reader role based on role definitions. * Checks if the user has contributor-style read-write access on the source account.
*/ */
export function checkTargetHasReaderRoleOnSource(roleDefinitions: RoleDefinitionType[]): boolean { export function checkTargetHasReadWriteRoleOnSource(roleDefinitions: RoleDefinitionType[]): boolean {
return roleDefinitions?.some( return roleDefinitions?.some((role) => {
(role) => if (role.name === COSMOS_DB_BUILT_IN_DATA_CONTRIBUTOR_ROLE_ID) {
role.name === "00000000-0000-0000-0000-000000000001" || return true;
role.permissions.some( }
(permission) =>
permission.dataActions.includes("Microsoft.DocumentDB/databaseAccounts/readMetadata") && const dataActions = role.permissions?.flatMap((permission) => permission.dataActions ?? []) ?? [];
permission.dataActions.includes("Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/read"),
), const hasAccountWildcard = dataActions.includes("Microsoft.DocumentDB/databaseAccounts/*");
); const hasContainerWildcard =
hasAccountWildcard || dataActions.includes("Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/*");
const hasItemsWildcard =
hasContainerWildcard ||
dataActions.includes("Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/*");
const hasAccountReadMetadata =
hasAccountWildcard || dataActions.includes("Microsoft.DocumentDB/databaseAccounts/readMetadata");
const hasItemRead =
hasItemsWildcard ||
dataActions.includes("Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/read");
const hasItemWrite =
hasItemsWildcard ||
dataActions.includes("Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/write");
return hasAccountReadMetadata && hasItemRead && hasItemWrite;
});
} }
/** /**

View File

@@ -81,7 +81,7 @@ describe("AddCollectionPanelWrapper", () => {
databaseId: "", databaseId: "",
containerId: "", containerId: "",
}, },
sourceReadAccessFromTarget: false, sourceReadWriteAccessFromTarget: false,
}, },
setCopyJobState: mockSetCopyJobState, setCopyJobState: mockSetCopyJobState,
flow: null, flow: null,

View File

@@ -98,7 +98,7 @@ describe("PreviewCopyJob", () => {
databaseId: "target-database", databaseId: "target-database",
containerId: "target-container", containerId: "target-container",
}, },
sourceReadAccessFromTarget: false, sourceReadWriteAccessFromTarget: false,
...overrides, ...overrides,
}; };
@@ -290,7 +290,7 @@ describe("PreviewCopyJob", () => {
databaseId: "target-database", databaseId: "target-database",
containerId: "target-container", containerId: "target-container",
}, },
sourceReadAccessFromTarget: true, sourceReadWriteAccessFromTarget: true,
}); });
const { container } = render( const { container } = render(

View File

@@ -52,7 +52,7 @@ describe("AccountDropdown", () => {
databaseId: "", databaseId: "",
containerId: "", containerId: "",
}, },
sourceReadAccessFromTarget: false, sourceReadWriteAccessFromTarget: false,
} as CopyJobContextState; } as CopyJobContextState;
const mockCopyJobContextValue = { const mockCopyJobContextValue = {

View File

@@ -29,7 +29,7 @@ describe("MigrationType", () => {
databaseId: "", databaseId: "",
containerId: "", containerId: "",
}, },
sourceReadAccessFromTarget: false, sourceReadWriteAccessFromTarget: false,
}, },
setCopyJobState: mockSetCopyJobState, setCopyJobState: mockSetCopyJobState,
flow: { currentScreen: "selectAccount" }, flow: { currentScreen: "selectAccount" },

View File

@@ -41,7 +41,7 @@ describe("SelectAccount", () => {
databaseId: "", databaseId: "",
containerId: "", containerId: "",
}, },
sourceReadAccessFromTarget: false, sourceReadWriteAccessFromTarget: false,
}, },
setCopyJobState: mockSetCopyJobState, setCopyJobState: mockSetCopyJobState,
flow: { currentScreen: "selectAccount" }, flow: { currentScreen: "selectAccount" },

View File

@@ -7,7 +7,7 @@ import { dropDownChangeHandler } from "./DropDownChangeHandler";
const createMockInitialState = (): CopyJobContextState => ({ const createMockInitialState = (): CopyJobContextState => ({
jobName: "test-job", jobName: "test-job",
migrationType: CopyJobMigrationType.Offline, migrationType: CopyJobMigrationType.Offline,
sourceReadAccessFromTarget: false, sourceReadWriteAccessFromTarget: false,
source: { source: {
subscriptionId: "source-sub-id", subscriptionId: "source-sub-id",
account: { account: {
@@ -181,7 +181,7 @@ describe("dropDownChangeHandler", () => {
expect(capturedState.jobName).toBe(initialState.jobName); expect(capturedState.jobName).toBe(initialState.jobName);
expect(capturedState.migrationType).toBe(initialState.migrationType); expect(capturedState.migrationType).toBe(initialState.migrationType);
expect(capturedState.sourceReadAccessFromTarget).toBe(initialState.sourceReadAccessFromTarget); expect(capturedState.sourceReadWriteAccessFromTarget).toBe(initialState.sourceReadWriteAccessFromTarget);
}); });
}); });
@@ -227,7 +227,7 @@ describe("dropDownChangeHandler", () => {
expect(capturedState.jobName).toBe(initialState.jobName); expect(capturedState.jobName).toBe(initialState.jobName);
expect(capturedState.migrationType).toBe(initialState.migrationType); expect(capturedState.migrationType).toBe(initialState.migrationType);
expect(capturedState.sourceReadAccessFromTarget).toBe(initialState.sourceReadAccessFromTarget); expect(capturedState.sourceReadWriteAccessFromTarget).toBe(initialState.sourceReadWriteAccessFromTarget);
}); });
}); });

View File

@@ -90,7 +90,7 @@ describe("SelectSourceAndTargetContainers", () => {
databaseId: "db2", databaseId: "db2",
containerId: "container2", containerId: "container2",
}, },
sourceReadAccessFromTarget: false, sourceReadWriteAccessFromTarget: false,
}; };
const mockMemoizedData = { const mockMemoizedData = {

View File

@@ -69,7 +69,7 @@ describe("useSourceAndTargetData", () => {
const mockCopyJobState: CopyJobContextState = { const mockCopyJobState: CopyJobContextState = {
jobName: "test-job", jobName: "test-job",
migrationType: CopyJobMigrationType.Offline, migrationType: CopyJobMigrationType.Offline,
sourceReadAccessFromTarget: false, sourceReadWriteAccessFromTarget: false,
source: { source: {
subscriptionId: "source-subscription-id", subscriptionId: "source-subscription-id",
account: mockSourceAccount, account: mockSourceAccount,

View File

@@ -55,7 +55,7 @@ export interface DatabaseContainerSectionProps {
export interface CopyJobContextState { export interface CopyJobContextState {
jobName: string; jobName: string;
migrationType: CopyJobMigrationType; migrationType: CopyJobMigrationType;
sourceReadAccessFromTarget?: boolean; sourceReadWriteAccessFromTarget?: boolean;
source: { source: {
subscriptionId: string; subscriptionId: string;
account: DatabaseAccount | null; account: DatabaseAccount | null;

View File

@@ -93,7 +93,7 @@ export const assignRole = async (
return null; return null;
} }
const accountScope = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}`; const accountScope = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}`;
const roleDefinitionId = `${accountScope}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000001`; const roleDefinitionId = `${accountScope}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000002`; // Built-in Contributor role definition ID for Cosmos DB
const roleAssignmentName = crypto.randomUUID(); const roleAssignmentName = crypto.randomUUID();
const path = `${accountScope}/sqlRoleAssignments/${roleAssignmentName}`; const path = `${accountScope}/sqlRoleAssignments/${roleAssignmentName}`;