Merge branch 'backstage:master' into master
This commit is contained in:
@@ -69,6 +69,10 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
||||
|
||||
# From here on we use the least-privileged `node` user to run the backend.
|
||||
USER node
|
||||
|
||||
# This should create the app dir as `node`.
|
||||
# If it is instead created as `root` then the `tar` command below will fail: `can't create directory 'packages/': Permission denied`.
|
||||
# If this occurs, then ensure BuildKit is enabled (`DOCKER_BUILDKIT=1`) so the app dir is correctly created as `node`.
|
||||
WORKDIR /app
|
||||
|
||||
# This switches many Node.js dependencies to production mode.
|
||||
@@ -206,6 +210,10 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
||||
|
||||
# From here on we use the least-privileged `node` user to run the backend.
|
||||
USER node
|
||||
|
||||
# This should create the app dir as `node`.
|
||||
# If it is instead created as `root` then the `tar` command below will fail: `can't create directory 'packages/': Permission denied`.
|
||||
# If this occurs, then ensure BuildKit is enabled (`DOCKER_BUILDKIT=1`) so the app dir is correctly created as `node`.
|
||||
WORKDIR /app
|
||||
|
||||
# Copy the install dependencies from the build stage and context
|
||||
|
||||
@@ -110,7 +110,7 @@ metadata:
|
||||
backstage.io/edit-url: https://github.com/my-org/catalog/edit/master/my-service.jsonnet
|
||||
```
|
||||
|
||||
These annotations allow customising links from the catalog pages. The view URL
|
||||
These annotations allow customizing links from the catalog pages. The view URL
|
||||
should point to the canonical metadata YAML that governs this entity. The edit
|
||||
URL should point to the source file for the metadata. In the example above,
|
||||
`my-org` generates its catalog data from Jsonnet files in a monorepo, so the
|
||||
@@ -159,11 +159,11 @@ metadata:
|
||||
github.com/project-slug: backstage/backstage
|
||||
```
|
||||
|
||||
The value of this annotation is the so-called slug that identifies a project on
|
||||
The value of this annotation is the so-called slug that identifies a repository on
|
||||
[GitHub](https://github.com) (either the public one, or a private GitHub
|
||||
Enterprise installation) that is related to this entity. It is on the format
|
||||
`<organization>/<project>`, and is the same as can be seen in the URL location
|
||||
bar of the browser when viewing that project.
|
||||
`<organization or owner>/<repository>`, and is the same as can be seen in the URL location
|
||||
bar of the browser when viewing that repository.
|
||||
|
||||
Specifying this annotation will enable GitHub related features in Backstage for
|
||||
that entity.
|
||||
|
||||
@@ -81,8 +81,7 @@ import {
|
||||
scaffolderPlugin,
|
||||
createScaffolderFieldExtension,
|
||||
} from '@backstage/plugin-scaffolder';
|
||||
import { MyCustomExtension } from './MyCustomExtension';
|
||||
import { myCustomValidation } from './validation';
|
||||
import { MyCustomExtension, myCustomValidation } from './MyCustomExtension';
|
||||
|
||||
export const MyCustomFieldExtension = scaffolderPlugin.provide(
|
||||
createScaffolderFieldExtension({
|
||||
|
||||
@@ -30,14 +30,14 @@ And then add the entity provider to your catalog builder:
|
||||
|
||||
```diff
|
||||
// In packages/backend/src/plugins/catalog.ts
|
||||
+ import { GitHubEntityProvider } from '@backstage/plugin-catalog-backend-module-github';
|
||||
+ import { GithubEntityProvider } from '@backstage/plugin-catalog-backend-module-github';
|
||||
|
||||
export default async function createPlugin(
|
||||
env: PluginEnvironment,
|
||||
): Promise<Router> {
|
||||
const builder = await CatalogBuilder.create(env);
|
||||
+ builder.addEntityProvider(
|
||||
+ GitHubEntityProvider.fromConfig(env.config, {
|
||||
+ GithubEntityProvider.fromConfig(env.config, {
|
||||
+ logger: env.logger,
|
||||
+ // optional: alternatively, use scheduler with schedule defined in app-config.yaml
|
||||
+ schedule: env.scheduler.createScheduledTaskRunner({
|
||||
|
||||
@@ -14,12 +14,18 @@ Plugins should export a rule factory that provides type-safety that ensures comp
|
||||
import type { Entity } from '@backstage/plugin-catalog-model';
|
||||
import { createCatalogPermissionRule } from '@backstage/plugin-catalog-backend/alpha';
|
||||
import { createConditionFactory } from '@backstage/plugin-permission-node';
|
||||
import { z } from 'zod';
|
||||
|
||||
export const isInSystemRule = createCatalogPermissionRule({
|
||||
name: 'IS_IN_SYSTEM',
|
||||
description: 'Checks if an entity is part of the system provided',
|
||||
resourceType: 'catalog-entity',
|
||||
apply: (resource: Entity, systemRef: string) => {
|
||||
paramsSchema: z.object({
|
||||
systemRef: z
|
||||
.string()
|
||||
.describe('SystemRef to check the resource is part of'),
|
||||
}),
|
||||
apply: (resource: Entity, { systemRef }) => {
|
||||
if (!resource.relations) {
|
||||
return false;
|
||||
}
|
||||
@@ -28,7 +34,7 @@ export const isInSystemRule = createCatalogPermissionRule({
|
||||
.filter(relation => relation.type === 'partOf')
|
||||
.some(relation => relation.targetRef === systemRef);
|
||||
},
|
||||
toQuery: (systemRef: string) => ({
|
||||
toQuery: ({ systemRef }) => ({
|
||||
key: 'relations.partOf',
|
||||
values: [systemRef],
|
||||
}),
|
||||
@@ -85,14 +91,14 @@ class TestPermissionPolicy implements PermissionPolicy {
|
||||
if (isResourcePermission(request.permission, 'catalog-entity')) {
|
||||
return createCatalogConditionalDecision(
|
||||
request.permission,
|
||||
- catalogConditions.isEntityOwner(
|
||||
- user?.identity.ownershipEntityRefs ?? [],
|
||||
- ),
|
||||
- catalogConditions.isEntityOwner({
|
||||
- claims: user?.identity.ownershipEntityRefs ?? [],
|
||||
- }),
|
||||
+ {
|
||||
+ anyOf: [
|
||||
+ catalogConditions.isEntityOwner(
|
||||
+ user?.identity.ownershipEntityRefs ?? []
|
||||
+ ),
|
||||
+ catalogConditions.isEntityOwner({
|
||||
+ claims: user?.identity.ownershipEntityRefs ?? []
|
||||
+ }),
|
||||
+ isInSystem('interviewing')
|
||||
+ ]
|
||||
+ }
|
||||
|
||||
@@ -84,6 +84,7 @@ Create a new `plugins/todo-list-backend/src/service/rules.ts` file and append th
|
||||
```typescript
|
||||
import { makeCreatePermissionRule } from '@backstage/plugin-permission-node';
|
||||
import { TODO_LIST_RESOURCE_TYPE } from '@internal/plugin-todo-list-common';
|
||||
import { z } from 'zod';
|
||||
import { Todo, TodoFilter } from './todos';
|
||||
|
||||
export const createTodoListPermissionRule = makeCreatePermissionRule<
|
||||
@@ -95,10 +96,13 @@ export const isOwner = createTodoListPermissionRule({
|
||||
name: 'IS_OWNER',
|
||||
description: 'Should allow only if the todo belongs to the user',
|
||||
resourceType: TODO_LIST_RESOURCE_TYPE,
|
||||
apply: (resource: Todo, userId: string) => {
|
||||
paramsSchema: z.object({
|
||||
userId: z.string().describe('User ID to match on the resource')
|
||||
})
|
||||
apply: (resource: Todo, { userId }) => {
|
||||
return resource.author === userId;
|
||||
},
|
||||
toQuery: (userId: string) => {
|
||||
toQuery: ({ userId }) => {
|
||||
return {
|
||||
property: 'author',
|
||||
values: [userId],
|
||||
@@ -223,7 +227,9 @@ Let's go back to the permission policy's handle function and try to authorize ou
|
||||
+ if (isPermission(request.permission, todoListUpdatePermission)) {
|
||||
+ return createTodoListConditionalDecision(
|
||||
+ request.permission,
|
||||
+ todoListConditions.isOwner(user?.identity.userEntityRef),
|
||||
+ todoListConditions.isOwner({
|
||||
+ userId: user?.identity.userEntityRef ?? '',
|
||||
+ }),
|
||||
+ );
|
||||
+ }
|
||||
+
|
||||
|
||||
@@ -144,7 +144,9 @@ import {
|
||||
+ ) {
|
||||
return createTodoListConditionalDecision(
|
||||
request.permission,
|
||||
todoListConditions.isOwner(user?.identity.userEntityRef),
|
||||
todoListConditions.isOwner({
|
||||
userId: user?.identity.userEntityRef
|
||||
}),
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
@@ -70,9 +70,9 @@ Let's change the policy to the following:
|
||||
- };
|
||||
+ return createCatalogConditionalDecision(
|
||||
+ request.permission,
|
||||
+ catalogConditions.isEntityOwner(
|
||||
+ user?.identity.ownershipEntityRefs ?? [],
|
||||
+ ),
|
||||
+ catalogConditions.isEntityOwner({
|
||||
+ claims: user?.identity.ownershipEntityRefs ?? [],
|
||||
+ }),
|
||||
+ );
|
||||
}
|
||||
|
||||
@@ -119,9 +119,9 @@ class TestPermissionPolicy implements PermissionPolicy {
|
||||
+ if (isResourcePermission(request.permission, 'catalog-entity')) {
|
||||
return createCatalogConditionalDecision(
|
||||
request.permission,
|
||||
catalogConditions.isEntityOwner(
|
||||
user?.identity.ownershipEntityRefs ?? [],
|
||||
),
|
||||
catalogConditions.isEntityOwner({
|
||||
claims: user?.identity.ownershipEntityRefs ?? [],
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -178,7 +178,7 @@ When migrating over to React Router v6 stable, you might also see browser consol
|
||||
|
||||
```diff
|
||||
- <Navigate key="/" to="catalog" />
|
||||
+ <Route path="/" element={<Navigate to="/catalog" />} />
|
||||
+ <Route path="/" element={<Navigate to="catalog" />} />
|
||||
```
|
||||
|
||||
### `NavLink`
|
||||
|
||||
Reference in New Issue
Block a user