Merge branch 'backstage:master' into integrations/gitlab-url-reader-token
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
---
|
||||
'@backstage/plugin-auth-backend': patch
|
||||
---
|
||||
|
||||
Added the configuration flag `auth.omitIdentityTokenOwnershipClaim` that causes issued user tokens to no longer contain the `ent` claim that represents the ownership references of the user.
|
||||
|
||||
The benefit of this new flag is that issued user tokens will be much smaller in
|
||||
size, but they will no longer be self-contained. This means that any consumers
|
||||
of the token that require access to the ownership claims now need to call the
|
||||
`/api/auth/v1/userinfo` endpoint instead. Within the Backstage ecosystem this is
|
||||
done automatically, as clients will still receive the full set of claims during
|
||||
authentication, while plugin backends will need to use the `UserInfoService`
|
||||
which already calls the user info endpoint if necessary.
|
||||
|
||||
When enabling this flag, it is important that any custom sign-in resolvers directly return the result of the sign-in method. For example, the following would not work:
|
||||
|
||||
```ts
|
||||
const { token } = await ctx.issueToken({
|
||||
claims: { sub: entityRef, ent: [entityRef] },
|
||||
});
|
||||
return { token }; // WARNING: This will not work with the flag enabled
|
||||
```
|
||||
|
||||
Instead, the sign-in resolver should directly return the result:
|
||||
|
||||
```ts
|
||||
return ctx.issueToken({
|
||||
claims: { sub: entityRef, ent: [entityRef] },
|
||||
});
|
||||
```
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/plugin-auth-node': patch
|
||||
---
|
||||
|
||||
Added the `identity` property to `BackstageSignInResult`.
|
||||
|
||||
The `prepareBackstageIdentityResponse` function will now also forward the `identity` to the response if present in the provided sign-in result.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-events-backend-module-github': patch
|
||||
---
|
||||
|
||||
Correct README installation instructions.
|
||||
@@ -0,0 +1,92 @@
|
||||
# This file contains common fields for all issue templates
|
||||
# Each field is identified by its ID, and are synced with the `sync.js` script
|
||||
#
|
||||
# WARNING: After updating this file, run `yarn sync-issue-templates`
|
||||
#
|
||||
|
||||
body:
|
||||
- id: issue-labels
|
||||
type: checkboxes
|
||||
attributes:
|
||||
label: '📜 Issue Labels'
|
||||
options:
|
||||
- label: 'Please familiarize yourself with the issue labels used in this project: [LABELS.md](https://github.com/backstage/backstage/blob/master/LABELS.md)'
|
||||
required: true
|
||||
- id: search-terms
|
||||
type: textarea
|
||||
attributes:
|
||||
label: '🔎 Search Terms'
|
||||
render: plain
|
||||
description: |
|
||||
What search terms did you use when trying to find similar issues?
|
||||
placeholder: |
|
||||
List of keywords you searched for before creating this issue. Write them down here so that others can find this issue more easily and help provide feedback.
|
||||
|
||||
e.g. "catalog github rate limited", "http root service configurer", "scaffolder template include", "entity card title"
|
||||
validations:
|
||||
required: true
|
||||
- id: project-area
|
||||
type: dropdown
|
||||
attributes:
|
||||
label: '🗃️ Project Area'
|
||||
description: Which project area is this issue most closely related to? This will help find an owner for the issue faster.
|
||||
options:
|
||||
- Unknown
|
||||
- Auditor
|
||||
- Auth
|
||||
- Catalog
|
||||
- CLI Tooling
|
||||
- Core Framework
|
||||
- Design System
|
||||
- Documentation
|
||||
- Events System
|
||||
- Home
|
||||
- Kubernetes Plugin
|
||||
- Notifications
|
||||
- OpenAPI Tooling
|
||||
- Permission Framework
|
||||
- Search
|
||||
- Software Templates
|
||||
- TechDocs
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: integration
|
||||
attributes:
|
||||
label: '🔗 External Integration'
|
||||
description: Is this issue related to an integration with any particular external system?
|
||||
options:
|
||||
- N/A
|
||||
- AWS
|
||||
- Azure
|
||||
- Azure DevOps
|
||||
- Bitbucket Cloud
|
||||
- Bitbucket Server
|
||||
- GCP
|
||||
- Gerrit
|
||||
- Gitea
|
||||
- GitHub
|
||||
- GitLab
|
||||
- Other
|
||||
validations:
|
||||
required: true
|
||||
- id: read-code-of-conduct
|
||||
type: checkboxes
|
||||
attributes:
|
||||
label: 'Have you read the Code of Conduct?'
|
||||
options:
|
||||
- label: 'I have read the [Code of Conduct](https://github.com/backstage/backstage/blob/master/CODE_OF_CONDUCT.md)'
|
||||
required: true
|
||||
- id: willing-to-submit-pr
|
||||
type: dropdown
|
||||
attributes:
|
||||
label: Are you willing to submit a PR?
|
||||
description: This is absolutely not required, but we are happy to guide you in the contribution process.
|
||||
options:
|
||||
- Undecided
|
||||
- Yes, and I have enough information to get started
|
||||
- Yes, but I would like some more guidance
|
||||
- No, but I'm happy to collaborate on a PR with someone else
|
||||
- No, I don't have time to work on this right now
|
||||
validations:
|
||||
required: true
|
||||
@@ -0,0 +1,161 @@
|
||||
name: '🪲 Report a bug'
|
||||
description: 'Report a bug that you have encountered'
|
||||
labels:
|
||||
- type:bug
|
||||
- status:needs-triage
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Please fill in each section completely, and [search in GitHub](https://github.com/backstage/backstage/search?type=Issues)
|
||||
before reporting a new bug to avoid duplicates. Thank you!
|
||||
# This field is managed by .common.yaml
|
||||
- id: issue-labels
|
||||
type: checkboxes
|
||||
attributes:
|
||||
label: '📜 Issue Labels'
|
||||
options:
|
||||
- label: 'Please familiarize yourself with the issue labels used in this project: [LABELS.md](https://github.com/backstage/backstage/blob/master/LABELS.md)'
|
||||
required: true
|
||||
# This field is managed by .common.yaml
|
||||
- id: search-terms
|
||||
type: textarea
|
||||
attributes:
|
||||
label: '🔎 Search Terms'
|
||||
render: plain
|
||||
description: |
|
||||
What search terms did you use when trying to find similar issues?
|
||||
placeholder: |
|
||||
List of keywords you searched for before creating this issue. Write them down here so that others can find this issue more easily and help provide feedback.
|
||||
|
||||
e.g. "catalog github rate limited", "http root service configurer", "scaffolder template include", "entity card title"
|
||||
validations:
|
||||
required: true
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: '<br/>' # empty space
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
## Defining the bug
|
||||
|
||||
Defining the bug accurately will help ensure that it is identified and fixed correctly.
|
||||
# This field is managed by .common.yaml
|
||||
- id: project-area
|
||||
type: dropdown
|
||||
attributes:
|
||||
label: '🗃️ Project Area'
|
||||
description: Which project area is this issue most closely related to? This will help find an owner for the issue faster.
|
||||
options:
|
||||
- Unknown
|
||||
- Auditor
|
||||
- Auth
|
||||
- Catalog
|
||||
- CLI Tooling
|
||||
- Core Framework
|
||||
- Design System
|
||||
- Documentation
|
||||
- Events System
|
||||
- Home
|
||||
- Kubernetes Plugin
|
||||
- Notifications
|
||||
- OpenAPI Tooling
|
||||
- Permission Framework
|
||||
- Search
|
||||
- Software Templates
|
||||
- TechDocs
|
||||
validations:
|
||||
required: true
|
||||
# This field is managed by .common.yaml
|
||||
- type: dropdown
|
||||
id: integration
|
||||
attributes:
|
||||
label: '🔗 External Integration'
|
||||
description: Is this issue related to an integration with any particular external system?
|
||||
options:
|
||||
- N/A
|
||||
- AWS
|
||||
- Azure
|
||||
- Azure DevOps
|
||||
- Bitbucket Cloud
|
||||
- Bitbucket Server
|
||||
- GCP
|
||||
- Gerrit
|
||||
- Gitea
|
||||
- GitHub
|
||||
- GitLab
|
||||
- Other
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: description
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: '📝 Description & Context'
|
||||
placeholder: |
|
||||
Describe the observed behavior that you believe to be incorrect, as well as any additional context that might be useful in understanding the bug.
|
||||
|
||||
e.g. "When I navigate to the catalog index page, it loads without any issues. This might be related to https://xkcd.com/1172"
|
||||
- type: textarea
|
||||
id: expected-behavior
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: '👍 Expected Behavior'
|
||||
placeholder: |
|
||||
Describe the behavior or result that you expected instead of the observed one.
|
||||
|
||||
e.g. "I expect the catalog index page to overheat my CPU"
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: '<br/>' # empty space
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
## Reproducing the bug
|
||||
|
||||
Being able to easily reproduce the bug will significantly increase the likelihood that it can be identified and fixed. Please provide a repository where the bug can be reproduced, unless this is a critical bug that needs immediate attention.
|
||||
|
||||
If you are unable to provide a reproduction repository, please explain the reproduction steps in as much detail as possible, and include the output of `yarn backstage-cli info` if relevant.
|
||||
|
||||
If inadequate or no reproduction steps are provided, the bug report is likely to be labeled as needing reproduction steps before it can be progressed further.
|
||||
- type: input
|
||||
id: reproduction-repo
|
||||
attributes:
|
||||
label: '📦 Reproduction Repo'
|
||||
description: A link to a GitHub repository where the issue can be reproduced
|
||||
placeholder: https://github.com/ghost/my-repro-repo
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: steps-to-reproduce
|
||||
attributes:
|
||||
label: '🥾 Reproduction steps'
|
||||
description: 'How do you trigger this bug? Please walk us through it step by step.'
|
||||
placeholder: |
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'"
|
||||
validations:
|
||||
required: false
|
||||
# This field is managed by .common.yaml
|
||||
- id: read-code-of-conduct
|
||||
type: checkboxes
|
||||
attributes:
|
||||
label: 'Have you read the Code of Conduct?'
|
||||
options:
|
||||
- label: 'I have read the [Code of Conduct](https://github.com/backstage/backstage/blob/master/CODE_OF_CONDUCT.md)'
|
||||
required: true
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Are you willing to submit PR?
|
||||
description: This is absolutely not required, but we are happy to guide you in the contribution process.
|
||||
options:
|
||||
- Undecided
|
||||
- Yes, and I have enough information to get started
|
||||
- Yes, but I would like some more guidance
|
||||
- No, but I'm happy to collaborate on a PR with someone else
|
||||
- No, I don't have time to work on this right now
|
||||
validations:
|
||||
required: true
|
||||
@@ -0,0 +1,97 @@
|
||||
name: '📖 Report an issue in the documentation'
|
||||
description: 'Report an issue in the Backstage documentation'
|
||||
labels:
|
||||
- domain:docs
|
||||
- type:documentation
|
||||
- status:needs-triage
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
This template is used to report issues in the Backstage documentation.
|
||||
|
||||
The documentation at [backstage.io](https://backstage.io) is only updated when a new release is made. Before reporting an issue here, please verify that the issue also exists in the ["next"](https://backstage.io/docs/next/overview/what-is-backstage) version of the documentation, which you can access using the top-right dropdown menu.
|
||||
# This field is managed by .common.yaml
|
||||
- id: issue-labels
|
||||
type: checkboxes
|
||||
attributes:
|
||||
label: '📜 Issue Labels'
|
||||
options:
|
||||
- label: 'Please familiarize yourself with the issue labels used in this project: [LABELS.md](https://github.com/backstage/backstage/blob/master/LABELS.md)'
|
||||
required: true
|
||||
# This field is managed by .common.yaml
|
||||
- id: project-area
|
||||
type: dropdown
|
||||
attributes:
|
||||
label: '🗃️ Project Area'
|
||||
description: Which project area is this issue most closely related to? This will help find an owner for the issue faster.
|
||||
options:
|
||||
- Unknown
|
||||
- Auditor
|
||||
- Auth
|
||||
- Catalog
|
||||
- CLI Tooling
|
||||
- Core Framework
|
||||
- Design System
|
||||
- Documentation
|
||||
- Events System
|
||||
- Home
|
||||
- Kubernetes Plugin
|
||||
- Notifications
|
||||
- OpenAPI Tooling
|
||||
- Permission Framework
|
||||
- Search
|
||||
- Software Templates
|
||||
- TechDocs
|
||||
validations:
|
||||
required: true
|
||||
# This field is managed by .common.yaml
|
||||
- type: dropdown
|
||||
id: integration
|
||||
attributes:
|
||||
label: '🔗 External Integration'
|
||||
description: Is this issue related to an integration with any particular external system?
|
||||
options:
|
||||
- N/A
|
||||
- AWS
|
||||
- Azure
|
||||
- Azure DevOps
|
||||
- Bitbucket Cloud
|
||||
- Bitbucket Server
|
||||
- GCP
|
||||
- Gerrit
|
||||
- Gitea
|
||||
- GitHub
|
||||
- GitLab
|
||||
- Other
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: description
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: '📝 Description'
|
||||
description: Describe the problem you have found in the documentation.
|
||||
placeholder: |
|
||||
Please provide links to the specific pages and sections that need to be corrected, and describe the problem you have found.
|
||||
# This field is managed by .common.yaml
|
||||
- id: read-code-of-conduct
|
||||
type: checkboxes
|
||||
attributes:
|
||||
label: 'Have you read the Code of Conduct?'
|
||||
options:
|
||||
- label: 'I have read the [Code of Conduct](https://github.com/backstage/backstage/blob/master/CODE_OF_CONDUCT.md)'
|
||||
required: true
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Are you willing to submit PR?
|
||||
description: This is absolutely not required, but we are happy to guide you in the contribution process.
|
||||
options:
|
||||
- Undecided
|
||||
- Yes, and I have enough information to get started
|
||||
- Yes, but I would like some more guidance
|
||||
- No, but I'm happy to collaborate on a PR with someone else
|
||||
- No, I don't have time to work on this right now
|
||||
validations:
|
||||
required: true
|
||||
@@ -0,0 +1,113 @@
|
||||
name: '💡 Suggest a change'
|
||||
description: 'Suggest an idea for a new feature or change to Backstage'
|
||||
labels:
|
||||
- type:suggestion
|
||||
- status:needs-triage
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
This template helps you propose new features, enhancements, or other ideas for Backstage. You can keep your proposal lightweight, but please provide enough detail for reviewers to understand and respond effectively.
|
||||
|
||||
For complex additions, consider creating a [Backstage Enhancement Proposal](https://github.com/backstage/backstage/blob/master/beps/README.md) (BEP) instead, as this process streamlines discussions and iteration. Don't worry - you can always convert this issue to a BEP later.
|
||||
# This field is managed by .common.yaml
|
||||
- id: issue-labels
|
||||
type: checkboxes
|
||||
attributes:
|
||||
label: '📜 Issue Labels'
|
||||
options:
|
||||
- label: 'Please familiarize yourself with the issue labels used in this project: [LABELS.md](https://github.com/backstage/backstage/blob/master/LABELS.md)'
|
||||
required: true
|
||||
# This field is managed by .common.yaml
|
||||
- id: search-terms
|
||||
type: textarea
|
||||
attributes:
|
||||
label: '🔎 Search Terms'
|
||||
render: plain
|
||||
description: |
|
||||
What search terms did you use when trying to find similar issues?
|
||||
placeholder: |
|
||||
List of keywords you searched for before creating this issue. Write them down here so that others can find this issue more easily and help provide feedback.
|
||||
|
||||
e.g. "catalog github rate limited", "http root service configurer", "scaffolder template include", "entity card title"
|
||||
validations:
|
||||
required: true
|
||||
# This field is managed by .common.yaml
|
||||
- id: project-area
|
||||
type: dropdown
|
||||
attributes:
|
||||
label: '🗃️ Project Area'
|
||||
description: Which project area is this issue most closely related to? This will help find an owner for the issue faster.
|
||||
options:
|
||||
- Unknown
|
||||
- Auditor
|
||||
- Auth
|
||||
- Catalog
|
||||
- CLI Tooling
|
||||
- Core Framework
|
||||
- Design System
|
||||
- Documentation
|
||||
- Events System
|
||||
- Home
|
||||
- Kubernetes Plugin
|
||||
- Notifications
|
||||
- OpenAPI Tooling
|
||||
- Permission Framework
|
||||
- Search
|
||||
- Software Templates
|
||||
- TechDocs
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: need
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: '🔖 Need'
|
||||
description: What is the rationale for this change, and who will benefit from it?
|
||||
placeholder: |
|
||||
Explain why this change is important and who will benefit from it. Provide context for the change, such as highlighting relevant past work in this area or specific use cases.
|
||||
- type: textarea
|
||||
id: proposal
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: '📝 Proposal'
|
||||
description: Describe the change that you are suggesting.
|
||||
placeholder: |
|
||||
Provide sufficient detail for reviewers to give concrete feedback.
|
||||
|
||||
Including a proposed implementation is optional, but if you do, consider adding design details such as TypeScript examples, database schema, or sequence diagrams.
|
||||
|
||||
If the change requires particular care when being rolled out, it can be helpful to include a plan for a phased release.
|
||||
- type: textarea
|
||||
id: alternatives
|
||||
attributes:
|
||||
label: '🔄 Alternatives'
|
||||
description: Did you consider any other approaches?
|
||||
placeholder: |
|
||||
Did you consider any other approaches, and if so, why did you rule them out?
|
||||
|
||||
These do not need to be as detailed as the main proposal, but should include enough information to understand the idea and why it wasn't suitable.
|
||||
# This field is managed by .common.yaml
|
||||
- id: read-code-of-conduct
|
||||
type: checkboxes
|
||||
attributes:
|
||||
label: 'Have you read the Code of Conduct?'
|
||||
options:
|
||||
- label: 'I have read the [Code of Conduct](https://github.com/backstage/backstage/blob/master/CODE_OF_CONDUCT.md)'
|
||||
required: true
|
||||
# This field is managed by .common.yaml
|
||||
- id: willing-to-submit-pr
|
||||
type: dropdown
|
||||
attributes:
|
||||
label: Are you willing to submit a PR?
|
||||
description: This is absolutely not required, but we are happy to guide you in the contribution process.
|
||||
options:
|
||||
- Undecided
|
||||
- Yes, and I have enough information to get started
|
||||
- Yes, but I would like some more guidance
|
||||
- No, but I'm happy to collaborate on a PR with someone else
|
||||
- No, I don't have time to work on this right now
|
||||
validations:
|
||||
required: true
|
||||
@@ -0,0 +1,100 @@
|
||||
name: '🚧 Track a maintenance task'
|
||||
description: 'Track a maintenance task'
|
||||
labels:
|
||||
- type:maintenance
|
||||
- status:needs-triage
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
This template helps you track maintenance tasks that require special consideration, such as complex version updates or migrations.
|
||||
# This field is managed by .common.yaml
|
||||
- id: issue-labels
|
||||
type: checkboxes
|
||||
attributes:
|
||||
label: '📜 Issue Labels'
|
||||
options:
|
||||
- label: 'Please familiarize yourself with the issue labels used in this project: [LABELS.md](https://github.com/backstage/backstage/blob/master/LABELS.md)'
|
||||
required: true
|
||||
# This field is managed by .common.yaml
|
||||
- id: search-terms
|
||||
type: textarea
|
||||
attributes:
|
||||
label: '🔎 Search Terms'
|
||||
render: plain
|
||||
description: |
|
||||
What search terms did you use when trying to find similar issues?
|
||||
placeholder: |
|
||||
List of keywords you searched for before creating this issue. Write them down here so that others can find this issue more easily and help provide feedback.
|
||||
|
||||
e.g. "catalog github rate limited", "http root service configurer", "scaffolder template include", "entity card title"
|
||||
validations:
|
||||
required: true
|
||||
# This field is managed by .common.yaml
|
||||
- id: project-area
|
||||
type: dropdown
|
||||
attributes:
|
||||
label: '🗃️ Project Area'
|
||||
description: Which project area is this issue most closely related to? This will help find an owner for the issue faster.
|
||||
options:
|
||||
- Unknown
|
||||
- Auditor
|
||||
- Auth
|
||||
- Catalog
|
||||
- CLI Tooling
|
||||
- Core Framework
|
||||
- Design System
|
||||
- Documentation
|
||||
- Events System
|
||||
- Home
|
||||
- Kubernetes Plugin
|
||||
- Notifications
|
||||
- OpenAPI Tooling
|
||||
- Permission Framework
|
||||
- Search
|
||||
- Software Templates
|
||||
- TechDocs
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: task
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: '🛠️ Task'
|
||||
description: Describe the task that requires attention
|
||||
placeholder: |
|
||||
Explain what needs to be accomplished, including any relevant context such as dependencies or related components.
|
||||
- type: textarea
|
||||
id: proposal
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: '📊 Priority & Impact'
|
||||
description: Explain the urgency and impact of this task
|
||||
placeholder: |
|
||||
Explain what level of prioritization this task should receive. Are there any particular benefits provided in newer versions in case of a version update, or any security vulnerabilities that can be addressed?
|
||||
|
||||
Also list any important dates or deadlines, such as current versions reaching end of life, or release dates for stable releases.
|
||||
# This field is managed by .common.yaml
|
||||
- id: read-code-of-conduct
|
||||
type: checkboxes
|
||||
attributes:
|
||||
label: 'Have you read the Code of Conduct?'
|
||||
options:
|
||||
- label: 'I have read the [Code of Conduct](https://github.com/backstage/backstage/blob/master/CODE_OF_CONDUCT.md)'
|
||||
required: true
|
||||
# This field is managed by .common.yaml
|
||||
- id: willing-to-submit-pr
|
||||
type: dropdown
|
||||
attributes:
|
||||
label: Are you willing to submit a PR?
|
||||
description: This is absolutely not required, but we are happy to guide you in the contribution process.
|
||||
options:
|
||||
- Undecided
|
||||
- Yes, and I have enough information to get started
|
||||
- Yes, but I would like some more guidance
|
||||
- No, but I'm happy to collaborate on a PR with someone else
|
||||
- No, I don't have time to work on this right now
|
||||
validations:
|
||||
required: true
|
||||
@@ -0,0 +1,22 @@
|
||||
name: '❓ Other'
|
||||
description: 'Something not captured by any other template'
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
This template can be used to create issues that don't fit any of the other templates. Valid examples include meta issues or other task tracking issues to help coordinate work, or informative issues that are kept for search purposes.
|
||||
|
||||
Do not use this template to submit support or help requests, as they will be closed. Please use other forums such as our [Community Discord](https://discord.gg/backstage-687207715902193673) instead.
|
||||
- type: checkboxes
|
||||
id: acknowledgement
|
||||
attributes:
|
||||
label: '📝 Acknowledgement'
|
||||
options:
|
||||
- label: I acknowledge that issues using this template may be closed without further explanation.
|
||||
required: true
|
||||
- type: textarea
|
||||
id: contents
|
||||
attributes:
|
||||
label: Content
|
||||
validations:
|
||||
required: true
|
||||
@@ -1,84 +0,0 @@
|
||||
name: '🐛 Bug Report'
|
||||
description: 'Submit a bug report to help us improve'
|
||||
title: '🐛 Bug Report: <title>'
|
||||
labels:
|
||||
- bug
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: We value your time and effort to submit this bug report. 🙏
|
||||
- type: textarea
|
||||
id: description
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: '📜 Description'
|
||||
description: 'A clear and concise description of what the bug is.'
|
||||
placeholder: 'It bugs out when ...'
|
||||
- type: textarea
|
||||
id: expected-behavior
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: '👍 Expected behavior'
|
||||
description: 'What did you think should happen?'
|
||||
placeholder: 'It should ...'
|
||||
- type: textarea
|
||||
id: actual-behavior
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: '👎 Actual Behavior with Screenshots'
|
||||
description: 'What did actually happen? Add screenshots, if applicable.'
|
||||
placeholder: 'It actually ...'
|
||||
- type: textarea
|
||||
id: steps-to-reproduce
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: '👟 Reproduction steps'
|
||||
description: 'How do you trigger this bug? Please walk us through it step by step.'
|
||||
placeholder:
|
||||
"Provide a link to a live example, or an unambiguous set of steps to reproduce this bug. Include code or configuration to reproduce, if relevant.\n
|
||||
1. Go to '...'\n
|
||||
2. Click on '....'\n
|
||||
3. Scroll down to '....'"
|
||||
- type: textarea
|
||||
id: context
|
||||
validations:
|
||||
required: false
|
||||
attributes:
|
||||
label: '📃 Provide the context for the Bug.'
|
||||
description: 'How has this issue affected you? What are you trying to accomplish?'
|
||||
placeholder: 'Providing context (e.g. links to configuration settings, stack trace or log data) helps us come up with a solution that is most useful in the real world.'
|
||||
- type: textarea
|
||||
id: environment
|
||||
validations:
|
||||
required: false
|
||||
attributes:
|
||||
label: '🖥️ Your Environment'
|
||||
description: 'Provide Browser Information
|
||||
Provide Output of `yarn backstage-cli info`'
|
||||
placeholder: 'Include as many relevant details about the environment you experienced the bug in.'
|
||||
- type: checkboxes
|
||||
id: no-duplicate-issues
|
||||
attributes:
|
||||
label: '👀 Have you spent some time to check if this bug has been raised before?'
|
||||
options:
|
||||
- label: "I checked and didn't find similar issue"
|
||||
required: true
|
||||
- type: checkboxes
|
||||
id: read-code-of-conduct
|
||||
attributes:
|
||||
label: '🏢 Have you read the Code of Conduct?'
|
||||
options:
|
||||
- label: 'I have read the [Code of Conduct](https://github.com/backstage/backstage/blob/master/CODE_OF_CONDUCT.md)'
|
||||
required: true
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Are you willing to submit PR?
|
||||
description: This is absolutely not required, but we are happy to guide you in the contribution process.
|
||||
options:
|
||||
- Yes I am willing to submit a PR!
|
||||
- No, but I'm happy to collaborate on a PR with someone else
|
||||
- No, I don't have time to work on this right now
|
||||
@@ -1,54 +0,0 @@
|
||||
name: 🚀 Feature
|
||||
description: 'Submit a proposal for a new feature'
|
||||
title: '🚀 Feature: <title>'
|
||||
labels: [enhancement]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
We value your time and efforts to submit this Feature request form. 🙏
|
||||
- type: textarea
|
||||
id: feature-description
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: '🔖 Feature description'
|
||||
description: 'A clear and concise description of what the feature is.'
|
||||
placeholder: 'You should add ...'
|
||||
- type: textarea
|
||||
id: context
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: '🎤 Context'
|
||||
description: 'Please explain why this feature should be implemented and how it would be used. Add examples, if applicable.'
|
||||
placeholder: 'In my use-case, ...'
|
||||
- type: textarea
|
||||
id: implementation
|
||||
attributes:
|
||||
label: '✌️ Possible Implementation'
|
||||
description: 'A clear and concise description of what you want to happen.'
|
||||
placeholder: 'Not obligatory, but ideas as to the implementation of the addition or change'
|
||||
- type: checkboxes
|
||||
id: no-duplicate-issues
|
||||
attributes:
|
||||
label: '👀 Have you spent some time to check if this feature request has been raised before?'
|
||||
options:
|
||||
- label: "I checked and didn't find similar issue"
|
||||
required: true
|
||||
- type: checkboxes
|
||||
id: read-code-of-conduct
|
||||
attributes:
|
||||
label: '🏢 Have you read the Code of Conduct?'
|
||||
options:
|
||||
- label: 'I have read the [Code of Conduct](https://github.com/backstage/backstage/blob/master/CODE_OF_CONDUCT.md)'
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: willing-to-submit-pr
|
||||
attributes:
|
||||
label: Are you willing to submit PR?
|
||||
description: This is absolutely not required, but we are happy to guide you in the contribution process.
|
||||
options:
|
||||
- Yes I am willing to submit a PR!
|
||||
- No, but I'm happy to collaborate on a PR with someone else
|
||||
- No, I don't have time to work on this right now
|
||||
@@ -1,51 +0,0 @@
|
||||
name: 💬 RFC
|
||||
description: 'Request For Comments (RFC) from the community'
|
||||
title: '💬 RFC: <title>'
|
||||
labels: [rfc]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
We value your time and efforts to submit this RFC form. 🙏
|
||||
- type: textarea
|
||||
id: rfc-need
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: '🔖 Need'
|
||||
description: 'Let us know why are you proposing this change'
|
||||
placeholder: 'The problem we’re trying to address and the benefits/impact we expect to get from this are ...'
|
||||
- type: textarea
|
||||
id: proposal
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: '🎉 Proposal'
|
||||
description: 'Describe the proposal in as much detail as needed for reviewers to give concrete feedback.'
|
||||
placeholder: 'Take special care in this section to describe any implications on data privacy or security.'
|
||||
- type: textarea
|
||||
id: alternatives
|
||||
attributes:
|
||||
label: '〽️ Alternatives'
|
||||
description: 'What alternatives to the proposed solution were considered?'
|
||||
placeholder: 'What criteria/data was used to discard these?'
|
||||
- type: textarea
|
||||
id: risk
|
||||
attributes:
|
||||
label: '❌ Risks'
|
||||
description: 'What other things happening could conflict or compete (for example for resources) with the proposal?'
|
||||
placeholder: 'What risk are there and how do we plan to handle them?'
|
||||
- type: checkboxes
|
||||
id: no-duplicate-issues
|
||||
attributes:
|
||||
label: '👀 Have you spent some time to check if this RFC has been raised before?'
|
||||
options:
|
||||
- label: "I checked and didn't find similar issue"
|
||||
required: true
|
||||
- type: checkboxes
|
||||
id: read-code-of-conduct
|
||||
attributes:
|
||||
label: '🏢 Have you read the Code of Conduct?'
|
||||
options:
|
||||
- label: 'I have read the [Code of Conduct](https://github.com/backstage/backstage/blob/master/CODE_OF_CONDUCT.md)'
|
||||
required: true
|
||||
Executable
+54
@@ -0,0 +1,54 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
const yaml = require('yaml');
|
||||
|
||||
const TEMPLATES_DIR = path.join(__dirname);
|
||||
const COMMON_FILE = path.join(TEMPLATES_DIR, '.common.yaml');
|
||||
|
||||
// Read the common fields from .common.yaml
|
||||
const commonDoc = yaml.parseDocument(fs.readFileSync(COMMON_FILE, 'utf8'));
|
||||
const commonFields = new Map(
|
||||
commonDoc.get('body').items.map(field => {
|
||||
field.commentBefore = ' This field is managed by .common.yaml';
|
||||
return [field.get('id'), field];
|
||||
}),
|
||||
);
|
||||
|
||||
// Get all YAML files in the templates directory except .common.yaml
|
||||
const templateFiles = fs
|
||||
.readdirSync(TEMPLATES_DIR)
|
||||
.filter(file => file.endsWith('.yaml') && file !== '.common.yaml');
|
||||
|
||||
// Process each template file
|
||||
for (const templateFile of templateFiles) {
|
||||
const templatePath = path.join(TEMPLATES_DIR, templateFile);
|
||||
const templateDoc = yaml.parseDocument(fs.readFileSync(templatePath, 'utf8'));
|
||||
|
||||
if (templateDoc.get('body')) {
|
||||
const body = templateDoc.get('body');
|
||||
for (let i = 0; i < body.items.length; i++) {
|
||||
const field = body.items[i];
|
||||
|
||||
const commonField = commonFields.get(field.get('id'));
|
||||
if (commonField) {
|
||||
body.items[i] = commonField;
|
||||
}
|
||||
}
|
||||
|
||||
// Write the updated template back to file with matching style
|
||||
fs.writeFileSync(
|
||||
templatePath,
|
||||
templateDoc.toString({
|
||||
indent: 2,
|
||||
lineWidth: 0,
|
||||
minContentWidth: 0,
|
||||
singleQuote: true,
|
||||
}),
|
||||
);
|
||||
console.log(`Updated ${templateFile}`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('Sync complete!');
|
||||
@@ -1,53 +0,0 @@
|
||||
name: 🦄 UX Component
|
||||
description: 'For designers to request UX components to be added to the Backstage Storybook'
|
||||
title: '🦄 UX Component: <title>'
|
||||
labels: [design]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
We value your time and efforts to submit this RFC form. 🙏
|
||||
- type: textarea
|
||||
id: ux-general
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: '🔖 General'
|
||||
description: 'Write a nice note to the community requesting the creation of a new component.'
|
||||
placeholder: 'Include an image of your component. Bonus points for a GIF!'
|
||||
- type: textarea
|
||||
id: usage
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: '💻 Usage'
|
||||
description: "Tell us what's the point of this component/pattern is."
|
||||
placeholder: 'How does it help? How should it work? Any rules?'
|
||||
- type: textarea
|
||||
id: specs
|
||||
validations:
|
||||
required: true
|
||||
attributes:
|
||||
label: '📐 Specs'
|
||||
description: 'Include images that detail the redlines for your component.'
|
||||
placeholder: "Once we get our Figma workspace set up, we'll be posting the Figma files rather than doing specs by hand."
|
||||
- type: textarea
|
||||
id: future
|
||||
attributes:
|
||||
label: '🔮 Future'
|
||||
description: 'List out any upcoming, exciting functionality for this component.'
|
||||
placeholder: 'The component will have ...'
|
||||
- type: checkboxes
|
||||
id: no-duplicate-issues
|
||||
attributes:
|
||||
label: '👀 Have you spent some time to check if this UX Component request has been raised before?'
|
||||
options:
|
||||
- label: "I checked and didn't find similar issue"
|
||||
required: true
|
||||
- type: checkboxes
|
||||
id: read-code-of-conduct
|
||||
attributes:
|
||||
label: '🏢 Have you read the Code of Conduct?'
|
||||
options:
|
||||
- label: 'I have read the [Code of Conduct](https://github.com/backstage/backstage/blob/master/CODE_OF_CONDUCT.md)'
|
||||
required: true
|
||||
@@ -0,0 +1,56 @@
|
||||
policy:
|
||||
- section:
|
||||
- id: ['project-area']
|
||||
block-list: []
|
||||
label:
|
||||
- name: 'area:auditor'
|
||||
keys: ['Auditor']
|
||||
- name: 'area:auth'
|
||||
keys: ['Auth']
|
||||
- name: 'area:catalog'
|
||||
keys: ['Catalog']
|
||||
- name: 'area:core'
|
||||
keys: ['Core Framework', 'CLI Tooling']
|
||||
- name: 'area:design-system'
|
||||
keys: ['Design System']
|
||||
- name: 'area:documentation'
|
||||
keys: ['Documentation']
|
||||
- name: 'area:events'
|
||||
keys: ['Events System']
|
||||
- name: 'area:home'
|
||||
keys: ['Home']
|
||||
- name: 'area:kubernetes'
|
||||
keys: ['Kubernetes Plugin']
|
||||
- name: 'area:notifications'
|
||||
keys: ['Notifications']
|
||||
- name: 'area:openapi-tooling'
|
||||
keys: ['OpenAPI Tooling']
|
||||
- name: 'area:permission'
|
||||
keys: ['Permission Framework']
|
||||
- name: 'area:search'
|
||||
keys: ['Search']
|
||||
- name: 'area:scaffolder'
|
||||
keys: ['Software Templates']
|
||||
- name: 'area:techdocs'
|
||||
keys: ['TechDocs']
|
||||
- id: ['integration']
|
||||
block-list: []
|
||||
label:
|
||||
- name: 'integration:aws'
|
||||
keys: ['AWS']
|
||||
- name: 'integration:azure'
|
||||
keys: ['Azure', 'Azure DevOps']
|
||||
- name: 'integration:bitbucket-cloud'
|
||||
keys: ['Bitbucket Cloud']
|
||||
- name: 'integration:bitbucket-server'
|
||||
keys: ['Bitbucket Server']
|
||||
- name: 'integration:gcp'
|
||||
keys: ['GCP']
|
||||
- name: 'integration:gerrit'
|
||||
keys: ['Gerrit']
|
||||
- name: 'integration:gitea'
|
||||
keys: ['Gitea']
|
||||
- name: 'integration:github'
|
||||
keys: ['GitHub']
|
||||
- name: 'integration:gitlab'
|
||||
keys: ['GitLab']
|
||||
@@ -10,5 +10,3 @@ area:scaffolder:
|
||||
- '/scaffolder/i'
|
||||
area:permission:
|
||||
- '/permission/i'
|
||||
bep:
|
||||
- '/\bbep\b/i'
|
||||
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
for your contributions.
|
||||
days-before-issue-stale: 60
|
||||
days-before-issue-close: 7
|
||||
exempt-issue-labels: plugin,after-vacations,will-fix,bep
|
||||
exempt-issue-labels: after vacations,no stale
|
||||
stale-issue-label: stale
|
||||
stale-pr-message: >
|
||||
This PR has been automatically marked as stale because it has not had
|
||||
@@ -37,6 +37,6 @@ jobs:
|
||||
and we'll re-open the PR so that you can continue the contribution!
|
||||
days-before-pr-stale: 14
|
||||
days-before-pr-close: 7
|
||||
exempt-pr-labels: after-vacations,will-fix
|
||||
exempt-pr-labels: after vacations,no stale
|
||||
stale-pr-label: stale
|
||||
operations-per-run: 100
|
||||
|
||||
@@ -20,6 +20,12 @@ jobs:
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
# We need to checkout the `.github/ISSUE_TEMPLATE` for the advanced labeler action to be able to read the templates
|
||||
# While at it we might as well checkout all of `.github` so that the labeling actions don't need to fetch their configs
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: .github
|
||||
|
||||
- name: Add issue labels
|
||||
uses: github/issue-labeler@c1b0f9f52a63158c4adc09425e858e87b32e9685 # v3.4
|
||||
with:
|
||||
@@ -29,3 +35,15 @@ jobs:
|
||||
enable-versioned-regex: 0
|
||||
not-before: 2024-04-19T15:03:51Z
|
||||
repo-token: '${{ secrets.GITHUB_TOKEN }}'
|
||||
|
||||
# These two steps add labels based on user input in the issue form
|
||||
- name: Parse issue form
|
||||
uses: stefanbuck/github-issue-parser@v3
|
||||
id: issue-parser
|
||||
with:
|
||||
template-path: .github/ISSUE_TEMPLATE/.common.yaml
|
||||
- name: Add advanced issue labels
|
||||
uses: redhat-plumbers-in-action/advanced-issue-labeler@v2
|
||||
with:
|
||||
issue-form: ${{ steps.issue-parser.outputs.jsonString }}
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
# GitHub Labels in Backstage
|
||||
|
||||
This document explains the GitHub labels used in the Backstage main repository. Labels help categorize and track issues and pull requests, but are also used as a communication tool in order to help maintainers respond to issues and pull requests faster.
|
||||
|
||||
## Issue Type Labels - `type:*`
|
||||
|
||||
These labels help you understand what type of work is needed.
|
||||
|
||||
- `type:bug` - Something doesn't work as expected and needs fixing.
|
||||
- `type:docs` - Documentation is missing or needs updating.
|
||||
- `type:suggestion` - An proposal for a new feature or change.
|
||||
- `type:maintenance` - Routine maintenance tasks, version bumps, cleanup, deprecations, etc.
|
||||
|
||||
## Priority Labels - `priority:*`
|
||||
|
||||
These labels all signal that the issue has been accepted for implementation, and further indicate its priority and whether the owners of the area will address it:
|
||||
|
||||
- `priority:critical` - The owners of the area will address this as soon as possible.
|
||||
- `priority:roadmap` - The owners of the area have this on their roadmap and will address it when possible, some contributions may be welcome.
|
||||
- `priority:contrib-welcome` - The owners of the area are unlikely to address this in the short term, but contributions are welcome.
|
||||
- `priority:contrib-needed` - This will not be addressed by the owners of the area, but contributions are welcome.
|
||||
|
||||
## Need Labels - `needs:*`
|
||||
|
||||
These labels indicate what is needed to move an issue forward before it can be accepted for implementation:
|
||||
|
||||
- `needs:bep` - The issue is an advanced addition that needs a [Backstage Enhancement Proposal](./beps/README.md).
|
||||
- `needs:direction` - The issue needs direction from the owners of the area.
|
||||
- `needs:more-info` - The issue needs more information from the author.
|
||||
- `needs:motivation` - It is not clear why this change is needed. The author should provide motivation for the change, for instance by giving examples of concrete use cases or scenarios.
|
||||
- `needs:repro` - The issue cannot be reproduced by the owners of the area. The author should provide more information to help them reproduce the issue, if possible with a minimal reproduction repository.
|
||||
- `needs:triage` - The issue needs initial review.
|
||||
- `needs:unblock` - The issue is blocked by another issue or upstream dependency.
|
||||
|
||||
## Area Labels - `area:*`
|
||||
|
||||
These labels indicate which part of Backstage an issue or pull request relates to. As a contributor, these help you find issues in areas you're interested in or have expertise in.
|
||||
|
||||
- `area:auditor` - Auditor service and it's use in plugins.
|
||||
- `area:auth` - Authentication and 3rd party authorization.
|
||||
- `area:catalog` - The Catalog plugin and the Software Catalog model and integrations.
|
||||
- `area:core` - The core Backstage framework.
|
||||
- `area:design-system` - The Canon design system and library.
|
||||
- `area:documentation` - Documentation for adopters, users, and developers.
|
||||
- `area:events` - The Events system and integrations for other plugins.
|
||||
- `area:home` - The Home plugin and the main page of the Backstage site.
|
||||
- `area:kubernetes` - The Kubernetes plugin and integrations for other plugins.
|
||||
- `area:notifications` - The Notifications plugin and integrations for other plugins.
|
||||
- `area:openapi-tooling` - The OpenAPI tooling it's use in plugins.
|
||||
- `area:permission` - The Permissions system and permission integrations from other plugins.
|
||||
- `area:scaffolder` - The Scaffolder plugin that powers Software Templates.
|
||||
- `area:search` - The Search plugin and search integrations for other plugins.
|
||||
- `area:techdocs` - The TechDocs plugin.
|
||||
|
||||
## Integration Labels - `integration:*`
|
||||
|
||||
These labels help you find issues related to specific external integrations:
|
||||
|
||||
- `integration:aws` - [Amazon Web Services](https://aws.amazon.com/)
|
||||
- `integration:azure` - [Microsoft Azure](https://azure.microsoft.com/) and [Azure DevOps](https://dev.azure.com/)
|
||||
- `integration:bitbucket-cloud` - [Bitbucket Cloud](https://bitbucket.org/)
|
||||
- `integration:bitbucket-server` - Bitbucket Server (Stash)
|
||||
- `integration:gcp` - [Google Cloud Platform](https://cloud.google.com/)
|
||||
- `integration:gerrit` - [Gerrit](https://www.gerritcodereview.com/)
|
||||
- `integration:gitea` - [Gitea](https://gitea.com/)
|
||||
- `integration:github` - [GitHub](https://github.com/)
|
||||
- `integration:gitlab` - [GitLab](https://gitlab.com/)
|
||||
|
||||
## Domain Labels
|
||||
|
||||
These labels indicate that an issue is related to specific domains of expertise.
|
||||
|
||||
- `domain:a11y` - Web domain issues specifically related to accessibility.
|
||||
- `domain:design` - Visual design and user experience.
|
||||
- `domain:docs` - Documentation for adopters, users, and developers.
|
||||
- `domain:backend` - Backend development in Node.js.
|
||||
- `domain:tooling` - Tooling and automation in Node.js and GitHub Actions.
|
||||
- `domain:web` - Frontend development using TypeScript and React.
|
||||
|
||||
## General Labels
|
||||
|
||||
- `after vacations` - To be handled once the owners return from vacation.
|
||||
- `do not merge` - The pull request should not be merged.
|
||||
- `fix before release` - Should be handled before the next release.
|
||||
- `good first issue` - Good for new contributors.
|
||||
- `stale` - The issue or pull request has not seen any activity for a while and will be closed if no further activity is seen.
|
||||
- `no stale` - The issue or pull request should not be closed due to inactivity.
|
||||
|
||||
## Common Issue Filters
|
||||
|
||||
This is a collection of common issue filters that can help you find issues that you are looking for or that match your interests and skills.
|
||||
|
||||
### New Contributors
|
||||
|
||||
These issues are ideal for new contributors to get started and don't require much familiarity with Backstage.
|
||||
|
||||
- [Backend](https://github.com/backstage/backstage/issues?q=is%3Aopen%20is%3Aissue%20label%3A%22good%20first%20issue%22%20label%3A%22domain%3Abackend%22%20)
|
||||
- [Documentation](https://github.com/backstage/backstage/issues?q=is%3Aopen%20is%3Aissue%20label%3A%22good%20first%20issue%22%20label%3A%22domain%3Adocs%22%20)
|
||||
- [Tooling](https://github.com/backstage/backstage/issues?q=is%3Aopen%20is%3Aissue%20label%3A%22good%20first%20issue%22%20label%3A%22domain%3Atooling%22%20)
|
||||
- [Web](https://github.com/backstage/backstage/issues?q=is%3Aopen%20is%3Aissue%20label%3A%22good%20first%20issue%22%20label%3A%22domain%3Aweb%22%20)
|
||||
|
||||
### Experienced Contributors
|
||||
|
||||
These issues generally require some familiarity with Backstage and the codebase, and are either open for or require contributions from the community.
|
||||
|
||||
- [Backend](<https://github.com/backstage/backstage/issues?q=is%3Aopen%20is%3Aissue%20(label%3Apriority%3Acontrib-welcome%20OR%20label%3Apriority%3Acontrib-needed)%20label%3A%22domain%3Abackend%22%20>)
|
||||
- [Documentation](<https://github.com/backstage/backstage/issues?q=is%3Aopen%20is%3Aissue%20(label%3Apriority%3Acontrib-welcome%20OR%20label%3Apriority%3Acontrib-needed)%20label%3A%22domain%3Adocs%22%20>)
|
||||
- [Tooling](<https://github.com/backstage/backstage/issues?q=is%3Aopen%20is%3Aissue%20(label%3Apriority%3Acontrib-welcome%20OR%20label%3Apriority%3Acontrib-needed)%20label%3A%22domain%3Atooling%22%20>)
|
||||
- [Web](<https://github.com/backstage/backstage/issues?q=is%3Aopen%20is%3Aissue%20(label%3Apriority%3Acontrib-welcome%20OR%20label%3Apriority%3Acontrib-needed)%20label%3A%22domain%3Aweb%22%20>)
|
||||
|
||||
### Maintainer Lists
|
||||
|
||||
These are useful lists for maintainers.
|
||||
|
||||
- [After vacations](https://github.com/backstage/backstage/issues?q=is%3Aopen%20is%3Aissue%20label%3A%22after%20vacations%22)
|
||||
- [Critical priority](https://github.com/backstage/backstage/issues?q=is%3Aopen%20is%3Aissue%20label%3A%22priority%3Acritical%22)
|
||||
- [Fix before release](https://github.com/backstage/backstage/issues?q=is%3Aopen%20is%3Aissue%20label%3A%22fix%20before%20release%22)
|
||||
- [Needs direction](https://github.com/backstage/backstage/issues?q=is%3Aopen%20is%3Aissue%20label%3A%22needs%3Adirection%22)
|
||||
- [Needs triage](https://github.com/backstage/backstage/issues?q=is%3Aopen%20is%3Aissue%20label%3A%22needs%3Atriage%22)
|
||||
@@ -402,6 +402,50 @@ async signInResolver({ profile }, ctx) {
|
||||
}
|
||||
```
|
||||
|
||||
## Reducing the size of issued tokens
|
||||
|
||||
By default the auth backend will issue user identity tokens that include the
|
||||
ownership references of the user in the `ent` claim of the JWT payload. This is
|
||||
done to make it easier and more efficient for consumers of the token to resolve
|
||||
ownership of the user. However, depending on the shape of your organization and
|
||||
how you resolve ownership claims, these tokens can grow quite large.
|
||||
|
||||
To address this, the auth backend now supports the configuration flag
|
||||
`auth.omitIdentityTokenOwnershipClaim` that causes the `ent` claim to be omitted
|
||||
from the token. This can be set to `true` in the `app-config.yaml` file.
|
||||
|
||||
```yaml title="in app-config.yaml"
|
||||
auth:
|
||||
omitIdentityTokenOwnershipClaim: true
|
||||
```
|
||||
|
||||
When this flag is set, the `ent` claim will no longer be present in the token,
|
||||
and consumers of the token will need to call the `/v1/userinfo` endpoint on the
|
||||
auth backend to fetch the ownership references of the user. However, there's usually no
|
||||
action required for consumers. Clients will still receive the full set
|
||||
of claims during authentication, and any plugin backends will already need to
|
||||
use the
|
||||
[`UserInfoService`](../backend-system/core-services/user-info.md) to
|
||||
access the ownership references from user credentials, which already calls the
|
||||
user info endpoint if necessary.
|
||||
|
||||
When enabling this flag, it is important that any custom sign-in resolvers directly return the result of the sign-in method. For example, the following would not work:
|
||||
|
||||
```ts
|
||||
const { token } = await ctx.issueToken({
|
||||
claims: { sub: entityRef, ent: [entityRef] },
|
||||
});
|
||||
return { token }; // WARNING: This will not work
|
||||
```
|
||||
|
||||
Instead, the sign-in resolver should directly return the result:
|
||||
|
||||
```ts
|
||||
return ctx.issueToken({
|
||||
claims: { sub: entityRef, ent: [entityRef] },
|
||||
});
|
||||
```
|
||||
|
||||
## Profile Transforms
|
||||
|
||||
Similar to a custom sign-in resolver, you can also write a custom profile transform
|
||||
|
||||
@@ -70,7 +70,7 @@ putting all extensions like this in a backend module package of their own in the
|
||||
`plugins` folder of your Backstage repo:
|
||||
|
||||
```sh
|
||||
yarn new --select backend-module --option pluginId=catalog
|
||||
yarn new --select backend-plugin-module --option pluginId=catalog
|
||||
```
|
||||
|
||||
The class will have this basic structure:
|
||||
|
||||
+3
-1
@@ -55,6 +55,7 @@
|
||||
"start:microsite": "cd microsite/ && yarn start",
|
||||
"start:next": "yarn start example-app-next example-backend",
|
||||
"storybook": "yarn ./storybook run storybook",
|
||||
"sync-issue-templates": "node ./.github/ISSUE_TEMPLATE/sync.js",
|
||||
"techdocs-cli": "node scripts/techdocs-cli.js",
|
||||
"techdocs-cli:dev": "cross-env TECHDOCS_CLI_DEV_MODE=true node scripts/techdocs-cli.js",
|
||||
"test": "NODE_OPTIONS='--no-node-snapshot --experimental-vm-modules' backstage-cli repo test",
|
||||
@@ -113,7 +114,8 @@
|
||||
"@backstage/errors": "workspace:^",
|
||||
"@manypkg/get-packages": "^1.1.3",
|
||||
"@types/global-agent": "^2.1.3",
|
||||
"@useoptic/optic": "^1.0.0"
|
||||
"@useoptic/optic": "^1.0.0",
|
||||
"yaml": "^2.7.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "workspace:*",
|
||||
|
||||
Vendored
+9
@@ -43,6 +43,15 @@ export interface Config {
|
||||
*/
|
||||
identityTokenAlgorithm?: string;
|
||||
|
||||
/**
|
||||
* Whether to omit the entity ownership references (`ent`) claim from the
|
||||
* identity token. If this is enabled the `ent` claim will only be available
|
||||
* via the user info endpoint and the `UserInfoService`.
|
||||
*
|
||||
* Defaults to `false`.
|
||||
*/
|
||||
omitIdentityTokenOwnershipClaim?: boolean;
|
||||
|
||||
/** To control how to store JWK data in auth-backend */
|
||||
keyStore?: {
|
||||
provider?: 'database' | 'memory' | 'firestore' | 'static';
|
||||
|
||||
@@ -69,6 +69,7 @@
|
||||
"@backstage/backend-test-utils": "workspace:^",
|
||||
"@backstage/cli": "workspace:^",
|
||||
"@backstage/plugin-auth-backend-module-google-provider": "workspace:^",
|
||||
"@backstage/plugin-auth-backend-module-guest-provider": "workspace:^",
|
||||
"@types/cookie-parser": "^1.4.2",
|
||||
"@types/express": "^4.17.6",
|
||||
"@types/express-session": "^1.17.2",
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
import { mockServices, startTestBackend } from '@backstage/backend-test-utils';
|
||||
import request from 'supertest';
|
||||
import { authPlugin } from './authPlugin';
|
||||
import authModuleGuestProvider from '@backstage/plugin-auth-backend-module-guest-provider';
|
||||
import { authServiceFactory } from '@backstage/backend-defaults/auth';
|
||||
|
||||
describe('authPlugin', () => {
|
||||
it('should provide an OpenID configuration', async () => {
|
||||
@@ -42,4 +44,125 @@ describe('authPlugin', () => {
|
||||
issuer: `http://localhost:${server.port()}/api/auth`,
|
||||
});
|
||||
});
|
||||
|
||||
describe('mock provider', () => {
|
||||
const mockProvidersConfig = {
|
||||
environment: 'test',
|
||||
providers: {
|
||||
guest: {
|
||||
dangerouslyAllowOutsideDevelopment: true,
|
||||
userEntityRef: 'user:default/tester',
|
||||
ownershipEntityRefs: [
|
||||
'group:default/testers',
|
||||
'group:default/testers2',
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const expectedIdentity = {
|
||||
type: 'user',
|
||||
userEntityRef: 'user:default/tester',
|
||||
ownershipEntityRefs: ['group:default/testers', 'group:default/testers2'],
|
||||
};
|
||||
|
||||
it('should return tokens with all identity claims by default', async () => {
|
||||
const { server } = await startTestBackend({
|
||||
features: [
|
||||
authPlugin,
|
||||
authModuleGuestProvider,
|
||||
authServiceFactory,
|
||||
mockServices.rootConfig.factory({
|
||||
data: {
|
||||
app: {
|
||||
baseUrl: 'http://localhost',
|
||||
},
|
||||
auth: {
|
||||
...mockProvidersConfig,
|
||||
},
|
||||
},
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
const refreshRes = await request(server).post('/api/auth/guest/refresh');
|
||||
expect(refreshRes.status).toBe(200);
|
||||
expect(refreshRes.body).toMatchObject({
|
||||
backstageIdentity: {
|
||||
expiresInSeconds: expect.any(Number),
|
||||
identity: expectedIdentity,
|
||||
token: expect.any(String),
|
||||
},
|
||||
profile: {},
|
||||
});
|
||||
|
||||
const token = refreshRes.body.backstageIdentity.token;
|
||||
const decoded = JSON.parse(atob(token.split('.')[1]));
|
||||
expect(decoded.sub).toEqual(expectedIdentity.userEntityRef);
|
||||
expect(decoded.ent).toEqual(expectedIdentity.ownershipEntityRefs);
|
||||
|
||||
const userInfoRes = await request(server)
|
||||
.get('/api/auth/v1/userinfo')
|
||||
.set('Authorization', `Bearer ${token}`);
|
||||
|
||||
expect(userInfoRes.status).toBe(200);
|
||||
expect(userInfoRes.body).toMatchObject({
|
||||
claims: {
|
||||
sub: expectedIdentity.userEntityRef,
|
||||
ent: expectedIdentity.ownershipEntityRefs,
|
||||
exp: expect.any(Number),
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should omit ownership claims from the token when the config is set', async () => {
|
||||
const { server } = await startTestBackend({
|
||||
features: [
|
||||
authPlugin,
|
||||
authModuleGuestProvider,
|
||||
authServiceFactory,
|
||||
mockServices.rootConfig.factory({
|
||||
data: {
|
||||
app: {
|
||||
baseUrl: 'http://localhost',
|
||||
},
|
||||
auth: {
|
||||
omitIdentityTokenOwnershipClaim: true,
|
||||
...mockProvidersConfig,
|
||||
},
|
||||
},
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
const refreshRes = await request(server).post('/api/auth/guest/refresh');
|
||||
expect(refreshRes.status).toBe(200);
|
||||
expect(refreshRes.body).toMatchObject({
|
||||
backstageIdentity: {
|
||||
expiresInSeconds: expect.any(Number),
|
||||
identity: expectedIdentity,
|
||||
token: expect.any(String),
|
||||
},
|
||||
profile: {},
|
||||
});
|
||||
|
||||
const token = refreshRes.body.backstageIdentity.token;
|
||||
const decoded = JSON.parse(atob(token.split('.')[1]));
|
||||
expect(decoded.sub).toEqual(expectedIdentity.userEntityRef);
|
||||
expect(decoded.ent).toBeUndefined();
|
||||
|
||||
const userInfoRes = await request(server)
|
||||
.get('/api/auth/v1/userinfo')
|
||||
.set('Authorization', `Bearer ${token}`);
|
||||
|
||||
expect(userInfoRes.status).toBe(200);
|
||||
expect(userInfoRes.body).toMatchObject({
|
||||
claims: {
|
||||
sub: expectedIdentity.userEntityRef,
|
||||
ent: expectedIdentity.ownershipEntityRefs,
|
||||
exp: expect.any(Number),
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -83,7 +83,7 @@ describe('StaticTokenIssuer', () => {
|
||||
options,
|
||||
staticKeyStore as unknown as StaticKeyStore,
|
||||
);
|
||||
const token = await issuer.issueToken({
|
||||
const { token } = await issuer.issueToken({
|
||||
claims: {
|
||||
sub: entityRef,
|
||||
ent: [entityRef],
|
||||
|
||||
@@ -20,7 +20,10 @@ import { parseEntityRef } from '@backstage/catalog-model';
|
||||
import { AuthenticationError } from '@backstage/errors';
|
||||
import { LoggerService } from '@backstage/backend-plugin-api';
|
||||
import { StaticKeyStore } from './StaticKeyStore';
|
||||
import { TokenParams } from '@backstage/plugin-auth-node';
|
||||
import {
|
||||
BackstageSignInResult,
|
||||
TokenParams,
|
||||
} from '@backstage/plugin-auth-node';
|
||||
|
||||
const MS_IN_S = 1000;
|
||||
|
||||
@@ -56,7 +59,7 @@ export class StaticTokenIssuer implements TokenIssuer {
|
||||
this.keyStore = keyStore;
|
||||
}
|
||||
|
||||
public async issueToken(params: TokenParams): Promise<string> {
|
||||
public async issueToken(params: TokenParams): Promise<BackstageSignInResult> {
|
||||
const key = await this.getSigningKey();
|
||||
|
||||
// TODO: code shared with TokenFactory.ts
|
||||
@@ -81,7 +84,15 @@ export class StaticTokenIssuer implements TokenIssuer {
|
||||
throw new AuthenticationError('No algorithm was provided in the key');
|
||||
}
|
||||
|
||||
return new SignJWT({ ...additionalClaims, iss, sub, ent, aud, iat, exp })
|
||||
const token = await new SignJWT({
|
||||
...additionalClaims,
|
||||
iss,
|
||||
sub,
|
||||
ent,
|
||||
aud,
|
||||
iat,
|
||||
exp,
|
||||
})
|
||||
.setProtectedHeader({ alg: key.alg, kid: key.kid })
|
||||
.setIssuer(iss)
|
||||
.setAudience(aud)
|
||||
@@ -89,6 +100,7 @@ export class StaticTokenIssuer implements TokenIssuer {
|
||||
.setIssuedAt(iat)
|
||||
.setExpirationTime(exp)
|
||||
.sign(await importJWK(key));
|
||||
return { token };
|
||||
}
|
||||
|
||||
private async getSigningKey(): Promise<JWK> {
|
||||
|
||||
@@ -60,7 +60,7 @@ describe('TokenFactory', () => {
|
||||
});
|
||||
|
||||
await expect(factory.listPublicKeys()).resolves.toEqual({ keys: [] });
|
||||
const token = await factory.issueToken({
|
||||
const { token, identity } = await factory.issueToken({
|
||||
claims: {
|
||||
sub: entityRef,
|
||||
ent: [entityRef],
|
||||
@@ -68,6 +68,11 @@ describe('TokenFactory', () => {
|
||||
aud: 'this value will be overridden',
|
||||
},
|
||||
});
|
||||
expect(identity).toEqual({
|
||||
type: 'user',
|
||||
userEntityRef: entityRef,
|
||||
ownershipEntityRefs: [entityRef],
|
||||
});
|
||||
|
||||
const { keys } = await factory.listPublicKeys();
|
||||
const keyStore = createLocalJWKSet({ keys: keys });
|
||||
@@ -137,10 +142,10 @@ describe('TokenFactory', () => {
|
||||
userInfoDatabaseHandler: mockUserInfoDatabaseHandler,
|
||||
});
|
||||
|
||||
const token1 = await factory.issueToken({
|
||||
const { token: token1 } = await factory.issueToken({
|
||||
claims: { sub: entityRef },
|
||||
});
|
||||
const token2 = await factory.issueToken({
|
||||
const { token: token2 } = await factory.issueToken({
|
||||
claims: { sub: entityRef },
|
||||
});
|
||||
expect(jwtKid(token1)).toBe(jwtKid(token2));
|
||||
@@ -159,7 +164,7 @@ describe('TokenFactory', () => {
|
||||
keys: [],
|
||||
});
|
||||
|
||||
const token3 = await factory.issueToken({
|
||||
const { token: token3 } = await factory.issueToken({
|
||||
claims: { sub: entityRef },
|
||||
});
|
||||
expect(jwtKid(token3)).not.toBe(jwtKid(token2));
|
||||
@@ -236,7 +241,7 @@ describe('TokenFactory', () => {
|
||||
userInfoDatabaseHandler: mockUserInfoDatabaseHandler,
|
||||
});
|
||||
|
||||
const token = await factory.issueToken({
|
||||
const { token } = await factory.issueToken({
|
||||
claims: { sub: entityRef, ent: [entityRef] },
|
||||
});
|
||||
|
||||
|
||||
@@ -29,7 +29,11 @@ import { omit } from 'lodash';
|
||||
import { DateTime } from 'luxon';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import { LoggerService } from '@backstage/backend-plugin-api';
|
||||
import { TokenParams, tokenTypes } from '@backstage/plugin-auth-node';
|
||||
import {
|
||||
BackstageSignInResult,
|
||||
TokenParams,
|
||||
tokenTypes,
|
||||
} from '@backstage/plugin-auth-node';
|
||||
import { AnyJWK, KeyStore, TokenIssuer } from './types';
|
||||
import { JsonValue } from '@backstage/types';
|
||||
import { UserInfoDatabaseHandler } from './UserInfoDatabaseHandler';
|
||||
@@ -119,6 +123,10 @@ type Options = {
|
||||
* If not, add a knex migration file in the migrations folder.
|
||||
* More info on supported algorithms: https://github.com/panva/jose */
|
||||
algorithm?: string;
|
||||
/**
|
||||
* A list of claims to omit from issued tokens and only store in the user info database
|
||||
*/
|
||||
omitClaimsFromToken?: string[];
|
||||
userInfoDatabaseHandler: UserInfoDatabaseHandler;
|
||||
};
|
||||
|
||||
@@ -142,6 +150,7 @@ export class TokenFactory implements TokenIssuer {
|
||||
private readonly keyStore: KeyStore;
|
||||
private readonly keyDurationSeconds: number;
|
||||
private readonly algorithm: string;
|
||||
private readonly omitClaimsFromToken?: string[];
|
||||
private readonly userInfoDatabaseHandler: UserInfoDatabaseHandler;
|
||||
|
||||
private keyExpiry?: Date;
|
||||
@@ -153,10 +162,11 @@ export class TokenFactory implements TokenIssuer {
|
||||
this.keyStore = options.keyStore;
|
||||
this.keyDurationSeconds = options.keyDurationSeconds;
|
||||
this.algorithm = options.algorithm ?? 'ES256';
|
||||
this.omitClaimsFromToken = options.omitClaimsFromToken;
|
||||
this.userInfoDatabaseHandler = options.userInfoDatabaseHandler;
|
||||
}
|
||||
|
||||
async issueToken(params: TokenParams): Promise<string> {
|
||||
async issueToken(params: TokenParams): Promise<BackstageSignInResult> {
|
||||
const key = await this.getKey();
|
||||
|
||||
const iss = this.issuer;
|
||||
@@ -203,7 +213,10 @@ export class TokenFactory implements TokenIssuer {
|
||||
uip,
|
||||
};
|
||||
|
||||
const token = await new SignJWT(claims)
|
||||
const tokenClaims = this.omitClaimsFromToken
|
||||
? omit(claims, this.omitClaimsFromToken)
|
||||
: claims;
|
||||
const token = await new SignJWT(tokenClaims)
|
||||
.setProtectedHeader({
|
||||
typ: tokenTypes.user.typParam,
|
||||
alg: key.alg,
|
||||
@@ -214,7 +227,7 @@ export class TokenFactory implements TokenIssuer {
|
||||
if (token.length > MAX_TOKEN_LENGTH) {
|
||||
throw new Error(
|
||||
`Failed to issue a new user token. The resulting token is excessively large, with either too many ownership claims or too large custom claims. You likely have a bug either in the sign-in resolver or catalog data. The following claims were requested: '${JSON.stringify(
|
||||
claims,
|
||||
tokenClaims,
|
||||
)}'`,
|
||||
);
|
||||
}
|
||||
@@ -225,7 +238,14 @@ export class TokenFactory implements TokenIssuer {
|
||||
claims: omit(claims, ['aud', 'iat', 'iss', 'uip']),
|
||||
});
|
||||
|
||||
return token;
|
||||
return {
|
||||
token,
|
||||
identity: {
|
||||
type: 'user',
|
||||
userEntityRef: sub,
|
||||
ownershipEntityRefs: ent,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// This will be called by other services that want to verify ID tokens.
|
||||
|
||||
@@ -14,7 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { TokenParams } from '@backstage/plugin-auth-node';
|
||||
import {
|
||||
BackstageUserIdentity,
|
||||
TokenParams,
|
||||
} from '@backstage/plugin-auth-node';
|
||||
|
||||
/** Represents any form of serializable JWK */
|
||||
export interface AnyJWK extends Record<string, string> {
|
||||
@@ -31,7 +34,9 @@ export type TokenIssuer = {
|
||||
/**
|
||||
* Issues a new ID Token
|
||||
*/
|
||||
issueToken(params: TokenParams): Promise<string>;
|
||||
issueToken(
|
||||
params: TokenParams,
|
||||
): Promise<{ token: string; identity?: BackstageUserIdentity }>;
|
||||
|
||||
/**
|
||||
* List all public keys that are currently being used to sign tokens, or have been used
|
||||
|
||||
@@ -77,8 +77,7 @@ export class CatalogAuthResolverContext implements AuthResolverContext {
|
||||
) {}
|
||||
|
||||
async issueToken(params: TokenParams) {
|
||||
const token = await this.tokenIssuer.issueToken(params);
|
||||
return { token };
|
||||
return await this.tokenIssuer.issueToken(params);
|
||||
}
|
||||
|
||||
async findCatalogUser(query: AuthResolverCatalogUserQuery) {
|
||||
@@ -147,13 +146,12 @@ export class CatalogAuthResolverContext implements AuthResolverContext {
|
||||
entity,
|
||||
);
|
||||
|
||||
const token = await this.tokenIssuer.issueToken({
|
||||
return await this.tokenIssuer.issueToken({
|
||||
claims: {
|
||||
sub: stringifyEntityRef(entity),
|
||||
ent: ownershipEntityRefs,
|
||||
},
|
||||
});
|
||||
return { token };
|
||||
}
|
||||
|
||||
async resolveOwnershipEntityRefs(
|
||||
|
||||
@@ -101,6 +101,11 @@ export async function createRouter(
|
||||
tokenFactoryAlgorithm ??
|
||||
config.getOptionalString('auth.identityTokenAlgorithm'),
|
||||
userInfoDatabaseHandler,
|
||||
omitClaimsFromToken: config.getOptionalBoolean(
|
||||
'auth.omitIdentityTokenOwnershipClaim',
|
||||
)
|
||||
? ['ent']
|
||||
: [],
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -104,9 +104,7 @@ export type AuthResolverCatalogUserQuery =
|
||||
|
||||
// @public
|
||||
export type AuthResolverContext = {
|
||||
issueToken(params: TokenParams): Promise<{
|
||||
token: string;
|
||||
}>;
|
||||
issueToken(params: TokenParams): Promise<BackstageSignInResult>;
|
||||
findCatalogUser(query: AuthResolverCatalogUserQuery): Promise<{
|
||||
entity: Entity;
|
||||
}>;
|
||||
@@ -126,6 +124,7 @@ export interface BackstageIdentityResponse extends BackstageSignInResult {
|
||||
|
||||
// @public
|
||||
export interface BackstageSignInResult {
|
||||
identity?: BackstageUserIdentity;
|
||||
token: string;
|
||||
}
|
||||
|
||||
|
||||
@@ -44,6 +44,30 @@ describe('prepareBackstageIdentityResponse', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('uses the identity in the result if present', () => {
|
||||
jest.spyOn(Date, 'now').mockReturnValue(5000);
|
||||
|
||||
const token = mkToken({ sub: 'k:ns/n', ent: ['k:ns/o'], exp: 1005 });
|
||||
expect(
|
||||
prepareBackstageIdentityResponse({
|
||||
token,
|
||||
identity: {
|
||||
type: 'user',
|
||||
userEntityRef: 'k:ns/other',
|
||||
ownershipEntityRefs: ['k:ns/group1', 'k:ns/group2'],
|
||||
},
|
||||
}),
|
||||
).toEqual({
|
||||
token,
|
||||
expiresInSeconds: 1000,
|
||||
identity: {
|
||||
type: 'user',
|
||||
userEntityRef: 'k:ns/other',
|
||||
ownershipEntityRefs: ['k:ns/group1', 'k:ns/group2'],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should reject tokens without subject', () => {
|
||||
const token = mkToken({});
|
||||
expect(() =>
|
||||
|
||||
@@ -57,7 +57,7 @@ export function prepareBackstageIdentityResponse(
|
||||
return {
|
||||
...result,
|
||||
expiresInSeconds: exp,
|
||||
identity: {
|
||||
identity: result.identity ?? {
|
||||
type: 'user',
|
||||
userEntityRef: sub,
|
||||
ownershipEntityRefs: ent,
|
||||
|
||||
@@ -34,6 +34,12 @@ export interface BackstageSignInResult {
|
||||
* The token used to authenticate the user within Backstage.
|
||||
*/
|
||||
token: string;
|
||||
|
||||
/**
|
||||
* Identity information to pass to the client rather than using the
|
||||
* information that's embeeded in the token.
|
||||
*/
|
||||
identity?: BackstageUserIdentity;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -141,7 +147,7 @@ export type AuthResolverContext = {
|
||||
/**
|
||||
* Issues a Backstage token using the provided parameters.
|
||||
*/
|
||||
issueToken(params: TokenParams): Promise<{ token: string }>;
|
||||
issueToken(params: TokenParams): Promise<BackstageSignInResult>;
|
||||
|
||||
/**
|
||||
* Finds a single user in the catalog using the provided query.
|
||||
|
||||
@@ -27,16 +27,14 @@ Please find all possible webhook event types at the
|
||||
yarn --cwd packages/backend add @backstage/plugin-events-backend-module-github
|
||||
```
|
||||
|
||||
### Event Router
|
||||
|
||||
```ts
|
||||
// packages/backend/src/index.ts
|
||||
import { eventsModuleGithubEventRouter } from '@backstage/plugin-events-backend-module-github/alpha';
|
||||
// ...
|
||||
backend.add(eventsModuleGithubEventRouter);
|
||||
backend.add(import('@backstage/plugin-events-backend-module-github'));
|
||||
```
|
||||
|
||||
#### Legacy Backend System
|
||||
### Legacy Backend System
|
||||
|
||||
#### Event Router
|
||||
|
||||
```ts
|
||||
// packages/backend/src/plugins/events.ts
|
||||
@@ -44,16 +42,7 @@ const eventRouter = new GithubEventRouter({ events: env.events });
|
||||
await eventRouter.subscribe();
|
||||
```
|
||||
|
||||
### Signature Validator
|
||||
|
||||
```ts
|
||||
// packages/backend/src/index.ts
|
||||
import { eventsModuleGithubWebhook } from '@backstage/plugin-events-backend-module-github/alpha';
|
||||
// ...
|
||||
backend.add(eventsModuleGithubWebhook);
|
||||
```
|
||||
|
||||
#### Legacy Backend System
|
||||
#### Signature Validator
|
||||
|
||||
Add the signature validator for the topic `github`:
|
||||
|
||||
|
||||
@@ -5477,6 +5477,7 @@ __metadata:
|
||||
"@backstage/config": "workspace:^"
|
||||
"@backstage/errors": "workspace:^"
|
||||
"@backstage/plugin-auth-backend-module-google-provider": "workspace:^"
|
||||
"@backstage/plugin-auth-backend-module-guest-provider": "workspace:^"
|
||||
"@backstage/plugin-auth-node": "workspace:^"
|
||||
"@backstage/plugin-catalog-node": "workspace:^"
|
||||
"@backstage/types": "workspace:^"
|
||||
@@ -43610,6 +43611,7 @@ __metadata:
|
||||
sort-package-json: "npm:^2.8.0"
|
||||
typedoc: "npm:^0.27.6"
|
||||
typescript: "npm:~5.6.0"
|
||||
yaml: "npm:^2.7.0"
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
|
||||
Reference in New Issue
Block a user