Skip to content

feat(extensions): Add extension permissions#691

Merged
christoph-jerolimov merged 3 commits into
redhat-developer:mainfrom
debsmita1:marketplace-permissions
May 9, 2025
Merged

feat(extensions): Add extension permissions#691
christoph-jerolimov merged 3 commits into
redhat-developer:mainfrom
debsmita1:marketplace-permissions

Conversation

@debsmita1
Copy link
Copy Markdown
Member

@debsmita1 debsmita1 commented Apr 24, 2025

Hey, I just made a Pull Request!

Resolves:

https://issues.redhat.com/browse/RHIDP-6766

How to test:

Install rbac frontend and backend plugins
Add the Github signin page
Add the following in you rbac-policy.csv file

p, role:default/admins, extension-plugin, read, allow
p, role:default/admins, extension-plugin, create, allow

Add the following to your app-config.yaml

permission:
  enabled: true
  rbac:
    pluginsWithPermission:
      - marketplace
      - catalog
      - permission
    policies-csv-file: <path-to-your-csv-file>/rbac-policy.csv
    policyFileReload: true
    admin:
      users:
        - name: user:default/<github-id>
        - name: group:default/admins

Screenshots/GIF:

User with no config read permission

Screenshot 2025-04-29 at 7 10 52 PM

User with only config read permission

Screen.Recording.2025-04-30.at.4.43.57.PM.mov

User with both read and create permissions

Screen.Recording.2025-04-28.at.9.51.56.PM.mov

User with conditional permissions

Screen.Recording.2025-04-28.at.9.53.22.PM.mov

TODO (to be addressed in separate PRs):

  • Update RBAC documentation to include the newly added Extensions permissions
  • Update Extensions frontend plugin readme to include the policies to be added when the Permission framework is enabled

✔️ Checklist

  • A changeset describing the change and affected packages. (more info)
  • Added or Updated documentation
  • Tests for new functionality and regression tests for bug fixes
  • Screenshots attached (for UI changes)

@rhdh-gh-app
Copy link
Copy Markdown

rhdh-gh-app Bot commented Apr 24, 2025

Important

This PR includes changes that affect public-facing API. Please ensure you are adding/updating documentation for new features or behavior.

Changed Packages

Package Name Package Path Changeset Bump Current Version
@red-hat-developer-hub/backstage-plugin-marketplace-backend workspaces/marketplace/plugins/marketplace-backend minor v0.3.1
@red-hat-developer-hub/backstage-plugin-marketplace-common workspaces/marketplace/plugins/marketplace-common minor v0.3.0
@red-hat-developer-hub/backstage-plugin-marketplace workspaces/marketplace/plugins/marketplace minor v0.5.7

@debsmita1 debsmita1 force-pushed the marketplace-permissions branch 12 times, most recently from 76326bd to 5c8e59a Compare April 28, 2025 16:11
@debsmita1 debsmita1 changed the title [WIP] feat(extensions): Add extension permissions feat(extensions): Add extension permissions Apr 28, 2025
@debsmita1 debsmita1 requested a review from ShiranHi April 28, 2025 16:28
@debsmita1 debsmita1 force-pushed the marketplace-permissions branch 3 times, most recently from a757c03 to 6013840 Compare April 28, 2025 16:46
@ShiranHi
Copy link
Copy Markdown

Thank you @debsmita1, it looks great!

I have two requests:

  1. For user with no config read permission: let's change the tooltip to be "You don't have permission to install plugins or view their configurations. Contact your administrator to request access or assistance."
  2. For user with only config read permission: let's keep the Install button there, but disabled, and add a tooltip on hover "You don't have permission to install plugins or edit their configurations. Contact your administrator to request access or assistance."

@debsmita1 debsmita1 force-pushed the marketplace-permissions branch from 6013840 to 63afb2f Compare April 29, 2025 13:41
@debsmita1 debsmita1 changed the title [WIP] feat(extensions): Add extension permissions feat(extensions): Add extension permissions Apr 29, 2025
@debsmita1 debsmita1 force-pushed the marketplace-permissions branch from 63afb2f to e66e1eb Compare April 29, 2025 13:56
Copy link
Copy Markdown
Member

