diff --git a/workspaces/dcm/app-config.yaml b/workspaces/dcm/app-config.yaml
index 4b11226c3c..ac1c39ae7e 100644
--- a/workspaces/dcm/app-config.yaml
+++ b/workspaces/dcm/app-config.yaml
@@ -43,6 +43,23 @@ auth:
providers:
guest: {}
+permission:
+ enabled: true
+ rbac:
+ policyFileReload: true
+ pluginsWithPermission:
+ - catalog
+ - scaffolder
+ - permission
+ - dcm
+ admin:
+ users:
+ - name: group:default/admins
+ - name: user:default/guest
+ superUsers:
+ - name: group:default/admins
+ - name: user:default/guest
+
scaffolder: {}
catalog:
diff --git a/workspaces/dcm/examples/entities.yaml b/workspaces/dcm/examples/entities.yaml
new file mode 100644
index 0000000000..447e8b1f34
--- /dev/null
+++ b/workspaces/dcm/examples/entities.yaml
@@ -0,0 +1,41 @@
+---
+# https://backstage.io/docs/features/software-catalog/descriptor-format#kind-system
+apiVersion: backstage.io/v1alpha1
+kind: System
+metadata:
+ name: examples
+spec:
+ owner: guests
+---
+# https://backstage.io/docs/features/software-catalog/descriptor-format#kind-component
+apiVersion: backstage.io/v1alpha1
+kind: Component
+metadata:
+ name: example-website
+spec:
+ type: website
+ lifecycle: experimental
+ owner: guests
+ system: examples
+ providesApis: [example-grpc-api]
+---
+# https://backstage.io/docs/features/software-catalog/descriptor-format#kind-api
+apiVersion: backstage.io/v1alpha1
+kind: API
+metadata:
+ name: example-grpc-api
+spec:
+ type: grpc
+ lifecycle: experimental
+ owner: guests
+ system: examples
+ definition: |
+ syntax = "proto3";
+
+ service Exampler {
+ rpc Example (ExampleMessage) returns (ExampleMessage) {};
+ }
+
+ message ExampleMessage {
+ string example = 1;
+ };
diff --git a/workspaces/dcm/examples/org.yaml b/workspaces/dcm/examples/org.yaml
new file mode 100644
index 0000000000..a10e81fc7f
--- /dev/null
+++ b/workspaces/dcm/examples/org.yaml
@@ -0,0 +1,17 @@
+---
+# https://backstage.io/docs/features/software-catalog/descriptor-format#kind-user
+apiVersion: backstage.io/v1alpha1
+kind: User
+metadata:
+ name: guest
+spec:
+ memberOf: [guests]
+---
+# https://backstage.io/docs/features/software-catalog/descriptor-format#kind-group
+apiVersion: backstage.io/v1alpha1
+kind: Group
+metadata:
+ name: guests
+spec:
+ type: team
+ children: []
diff --git a/workspaces/dcm/examples/template/content/catalog-info.yaml b/workspaces/dcm/examples/template/content/catalog-info.yaml
new file mode 100644
index 0000000000..d4ccca42ef
--- /dev/null
+++ b/workspaces/dcm/examples/template/content/catalog-info.yaml
@@ -0,0 +1,8 @@
+apiVersion: backstage.io/v1alpha1
+kind: Component
+metadata:
+ name: ${{ values.name | dump }}
+spec:
+ type: service
+ owner: user:guest
+ lifecycle: experimental
diff --git a/workspaces/dcm/examples/template/content/index.js b/workspaces/dcm/examples/template/content/index.js
new file mode 100644
index 0000000000..d4e00fc5dc
--- /dev/null
+++ b/workspaces/dcm/examples/template/content/index.js
@@ -0,0 +1,17 @@
+/*
+ * Copyright Red Hat, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+console.log('Hello from ${{ values.name }}!');
diff --git a/workspaces/dcm/examples/template/content/package.json b/workspaces/dcm/examples/template/content/package.json
new file mode 100644
index 0000000000..86f968a73b
--- /dev/null
+++ b/workspaces/dcm/examples/template/content/package.json
@@ -0,0 +1,5 @@
+{
+ "name": "${{ values.name }}",
+ "private": true,
+ "dependencies": {}
+}
diff --git a/workspaces/dcm/examples/template/template.yaml b/workspaces/dcm/examples/template/template.yaml
new file mode 100644
index 0000000000..33f262b49c
--- /dev/null
+++ b/workspaces/dcm/examples/template/template.yaml
@@ -0,0 +1,74 @@
+apiVersion: scaffolder.backstage.io/v1beta3
+# https://backstage.io/docs/features/software-catalog/descriptor-format#kind-template
+kind: Template
+metadata:
+ name: example-nodejs-template
+ title: Example Node.js Template
+ description: An example template for the scaffolder that creates a simple Node.js service
+spec:
+ owner: user:guest
+ type: service
+
+ # These parameters are used to generate the input form in the frontend, and are
+ # used to gather input data for the execution of the template.
+ parameters:
+ - title: Fill in some steps
+ required:
+ - name
+ properties:
+ name:
+ title: Name
+ type: string
+ description: Unique name of the component
+ ui:autofocus: true
+ ui:options:
+ rows: 5
+ - title: Choose a location
+ required:
+ - repoUrl
+ properties:
+ repoUrl:
+ title: Repository Location
+ type: string
+ ui:field: RepoUrlPicker
+ ui:options:
+ allowedHosts:
+ - github.com
+
+ # These steps are executed in the scaffolder backend, using data that we gathered
+ # via the parameters above.
+ steps:
+ # Each step executes an action, in this case one templates files into the working directory.
+ - id: fetch-base
+ name: Fetch Base
+ action: fetch:template
+ input:
+ url: ./content
+ values:
+ name: ${{ parameters.name }}
+
+ # This step publishes the contents of the working directory to GitHub.
+ - id: publish
+ name: Publish
+ action: publish:github
+ input:
+ allowedHosts: ['github.com']
+ description: This is ${{ parameters.name }}
+ repoUrl: ${{ parameters.repoUrl }}
+
+ # The final step is to register our new component in the catalog.
+ - id: register
+ name: Register
+ action: catalog:register
+ input:
+ repoContentsUrl: ${{ steps['publish'].output.repoContentsUrl }}
+ catalogInfoPath: '/catalog-info.yaml'
+
+ # Outputs are displayed to the user after a successful execution of the template.
+ output:
+ links:
+ - title: Repository
+ url: ${{ steps['publish'].output.remoteUrl }}
+ - title: Open in catalog
+ icon: catalog
+ entityRef: ${{ steps['register'].output.entityRef }}
diff --git a/workspaces/dcm/package.json b/workspaces/dcm/package.json
index 0b4e03fc2a..eb67a44e53 100644
--- a/workspaces/dcm/package.json
+++ b/workspaces/dcm/package.json
@@ -16,7 +16,7 @@
"tsc:full": "tsc --skipLibCheck true --incremental false",
"build:all": "backstage-cli repo build --all",
"build:api-reports": "yarn build:api-reports:only --tsc",
- "build:api-reports:only": "backstage-repo-tools api-reports -o ae-wrong-input-file-type --validate-release-tags",
+ "build:api-reports:only": "backstage-repo-tools api-reports -o ae-wrong-input-file-type,ae-missing-release-tag --validate-release-tags",
"build:knip-reports": "backstage-repo-tools knip-reports",
"clean": "backstage-cli repo clean",
"test": "backstage-cli repo test",
@@ -55,7 +55,9 @@
"resolutions": {
"@types/react": "^18",
"@types/react-dom": "^18",
- "fsevents": "~2.3.2"
+ "fsevents": "~2.3.2",
+ "@backstage/backend-app-api": "1.4.1",
+ "@backstage/backend-plugin-api": "1.6.2"
},
"prettier": "@spotify/prettier-config",
"lint-staged": {
diff --git a/workspaces/dcm/packages/app/src/components/Root/Root.tsx b/workspaces/dcm/packages/app/src/components/Root/Root.tsx
index c260bdf32f..0f6815eea7 100644
--- a/workspaces/dcm/packages/app/src/components/Root/Root.tsx
+++ b/workspaces/dcm/packages/app/src/components/Root/Root.tsx
@@ -14,8 +14,9 @@
* limitations under the License.
*/
-import React, { type PropsWithChildren } from 'react';
-import { makeStyles } from '@material-ui/core';
+import React, { type PropsWithChildren, useState } from 'react';
+import { useLocation } from 'react-router-dom';
+import { makeStyles, Button, Typography, Box } from '@material-ui/core';
import ExtensionIcon from '@material-ui/icons/Extension';
import HomeIcon from '@material-ui/icons/Home';
import LibraryBooks from '@material-ui/icons/LibraryBooks';
@@ -38,10 +39,14 @@ import {
} from '@backstage/core-components';
import MenuIcon from '@material-ui/icons/Menu';
import SearchIcon from '@material-ui/icons/Search';
+import SecurityIcon from '@material-ui/icons/Security';
+import StorageIcon from '@material-ui/icons/Storage';
+import VpnKeyIcon from '@material-ui/icons/VpnKey';
+import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
+import ChevronRightIcon from '@material-ui/icons/ChevronRight';
import LogoFull from './LogoFull';
import LogoIcon from './LogoIcon';
import { useRhdhTheme } from '../../hooks/useRhdhTheme';
-import { Administration } from '@backstage-community/plugin-rbac';
const useSidebarLogoStyles = makeStyles({
root: {
@@ -58,6 +63,131 @@ const useSidebarLogoStyles = makeStyles({
},
});
+const useSidebarItemStyles = makeStyles(theme => ({
+ '.MuiButtonBase-root': {},
+ securityIcon: {
+ '& .securityIcon': {
+ fontSize: '20px !important',
+ minWidth: 'unset !important',
+ width: '20px !important',
+ height: '20px !important',
+ },
+ },
+ submenuItem: {
+ marginBottom: 4,
+ '& .MuiSvgIcon-root': {
+ fontSize: '20px !important',
+ },
+ '& .MuiTypography-root': {
+ marginLeft: 8,
+ fontWeight: 400,
+ fontSize: 14,
+ },
+ },
+ submenuItemActive: {
+ borderRadius: 6,
+ border: `1px solid ${
+ (theme.palette as { type?: string; mode?: string }).type === 'dark' ||
+ (theme.palette as { mode?: string }).mode === 'dark'
+ ? 'rgba(255,255,255,0.2)'
+ : 'rgba(0,0,0,0.12)'
+ }`,
+ backgroundColor: `${
+ (theme.palette as { type?: string; mode?: string }).type === 'dark' ||
+ (theme.palette as { mode?: string }).mode === 'dark'
+ ? 'rgba(255,255,255,0.12)'
+ : 'rgba(0,0,0,0.06)'
+ } !important`,
+ },
+ inactiveItem: {
+ backgroundColor: 'transparent !important',
+ },
+ iconContainer: {
+ width: 20,
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'center',
+ '& .MuiSvgIcon-root': { fontSize: '20px !important' },
+ marginRight: 5,
+ },
+ text: {
+ marginRight: 20,
+ },
+ collapsibleTrigger: {
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'center',
+ width: '100%',
+ minHeight: 48,
+ padding: '0 !important',
+ marginLeft: 0,
+ marginBottom: 10,
+ textTransform: 'none',
+ color: `${
+ theme.palette.navigation?.color ??
+ ((theme.palette as { type?: string; mode?: string }).type === 'dark' ||
+ (theme.palette as { type?: string; mode?: string }).mode === 'dark'
+ ? theme.palette.common.white
+ : theme.palette.text.primary)
+ } !important`,
+ '& .MuiTypography-root': {
+ color: 'inherit !important',
+ marginLeft: theme.spacing(0.5),
+ fontSize: 14,
+ fontWeight: 600,
+ },
+ '& .MuiSvgIcon-root': {
+ fontSize: '20px !important',
+ flexShrink: 0,
+ },
+ '&:hover': {
+ backgroundColor:
+ theme.palette.navigation?.navItem?.hoverBackground ??
+ 'rgba(255,255,255,0.08)',
+ },
+ },
+ collapsibleContent: {
+ marginLeft: theme.spacing(3),
+ },
+}));
+
+const CollapsibleSubmenu = ({
+ icon,
+ text,
+ children,
+ classes,
+}: {
+ icon: React.ReactElement;
+ text: string;
+ children: React.ReactNode;
+ classes: {
+ collapsibleTrigger: string;
+ collapsibleContent: string;
+ iconContainer: string;
+ text: string;
+ };
+}) => {
+ const [isOpen, setIsOpen] = useState(true);
+ const { isOpen: sidebarOpen } = useSidebarOpenState();
+
+ return (
+
+
+ {isOpen && {children}}
+
+ );
+};
+
const Logo = (props: { isOpen?: boolean }) => {
const { isOpen = false } = props;
const rhdhTheme = useRhdhTheme();
@@ -87,33 +217,67 @@ const SidebarLogo = () => {
);
};
-export const Root = ({ children }: PropsWithChildren<{}>) => (
-
-
-
- } to="/search">
-
-
-
- }>
-
-
-
-
+export const Root = ({ children }: PropsWithChildren<{}>) => {
+ const classes = useSidebarItemStyles();
+ const location = useLocation();
+ const isDcmActive = location.pathname === '/dcm';
+ const isRbacActive = location.pathname === '/rbac';
+
+ return (
+
+
+
+ } to="/search">
+
+
-
-
-
-
-
- }
- to="/settings"
- >
-
-
-
- {children}
-
-);
+ }>
+
+
+
+
+
+
+
+ }>
+
+ }
+ text="Administration"
+ classes={classes}
+ >
+
+
+
+
+ }
+ to="/settings"
+ >
+
+
+
+ {children}
+
+ );
+};
diff --git a/workspaces/dcm/packages/backend/package.json b/workspaces/dcm/packages/backend/package.json
index 24984fc537..e417d06e99 100644
--- a/workspaces/dcm/packages/backend/package.json
+++ b/workspaces/dcm/packages/backend/package.json
@@ -20,6 +20,7 @@
"clean": "backstage-cli package clean"
},
"dependencies": {
+ "@backstage-community/plugin-rbac-backend": "5.2.6",
"@backstage/backend-defaults": "^0.15.1",
"@backstage/config": "^1.3.2",
"@backstage/plugin-app-backend": "^0.4.4",
@@ -28,6 +29,8 @@
"@backstage/plugin-catalog-backend": "^1.30.0",
"@backstage/plugin-catalog-backend-module-logs": "^0.1.8",
"@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "^0.2.4",
+ "@backstage/plugin-events-backend": "^0.5.0",
+ "@backstage/plugin-permission-backend": "^0.5.53",
"@backstage/plugin-proxy-backend": "^0.5.10",
"@backstage/plugin-scaffolder-backend": "^1.29.0",
"@backstage/plugin-search-backend": "^1.8.1",
diff --git a/workspaces/dcm/packages/backend/src/index.ts b/workspaces/dcm/packages/backend/src/index.ts
index 4e469731b2..66a38f6831 100644
--- a/workspaces/dcm/packages/backend/src/index.ts
+++ b/workspaces/dcm/packages/backend/src/index.ts
@@ -23,17 +23,22 @@ backend.add(import('@backstage/plugin-proxy-backend'));
backend.add(import('@backstage/plugin-scaffolder-backend'));
backend.add(import('@backstage/plugin-techdocs-backend'));
-backend.add(import('@red-hat-developer-hub/backstage-plugin-dcm-backend'));
-
backend.add(import('@backstage/plugin-auth-backend'));
backend.add(import('@backstage/plugin-auth-backend-module-guest-provider'));
+backend.add(import('@backstage/plugin-events-backend'));
+
backend.add(import('@backstage/plugin-catalog-backend'));
backend.add(
import('@backstage/plugin-catalog-backend-module-scaffolder-entity-model'),
);
backend.add(import('@backstage/plugin-catalog-backend-module-logs'));
+// RBAC backend (registers as "permission" and provides /rbac; do not add plugin-permission-backend separately)
+backend.add(import('@backstage-community/plugin-rbac-backend'));
+
+backend.add(import('@red-hat-developer-hub/backstage-plugin-dcm-backend'));
+
backend.add(import('@backstage/plugin-search-backend'));
backend.add(import('@backstage/plugin-search-backend-module-catalog'));
backend.add(import('@backstage/plugin-search-backend-module-techdocs'));
diff --git a/workspaces/dcm/plugins/dcm-backend/package.json b/workspaces/dcm/plugins/dcm-backend/package.json
index e62af2c614..8bcc35287b 100644
--- a/workspaces/dcm/plugins/dcm-backend/package.json
+++ b/workspaces/dcm/plugins/dcm-backend/package.json
@@ -38,7 +38,11 @@
"@backstage/catalog-client": "^1.12.1",
"@backstage/errors": "^1.2.7",
"@backstage/plugin-catalog-node": "^1.20.1",
+ "@backstage/plugin-permission-common": "^0.8.4",
+ "@backstage/plugin-permission-node": "^0.8.7",
"@backstage/types": "^1.2.2",
+ "@red-hat-developer-hub/backstage-plugin-dcm-common": "workspace:^",
+ "assert": "^2.1.0",
"express": "^4.17.1",
"express-promise-router": "^4.1.0",
"zod": "^3.25.76"
diff --git a/workspaces/dcm/plugins/dcm-backend/src/models/GetTokenResponse.ts b/workspaces/dcm/plugins/dcm-backend/src/models/GetTokenResponse.ts
new file mode 100644
index 0000000000..db0052abcb
--- /dev/null
+++ b/workspaces/dcm/plugins/dcm-backend/src/models/GetTokenResponse.ts
@@ -0,0 +1,24 @@
+/*
+ * Copyright Red Hat, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF THE License, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @public
+ */
+export interface GetTokenResponse {
+ accessToken: string;
+ /** The Unix Epoch at which the token will expire */
+ expiresAt: number;
+}
diff --git a/workspaces/dcm/plugins/dcm-backend/src/models/RouterOptions.ts b/workspaces/dcm/plugins/dcm-backend/src/models/RouterOptions.ts
new file mode 100644
index 0000000000..9f393a75ab
--- /dev/null
+++ b/workspaces/dcm/plugins/dcm-backend/src/models/RouterOptions.ts
@@ -0,0 +1,32 @@
+/*
+ * Copyright Red Hat, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF THE License, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import type {
+ LoggerService,
+ RootConfigService,
+ HttpAuthService,
+ PermissionsService,
+ CacheService,
+} from '@backstage/backend-plugin-api';
+
+/** @public */
+export interface RouterOptions {
+ logger: LoggerService;
+ config?: RootConfigService;
+ httpAuth: HttpAuthService;
+ permissions: PermissionsService;
+ cache: CacheService;
+}
diff --git a/workspaces/dcm/plugins/dcm-backend/src/plugin.test.ts b/workspaces/dcm/plugins/dcm-backend/src/plugin.test.ts
index 37ba0e6383..b386c5713d 100644
--- a/workspaces/dcm/plugins/dcm-backend/src/plugin.test.ts
+++ b/workspaces/dcm/plugins/dcm-backend/src/plugin.test.ts
@@ -14,132 +14,19 @@
* limitations under the License.
*/
/* eslint-disable @backstage/no-undeclared-imports -- deps in dcm-backend package.json */
-import {
- mockCredentials,
- startTestBackend,
-} from '@backstage/backend-test-utils';
-import { createServiceFactory } from '@backstage/backend-plugin-api';
-import { todoListServiceRef } from './services/TodoListService';
+import { startTestBackend } from '@backstage/backend-test-utils';
import { dcmPlugin } from './plugin';
import request from 'supertest';
-import { catalogServiceMock } from '@backstage/plugin-catalog-node/testUtils';
-import {
- ConflictError,
- AuthenticationError,
- NotAllowedError,
-} from '@backstage/errors';
-// TEMPLATE NOTE:
-// Plugin tests are integration tests for your plugin, ensuring that all pieces
-// work together end-to-end. You can still mock injected backend services
-// however, just like anyone who installs your plugin might replace the
-// services with their own implementations.
describe('plugin', () => {
- it('should create and read TODO items', async () => {
+ it('should serve health endpoint', async () => {
const { server } = await startTestBackend({
features: [dcmPlugin],
});
- await request(server).get('/api/dcm/todos').expect(200, {
- items: [],
- });
-
- const createRes = await request(server)
- .post('/api/dcm/todos')
- .send({ title: 'My Todo' });
-
- expect(createRes.status).toBe(201);
- expect(createRes.body).toEqual({
- id: expect.any(String),
- title: 'My Todo',
- createdBy: mockCredentials.user().principal.userEntityRef,
- createdAt: expect.any(String),
- });
-
- const createdTodoItem = createRes.body;
-
- await request(server)
- .get('/api/dcm/todos')
- .expect(200, {
- items: [createdTodoItem],
- });
-
- await request(server)
- .get(`/api/dcm/todos/${createdTodoItem.id}`)
- .expect(200, createdTodoItem);
- });
-
- it('should create TODO item with catalog information', async () => {
- const { server } = await startTestBackend({
- features: [
- dcmPlugin,
- catalogServiceMock.factory({
- entities: [
- {
- apiVersion: 'backstage.io/v1alpha1',
- kind: 'Component',
- metadata: {
- name: 'my-component',
- namespace: 'default',
- title: 'My Component',
- },
- spec: {
- type: 'service',
- owner: 'me',
- },
- },
- ],
- }),
- ],
- });
-
- const createRes = await request(server)
- .post('/api/dcm/todos')
- .send({ title: 'My Todo', entityRef: 'component:default/my-component' });
+ const res = await request(server).get('/api/dcm/health');
- expect(createRes.status).toBe(201);
- expect(createRes.body).toEqual({
- id: expect.any(String),
- title: '[My Component] My Todo',
- createdBy: mockCredentials.user().principal.userEntityRef,
- createdAt: expect.any(String),
- });
- });
-
- it('should forward errors from the TodoListService', async () => {
- const { server } = await startTestBackend({
- features: [
- dcmPlugin,
- createServiceFactory({
- service: todoListServiceRef,
- deps: {},
- factory: () => ({
- createTodo: jest.fn().mockRejectedValue(new ConflictError()),
- listTodos: jest.fn().mockRejectedValue(new AuthenticationError()),
- getTodo: jest.fn().mockRejectedValue(new NotAllowedError()),
- }),
- }),
- ],
- });
-
- const createRes = await request(server)
- .post('/api/dcm/todos')
- .send({ title: 'My Todo', entityRef: 'component:default/my-component' });
- expect(createRes.status).toBe(409);
- expect(createRes.body).toMatchObject({
- error: { name: 'ConflictError' },
- });
-
- const listRes = await request(server).get('/api/dcm/todos');
- expect(listRes.status).toBe(401);
- expect(listRes.body).toMatchObject({
- error: { name: 'AuthenticationError' },
- });
-
- const getRes = await request(server).get('/api/dcm/todos/123');
- expect(getRes.status).toBe(403);
- expect(getRes.body).toMatchObject({
- error: { name: 'NotAllowedError' },
- });
+ expect(res.status).toBe(200);
+ expect(res.body).toEqual({ status: 'ok' });
});
});
diff --git a/workspaces/dcm/plugins/dcm-backend/src/plugin.ts b/workspaces/dcm/plugins/dcm-backend/src/plugin.ts
index 4f98efe8f3..387381284c 100644
--- a/workspaces/dcm/plugins/dcm-backend/src/plugin.ts
+++ b/workspaces/dcm/plugins/dcm-backend/src/plugin.ts
@@ -9,7 +9,7 @@
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * WITHOUT WARRANTIES OR CONDITIONS OF THE License, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@@ -18,7 +18,6 @@ import {
createBackendPlugin,
} from '@backstage/backend-plugin-api';
import { createRouter } from './router';
-import { todoListServiceRef } from './services/TodoListService';
/**
* dcmPlugin backend plugin
@@ -30,17 +29,34 @@ export const dcmPlugin = createBackendPlugin({
register(env) {
env.registerInit({
deps: {
- httpAuth: coreServices.httpAuth,
httpRouter: coreServices.httpRouter,
- todoList: todoListServiceRef,
+ logger: coreServices.logger,
+ config: coreServices.rootConfig,
+ httpAuth: coreServices.httpAuth,
+ permissions: coreServices.permissions,
+ cache: coreServices.cache,
},
- async init({ httpAuth, httpRouter, todoList }) {
- httpRouter.use(
- await createRouter({
- httpAuth,
- todoList,
- }),
- );
+ async init({ httpRouter, logger, config, httpAuth, permissions, cache }) {
+ const router = await createRouter({
+ logger,
+ config,
+ httpAuth,
+ permissions,
+ cache,
+ });
+ httpRouter.use(router);
+ httpRouter.addAuthPolicy({
+ path: '/health',
+ allow: 'unauthenticated',
+ });
+ httpRouter.addAuthPolicy({
+ path: '/token',
+ allow: 'user-cookie',
+ });
+ httpRouter.addAuthPolicy({
+ path: '/access',
+ allow: 'user-cookie',
+ });
},
});
},
diff --git a/workspaces/dcm/plugins/dcm-backend/src/router.test.ts b/workspaces/dcm/plugins/dcm-backend/src/router.test.ts
index 49b4ce228b..863feb2804 100644
--- a/workspaces/dcm/plugins/dcm-backend/src/router.test.ts
+++ b/workspaces/dcm/plugins/dcm-backend/src/router.test.ts
@@ -14,70 +14,30 @@
* limitations under the License.
*/
/* eslint-disable @backstage/no-undeclared-imports -- deps in dcm-backend package.json */
-import {
- mockCredentials,
- mockErrorHandler,
- mockServices,
-} from '@backstage/backend-test-utils';
+import { mockServices } from '@backstage/backend-test-utils';
import express from 'express';
import request from 'supertest';
import { createRouter } from './router';
-import { todoListServiceRef } from './services/TodoListService';
-const mockTodoItem = {
- title: 'Do the thing',
- id: '123',
- createdBy: mockCredentials.user().principal.userEntityRef,
- createdAt: new Date().toISOString(),
-};
-
-// TEMPLATE NOTE:
-// Testing the router directly allows you to write a unit test that mocks the provided options.
describe('createRouter', () => {
let app: express.Express;
- let todoList: jest.Mocked;
beforeEach(async () => {
- todoList = {
- createTodo: jest.fn(),
- listTodos: jest.fn(),
- getTodo: jest.fn(),
- };
const router = await createRouter({
+ logger: mockServices.rootLogger(),
httpAuth: mockServices.httpAuth(),
- todoList,
+ permissions: mockServices.permissions.mock(),
+ cache: mockServices.cache.mock(),
});
app = express();
app.use(router);
- app.use(mockErrorHandler());
});
- it('should create a TODO', async () => {
- todoList.createTodo.mockResolvedValue(mockTodoItem);
-
- const response = await request(app).post('/todos').send({
- title: 'Do the thing',
- });
-
- expect(response.status).toBe(201);
- expect(response.body).toEqual(mockTodoItem);
- });
-
- it('should not allow unauthenticated requests to create a TODO', async () => {
- todoList.createTodo.mockResolvedValue(mockTodoItem);
-
- // TEMPLATE NOTE:
- // The HttpAuth mock service considers all requests to be authenticated as a
- // mock user by default. In order to test other cases we need to explicitly
- // pass an authorization header with mock credentials.
- const response = await request(app)
- .post('/todos')
- .set('Authorization', mockCredentials.none.header())
- .send({
- title: 'Do the thing',
- });
+ it('should return ok for GET /health', async () => {
+ const response = await request(app).get('/health');
- expect(response.status).toBe(401);
+ expect(response.status).toBe(200);
+ expect(response.body).toEqual({ status: 'ok' });
});
});
diff --git a/workspaces/dcm/plugins/dcm-backend/src/router.ts b/workspaces/dcm/plugins/dcm-backend/src/router.ts
index ea01d6559b..3e0511197a 100644
--- a/workspaces/dcm/plugins/dcm-backend/src/router.ts
+++ b/workspaces/dcm/plugins/dcm-backend/src/router.ts
@@ -9,59 +9,37 @@
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * WITHOUT WARRANTIES OR CONDITIONS OF THE License, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* eslint-disable @backstage/no-undeclared-imports -- deps in dcm-backend package.json */
-import { HttpAuthService } from '@backstage/backend-plugin-api';
-import { InputError } from '@backstage/errors';
-import { z } from 'zod';
+import { createPermissionIntegrationRouter } from '@backstage/plugin-permission-node';
+import { dcmPluginPermissions } from '@red-hat-developer-hub/backstage-plugin-dcm-common';
import express from 'express';
import Router from 'express-promise-router';
-import { todoListServiceRef } from './services/TodoListService';
+import type { RouterOptions } from './models/RouterOptions';
+import { getToken } from './routes/token';
+import { getAccess } from './routes/access';
-export async function createRouter({
- httpAuth,
- todoList,
-}: {
- httpAuth: HttpAuthService;
- todoList: typeof todoListServiceRef.T;
-}): Promise {
+export async function createRouter(
+ options: RouterOptions,
+): Promise {
const router = Router();
- router.use(express.json());
-
- // TEMPLATE NOTE:
- // Zod is a powerful library for data validation and recommended in particular
- // for user-defined schemas. In this case we use it for input validation too.
- //
- // If you want to define a schema for your API we recommend using Backstage's
- // OpenAPI tooling: https://backstage.io/docs/next/openapi/01-getting-started
- const todoSchema = z.object({
- title: z.string(),
- entityRef: z.string().optional(),
- });
- router.post('/todos', async (req, res) => {
- const parsed = todoSchema.safeParse(req.body);
- if (!parsed.success) {
- throw new InputError(parsed.error.toString());
- }
-
- const result = await todoList.createTodo(parsed.data, {
- credentials: await httpAuth.credentials(req, { allow: ['user'] }),
- });
+ router.use(express.json());
- res.status(201).json(result);
+ const permissionsIntegrationRouter = createPermissionIntegrationRouter({
+ permissions: dcmPluginPermissions,
});
+ router.use(permissionsIntegrationRouter);
- router.get('/todos', async (_req, res) => {
- res.json(await todoList.listTodos());
+ router.get('/health', (_req, res) => {
+ res.json({ status: 'ok' });
});
- router.get('/todos/:id', async (req, res) => {
- res.json(await todoList.getTodo({ id: req.params.id }));
- });
+ router.get('/token', getToken(options));
+ router.get('/access', getAccess(options));
return router;
}
diff --git a/workspaces/dcm/plugins/dcm-backend/src/routes/access.ts b/workspaces/dcm/plugins/dcm-backend/src/routes/access.ts
new file mode 100644
index 0000000000..cdf6abaa0f
--- /dev/null
+++ b/workspaces/dcm/plugins/dcm-backend/src/routes/access.ts
@@ -0,0 +1,50 @@
+/*
+ * Copyright Red Hat, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF THE License, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import type { RequestHandler } from 'express';
+import type { RouterOptions } from '../models/RouterOptions';
+import { AuthorizeResult } from '@backstage/plugin-permission-common';
+import { dcmPluginPermissions } from '@red-hat-developer-hub/backstage-plugin-dcm-common';
+
+async function authorize(
+ request: Parameters[0],
+ options: RouterOptions,
+): Promise {
+ const { permissions, httpAuth } = options;
+ const credentials = await httpAuth.credentials(request);
+ const decisions = await permissions.authorize(
+ dcmPluginPermissions.map(permission => ({ permission })),
+ { credentials },
+ );
+ const allow = decisions.find(d => d.result === AuthorizeResult.ALLOW);
+ return allow ? AuthorizeResult.ALLOW : AuthorizeResult.DENY;
+}
+
+export const getAccess =
+ (options: RouterOptions): RequestHandler =>
+ async (req, response) => {
+ const { logger } = options;
+
+ const decision = await authorize(req, options);
+
+ logger.info(`DCM access decision: ${decision}`);
+
+ response.json({
+ decision,
+ authorizeClusterIds: [],
+ authorizeProjects: [],
+ });
+ };
diff --git a/workspaces/dcm/plugins/dcm-backend/src/routes/token.ts b/workspaces/dcm/plugins/dcm-backend/src/routes/token.ts
new file mode 100644
index 0000000000..1d049ddaba
--- /dev/null
+++ b/workspaces/dcm/plugins/dcm-backend/src/routes/token.ts
@@ -0,0 +1,64 @@
+/*
+ * Copyright Red Hat, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF THE License, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import type { RequestHandler } from 'express';
+import type { GetTokenResponse } from '../models/GetTokenResponse';
+import type { RouterOptions } from '../models/RouterOptions';
+import { DEFAULT_SSO_BASE_URL } from '../util/constant';
+import assert from 'assert';
+
+export const getToken =
+ (options: RouterOptions): RequestHandler =>
+ async (_, response) => {
+ const { logger, config } = options;
+
+ assert(typeof config !== 'undefined', 'Config is undefined');
+
+ logger.info('Requesting new access token');
+
+ const ssoBaseUrl =
+ config.getOptionalString('dcm.ssoBaseUrl') ?? DEFAULT_SSO_BASE_URL;
+ const clientId = config.getString('dcm.clientId');
+ const clientSecret = config.getString('dcm.clientSecret');
+
+ const tokenUrl = `${ssoBaseUrl}/auth/realms/redhat-external/protocol/openid-connect/token`;
+ const body = new URLSearchParams({
+ client_id: clientId,
+ client_secret: clientSecret,
+ scope: 'api.console',
+ grant_type: 'client_credentials',
+ });
+
+ const rhSsoResponse = await fetch(tokenUrl, {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
+ body: body.toString(),
+ });
+
+ if (rhSsoResponse.ok) {
+ const json = (await rhSsoResponse.json()) as {
+ access_token: string;
+ expires_in: number;
+ };
+ const bodyRes: GetTokenResponse = {
+ accessToken: json.access_token,
+ expiresAt: Date.now() + json.expires_in * 1000,
+ };
+ response.json(bodyRes);
+ } else {
+ throw new Error(rhSsoResponse.statusText);
+ }
+ };
diff --git a/workspaces/dcm/plugins/dcm-backend/src/util/constant.ts b/workspaces/dcm/plugins/dcm-backend/src/util/constant.ts
new file mode 100644
index 0000000000..93397df581
--- /dev/null
+++ b/workspaces/dcm/plugins/dcm-backend/src/util/constant.ts
@@ -0,0 +1,17 @@
+/*
+ * Copyright Red Hat, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF THE License, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export const DEFAULT_SSO_BASE_URL = 'https://sso.redhat.com';
diff --git a/workspaces/dcm/plugins/dcm-backend/src/util/tokenUtil.ts b/workspaces/dcm/plugins/dcm-backend/src/util/tokenUtil.ts
new file mode 100644
index 0000000000..4ee0b02cc4
--- /dev/null
+++ b/workspaces/dcm/plugins/dcm-backend/src/util/tokenUtil.ts
@@ -0,0 +1,92 @@
+/*
+ * Copyright Red Hat, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF THE License, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import assert from 'assert';
+import type { RouterOptions } from '../models/RouterOptions';
+import { DEFAULT_SSO_BASE_URL } from './constant';
+
+const TOKEN_CACHE_KEY = 'dcm_sso_access_token';
+
+export const getTokenFromApi = async (
+ options: RouterOptions,
+): Promise => {
+ const { logger, config, cache } = options;
+
+ const now = Date.now();
+
+ const cachedToken = (await cache.get(TOKEN_CACHE_KEY)) as
+ | { token: string; expiresAt: number }
+ | undefined;
+
+ if (cachedToken) {
+ const timeUntilExpirySeconds = Math.floor(
+ (cachedToken.expiresAt - now) / 1000,
+ );
+ logger.info(
+ `Cache check: Token expires in ${timeUntilExpirySeconds}s, needs >60s to be valid`,
+ );
+ } else {
+ logger.info('Cache check: No cached token exists');
+ }
+
+ if (cachedToken && cachedToken.expiresAt > now + 60000) {
+ logger.info('Using cached access token');
+ return cachedToken.token;
+ }
+
+ assert(typeof config !== 'undefined', 'Config is undefined');
+
+ logger.info('Requesting new access token');
+
+ const ssoBaseUrl =
+ config.getOptionalString('dcm.ssoBaseUrl') ?? DEFAULT_SSO_BASE_URL;
+ const clientId = config.getString('dcm.clientId');
+ const clientSecret = config.getString('dcm.clientSecret');
+
+ const tokenUrl = `${ssoBaseUrl}/auth/realms/redhat-external/protocol/openid-connect/token`;
+ const body = new URLSearchParams({
+ client_id: clientId,
+ client_secret: clientSecret,
+ scope: 'api.console',
+ grant_type: 'client_credentials',
+ });
+
+ const response = await fetch(tokenUrl, {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
+ body: body.toString(),
+ });
+
+ if (!response.ok) {
+ throw new Error(response.statusText);
+ }
+
+ const json = (await response.json()) as {
+ access_token: string;
+ expires_in: number;
+ };
+ const accessToken = json.access_token;
+ const expiresAt = Date.now() + json.expires_in * 1000;
+
+ await cache.set(
+ TOKEN_CACHE_KEY,
+ { token: accessToken, expiresAt },
+ { ttl: json.expires_in * 1000 },
+ );
+
+ logger.info(`Token cached, expires in ${json.expires_in} seconds`);
+ return accessToken;
+};
diff --git a/workspaces/dcm/plugins/dcm-common/package.json b/workspaces/dcm/plugins/dcm-common/package.json
index 9d19c6c1b3..f74c32ebbf 100644
--- a/workspaces/dcm/plugins/dcm-common/package.json
+++ b/workspaces/dcm/plugins/dcm-common/package.json
@@ -46,7 +46,8 @@
"postpack": "backstage-cli package postpack"
},
"dependencies": {
- "@backstage/core-plugin-api": "^1.12.2"
+ "@backstage/core-plugin-api": "^1.12.2",
+ "@backstage/plugin-permission-common": "^0.8.4"
},
"devDependencies": {
"@backstage/cli": "^0.35.2"
diff --git a/workspaces/dcm/plugins/dcm-common/report.api.md b/workspaces/dcm/plugins/dcm-common/report.api.md
index a4f767e7cf..d7e453b68f 100644
--- a/workspaces/dcm/plugins/dcm-common/report.api.md
+++ b/workspaces/dcm/plugins/dcm-common/report.api.md
@@ -3,8 +3,14 @@
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
+import { BasicPermission } from '@backstage/plugin-permission-common';
+
// @public
export const DCM_COMMON_PLUGIN_ID: 'dcm';
-// (No @packageDocumentation comment for this package)
+// @public
+export const dcmPluginPermissions: BasicPermission[];
+
+// @public
+export const dcmPluginReadPermission: BasicPermission;
```
diff --git a/workspaces/dcm/plugins/dcm-common/src/index.ts b/workspaces/dcm/plugins/dcm-common/src/index.ts
index 3b52c918b6..d3e78f7c41 100644
--- a/workspaces/dcm/plugins/dcm-common/src/index.ts
+++ b/workspaces/dcm/plugins/dcm-common/src/index.ts
@@ -15,9 +15,13 @@
*/
/**
- * Common types and utilities for the dcm plugin.
+ * Common types and utilities for the DCM plugin.
* Add shared code between frontend and backend plugins here.
*
- * @public
+ * @packageDocumentation
*/
+
+/** Plugin ID for the DCM plugin. @public */
export const DCM_COMMON_PLUGIN_ID = 'dcm' as const;
+
+export { dcmPluginReadPermission, dcmPluginPermissions } from './permissions';
diff --git a/workspaces/dcm/plugins/dcm-common/src/permissions.ts b/workspaces/dcm/plugins/dcm-common/src/permissions.ts
new file mode 100644
index 0000000000..3e35f2b41a
--- /dev/null
+++ b/workspaces/dcm/plugins/dcm-common/src/permissions.ts
@@ -0,0 +1,34 @@
+/*
+ * Copyright Red Hat, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF THE License, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { createPermission } from '@backstage/plugin-permission-common';
+
+/**
+ * Permission for reading the DCM plugin.
+ *
+ * @public
+ */
+export const dcmPluginReadPermission = createPermission({
+ name: 'dcm.plugin',
+ attributes: { action: 'read' },
+});
+
+/**
+ * List of all DCM plugin permissions.
+ *
+ * @public
+ */
+export const dcmPluginPermissions = [dcmPluginReadPermission];
diff --git a/workspaces/dcm/yarn.lock b/workspaces/dcm/yarn.lock
index 6b5382fd64..efeccfc7d3 100644
--- a/workspaces/dcm/yarn.lock
+++ b/workspaces/dcm/yarn.lock
@@ -1569,6 +1569,35 @@ __metadata:
languageName: node
linkType: hard
+"@backstage-community/plugin-rbac-backend@npm:5.2.6":
+ version: 5.2.6
+ resolution: "@backstage-community/plugin-rbac-backend@npm:5.2.6"
+ dependencies:
+ "@backstage-community/plugin-rbac-common": "npm:^1.12.2"
+ "@backstage-community/plugin-rbac-node": "npm:^1.8.2"
+ "@backstage/backend-defaults": "npm:^0.5.2"
+ "@backstage/backend-plugin-api": "npm:^1.0.1"
+ "@backstage/catalog-client": "npm:^1.7.1"
+ "@backstage/catalog-model": "npm:^1.7.0"
+ "@backstage/errors": "npm:^1.2.4"
+ "@backstage/plugin-auth-node": "npm:^0.5.3"
+ "@backstage/plugin-permission-backend": "npm:^0.5.50"
+ "@backstage/plugin-permission-common": "npm:^0.8.1"
+ "@backstage/plugin-permission-node": "npm:^0.8.4"
+ "@dagrejs/graphlib": "npm:^2.1.13"
+ "@janus-idp/backstage-plugin-audit-log-node": "npm:^1.7.1"
+ casbin: "npm:^5.27.1"
+ chokidar: "npm:^3.6.0"
+ csv-parse: "npm:^5.5.5"
+ express: "npm:^4.18.2"
+ js-yaml: "npm:^4.1.0"
+ knex: "npm:^3.0.0"
+ lodash: "npm:^4.17.21"
+ typeorm-adapter: "npm:^1.6.1"
+ checksum: 10/095da0a1f6922bf635ea89c7a4ba9d9decb3dab58b43bc34694fff5db912a42280d061845348c1a4af6b0ef38cb694d54b7c24225f3416cc126433605e2d70ea
+ languageName: node
+ linkType: hard
+
"@backstage-community/plugin-rbac-common@npm:^1.12.2":
version: 1.23.0
resolution: "@backstage-community/plugin-rbac-common@npm:1.23.0"
@@ -1579,6 +1608,15 @@ __metadata:
languageName: node
linkType: hard
+"@backstage-community/plugin-rbac-node@npm:^1.8.2":
+ version: 1.17.0
+ resolution: "@backstage-community/plugin-rbac-node@npm:1.17.0"
+ dependencies:
+ "@backstage/backend-plugin-api": "npm:^1.6.2"
+ checksum: 10/60a3e2f1757d9393a231ea0f518b7b01aa94bdda76809dd4df4aebab12ae445c5d53806623c59cd1b5198c21a7681794fb20d4061a780c89e1ca688a6995c66d
+ languageName: node
+ linkType: hard
+
"@backstage-community/plugin-rbac@npm:1.33.2":
version: 1.33.2
resolution: "@backstage-community/plugin-rbac@npm:1.33.2"
@@ -1634,7 +1672,7 @@ __metadata:
languageName: node
linkType: hard
-"@backstage/backend-app-api@npm:^1.2.1, @backstage/backend-app-api@npm:^1.2.3, @backstage/backend-app-api@npm:^1.4.1":
+"@backstage/backend-app-api@npm:1.4.1":
version: 1.4.1
resolution: "@backstage/backend-app-api@npm:1.4.1"
dependencies:
@@ -1888,6 +1926,83 @@ __metadata:
languageName: node
linkType: hard
+"@backstage/backend-defaults@npm:^0.5.2":
+ version: 0.5.3
+ resolution: "@backstage/backend-defaults@npm:0.5.3"
+ dependencies:
+ "@aws-sdk/abort-controller": "npm:^3.347.0"
+ "@aws-sdk/client-codecommit": "npm:^3.350.0"
+ "@aws-sdk/client-s3": "npm:^3.350.0"
+ "@aws-sdk/credential-providers": "npm:^3.350.0"
+ "@aws-sdk/types": "npm:^3.347.0"
+ "@backstage/backend-app-api": "npm:^1.0.2"
+ "@backstage/backend-dev-utils": "npm:^0.1.5"
+ "@backstage/backend-plugin-api": "npm:^1.0.2"
+ "@backstage/cli-common": "npm:^0.1.15"
+ "@backstage/cli-node": "npm:^0.2.10"
+ "@backstage/config": "npm:^1.3.0"
+ "@backstage/config-loader": "npm:^1.9.2"
+ "@backstage/errors": "npm:^1.2.5"
+ "@backstage/integration": "npm:^1.15.2"
+ "@backstage/integration-aws-node": "npm:^0.1.13"
+ "@backstage/plugin-auth-node": "npm:^0.5.4"
+ "@backstage/plugin-events-node": "npm:^0.4.5"
+ "@backstage/plugin-permission-node": "npm:^0.8.5"
+ "@backstage/types": "npm:^1.2.0"
+ "@google-cloud/storage": "npm:^7.0.0"
+ "@keyv/memcache": "npm:^1.3.5"
+ "@keyv/redis": "npm:^2.5.3"
+ "@manypkg/get-packages": "npm:^1.1.3"
+ "@octokit/rest": "npm:^19.0.3"
+ "@opentelemetry/api": "npm:^1.3.0"
+ "@types/cors": "npm:^2.8.6"
+ "@types/express": "npm:^4.17.6"
+ archiver: "npm:^7.0.0"
+ base64-stream: "npm:^1.0.0"
+ better-sqlite3: "npm:^11.0.0"
+ compression: "npm:^1.7.4"
+ concat-stream: "npm:^2.0.0"
+ cookie: "npm:^0.7.0"
+ cors: "npm:^2.8.5"
+ cron: "npm:^3.0.0"
+ express: "npm:^4.17.1"
+ express-promise-router: "npm:^4.1.0"
+ fs-extra: "npm:^11.2.0"
+ git-url-parse: "npm:^15.0.0"
+ helmet: "npm:^6.0.0"
+ isomorphic-git: "npm:^1.23.0"
+ jose: "npm:^5.0.0"
+ keyv: "npm:^4.5.2"
+ knex: "npm:^3.0.0"
+ lodash: "npm:^4.17.21"
+ logform: "npm:^2.3.2"
+ luxon: "npm:^3.0.0"
+ minimatch: "npm:^9.0.0"
+ minimist: "npm:^1.2.5"
+ morgan: "npm:^1.10.0"
+ mysql2: "npm:^3.0.0"
+ node-fetch: "npm:^2.7.0"
+ node-forge: "npm:^1.3.1"
+ p-limit: "npm:^3.1.0"
+ path-to-regexp: "npm:^8.0.0"
+ pg: "npm:^8.11.3"
+ pg-connection-string: "npm:^2.3.0"
+ pg-format: "npm:^1.0.4"
+ raw-body: "npm:^2.4.1"
+ selfsigned: "npm:^2.0.0"
+ stoppable: "npm:^1.1.0"
+ tar: "npm:^6.1.12"
+ triple-beam: "npm:^1.4.1"
+ uuid: "npm:^11.0.0"
+ winston: "npm:^3.2.1"
+ winston-transport: "npm:^4.5.0"
+ yauzl: "npm:^3.0.0"
+ yn: "npm:^4.0.0"
+ zod: "npm:^3.22.4"
+ checksum: 10/b276ca8716835f68bf365b0d99f8b3ffd02609daf6c5fc6f750de8dadcac9f26e4740cfb4d44886d687f87e5820060efa560ee74eba08b863956a521fbe59562
+ languageName: node
+ linkType: hard
+
"@backstage/backend-defaults@npm:^0.8.0":
version: 0.8.2
resolution: "@backstage/backend-defaults@npm:0.8.2"
@@ -1998,12 +2113,12 @@ __metadata:
languageName: node
linkType: hard
-"@backstage/backend-openapi-utils@npm:^0.6.5":
- version: 0.6.5
- resolution: "@backstage/backend-openapi-utils@npm:0.6.5"
+"@backstage/backend-openapi-utils@npm:^0.6.5, @backstage/backend-openapi-utils@npm:^0.6.6":
+ version: 0.6.6
+ resolution: "@backstage/backend-openapi-utils@npm:0.6.6"
dependencies:
"@apidevtools/swagger-parser": "npm:^10.1.0"
- "@backstage/backend-plugin-api": "npm:^1.6.1"
+ "@backstage/backend-plugin-api": "npm:^1.7.0"
"@backstage/errors": "npm:^1.2.7"
"@backstage/types": "npm:^1.2.2"
"@types/express": "npm:^4.17.6"
@@ -2018,11 +2133,11 @@ __metadata:
mockttp: "npm:^3.13.0"
openapi-merge: "npm:^1.3.2"
openapi3-ts: "npm:^3.1.2"
- checksum: 10/e65f216905a50698deedda54e1cc38e89e8f63b136bce42b3d59d9e9a1055837c6534bd222d296c5b1dd6b6741cd5ff934563c80ddbece052b0936ad197b2b35
+ checksum: 10/586006ad050233955cc702701e6d3437ca26289ca1202162738b26bc18707050d30eb3f6ec5507752003d8c1e171567e6022d01b06774cd28f13562850b38a8d
languageName: node
linkType: hard
-"@backstage/backend-plugin-api@npm:^1.0.0, @backstage/backend-plugin-api@npm:^1.1.1, @backstage/backend-plugin-api@npm:^1.2.0, @backstage/backend-plugin-api@npm:^1.2.1, @backstage/backend-plugin-api@npm:^1.3.0, @backstage/backend-plugin-api@npm:^1.3.1, @backstage/backend-plugin-api@npm:^1.4.1, @backstage/backend-plugin-api@npm:^1.4.4, @backstage/backend-plugin-api@npm:^1.5.0, @backstage/backend-plugin-api@npm:^1.6.0, @backstage/backend-plugin-api@npm:^1.6.1, @backstage/backend-plugin-api@npm:^1.6.2":
+"@backstage/backend-plugin-api@npm:1.6.2":
version: 1.6.2
resolution: "@backstage/backend-plugin-api@npm:1.6.2"
dependencies:
@@ -2084,15 +2199,17 @@ __metadata:
languageName: node
linkType: hard
-"@backstage/catalog-client@npm:^1.10.0, @backstage/catalog-client@npm:^1.11.0, @backstage/catalog-client@npm:^1.12.1, @backstage/catalog-client@npm:^1.9.1":
- version: 1.12.1
- resolution: "@backstage/catalog-client@npm:1.12.1"
+"@backstage/catalog-client@npm:^1.10.0, @backstage/catalog-client@npm:^1.11.0, @backstage/catalog-client@npm:^1.12.1, @backstage/catalog-client@npm:^1.7.1, @backstage/catalog-client@npm:^1.9.1":
+ version: 1.13.0
+ resolution: "@backstage/catalog-client@npm:1.13.0"
dependencies:
"@backstage/catalog-model": "npm:^1.7.6"
"@backstage/errors": "npm:^1.2.7"
+ "@backstage/filter-predicates": "npm:^0.1.0"
cross-fetch: "npm:^4.0.0"
+ lodash: "npm:^4.17.21"
uri-template: "npm:^2.0.0"
- checksum: 10/f8963a68150e3aa7001128c9ee73d7a022260b69aa08902c8f9a05861797609bebdb7a98ded1844c3e2bd96298e0673f21a0d0125d8cbbd85110cbaa52efee90
+ checksum: 10/a89ef429d573e8eb8b8e5aef0ed0004e7a00c1c46567710f4ef436508fe1a9bc818cd6f5c77f8d055663cecf33ccc6c0dbcfd8b9b39f591ce0fb0d34a73dfa41
languageName: node
linkType: hard
@@ -2108,23 +2225,23 @@ __metadata:
languageName: node
linkType: hard
-"@backstage/cli-common@npm:^0.1.14, @backstage/cli-common@npm:^0.1.16, @backstage/cli-common@npm:^0.1.17":
- version: 0.1.17
- resolution: "@backstage/cli-common@npm:0.1.17"
+"@backstage/cli-common@npm:^0.1.14, @backstage/cli-common@npm:^0.1.15, @backstage/cli-common@npm:^0.1.17, @backstage/cli-common@npm:^0.1.18":
+ version: 0.1.18
+ resolution: "@backstage/cli-common@npm:0.1.18"
dependencies:
"@backstage/errors": "npm:^1.2.7"
cross-spawn: "npm:^7.0.3"
global-agent: "npm:^3.0.0"
undici: "npm:^7.2.3"
- checksum: 10/e5b1d87548c739012554bb68f5bcd84239f8692bbce3e79a46299cd70308ab144615be9d3ad96c78d4796eb52faa8d50f09226d3d61411c05251d4d0d24b7e7f
+ checksum: 10/2ed0c51bfc7a24d09a2c5fdb0e9b715f654e1ec5b6f6d528c457dad96ad57dfc57840292712dac29a9af206bb4f9d3cefbe311200f5708f9587386b00897e5b0
languageName: node
linkType: hard
-"@backstage/cli-node@npm:^0.2.13, @backstage/cli-node@npm:^0.2.17":
- version: 0.2.17
- resolution: "@backstage/cli-node@npm:0.2.17"
+"@backstage/cli-node@npm:^0.2.10, @backstage/cli-node@npm:^0.2.13, @backstage/cli-node@npm:^0.2.17":
+ version: 0.2.18
+ resolution: "@backstage/cli-node@npm:0.2.18"
dependencies:
- "@backstage/cli-common": "npm:^0.1.17"
+ "@backstage/cli-common": "npm:^0.1.18"
"@backstage/errors": "npm:^1.2.7"
"@backstage/types": "npm:^1.2.2"
"@manypkg/get-packages": "npm:^1.1.3"
@@ -2132,7 +2249,7 @@ __metadata:
fs-extra: "npm:^11.2.0"
semver: "npm:^7.5.3"
zod: "npm:^3.25.76"
- checksum: 10/2bcce77ad5c5c34cfd1380a7fa5b3f01b0e98f4a42b0fc2927f3c41f553b78766d908f656584fc1870107913f92f7c037de0323f13b1132ef000336a560e6b84
+ checksum: 10/fafdacdf29e8aac9607c5dd2de3a4294f2d40acc5e610e6041841d678fb460b4fff74f39824f6f155fc5191f09ed6537e4e2c867bc2708855ce0a4d7ea62e3a3
languageName: node
linkType: hard
@@ -2282,11 +2399,11 @@ __metadata:
languageName: node
linkType: hard
-"@backstage/config-loader@npm:^1.10.0, @backstage/config-loader@npm:^1.10.1, @backstage/config-loader@npm:^1.10.7, @backstage/config-loader@npm:^1.9.1, @backstage/config-loader@npm:^1.9.6":
- version: 1.10.7
- resolution: "@backstage/config-loader@npm:1.10.7"
+"@backstage/config-loader@npm:^1.10.0, @backstage/config-loader@npm:^1.10.1, @backstage/config-loader@npm:^1.10.7, @backstage/config-loader@npm:^1.9.1, @backstage/config-loader@npm:^1.9.2, @backstage/config-loader@npm:^1.9.6":
+ version: 1.10.8
+ resolution: "@backstage/config-loader@npm:1.10.8"
dependencies:
- "@backstage/cli-common": "npm:^0.1.16"
+ "@backstage/cli-common": "npm:^0.1.18"
"@backstage/config": "npm:^1.3.6"
"@backstage/errors": "npm:^1.2.7"
"@backstage/types": "npm:^1.2.2"
@@ -2301,11 +2418,11 @@ __metadata:
minimist: "npm:^1.2.5"
typescript-json-schema: "npm:^0.67.0"
yaml: "npm:^2.0.0"
- checksum: 10/36b73687663a6d380db884955c66f8f8616cf6fbf61469a8b2bc7a6de59f41754aa121cc836c143248354eea672a5cce781eee9c724fe1949033320cbbca99fb
+ checksum: 10/c44e6796ce0a2efe882f7a69f32f9e1f00cd6dca3406f0bd3a96ab22e7f7561b25154cb1cee208b069a97056d6e7728cf00e73f0ba15993ffa1985c75dc604d8
languageName: node
linkType: hard
-"@backstage/config@npm:^1.2.0, @backstage/config@npm:^1.3.2, @backstage/config@npm:^1.3.3, @backstage/config@npm:^1.3.5, @backstage/config@npm:^1.3.6":
+"@backstage/config@npm:^1.2.0, @backstage/config@npm:^1.3.0, @backstage/config@npm:^1.3.2, @backstage/config@npm:^1.3.3, @backstage/config@npm:^1.3.5, @backstage/config@npm:^1.3.6":
version: 1.3.6
resolution: "@backstage/config@npm:1.3.6"
dependencies:
@@ -2672,7 +2789,7 @@ __metadata:
languageName: node
linkType: hard
-"@backstage/errors@npm:^1.2.4, @backstage/errors@npm:^1.2.7":
+"@backstage/errors@npm:^1.2.4, @backstage/errors@npm:^1.2.5, @backstage/errors@npm:^1.2.7":
version: 1.2.7
resolution: "@backstage/errors@npm:1.2.7"
dependencies:
@@ -2692,6 +2809,19 @@ __metadata:
languageName: node
linkType: hard
+"@backstage/filter-predicates@npm:^0.1.0":
+ version: 0.1.0
+ resolution: "@backstage/filter-predicates@npm:0.1.0"
+ dependencies:
+ "@backstage/config": "npm:^1.3.6"
+ "@backstage/errors": "npm:^1.2.7"
+ "@backstage/types": "npm:^1.2.2"
+ zod: "npm:^3.25.76"
+ zod-validation-error: "npm:^4.0.2"
+ checksum: 10/82bd6dde6615e48a7152fbdb6b3d2fa64b574864edd5d9e00b52922e120237c42822afc601a693c81af28bed143d2b1234854dd20bfcd5a944b869a4e09564e7
+ languageName: node
+ linkType: hard
+
"@backstage/frontend-app-api@npm:^0.14.1":
version: 0.14.1
resolution: "@backstage/frontend-app-api@npm:0.14.1"
@@ -2860,9 +2990,9 @@ __metadata:
languageName: node
linkType: hard
-"@backstage/integration-aws-node@npm:^0.1.12, @backstage/integration-aws-node@npm:^0.1.15, @backstage/integration-aws-node@npm:^0.1.16, @backstage/integration-aws-node@npm:^0.1.19":
- version: 0.1.19
- resolution: "@backstage/integration-aws-node@npm:0.1.19"
+"@backstage/integration-aws-node@npm:^0.1.12, @backstage/integration-aws-node@npm:^0.1.13, @backstage/integration-aws-node@npm:^0.1.15, @backstage/integration-aws-node@npm:^0.1.16, @backstage/integration-aws-node@npm:^0.1.19":
+ version: 0.1.20
+ resolution: "@backstage/integration-aws-node@npm:0.1.20"
dependencies:
"@aws-sdk/client-sts": "npm:^3.350.0"
"@aws-sdk/credential-provider-node": "npm:^3.350.0"
@@ -2871,7 +3001,7 @@ __metadata:
"@aws-sdk/util-arn-parser": "npm:^3.310.0"
"@backstage/config": "npm:^1.3.6"
"@backstage/errors": "npm:^1.2.7"
- checksum: 10/b6a55ef787d88dd0ee41b5f4184508789cb3fdda54a5aaebba0db6b48604718666cc61969b6b41a3ddb6fedd38f7acef3884b0fc37471b8a3bd646925700f80d
+ checksum: 10/3768285e34542f266d817c916502c82e35f16cb131190f8d990692b5b7e94591e1881ded8a9b1696ee9e7f13a7c5d2cbd087f4c855d301d1891951774b52daf7
languageName: node
linkType: hard
@@ -2896,9 +3026,9 @@ __metadata:
languageName: node
linkType: hard
-"@backstage/integration@npm:^1.15.0, @backstage/integration@npm:^1.16.1, @backstage/integration@npm:^1.16.2, @backstage/integration@npm:^1.16.3, @backstage/integration@npm:^1.17.0, @backstage/integration@npm:^1.18.1, @backstage/integration@npm:^1.18.2, @backstage/integration@npm:^1.19.2":
- version: 1.19.2
- resolution: "@backstage/integration@npm:1.19.2"
+"@backstage/integration@npm:^1.15.0, @backstage/integration@npm:^1.15.2, @backstage/integration@npm:^1.16.1, @backstage/integration@npm:^1.16.2, @backstage/integration@npm:^1.16.3, @backstage/integration@npm:^1.17.0, @backstage/integration@npm:^1.18.1, @backstage/integration@npm:^1.18.2, @backstage/integration@npm:^1.19.2":
+ version: 1.20.0
+ resolution: "@backstage/integration@npm:1.20.0"
dependencies:
"@azure/identity": "npm:^4.0.0"
"@azure/storage-blob": "npm:^12.5.0"
@@ -2910,7 +3040,7 @@ __metadata:
git-url-parse: "npm:^15.0.0"
lodash: "npm:^4.17.21"
luxon: "npm:^3.0.0"
- checksum: 10/20114acea62636de02c52bdf2e7e6a5cc426bbdb23f343932bc60baed831fc299b3b53ce6e45687027cf5ca7265c67d3e9dee23dd03791948c0729538513c232
+ checksum: 10/c790383e5c38fde4aa80dd9e39e762b059b17af04a7175f96c62b1fcd705a59da6092238cbbcd7da1d91b44e80e6d82ed52d228b0bb3eb98936f292d75eb7aae
languageName: node
linkType: hard
@@ -3384,7 +3514,7 @@ __metadata:
languageName: node
linkType: hard
-"@backstage/plugin-auth-node@npm:^0.5.2":
+"@backstage/plugin-auth-node@npm:^0.5.2, @backstage/plugin-auth-node@npm:^0.5.3, @backstage/plugin-auth-node@npm:^0.5.4":
version: 0.5.6
resolution: "@backstage/plugin-auth-node@npm:0.5.6"
dependencies:
@@ -3755,11 +3885,30 @@ __metadata:
languageName: node
linkType: hard
-"@backstage/plugin-events-node@npm:^0.4.10, @backstage/plugin-events-node@npm:^0.4.11, @backstage/plugin-events-node@npm:^0.4.18, @backstage/plugin-events-node@npm:^0.4.9":
- version: 0.4.18
- resolution: "@backstage/plugin-events-node@npm:0.4.18"
+"@backstage/plugin-events-backend@npm:^0.5.0":
+ version: 0.5.11
+ resolution: "@backstage/plugin-events-backend@npm:0.5.11"
dependencies:
- "@backstage/backend-plugin-api": "npm:^1.6.0"
+ "@backstage/backend-openapi-utils": "npm:^0.6.6"
+ "@backstage/backend-plugin-api": "npm:^1.7.0"
+ "@backstage/config": "npm:^1.3.6"
+ "@backstage/errors": "npm:^1.2.7"
+ "@backstage/plugin-events-node": "npm:^0.4.19"
+ "@backstage/types": "npm:^1.2.2"
+ "@types/express": "npm:^4.17.6"
+ content-type: "npm:^1.0.5"
+ express: "npm:^4.22.0"
+ express-promise-router: "npm:^4.1.0"
+ knex: "npm:^3.0.0"
+ checksum: 10/1db5efaec0308a18b727162c38506ef3905b210f6730f2c0a6b8fdf967b79b1a5d516f772f3ae4abeacc7f213b02e98335c032e9b3e6fcc43b1b03587fb677c8
+ languageName: node
+ linkType: hard
+
+"@backstage/plugin-events-node@npm:^0.4.10, @backstage/plugin-events-node@npm:^0.4.11, @backstage/plugin-events-node@npm:^0.4.18, @backstage/plugin-events-node@npm:^0.4.19, @backstage/plugin-events-node@npm:^0.4.5, @backstage/plugin-events-node@npm:^0.4.9":
+ version: 0.4.19
+ resolution: "@backstage/plugin-events-node@npm:0.4.19"
+ dependencies:
+ "@backstage/backend-plugin-api": "npm:^1.7.0"
"@backstage/errors": "npm:^1.2.7"
"@backstage/types": "npm:^1.2.2"
"@types/content-type": "npm:^1.1.8"
@@ -3768,7 +3917,7 @@ __metadata:
cross-fetch: "npm:^4.0.0"
express: "npm:^4.22.0"
uri-template: "npm:^2.0.0"
- checksum: 10/214f62c4d49fba4303bd391874cc784d30a4e198bd193a121445cd937a33f287cbdc477239d28624310c897d3a30ed405ab478089171d43eb71bd1181b202058
+ checksum: 10/bc54ef476d30aa2de09a4efb7bd5d2bdc641d049a9d8ffca8e51710417dea8c21ec99cad83642c296eeef01055b744197f13b516baac3d03f5d935e2ac1906e1
languageName: node
linkType: hard
@@ -3854,6 +4003,28 @@ __metadata:
languageName: node
linkType: hard
+"@backstage/plugin-permission-backend@npm:^0.5.50, @backstage/plugin-permission-backend@npm:^0.5.53":
+ version: 0.5.55
+ resolution: "@backstage/plugin-permission-backend@npm:0.5.55"
+ dependencies:
+ "@backstage/backend-common": "npm:^0.25.0"
+ "@backstage/backend-plugin-api": "npm:^1.2.1"
+ "@backstage/config": "npm:^1.3.2"
+ "@backstage/errors": "npm:^1.2.7"
+ "@backstage/plugin-auth-node": "npm:^0.6.1"
+ "@backstage/plugin-permission-common": "npm:^0.8.4"
+ "@backstage/plugin-permission-node": "npm:^0.9.0"
+ "@types/express": "npm:^4.17.6"
+ dataloader: "npm:^2.0.0"
+ express: "npm:^4.17.1"
+ express-promise-router: "npm:^4.1.0"
+ lodash: "npm:^4.17.21"
+ yn: "npm:^4.0.0"
+ zod: "npm:^3.22.4"
+ checksum: 10/6a1bf0268cfeb2b80b603eb292e207cb1b572cc238d6dcff21e420dbab9c124c88c2896bb40afcff6395939ef9c0cfc10f5800bc05873a4a035e6358ba75abbc
+ languageName: node
+ linkType: hard
+
"@backstage/plugin-permission-common@npm:^0.8.1, @backstage/plugin-permission-common@npm:^0.8.4":
version: 0.8.4
resolution: "@backstage/plugin-permission-common@npm:0.8.4"
@@ -3902,7 +4073,7 @@ __metadata:
languageName: node
linkType: hard
-"@backstage/plugin-permission-node@npm:^0.8.8":
+"@backstage/plugin-permission-node@npm:^0.8.4, @backstage/plugin-permission-node@npm:^0.8.5, @backstage/plugin-permission-node@npm:^0.8.7, @backstage/plugin-permission-node@npm:^0.8.8":
version: 0.8.8
resolution: "@backstage/plugin-permission-node@npm:0.8.8"
dependencies:
@@ -4914,7 +5085,7 @@ __metadata:
languageName: node
linkType: hard
-"@backstage/types@npm:^1.1.1, @backstage/types@npm:^1.2.1, @backstage/types@npm:^1.2.2":
+"@backstage/types@npm:^1.1.1, @backstage/types@npm:^1.2.0, @backstage/types@npm:^1.2.1, @backstage/types@npm:^1.2.2":
version: 1.2.2
resolution: "@backstage/types@npm:1.2.2"
checksum: 10/813129ae2f4be2765b54a16457955c8bbeb7cc6685bc2cae8b981ae7010353d9cd1110acf846f5c23cf7fbbb6bee6d56b629d5f59933247bb529f4816218c1e7
@@ -4982,6 +5153,15 @@ __metadata:
languageName: node
linkType: hard
+"@casbin/expression-eval@npm:^5.3.0":
+ version: 5.3.0
+ resolution: "@casbin/expression-eval@npm:5.3.0"
+ dependencies:
+ jsep: "npm:^0.3.0"
+ checksum: 10/df924541a02331c547eb5fdcb4291db9aa3d4b224467d64821603b036ea595bd71ad0d18aec00ce60fe29c6713b67038d7c33484ec01368be7799c8d81593b45
+ languageName: node
+ linkType: hard
+
"@changesets/apply-release-plan@npm:^7.0.14":
version: 7.0.14
resolution: "@changesets/apply-release-plan@npm:7.0.14"
@@ -5407,7 +5587,7 @@ __metadata:
languageName: node
linkType: hard
-"@dagrejs/graphlib@npm:2.2.4":
+"@dagrejs/graphlib@npm:2.2.4, @dagrejs/graphlib@npm:^2.1.13":
version: 2.2.4
resolution: "@dagrejs/graphlib@npm:2.2.4"
checksum: 10/1fc5393525a3d666284ca740867d082768bc87ff61f5f181eb5c1a73c1a6e328ad23581f7415c81df2614171b8a4b4a8e6a417eefd7f9fca74a4a625ec3aa848
@@ -6828,6 +7008,15 @@ __metadata:
languageName: node
linkType: hard
+"@janus-idp/backstage-plugin-audit-log-node@npm:^1.7.1":
+ version: 1.8.1
+ resolution: "@janus-idp/backstage-plugin-audit-log-node@npm:1.8.1"
+ dependencies:
+ lodash: "npm:^4.17.21"
+ checksum: 10/7ac4510f104a8dea94bd135ee97824cb98531a4721dbfbd400883c1feb78878fca3c1042898d6a724540a689a19cc592e1023d26ae6fbb585045aac212ac70fe
+ languageName: node
+ linkType: hard
+
"@janus-idp/shared-react@npm:^2.13.1":
version: 2.18.0
resolution: "@janus-idp/shared-react@npm:2.18.0"
@@ -11793,9 +11982,13 @@ __metadata:
"@backstage/cli": "npm:^0.35.2"
"@backstage/errors": "npm:^1.2.7"
"@backstage/plugin-catalog-node": "npm:^1.20.1"
+ "@backstage/plugin-permission-common": "npm:^0.8.4"
+ "@backstage/plugin-permission-node": "npm:^0.8.7"
"@backstage/types": "npm:^1.2.2"
+ "@red-hat-developer-hub/backstage-plugin-dcm-common": "workspace:^"
"@types/express": "npm:^4.17.6"
"@types/supertest": "npm:^2.0.12"
+ assert: "npm:^2.1.0"
express: "npm:^4.17.1"
express-promise-router: "npm:^4.1.0"
supertest: "npm:^6.2.4"
@@ -11803,12 +11996,13 @@ __metadata:
languageName: unknown
linkType: soft
-"@red-hat-developer-hub/backstage-plugin-dcm-common@workspace:plugins/dcm-common":
+"@red-hat-developer-hub/backstage-plugin-dcm-common@workspace:^, @red-hat-developer-hub/backstage-plugin-dcm-common@workspace:plugins/dcm-common":
version: 0.0.0-use.local
resolution: "@red-hat-developer-hub/backstage-plugin-dcm-common@workspace:plugins/dcm-common"
dependencies:
"@backstage/cli": "npm:^0.35.2"
"@backstage/core-plugin-api": "npm:^1.12.2"
+ "@backstage/plugin-permission-common": "npm:^0.8.4"
languageName: unknown
linkType: soft
@@ -13246,6 +13440,13 @@ __metadata:
languageName: node
linkType: hard
+"@sqltools/formatter@npm:^1.2.5":
+ version: 1.2.5
+ resolution: "@sqltools/formatter@npm:1.2.5"
+ checksum: 10/ce9335025cd033f8f1ac997d290af22d5a5cdbd5f04cbf0fa18d5388871e980a4fc67875037821799b356032f851732dee1017b2ee7de84f5c2a2b8bfd5604f5
+ languageName: node
+ linkType: hard
+
"@stoplight/better-ajv-errors@npm:1.0.3":
version: 1.0.3
resolution: "@stoplight/better-ajv-errors@npm:1.0.3"
@@ -16190,6 +16391,13 @@ __metadata:
languageName: node
linkType: hard
+"ansis@npm:^4.2.0":
+ version: 4.2.0
+ resolution: "ansis@npm:4.2.0"
+ checksum: 10/493e15fad267bd6e3e275d6886c3b3c96a075784d9eae3e16d16383d488e94cc3deb1b357e1246f572599767360548ef9e5b7eab9b72e4ee3f7bad9ce6bc8797
+ languageName: node
+ linkType: hard
+
"any-promise@npm:^1.0.0":
version: 1.3.0
resolution: "any-promise@npm:1.3.0"
@@ -16214,6 +16422,13 @@ __metadata:
languageName: node
linkType: hard
+"app-root-path@npm:^3.1.0":
+ version: 3.1.0
+ resolution: "app-root-path@npm:3.1.0"
+ checksum: 10/b4cdab5f7e51ec43fa04c97eca2adedf8e18d6c3dd21cd775b70457c5e71f0441c692a49dcceb426f192640b7393dcd41d85c36ef98ecb7c785a53159c912def
+ languageName: node
+ linkType: hard
+
"app@workspace:packages/app":
version: 0.0.0-use.local
resolution: "app@workspace:packages/app"
@@ -16546,7 +16761,7 @@ __metadata:
languageName: node
linkType: hard
-"assert@npm:^2.0.0":
+"assert@npm:^2.0.0, assert@npm:^2.1.0":
version: 2.1.0
resolution: "assert@npm:2.1.0"
dependencies:
@@ -16695,6 +16910,13 @@ __metadata:
languageName: node
linkType: hard
+"await-lock@npm:^2.0.1":
+ version: 2.2.2
+ resolution: "await-lock@npm:2.2.2"
+ checksum: 10/feb11f36768a8545879ed2d214b46aae484e6564ffa466af9212d5782897203770795cae01f813de04a46f66c0b8ee6bc690a0c435b04e00cad5a18ef0842e25
+ languageName: node
+ linkType: hard
+
"aws-sign2@npm:~0.7.0":
version: 0.7.0
resolution: "aws-sign2@npm:0.7.0"
@@ -16813,6 +17035,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "backend@workspace:packages/backend"
dependencies:
+ "@backstage-community/plugin-rbac-backend": "npm:5.2.6"
"@backstage/backend-defaults": "npm:^0.15.1"
"@backstage/cli": "npm:^0.35.2"
"@backstage/config": "npm:^1.3.2"
@@ -16822,6 +17045,8 @@ __metadata:
"@backstage/plugin-catalog-backend": "npm:^1.30.0"
"@backstage/plugin-catalog-backend-module-logs": "npm:^0.1.8"
"@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "npm:^0.2.4"
+ "@backstage/plugin-events-backend": "npm:^0.5.0"
+ "@backstage/plugin-permission-backend": "npm:^0.5.53"
"@backstage/plugin-proxy-backend": "npm:^0.5.10"
"@backstage/plugin-scaffolder-backend": "npm:^1.29.0"
"@backstage/plugin-search-backend": "npm:^1.8.1"
@@ -17646,6 +17871,19 @@ __metadata:
languageName: node
linkType: hard
+"casbin@npm:^5.27.0, casbin@npm:^5.27.1":
+ version: 5.49.0
+ resolution: "casbin@npm:5.49.0"
+ dependencies:
+ "@casbin/expression-eval": "npm:^5.3.0"
+ await-lock: "npm:^2.0.1"
+ buffer: "npm:^6.0.3"
+ csv-parse: "npm:^5.5.6"
+ minimatch: "npm:^10.2.1"
+ checksum: 10/a608363d63f35a2284161951ef41503651107c3f8877425b412ee7336d127801ad38ea2de204f30c6f58c0ab1a192a2661410a491e2708281bd564de550e8018
+ languageName: node
+ linkType: hard
+
"caseless@npm:~0.12.0":
version: 0.12.0
resolution: "caseless@npm:0.12.0"
@@ -18990,6 +19228,13 @@ __metadata:
languageName: node
linkType: hard
+"csv-parse@npm:^5.5.5, csv-parse@npm:^5.5.6":
+ version: 5.6.0
+ resolution: "csv-parse@npm:5.6.0"
+ checksum: 10/4c82e11f50ae0ccbac2aed716ef2502d0468bf96552083561db789fc0258ee4bb0a30106fcfb2684f153cb4042f0413e0eac3645d5466874803b7ccdeba67ac8
+ languageName: node
+ linkType: hard
+
"ctrlc-windows@npm:^2.1.0":
version: 2.2.0
resolution: "ctrlc-windows@npm:2.2.0"
@@ -19208,6 +19453,13 @@ __metadata:
languageName: node
linkType: hard
+"dayjs@npm:^1.11.19":
+ version: 1.11.19
+ resolution: "dayjs@npm:1.11.19"
+ checksum: 10/185b820d68492b83a3ce2b8ddc7543034edc1dfd1423183f6ae4707b29929a3cc56503a81826309279f9084680c15966b99456e74cf41f7d1f6a2f98f9c7196f
+ languageName: node
+ linkType: hard
+
"debounce-promise@npm:^3.1.2":
version: 3.1.2
resolution: "debounce-promise@npm:3.1.2"
@@ -19289,6 +19541,18 @@ __metadata:
languageName: node
linkType: hard
+"dedent@npm:^1.7.0":
+ version: 1.7.1
+ resolution: "dedent@npm:1.7.1"
+ peerDependencies:
+ babel-plugin-macros: ^3.1.0
+ peerDependenciesMeta:
+ babel-plugin-macros:
+ optional: true
+ checksum: 10/78785ef592e37e0b1ca7a7a5964c8f3dee1abdff46c5bb49864168579c122328f6bb55c769bc7e005046a7381c3372d3859f0f78ab083950fa146e1c24873f4f
+ languageName: node
+ linkType: hard
+
"deep-equal@npm:^2.0.5":
version: 2.2.3
resolution: "deep-equal@npm:2.2.3"
@@ -19802,6 +20066,13 @@ __metadata:
languageName: node
linkType: hard
+"dotenv@npm:^16.6.1":
+ version: 16.6.1
+ resolution: "dotenv@npm:16.6.1"
+ checksum: 10/1d1897144344447ffe62aa1a6d664f4cd2e0784e0aff787eeeec1940ded32f8e4b5b506d665134fc87157baa086fce07ec6383970a2b6d2e7985beaed6a4cc14
+ languageName: node
+ linkType: hard
+
"drange@npm:^1.0.2":
version: 1.1.1
resolution: "drange@npm:1.1.1"
@@ -20900,7 +21171,7 @@ __metadata:
languageName: node
linkType: hard
-"express@npm:^4.14.0, express@npm:^4.17.1, express@npm:^4.22.0, express@npm:^4.22.1":
+"express@npm:^4.14.0, express@npm:^4.17.1, express@npm:^4.18.2, express@npm:^4.22.0, express@npm:^4.22.1":
version: 4.22.1
resolution: "express@npm:4.22.1"
dependencies:
@@ -22015,7 +22286,7 @@ __metadata:
languageName: node
linkType: hard
-"glob@npm:^10.0.0, glob@npm:^10.4.1":
+"glob@npm:^10.0.0, glob@npm:^10.4.1, glob@npm:^10.5.0":
version: 10.5.0
resolution: "glob@npm:10.5.0"
dependencies:
@@ -24379,6 +24650,13 @@ __metadata:
languageName: node
linkType: hard
+"jsep@npm:^0.3.0":
+ version: 0.3.5
+ resolution: "jsep@npm:0.3.5"
+ checksum: 10/cfdb0cf6553dc2febc85e2741667f81fdd1d7b062207c8fbf03dea399f29c7c3cd448f3147e96d1b2082a399e8a419a5462d5c79569efb18dba0eb3596755e50
+ languageName: node
+ linkType: hard
+
"jsep@npm:^1.2.0, jsep@npm:^1.3.6, jsep@npm:^1.4.0":
version: 1.4.0
resolution: "jsep@npm:1.4.0"
@@ -30725,13 +31003,20 @@ __metadata:
languageName: node
linkType: hard
-"reflect-metadata@npm:0.2.2":
+"reflect-metadata@npm:0.2.2, reflect-metadata@npm:^0.2.2":
version: 0.2.2
resolution: "reflect-metadata@npm:0.2.2"
checksum: 10/1c93f9ac790fea1c852fde80c91b2760420069f4862f28e6fae0c00c6937a56508716b0ed2419ab02869dd488d123c4ab92d062ae84e8739ea7417fae10c4745
languageName: node
linkType: hard
+"reflect-metadata@npm:^0.1.13":
+ version: 0.1.14
+ resolution: "reflect-metadata@npm:0.1.14"
+ checksum: 10/fcab9c17ec3b9fea0e2f748c2129aceb57c24af6d8d13842b8a77c8c79dde727d7456ce293e76e8d7b267d1dbf93eea4c5b3c9101299a789a075824f2e40f1ee
+ languageName: node
+ linkType: hard
+
"reflect.getprototypeof@npm:^1.0.6, reflect.getprototypeof@npm:^1.0.9":
version: 1.0.10
resolution: "reflect.getprototypeof@npm:1.0.10"
@@ -32198,6 +32483,13 @@ __metadata:
languageName: node
linkType: hard
+"sql-highlight@npm:^6.1.0":
+ version: 6.1.0
+ resolution: "sql-highlight@npm:6.1.0"
+ checksum: 10/6cd92e7ca3046563f3daf2086adc4c2e1ce43784e59827a12bb9e569bf915eace1d800713f4d2798fc7d475f64852bf08001dca8dd409e9895ba5e0e170b94ff
+ languageName: node
+ linkType: hard
+
"ssh-remote-port-forward@npm:^1.0.4":
version: 1.0.4
resolution: "ssh-remote-port-forward@npm:1.0.4"
@@ -33843,6 +34135,94 @@ __metadata:
languageName: node
linkType: hard
+"typeorm-adapter@npm:^1.6.1":
+ version: 1.9.0
+ resolution: "typeorm-adapter@npm:1.9.0"
+ dependencies:
+ casbin: "npm:^5.27.0"
+ reflect-metadata: "npm:^0.1.13"
+ typeorm: "npm:^0.3.17"
+ checksum: 10/6c96409508ddd792ca71bd561f54c5f75249093bb301ee9eb451fa2e6d21dbb49aff396486538e7b1e06663d99deb9070f2ecd2170852ab69a2fd3ec9fd68ab8
+ languageName: node
+ linkType: hard
+
+"typeorm@npm:^0.3.17":
+ version: 0.3.28
+ resolution: "typeorm@npm:0.3.28"
+ dependencies:
+ "@sqltools/formatter": "npm:^1.2.5"
+ ansis: "npm:^4.2.0"
+ app-root-path: "npm:^3.1.0"
+ buffer: "npm:^6.0.3"
+ dayjs: "npm:^1.11.19"
+ debug: "npm:^4.4.3"
+ dedent: "npm:^1.7.0"
+ dotenv: "npm:^16.6.1"
+ glob: "npm:^10.5.0"
+ reflect-metadata: "npm:^0.2.2"
+ sha.js: "npm:^2.4.12"
+ sql-highlight: "npm:^6.1.0"
+ tslib: "npm:^2.8.1"
+ uuid: "npm:^11.1.0"
+ yargs: "npm:^17.7.2"
+ peerDependencies:
+ "@google-cloud/spanner": ^5.18.0 || ^6.0.0 || ^7.0.0 || ^8.0.0
+ "@sap/hana-client": ^2.14.22
+ better-sqlite3: ^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0 || ^12.0.0
+ ioredis: ^5.0.4
+ mongodb: ^5.8.0 || ^6.0.0
+ mssql: ^9.1.1 || ^10.0.0 || ^11.0.0 || ^12.0.0
+ mysql2: ^2.2.5 || ^3.0.1
+ oracledb: ^6.3.0
+ pg: ^8.5.1
+ pg-native: ^3.0.0
+ pg-query-stream: ^4.0.0
+ redis: ^3.1.1 || ^4.0.0 || ^5.0.14
+ sql.js: ^1.4.0
+ sqlite3: ^5.0.3
+ ts-node: ^10.7.0
+ typeorm-aurora-data-api-driver: ^2.0.0 || ^3.0.0
+ peerDependenciesMeta:
+ "@google-cloud/spanner":
+ optional: true
+ "@sap/hana-client":
+ optional: true
+ better-sqlite3:
+ optional: true
+ ioredis:
+ optional: true
+ mongodb:
+ optional: true
+ mssql:
+ optional: true
+ mysql2:
+ optional: true
+ oracledb:
+ optional: true
+ pg:
+ optional: true
+ pg-native:
+ optional: true
+ pg-query-stream:
+ optional: true
+ redis:
+ optional: true
+ sql.js:
+ optional: true
+ sqlite3:
+ optional: true
+ ts-node:
+ optional: true
+ typeorm-aurora-data-api-driver:
+ optional: true
+ bin:
+ typeorm: cli.js
+ typeorm-ts-node-commonjs: cli-ts-node-commonjs.js
+ typeorm-ts-node-esm: cli-ts-node-esm.js
+ checksum: 10/4eb217d65414291fb226267d903d123a16a9eb090b4e8f8da2dfe2f64680265823bea3712d363d31fe96c6dc2cef00edd545f42e63ec65b8a1899a1b455f757b
+ languageName: node
+ linkType: hard
+
"types-ramda@npm:^0.30.1":
version: 0.30.1
resolution: "types-ramda@npm:0.30.1"
@@ -34476,7 +34856,7 @@ __metadata:
languageName: node
linkType: hard
-"uuid@npm:^11.0.0, uuid@npm:^11.0.2":
+"uuid@npm:^11.0.0, uuid@npm:^11.0.2, uuid@npm:^11.1.0":
version: 11.1.0
resolution: "uuid@npm:11.1.0"
bin: