Skip to content

Fixes #27487: restore import/export buttons when EditAll uses conditional policies#27488

Open
miantalha45 wants to merge 2 commits intoopen-metadata:mainfrom
miantalha45:import/export-functionality-disable
Open

Fixes #27487: restore import/export buttons when EditAll uses conditional policies#27488
miantalha45 wants to merge 2 commits intoopen-metadata:mainfrom
miantalha45:import/export-functionality-disable

Conversation

@miantalha45
Copy link
Copy Markdown

Problem

Users with a Data Producer role (EditAll on glossaryTerm with conditions
like isOwner(), hasDomain(), or matchTeam()) could not see the
Import/Export options in the Glossary header manage menu, even when the
condition was satisfied (e.g. the user was the owner of the glossary).

Root Cause

importExportPermissions was computed solely from globalPermissions
(resource-level, no entity context). The backend cannot evaluate
isOwner() at the resource level and returns ConditionalAllow, which
the frontend maps to false.

Fix

Added a fallback to the entity-level permissions object from
GenericProvider context. These permissions are fetched with the specific
glossary entity ID, so the backend can correctly evaluate conditions and
return Allow when the user satisfies them.

Test

  1. Create a role with EditAll on glossaryTerm + condition isOwner()
  2. Assign the role to a user, make them owner of a glossary
  3. Login as that user → Import/Export options now visible in the manage menu

Fixes #27487

Copilot AI review requested due to automatic review settings April 17, 2026 15:34
@miantalha45 miantalha45 requested a review from a team as a code owner April 17, 2026 15:34
@github-actions
Copy link
Copy Markdown
Contributor

Hi there 👋 Thanks for your contribution!

The OpenMetadata team will review the PR shortly! Once it has been labeled as safe to test, the CI workflows
will start executing and we'll be able to make sure everything is working as expected.

Let us know if you need any help!

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Restores visibility of Glossary Import/Export actions for users whose effective permissions depend on conditional policy evaluation, by considering entity-scoped permissions (with entity context) in addition to resource-scoped global permissions.

Changes:

  • Update importExportPermissions computation to fall back from resource-level globalPermissions to entity-level permissions from GenericProvider context.

Comment on lines 130 to +144
const importExportPermissions = useMemo(
() =>
checkPermission(
Operation.All,
ResourceEntity.GLOSSARY_TERM,
globalPermissions
) ||
checkPermission(
Operation.EditAll,
ResourceEntity.GLOSSARY_TERM,
globalPermissions
),
[globalPermissions]
) ||
permissions[Operation.All] ||
permissions[Operation.EditAll],
[globalPermissions, permissions]
@github-actions
Copy link
Copy Markdown
Contributor

Hi there 👋 Thanks for your contribution!

The OpenMetadata team will review the PR shortly! Once it has been labeled as safe to test, the CI workflows
will start executing and we'll be able to make sure everything is working as expected.

Let us know if you need any help!

Comment on lines +326 to +340
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(
<GlossaryHeader
updateVote={mockOnUpdateVote}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Quality: Mutable shared test state not reset between tests

The new describe block mutates module-level mockGlossaryTermPermission and mockContext (lines 330-336, 358-365) without resetting them afterward. While this matches the existing pattern in the file, the new tests depend on and further propagate leaked state. For example, the first new test (line 327) inherits mockContext.type from whatever the previous test set it to (line 233 sets it to GLOSSARY_TERM), then overrides it to GLOSSARY at line 335 — which then leaks into the second new test.

Currently this doesn't cause failures because test execution order is deterministic and these are the last tests, but it's fragile. Adding a beforeEach or afterEach in the new describe block to snapshot and restore the shared objects would make these tests order-independent.

Suggested fix:

describe('import/export visibility with conditional policies', () => {
  let origPermission: typeof mockGlossaryTermPermission;
  let origContext: typeof mockContext;

  beforeEach(() => {
    origPermission = { ...mockGlossaryTermPermission };
    origContext = { ...mockContext };
  });

  afterEach(() => {
    Object.assign(mockGlossaryTermPermission, origPermission);
    Object.assign(mockContext, origContext);
  });
  // ... tests
});

Was this helpful? React with 👍 / 👎 | Reply gitar fix to apply this suggestion

@gitar-bot
Copy link
Copy Markdown

gitar-bot bot commented Apr 17, 2026

Code Review 👍 Approved with suggestions 0 resolved / 1 findings

Restores missing import/export buttons in the EditAll interface under conditional policies. Please reset the module-level mocks in the new test block to prevent shared state leakage between tests.

💡 Quality: Mutable shared test state not reset between tests

📄 openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryHeader/GlossaryHeader.test.tsx:326-340

The new describe block mutates module-level mockGlossaryTermPermission and mockContext (lines 330-336, 358-365) without resetting them afterward. While this matches the existing pattern in the file, the new tests depend on and further propagate leaked state. For example, the first new test (line 327) inherits mockContext.type from whatever the previous test set it to (line 233 sets it to GLOSSARY_TERM), then overrides it to GLOSSARY at line 335 — which then leaks into the second new test.

Currently this doesn't cause failures because test execution order is deterministic and these are the last tests, but it's fragile. Adding a beforeEach or afterEach in the new describe block to snapshot and restore the shared objects would make these tests order-independent.

Suggested fix
describe('import/export visibility with conditional policies', () => {
  let origPermission: typeof mockGlossaryTermPermission;
  let origContext: typeof mockContext;

  beforeEach(() => {
    origPermission = { ...mockGlossaryTermPermission };
    origContext = { ...mockContext };
  });

  afterEach(() => {
    Object.assign(mockGlossaryTermPermission, origPermission);
    Object.assign(mockContext, origContext);
  });
  // ... tests
});
🤖 Prompt for agents
Code Review: Restores missing import/export buttons in the EditAll interface under conditional policies. Please reset the module-level mocks in the new test block to prevent shared state leakage between tests.

1. 💡 Quality: Mutable shared test state not reset between tests
   Files: openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryHeader/GlossaryHeader.test.tsx:326-340

   The new `describe` block mutates module-level `mockGlossaryTermPermission` and `mockContext` (lines 330-336, 358-365) without resetting them afterward. While this matches the existing pattern in the file, the new tests depend on and further propagate leaked state. For example, the first new test (line 327) inherits `mockContext.type` from whatever the previous test set it to (line 233 sets it to `GLOSSARY_TERM`), then overrides it to `GLOSSARY` at line 335 — which then leaks into the second new test.
   
   Currently this doesn't cause failures because test execution order is deterministic and these are the last tests, but it's fragile. Adding a `beforeEach` or `afterEach` in the new `describe` block to snapshot and restore the shared objects would make these tests order-independent.

   Suggested fix:
   describe('import/export visibility with conditional policies', () => {
     let origPermission: typeof mockGlossaryTermPermission;
     let origContext: typeof mockContext;
   
     beforeEach(() => {
       origPermission = { ...mockGlossaryTermPermission };
       origContext = { ...mockContext };
     });
   
     afterEach(() => {
       Object.assign(mockGlossaryTermPermission, origPermission);
       Object.assign(mockContext, origContext);
     });
     // ... tests
   });

Options

Display: compact → Showing less information.

Comment with these commands to change:

Compact
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

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.

Permissions: Import/Export functionality is Disabled by Conditions

2 participants