From 16054a87ca9fa1ec7dd20e640268ff69b021ecf5 Mon Sep 17 00:00:00 2001 From: Ivan Shmidt Date: Wed, 17 Jun 2020 21:21:32 +0200 Subject: [PATCH 01/25] feat(scaffolder): load data from catalog api --- plugins/scaffolder/package.json | 2 + .../src/components/ScaffolderPage/index.tsx | 70 ++++++++++++------- .../src/components/TemplateCard.tsx | 2 +- 3 files changed, 47 insertions(+), 27 deletions(-) diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index 84132a42f9..87ce329b39 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -22,7 +22,9 @@ "clean": "backstage-cli clean" }, "dependencies": { + "@backstage/catalog-model": "^0.1.1-alpha.9", "@backstage/core": "^0.1.1-alpha.9", + "@backstage/plugin-catalog": "^0.1.1-alpha.9", "@backstage/theme": "^0.1.1-alpha.9", "@material-ui/core": "^4.9.1", "@material-ui/icons": "^4.9.1", diff --git a/plugins/scaffolder/src/components/ScaffolderPage/index.tsx b/plugins/scaffolder/src/components/ScaffolderPage/index.tsx index aa1cf36082..15d2efe1f4 100644 --- a/plugins/scaffolder/src/components/ScaffolderPage/index.tsx +++ b/plugins/scaffolder/src/components/ScaffolderPage/index.tsx @@ -22,24 +22,38 @@ import { Header, Page, pageTheme, + useApi, } from '@backstage/core'; -import { Typography, Link, Button } from '@material-ui/core'; +import { catalogApiRef } from '@backstage/plugin-catalog'; +import { + Typography, + Link, + Button, + Grid, + LinearProgress, +} from '@material-ui/core'; import { Link as RouterLink } from 'react-router-dom'; import TemplateCard from '../TemplateCard'; +import { useAsync } from 'react-use'; +import { TemplateEntityV1alpha1 } from '@backstage/catalog-model'; -// TODO(blam): Connect to backend -const STATIC_DATA = [ - { - id: 'react-ssr-template', - type: 'web-infra', - name: 'SSR React Website', - tags: ['Experimental'], - description: - 'Next.js application skeleton for creating isomorphic web applications.', - ownerId: 'something', - }, -]; const ScaffolderPage: React.FC<{}> = () => { + const catalogApi = useApi(catalogApiRef); + + const { value, loading } = useAsync(async () => { + const entities = await catalogApi.getEntities({ kind: 'Template' }); + return (entities as TemplateEntityV1alpha1[]).map(template => ({ + id: template.metadata.uid, + type: template.spec.type, + name: template.metadata.name, + // TODO(shmidt-i): decide on tags + tags: ['not-implemented'], + description: template.metadata.description ?? '-', + // TODO(shmidt-i): decide on owner + ownerId: '-', + })); + }); + return (
= () => { . -
- {STATIC_DATA.map(item => { - return ( - - ); - })} -
+ {loading ? ( + + ) : ( + + {value!.map(item => { + return ( + + ); + })} + + )} ); diff --git a/plugins/scaffolder/src/components/TemplateCard.tsx b/plugins/scaffolder/src/components/TemplateCard.tsx index 56d8907f7b..618eda64f1 100644 --- a/plugins/scaffolder/src/components/TemplateCard.tsx +++ b/plugins/scaffolder/src/components/TemplateCard.tsx @@ -67,7 +67,7 @@ const TemplateCard: FC = ({
{tags?.map(tag => ( - + ))} {description} From 2808d8aa06c931dbe176b3a5dc999e193dd5dae9 Mon Sep 17 00:00:00 2001 From: Ivan Shmidt Date: Sat, 20 Jun 2020 13:55:22 +0200 Subject: [PATCH 02/25] feat(scaffolder): use swr, pretty template mocks, move out grid item --- .../react-ssr-template/template.yaml | 6 +- .../springboot-template/template.yaml | 12 ++++ plugins/scaffolder-backend/scripts/mock-data | 16 +++-- plugins/scaffolder/package.json | 3 +- .../src/components/ScaffolderPage/index.tsx | 62 ++++++++++--------- .../src/components/TemplateCard.tsx | 43 +++++-------- 6 files changed, 78 insertions(+), 64 deletions(-) create mode 100644 plugins/scaffolder-backend/sample-templates/springboot-template/template.yaml diff --git a/plugins/scaffolder-backend/sample-templates/react-ssr-template/template.yaml b/plugins/scaffolder-backend/sample-templates/react-ssr-template/template.yaml index 17f9ebbf7d..058e2a715f 100644 --- a/plugins/scaffolder-backend/sample-templates/react-ssr-template/template.yaml +++ b/plugins/scaffolder-backend/sample-templates/react-ssr-template/template.yaml @@ -4,7 +4,9 @@ metadata: name: react-ssr-template title: React SSR Template description: Next.js application skeleton for creating isomorphic web applications. + annotations: + tags: Recommended,React spec: - type: cookiecutter + processor: cookiecutter + type: website path: '.' - diff --git a/plugins/scaffolder-backend/sample-templates/springboot-template/template.yaml b/plugins/scaffolder-backend/sample-templates/springboot-template/template.yaml new file mode 100644 index 0000000000..d44d926ef4 --- /dev/null +++ b/plugins/scaffolder-backend/sample-templates/springboot-template/template.yaml @@ -0,0 +1,12 @@ +apiVersion: backstage.io/v1alpha1 +kind: Template +metadata: + name: springboot-template + title: Spring Boot Service + description: Standard Spring Boot (Java) microservice with recommended configuration. + annotations: + tags: Recommended,Java +spec: + processor: cookiecutter + type: service + path: '.' diff --git a/plugins/scaffolder-backend/scripts/mock-data b/plugins/scaffolder-backend/scripts/mock-data index be3fa2b6cf..594bd76607 100755 --- a/plugins/scaffolder-backend/scripts/mock-data +++ b/plugins/scaffolder-backend/scripts/mock-data @@ -1,8 +1,12 @@ #!/usr/bin/env bash -curl \ ---location \ ---request POST 'localhost:7000/catalog/locations' \ ---header 'Content-Type: application/json' \ ---data-raw "{\"type\": \"file\", \"target\": \"$(pwd)/sample-templates/react-ssr-template/template.yaml\"}" - +for URL in \ + 'react-ssr-template' \ + 'springboot-template' \ +; do \ + curl \ + --location \ + --request POST 'localhost:7000/catalog/locations' \ + --header 'Content-Type: application/json' \ + --data-raw "{\"type\": \"file\", \"target\": \"$(pwd)/sample-templates/${URL}/template.yaml\"}" +done diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index 6710fdc1f7..683d277be2 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -31,7 +31,8 @@ "react": "^16.13.1", "react-dom": "^16.13.1", "react-router-dom": "6.0.0-alpha.5", - "react-use": "^14.2.0" + "react-use": "^14.2.0", + "swr": "^0.2.2" }, "devDependencies": { "@backstage/cli": "^0.1.1-alpha.9", diff --git a/plugins/scaffolder/src/components/ScaffolderPage/index.tsx b/plugins/scaffolder/src/components/ScaffolderPage/index.tsx index 1dbd993d93..a6dbac8f83 100644 --- a/plugins/scaffolder/src/components/ScaffolderPage/index.tsx +++ b/plugins/scaffolder/src/components/ScaffolderPage/index.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import React from 'react'; +import React, { useEffect } from 'react'; import { Lifecycle, Content, @@ -24,6 +24,7 @@ import { Page, pageTheme, useApi, + errorApiRef, } from '@backstage/core'; import { catalogApiRef } from '@backstage/plugin-catalog'; import { @@ -35,25 +36,25 @@ import { } from '@material-ui/core'; import { Link as RouterLink } from 'react-router-dom'; import TemplateCard from '../TemplateCard'; -import { useAsync } from 'react-use'; +import useStaleWhileRevalidate from 'swr'; import { TemplateEntityV1alpha1 } from '@backstage/catalog-model'; const ScaffolderPage: React.FC<{}> = () => { const catalogApi = useApi(catalogApiRef); + const errorApi = useApi(errorApiRef); - const { value, loading } = useAsync(async () => { - const entities = await catalogApi.getEntities({ kind: 'Template' }); - return (entities as TemplateEntityV1alpha1[]).map(template => ({ - id: template.metadata.uid, - type: template.spec.type, - name: template.metadata.name, - // TODO(shmidt-i): decide on tags - tags: ['not-implemented'], - description: template.metadata.description ?? '-', - // TODO(shmidt-i): decide on owner - ownerId: '-', - })); - }); + const { data: templates, isValidating, error } = useStaleWhileRevalidate( + 'templates/all', + async () => + catalogApi.getEntities({ kind: 'Template' }) as Promise< + TemplateEntityV1alpha1[] + >, + ); + + useEffect(() => { + if (!error) return; + errorApi.post(error); + }, [error, errorApi]); return ( @@ -89,23 +90,26 @@ const ScaffolderPage: React.FC<{}> = () => { . - {loading ? ( - - ) : ( - - {value!.map(item => { + {isValidating && } + + {templates && + templates.map(template => { return ( - + + + ); })} - - )} + ); diff --git a/plugins/scaffolder/src/components/TemplateCard.tsx b/plugins/scaffolder/src/components/TemplateCard.tsx index 618eda64f1..6d47f05693 100644 --- a/plugins/scaffolder/src/components/TemplateCard.tsx +++ b/plugins/scaffolder/src/components/TemplateCard.tsx @@ -14,14 +14,7 @@ * limitations under the License. */ import React, { FC } from 'react'; -import { - Button, - Card, - Chip, - Grid, - Typography, - makeStyles, -} from '@material-ui/core'; +import { Button, Card, Chip, Typography, makeStyles } from '@material-ui/core'; const useStyles = makeStyles(theme => ({ header: { @@ -59,25 +52,23 @@ const TemplateCard: FC = ({ const classes = useStyles(); return ( - - -
- {type} - {title} + +
+ {type} + {title} +
+
+ {tags?.map(tag => ( + + ))} + + {description} + +
+
-
- {tags?.map(tag => ( - - ))} - - {description} - -
- -
-
- - +
+
); }; From 1088b916e69c7ba046d2f12367a1bf0ffe9a16a1 Mon Sep 17 00:00:00 2001 From: Ivan Shmidt Date: Wed, 24 Jun 2020 23:36:09 +0200 Subject: [PATCH 03/25] feat(scaffolder): tags as list --- .../sample-templates/react-ssr-template/template.yaml | 5 +++-- .../sample-templates/springboot-template/template.yaml | 5 +++-- plugins/scaffolder/src/components/ScaffolderPage/index.tsx | 3 +-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/plugins/scaffolder-backend/sample-templates/react-ssr-template/template.yaml b/plugins/scaffolder-backend/sample-templates/react-ssr-template/template.yaml index 058e2a715f..124d1575ce 100644 --- a/plugins/scaffolder-backend/sample-templates/react-ssr-template/template.yaml +++ b/plugins/scaffolder-backend/sample-templates/react-ssr-template/template.yaml @@ -4,8 +4,9 @@ metadata: name: react-ssr-template title: React SSR Template description: Next.js application skeleton for creating isomorphic web applications. - annotations: - tags: Recommended,React + tags: + - Recommended + - React spec: processor: cookiecutter type: website diff --git a/plugins/scaffolder-backend/sample-templates/springboot-template/template.yaml b/plugins/scaffolder-backend/sample-templates/springboot-template/template.yaml index d44d926ef4..681e8e7f51 100644 --- a/plugins/scaffolder-backend/sample-templates/springboot-template/template.yaml +++ b/plugins/scaffolder-backend/sample-templates/springboot-template/template.yaml @@ -4,8 +4,9 @@ metadata: name: springboot-template title: Spring Boot Service description: Standard Spring Boot (Java) microservice with recommended configuration. - annotations: - tags: Recommended,Java + tags: + - Recommended + - Java spec: processor: cookiecutter type: service diff --git a/plugins/scaffolder/src/components/ScaffolderPage/index.tsx b/plugins/scaffolder/src/components/ScaffolderPage/index.tsx index a6dbac8f83..aa2a8b639a 100644 --- a/plugins/scaffolder/src/components/ScaffolderPage/index.tsx +++ b/plugins/scaffolder/src/components/ScaffolderPage/index.tsx @@ -103,8 +103,7 @@ const ScaffolderPage: React.FC<{}> = () => { }`} type={template.spec.type ?? ''} description={template.metadata.description ?? '-'} - // TODO(shmidt-i): how to store tags - tags={template.metadata.annotations?.tags.split(',') ?? []} + tags={template.metadata?.tags ?? []} /> ); From 515d64e40a657ca0120a7b97a2db010b787dab8f Mon Sep 17 00:00:00 2001 From: Nicholas Pirrello Date: Wed, 24 Jun 2020 22:55:14 -0400 Subject: [PATCH 04/25] Add okta integration --- plugins/auth-backend/package.json | 2 + .../auth-backend/src/providers/factories.ts | 2 + .../auth-backend/src/providers/okta/index.ts | 16 ++ .../src/providers/okta/provider.ts | 208 ++++++++++++++++++ .../src/providers/okta/types.d.ts | 22 ++ plugins/auth-backend/src/providers/types.ts | 4 + plugins/auth-backend/src/service/router.ts | 9 + 7 files changed, 263 insertions(+) create mode 100644 plugins/auth-backend/src/providers/okta/index.ts create mode 100644 plugins/auth-backend/src/providers/okta/provider.ts create mode 100644 plugins/auth-backend/src/providers/okta/types.d.ts diff --git a/plugins/auth-backend/package.json b/plugins/auth-backend/package.json index 2de098c7eb..d137357d60 100644 --- a/plugins/auth-backend/package.json +++ b/plugins/auth-backend/package.json @@ -40,6 +40,8 @@ "passport": "^0.4.1", "passport-github2": "^0.1.12", "passport-google-oauth20": "^2.0.0", + "passport-oauth2": "^1.5.0", + "passport-okta-oauth": "^0.0.1", "passport-saml": "^1.3.3", "uuid": "^8.0.0", "winston": "^3.2.1", diff --git a/plugins/auth-backend/src/providers/factories.ts b/plugins/auth-backend/src/providers/factories.ts index 5096b0698a..9feefdac9f 100644 --- a/plugins/auth-backend/src/providers/factories.ts +++ b/plugins/auth-backend/src/providers/factories.ts @@ -18,6 +18,7 @@ import Router from 'express-promise-router'; import { createGithubProvider } from './github'; import { createGoogleProvider } from './google'; import { createSamlProvider } from './saml'; +import { createOktaProvider } from './okta'; import { AuthProviderFactory, AuthProviderConfig } from './types'; import { Logger } from 'winston'; import { TokenIssuer } from '../identity'; @@ -26,6 +27,7 @@ const factories: { [providerId: string]: AuthProviderFactory } = { google: createGoogleProvider, github: createGithubProvider, saml: createSamlProvider, + okta: createOktaProvider, }; export const createAuthProviderRouter = ( diff --git a/plugins/auth-backend/src/providers/okta/index.ts b/plugins/auth-backend/src/providers/okta/index.ts new file mode 100644 index 0000000000..bc32601ac2 --- /dev/null +++ b/plugins/auth-backend/src/providers/okta/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2020 Spotify AB + * + * 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. + */ +export { createOktaProvider } from './provider'; diff --git a/plugins/auth-backend/src/providers/okta/provider.ts b/plugins/auth-backend/src/providers/okta/provider.ts new file mode 100644 index 0000000000..7b3d5770d7 --- /dev/null +++ b/plugins/auth-backend/src/providers/okta/provider.ts @@ -0,0 +1,208 @@ +/* + * Copyright 2020 Spotify AB + * + * 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. + */ +import express, { Request } from 'express'; +import { OAuthProvider } from '../../lib/OAuthProvider'; +import { Strategy as OktaStrategy } from 'passport-okta-oauth'; +import passport from 'passport'; +import { + executeFrameHandlerStrategy, + executeRedirectStrategy, + executeRefreshTokenStrategy, + makeProfileInfo, + executeFetchUserProfileStrategy, +} from '../../lib/PassportStrategyHelper'; +import { + OAuthProviderHandlers, + RedirectInfo, + AuthProviderConfig, + EnvironmentProviderConfig, + OAuthProviderOptions, + OAuthProviderConfig, + OAuthResponse, + PassportDoneCallback, +} from '../types'; +import { + EnvironmentHandler, + EnvironmentHandlers, +} from '../../lib/EnvironmentHandler'; +import { Logger } from 'winston'; +import { StateStore } from 'passport-oauth2'; +import { TokenIssuer } from '../../identity'; + +type PrivateInfo = { + refreshToken: string; +}; + +export class OktaAuthProvider implements OAuthProviderHandlers { + + private readonly _strategy: any; + + /** + * Due to passport-okta-oauth forcing options.state = true, + * passport-oauth2 requires express-session to be installed + * so that the 'state' parameter of the oauth2 flow can be stored. + * This implementation of StateStore matches the NullStore found within + * passport-oauth2, which is the StateStore implementation used when options.state = false, + * allowing us to avoid using express-session in order to integrate with Okta. + */ + private _store: StateStore = { + store(req: Request, cb: any) { + cb(null, null); + }, + verify(req: Request, state: string, cb: any) { + cb(null, true); + }, + } + + constructor(options: OAuthProviderOptions) { + this._strategy = new OktaStrategy({ + passReqToCallback: false as true, + ...options, + store: this._store, + response_type: 'code', + }, ( + accessToken: any, + refreshToken: any, + params: any, + rawProfile: passport.Profile, + done: PassportDoneCallback, + ) => { + const profile = makeProfileInfo(rawProfile, params.id_token); + + done( + undefined, + { + providerInfo: { + idToken: params.id_token, + accessToken, + scope: params.scope, + expiresInSeconds: params.expires_in, + }, + profile, + }, + { + refreshToken, + }, + ) + }); + } + + async start( + req: express.Request, + options: Record + ): Promise { + return await executeRedirectStrategy(req, this._strategy, options); + } + + async handler( + req: express.Request + ): Promise<{ response: OAuthResponse; refreshToken: string }> { + const { response, privateInfo } = await executeFrameHandlerStrategy< + OAuthResponse, + PrivateInfo + >(req, this._strategy); + + return { + response: await this.populateIdentity(response), + refreshToken: privateInfo.refreshToken, + }; + } + + async refresh(refreshToken: string, scope: string): Promise { + const { accessToken, params } = await executeRefreshTokenStrategy( + this._strategy, + refreshToken, + scope, + ); + + const profile = await executeFetchUserProfileStrategy( + this._strategy, + accessToken, + params.id_token, + ); + + return this.populateIdentity({ + providerInfo: { + accessToken, + idToken: params.id_token, + expiresInSeconds: params.expires_in, + scope: params.scope, + }, + profile, + }); + + } + + private async populateIdentity( + response: OAuthResponse, + ): Promise { + const { profile } = response; + + if (!profile.email) { + throw new Error('Okta profile contained no email'); + } + + // TODO(Rugvip): Hardcoded to the local part of the email for now + const id = profile.email.split('@')[0]; + + return { ...response, backstageIdentity: { id } }; + } +} + +export function createOktaProvider( + { baseUrl }: AuthProviderConfig, + providerConfig: EnvironmentProviderConfig, + logger: Logger, + tokenIssuer: TokenIssuer, +) { + const envProviders: EnvironmentHandlers = {}; + + for (const [env, envConfig] of Object.entries(providerConfig)) { + const config = (envConfig as unknown) as OAuthProviderConfig; + const { secure, appOrigin } = config; + const callbackURLParam = `?env=${env}`; + const opts = { + audience: config.audience, + clientID: config.clientId, + clientSecret: config.clientSecret, + callbackURL: `${baseUrl}/okta/handler/frame${callbackURLParam}`, + }; + + if (!opts.clientID || !opts.clientSecret || !opts.audience) { + if (process.env.NODE_ENV !== 'development') { + throw new Error( + 'Failed to initialize Okta auth provider, set AUTH_OKTA_CLIENT_ID, AUTH_OKTA_CLIENT_SECRET, and AUTH_OKTA_AUDIENCE env vars', + ); + } + + logger.warn( + 'Okta auth provider disabled, set AUTH_OKTA_CLIENT_ID, AUTH_OKTA_CLIENT_SECRET, and AUTH_OKTA_AUDIENCE env vars to enable', + ); + continue; + } + + envProviders[env] = new OAuthProvider(new OktaAuthProvider(opts), { + disableRefresh: false, + providerId: 'okta', + secure, + baseUrl, + appOrigin, + tokenIssuer, + }); + } + + return new EnvironmentHandler(envProviders); +} diff --git a/plugins/auth-backend/src/providers/okta/types.d.ts b/plugins/auth-backend/src/providers/okta/types.d.ts new file mode 100644 index 0000000000..bed6d24043 --- /dev/null +++ b/plugins/auth-backend/src/providers/okta/types.d.ts @@ -0,0 +1,22 @@ +/* + * Copyright 2020 Spotify AB + * + * 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. + */ +declare module 'passport-okta-oauth' { + + export class Strategy { + constructor(options: any, verify: any) + } +} + \ No newline at end of file diff --git a/plugins/auth-backend/src/providers/types.ts b/plugins/auth-backend/src/providers/types.ts index 56d4db79fa..aec4f9dfd0 100644 --- a/plugins/auth-backend/src/providers/types.ts +++ b/plugins/auth-backend/src/providers/types.ts @@ -55,6 +55,10 @@ export type OAuthProviderConfig = { * Client Secret of the auth provider. */ clientSecret: string; + /** + * The location of the OAuth Authorization Server + */ + audience?: string; }; export type EnvironmentProviderConfig = { diff --git a/plugins/auth-backend/src/service/router.ts b/plugins/auth-backend/src/service/router.ts index 28718e85a1..b9c0ff4496 100644 --- a/plugins/auth-backend/src/service/router.ts +++ b/plugins/auth-backend/src/service/router.ts @@ -82,6 +82,15 @@ export async function createRouter( issuer: 'passport-saml', }, }, + okta: { + development: { + appOrigin: 'http://localhost:3000', + secure: false, + clientId: process.env.AUTH_OKTA_CLIENT_ID!, + clientSecret: process.env.AUTH_OKTA_CLIENT_SECRET!, + audience: process.env.AUTH_OKTA_AUDIENCE, + } + } }, }, }; From 907371ffe09e9695397298238ae72f9298106582 Mon Sep 17 00:00:00 2001 From: Nicholas Pirrello Date: Wed, 24 Jun 2020 22:56:10 -0400 Subject: [PATCH 05/25] Add ui implementation for okta sso integration --- packages/app/src/App.tsx | 2 +- packages/app/src/apis.ts | 11 ++ .../core-api/src/apis/definitions/auth.ts | 17 ++ .../src/apis/implementations/auth/index.ts | 1 + .../auth/okta/OktaAuth.test.ts | 111 ++++++++++++ .../implementations/auth/okta/OktaAuth.ts | 168 ++++++++++++++++++ .../apis/implementations/auth/okta/index.ts | 18 ++ .../apis/implementations/auth/okta/types.ts | 27 +++ .../core/src/layout/Sidebar/UserSettings.tsx | 6 + .../src/layout/SignInPage/oktaProvider.tsx | 93 ++++++++++ .../core/src/layout/SignInPage/providers.tsx | 4 +- yarn.lock | 35 +++- 12 files changed, 489 insertions(+), 4 deletions(-) create mode 100644 packages/core-api/src/apis/implementations/auth/okta/OktaAuth.test.ts create mode 100644 packages/core-api/src/apis/implementations/auth/okta/OktaAuth.ts create mode 100644 packages/core-api/src/apis/implementations/auth/okta/index.ts create mode 100644 packages/core-api/src/apis/implementations/auth/okta/types.ts create mode 100644 packages/core/src/layout/SignInPage/oktaProvider.tsx diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx index f4515cbf01..ccaeb2828b 100644 --- a/packages/app/src/App.tsx +++ b/packages/app/src/App.tsx @@ -31,7 +31,7 @@ const app = createApp({ plugins: Object.values(plugins), components: { SignInPage: props => ( - + ), }, }); diff --git a/packages/app/src/apis.ts b/packages/app/src/apis.ts index 5011b16eaf..d2b2706464 100644 --- a/packages/app/src/apis.ts +++ b/packages/app/src/apis.ts @@ -26,10 +26,12 @@ import { FeatureFlags, GoogleAuth, GithubAuth, + OktaAuth, oauthRequestApiRef, OAuthRequestManager, googleAuthApiRef, githubAuthApiRef, + oktaAuthApiRef, storageApiRef, WebStorage, } from '@backstage/core'; @@ -91,6 +93,15 @@ export const apis = (config: ConfigApi) => { }), ); + builder.add( + oktaAuthApiRef, + OktaAuth.create({ + apiOrigin: 'http://localhost:7000', + basePath: '/auth/', + oauthRequestApi, + }), + ); + builder.add( techRadarApiRef, new TechRadar({ diff --git a/packages/core-api/src/apis/definitions/auth.ts b/packages/core-api/src/apis/definitions/auth.ts index d5c0e9c0a4..f82352cbc8 100644 --- a/packages/core-api/src/apis/definitions/auth.ts +++ b/packages/core-api/src/apis/definitions/auth.ts @@ -233,3 +233,20 @@ export const githubAuthApiRef = createApiRef< id: 'core.auth.github', description: 'Provides authentication towards Github APIs', }); + +/** + * Provides authentication towards Okta APIs. + * + * See https://developer.okta.com/docs/reference/api/oidc/ + * for a full list of supported scopes. + */ +export const oktaAuthApiRef = createApiRef< + OAuthApi & + OpenIdConnectApi & + ProfileInfoApi & + BackstageIdentityApi & + SessionStateApi +>({ + id: 'core.auth.okta', + description: 'Provides authentication towards Okta APIs', +}); diff --git a/packages/core-api/src/apis/implementations/auth/index.ts b/packages/core-api/src/apis/implementations/auth/index.ts index f13368b5c4..4fa992dfb5 100644 --- a/packages/core-api/src/apis/implementations/auth/index.ts +++ b/packages/core-api/src/apis/implementations/auth/index.ts @@ -16,3 +16,4 @@ export * from './google'; export * from './github'; +export * from './okta'; diff --git a/packages/core-api/src/apis/implementations/auth/okta/OktaAuth.test.ts b/packages/core-api/src/apis/implementations/auth/okta/OktaAuth.test.ts new file mode 100644 index 0000000000..7f2bd5d6bc --- /dev/null +++ b/packages/core-api/src/apis/implementations/auth/okta/OktaAuth.test.ts @@ -0,0 +1,111 @@ +/* + * Copyright 2020 Spotify AB + * + * 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. + */ +import OktaAuth from './OktaAuth'; + +const theFuture = new Date(Date.now() + 3600000); +const thePast = new Date(Date.now() - 10); + +describe('OktaAuth', () => { + it('should get refreshed access token', async () => { + const getSession = jest.fn().mockResolvedValue({ + providerInfo: { accessToken: 'access-token', expiresAt: theFuture }, + }); + const oktaAuth = new OktaAuth({ getSession } as any); + + expect(await oktaAuth.getAccessToken()).toBe('access-token'); + expect(getSession).toBeCalledTimes(1); + }); + + it('should get refreshed id token', async () => { + const getSession = jest.fn().mockResolvedValue({ + providerInfo: { idToken: 'id-token', expiresAt: theFuture }, + }); + const oktaAuth = new OktaAuth({ getSession } as any); + + expect(await oktaAuth.getIdToken()).toBe('id-token'); + expect(getSession).toBeCalledTimes(1); + }); + + it('should get optional id token', async () => { + const getSession = jest.fn().mockResolvedValue({ + providerInfo: { idToken: 'id-token', expiresAt: theFuture }, + }); + const oktaAuth = new OktaAuth({ getSession } as any); + + expect(await oktaAuth.getIdToken({ optional: true })).toBe('id-token'); + expect(getSession).toBeCalledTimes(1); + }); + + it('should share popup closed errors', async () => { + const error = new Error('NOPE'); + error.name = 'RejectedError'; + const getSession = jest + .fn() + .mockResolvedValueOnce({ + providerInfo: { + accessToken: 'access-token', + expiresAt: theFuture, + scopes: new Set([`not-a-scope`]), + }, + }) + .mockRejectedValue(error); + const oktaAuth = new OktaAuth({ getSession } as any); + + // Make sure we have a session before we do the double request, so that we get past the !this.currentSession check + await expect(oktaAuth.getAccessToken()).resolves.toBe('access-token'); + + const promise1 = oktaAuth.getAccessToken('more'); + const promise2 = oktaAuth.getAccessToken('more'); + await expect(promise1).rejects.toBe(error); + await expect(promise2).rejects.toBe(error); + expect(getSession).toBeCalledTimes(3); + }); + + it('should wait for all session refreshes', async () => { + const initialSession = { + providerInfo: { + idToken: 'token1', + expiresAt: theFuture, + scopes: new Set(), + }, + }; + const getSession = jest + .fn() + .mockResolvedValueOnce(initialSession) + .mockResolvedValue({ + providerInfo: { + idToken: 'token2', + expiresAt: theFuture, + scopes: new Set(), + }, + }); + const oktaAuth = new OktaAuth({ getSession } as any); + + // Grab the expired session first + await expect(oktaAuth.getIdToken()).resolves.toBe('token1'); + expect(getSession).toBeCalledTimes(1); + + initialSession.providerInfo.expiresAt = thePast; + + const promise1 = oktaAuth.getIdToken(); + const promise2 = oktaAuth.getIdToken(); + const promise3 = oktaAuth.getIdToken(); + await expect(promise1).resolves.toBe('token2'); + await expect(promise2).resolves.toBe('token2'); + await expect(promise3).resolves.toBe('token2'); + expect(getSession).toBeCalledTimes(4); // De-duping of session requests happens in client + }); +}); diff --git a/packages/core-api/src/apis/implementations/auth/okta/OktaAuth.ts b/packages/core-api/src/apis/implementations/auth/okta/OktaAuth.ts new file mode 100644 index 0000000000..55820375f6 --- /dev/null +++ b/packages/core-api/src/apis/implementations/auth/okta/OktaAuth.ts @@ -0,0 +1,168 @@ +/* + * Copyright 2020 Spotify AB + * + * 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. + */ + +import OktaIcon from '@material-ui/icons/AcUnit'; +import { DefaultAuthConnector } from '../../../../lib/AuthConnector'; +import { OktaSession } from './types'; +import { + OAuthApi, + OpenIdConnectApi, + ProfileInfoApi, + ProfileInfo, + SessionStateApi, + SessionState, + BackstageIdentityApi, + AuthRequestOptions, + BackstageIdentity, +} from '../../../definitions/auth'; +import { OAuthRequestApi, AuthProvider } from '../../../definitions'; +import { SessionManager } from '../../../../lib/AuthSessionManager/types'; +import { RefreshingAuthSessionManager } from '../../../../lib/AuthSessionManager'; +import { Observable } from '../../../../types'; + +type CreateOptions = { + apiOrigin: string; + basePath: string; + + oauthRequestApi: OAuthRequestApi; + + environment?: string; + provider?: AuthProvider & { id: string }; +}; + +export type OktaAuthResponse = { + providerInfo: { + accessToken: string; + idToken: string; + scope: string; + expiresInSeconds: number; + }; + profile: ProfileInfo; + backstageIdentity: BackstageIdentity; +}; + +const DEFAULT_PROVIDER = { + id: 'okta', + title: 'Okta', + icon: OktaIcon, +}; + +class OktaAuth implements + OAuthApi, + OpenIdConnectApi, + ProfileInfoApi, + BackstageIdentityApi, + SessionStateApi +{ + static create({ + apiOrigin, + basePath, + environment = 'development', + provider = DEFAULT_PROVIDER, + oauthRequestApi, + }: CreateOptions) { + const connector = new DefaultAuthConnector({ + apiOrigin, + basePath, + environment, + provider, + oauthRequestApi: oauthRequestApi, + sessionTransform(res: OktaAuthResponse): OktaSession { + return { + ...res, + providerInfo: { + idToken: res.providerInfo.idToken, + accessToken: res.providerInfo.accessToken, + scopes: OktaAuth.normalizeScopes(res.providerInfo.scope), + expiresAt: new Date( + Date.now() + res.providerInfo.expiresInSeconds * 1000, + ), + }, + }; + }, + }); + + const sessionManager = new RefreshingAuthSessionManager({ + connector, + defaultScopes: new Set([ + 'openid', + 'email', + 'profile', + 'offline_access', + ]), + sessionScopes: session => session.scopes, + sessionShouldRefresh: session => { + const expiresInSec = + (session.providerInfo.expiresAt.getTime() - Date.now()) / 1000; + return expiresInSec < 60 * 5; + }, + }); + + return new OktaAuth(sessionManager); + } + + sessionState$(): Observable { + return this.sessionManager.sessionState$(); + } + + constructor(private readonly sessionManager: SessionManager) {} + + async getAccessToken( + scope?: string, + options?: AuthRequestOptions + ) { + const session = await this.sessionManager.getSession({ + ...options, + scopes: OktaAuth.normalizeScopes(scope), + }); + return session?.providerInfo.accessToken ?? ''; + } + + async getIdToken(options: AuthRequestOptions = {}) { + const session = await this.sessionManager.getSession(options); + return session?.providerInfo.idToken ?? ''; + } + + async logout() { + await this.sessionManager.removeSession(); + } + + async getBackstageIdentity( + options: AuthRequestOptions = {}, + ): Promise { + const session = await this.sessionManager.getSession(options); + return session?.backstageIdentity; + } + + async getProfile(options: AuthRequestOptions = {}) { + const session = await this.sessionManager.getSession(options); + return session?.profile; + } + + static normalizeScopes(scope?: string): Set { + if (!scope) { + return new Set(); + } + + const scopeList = Array.isArray(scope) + ? scope + : scope.split(/[\s|,]/).filter(Boolean); + + return new Set(scopeList); + } +} + +export default OktaAuth; \ No newline at end of file diff --git a/packages/core-api/src/apis/implementations/auth/okta/index.ts b/packages/core-api/src/apis/implementations/auth/okta/index.ts new file mode 100644 index 0000000000..2bef0ce0db --- /dev/null +++ b/packages/core-api/src/apis/implementations/auth/okta/index.ts @@ -0,0 +1,18 @@ +/* + * Copyright 2020 Spotify AB + * + * 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. + */ + +export * from './types'; +export { default as OktaAuth } from './OktaAuth'; diff --git a/packages/core-api/src/apis/implementations/auth/okta/types.ts b/packages/core-api/src/apis/implementations/auth/okta/types.ts new file mode 100644 index 0000000000..e3392ba1d6 --- /dev/null +++ b/packages/core-api/src/apis/implementations/auth/okta/types.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2020 Spotify AB + * + * 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. + */ +import { ProfileInfo, BackstageIdentity } from '../../../definitions'; + +export type OktaSession = { + providerInfo: { + idToken: string; + accessToken: string; + scopes: Set; + expiresAt: Date; + }; + profile: ProfileInfo; + backstageIdentity: BackstageIdentity; +}; diff --git a/packages/core/src/layout/Sidebar/UserSettings.tsx b/packages/core/src/layout/Sidebar/UserSettings.tsx index 36e8e1088b..668cb1354a 100644 --- a/packages/core/src/layout/Sidebar/UserSettings.tsx +++ b/packages/core/src/layout/Sidebar/UserSettings.tsx @@ -23,6 +23,7 @@ import { googleAuthApiRef, githubAuthApiRef, identityApiRef, + oktaAuthApiRef, useApi, } from '@backstage/core-api'; import { @@ -56,6 +57,11 @@ export function SidebarUserSettings() { apiRef={githubAuthApiRef} icon={Star} /> + { + const oktaAuthApi = useApi(oktaAuthApiRef); + const errorApi = useApi(errorApiRef); + + const handleLogin = async () => { + try { + const identity = await oktaAuthApi.getBackstageIdentity({ + instantPopup: true, + }); + + const profile = await oktaAuthApi.getProfile(); + + onResult({ + userId: identity!.id, + profile: profile!, + getIdToken: () => + oktaAuthApi.getBackstageIdentity().then(i => i!.idToken), + logout: async () => { + await oktaAuthApi.logout(); + }, + }); + } catch (error) { + errorApi.post(error); + } + }; + + return ( + + + Sign In + + } + > + Sign In using Okta + + + ); +}; + +const loader: ProviderLoader = async apis => { + const oktaAuthApi = apis.get(oktaAuthApiRef)!; + + const identity = await oktaAuthApi.getBackstageIdentity({ + optional: true, + }); + + if (!identity) { + return undefined; + } + + const profile = await oktaAuthApi.getProfile(); + + return { + userId: identity.id, + profile: profile!, + getIdToken: () => + oktaAuthApi.getBackstageIdentity().then(i => i!.idToken), + logout: async () => { + await oktaAuthApi.logout(); + }, + }; +}; + +export const oktaProvider: SignInProvider = { Component, loader }; \ No newline at end of file diff --git a/packages/core/src/layout/SignInPage/providers.tsx b/packages/core/src/layout/SignInPage/providers.tsx index 96dbc30a89..a195b2042a 100644 --- a/packages/core/src/layout/SignInPage/providers.tsx +++ b/packages/core/src/layout/SignInPage/providers.tsx @@ -18,6 +18,7 @@ import React, { useLayoutEffect, useState, useMemo, useCallback } from 'react'; import { guestProvider } from './guestProvider'; import { googleProvider } from './googleProvider'; import { customProvider } from './customProvider'; +import { oktaProvider } from './oktaProvider'; import { SignInPageProps, SignInResult, @@ -30,12 +31,13 @@ import { SignInProvider } from './types'; const PROVIDER_STORAGE_KEY = '@backstage/core:SignInPage:provider'; // Separate list here to avoid exporting internal types -export type SignInProviderId = 'guest' | 'google' | 'custom'; +export type SignInProviderId = 'guest' | 'google' | 'custom' | 'okta'; const signInProviders: { [id in SignInProviderId]: SignInProvider } = { guest: guestProvider, google: googleProvider, custom: customProvider, + okta: oktaProvider, }; export const useSignInProviders = ( diff --git a/yarn.lock b/yarn.lock index dc34848cba..873cbb3582 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14239,7 +14239,16 @@ passport-google-oauth20@^2.0.0: dependencies: passport-oauth2 "1.x.x" -passport-oauth2@1.x.x: +passport-oauth1@1.x.x: + version "1.1.0" + resolved "https://registry.npmjs.org/passport-oauth1/-/passport-oauth1-1.1.0.tgz#a7de988a211f9cf4687377130ea74df32730c918" + integrity sha1-p96YiiEfnPRoc3cTDqdN8ycwyRg= + dependencies: + oauth "0.9.x" + passport-strategy "1.x.x" + utils-merge "1.x.x" + +passport-oauth2@1.x.x, passport-oauth2@^1.5.0: version "1.5.0" resolved "https://registry.npmjs.org/passport-oauth2/-/passport-oauth2-1.5.0.tgz#64babbb54ac46a4dcab35e7f266ed5294e3c4108" integrity sha512-kqBt6vR/5VlCK8iCx1/KpY42kQ+NEHZwsSyt4Y6STiNjU+wWICG1i8ucc1FapXDGO15C5O5VZz7+7vRzrDPXXQ== @@ -14250,6 +14259,23 @@ passport-oauth2@1.x.x: uid2 "0.0.x" utils-merge "1.x.x" +passport-oauth@1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/passport-oauth/-/passport-oauth-1.0.0.tgz#90aff63387540f02089af28cdad39ea7f80d77df" + integrity sha1-kK/2M4dUDwIImvKM2tOep/gNd98= + dependencies: + passport-oauth1 "1.x.x" + passport-oauth2 "1.x.x" + +passport-okta-oauth@^0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/passport-okta-oauth/-/passport-okta-oauth-0.0.1.tgz#c8bcee02af3d56ca79d3cca776f2df7cf15a5748" + integrity sha1-yLzuAq89Vsp508yndvLffPFaV0g= + dependencies: + passport-oauth "1.0.0" + pkginfo "0.2.x" + uid2 "0.0.3" + passport-saml@^1.3.3: version "1.3.3" resolved "https://registry.npmjs.org/passport-saml/-/passport-saml-1.3.3.tgz#cbea1a2b21ff32b3bc4bfd84dc39c3a370df9935" @@ -14498,6 +14524,11 @@ pkg-up@3.1.0, pkg-up@^3.1.0: dependencies: find-up "^3.0.0" +pkginfo@0.2.x: + version "0.2.3" + resolved "https://registry.npmjs.org/pkginfo/-/pkginfo-0.2.3.tgz#7239c42a5ef6c30b8f328439d9b9ff71042490f8" + integrity sha1-cjnEKl72wwuPMoQ52bn/cQQkkPg= + please-upgrade-node@^3.2.0: version "3.2.0" resolved "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz#aeddd3f994c933e4ad98b99d9a556efa0e2fe942" @@ -18517,7 +18548,7 @@ uid-number@0.0.6: resolved "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" integrity sha1-DqEOgDXo61uOREnwbaHHMGY7qoE= -uid2@0.0.x: +uid2@0.0.3, uid2@0.0.x: version "0.0.3" resolved "https://registry.npmjs.org/uid2/-/uid2-0.0.3.tgz#483126e11774df2f71b8b639dcd799c376162b82" integrity sha1-SDEm4Rd03y9xuLY53NeZw3YWK4I= From e73f3fbab7c221e4b99c20d9b08b7a3de340878c Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 25 Jun 2020 10:58:33 +0200 Subject: [PATCH 06/25] cli: implement postpack --- packages/cli/src/commands/pack.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/packages/cli/src/commands/pack.ts b/packages/cli/src/commands/pack.ts index 51c7e36086..1f81b89767 100644 --- a/packages/cli/src/commands/pack.ts +++ b/packages/cli/src/commands/pack.ts @@ -19,10 +19,15 @@ import { paths } from '../lib/paths'; const SKIPPED_KEYS = ['access', 'registry', 'tag']; -export const pre = async () => { - const pkgPath = paths.resolveTarget('package.json'); +const PKG_PATH = 'package.json'; +const PKG_BACKUP_PATH = 'package.json-prepack'; - const pkg = await fs.readJson(pkgPath); +export const pre = async () => { + const pkgPath = paths.resolveTarget(PKG_PATH); + + const pkgContent = await fs.readFile(pkgPath, 'utf8'); + const pkg = JSON.parse(pkgContent); + await fs.writeFile(PKG_BACKUP_PATH, pkgContent); for (const key of Object.keys(pkg.publishConfig ?? {})) { if (!SKIPPED_KEYS.includes(key)) { @@ -33,5 +38,6 @@ export const pre = async () => { }; export const post = async () => { - // postpack is a noop for now, since it's not called anyway + // postpack isn't called by yarn right now, so it needs to be called manually + await fs.move(PKG_BACKUP_PATH, PKG_PATH, { overwrite: true }); }; From c9a1b99af21f8caf61084c84eb547f66a9ebd87a Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 25 Jun 2020 11:39:28 +0200 Subject: [PATCH 07/25] cli: rename packager to builder --- packages/cli/src/commands/backend/build.ts | 2 +- packages/cli/src/commands/build.ts | 2 +- packages/cli/src/commands/plugin/build.ts | 2 +- packages/cli/src/lib/{packager => builder}/config.ts | 0 packages/cli/src/lib/{packager => builder}/index.ts | 0 packages/cli/src/lib/{packager => builder}/packager.ts | 0 packages/cli/src/lib/{packager => builder}/types.ts | 0 7 files changed, 3 insertions(+), 3 deletions(-) rename packages/cli/src/lib/{packager => builder}/config.ts (100%) rename packages/cli/src/lib/{packager => builder}/index.ts (100%) rename packages/cli/src/lib/{packager => builder}/packager.ts (100%) rename packages/cli/src/lib/{packager => builder}/types.ts (100%) diff --git a/packages/cli/src/commands/backend/build.ts b/packages/cli/src/commands/backend/build.ts index a9cdc51fa9..ceca5b0286 100644 --- a/packages/cli/src/commands/backend/build.ts +++ b/packages/cli/src/commands/backend/build.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { buildPackage, Output } from '../../lib/packager'; +import { buildPackage, Output } from '../../lib/builder'; export default async () => { await buildPackage({ diff --git a/packages/cli/src/commands/build.ts b/packages/cli/src/commands/build.ts index 19e4b17352..bd5bbc5e9f 100644 --- a/packages/cli/src/commands/build.ts +++ b/packages/cli/src/commands/build.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { buildPackage, Output } from '../lib/packager'; +import { buildPackage, Output } from '../lib/builder'; import { Command } from 'commander'; export default async (cmd: Command) => { diff --git a/packages/cli/src/commands/plugin/build.ts b/packages/cli/src/commands/plugin/build.ts index 7e4e5cd36a..d62ffbeebd 100644 --- a/packages/cli/src/commands/plugin/build.ts +++ b/packages/cli/src/commands/plugin/build.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { buildPackage, Output } from '../../lib/packager'; +import { buildPackage, Output } from '../../lib/builder'; export default async () => { await buildPackage({ diff --git a/packages/cli/src/lib/packager/config.ts b/packages/cli/src/lib/builder/config.ts similarity index 100% rename from packages/cli/src/lib/packager/config.ts rename to packages/cli/src/lib/builder/config.ts diff --git a/packages/cli/src/lib/packager/index.ts b/packages/cli/src/lib/builder/index.ts similarity index 100% rename from packages/cli/src/lib/packager/index.ts rename to packages/cli/src/lib/builder/index.ts diff --git a/packages/cli/src/lib/packager/packager.ts b/packages/cli/src/lib/builder/packager.ts similarity index 100% rename from packages/cli/src/lib/packager/packager.ts rename to packages/cli/src/lib/builder/packager.ts diff --git a/packages/cli/src/lib/packager/types.ts b/packages/cli/src/lib/builder/types.ts similarity index 100% rename from packages/cli/src/lib/packager/types.ts rename to packages/cli/src/lib/builder/types.ts From 686018f81161fb016ae89dc4c589c5f73748f546 Mon Sep 17 00:00:00 2001 From: Nicholas Pirrello Date: Thu, 25 Jun 2020 08:44:55 -0400 Subject: [PATCH 08/25] Add correct link for okta resouce scopes --- packages/core-api/src/apis/definitions/auth.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core-api/src/apis/definitions/auth.ts b/packages/core-api/src/apis/definitions/auth.ts index f82352cbc8..a944e85a7e 100644 --- a/packages/core-api/src/apis/definitions/auth.ts +++ b/packages/core-api/src/apis/definitions/auth.ts @@ -237,7 +237,7 @@ export const githubAuthApiRef = createApiRef< /** * Provides authentication towards Okta APIs. * - * See https://developer.okta.com/docs/reference/api/oidc/ + * See https://developer.okta.com/docs/guides/implement-oauth-for-okta/scopes/ * for a full list of supported scopes. */ export const oktaAuthApiRef = createApiRef< From d286e3b93fa597283e75ab2c86d5764e51772b56 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 25 Jun 2020 17:15:23 +0200 Subject: [PATCH 09/25] cli: add packager lib for packaging packages into a dist workspace Co-authored-by: Ivan Shmidt Co-authored-by: Raghunandan --- packages/cli/src/lib/packager/index.ts | 142 +++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 packages/cli/src/lib/packager/index.ts diff --git a/packages/cli/src/lib/packager/index.ts b/packages/cli/src/lib/packager/index.ts new file mode 100644 index 0000000000..c702fd3df4 --- /dev/null +++ b/packages/cli/src/lib/packager/index.ts @@ -0,0 +1,142 @@ +/* + * Copyright 2020 Spotify AB + * + * 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. + */ + +import fs from 'fs-extra'; +import { resolve as resolvePath, relative as relativePath } from 'path'; +import { paths } from '../paths'; +import { run } from '../run'; +import tar from 'tar'; +import { tmpdir } from 'os'; + +type LernaPackage = { + name: string; + private: boolean; + location: string; +}; + +type FileEntry = + | string + | { + src: string; + dest: string; + }; + +type Options = { + /** + * Target directory for the dist workspace, defaults to a temporary directory + */ + targetDir?: string; + + /** + * Files to copy into the target workspace. + * + * Defaults to ['yarn.lock', 'package.json']. + */ + files?: FileEntry[]; +}; + +/** + * Uses `yarn pack` to package local packages and unpacks them into a dist workspace. + * The target workspace will end up containing dist version of each package and + * will be suitable for packaging e.g. into a docker image. + * + * This creates a structure that is functionally similar to if the packages where + * installed from NPM, but uses yarn workspaces to link to them at runtime. + */ +export async function createDistWorkspace( + packageNames: string[], + options: Options, +) { + const targetDir = + options.targetDir ?? + (await fs.mkdtemp(resolvePath(tmpdir(), 'dist-workspace'))); + + const targets = await findTargetPackages(packageNames); + + await moveToDistWorkspace(targetDir, targets); + + const files: FileEntry[] = options.files ?? ['yarn.lock', 'package.json']; + + for (const file of files) { + const src = typeof file === 'string' ? file : file.src; + const dest = typeof file === 'string' ? file : file.dest; + await fs.copy(paths.resolveTargetRoot(src), resolvePath(targetDir, dest)); + } +} + +async function moveToDistWorkspace( + workspaceDir: string, + localPackages: LernaPackage[], +): Promise { + await Promise.all( + localPackages.map(async (target, index) => { + console.log(`Repacking ${target.name} into dist workspace`); + const archive = `temp-package-${index}.tgz`; + const archivePath = resolvePath(workspaceDir, archive); + + await run('yarn', ['pack', '--filename', archivePath], { + cwd: target.location, + }); + // TODO(Rugvip): yarn pack doesn't call postpack, once the bug is fixed this can be removed + await run('yarn', ['postpack'], { cwd: target.location }); + + const outputDir = relativePath(paths.targetRoot, target.location); + const absoluteOutputPath = resolvePath(workspaceDir, outputDir); + await fs.ensureDir(absoluteOutputPath); + + await tar.extract({ + file: archivePath, + cwd: absoluteOutputPath, + strip: 1, + }); + await fs.remove(archivePath); + }), + ); +} + +async function findTargetPackages(pkgNames: string[]): Promise { + const LernaProject = require('@lerna/project'); + const PackageGraph = require('@lerna/package-graph'); + + const project = new LernaProject(paths.targetDir); + const packages = await project.getPackages(); + const graph = new PackageGraph(packages); + + const targets = new Map(); + const searchNames = pkgNames.slice(); + + while (searchNames.length) { + const name = searchNames.pop()!; + + if (targets.has(name)) { + continue; + } + + const node = graph.get(name); + if (!node) { + throw new Error(`Package '${name}' not found`); + } + + const pkgDeps = Object.keys(node.pkg.dependencies); + const localDeps: string[] = Array.from(node.localDependencies.keys()); + const filteredDeps = localDeps.filter(dep => pkgDeps.includes(dep)); + + searchNames.push(...filteredDeps); + targets.set(name, node.pkg); + } + + return Array.from(targets.values()); +} From 84b55c10ca9363a7249b265766a85f8876da59b0 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 25 Jun 2020 18:03:21 +0200 Subject: [PATCH 10/25] cli: added backend:build-image command Co-authored-by: Ivan Shmidt --- .../cli/src/commands/backend/buildImage.ts | 39 +++++++++++++++++++ packages/cli/src/index.ts | 9 +++++ packages/cli/src/lib/packager/index.ts | 1 + 3 files changed, 49 insertions(+) create mode 100644 packages/cli/src/commands/backend/buildImage.ts diff --git a/packages/cli/src/commands/backend/buildImage.ts b/packages/cli/src/commands/backend/buildImage.ts new file mode 100644 index 0000000000..a847f1ef54 --- /dev/null +++ b/packages/cli/src/commands/backend/buildImage.ts @@ -0,0 +1,39 @@ +/* + * Copyright 2020 Spotify AB + * + * 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. + */ + +import fs from 'fs-extra'; +import { createDistWorkspace } from '../../lib/packager'; +import { paths } from '../../lib/paths'; +import { run } from '../../lib/run'; + +export default async (imageTag: string) => { + const tempDistWorkspace = await createDistWorkspace(['example-backend'], { + files: [ + 'package.json', + 'yarn.lock', + 'app-config.yaml', + { src: paths.resolveTarget('Dockerfile'), dest: 'Dockerfile' }, + ], + }); + + console.log(`Dist workspace ready at ${tempDistWorkspace}`); + + await run('docker', ['build', '.', '-t', imageTag], { + cwd: tempDistWorkspace, + }); + + await fs.remove(tempDistWorkspace); +}; diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index e67a52c795..bed32bcf8b 100644 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -46,6 +46,15 @@ const main = (argv: string[]) => { .description('Build a backend plugin') .action(lazyAction(() => import('./commands/backend/build'), 'default')); + program + .command('backend:build-image ') + .description( + 'Builds a docker image from the package, with all local deps included', + ) + .action( + lazyAction(() => import('./commands/backend/buildImage'), 'default'), + ); + program .command('backend:dev') .description('Start local development server with HMR for the backend') diff --git a/packages/cli/src/lib/packager/index.ts b/packages/cli/src/lib/packager/index.ts index c702fd3df4..2f5233f93f 100644 --- a/packages/cli/src/lib/packager/index.ts +++ b/packages/cli/src/lib/packager/index.ts @@ -75,6 +75,7 @@ export async function createDistWorkspace( const dest = typeof file === 'string' ? file : file.dest; await fs.copy(paths.resolveTargetRoot(src), resolvePath(targetDir, dest)); } + return targetDir; } async function moveToDistWorkspace( From 66e2bfe073710bd3ac34c0fa0704c2f8523cd2bf Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 25 Jun 2020 18:05:11 +0200 Subject: [PATCH 11/25] backend: update packaging and add build-image command + Dockerfile Co-authored-by: Ivan Shmidt --- packages/backend/Dockerfile | 9 +++++++++ packages/backend/package.json | 10 +++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 packages/backend/Dockerfile diff --git a/packages/backend/Dockerfile b/packages/backend/Dockerfile new file mode 100644 index 0000000000..3e8ba36cec --- /dev/null +++ b/packages/backend/Dockerfile @@ -0,0 +1,9 @@ +FROM node:12 + +WORKDIR /usr/src/app + +COPY . . + +RUN yarn install --frozen-lockfile --production + +CMD ["node", "packages/backend"] diff --git a/packages/backend/package.json b/packages/backend/package.json index 3be1f5ee3e..53b1f431c0 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -1,19 +1,27 @@ { "name": "example-backend", "version": "0.1.1-alpha.12", - "main": "dist/index.cjs.js", + "main": "src/index.ts", "types": "src/index.ts", "private": true, "license": "Apache-2.0", "engines": { "node": ">=12" }, + "publishConfig": { + "access": "public", + "main": "dist/index.cjs.js", + "types": "dist/index.d.ts" + }, "scripts": { "build": "backstage-cli backend:build", + "build-image": "backstage-cli backend:build-image example-backend", "start": "backstage-cli backend:dev", "lint": "backstage-cli lint", "test": "backstage-cli test", "clean": "backstage-cli clean", + "prepack": "backstage-cli prepack", + "postpack": "backstage-cli postpack", "migrate:create": "knex migrate:make -x ts" }, "dependencies": { From d49e05e9e7c74540bec38639a8e4cfef1ee15167 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 25 Jun 2020 18:05:45 +0200 Subject: [PATCH 12/25] plugins/auth-backend: include migrations in published package Co-authored-by: Ivan Shmidt --- plugins/auth-backend/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/auth-backend/package.json b/plugins/auth-backend/package.json index 2de098c7eb..290dd39489 100644 --- a/plugins/auth-backend/package.json +++ b/plugins/auth-backend/package.json @@ -57,6 +57,7 @@ "jest-fetch-mock": "^3.0.3" }, "files": [ - "dist" + "dist", + "migrations" ] } From c06c7d7e6bf3c9ea197e9e45aa5b99fc2190551c Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 25 Jun 2020 19:56:18 +0200 Subject: [PATCH 13/25] packages/backend,cli: revert publish config and remove postpack script requirement from image-build --- packages/backend/package.json | 9 +-------- packages/cli/src/lib/packager/index.ts | 5 ++++- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/packages/backend/package.json b/packages/backend/package.json index 53b1f431c0..64ca2c3113 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -1,18 +1,13 @@ { "name": "example-backend", "version": "0.1.1-alpha.12", - "main": "src/index.ts", + "main": "dist/index.cjs.js", "types": "src/index.ts", "private": true, "license": "Apache-2.0", "engines": { "node": ">=12" }, - "publishConfig": { - "access": "public", - "main": "dist/index.cjs.js", - "types": "dist/index.d.ts" - }, "scripts": { "build": "backstage-cli backend:build", "build-image": "backstage-cli backend:build-image example-backend", @@ -20,8 +15,6 @@ "lint": "backstage-cli lint", "test": "backstage-cli test", "clean": "backstage-cli clean", - "prepack": "backstage-cli prepack", - "postpack": "backstage-cli postpack", "migrate:create": "knex migrate:make -x ts" }, "dependencies": { diff --git a/packages/cli/src/lib/packager/index.ts b/packages/cli/src/lib/packager/index.ts index 2f5233f93f..5e309ab953 100644 --- a/packages/cli/src/lib/packager/index.ts +++ b/packages/cli/src/lib/packager/index.ts @@ -25,6 +25,7 @@ type LernaPackage = { name: string; private: boolean; location: string; + scripts: Record; }; type FileEntry = @@ -92,7 +93,9 @@ async function moveToDistWorkspace( cwd: target.location, }); // TODO(Rugvip): yarn pack doesn't call postpack, once the bug is fixed this can be removed - await run('yarn', ['postpack'], { cwd: target.location }); + if (target.scripts.postpack) { + await run('yarn', ['postpack'], { cwd: target.location }); + } const outputDir = relativePath(paths.targetRoot, target.location); const absoluteOutputPath = resolvePath(workspaceDir, outputDir); From 48aaf9a8db3018505106ce7fabd6e9ce9276f1a2 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 25 Jun 2020 21:18:54 +0200 Subject: [PATCH 14/25] yarnrc: bump network timeout --- .yarnrc | 1 + 1 file changed, 1 insertion(+) diff --git a/.yarnrc b/.yarnrc index 524dcb98eb..f465c5c5e6 100644 --- a/.yarnrc +++ b/.yarnrc @@ -5,3 +5,4 @@ registry "https://registry.npmjs.org/" lastUpdateCheck 1580389148099 yarn-path ".yarn/releases/yarn-1.22.1.js" +network-timeout 600000 From c9354c2bff95a3524772ccd80b72c3a2550e3952 Mon Sep 17 00:00:00 2001 From: Remy DeCausemaker Date: Thu, 25 Jun 2020 15:20:19 -0400 Subject: [PATCH 15/25] Patch 3: Fixes #1323 (#1461) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Updated FAQ with correct link “Will Spotify’s internal plugins be open sourced, too?” had an incorrect link, and I added the correct one. * Update FAQ.md * Update FAQ.md * Fix links to include full path to .md files Co-authored-by: Nikki Beesetti <12538017+nikkibeesetti@users.noreply.github.com> Co-authored-by: Stefan Ålund --- docs/FAQ.md | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/docs/FAQ.md b/docs/FAQ.md index e38fa84e73..7bfdbec478 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -36,7 +36,7 @@ more, read our blog post, Yes, we've already started releasing open source versions of some of the plugins we use here, and we'll continue to do so. -[Plugins](https://github.com/spotify/faq#what-is-a-plugin-in-backstage) are the +[Plugins](https://github.com/spotify/backstage/blob/master/docs/FAQ.md#what-is-a-plugin-in-backstage) are the building blocks of functionality in Backstage. We have over 120 plugins inside Spotify — many of those are specialized for our use, so will remain internal and proprietary to us. But we estimate that about a third of our existing plugins @@ -122,15 +122,7 @@ can browse and search for all available plugins. ​ ### Which plugin is used the most at Spotify? -​ By far, our most-used plugin is our TechDocs plugin, which we use for creating -technical documentation. Our philosophy at Spotify is to treat "docs like code", -where you write documentation using the same workflow as you write your code. -This makes it easier to create, find, and update documentation. We hope to -release -[the open source version](https://github.com/spotify/backstage/issues/687) in -the future. (See also: -"[Will Spotify's internal plugins be open sourced, too?](https://github.com/spotify/faq#will-spotifys-internal-plugins-be-open-sourced-too)" -above) ​ +By far, our most-used plugin is our TechDocs plugin, which we use for creating technical documentation. Our philosophy at Spotify is to treat "docs like code", where you write documentation using the same workflow as you write your code. This makes it easier to create, find, and update documentation. We hope to release [the open source version](https://github.com/spotify/backstage/issues/687) in the future. (See also: "[Will Spotify's internal plugins be open sourced, too?](https://github.com/spotify/backstage/blob/master/docs/FAQ.md#will-spotifys-internal-plugins-be-open-sourced-too)" above) ### Are you planning to have plugins baked into the repo? Or should they be developed in separate repos? From 4e57eeb1010b5ed44d1f498374dc4cda5c64a1a9 Mon Sep 17 00:00:00 2001 From: Raghunandan Balachandran Date: Thu, 25 Jun 2020 21:21:04 +0200 Subject: [PATCH 16/25] fixing doc links (#1456) --- docs/auth/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/auth/README.md b/docs/auth/README.md index 081d10add6..9809f57168 100644 --- a/docs/auth/README.md +++ b/docs/auth/README.md @@ -80,7 +80,7 @@ sign-in methods. More details are provided in dedicated sections of the documentation. -- [OAuth](./oauth): Description of the generic OAuth flow implemented by the +- [OAuth](./oauth.md): Description of the generic OAuth flow implemented by the [auth-backend](../../plugins/auth-backend). -- [Glossary](./glossary): Glossary of some common terms related to the auth +- [Glossary](./glossary.md): Glossary of some common terms related to the auth flows. From b56524fd718a2c78148b6cb3833675ad237c73f8 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 25 Jun 2020 21:22:00 +0200 Subject: [PATCH 17/25] build(deps): bump helmet from 3.22.0 to 3.23.2 (#1450) Bumps [helmet](https://github.com/helmetjs/helmet) from 3.22.0 to 3.23.2. - [Release notes](https://github.com/helmetjs/helmet/releases) - [Changelog](https://github.com/helmetjs/helmet/blob/master/CHANGELOG.md) - [Commits](https://github.com/helmetjs/helmet/compare/v3.22.0...v3.23.2) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- yarn.lock | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/yarn.lock b/yarn.lock index 026946b1e5..e980d91f57 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7578,11 +7578,6 @@ dns-packet@^1.3.1: ip "^1.1.0" safe-buffer "^5.0.1" -dns-prefetch-control@0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/dns-prefetch-control/-/dns-prefetch-control-0.2.0.tgz#73988161841f3dcc81f47686d539a2c702c88624" - integrity sha512-hvSnros73+qyZXhHFjx2CMLwoj3Fe7eR9EJsFsqmcI1bB2OBWL/+0YzaEaKssCHnj/6crawNnUyw74Gm2EKe+Q== - dns-txt@^2.0.2: version "2.0.2" resolved "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz#b91d806f5d27188e4ab3e7d107d881a1cc4642b6" @@ -9912,12 +9907,11 @@ helmet-csp@2.10.0: dasherize "2.0.0" helmet@^3.22.0: - version "3.22.0" - resolved "https://registry.npmjs.org/helmet/-/helmet-3.22.0.tgz#3a6f11d931799145f0aff15dbc563cff9e13131f" - integrity sha512-Xrqicn2nm1ZIUxP3YGuTBmbDL04neKsIT583Sjh0FkiwKDXYCMUqGqC88w3NUvVXtA75JyR2Jn6jw6ZEMOD+ZA== + version "3.23.2" + resolved "https://registry.npmjs.org/helmet/-/helmet-3.23.2.tgz#390bb6f3f5e593f90f441bdd91000912c543a898" + integrity sha512-pe0UiHw3aHbP8Lon9McCq4AN2XLUMSbhwxJnUY6U2t8wTda7F1SsYg0/pBa1BPugaRqAtx9e1/FyF6E9PsUU5A== dependencies: depd "2.0.0" - dns-prefetch-control "0.2.0" dont-sniff-mimetype "1.1.0" expect-ct "0.2.0" feature-policy "0.3.0" @@ -9927,7 +9921,6 @@ helmet@^3.22.0: hide-powered-by "1.1.0" hpkp "2.0.0" hsts "2.2.0" - ienoopen "1.1.0" nocache "2.1.0" referrer-policy "1.2.0" x-xss-protection "1.3.0" @@ -10290,11 +10283,6 @@ ieee754@^1.1.4: resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg== -ienoopen@1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/ienoopen/-/ienoopen-1.1.0.tgz#411e5d530c982287dbdc3bb31e7a9c9e32630974" - integrity sha512-MFs36e/ca6ohEKtinTJ5VvAJ6oDRAYFdYXweUnGY9L9vcoqFOU4n2ZhmJ0C4z/cwGZ3YIQRSB3XZ1+ghZkY5NQ== - iferr@^0.1.5: version "0.1.5" resolved "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" From 144a3b9294c42c4a601696c280e1aa0461b70bd9 Mon Sep 17 00:00:00 2001 From: Nicholas Pirrello Date: Thu, 25 Jun 2020 18:20:13 -0400 Subject: [PATCH 18/25] Fix build and add okta oauth2 scope normalization --- .../auth/okta/OktaAuth.test.ts | 18 +++++++++++++++ .../implementations/auth/okta/OktaAuth.ts | 22 +++++++++++++++++-- packages/storybook/.storybook/apis.js | 11 ++++++++++ .../src/providers/okta/provider.ts | 4 ++-- 4 files changed, 51 insertions(+), 4 deletions(-) diff --git a/packages/core-api/src/apis/implementations/auth/okta/OktaAuth.test.ts b/packages/core-api/src/apis/implementations/auth/okta/OktaAuth.test.ts index 7f2bd5d6bc..ab6c46c9b4 100644 --- a/packages/core-api/src/apis/implementations/auth/okta/OktaAuth.test.ts +++ b/packages/core-api/src/apis/implementations/auth/okta/OktaAuth.test.ts @@ -18,6 +18,8 @@ import OktaAuth from './OktaAuth'; const theFuture = new Date(Date.now() + 3600000); const thePast = new Date(Date.now() - 10); +const PREFIX = 'okta.'; + describe('OktaAuth', () => { it('should get refreshed access token', async () => { const getSession = jest.fn().mockResolvedValue({ @@ -108,4 +110,20 @@ describe('OktaAuth', () => { await expect(promise3).resolves.toBe('token2'); expect(getSession).toBeCalledTimes(4); // De-duping of session requests happens in client }); + + it.each([ + ['openid', ['openid']], + ['profile email', ['profile', 'email']], + [`${PREFIX}groups.manage`, [`${PREFIX}groups.manage`]], + ['groups.read', [`${PREFIX}groups.read`]], + [`${PREFIX}groups.manage groups.read, openid`, [`${PREFIX}groups.manage`, `${PREFIX}groups.read`, 'openid']], + [`email\t ${PREFIX}groups.read`, ['email', `${PREFIX}groups.read`]], + + // Some incorrect scopes that we don't try to fix + [`${PREFIX}email`, [`${PREFIX}email`]], + [`${PREFIX}profile`, [`${PREFIX}profile`]], + [`${PREFIX}openid`, [`${PREFIX}openid`]], + ])(`should normalize scopes correctly - %p`, (scope, scopes) => { + expect(OktaAuth.normalizeScopes(scope)).toEqual(new Set(scopes)); + }); }); diff --git a/packages/core-api/src/apis/implementations/auth/okta/OktaAuth.ts b/packages/core-api/src/apis/implementations/auth/okta/OktaAuth.ts index 55820375f6..5631648016 100644 --- a/packages/core-api/src/apis/implementations/auth/okta/OktaAuth.ts +++ b/packages/core-api/src/apis/implementations/auth/okta/OktaAuth.ts @@ -60,6 +60,12 @@ const DEFAULT_PROVIDER = { icon: OktaIcon, }; +const OKTA_OIDC_SCOPES: Set = new Set( + ['openid', 'profile', 'email', 'phone', 'address', 'groups', 'offline_access'] +) + +const OKTA_SCOPE_PREFIX: string = 'okta.' + class OktaAuth implements OAuthApi, OpenIdConnectApi, @@ -152,7 +158,7 @@ class OktaAuth implements return session?.profile; } - static normalizeScopes(scope?: string): Set { + static normalizeScopes(scope?: string | string[]): Set { if (!scope) { return new Set(); } @@ -161,7 +167,19 @@ class OktaAuth implements ? scope : scope.split(/[\s|,]/).filter(Boolean); - return new Set(scopeList); + const normalizedScopes = scopeList.map(scope => { + if (OKTA_OIDC_SCOPES.has(scope)) { + return scope; + } + + if (scope.startsWith(OKTA_SCOPE_PREFIX)) { + return scope; + } + + return `${OKTA_SCOPE_PREFIX}${scope}` + }); + + return new Set(normalizedScopes); } } diff --git a/packages/storybook/.storybook/apis.js b/packages/storybook/.storybook/apis.js index 3b61ae7af8..0d0cf74e8f 100644 --- a/packages/storybook/.storybook/apis.js +++ b/packages/storybook/.storybook/apis.js @@ -6,11 +6,13 @@ import { OAuthRequestManager, googleAuthApiRef, githubAuthApiRef, + oktaAuthApiRef, AlertApiForwarder, ErrorApiForwarder, ErrorAlerter, GoogleAuth, GithubAuth, + OktaAuth, identityApiRef, } from '@backstage/core'; @@ -50,4 +52,13 @@ builder.add( }), ); +builder.add( + oktaAuthApiRef, + OktaAuth.create({ + apiOrigin: 'http://localhost:7000', + basePath: '/auth/', + oauthRequestApi, + }), +); + export const apis = builder.build(); diff --git a/plugins/auth-backend/src/providers/okta/provider.ts b/plugins/auth-backend/src/providers/okta/provider.ts index 7b3d5770d7..788af9c4bd 100644 --- a/plugins/auth-backend/src/providers/okta/provider.ts +++ b/plugins/auth-backend/src/providers/okta/provider.ts @@ -59,10 +59,10 @@ export class OktaAuthProvider implements OAuthProviderHandlers { * allowing us to avoid using express-session in order to integrate with Okta. */ private _store: StateStore = { - store(req: Request, cb: any) { + store({}, cb: any) { cb(null, null); }, - verify(req: Request, state: string, cb: any) { + verify({}, {}, cb: any) { cb(null, true); }, } From 72387eb720ba4c9c94c0f7bdd404774f146b0d3a Mon Sep 17 00:00:00 2001 From: Nicholas Pirrello Date: Thu, 25 Jun 2020 18:28:51 -0400 Subject: [PATCH 19/25] Fix linting and tsc issues --- .../src/apis/implementations/auth/okta/OktaAuth.ts | 10 +++++----- plugins/auth-backend/src/providers/okta/provider.ts | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/core-api/src/apis/implementations/auth/okta/OktaAuth.ts b/packages/core-api/src/apis/implementations/auth/okta/OktaAuth.ts index 5631648016..f10ec4ebce 100644 --- a/packages/core-api/src/apis/implementations/auth/okta/OktaAuth.ts +++ b/packages/core-api/src/apis/implementations/auth/okta/OktaAuth.ts @@ -158,14 +158,14 @@ class OktaAuth implements return session?.profile; } - static normalizeScopes(scope?: string | string[]): Set { - if (!scope) { + static normalizeScopes(scopes?: string | string[]): Set { + if (!scopes) { return new Set(); } - const scopeList = Array.isArray(scope) - ? scope - : scope.split(/[\s|,]/).filter(Boolean); + const scopeList = Array.isArray(scopes) + ? scopes + : scopes.split(/[\s|,]/).filter(Boolean); const normalizedScopes = scopeList.map(scope => { if (OKTA_OIDC_SCOPES.has(scope)) { diff --git a/plugins/auth-backend/src/providers/okta/provider.ts b/plugins/auth-backend/src/providers/okta/provider.ts index 788af9c4bd..2dd3b57137 100644 --- a/plugins/auth-backend/src/providers/okta/provider.ts +++ b/plugins/auth-backend/src/providers/okta/provider.ts @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import express, { Request } from 'express'; +import express from 'express'; import { OAuthProvider } from '../../lib/OAuthProvider'; import { Strategy as OktaStrategy } from 'passport-okta-oauth'; import passport from 'passport'; From d3a990ac0492ace10cb7d0f72a4900ee0c7b5d57 Mon Sep 17 00:00:00 2001 From: Nicholas Pirrello Date: Thu, 25 Jun 2020 19:42:32 -0400 Subject: [PATCH 20/25] Add prompt: consent. Adjust unused types for StateStore --- plugins/auth-backend/src/providers/okta/provider.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/plugins/auth-backend/src/providers/okta/provider.ts b/plugins/auth-backend/src/providers/okta/provider.ts index 2dd3b57137..e73843bb0c 100644 --- a/plugins/auth-backend/src/providers/okta/provider.ts +++ b/plugins/auth-backend/src/providers/okta/provider.ts @@ -59,10 +59,10 @@ export class OktaAuthProvider implements OAuthProviderHandlers { * allowing us to avoid using express-session in order to integrate with Okta. */ private _store: StateStore = { - store({}, cb: any) { + store(_req: express.Request, cb: any) { cb(null, null); }, - verify({}, {}, cb: any) { + verify(_req: express.Request, _state: string, cb: any) { cb(null, true); }, } @@ -104,7 +104,12 @@ export class OktaAuthProvider implements OAuthProviderHandlers { req: express.Request, options: Record ): Promise { - return await executeRedirectStrategy(req, this._strategy, options); + const providerOptions = { + ...options, + accessType: 'offline', + prompt: 'consent', + }; + return await executeRedirectStrategy(req, this._strategy, providerOptions); } async handler( From ced2fb19252c3b8579d12e7a959abaa0f085c680 Mon Sep 17 00:00:00 2001 From: Jeff Feng <46946747+fengypants@users.noreply.github.com> Date: Fri, 26 Jun 2020 03:09:10 -0400 Subject: [PATCH 21/25] Update FAQ.md (#1464) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update FAQ.md — Changed anchor links to relative links (/docs/FAQ.md#heading-name) — Restored the heading + answer for "What is a "plugin" in Backstage?" — Cleaned up extra spaces throughout and added line breaks to the answer for "What is the end-to-end user flow?". * Update FAQ.md --- docs/FAQ.md | 98 ++++++++++++++++++++++++++++------------------------- 1 file changed, 51 insertions(+), 47 deletions(-) diff --git a/docs/FAQ.md b/docs/FAQ.md index 7bfdbec478..7d568a840e 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -15,11 +15,11 @@ No, but it can be! Backstage is designed to be a developer portal for all your infrastructure tooling, services, and documentation. So, it's not a monitoring platform — but that doesn't mean you can't integrate a monitoring tool into Backstage by writing -[a plugin](https://github.com/spotify/backstage/blob/master/docs/FAQ.md#what-is-a-plugin-in-backstage). +[a plugin](/docs/FAQ.md#what-is-a-plugin-in-backstage). ### How is Backstage licensed? -Backstage was released as open sourced software by Spotify and is licensed under +Backstage was released as open source software by Spotify and is licensed under [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0). ### Why did we open source Backstage? @@ -36,16 +36,16 @@ more, read our blog post, Yes, we've already started releasing open source versions of some of the plugins we use here, and we'll continue to do so. -[Plugins](https://github.com/spotify/backstage/blob/master/docs/FAQ.md#what-is-a-plugin-in-backstage) are the +[Plugins](/docs/FAQ.md#what-is-a-plugin-in-backstage) are the building blocks of functionality in Backstage. We have over 120 plugins inside Spotify — many of those are specialized for our use, so will remain internal and proprietary to us. But we estimate that about a third of our existing plugins make good open source candidates. (And we'll probably end up writing some brand -new ones, too.) ​ +new ones, too.) ### What's the roadmap for Backstage? -​ We envision three phases, which you can learn about in +We envision three phases, which you can learn about in [our project roadmap](https://github.com/spotify/backstage#project-roadmap). Even though the open source version of Backstage is relatively new compared to our internal version, we have already begun work on various aspects of all three @@ -80,134 +80,138 @@ knew that we would like to use. It strikes a good balance between power, customizability, and ease of use. A core focus of Backstage is to make plugin developers productive with as few hurdles as possible. Material-UI lets plugin makers get going easily with both -well-known tech and a large flora of components. ​ +well-known tech and a large flora of components. ### What technology does Backstage use? -​ The code base is a large-scale React application that uses TypeScript. For +The code base is a large-scale React application that uses TypeScript. For [Phase 2](https://github.com/spotify/backstage#project-roadmap), we plan to use -Node.js and GraphQL. ​ +Node.js and GraphQL. ### What is the end-to-end user flow? The happy path story. -​ There are three main user profiles for Backstage: the integrator, the -contributor, and the software engineer. ​ The **integrator** hosts the Backstage -app and configures which plugins are available to use in the app. ​ The -**contributor** adds functionality to the app by writing plugins. ​ The -**software engineer** uses the app's functionality and interacts with its -plugins. ​ +There are three main user profiles for Backstage: the integrator, the +contributor, and the software engineer. -### What is the use of a "plugin" in Backstage? +The **integrator** hosts the Backstage app and configures which plugins are available to use in the app. -​ A Backstage Plugin adds functionality to Backstage. ​ +The **contributor** adds functionality to the app by writing plugins. +The **software engineer** uses the app's functionality and interacts with its plugins. + +### What is a "plugin" in Backstage? + +Plugins are what provide the feature functionality in Backstage. They are used to integrate different systems into Backstage's frontend, so that the developer gets a consistent UX, no matter what tool or service is being accessed on the other side. + +Each plugin is treated as a self-contained web app and can include almost any type of content. Plugins all use a common set of platform APIs and reusable UI components. Plugins can fetch data either from the backend or an API exposed through the proxy. + +Learn more about [the different components](https://github.com/spotify/backstage#overview) that make up Backstage. ### Do I have to write plugins in TypeScript? -​ No, you can use JavaScript if you prefer. ​ We want to keep the Backstage core -APIs in TypeScript, but aren't forcing it on individual plugins. ​ +No, you can use JavaScript if you prefer. We want to keep the Backstage core +APIs in TypeScript, but aren't forcing it on individual plugins. ### How do I find out if a plugin already exists? -​ Before you write a plugin, +Before you write a plugin, [search the plugin issues](https://github.com/spotify/backstage/issues?q=is%3Aissue+label%3Aplugin+) to see if it already exists or is in the works. If no one's thought of it yet, great! Open a new issue as [a plugin suggestion](https://github.com/spotify/backstage/issues/new/choose) and describe what your plugin will do. This will help coordinate our -contributors' efforts and avoid duplicating existing functionality. ​ In the +contributors' efforts and avoid duplicating existing functionality. In the future, we will create [a plugin gallery](https://github.com/spotify/backstage/issues/260) where people -can browse and search for all available plugins. ​ +can browse and search for all available plugins. ### Which plugin is used the most at Spotify? -By far, our most-used plugin is our TechDocs plugin, which we use for creating technical documentation. Our philosophy at Spotify is to treat "docs like code", where you write documentation using the same workflow as you write your code. This makes it easier to create, find, and update documentation. We hope to release [the open source version](https://github.com/spotify/backstage/issues/687) in the future. (See also: "[Will Spotify's internal plugins be open sourced, too?](https://github.com/spotify/backstage/blob/master/docs/FAQ.md#will-spotifys-internal-plugins-be-open-sourced-too)" above) +By far, our most-used plugin is our TechDocs plugin, which we use for creating technical documentation. Our philosophy at Spotify is to treat "docs like code", where you write documentation using the same workflow as you write your code. This makes it easier to create, find, and update documentation. We hope to release [the open source version](https://github.com/spotify/backstage/issues/687) in the future. (See also: "[Will Spotify's internal plugins be open sourced, too?](/docs/FAQ.md#will-spotifys-internal-plugins-be-open-sourced-too)" above) ### Are you planning to have plugins baked into the repo? Or should they be developed in separate repos? -​ Contributors can add open source plugins to the plugins directory in +Contributors can add open source plugins to the plugins directory in [this monorepo](https://github.com/spotify/backstage). Integrators can then configure which open source plugins are available to use in their instance of the app. Open source plugins are downloaded as npm packages published in the -open source repository. ​ While we encourage using the open source model, we +open source repository. While we encourage using the open source model, we know there are cases where contributors might want to experiment internally or keep their plugins closed source. Contributors writing closed source plugins should develop them in the plugins directory in their own Backstage repository. -Integrators also configure closed source plugins locally from the monorepo. ​ +Integrators also configure closed source plugins locally from the monorepo. ### Any plans for integrating with other repository managers, such as GitLab or Bitbucket? -​ We chose GitHub because it is the tool that we are most familiar with, so that +We chose GitHub because it is the tool that we are most familiar with, so that will naturally lead to integrations for GitHub being developed at an early -stage. ​ Hosting this project on GitHub does not exclude integrations with +stage. Hosting this project on GitHub does not exclude integrations with alternatives, such as [GitLab](https://github.com/spotify/backstage/issues?q=is%3Aissue+is%3Aopen+GitLab) or Bitbucket. We believe that in time there will be plugins that will provide -functionality for these tools as well. Hopefully, contributed by the community! -​ Also note, implementations of Backstage can be hosted wherever you feel suits -your needs best. ​ +functionality for these tools as well. Hopefully, contributed by the community! Also note, implementations of Backstage can be hosted wherever you feel suits +your needs best. ### Who maintains Backstage? -​ Spotify will maintain the open source core, but we envision different parts of +Spotify will maintain the open source core, but we envision different parts of the project being maintained by various companies and contributors. We also envision a large, diverse ecosystem of open source plugins, which would be -maintained by their original authors/contributors or by the community. ​ When it +maintained by their original authors/contributors or by the community. When it comes to [deployment](https://github.com/spotify/backstage/blob/master/DEPLOYMENT.md), the system integrator (typically, the infrastructure team in your organization) -maintains Backstage in your own environment. ​ +maintains Backstage in your own environment. ### Does Spotify provide a managed version of Backstage? -​ No, this is not a service offering. We build the piece of software, and +No, this is not a service offering. We build the piece of software, and someone in your infrastructure team is responsible for [deploying](https://github.com/spotify/backstage/blob/master/DEPLOYMENT.md) and -maintaining it. ​ +maintaining it. ### How secure is Backstage? -​ We take security seriously. When it comes to packages and code we scan our +We take security seriously. When it comes to packages and code we scan our repositories periodically and update our packages to the latest versions. When it comes to deployment of Backstage within an organisation it depends on the deployment and security setup in your organisation. Reach out to us on [Discord](https://discord.gg/MUpMjP2) if you have specific queries. Please report sensitive security issues via Spotify's -[bug-bounty program](https://hackerone.com/spotify) rather than GitHub. ​ +[bug-bounty program](https://hackerone.com/spotify) rather than GitHub. ### Does Backstage collect any information that is shared with Spotify? -​ No. Backstage does not collect any telemetry from any third party using the +No. Backstage does not collect any telemetry from any third party using the platform. Spotify, and the open source community, does have access to [GitHub Insights](https://github.com/features/insights), which contains -information such as contributors, commits, traffic, and dependencies. ​ +information such as contributors, commits, traffic, and dependencies. Backstage is an open platform, but you are in control of your own data. You control who has access to any data you provide to your version of Backstage and -who that data is shared with. ​ +who that data is shared with. ### Can Backstage be used to build something other than a developer portal? -​ Yes. The core frontend framework could be used for building any large-scale +Yes. The core frontend framework could be used for building any large-scale web application where (1) multiple teams are building separate parts of the app, -and (2) you want the overall experience to be consistent. ​ That being said, in +and (2) you want the overall experience to be consistent. That being said, in [Phase 2](https://github.com/spotify/backstage#project-roadmap) of the project we will add features that are needed for developer portals and systems for -managing software ecosystems. Our ambition will be to keep Backstage modular. ​ +managing software ecosystems. Our ambition will be to keep Backstage modular. ### How can I get involved? -​ Jump right in! Come help us fix some of the +Jump right in! Come help us fix some of the [early bugs and first issues](https://github.com/spotify/backstage/labels/good%20first%20issue) or reach [a new milestone](https://github.com/spotify/backstage/milestones). Or write an open source plugin for Backstage, like this [Lighthouse plugin](https://github.com/spotify/backstage/tree/master/plugins/lighthouse). -​ See all the ways you can +See all the ways you can [contribute here](https://github.com/spotify/backstage/blob/master/CONTRIBUTING.md). -We'd love to have you as part of the community. ​ +We'd love to have you as part of the community. ### Can I join the Backstage team? -​ If you're interested in being part of the Backstage team, reach out to +If you're interested in being part of the Backstage team, reach out to [fossopportunities@spotify.com](mailto:fossopportunities@spotify.com) From 62130b805041c7e230c1d9c2657987441703ed69 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 26 Jun 2020 09:09:49 +0200 Subject: [PATCH 22/25] build(deps): bump inquirer from 7.1.0 to 7.2.0 (#1451) Bumps [inquirer](https://github.com/SBoudrias/Inquirer.js) from 7.1.0 to 7.2.0. - [Release notes](https://github.com/SBoudrias/Inquirer.js/releases) - [Commits](https://github.com/SBoudrias/Inquirer.js/compare/inquirer@7.1.0...inquirer@7.2.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- yarn.lock | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/yarn.lock b/yarn.lock index e980d91f57..fa00ad8540 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10530,9 +10530,9 @@ inquirer@^6.2.0: through "^2.3.6" inquirer@^7.0.0, inquirer@^7.0.4: - version "7.1.0" - resolved "https://registry.npmjs.org/inquirer/-/inquirer-7.1.0.tgz#1298a01859883e17c7264b82870ae1034f92dd29" - integrity sha512-5fJMWEmikSYu0nv/flMc475MhGbB7TSPd/2IpFV4I4rMklboCH2rQjYY5kKiYGHqUF9gvaambupcJFFG9dvReg== + version "7.2.0" + resolved "https://registry.npmjs.org/inquirer/-/inquirer-7.2.0.tgz#63ce99d823090de7eb420e4bb05e6f3449aa389a" + integrity sha512-E0c4rPwr9ByePfNlTIB8z51kK1s2n6jrHuJeEHENl/sbq2G/S1auvibgEwNR4uSyiU+PiYHqSwsgGiXjG8p5ZQ== dependencies: ansi-escapes "^4.2.1" chalk "^3.0.0" @@ -16565,20 +16565,13 @@ run-queue@^1.0.0, run-queue@^1.0.3: dependencies: aproba "^1.1.1" -rxjs@^6.3.3, rxjs@^6.5.5: +rxjs@^6.3.3, rxjs@^6.4.0, rxjs@^6.5.3, rxjs@^6.5.4, rxjs@^6.5.5: version "6.5.5" resolved "https://registry.npmjs.org/rxjs/-/rxjs-6.5.5.tgz#c5c884e3094c8cfee31bf27eb87e54ccfc87f9ec" integrity sha512-WfQI+1gohdf0Dai/Bbmk5L5ItH5tYqm3ki2c5GdWhKjalzjg93N3avFjVStyZZz+A2Em+ZxKH5bNghw9UeylGQ== dependencies: tslib "^1.9.0" -rxjs@^6.4.0, rxjs@^6.5.3, rxjs@^6.5.4: - version "6.5.4" - resolved "https://registry.npmjs.org/rxjs/-/rxjs-6.5.4.tgz#e0777fe0d184cec7872df147f303572d414e211c" - integrity sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q== - dependencies: - tslib "^1.9.0" - safe-buffer@5.1.1: version "5.1.1" resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" From 09abd44666172ef7cdb02eab4f0cfaaf26b247f3 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 26 Jun 2020 09:12:39 +0200 Subject: [PATCH 23/25] build(deps-dev): bump cypress from 4.7.0 to 4.9.0 (#1454) Bumps [cypress](https://github.com/cypress-io/cypress) from 4.7.0 to 4.9.0. - [Release notes](https://github.com/cypress-io/cypress/releases) - [Commits](https://github.com/cypress-io/cypress/compare/v4.7.0...v4.9.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- yarn.lock | 92 ++++++++++++++++++------------------------------------- 1 file changed, 30 insertions(+), 62 deletions(-) diff --git a/yarn.lock b/yarn.lock index fa00ad8540..b42ca52288 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4677,10 +4677,10 @@ aproba@^2.0.0: resolved "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== -arch@2.1.1: - version "2.1.1" - resolved "https://registry.npmjs.org/arch/-/arch-2.1.1.tgz#8f5c2731aa35a30929221bb0640eed65175ec84e" - integrity sha512-BLM56aPo9vLLFVa8+/+pJLnrZ7QGGTVHWsCwieAWT9o9K8UeGaQbzZbGoabWLOo2ksBCztoXdqBZBplqLDDCSg== +arch@2.1.2: + version "2.1.2" + resolved "https://registry.npmjs.org/arch/-/arch-2.1.2.tgz#0c52bbe7344bb4fa260c443d2cbad9c00ff2f0bf" + integrity sha512-NTBIIbAfkJeIletyABbVtdPgeKfDafR+1mZV/AyyfC1UkVkp9iUjV+wwmqtUgphHYajbI86jejBJp5e+jkGTiQ== are-we-there-yet@~1.1.2: version "1.1.5" @@ -4917,7 +4917,7 @@ async@^2.6.1, async@^2.6.2: dependencies: lodash "^4.17.14" -async@^3.1.0: +async@^3.2.0: version "3.2.0" resolved "https://registry.npmjs.org/async/-/async-3.2.0.tgz#b3a2685c5ebb641d3de02d161002c60fc9f85720" integrity sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw== @@ -6343,21 +6343,16 @@ comma-separated-tokens@^1.0.0: resolved "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz#632b80b6117867a158f1080ad498b2fbe7e3f5ea" integrity sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw== -commander@4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/commander/-/commander-4.1.0.tgz#545983a0603fe425bc672d66c9e3c89c42121a83" - integrity sha512-NIQrwvv9V39FHgGFm36+U9SMQzbiHvU79k+iADraJTpmrFFfx7Ds0IvDoAdZsDrknlkRk14OYoWXb57uTh7/sw== +commander@4.1.1, commander@^4.0.0, commander@^4.0.1, commander@^4.1.1: + version "4.1.1" + resolved "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" + integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== commander@^2.11.0, commander@^2.19.0, commander@^2.20.0, commander@~2.20.3: version "2.20.3" resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== -commander@^4.0.0, commander@^4.0.1, commander@^4.1.1: - version "4.1.1" - resolved "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" - integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== - commander@^5.1.0: version "5.1.0" resolved "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae" @@ -7099,38 +7094,38 @@ cyclist@^1.0.1: integrity sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk= cypress@*, cypress@^4.2.0: - version "4.7.0" - resolved "https://registry.npmjs.org/cypress/-/cypress-4.7.0.tgz#3ea29bddaf9a1faeaa5b8d54b60a84ed1cafa83d" - integrity sha512-Vav6wUFhPRlImIND/2lOQlUnAWzgCC/iXyJlJjX9nJOJul5LC1vUpf/m8Oiae870PFPyT0ZLLwPHKTXZNdXmHw== + version "4.9.0" + resolved "https://registry.npmjs.org/cypress/-/cypress-4.9.0.tgz#c188a3864ddf841c0fdc81a9e4eff5cf539cd1c1" + integrity sha512-qGxT5E0j21FPryzhb0OBjCdhoR/n1jXtumpFFSBPYWsaZZhNaBvc3XlBUDEZKkkXPsqUFYiyhWdHN/zo0t5FcA== dependencies: "@cypress/listr-verbose-renderer" "0.4.1" "@cypress/request" "2.88.5" "@cypress/xvfb" "1.2.4" "@types/sinonjs__fake-timers" "6.0.1" "@types/sizzle" "2.3.2" - arch "2.1.1" + arch "2.1.2" bluebird "3.7.2" cachedir "2.3.0" chalk "2.4.2" check-more-types "2.24.0" cli-table3 "0.5.1" - commander "4.1.0" + commander "4.1.1" common-tags "1.8.0" debug "4.1.1" - eventemitter2 "4.1.2" + eventemitter2 "6.4.2" execa "1.0.0" executable "4.1.1" extract-zip "1.7.0" fs-extra "8.1.0" - getos "3.1.4" + getos "3.2.1" is-ci "2.0.0" - is-installed-globally "0.1.0" + is-installed-globally "0.3.2" lazy-ass "1.6.0" listr "0.14.3" lodash "4.17.15" log-symbols "3.0.0" minimist "1.2.5" - moment "2.24.0" + moment "2.26.0" ospath "1.2.2" pretty-bytes "5.3.0" ramda "0.26.1" @@ -8360,10 +8355,10 @@ event-stream@=3.3.4: stream-combiner "~0.0.4" through "~2.3.1" -eventemitter2@4.1.2: - version "4.1.2" - resolved "https://registry.npmjs.org/eventemitter2/-/eventemitter2-4.1.2.tgz#0e1a8477af821a6ef3995b311bf74c23a5247f15" - integrity sha1-DhqEd6+CGm7zmVsxG/dMI6UkfxU= +eventemitter2@6.4.2: + version "6.4.2" + resolved "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.2.tgz#f31f8b99d45245f0edbc5b00797830ff3b388970" + integrity sha512-r/Pwupa5RIzxIHbEKCkNXqpEQIIT4uQDxmP4G/Lug/NokVUWj0joz/WzWl3OxRpC5kDrH/WdiUJoR+IrwvXJEw== eventemitter3@^3.1.0: version "3.1.2" @@ -9326,12 +9321,12 @@ getopts@2.2.5: resolved "https://registry.npmjs.org/getopts/-/getopts-2.2.5.tgz#67a0fe471cacb9c687d817cab6450b96dde8313b" integrity sha512-9jb7AW5p3in+IiJWhQiZmmwkpLaR/ccTWdWQCtZM66HJcHHLegowh4q4tSD7gouUyeNvFWRavfK9GXosQHDpFA== -getos@3.1.4: - version "3.1.4" - resolved "https://registry.npmjs.org/getos/-/getos-3.1.4.tgz#29cdf240ed10a70c049add7b6f8cb08c81876faf" - integrity sha512-UORPzguEB/7UG5hqiZai8f0vQ7hzynMQyJLxStoQ8dPGAcmgsfXOPA4iE/fGtweHYkK+z4zc9V0g+CIFRf5HYw== +getos@3.2.1: + version "3.2.1" + resolved "https://registry.npmjs.org/getos/-/getos-3.2.1.tgz#0134d1f4e00eb46144c5a9c0ac4dc087cbb27dc5" + integrity sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q== dependencies: - async "^3.1.0" + async "^3.2.0" getpass@^0.1.1: version "0.1.7" @@ -9436,13 +9431,6 @@ glob@7.1.6, glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glo once "^1.3.0" path-is-absolute "^1.0.0" -global-dirs@^0.1.0: - version "0.1.1" - resolved "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445" - integrity sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU= - dependencies: - ini "^1.3.4" - global-dirs@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/global-dirs/-/global-dirs-2.0.1.tgz#acdf3bb6685bcd55cb35e8a052266569e9469201" @@ -10845,15 +10833,7 @@ is-in-browser@^1.0.2, is-in-browser@^1.1.3: resolved "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz#56ff4db683a078c6082eb95dad7dc62e1d04f835" integrity sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU= -is-installed-globally@0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz#0dfd98f5a9111716dd535dda6492f67bf3d25a80" - integrity sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA= - dependencies: - global-dirs "^0.1.0" - is-path-inside "^1.0.0" - -is-installed-globally@^0.3.1: +is-installed-globally@0.3.2, is-installed-globally@^0.3.1: version "0.3.2" resolved "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.3.2.tgz#fd3efa79ee670d1187233182d5b0a1dd00313141" integrity sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g== @@ -10927,13 +10907,6 @@ is-path-in-cwd@^2.0.0: dependencies: is-path-inside "^2.1.0" -is-path-inside@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" - integrity sha1-jvW33lBDej/cprToZe96pVy0gDY= - dependencies: - path-is-inside "^1.0.1" - is-path-inside@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz#7c9810587d659a40d27bcdb4d5616eab059494b2" @@ -13059,12 +13032,7 @@ modify-values@^1.0.0: resolved "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022" integrity sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw== -moment@2.24.0: - version "2.24.0" - resolved "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b" - integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg== - -moment@^2.25.3, moment@^2.26.0: +moment@2.26.0, moment@^2.25.3, moment@^2.26.0: version "2.26.0" resolved "https://registry.npmjs.org/moment/-/moment-2.26.0.tgz#5e1f82c6bafca6e83e808b30c8705eed0dcbd39a" integrity sha512-oIixUO+OamkUkwjhAVE18rAMfRJNsNe/Stid/gwHSOfHrOtw9EhAY2AHvdKZ/k/MggcYELFCJz/Sn2pL8b8JMw== @@ -14304,7 +14272,7 @@ path-is-absolute@^1.0.0: resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= -path-is-inside@^1.0.1, path-is-inside@^1.0.2: +path-is-inside@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= From 22d1c40629ab0a09ccb5da64ac504b55aaccea0a Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 26 Jun 2020 09:13:24 +0200 Subject: [PATCH 24/25] build(deps): bump graphiql from 1.0.0-alpha.10 to 1.0.3 (#1453) Bumps [graphiql](https://github.com/graphql/graphiql) from 1.0.0-alpha.10 to 1.0.3. - [Release notes](https://github.com/graphql/graphiql/releases) - [Changelog](https://github.com/graphql/graphiql/blob/main/CHANGELOG.md) - [Commits](https://github.com/graphql/graphiql/compare/graphiql@1.0.0-alpha.10...graphiql@1.0.3) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- yarn.lock | 355 +++++++++++------------------------------------------- 1 file changed, 71 insertions(+), 284 deletions(-) diff --git a/yarn.lock b/yarn.lock index b42ca52288..0dd8044248 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1184,71 +1184,6 @@ unique-filename "^1.1.1" which "^1.3.1" -"@graphql-toolkit/common@0.10.7", "@graphql-toolkit/common@~0.10.2": - version "0.10.7" - resolved "https://registry.npmjs.org/@graphql-toolkit/common/-/common-0.10.7.tgz#e5d4ddeae080c4f7357bc7d6a8d02e75578e9bd1" - integrity sha512-epcJvmIAo+vSEY76F0Dj1Ef6oeewT5pdMe1obHj7LHXN9V22O86aQzwdEEm1iG91qROqSw/apcDnSCMjuVeQVA== - dependencies: - aggregate-error "3.0.1" - camel-case "4.1.1" - graphql-tools "5.0.0" - lodash "4.17.15" - -"@graphql-toolkit/core@~0.10.2": - version "0.10.7" - resolved "https://registry.npmjs.org/@graphql-toolkit/core/-/core-0.10.7.tgz#e4d86d9e439fbb05b634054b0865c16d488fad97" - integrity sha512-LXcFLG7XcRJrPz/xD+0cExzLx/ptVynDM20650/FbmHbKOU50d9mSbcsrzAOq/3f4q3HrRDssvn0f6pPm0EHMg== - dependencies: - "@graphql-toolkit/common" "0.10.7" - "@graphql-toolkit/schema-merging" "0.10.7" - aggregate-error "3.0.1" - globby "11.0.0" - import-from "^3.0.0" - is-glob "4.0.1" - lodash "4.17.15" - p-limit "2.3.0" - resolve-from "5.0.0" - tslib "1.11.2" - unixify "1.0.0" - valid-url "1.0.9" - -"@graphql-toolkit/graphql-file-loader@~0.10.2": - version "0.10.7" - resolved "https://registry.npmjs.org/@graphql-toolkit/graphql-file-loader/-/graphql-file-loader-0.10.7.tgz#496e49712def12449b339739d3583ed1bda7a24f" - integrity sha512-6tUIuw/YBlm0VyVgXgMrOXsEQ+WpXVgr2NQwHNzmZo82kPGqImveq7A2D3gBWLyVTcinDScRcKJMxM4kCF5T0A== - dependencies: - "@graphql-toolkit/common" "0.10.7" - tslib "1.11.2" - -"@graphql-toolkit/json-file-loader@~0.10.2": - version "0.10.7" - resolved "https://registry.npmjs.org/@graphql-toolkit/json-file-loader/-/json-file-loader-0.10.7.tgz#6ac38258bc3da8540b38232b71bb5820bf02cff6" - integrity sha512-nVISrODqvn5LiQ4nKL5pz1Let/W1tuj2viEwrNyTS+9mcjaCE2nhV5MOK/7ZY0cR+XeA4N2u65EH1lQd63U3Cw== - dependencies: - "@graphql-toolkit/common" "0.10.7" - tslib "1.11.2" - -"@graphql-toolkit/schema-merging@0.10.7", "@graphql-toolkit/schema-merging@~0.10.2": - version "0.10.7" - resolved "https://registry.npmjs.org/@graphql-toolkit/schema-merging/-/schema-merging-0.10.7.tgz#7b33becd48629bc656d602405c0b5c17d33ebd85" - integrity sha512-VngxJbVdRfXYhdMLhL90pqN+hD/2XTZwhHPGvpWqmGQhT6roc98yN3xyDyrWFYYsuiY4gTexdmrHQ3d7mzitwA== - dependencies: - "@graphql-toolkit/common" "0.10.7" - deepmerge "4.2.2" - graphql-tools "5.0.0" - tslib "1.11.2" - -"@graphql-toolkit/url-loader@~0.10.2": - version "0.10.7" - resolved "https://registry.npmjs.org/@graphql-toolkit/url-loader/-/url-loader-0.10.7.tgz#0de998eeeaebcbf918526a26cb5f30f8250211f0" - integrity sha512-Ec3T4Zuo63LwG+RfK2ryz8ChPfncBf8fiSJ1xr68FtLDVznDNulvlNKFbfREE5koWejwsnJrjLCv6IX5IbhExg== - dependencies: - "@graphql-toolkit/common" "0.10.7" - cross-fetch "3.0.4" - graphql-tools "5.0.0" - tslib "1.11.2" - valid-url "1.0.9" - "@hapi/address@^2.1.2": version "2.1.4" resolved "https://registry.npmjs.org/@hapi/address/-/address-2.1.4.tgz#5d67ed43f3fd41a69d4b9ff7b56e7c0d1d0a81e5" @@ -4331,13 +4266,6 @@ "@webassemblyjs/wast-parser" "1.9.0" "@xtuc/long" "4.2.2" -"@wry/equality@^0.1.2": - version "0.1.11" - resolved "https://registry.npmjs.org/@wry/equality/-/equality-0.1.11.tgz#35cb156e4a96695aa81a9ecc4d03787bc17f1790" - integrity sha512-mwEVBDUVODlsQQ5dfuLUS5/Tf7jqUKyhKYHmVi4fPB6bDMOfWvUPJmKgS1Z7Za/sOI3vzWt4+O7yCiL/70MogA== - dependencies: - tslib "^1.9.3" - "@xobotyi/scrollbar-width@1.9.5": version "1.9.5" resolved "https://registry.npmjs.org/@xobotyi/scrollbar-width/-/scrollbar-width-1.9.5.tgz#80224a6919272f405b87913ca13b92929bdf3c4d" @@ -4465,7 +4393,7 @@ agentkeepalive@^3.4.1: dependencies: humanize-ms "^1.2.1" -aggregate-error@3.0.1, aggregate-error@^3.0.0: +aggregate-error@^3.0.0: version "3.0.1" resolved "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz#db2fe7246e536f40d9b5442a39e117d7dd6a24e0" integrity sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA== @@ -4623,45 +4551,6 @@ anymatch@^3.0.3, anymatch@~3.1.1: normalize-path "^3.0.0" picomatch "^2.0.4" -apollo-link-http-common@^0.2.14: - version "0.2.16" - resolved "https://registry.npmjs.org/apollo-link-http-common/-/apollo-link-http-common-0.2.16.tgz#756749dafc732792c8ca0923f9a40564b7c59ecc" - integrity sha512-2tIhOIrnaF4UbQHf7kjeQA/EmSorB7+HyJIIrUjJOKBgnXwuexi8aMecRlqTIDWcyVXCeqLhUnztMa6bOH/jTg== - dependencies: - apollo-link "^1.2.14" - ts-invariant "^0.4.0" - tslib "^1.9.3" - -apollo-link@^1.2.12, apollo-link@^1.2.14: - version "1.2.14" - resolved "https://registry.npmjs.org/apollo-link/-/apollo-link-1.2.14.tgz#3feda4b47f9ebba7f4160bef8b977ba725b684d9" - integrity sha512-p67CMEFP7kOG1JZ0ZkYZwRDa369w5PIjtMjvrQd/HnIV8FRsHRqLqK+oAZQnFa1DDdZtOtHTi+aMIW6EatC2jg== - dependencies: - apollo-utilities "^1.3.0" - ts-invariant "^0.4.0" - tslib "^1.9.3" - zen-observable-ts "^0.8.21" - -apollo-upload-client@^13.0.0: - version "13.0.0" - resolved "https://registry.npmjs.org/apollo-upload-client/-/apollo-upload-client-13.0.0.tgz#146d1ddd85d711fcac8ca97a72d3ca6787f2b71b" - integrity sha512-lJ9/bk1BH1lD15WhWRha2J3+LrXrPIX5LP5EwiOUHv8PCORp4EUrcujrA3rI5hZeZygrTX8bshcuMdpqpSrvtA== - dependencies: - "@babel/runtime" "^7.9.2" - apollo-link "^1.2.12" - apollo-link-http-common "^0.2.14" - extract-files "^8.0.0" - -apollo-utilities@^1.3.0: - version "1.3.4" - resolved "https://registry.npmjs.org/apollo-utilities/-/apollo-utilities-1.3.4.tgz#6129e438e8be201b6c55b0f13ce49d2c7175c9cf" - integrity sha512-pk2hiWrCXMAy2fRPwEyhvka+mqwzeP60Jr1tRYi5xru+3ko94HI9o6lK0CT33/w4RDlxWchmdhDCrvdr+pHCig== - dependencies: - "@wry/equality" "^0.1.2" - fast-json-stable-stringify "^2.0.0" - ts-invariant "^0.4.0" - tslib "^1.10.0" - app-root-dir@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/app-root-dir/-/app-root-dir-1.0.2.tgz#38187ec2dea7577fff033ffcb12172692ff6e118" @@ -5820,7 +5709,7 @@ callsites@^3.0.0: resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== -camel-case@4.1.1, camel-case@^4.1.1: +camel-case@^4.1.1: version "4.1.1" resolved "https://registry.npmjs.org/camel-case/-/camel-case-4.1.1.tgz#1fc41c854f00e2f7d0139dfeba1542d6896fe547" integrity sha512-7fa2WcG4fYFkclIvEmxBbTvmibwF2/agfEBc6q3lOpVu0A13ltLsA+Hr/8Hp6kp5f+G7hKi6t8lys6XxP+1K6Q== @@ -6221,13 +6110,13 @@ code-point-at@^1.0.0: resolved "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= -codemirror-graphql@^0.12.0-alpha.8: - version "0.12.0-alpha.8" - resolved "https://registry.npmjs.org/codemirror-graphql/-/codemirror-graphql-0.12.0-alpha.8.tgz#cd7653299baefcdff2349bc9c3def9549c78775c" - integrity sha512-leCFSjrwtdKQE70ROWIUoc1U6F8fy6i+cd9/0D1dRbEecoleCt5+zODdANETw9map50kxNPf3EcGW4BPYj14hw== +codemirror-graphql@^0.12.0: + version "0.12.0" + resolved "https://registry.npmjs.org/codemirror-graphql/-/codemirror-graphql-0.12.0.tgz#55f782ffaaea7ff8dbda037e6b97b584dff2402a" + integrity sha512-C/0vKzQT5Uw+DLz6/MwKer29FQM52sh9Bem+VdDW42094j8nES1sdnuqj4k5ahNdQpW4FmVeoj/ngn2g3AWmgg== dependencies: - graphql-language-service-interface "^2.4.0-alpha.8" - graphql-language-service-parser "^1.6.0-alpha.4" + graphql-language-service-interface "^2.4.0" + graphql-language-service-parser "^1.6.0" codemirror@^5.52.2: version "5.53.2" @@ -6686,17 +6575,6 @@ cors@^2.8.5: object-assign "^4" vary "^1" -cosmiconfig@6.0.0, cosmiconfig@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz#da4fee853c52f6b1e6935f41c1a2fc50bd4a9982" - integrity sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg== - dependencies: - "@types/parse-json" "^4.0.0" - import-fresh "^3.1.0" - parse-json "^5.0.0" - path-type "^4.0.0" - yaml "^1.7.2" - cosmiconfig@^5.0.0, cosmiconfig@^5.1.0, cosmiconfig@^5.2.1: version "5.2.1" resolved "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a" @@ -6707,6 +6585,17 @@ cosmiconfig@^5.0.0, cosmiconfig@^5.1.0, cosmiconfig@^5.2.1: js-yaml "^3.13.1" parse-json "^4.0.0" +cosmiconfig@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz#da4fee853c52f6b1e6935f41c1a2fc50bd4a9982" + integrity sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg== + dependencies: + "@types/parse-json" "^4.0.0" + import-fresh "^3.1.0" + parse-json "^5.0.0" + path-type "^4.0.0" + yaml "^1.7.2" + create-ecdh@^4.0.0: version "4.0.3" resolved "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff" @@ -6753,7 +6642,7 @@ cross-env@^7.0.0: dependencies: cross-spawn "^7.0.1" -cross-fetch@3.0.4, cross-fetch@^3.0.4: +cross-fetch@^3.0.4: version "3.0.4" resolved "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.0.4.tgz#7bef7020207e684a7638ef5f2f698e24d9eb283c" integrity sha512-MSHgpjQqgbT/94D4CyADeNoYh52zMkCX4pcJvPP5WqPsLFMKjr2TCMg381ox5qI0ii2dPwaLx/00477knXqXVw== @@ -7327,7 +7216,7 @@ deep-object-diff@^1.1.0: resolved "https://registry.npmjs.org/deep-object-diff/-/deep-object-diff-1.1.0.tgz#d6fabf476c2ed1751fc94d5ca693d2ed8c18bc5a" integrity sha512-b+QLs5vHgS+IoSNcUE4n9HP2NwcHj7aqnJWsjPtuG75Rh5TOaGt0OjAYInh77d5T16V5cRDC+Pw/6ZZZiETBGw== -deepmerge@4.2.2, deepmerge@^4.2.2: +deepmerge@^4.2.2: version "4.2.2" resolved "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== @@ -7433,11 +7322,6 @@ depd@~1.1.2: resolved "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= -deprecated-decorator@^0.1.6: - version "0.1.6" - resolved "https://registry.npmjs.org/deprecated-decorator/-/deprecated-decorator-0.1.6.tgz#00966317b7a12fe92f3cc831f7583af329b86c37" - integrity sha1-AJZjF7ehL+kvPMgx91g68ym4bDc= - deprecation@^2.0.0, deprecation@^2.3.1: version "2.3.1" resolved "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" @@ -8581,11 +8465,6 @@ extglob@^2.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" -extract-files@^8.0.0: - version "8.1.0" - resolved "https://registry.npmjs.org/extract-files/-/extract-files-8.1.0.tgz#46a0690d0fe77411a2e3804852adeaa65cd59288" - integrity sha512-PTGtfthZK79WUMk+avLmwx3NGdU8+iVFXC2NMGxKsn0MnihOG2lvumj+AZo8CTwTrwjXDgZ5tztbRlEdRjBonQ== - extract-zip@1.7.0: version "1.7.0" resolved "https://registry.npmjs.org/extract-zip/-/extract-zip-1.7.0.tgz#556cc3ae9df7f452c493a0cfb51cc30277940927" @@ -9501,18 +9380,6 @@ globalthis@^1.0.0: dependencies: define-properties "^1.1.3" -globby@11.0.0: - version "11.0.0" - resolved "https://registry.npmjs.org/globby/-/globby-11.0.0.tgz#56fd0e9f0d4f8fb0c456f1ab0dee96e1380bc154" - integrity sha512-iuehFnR3xu5wBBtm4xi0dMe92Ob87ufyu/dHwpDYfbcpYpIbrO5OnS8M1vWvrBhSGEJ3/Ecj7gnX76P8YxpPEg== - dependencies: - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.1.1" - ignore "^5.1.4" - merge2 "^1.3.0" - slash "^3.0.0" - globby@8.0.2: version "8.0.2" resolved "https://registry.npmjs.org/globby/-/globby-8.0.2.tgz#5697619ccd95c5275dbb2d6faa42087c1a941d8d" @@ -9624,86 +9491,55 @@ graceful-fs@^4.2.4: integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== graphiql@^1.0.0-alpha.10: - version "1.0.0-alpha.10" - resolved "https://registry.npmjs.org/graphiql/-/graphiql-1.0.0-alpha.10.tgz#9b6b5e554c6586e9bc09ebc863df8bcfd844110d" - integrity sha512-fKyYXQQRjsxOQw0rZMvICA2+P7ieUjj8AyfMaYlQeXGsGkZo0FUvBXVsN6LTraAPRBvVFo2jH9MSH68ujDXoeQ== + version "1.0.3" + resolved "https://registry.npmjs.org/graphiql/-/graphiql-1.0.3.tgz#f6b5d5c417d8f1a28786d3228a69883426ba74ad" + integrity sha512-6YW76m2exdpGiVS75I0QsbM4NanvenKFR9FtW/IFbui0mWv89iVa1FbdjhUt+kxa+LX/WlqTshiqiZRz7E5Bgg== dependencies: "@emotion/core" "^10.0.28" "@mdx-js/react" "^1.5.2" codemirror "^5.52.2" - codemirror-graphql "^0.12.0-alpha.8" + codemirror-graphql "^0.12.0" copy-to-clipboard "^3.2.0" entities "^2.0.0" markdown-it "^10.0.0" - monaco-graphql "^0.1.1" + monaco-graphql "^0.2.0" regenerator-runtime "^0.13.5" theme-ui "^0.3.1" -graphql-config@3.0.0-rc.2: - version "3.0.0-rc.2" - resolved "https://registry.npmjs.org/graphql-config/-/graphql-config-3.0.0-rc.2.tgz#760a1d7bcf8b114b7c1675c5a6ac624976d62e09" - integrity sha512-fb14mSDRatKsz2XXWgQjupbRsur/5vfQqHFFKo+N7hZNzRdT4hm+52HG8gn57mHQNZsN18q4aROwRQQRICMqZA== +graphql-language-service-interface@^2.4.0: + version "2.4.0" + resolved "https://registry.npmjs.org/graphql-language-service-interface/-/graphql-language-service-interface-2.4.0.tgz#4e2e63242c76197c4f56c61122db68187ea566b3" + integrity sha512-r7DQPyhCFY5TlpEukdh9tekJ9hAc7MD9TdOsb5CfAPlsIb1/faVVo2Ty19PxGSYDxygXjwpKLOQD0LqqFuw63A== dependencies: - "@graphql-toolkit/common" "~0.10.2" - "@graphql-toolkit/core" "~0.10.2" - "@graphql-toolkit/graphql-file-loader" "~0.10.2" - "@graphql-toolkit/json-file-loader" "~0.10.2" - "@graphql-toolkit/schema-merging" "~0.10.2" - "@graphql-toolkit/url-loader" "~0.10.2" - cosmiconfig "6.0.0" - globby "11.0.0" - minimatch "3.0.4" - tslib "^1.11.1" - -graphql-language-service-interface@^2.4.0-alpha.8: - version "2.4.0-alpha.8" - resolved "https://registry.npmjs.org/graphql-language-service-interface/-/graphql-language-service-interface-2.4.0-alpha.8.tgz#2f50b107c72be01796417bcfec2669d42f3b57c7" - integrity sha512-HT77H0GQk2jtpE9NAE+f8aNKvCkv5e7cZ32RZd+lCL23qNmuLJYpQcy+pbuRxxFKOWpiZLa5lc17T010gd64rQ== - dependencies: - graphql-language-service-parser "^1.6.0-alpha.4" - graphql-language-service-types "^1.6.0-alpha.6" - graphql-language-service-utils "^2.4.0-alpha.7" + graphql-language-service-parser "^1.6.0" + graphql-language-service-types "^1.6.0" + graphql-language-service-utils "^2.4.0" vscode-languageserver-types "^3.15.1" -graphql-language-service-parser@^1.6.0-alpha.4: - version "1.6.0-alpha.4" - resolved "https://registry.npmjs.org/graphql-language-service-parser/-/graphql-language-service-parser-1.6.0-alpha.4.tgz#5d80046b1a3848a655d8f514ef65f40261b74897" - integrity sha512-l76uie88SNsa37Noc0/Bpw3HT1UxLdIrrs5A3NDj6Fm4FHmri+0Mvgjygpa3y4Y0W3AGje2MILtuJUmUSjiriA== +graphql-language-service-parser@^1.6.0: + version "1.6.0" + resolved "https://registry.npmjs.org/graphql-language-service-parser/-/graphql-language-service-parser-1.6.0.tgz#53a97619461ed41ae237b9070e7e20cfaca56118" + integrity sha512-tkfYXl6WBECWNcsyw7O09c0oCMrxqr3JGyDNvdISDSDhvk8EwEk+AOweBEJkycJwoiv1lVlM+EdLfj7dzw4/6w== -graphql-language-service-types@^1.6.0-alpha.6: - version "1.6.0-alpha.6" - resolved "https://registry.npmjs.org/graphql-language-service-types/-/graphql-language-service-types-1.6.0-alpha.6.tgz#a7a50abbdfaf41074019d107754fc9c00ed824e2" - integrity sha512-cQfLC4CYDBVKcr3C53apqqd9imT+el3oEvIPz5/MocClWAZa4EsoEr2Z4WP9X5L4QrLk3hhFOJHor1aPzQRsLw== +graphql-language-service-types@^1.6.0: + version "1.6.0" + resolved "https://registry.npmjs.org/graphql-language-service-types/-/graphql-language-service-types-1.6.0.tgz#32529bb9d2e3b8ae9dd6d9646e15481ac5dfe9ad" + integrity sha512-7y4pkhTL+MtarC8CeHpvRYVc6pkT6ITdQXs+Gr7OClnk4Lz5nQEK0eO29kUdd0jEnYfHyh5iqhnL5Owfy+wT0A== -graphql-language-service-utils@^2.4.0-alpha.7: - version "2.4.0-alpha.7" - resolved "https://registry.npmjs.org/graphql-language-service-utils/-/graphql-language-service-utils-2.4.0-alpha.7.tgz#a78150eb57a079af52eaffadf9f21a9b3c82cea9" - integrity sha512-iPw9aFUWAJJx+aWY9DUf4rvIKnJVB1Qoaf7NzHegEC7LMIg7052i8ealMFKiSqk0q/zP6PCmiQblCMnGCjnEwg== +graphql-language-service-utils@^2.4.0: + version "2.4.0" + resolved "https://registry.npmjs.org/graphql-language-service-utils/-/graphql-language-service-utils-2.4.0.tgz#d4992a1968860abc43a118de498fec84361a4b87" + integrity sha512-aLa+8iqb7AJYgdcawsKH8/KLc14DHcRsnveshOm8hN6bBVT0YiQP6mEfJoci741O74uaDF2zj1J3c02vorichw== dependencies: - graphql-language-service-types "^1.6.0-alpha.6" + graphql-language-service-types "^1.6.0" -graphql-language-service@^3.0.0-alpha.1: - version "3.0.0-alpha.1" - resolved "https://registry.npmjs.org/graphql-language-service/-/graphql-language-service-3.0.0-alpha.1.tgz#dc04c0ca3f35ce322dc38548aaa023cde867ca1b" - integrity sha512-JkkONXR7+yYcm8Q4bohBJtRl6hLodgogt01lS0ROX8lcwkaihKaU+dyoSVgrRaNAibahjFrDLo0j7iAOarJ5ow== +graphql-language-service@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/graphql-language-service/-/graphql-language-service-3.0.0.tgz#953c3bbf4cc35ff9a7bd54e428bca17832367490" + integrity sha512-ySPrbecxtjQtzIFdCIOoSJzaco9dQvZK+wZN/tTjcSEEWh3fgMYXmctAG+WddJiZg3AB7I4Xsb2AsO5yFBbLHg== dependencies: - graphql-config "3.0.0-rc.2" - graphql-language-service-interface "^2.4.0-alpha.8" - graphql-language-service-types "^1.6.0-alpha.6" - -graphql-tools@5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/graphql-tools/-/graphql-tools-5.0.0.tgz#67281c834a0e29f458adba8018f424816fa627e9" - integrity sha512-5zn3vtn//382b7G3Wzz3d5q/sh+f7tVrnxeuhTMTJ7pWJijNqLxH7VEzv8VwXCq19zAzHYEosFHfXiK7qzvk7w== - dependencies: - apollo-link "^1.2.14" - apollo-upload-client "^13.0.0" - deprecated-decorator "^0.1.6" - form-data "^3.0.0" - iterall "^1.3.0" - node-fetch "^2.6.0" - tslib "^1.11.1" - uuid "^7.0.3" + graphql-language-service-interface "^2.4.0" + graphql-language-service-types "^1.6.0" graphql@15.1.0, graphql@^15.0.0: version "15.1.0" @@ -10802,13 +10638,6 @@ is-generator-fn@^2.0.0: resolved "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== -is-glob@4.0.1, is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: - version "4.0.1" - resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" - integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== - dependencies: - is-extglob "^2.1.1" - is-glob@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" @@ -10823,6 +10652,13 @@ is-glob@^3.1.0: dependencies: is-extglob "^2.1.0" +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" + integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== + dependencies: + is-extglob "^2.1.1" + is-hexadecimal@^1.0.0: version "1.0.4" resolved "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7" @@ -11170,11 +11006,6 @@ istanbul-reports@^3.0.2: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" -iterall@^1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/iterall/-/iterall-1.3.0.tgz#afcb08492e2915cbd8a0884eb93a8c94d0d72fea" - integrity sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg== - iterate-iterator@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/iterate-iterator/-/iterate-iterator-1.0.1.tgz#1693a768c1ddd79c969051459453f082fe82e9f6" @@ -13042,13 +12873,13 @@ monaco-editor@^0.20.0: resolved "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.20.0.tgz#5d5009343a550124426cb4d965a4d27a348b4dea" integrity sha512-hkvf4EtPJRMQlPC3UbMoRs0vTAFAYdzFQ+gpMb8A+9znae1c43q8Mab9iVsgTcg/4PNiLGGn3SlDIa8uvK1FIQ== -monaco-graphql@^0.1.1: - version "0.1.1" - resolved "https://registry.npmjs.org/monaco-graphql/-/monaco-graphql-0.1.1.tgz#d74b03a14d60805841157efe99c3ddec6e8c1407" - integrity sha512-P6K03iP2hme9geA9TR2zYkSrdhVR0/YcMBQjAaTALGvI4dIILTieGxuBeElZAZFEhsj38CNZZKUF8pKXapA86Q== +monaco-graphql@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/monaco-graphql/-/monaco-graphql-0.2.0.tgz#be6bd165b6cbdc624fde6c108fe9ee32f50f2e80" + integrity sha512-IwpbJvrNlFxq6xjnQQ8eC72ep+q2vfiUaHBNkfqe314CXYnUCcXYfoMBfR5EuLAXRBOTf4CKl6BCN1/9eHrq7A== dependencies: - graphql-language-service "^3.0.0-alpha.1" - graphql-language-service-utils "^2.4.0-alpha.7" + graphql-language-service "^3.0.0" + graphql-language-service-utils "^2.4.0" monaco-editor "^0.20.0" morgan@^1.10.0: @@ -13906,13 +13737,6 @@ p-finally@^2.0.0: resolved "https://registry.npmjs.org/p-finally/-/p-finally-2.0.1.tgz#bd6fcaa9c559a096b680806f4d657b3f0f240561" integrity sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw== -p-limit@2.3.0: - version "2.3.0" - resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" - integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== - dependencies: - p-try "^2.0.0" - p-limit@^1.1.0: version "1.3.0" resolved "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" @@ -16269,11 +16093,6 @@ resolve-dir@^1.0.0, resolve-dir@^1.0.1: expand-tilde "^2.0.0" global-modules "^1.0.0" -resolve-from@5.0.0, resolve-from@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" - integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== - resolve-from@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" @@ -16284,6 +16103,11 @@ resolve-from@^4.0.0: resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + resolve-pathname@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd" @@ -18282,13 +18106,6 @@ ts-interface-checker@^0.1.9: resolved "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.10.tgz#b68a49e37e90a05797e590f08494dd528bf383cf" integrity sha512-UJYuKET7ez7ry0CnvfY6fPIUIZDw+UI3qvTUQeS2MyI4TgEeWAUBqy185LeaHcdJ9zG2dgFpPJU/AecXU0Afug== -ts-invariant@^0.4.0: - version "0.4.4" - resolved "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.4.4.tgz#97a523518688f93aafad01b0e80eb803eb2abd86" - integrity sha512-uEtWkFM/sdZvRNNDL3Ehu4WVpwaulhwQszV8mrtcdeE8nN00BV9mAmQ88RkrBhFgl9gMgvjJLAQcZbnPXI9mlA== - dependencies: - tslib "^1.9.3" - ts-jest@^26.0.0: version "26.1.0" resolved "https://registry.npmjs.org/ts-jest/-/ts-jest-26.1.0.tgz#e9070fc97b3ea5557a48b67c631c74eb35e15417" @@ -18347,21 +18164,11 @@ tslib@1.10.0: resolved "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== -tslib@1.11.2: - version "1.11.2" - resolved "https://registry.npmjs.org/tslib/-/tslib-1.11.2.tgz#9c79d83272c9a7aaf166f73915c9667ecdde3cc9" - integrity sha512-tTSkux6IGPnUGUd1XAZHcpu85MOkIl5zX49pO+jfsie3eP0B6pyhOlLXm3cAC6T7s+euSDDUUV+Acop5WmtkVg== - tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: version "1.11.1" resolved "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz#eb15d128827fbee2841549e171f45ed338ac7e35" integrity sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA== -tslib@^1.11.1: - version "1.13.0" - resolved "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043" - integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q== - tsutils@^3.17.1: version "3.17.1" resolved "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759" @@ -18644,13 +18451,6 @@ universalify@^1.0.0: resolved "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz#b61a1da173e8435b2fe3c67d29b9adf8594bd16d" integrity sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug== -unixify@1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/unixify/-/unixify-1.0.0.tgz#3a641c8c2ffbce4da683a5c70f03a462940c2090" - integrity sha1-OmQcjC/7zk2mg6XHDwOkYpQMIJA= - dependencies: - normalize-path "^2.1.1" - unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" @@ -18864,11 +18664,6 @@ v8flags@^3.1.3: dependencies: homedir-polyfill "^1.0.1" -valid-url@1.0.9: - version "1.0.9" - resolved "https://registry.npmjs.org/valid-url/-/valid-url-1.0.9.tgz#1c14479b40f1397a75782f115e4086447433a200" - integrity sha1-HBRHm0DxOXp1eC8RXkCGRHQzogA= - validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.3: version "3.0.4" resolved "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" @@ -19642,15 +19437,7 @@ yup@^0.29.1: synchronous-promise "^2.0.10" toposort "^2.0.2" -zen-observable-ts@^0.8.21: - version "0.8.21" - resolved "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-0.8.21.tgz#85d0031fbbde1eba3cd07d3ba90da241215f421d" - integrity sha512-Yj3yXweRc8LdRMrCC8nIc4kkjWecPAUVh0TI0OUrWXx6aX790vLcDlWca6I4vsyCGH3LpWxq0dJRcMOFoVqmeg== - dependencies: - tslib "^1.9.3" - zen-observable "^0.8.0" - -zen-observable@^0.8.0, zen-observable@^0.8.15: +zen-observable@^0.8.15: version "0.8.15" resolved "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.15.tgz#96415c512d8e3ffd920afd3889604e30b9eaac15" integrity sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ== From d65c67ea93da82c95737e92caf7fb72e778a634c Mon Sep 17 00:00:00 2001 From: Ivan Shmidt Date: Fri, 26 Jun 2020 09:27:24 +0200 Subject: [PATCH 25/25] fix(scaffolder): show progressbar if no data --- plugins/scaffolder/src/components/ScaffolderPage/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/scaffolder/src/components/ScaffolderPage/index.tsx b/plugins/scaffolder/src/components/ScaffolderPage/index.tsx index aa2a8b639a..2f9774757b 100644 --- a/plugins/scaffolder/src/components/ScaffolderPage/index.tsx +++ b/plugins/scaffolder/src/components/ScaffolderPage/index.tsx @@ -90,7 +90,7 @@ const ScaffolderPage: React.FC<{}> = () => { . - {isValidating && } + {!templates && isValidating && } {templates && templates.map(template => { @@ -103,7 +103,7 @@ const ScaffolderPage: React.FC<{}> = () => { }`} type={template.spec.type ?? ''} description={template.metadata.description ?? '-'} - tags={template.metadata?.tags ?? []} + tags={(template.metadata?.tags as string[]) ?? []} /> );