@PatAKnight PatAKnight left a comment

Choose a reason for hiding this comment

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

Left a couple of initial comments but will need to do a deeper dive into the plugin itself to try to understand it a bit better. If you want, we can sync up on this as I recently had to do this for the RBAC plugin and it is still fairly top of mind.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I wonder if this should just be the read permission only and then we can use the create permission for post.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@PatAKnight I updated this to create a separate service to determine the privileges, which is then consumed by the UI to show "Install" or "View" plugin configuration based on the access rights

And I converted this one to check only the read access, and eventually it should return the YAML config

PTAL and let me know your thoughts on this

@debsmita1 debsmita1 requested a review from PatAKnight April 30, 2025 11:26
@debsmita1
Copy link
Copy Markdown
Member Author

Are you suggesting that we remove the 'View' button and instead display a disabled 'Install' button? The idea is to allow users with read-only permissions to access the plugin configuration.

Sorry for the confusion! We have two "Install" buttons. Let me clarify it:

  1. For user with no config read permission: let's change the tooltip text that appears on the drawer when hovering over the Install button to: "You don't have permission to install plugins or view their configurations. Contact your administrator to request access or assistance."
  2. For user with only config read permission: let's keep the Install button on the configuration page, but disabled, and add a tooltip on hover "You don't have permission to install plugins or edit their configurations. Contact your administrator to request access or assistance."

@ShiranHi Addressed your comments and updated the GIF

@debsmita1 debsmita1 requested a review from logonoff April 30, 2025 11:33
@debsmita1 debsmita1 force-pushed the marketplace-permissions branch 3 times, most recently from 285f57c to 6211a8b Compare May 5, 2025 12:26
@debsmita1 debsmita1 force-pushed the marketplace-permissions branch from 6211a8b to 4bf1c56 Compare May 8, 2025 07:08
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented May 8, 2025

}),
apply: (plugin: MarketplacePlugin, { pluginNames }) => {
return pluginNames && pluginNames.length > 0
? !!pluginNames?.find(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

super nit. isn't this the same?

Suggested change
? !!pluginNames?.find(
? pluginNames?.some(

@logonoff logonoff requested a review from Copilot May 8, 2025 13:40
Copy link
Copy Markdown

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

This PR adds extension permissions to the marketplace plugins by introducing new API endpoints, permission rules, and updated hooks/components to support permission-based access for installing and configuring extensions. Key changes include:

  • Adding a new hook (useExtensionConfigPermission) and associated API methods for extension configuration authorization.
  • Updating the marketplace backend router to handle new permission endpoints for reading and installing plugin configurations.
  • Introducing permission rules and updating dependency versions to support the new permission framework.

Reviewed Changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated no comments.

Show a summary per file
File Description
workspaces/marketplace/plugins/marketplace/src/hooks/useExtensionConfigPermission.ts New hook to fetch plugin configuration authorization.
workspaces/marketplace/plugins/marketplace/src/components/MarketplacePluginInstallContent.tsx Updated installation UI with permission-based disable logic and tooltips.
workspaces/marketplace/plugins/marketplace/src/components/MarketplacePluginContent.tsx Refactored action button to use permission hook and tooltip.
workspaces/marketplace/plugins/marketplace-backend/src/router.ts Added endpoints for plugin configuration authorization and configuration access with conditional permissions.
workspaces/marketplace/plugins/marketplace-backend/src/permissions/rules.ts New permission rules for extensions.
Various package.json and common files Added new dependencies and API definitions to support extension permissions.

Copy link
Copy Markdown
Member

@christoph-jerolimov christoph-jerolimov left a comment

Choose a reason for hiding this comment

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

Some thoughts, please take a look. I'm fine if we want align some of these also later:

MarketplacePlugin,
ExtentionFilter
>().with({
pluginId: 'marketplace',
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Next step is to rename the plugin, but we can use the new pluginId here already.

Please change it also in plugins/marketplace/src/plugin.ts

Suggested change
pluginId: 'marketplace',
pluginId: 'extensions',

.string()
.array()
.optional()
.describe('List of plugin names to match on'),
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
.describe('List of plugin names to match on'),
.describe('List of plugin names or titles to match on'),

Comment on lines +165 to +175
const [readDecision, installDecision] = await Promise.all([
authorizeConditional(req, extensionPluginReadPermission),
authorizeConditional(req, extensionPluginCreatePermission),
]);
if (
readDecision.result === AuthorizeResult.DENY &&
installDecision.result === AuthorizeResult.DENY
) {
res.status(403);
return;
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Isn't it cleaner if the /authorize call return always a successful response but with an access status?

Like

200 OK

{
  read: "ALLOW"
  write: "DENY"
}

Or whatever you want return.

Because I see that the MarketplaceClient expects 200 and converts this into an error.

But you don't handle errors when using useExtensionConfigPermission in MarketplacePluginContent.

Comment on lines +204 to +207
if (authorizedActions.length === 0) {
res.status(403);
return;
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Same here

Comment on lines +218 to +219
res.status(403).json({ error: 'Forbidden' });
return;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can we throw an error instead? For all 403 cases.

import {
  NotAllowedError,
} from '@backstage/errors';
Suggested change
res.status(403).json({ error: 'Forbidden' });
return;
throw new NotAllowedError(`Not allowed to configure ${req.params.namespace}:${req.params.name}`);

/** This permission grants access to the endpoint that reads the configuration of the extension plugin
* @public
*/
export const extensionPluginReadPermission = createPermission({
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The variable name should include Configuration as well, to avoid confusing that this is a permission to read the plugin metadata.

IMHO, as long as we don't differentiate between Create update and Delete we should have two permissions:

  • read
  • write or update

If you want have separate for enableing and disabling the plugin I personally would use

  • enable
  • disable

Actually, that's then maybe not a configuration enable/disable, its then maybe 'extensions.plugin.enable.

But I think we could start here also with extensions.plugin.configuration.write, because it just does this at the moment.

const params = useRouteRefParams(pluginRouteRef);
const getIndexPath = useRouteRef(rootRouteRef);
const getInstallPath = useRouteRef(pluginInstallRouteRef);
const canInstallPlugin = useExtensionConfigPermission(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think this hook should include that its for plugins

Suggested change
const canInstallPlugin = useExtensionConfigPermission(
const pluginConfigPerm = usePluginConfigurationPermissions(

>
Reset
</Button>
{canInstallPlugin.data?.authorizedActions?.includes('create') && (
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
{canInstallPlugin.data?.authorizedActions?.includes('create') && (
{pluginConfigPermissions.data?.includes('create') && (


import { useMarketplaceApi } from './useMarketplaceApi';

export const useExtensionConfigPermission = (
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

other hook names are aligned with the MarketplaceApi function they call and just replace get with use

Copy link
Copy Markdown
Member

@christoph-jerolimov christoph-jerolimov left a comment

Choose a reason for hiding this comment

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

As discussed, approving this spike but it would be nice if we can address some reviews soon. Esp. renaming all permission names to extensions.* before we release the plugin.

I will set the release on hold until this changes was done!

@christoph-jerolimov christoph-jerolimov merged commit 7d138e5 into redhat-developer:main May 9, 2025
10 checks passed
@debsmita1
Copy link
Copy Markdown
Member Author

As discussed, approving this spike but it would be nice if we can address some reviews soon. Esp. renaming all permission names to extensions.* before we release the plugin.

I will set the release on hold until this changes was done!

Addressed the review comments here #762

elai-shalev pushed a commit to elai-shalev/rhdh-plugins that referenced this pull request Jan 21, 2026
* feat(marketplace): add permissions to extensions

* adding conditional policies

* add new service to check config authorization
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.

6 participants