From 9568e07f74ce61eabf0f60c6d9daed825519be7c Mon Sep 17 00:00:00 2001 From: Talha Amjad Date: Fri, 17 Apr 2026 20:30:45 +0500 Subject: [PATCH 1/2] fix(permissions): show glossary import/export for conditional policies --- .../Glossary/GlossaryHeader/GlossaryHeader.component.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryHeader/GlossaryHeader.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryHeader/GlossaryHeader.component.tsx index 62c7f3b8556c..839f32a7c3e3 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryHeader/GlossaryHeader.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryHeader/GlossaryHeader.component.tsx @@ -138,8 +138,10 @@ const GlossaryHeader = ({ Operation.EditAll, ResourceEntity.GLOSSARY_TERM, globalPermissions - ), - [globalPermissions] + ) || + permissions[Operation.All] || + permissions[Operation.EditAll], + [globalPermissions, permissions] ); // To fetch the latest glossary data From 649b42d755f4eeed33388fc4a805aaed6831abb9 Mon Sep 17 00:00:00 2001 From: Talha Amjad Date: Fri, 17 Apr 2026 20:56:26 +0500 Subject: [PATCH 2/2] Add tests --- .../GlossaryHeader/GlossaryHeader.test.tsx | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryHeader/GlossaryHeader.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryHeader/GlossaryHeader.test.tsx index cbbf48cbce70..8775a942093c 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryHeader/GlossaryHeader.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryHeader/GlossaryHeader.test.tsx @@ -322,4 +322,57 @@ describe('GlossaryHeader component', () => { screen.queryByText('ChangeParentHierarchyComponent') ).not.toBeInTheDocument(); }); + + describe('import/export visibility with conditional policies', () => { + it('should show import/export when globalPermissions denies but entity-level permissions allow (isOwner condition satisfied)', async () => { + // Simulate a conditional policy: resource-level check returns false because + // the backend cannot evaluate isOwner() without entity context. + mockGlossaryTermPermission.All = false; + mockGlossaryTermPermission.EditAll = false; + + // Entity-level permissions are fetched with the glossary ID so the backend + // correctly evaluates isOwner() and returns Allow. + mockContext.type = EntityType.GLOSSARY; + mockContext.permissions = { ...DEFAULT_ENTITY_PERMISSION, EditAll: true }; + + render( + + ); + + await act(async () => { + fireEvent.click(screen.getByTestId('manage-button')); + }); + + expect(screen.queryByText('label.import')).toBeInTheDocument(); + expect(screen.queryByText('label.export')).toBeInTheDocument(); + }); + + it('should hide import/export when both globalPermissions and entity-level permissions deny', async () => { + // Both resource-level and entity-level permissions deny — user is not the + // owner and no other condition grants access. + mockGlossaryTermPermission.All = false; + mockGlossaryTermPermission.EditAll = false; + + mockContext.type = EntityType.GLOSSARY; + mockContext.permissions = { + ...DEFAULT_ENTITY_PERMISSION, + All: false, + EditAll: false, + }; + + render( + + ); + + expect(screen.queryByTestId('manage-button')).not.toBeInTheDocument(); + }); + }); });