Merge branch 'master' into scaffolderPromMetrics

Signed-off-by: spencerrichardhenry <46569542+spencerrichardhenry@users.noreply.github.com>
This commit is contained in:
spencerrichardhenry
2022-10-19 13:38:32 -06:00
committed by GitHub
920 changed files with 38180 additions and 8196 deletions
@@ -12,7 +12,7 @@ Using Cookiecutter extensions is a two-step process:
This step depends on how the scaffolder is setup to use Cookiecutter:
- Using a local Cookiecutter, or
- Using a Cookiecutter Docker image, e.g. [spotify/backstage-cookiecutter](https://github.com/backstage/backstage/blob/37e35b91/plugins/scaffolder-backend/scripts/Cookiecutter.dockerfile).
- Using a Cookiecutter Docker image, e.g. [spotify/backstage-cookiecutter](https://github.com/backstage/backstage/blob/master/plugins/scaffolder-backend/scripts/Cookiecutter.dockerfile).
Say we want to install [`jinja2_custom_filters_extension`](https://pypi.org/project/jinja2-custom-filters-extension/) to use the `upper_case_first_letter` filter in a Cookiecutter template.
@@ -8,30 +8,28 @@ API requests from frontend plugins include an authorization header with a Backst
As techdocs HTML pages load assets without an Authorization header the code below also sets a token cookie when the user logs in (and when the token is about to expire).
Create `packages/backend/src/authMiddleware.ts`:
```typescript
// packages/backend/src/index.ts from a create-app deployment
import cookieParser from 'cookie-parser';
import { Request, Response, NextFunction } from 'express';
import { JWT } from 'jose';
import { URL } from 'url';
import { SingleHostDiscovery } from '@backstage/backend-common';
import type { Config } from '@backstage/config';
import {
IdentityClient,
getBearerTokenFromAuthorizationHeader,
IdentityClient,
} from '@backstage/plugin-auth-node';
// ...
import { NextFunction, Request, Response, RequestHandler } from 'express';
import { decodeJwt } from 'jose';
import { URL } from 'url';
import { PluginEnvironment } from './types';
function setTokenCookie(
res: Response,
options: { token: string; secure: boolean; cookieDomain: string },
) {
try {
const payload = JWT.decode(options.token) as object & {
exp: number;
};
res.cookie(`token`, options.token, {
expires: new Date(payload?.exp ? payload?.exp * 1000 : 0),
const payload = decodeJwt(options.token);
res.cookie('token', options.token, {
expires: new Date(payload.exp ? payload.exp * 1000 : 0),
secure: options.secure,
sameSite: 'lax',
domain: options.cookieDomain,
@@ -43,9 +41,10 @@ function setTokenCookie(
}
}
async function main() {
// ...
export const createAuthMiddleware = async (
config: Config,
appEnv: PluginEnvironment,
) => {
const discovery = SingleHostDiscovery.fromConfig(config);
const identity = IdentityClient.create({
discovery,
@@ -54,7 +53,7 @@ async function main() {
const baseUrl = config.getString('backend.baseUrl');
const secure = baseUrl.startsWith('https://');
const cookieDomain = new URL(baseUrl).hostname;
const authMiddleware = async (
const authMiddleware: RequestHandler = async (
req: Request,
res: Response,
next: NextFunction,
@@ -62,13 +61,21 @@ async function main() {
try {
const token =
getBearerTokenFromAuthorizationHeader(req.headers.authorization) ||
req.cookies['token'];
req.user = await identity.authenticate(token);
(req.cookies.token as string | undefined);
if (!token) {
res.status(401).send('Unauthorized');
return;
}
try {
req.user = await identity.authenticate(token);
} catch {
await appEnv.tokenManager.authenticate(token);
}
if (!req.headers.authorization) {
// Authorization header may be forwarded by plugin requests
req.headers.authorization = `Bearer ${token}`;
}
if (token !== req.cookies['token']) {
if (token && token !== req.cookies.token) {
setTokenCookie(res, {
token,
secure,
@@ -77,9 +84,24 @@ async function main() {
}
next();
} catch (error) {
res.status(401).send(`Unauthorized`);
res.status(401).send('Unauthorized');
}
};
return authMiddleware;
};
```
```typescript
// packages/backend/src/index.ts from a create-app deployment
import { createAuthMiddleware } from './authMiddleware';
// ...
async function main() {
// ...
const authMiddleware = await createAuthMiddleware(config, appEnv);
const apiRouter = Router();
apiRouter.use(cookieParser());
@@ -99,12 +121,10 @@ async function main() {
}
```
Create `packages/app/src/cookieAuth.ts`:
```typescript
// packages/app/src/App.tsx from a create-app deployment
import { discoveryApiRef, useApi } from '@backstage/core-plugin-api';
// ...
import type { IdentityApi } from '@backstage/core-plugin-api';
// Parses supplied JWT token and returns the payload
function parseJwt(token: string): { exp: number } {
@@ -113,9 +133,11 @@ function parseJwt(token: string): { exp: number } {
const jsonPayload = decodeURIComponent(
atob(base64)
.split('')
.map(function (c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
})
.map(
c =>
// eslint-disable-next-line prefer-template
'%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2),
)
.join(''),
);
@@ -132,7 +154,7 @@ function msUntilExpiry(token: string): number {
// Calls the specified url regularly using an auth token to set a token cookie
// to authorize regular HTTP requests when loading techdocs
async function setTokenCookie(url: string, identityApi: IdentityApi) {
export async function setTokenCookie(url: string, identityApi: IdentityApi) {
const { token } = await identityApi.getCredentials();
if (!token) {
return;
@@ -155,6 +177,14 @@ async function setTokenCookie(url: string, identityApi: IdentityApi) {
ms > 0 ? ms : 10000,
);
}
```
```typescript
// packages/app/src/App.tsx from a create-app deployment
import { setTokenCookie } from './cookieAuth';
// ...
const app = createApp({
// ...
+31 -4
View File
@@ -2,20 +2,47 @@
## Overview
The Orphan Clean Up script is a basic PowerShell script to delete orphaned entities in the catalog. This script also assumes that you do not have authentication setup for your Backstage API endpoints.
The Orphan Clean Up scripts are a basic scripts to delete orphaned entities in the catalog.
This script also assumes that you do not have authentication setup for your Backstage API endpoints.
_Warning:_ There is a risk of entities being orphaned (and being deleted by this script) in case of the location having problems and returning a 404 status code. This might lead to accidental deletion of entities until the processing loop has recreated the entity.
## Requirements
## PowerShell
A PowerShell implementation of the orphan cleanup script.
### Requirements
This script is PowerShell based so therefore needs to be ran in a PowerShell session. If you are not able to use PowerShell the script should give you a clear idea as to how to create it with another scripting language like Bash.
## Usage
### Usage
Here's how to use the script:
1. Download the script
1. Download the `OrphanCleanUp.ps1` script
2. Now start a PowerShell session
3. Next navigate to the location you downloaded the script
4. Then run this command replacing `https:\\backstage.my-company.com` with the URL of your Backstage instance: `.\OrphanCleanUp.ps1 https:\\backstage.my-company.com`
5. The script will output the number of orphaned entities it finds and then the name for each one it deletes
## Bash
A bash implementation of the orphan cleanup script.
### Requirements
This script is shell based and requires the following programs to be installed on your system:
- curl
- jq
### Usage
Here's how to use the script:
1. Download the `orphan_cleanup.sh` script
2. Now start a bash session
3. Next navigate to the location you downloaded the script
4. Then run this command replacing `https://backstage.my-company.com` with the URL of your Backstage instance: `./orphan_cleanup.sh https://backstage.my-company.com`
5. The script will output the number of orphaned entities it finds and then the name for each one it deletes
+22
View File
@@ -0,0 +1,22 @@
#!/bin/bash
set -euo pipefail
# Cleanes up orphaned entities for the provided Backstage URL, defaults to the local backend
BACKSTAGE_URL=${1:-'http://localhost:7007'}
echo $BACKSTAGE_URL
ORPHAN_API_URL="$BACKSTAGE_URL/api/catalog/entities?filter=metadata.annotations.backstage.io/orphan=true"
ORPHAN_DELETE_API_URL="$BACKSTAGE_URL/api/catalog/entities/by-uid"
ORPHANS=$(curl -s $ORPHAN_API_URL)
echo ""
echo "Found $(echo $ORPHANS | jq length ) orphaned entities"
echo ""
jq -c '.[]' <<< $ORPHANS | while read ORPHAN; do
echo $ORPHAN | jq "."
echo "Deleting orphan entity: $(echo $ORPHAN | jq -r .metadata.name) of kind: $(echo $ORPHAN | jq -r .kind)"
curl -X DELETE "$ORPHAN_DELETE_API_URL/$(echo $ORPHAN | jq -r .metadata.uid)"
done
@@ -0,0 +1,30 @@
# Upgrade Backstage App
## Overview
The script upgrades the version of Backstage created via the create-app plugin. It lets you resolve conflicts iteratively with your own merge [tool](https://www.git-scm.com/docs/git-mergetool).
## Requirements
You will need to have the following tools in your shell environment:
- git
- curl
- jq
## Usage
Here's how to use the script:
1. download the script
2. copy it in the root of your app
3. bootstrap a git repository (you may already have done so):
```bash
git init
git add .
git commit -m "initial commit"
```
4. run `sh upgrade-backstage-app.sh [optional-backstage-version]`
5. resolve any conflicts iteratively
@@ -0,0 +1,15 @@
#!/bin/sh
CURRENT_VERSION="v$(cat backstage.json | jq -r '.version')"
TARGET_VERSION=${1:-"$(curl -s https://api.github.com/repos/backstage/backstage/releases/latest | jq -r '.tag_name')"}
CREATE_APP_CURRENT_VERSION=$(curl -s https://raw.githubusercontent.com/backstage/backstage/$CURRENT_VERSION/packages/create-app/package.json | jq -r '.version')
CREATE_APP_TARGET_VERSION=$(curl -s https://raw.githubusercontent.com/backstage/backstage/$TARGET_VERSION/packages/create-app/package.json | jq -r '.version')
if [ "$CURRENT_VERSION" == "$TARGET_VERSION" ]; then
echo "Already up to date"
else
echo "Attempting upgrade from Backstage $CURRENT_VERSION (create-app $CREATE_APP_CURRENT_VERSION) to $TARGET_VERSION ($CREATE_APP_TARGET_VERSION)"
rm -rf .upgrade && mkdir .upgrade
curl -s https://raw.githubusercontent.com/backstage/upgrade-helper-diff/master/diffs/$CREATE_APP_CURRENT_VERSION..$CREATE_APP_TARGET_VERSION.diff > .upgrade/upgrade.diff
git apply -3 .upgrade/upgrade.diff
git mergetool
fi