diff --git a/.changeset/eleven-pens-collect.md b/.changeset/eleven-pens-collect.md
new file mode 100644
index 0000000000..0df1bb0400
--- /dev/null
+++ b/.changeset/eleven-pens-collect.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-catalog': patch
+---
+
+Corrected replacements for depreciated FilteredEntityLayout items
diff --git a/.changeset/empty-pens-invent.md b/.changeset/empty-pens-invent.md
new file mode 100644
index 0000000000..d6937afc84
--- /dev/null
+++ b/.changeset/empty-pens-invent.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-search-backend': minor
+---
+
+**BREAKING**: The `authorization` property is no longer returned on search results when queried. Note: this will only result in a breaking change if you have custom code in your frontend that relies on the `authorization.resourceRef` property on documents.
diff --git a/.changeset/fair-lamps-leave.md b/.changeset/fair-lamps-leave.md
new file mode 100644
index 0000000000..9e902b51f2
--- /dev/null
+++ b/.changeset/fair-lamps-leave.md
@@ -0,0 +1,7 @@
+---
+'@backstage/plugin-user-settings': patch
+---
+
+Wired up the OneLogin provider to be visible in the Settings UI when configured correctly.
+
+Previously it wasn't visible at all.
diff --git a/.changeset/fast-cheetahs-grow.md b/.changeset/fast-cheetahs-grow.md
new file mode 100644
index 0000000000..5567436b5e
--- /dev/null
+++ b/.changeset/fast-cheetahs-grow.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-auth-node': minor
+---
+
+**BREAKING**: Removed the deprecated `id` and `entity` fields from `BackstageSignInResult`.
diff --git a/.changeset/happy-mugs-camp.md b/.changeset/happy-mugs-camp.md
new file mode 100644
index 0000000000..22d13d80d1
--- /dev/null
+++ b/.changeset/happy-mugs-camp.md
@@ -0,0 +1,7 @@
+---
+'@backstage/plugin-search-common': patch
+---
+
+- Introduce `SearchDocument` type. This type contains the subset of `IndexableDocument` properties relevant to the frontend, and is intended to be used for documents returned to the frontend from the search API.
+- `SearchResultSet` is now a wrapper for documents of type `SearchDocument`, and is intended to be used in the frontend. This isn't a breaking change, since `IndexableDocument`s are valid `SearchDocument`s, so the old and new types are compatible.
+- Introduce `IndexableResultSet` type, which wraps `IndexableDocument` instances in the same way as `SearchResultSet`.
diff --git a/.changeset/khaki-pears-march.md b/.changeset/khaki-pears-march.md
new file mode 100644
index 0000000000..5626bf3ea5
--- /dev/null
+++ b/.changeset/khaki-pears-march.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-auth-backend': minor
+---
+
+**BREAKING**: All sign-in resolvers must now return a `token` in their sign-in result. Returning an `id` is no longer supported.
diff --git a/.changeset/light-drinks-rule.md b/.changeset/light-drinks-rule.md
new file mode 100644
index 0000000000..2b99f5988c
--- /dev/null
+++ b/.changeset/light-drinks-rule.md
@@ -0,0 +1,8 @@
+---
+'@backstage/plugin-search-backend': patch
+'@backstage/plugin-search-backend-node': patch
+'@backstage/plugin-search-backend-module-elasticsearch': patch
+'@backstage/plugin-search-backend-module-pg': patch
+---
+
+Use new `IndexableResultSet` type as return type of query method in `SearchEngine` implementation.
diff --git a/.changeset/ninety-fishes-vanish.md b/.changeset/ninety-fishes-vanish.md
new file mode 100644
index 0000000000..b0d3ac370f
--- /dev/null
+++ b/.changeset/ninety-fishes-vanish.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-search': patch
+---
+
+Switch to `SearchDocument` type in `DefaultResultListItem` props
diff --git a/.changeset/purple-boats-punch.md b/.changeset/purple-boats-punch.md
new file mode 100644
index 0000000000..817f0a79bc
--- /dev/null
+++ b/.changeset/purple-boats-punch.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-auth-backend': patch
+---
+
+**DEPRECATION**: The `tokenIssuer` option for `OAuthAdapter` is no longer needed and has been deprecated.
diff --git a/.changeset/red-snakes-float.md b/.changeset/red-snakes-float.md
new file mode 100644
index 0000000000..f1bd16d84c
--- /dev/null
+++ b/.changeset/red-snakes-float.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-catalog-react': patch
+---
+
+Add support for string refs to the `EntityRefLinks` component
diff --git a/.changeset/silver-pots-call.md b/.changeset/silver-pots-call.md
new file mode 100644
index 0000000000..42b3016545
--- /dev/null
+++ b/.changeset/silver-pots-call.md
@@ -0,0 +1,5 @@
+---
+'@backstage/core-components': patch
+---
+
+fix support config ref to use backstage/backstage
diff --git a/.changeset/wicked-beds-return.md b/.changeset/wicked-beds-return.md
new file mode 100644
index 0000000000..add952ba0a
--- /dev/null
+++ b/.changeset/wicked-beds-return.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-kubernetes': patch
+---
+
+Fix division by zero in currentToDeclaredResourceToPerc when pod resources weren't set
diff --git a/.changeset/wicked-feet-clap.md b/.changeset/wicked-feet-clap.md
new file mode 100644
index 0000000000..e27f641820
--- /dev/null
+++ b/.changeset/wicked-feet-clap.md
@@ -0,0 +1,5 @@
+---
+'@backstage/backend-common': patch
+---
+
+Updated the visibility of database connection fields in config to be secret
diff --git a/ADOPTERS.md b/ADOPTERS.md
index e00031589d..10661f9792 100644
--- a/ADOPTERS.md
+++ b/ADOPTERS.md
@@ -106,3 +106,4 @@ _If you're using Backstage in your organization, please try to add your company
| [Alliander](https://www.alliander.com/) | [@leon-vg](https://github.com/leon-vg), [@gieljl](https://github.com/gieljl), [@niekteg](https://github.com/niekteg) | Developer portal - software catalog, technical documentation, software templates, tech radar and exploration of used tools/services |
| [VIA](https://www.via.com.br) | [@vagnerguedes](https://github.com/vagnerguedes) | Centralized Developer Experience portal - Software catalog and documentation platform, software templates, techdocs, scaffolding, self-service infrastructure |
| [Surevine](https://www.surevine.com/) | [@DJDANNY123](https://github.com/djdanny123) | Developer portal for software catalog, discovery and a view of the technologies we are using across the organisation, we are looking to explore how we can enrich our entities in Backstage by integrating a software bill of materials. |
+| [Bonial International GmbH](https://www.bonial.com/) | [@pjungermann](https://github.com/pjungermann) | Centralized developer portal with software catalog, tech docs, templates, and more. |
diff --git a/contrib/chart/backstage/templates/ingress.yaml b/contrib/chart/backstage/templates/ingress.yaml
index cac9b61553..7e008c5d9d 100644
--- a/contrib/chart/backstage/templates/ingress.yaml
+++ b/contrib/chart/backstage/templates/ingress.yaml
@@ -74,7 +74,7 @@ spec:
backend:
{{- if .Capabilities.APIVersions.Has "networking.k8s.io/v1" }}
service:
- name: {{ include "frontend.serviceName" . }}
+ name: {{ include "backend.serviceName" . }}
port:
number: 80
{{- else -}}
diff --git a/docs/features/software-templates/writing-templates.md b/docs/features/software-templates/writing-templates.md
index 9a1cfdf736..0163877a8b 100644
--- a/docs/features/software-templates/writing-templates.md
+++ b/docs/features/software-templates/writing-templates.md
@@ -364,7 +364,7 @@ spec:
secretsKey: USER_OAUTH_TOKEN
additionalScopes:
github:
- - workflow:write
+ - workflow
allowedHosts:
- github.com
...
diff --git a/microsite/blog/2022-03-17-backstage-1.0.md b/microsite/blog/2022-03-17-backstage-1.0.md
index 43034664a3..02ead0390c 100644
--- a/microsite/blog/2022-03-17-backstage-1.0.md
+++ b/microsite/blog/2022-03-17-backstage-1.0.md
@@ -45,7 +45,7 @@ In terms of maturity and stability, the road ahead for Backstage is bright and b
You can read more about Backstage’s roadmap [here](https://backstage.io/docs/overview/roadmap), but in terms of maturity and stability we would like to highlight the following:
- CNCF incubation: The Backstage project [recently moved from Sandbox to Incubation](https://www.cncf.io/blog/2022/03/15/backstage-project-joins-the-cncf-incubator/) phase within the [CNCF maturity levels](https://www.cncf.io/projects/#:~:text=Maturity%20levels,should%20be%20adopting%20different%20projects.).
-- Security auditing and strategy: With the CNCF’s support,, the project maintainers are working on a security audit initiative to make the platform more secure and will share more details soon. The audit is part of an overall security strategy being developed this quarter.
+- Security auditing and strategy: With the CNCF’s support, the project maintainers are working on a security audit initiative to make the platform more secure and will share more details soon. The audit is part of an overall security strategy being developed this quarter.
- Paid plugins for advanced and enterprise use cases: Last year, [Spotify announced its work on paid plugins](https://backstage.spotify.com/blog/paid-plugins-announcement/) built on top of the Backstage open source platform. This is another example of the platform’s maturity and Spotify’s continued commitment to the project, with a focus on customers and use cases requiring enterprise-focused support and plugins developed and proven by Spotify.
# Some links to peruse
diff --git a/packages/app/package.json b/packages/app/package.json
index f152df41f9..29e6541df7 100644
--- a/packages/app/package.json
+++ b/packages/app/package.json
@@ -60,10 +60,10 @@
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "4.0.0-alpha.57",
"@octokit/rest": "^18.5.3",
- "@roadiehq/backstage-plugin-buildkite": "^1.4.0",
- "@roadiehq/backstage-plugin-github-insights": "^1.6.0",
- "@roadiehq/backstage-plugin-github-pull-requests": "^1.5.0",
- "@roadiehq/backstage-plugin-travis-ci": "^1.4.0",
+ "@roadiehq/backstage-plugin-buildkite": "^2.0.0",
+ "@roadiehq/backstage-plugin-github-insights": "^2.0.0",
+ "@roadiehq/backstage-plugin-github-pull-requests": "^2.0.0",
+ "@roadiehq/backstage-plugin-travis-ci": "^2.0.0",
"history": "^5.0.0",
"prop-types": "^15.7.2",
"react": "^17.0.2",
diff --git a/packages/app/src/components/catalog/EntityPage.tsx b/packages/app/src/components/catalog/EntityPage.tsx
index 0a06c4fd5d..26068c6c8f 100644
--- a/packages/app/src/components/catalog/EntityPage.tsx
+++ b/packages/app/src/components/catalog/EntityPage.tsx
@@ -180,7 +180,7 @@ export const cicdContent = (
- boolean}>
+
@@ -192,7 +192,7 @@ export const cicdContent = (
- boolean}>
+
@@ -327,9 +327,7 @@ const overviewContent = (
{cicdCard}
- boolean}
- >
+
@@ -349,9 +347,7 @@ const overviewContent = (
- boolean}
- >
+
diff --git a/packages/backend-common/config.d.ts b/packages/backend-common/config.d.ts
index 058805aa62..6c473af3c0 100644
--- a/packages/backend-common/config.d.ts
+++ b/packages/backend-common/config.d.ts
@@ -73,7 +73,7 @@ export interface Config {
client: 'better-sqlite3' | 'sqlite3' | 'pg';
/**
* Base database connection string or Knex object
- * @secret
+ * @visibility secret
*/
connection: string | object;
/** Database name prefix override */
@@ -109,7 +109,7 @@ export interface Config {
client?: 'better-sqlite3' | 'sqlite3' | 'pg';
/**
* Database connection string or Knex object override
- * @secret
+ * @visibility secret
*/
connection?: string | object;
/**
@@ -138,7 +138,7 @@ export interface Config {
store: 'redis';
/**
* A redis connection string in the form `redis://user:pass@host:port`.
- * @secret
+ * @visibility secret
*/
connection: string;
}
@@ -146,7 +146,7 @@ export interface Config {
store: 'memcache';
/**
* A memcache connection string in the form `user:pass@host:port`.
- * @secret
+ * @visibility secret
*/
connection: string;
};
diff --git a/packages/core-components/src/hooks/useSupportConfig.ts b/packages/core-components/src/hooks/useSupportConfig.ts
index 546d779e01..e80eb457a1 100644
--- a/packages/core-components/src/hooks/useSupportConfig.ts
+++ b/packages/core-components/src/hooks/useSupportConfig.ts
@@ -42,7 +42,7 @@ const DEFAULT_SUPPORT_CONFIG: SupportConfig = {
{
// TODO: Update to dedicated support page on backstage.io/docs
title: 'Add `app.support` config key',
- url: 'https://github.com/andrewthauer/backstage/blob/master/app-config.yaml',
+ url: 'https://github.com/backstage/backstage/blob/master/app-config.yaml',
},
],
},
diff --git a/packages/integration-react/src/api/ScmAuth.test.ts b/packages/integration-react/src/api/ScmAuth.test.ts
index 1ad391d8d2..7e174c4cbf 100644
--- a/packages/integration-react/src/api/ScmAuth.test.ts
+++ b/packages/integration-react/src/api/ScmAuth.test.ts
@@ -153,11 +153,11 @@ describe('ScmAuth', () => {
githubAuth.getCredentials({
url: 'http://example.com',
additionalScope: {
- customScopes: { github: ['org:read', 'workflow:write'] },
+ customScopes: { github: ['org:read', 'workflow'] },
},
}),
).resolves.toMatchObject({
- token: 'repo read:org read:user org:read workflow:write',
+ token: 'repo read:org read:user org:read workflow',
});
const gitlabAuth = ScmAuth.forGitlab(mockAuthApi);
diff --git a/plugins/auth-backend/src/lib/flow/authFlowHelpers.test.ts b/plugins/auth-backend/src/lib/flow/authFlowHelpers.test.ts
index 07c8196dd2..87e6b96745 100644
--- a/plugins/auth-backend/src/lib/flow/authFlowHelpers.test.ts
+++ b/plugins/auth-backend/src/lib/flow/authFlowHelpers.test.ts
@@ -50,7 +50,6 @@ describe('oauth helpers', () => {
email: 'foo@bar.com',
},
backstageIdentity: {
- id: 'a',
token: 'a.b.c',
identity: {
type: 'user',
@@ -110,7 +109,6 @@ describe('oauth helpers', () => {
email: 'foo@bar.com',
},
backstageIdentity: {
- id: 'a',
token: 'a.b.c',
identity: {
type: 'user',
@@ -157,7 +155,6 @@ describe('oauth helpers', () => {
displayName: "Adam l'Hôpital",
},
backstageIdentity: {
- id: 'a',
token: 'a.b.c',
identity: {
type: 'user',
diff --git a/plugins/auth-backend/src/lib/oauth/OAuthAdapter.test.ts b/plugins/auth-backend/src/lib/oauth/OAuthAdapter.test.ts
index c1130b4270..0ce9dff66c 100644
--- a/plugins/auth-backend/src/lib/oauth/OAuthAdapter.test.ts
+++ b/plugins/auth-backend/src/lib/oauth/OAuthAdapter.test.ts
@@ -17,7 +17,7 @@
import express from 'express';
import { THOUSAND_DAYS_MS, TEN_MINUTES_MS, OAuthAdapter } from './OAuthAdapter';
import { encodeState } from './helpers';
-import { OAuthHandlers, OAuthResponse, OAuthState } from './types';
+import { OAuthHandlers, OAuthState } from './types';
const mockResponseData = {
providerInfo: {
@@ -30,18 +30,11 @@ const mockResponseData = {
email: 'foo@bar.com',
},
backstageIdentity: {
- id: 'foo',
token:
- 'eyblob.eyJzdWIiOiJqaW1teW1hcmt1bSIsImVudCI6WyJ1c2VyOmRlZmF1bHQvamltbXltYXJrdW0iXX0=.eyblob',
+ 'eyblob.eyJzdWIiOiJ1c2VyOmRlZmF1bHQvamltbXltYXJrdW0iLCJlbnQiOlsidXNlcjpkZWZhdWx0L2ppbW15bWFya3VtIl19.eyblob',
},
};
-function mkTokenBody(payload: unknown): string {
- return Buffer.from(JSON.stringify(payload), 'utf8')
- .toString('base64')
- .replace(/=/g, '');
-}
-
describe('OAuthAdapter', () => {
class MyAuthProvider implements OAuthHandlers {
async start() {
@@ -324,13 +317,11 @@ describe('OAuthAdapter', () => {
expect(mockResponse.json).toHaveBeenCalledWith({
...mockResponseData,
backstageIdentity: {
- id: mockResponseData.backstageIdentity.id,
token: mockResponseData.backstageIdentity.token,
- idToken: mockResponseData.backstageIdentity.token,
identity: {
- ownershipEntityRefs: ['user:default/jimmymarkum'],
type: 'user',
userEntityRef: 'user:default/jimmymarkum',
+ ownershipEntityRefs: ['user:default/jimmymarkum'],
},
},
});
@@ -356,95 +347,6 @@ describe('OAuthAdapter', () => {
);
});
- it('correctly populates incomplete identities', async () => {
- const mockRefresh = jest.fn<
- Promise<{ response: OAuthResponse }>,
- [express.Request]
- >();
-
- const oauthProvider = new OAuthAdapter(
- {
- refresh: mockRefresh,
- start: jest.fn(),
- handler: jest.fn(),
- } as OAuthHandlers,
- {
- ...oAuthProviderOptions,
- tokenIssuer: {
- issueToken: async ({ claims }) => `a.${mkTokenBody(claims)}.a`,
- listPublicKeys: async () => ({ keys: [] }),
- },
- disableRefresh: false,
- isOriginAllowed: () => false,
- },
- );
-
- const mockRequest = {
- header: () => 'XMLHttpRequest',
- cookies: {
- 'test-provider-refresh-token': 'token',
- },
- query: {},
- } as unknown as express.Request;
-
- const mockResponse = {
- json: jest.fn().mockReturnThis(),
- status: jest.fn().mockReturnThis(),
- } as unknown as express.Response;
-
- // Without a token
- mockRefresh.mockResolvedValueOnce({
- response: {
- ...mockResponseData,
- backstageIdentity: {
- id: 'foo',
- token: '',
- },
- },
- });
- await oauthProvider.refresh(mockRequest, mockResponse);
- expect(mockResponse.json).toHaveBeenCalledTimes(1);
- expect(mockResponse.json).toHaveBeenLastCalledWith({
- ...mockResponseData,
- backstageIdentity: {
- id: 'foo',
- token: `a.${mkTokenBody({ sub: 'user:default/foo' })}.a`,
- idToken: `a.${mkTokenBody({ sub: 'user:default/foo' })}.a`,
- identity: {
- type: 'user',
- userEntityRef: 'user:default/foo',
- ownershipEntityRefs: [],
- },
- },
- });
-
- // With a token
- mockRefresh.mockResolvedValueOnce({
- response: {
- ...mockResponseData,
- backstageIdentity: {
- id: 'foo',
- token: `z.${mkTokenBody({ sub: 'user:my-ns/foo' })}.z`,
- },
- },
- });
- await oauthProvider.refresh(mockRequest, mockResponse);
- expect(mockResponse.json).toHaveBeenCalledTimes(2);
- expect(mockResponse.json).toHaveBeenLastCalledWith({
- ...mockResponseData,
- backstageIdentity: {
- id: 'foo',
- token: `z.${mkTokenBody({ sub: 'user:my-ns/foo' })}.z`,
- idToken: `z.${mkTokenBody({ sub: 'user:my-ns/foo' })}.z`,
- identity: {
- type: 'user',
- userEntityRef: 'user:my-ns/foo',
- ownershipEntityRefs: [],
- },
- },
- });
- });
-
it('sets the correct cookie configuration using a callbackUrl', async () => {
const config = {
baseUrl: 'http://domain.org/auth',
diff --git a/plugins/auth-backend/src/lib/oauth/OAuthAdapter.ts b/plugins/auth-backend/src/lib/oauth/OAuthAdapter.ts
index 07611ddb9c..637dc1cff2 100644
--- a/plugins/auth-backend/src/lib/oauth/OAuthAdapter.ts
+++ b/plugins/auth-backend/src/lib/oauth/OAuthAdapter.ts
@@ -17,11 +17,6 @@
import express, { CookieOptions } from 'express';
import crypto from 'crypto';
import { URL } from 'url';
-import {
- DEFAULT_NAMESPACE,
- parseEntityRef,
- stringifyEntityRef,
-} from '@backstage/catalog-model';
import {
BackstageIdentityResponse,
BackstageSignInResult,
@@ -58,7 +53,8 @@ export type Options = {
cookieDomain: string;
cookiePath: string;
appOrigin: string;
- tokenIssuer: TokenIssuer;
+ /** @deprecated This option is no longer needed */
+ tokenIssuer?: TokenIssuer;
isOriginAllowed: (origin: string) => boolean;
callbackUrl: string;
};
@@ -263,22 +259,11 @@ export class OAuthAdapter implements AuthProviderRouteHandlers {
if (!identity) {
return undefined;
}
-
- if (identity.token) {
- return prepareBackstageIdentityResponse(identity);
+ if (!identity.token) {
+ throw new InputError(`Identity response must return a token`);
}
- const userEntityRef = stringifyEntityRef(
- parseEntityRef(identity.id, {
- defaultKind: 'user',
- defaultNamespace: DEFAULT_NAMESPACE,
- }),
- );
- const token = await this.options.tokenIssuer.issueToken({
- claims: { sub: userEntityRef },
- });
-
- return prepareBackstageIdentityResponse({ ...identity, token });
+ return prepareBackstageIdentityResponse(identity);
}
private setNonceCookie = (res: express.Response, nonce: string) => {
diff --git a/plugins/auth-backend/src/providers/aws-alb/provider.test.ts b/plugins/auth-backend/src/providers/aws-alb/provider.test.ts
index 37b5bc1f68..eb801fdd46 100644
--- a/plugins/auth-backend/src/providers/aws-alb/provider.test.ts
+++ b/plugins/auth-backend/src/providers/aws-alb/provider.test.ts
@@ -123,9 +123,8 @@ describe('AwsAlbAuthProvider', () => {
}),
signInResolver: async () => {
return {
- id: 'user.name',
token:
- 'eyblob.eyJzdWIiOiJqaW1teW1hcmt1bSIsImVudCI6WyJ1c2VyOmRlZmF1bHQvamltbXltYXJrdW0iXX0=.eyblob',
+ 'eyblob.eyJzdWIiOiJ1c2VyOmRlZmF1bHQvamltbXltYXJrdW0iLCJlbnQiOlsidXNlcjpkZWZhdWx0L2ppbW15bWFya3VtIl19.eyblob',
};
},
});
@@ -136,11 +135,8 @@ describe('AwsAlbAuthProvider', () => {
expect(mockResponse.json).toHaveBeenCalledWith({
backstageIdentity: {
- id: 'user.name',
token:
- 'eyblob.eyJzdWIiOiJqaW1teW1hcmt1bSIsImVudCI6WyJ1c2VyOmRlZmF1bHQvamltbXltYXJrdW0iXX0=.eyblob',
- idToken:
- 'eyblob.eyJzdWIiOiJqaW1teW1hcmt1bSIsImVudCI6WyJ1c2VyOmRlZmF1bHQvamltbXltYXJrdW0iXX0=.eyblob',
+ 'eyblob.eyJzdWIiOiJ1c2VyOmRlZmF1bHQvamltbXltYXJrdW0iLCJlbnQiOlsidXNlcjpkZWZhdWx0L2ppbW15bWFya3VtIl19.eyblob',
identity: {
ownershipEntityRefs: ['user:default/jimmymarkum'],
type: 'user',
diff --git a/plugins/auth-backend/src/providers/gcp-iap/provider.test.ts b/plugins/auth-backend/src/providers/gcp-iap/provider.test.ts
index aab0103140..eb2f5c478d 100644
--- a/plugins/auth-backend/src/providers/gcp-iap/provider.test.ts
+++ b/plugins/auth-backend/src/providers/gcp-iap/provider.test.ts
@@ -45,7 +45,7 @@ describe('GcpIapProvider', () => {
const iapToken = { sub: 's', email: 'e@mail.com' };
authHandler.mockResolvedValueOnce({ email: 'e@mail.com' });
- signInResolver.mockResolvedValueOnce({ id: 'i', token: backstageToken });
+ signInResolver.mockResolvedValueOnce({ token: backstageToken });
tokenValidator.mockResolvedValueOnce(iapToken);
const app = express();
@@ -61,8 +61,6 @@ describe('GcpIapProvider', () => {
);
expect(response.body).toEqual({
backstageIdentity: {
- id: 'i',
- idToken: backstageToken,
token: backstageToken,
identity: {
type: 'user',
diff --git a/plugins/auth-backend/src/providers/oauth2-proxy/provider.test.ts b/plugins/auth-backend/src/providers/oauth2-proxy/provider.test.ts
index 048a3b9344..61f08bc535 100644
--- a/plugins/auth-backend/src/providers/oauth2-proxy/provider.test.ts
+++ b/plugins/auth-backend/src/providers/oauth2-proxy/provider.test.ts
@@ -43,7 +43,7 @@ import {
describe('Oauth2ProxyAuthProvider', () => {
const mockToken =
- 'eyblob.eyJzdWIiOiJqaW1teW1hcmt1bSIsImVudCI6WyJ1c2VyOmRlZmF1bHQvamltbXltYXJrdW0iXX0=.eyblob';
+ 'eyblob.eyJzdWIiOiJ1c2VyOmRlZmF1bHQvamltbXltYXJrdW0iLCJlbnQiOlsidXNlcjpkZWZhdWx0L2ppbW15bWFya3VtIl19.eyblob';
let provider: Oauth2ProxyAuthProvider;
let logger: jest.Mocked;
@@ -122,7 +122,6 @@ describe('Oauth2ProxyAuthProvider', () => {
profile: {},
});
signInResolver.mockResolvedValue({
- id: 'some-id',
token: mockToken,
});
@@ -142,7 +141,6 @@ describe('Oauth2ProxyAuthProvider', () => {
const profile = { displayName: 'some value' };
mockRequest.header.mockReturnValue(`Bearer token`);
signInResolver.mockResolvedValue({
- id: 'some-id',
token: mockToken,
});
authHandler.mockResolvedValue({ profile: profile });
@@ -162,12 +160,10 @@ describe('Oauth2ProxyAuthProvider', () => {
);
expect(mockResponse.json).toHaveBeenCalledWith({
backstageIdentity: {
- id: 'some-id',
- idToken: mockToken,
identity: {
- ownershipEntityRefs: ['user:default/jimmymarkum'],
type: 'user',
userEntityRef: 'user:default/jimmymarkum',
+ ownershipEntityRefs: ['user:default/jimmymarkum'],
},
token: mockToken,
},
@@ -186,7 +182,6 @@ describe('Oauth2ProxyAuthProvider', () => {
profile: {},
});
signInResolver.mockResolvedValue({
- id: 'some-id',
token: mockToken,
});
});
diff --git a/plugins/auth-backend/src/providers/prepareBackstageIdentityResponse.test.ts b/plugins/auth-backend/src/providers/prepareBackstageIdentityResponse.test.ts
index 24442379c4..dac06f964e 100644
--- a/plugins/auth-backend/src/providers/prepareBackstageIdentityResponse.test.ts
+++ b/plugins/auth-backend/src/providers/prepareBackstageIdentityResponse.test.ts
@@ -27,13 +27,10 @@ describe('prepareBackstageIdentityResponse', () => {
const token = mkToken({ sub: 'k:ns/n', ent: ['k:ns/o'] });
expect(
prepareBackstageIdentityResponse({
- id: 'x',
token,
}),
).toEqual({
- id: 'x',
token,
- idToken: token,
identity: {
type: 'user',
userEntityRef: 'k:ns/n',
@@ -41,67 +38,4 @@ describe('prepareBackstageIdentityResponse', () => {
},
});
});
-
- it('populates incomplete identities', () => {
- expect(
- prepareBackstageIdentityResponse({
- id: 'x',
- token: mkToken({ sub: 'n' }),
- }),
- ).toEqual({
- id: 'x',
- token: expect.any(String),
- idToken: expect.any(String),
- identity: {
- type: 'user',
- userEntityRef: 'user:default/n',
- ownershipEntityRefs: [],
- },
- });
- expect(
- prepareBackstageIdentityResponse({
- id: 'x',
- token: mkToken({ sub: 'k:n' }),
- }),
- ).toEqual({
- id: 'x',
- token: expect.any(String),
- idToken: expect.any(String),
- identity: {
- type: 'user',
- userEntityRef: 'k:default/n',
- ownershipEntityRefs: [],
- },
- });
- expect(
- prepareBackstageIdentityResponse({
- id: 'x',
- token: mkToken({ sub: 'ns/n' }),
- }),
- ).toEqual({
- id: 'x',
- token: expect.any(String),
- idToken: expect.any(String),
- identity: {
- type: 'user',
- userEntityRef: 'user:ns/n',
- ownershipEntityRefs: [],
- },
- });
- expect(
- prepareBackstageIdentityResponse({
- id: 'x',
- token: mkToken({ sub: 'n', ent: ['k:ns/o'] }),
- }),
- ).toEqual({
- id: 'x',
- token: expect.any(String),
- idToken: expect.any(String),
- identity: {
- type: 'user',
- userEntityRef: 'user:default/n',
- ownershipEntityRefs: ['k:ns/o'],
- },
- });
- });
});
diff --git a/plugins/auth-backend/src/providers/prepareBackstageIdentityResponse.ts b/plugins/auth-backend/src/providers/prepareBackstageIdentityResponse.ts
index 5a4e0895d9..761618c225 100644
--- a/plugins/auth-backend/src/providers/prepareBackstageIdentityResponse.ts
+++ b/plugins/auth-backend/src/providers/prepareBackstageIdentityResponse.ts
@@ -14,11 +14,6 @@
* limitations under the License.
*/
-import {
- DEFAULT_NAMESPACE,
- parseEntityRef,
- stringifyEntityRef,
-} from '@backstage/catalog-model';
import {
BackstageIdentityResponse,
BackstageSignInResult,
@@ -41,21 +36,11 @@ export function prepareBackstageIdentityResponse(
): BackstageIdentityResponse {
const { sub, ent } = parseJwtPayload(result.token);
- const userEntityRef = stringifyEntityRef(
- parseEntityRef(sub, {
- defaultKind: 'user',
- defaultNamespace: DEFAULT_NAMESPACE,
- }),
- );
return {
- ...{
- // TODO: idToken is for backwards compatibility and can be removed in the future
- idToken: result.token,
- ...result,
- },
+ ...result,
identity: {
type: 'user',
- userEntityRef,
+ userEntityRef: sub,
ownershipEntityRefs: ent ?? [],
},
};
diff --git a/plugins/auth-node/api-report.md b/plugins/auth-node/api-report.md
index 7840fc7d74..f7fdd6369b 100644
--- a/plugins/auth-node/api-report.md
+++ b/plugins/auth-node/api-report.md
@@ -3,7 +3,6 @@
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
-import { Entity } from '@backstage/catalog-model';
import { PluginEndpointDiscovery } from '@backstage/backend-common';
// @public
@@ -13,10 +12,6 @@ export interface BackstageIdentityResponse extends BackstageSignInResult {
// @public
export interface BackstageSignInResult {
- // @deprecated
- entity?: Entity;
- // @deprecated
- id: string;
token: string;
}
diff --git a/plugins/auth-node/package.json b/plugins/auth-node/package.json
index fc595a13ba..cb430f2de1 100644
--- a/plugins/auth-node/package.json
+++ b/plugins/auth-node/package.json
@@ -24,7 +24,6 @@
},
"dependencies": {
"@backstage/backend-common": "^0.13.1",
- "@backstage/catalog-model": "^1.0.0",
"@backstage/config": "^1.0.0",
"@backstage/errors": "^1.0.0",
"jose": "^1.27.1",
diff --git a/plugins/auth-node/src/IdentityClient.test.ts b/plugins/auth-node/src/IdentityClient.test.ts
index 72ef7f2a57..88d4021dc3 100644
--- a/plugins/auth-node/src/IdentityClient.test.ts
+++ b/plugins/auth-node/src/IdentityClient.test.ts
@@ -135,12 +135,11 @@ describe('IdentityClient', () => {
const token = await factory.issueToken({ claims: { sub: 'foo' } });
const response = await client.authenticate(token);
expect(response).toEqual({
- id: 'foo',
token: token,
identity: {
- ownershipEntityRefs: [],
type: 'user',
userEntityRef: 'foo',
+ ownershipEntityRefs: [],
},
});
});
@@ -202,12 +201,11 @@ describe('IdentityClient', () => {
const token = await factory.issueToken({ claims: { sub: 'foo' } });
const response = await client.authenticate(token);
expect(response).toEqual({
- id: 'foo',
token: token,
identity: {
- ownershipEntityRefs: [],
type: 'user',
userEntityRef: 'foo',
+ ownershipEntityRefs: [],
},
});
});
diff --git a/plugins/auth-node/src/IdentityClient.ts b/plugins/auth-node/src/IdentityClient.ts
index d8e841bf75..54c2670ae8 100644
--- a/plugins/auth-node/src/IdentityClient.ts
+++ b/plugins/auth-node/src/IdentityClient.ts
@@ -87,7 +87,6 @@ export class IdentityClient {
}
const user: BackstageIdentityResponse = {
- id: decoded.sub,
token,
identity: {
type: 'user',
diff --git a/plugins/auth-node/src/types.ts b/plugins/auth-node/src/types.ts
index b574c2204d..0d3e015beb 100644
--- a/plugins/auth-node/src/types.ts
+++ b/plugins/auth-node/src/types.ts
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-import { Entity } from '@backstage/catalog-model';
-
/**
* A representation of a successful Backstage sign-in.
*
@@ -25,25 +23,6 @@ import { Entity } from '@backstage/catalog-model';
* @public
*/
export interface BackstageSignInResult {
- /**
- * An opaque ID that uniquely identifies the user within Backstage.
- *
- * This is typically the same as the user entity `metadata.name`.
- *
- * @deprecated Use the `identity` field instead
- */
- id: string;
-
- /**
- * The entity that the user is represented by within Backstage.
- *
- * This entity may or may not exist within the Catalog, and it can be used
- * to read and store additional metadata about the user.
- *
- * @deprecated Use the `identity` field instead.
- */
- entity?: Entity;
-
/**
* The token used to authenticate the user within Backstage.
*/
diff --git a/plugins/catalog-react/api-report.md b/plugins/catalog-react/api-report.md
index a1541b555e..b90072beba 100644
--- a/plugins/catalog-react/api-report.md
+++ b/plugins/catalog-react/api-report.md
@@ -261,15 +261,11 @@ export type EntityRefLinkProps = {
} & Omit;
// @public
-export const EntityRefLinks: ({
- entityRefs,
- defaultKind,
- ...linkProps
-}: EntityRefLinksProps) => JSX.Element;
+export function EntityRefLinks(props: EntityRefLinksProps): JSX.Element;
// @public
export type EntityRefLinksProps = {
- entityRefs: (Entity | CompoundEntityRef)[];
+ entityRefs: (string | Entity | CompoundEntityRef)[];
defaultKind?: string;
} & Omit;
diff --git a/plugins/catalog-react/src/components/EntityRefLink/EntityRefLinks.tsx b/plugins/catalog-react/src/components/EntityRefLink/EntityRefLinks.tsx
index d92cd2ec87..30dda011d4 100644
--- a/plugins/catalog-react/src/components/EntityRefLink/EntityRefLinks.tsx
+++ b/plugins/catalog-react/src/components/EntityRefLink/EntityRefLinks.tsx
@@ -25,7 +25,7 @@ import { LinkProps } from '@backstage/core-components';
* @public
*/
export type EntityRefLinksProps = {
- entityRefs: (Entity | CompoundEntityRef)[];
+ entityRefs: (string | Entity | CompoundEntityRef)[];
defaultKind?: string;
} & Omit;
@@ -34,17 +34,20 @@ export type EntityRefLinksProps = {
*
* @public
*/
-export const EntityRefLinks = ({
- entityRefs,
- defaultKind,
- ...linkProps
-}: EntityRefLinksProps) => (
- <>
- {entityRefs.map((r, i) => (
-
- {i > 0 && ', '}
-
-
- ))}
- >
-);
+export function EntityRefLinks(props: EntityRefLinksProps) {
+ const { entityRefs, defaultKind, ...linkProps } = props;
+ return (
+ <>
+ {entityRefs.map((r, i) => (
+
+ {i > 0 && ', '}
+
+
+ ))}
+ >
+ );
+}
diff --git a/plugins/catalog/src/components/FilteredEntityLayout/index.ts b/plugins/catalog/src/components/FilteredEntityLayout/index.ts
index 892aa34147..a9277a3298 100644
--- a/plugins/catalog/src/components/FilteredEntityLayout/index.ts
+++ b/plugins/catalog/src/components/FilteredEntityLayout/index.ts
@@ -18,7 +18,7 @@ import { CatalogFilterLayout } from '@backstage/plugin-catalog-react';
/**
* @public
- * @deprecated Use `FilteredCatalogLayout` from `@backstage/plugin-catalog-react` instead.
+ * @deprecated Use `CatalogFilterLayout` from `@backstage/plugin-catalog-react` instead.
*/
export const FilteredEntityLayout = CatalogFilterLayout as (props: {
children: React.ReactNode;
@@ -26,12 +26,12 @@ export const FilteredEntityLayout = CatalogFilterLayout as (props: {
/**
* @public
- * @deprecated Use `FilteredCatalogLayout.Filters` from `@backstage/plugin-catalog-react` instead.
+ * @deprecated Use `CatalogFilterLayout.Filters` from `@backstage/plugin-catalog-react` instead.
*/
export const FilterContainer = CatalogFilterLayout.Filters;
/**
* @public
- * @deprecated Use `FilteredCatalogLayout.Content` from `@backstage/plugin-catalog-react` instead.
+ * @deprecated Use `CatalogFilterLayout.Content` from `@backstage/plugin-catalog-react` instead.
*/
export const EntityListContainer = CatalogFilterLayout.Content;
diff --git a/plugins/kubernetes/src/utils/pod.tsx b/plugins/kubernetes/src/utils/pod.tsx
index 50cc983b9d..7bed160a5f 100644
--- a/plugins/kubernetes/src/utils/pod.tsx
+++ b/plugins/kubernetes/src/utils/pod.tsx
@@ -118,6 +118,8 @@ export const currentToDeclaredResourceToPerc = (
current: number | string,
resource: number | string,
): string => {
+ if (Number(resource) === 0) return `0%`;
+
if (typeof current === 'number' && typeof resource === 'number') {
return `${Math.round((current / resource) * 100)}%`;
}
diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.test.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.test.tsx
index 22043d5761..7fac9f7840 100644
--- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.test.tsx
+++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.test.tsx
@@ -138,7 +138,7 @@ describe('RepoUrlPicker', () => {
'ui:options': {
requestUserCredentials: {
secretsKey: 'testKey',
- additionalScopes: { github: ['workflow:write'] },
+ additionalScopes: { github: ['workflow'] },
},
},
}}
@@ -164,7 +164,7 @@ describe('RepoUrlPicker', () => {
additionalScope: {
repoWrite: true,
customScopes: {
- github: ['workflow:write'],
+ github: ['workflow'],
},
},
});
diff --git a/plugins/search-backend-module-elasticsearch/api-report.md b/plugins/search-backend-module-elasticsearch/api-report.md
index 265fdda686..10231f3a83 100644
--- a/plugins/search-backend-module-elasticsearch/api-report.md
+++ b/plugins/search-backend-module-elasticsearch/api-report.md
@@ -10,10 +10,10 @@ import { Client } from '@elastic/elasticsearch';
import { Config } from '@backstage/config';
import type { ConnectionOptions } from 'tls';
import { IndexableDocument } from '@backstage/plugin-search-common';
+import { IndexableResultSet } from '@backstage/plugin-search-common';
import { Logger } from 'winston';
import { SearchEngine } from '@backstage/plugin-search-common';
import { SearchQuery } from '@backstage/plugin-search-common';
-import { SearchResultSet } from '@backstage/plugin-search-common';
// Warning: (ae-missing-release-tag) "ElasticSearchClientOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
// Warning: (ae-unresolved-link) The @link reference could not be resolved: The package "@backstage/plugin-search-backend-module-elasticsearch" does not have an export "ElasticSearchEngine"
@@ -119,7 +119,7 @@ export class ElasticSearchSearchEngine implements SearchEngine {
getIndexer(type: string): Promise;
newClient(create: (options: ElasticSearchClientOptions) => T): T;
// (undocumented)
- query(query: SearchQuery): Promise;
+ query(query: SearchQuery): Promise;
// Warning: (ae-forgotten-export) The symbol "ElasticSearchQueryTranslator" needs to be exported by the entry point index.d.ts
//
// (undocumented)
diff --git a/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.ts b/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.ts
index f2ed5ed2b0..aec225a64b 100644
--- a/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.ts
+++ b/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.ts
@@ -21,9 +21,9 @@ import {
import { Config } from '@backstage/config';
import {
IndexableDocument,
+ IndexableResultSet,
SearchEngine,
SearchQuery,
- SearchResultSet,
} from '@backstage/plugin-search-common';
import { Client } from '@elastic/elasticsearch';
import esb from 'elastic-builder';
@@ -192,7 +192,7 @@ export class ElasticSearchSearchEngine implements SearchEngine {
return indexer;
}
- async query(query: SearchQuery): Promise {
+ async query(query: SearchQuery): Promise {
const { elasticSearchQuery, documentTypes, pageSize } =
this.translator(query);
const queryIndices = documentTypes
diff --git a/plugins/search-backend-module-pg/api-report.md b/plugins/search-backend-module-pg/api-report.md
index 39847a4935..71ceac996e 100644
--- a/plugins/search-backend-module-pg/api-report.md
+++ b/plugins/search-backend-module-pg/api-report.md
@@ -5,11 +5,11 @@
```ts
import { BatchSearchEngineIndexer } from '@backstage/plugin-search-backend-node';
import { IndexableDocument } from '@backstage/plugin-search-common';
+import { IndexableResultSet } from '@backstage/plugin-search-common';
import { Knex } from 'knex';
import { PluginDatabaseManager } from '@backstage/backend-common';
import { SearchEngine } from '@backstage/plugin-search-backend-node';
import { SearchQuery } from '@backstage/plugin-search-common';
-import { SearchResultSet } from '@backstage/plugin-search-common';
// Warning: (ae-missing-release-tag) "ConcretePgSearchQuery" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
@@ -88,7 +88,7 @@ export class PgSearchEngine implements SearchEngine {
// (undocumented)
getIndexer(type: string): Promise;
// (undocumented)
- query(query: SearchQuery): Promise;
+ query(query: SearchQuery): Promise;
// (undocumented)
setTranslator(
translator: (query: SearchQuery) => ConcretePgSearchQuery,
diff --git a/plugins/search-backend-module-pg/src/PgSearchEngine/PgSearchEngine.ts b/plugins/search-backend-module-pg/src/PgSearchEngine/PgSearchEngine.ts
index 8f75112837..ea363d8ea1 100644
--- a/plugins/search-backend-module-pg/src/PgSearchEngine/PgSearchEngine.ts
+++ b/plugins/search-backend-module-pg/src/PgSearchEngine/PgSearchEngine.ts
@@ -15,7 +15,10 @@
*/
import { PluginDatabaseManager } from '@backstage/backend-common';
import { SearchEngine } from '@backstage/plugin-search-backend-node';
-import { SearchQuery, SearchResultSet } from '@backstage/plugin-search-common';
+import {
+ SearchQuery,
+ IndexableResultSet,
+} from '@backstage/plugin-search-common';
import { PgSearchEngineIndexer } from './PgSearchEngineIndexer';
import {
DatabaseDocumentStore,
@@ -81,7 +84,7 @@ export class PgSearchEngine implements SearchEngine {
});
}
- async query(query: SearchQuery): Promise {
+ async query(query: SearchQuery): Promise {
const { pgQuery, pageSize } = this.translator(query);
const rows = await this.databaseStore.transaction(async tx =>
diff --git a/plugins/search-backend-node/api-report.md b/plugins/search-backend-node/api-report.md
index e4359eafac..ebc49df280 100644
--- a/plugins/search-backend-node/api-report.md
+++ b/plugins/search-backend-node/api-report.md
@@ -9,13 +9,13 @@ import { DocumentCollatorFactory } from '@backstage/plugin-search-common';
import { DocumentDecoratorFactory } from '@backstage/plugin-search-common';
import { DocumentTypeInfo } from '@backstage/plugin-search-common';
import { IndexableDocument } from '@backstage/plugin-search-common';
+import { IndexableResultSet } from '@backstage/plugin-search-common';
import { Logger } from 'winston';
import { default as lunr_2 } from 'lunr';
import { QueryTranslator } from '@backstage/plugin-search-common';
import { Readable } from 'stream';
import { SearchEngine } from '@backstage/plugin-search-common';
import { SearchQuery } from '@backstage/plugin-search-common';
-import { SearchResultSet } from '@backstage/plugin-search-common';
import { Transform } from 'stream';
import { Writable } from 'stream';
@@ -87,7 +87,7 @@ export class LunrSearchEngine implements SearchEngine {
// (undocumented)
protected lunrIndices: Record;
// (undocumented)
- query(query: SearchQuery): Promise;
+ query(query: SearchQuery): Promise;
// (undocumented)
setTranslator(translator: LunrQueryTranslator): void;
// (undocumented)
diff --git a/plugins/search-backend-node/src/engines/LunrSearchEngine.ts b/plugins/search-backend-node/src/engines/LunrSearchEngine.ts
index b1d695ad1d..09e8729ba8 100644
--- a/plugins/search-backend-node/src/engines/LunrSearchEngine.ts
+++ b/plugins/search-backend-node/src/engines/LunrSearchEngine.ts
@@ -16,8 +16,8 @@
import {
IndexableDocument,
+ IndexableResultSet,
SearchQuery,
- SearchResultSet,
QueryTranslator,
SearchEngine,
} from '@backstage/plugin-search-common';
@@ -147,7 +147,7 @@ export class LunrSearchEngine implements SearchEngine {
return indexer;
}
- async query(query: SearchQuery): Promise {
+ async query(query: SearchQuery): Promise {
const { lunrQueryBuilder, documentTypes, pageSize } = this.translator(
query,
) as ConcreteLunrQuery;
@@ -196,8 +196,8 @@ export class LunrSearchEngine implements SearchEngine {
? encodePageCursor({ page: page - 1 })
: undefined;
- // Translate results into SearchResultSet
- const realResultSet: SearchResultSet = {
+ // Translate results into IndexableResultSet
+ const realResultSet: IndexableResultSet = {
results: results.slice(offset, offset + pageSize).map(d => {
return { type: d.type, document: this.docStore[d.result.ref] };
}),
diff --git a/plugins/search-backend/src/service/AuthorizedSearchEngine.ts b/plugins/search-backend/src/service/AuthorizedSearchEngine.ts
index 2e65e18a84..2a5fc471f5 100644
--- a/plugins/search-backend/src/service/AuthorizedSearchEngine.ts
+++ b/plugins/search-backend/src/service/AuthorizedSearchEngine.ts
@@ -25,12 +25,12 @@ import {
} from '@backstage/plugin-permission-common';
import {
DocumentTypeInfo,
+ IndexableResult,
+ IndexableResultSet,
QueryRequestOptions,
QueryTranslator,
SearchEngine,
SearchQuery,
- SearchResult,
- SearchResultSet,
} from '@backstage/plugin-search-common';
import { Config } from '@backstage/config';
import { InputError } from '@backstage/errors';
@@ -85,7 +85,7 @@ export class AuthorizedSearchEngine implements SearchEngine {
async query(
query: SearchQuery,
options: QueryRequestOptions,
- ): Promise {
+ ): Promise {
const queryStartTime = Date.now();
const authorizer = new DataLoader(
@@ -144,7 +144,7 @@ export class AuthorizedSearchEngine implements SearchEngine {
const { page } = decodePageCursor(query.pageCursor);
const targetResults = (page + 1) * this.pageSize;
- let filteredResults: SearchResult[] = [];
+ let filteredResults: IndexableResult[] = [];
let nextPageCursor: string | undefined;
let latencyBudgetExhausted = false;
@@ -183,7 +183,7 @@ export class AuthorizedSearchEngine implements SearchEngine {
}
private async filterResults(
- results: SearchResult[],
+ results: IndexableResult[],
typeDecisions: Record,
authorizer: DataLoader,
) {
diff --git a/plugins/search-backend/src/service/router.test.ts b/plugins/search-backend/src/service/router.test.ts
index bdf46a240b..2efab91256 100644
--- a/plugins/search-backend/src/service/router.test.ts
+++ b/plugins/search-backend/src/service/router.test.ts
@@ -19,7 +19,6 @@ import { ConfigReader } from '@backstage/config';
import { PermissionAuthorizer } from '@backstage/plugin-permission-common';
import {
IndexBuilder,
- LunrSearchEngine,
SearchEngine,
} from '@backstage/plugin-search-backend-node';
import express from 'express';
@@ -39,8 +38,19 @@ describe('createRouter', () => {
beforeAll(async () => {
const logger = getVoidLogger();
- const searchEngine = new LunrSearchEngine({ logger });
- const indexBuilder = new IndexBuilder({ logger, searchEngine });
+ mockSearchEngine = {
+ getIndexer: jest.fn(),
+ setTranslator: jest.fn(),
+ query: jest.fn().mockResolvedValue({
+ results: [],
+ nextPageCursor: '',
+ previousPageCursor: '',
+ }),
+ };
+ const indexBuilder = new IndexBuilder({
+ logger,
+ searchEngine: mockSearchEngine,
+ });
const router = await createRouter({
engine: indexBuilder.getSearchEngine(),
@@ -56,7 +66,7 @@ describe('createRouter', () => {
});
beforeEach(() => {
- jest.resetAllMocks();
+ jest.clearAllMocks();
});
describe('GET /query', () => {
@@ -101,6 +111,42 @@ describe('createRouter', () => {
});
});
+ it('removes backend-only properties from search documents', async () => {
+ mockSearchEngine.query.mockResolvedValue({
+ results: [
+ {
+ type: 'software-catalog',
+ document: {
+ text: 'foo',
+ title: 'bar baz',
+ location: '/catalog/default/component/example',
+ authorization: {
+ resourceRef: 'component:default/example',
+ },
+ },
+ },
+ ],
+ nextPageCursor: '',
+ previousPageCursor: '',
+ });
+
+ const response = await request(app).get('/query');
+
+ expect(response.status).toEqual(200);
+ expect(response.body).toMatchObject({
+ results: [
+ {
+ type: 'software-catalog',
+ document: {
+ text: 'foo',
+ title: 'bar baz',
+ location: '/catalog/default/component/example',
+ },
+ },
+ ],
+ });
+ });
+
describe('search result filtering', () => {
beforeAll(async () => {
const logger = getVoidLogger();
diff --git a/plugins/search-backend/src/service/router.ts b/plugins/search-backend/src/service/router.ts
index 92e4e5526f..ff91465cf4 100644
--- a/plugins/search-backend/src/service/router.ts
+++ b/plugins/search-backend/src/service/router.ts
@@ -26,6 +26,7 @@ import { getBearerTokenFromAuthorizationHeader } from '@backstage/plugin-auth-no
import { PermissionAuthorizer } from '@backstage/plugin-permission-common';
import {
DocumentTypeInfo,
+ IndexableResultSet,
SearchResultSet,
} from '@backstage/plugin-search-common';
import { SearchEngine } from '@backstage/plugin-search-backend-node';
@@ -89,6 +90,17 @@ export async function createRouter(
}),
});
+ const toSearchResults = (resultSet: IndexableResultSet): SearchResultSet => ({
+ ...resultSet,
+ results: resultSet.results.map(result => ({
+ ...result,
+ document: {
+ ...result.document,
+ authorization: undefined,
+ },
+ })),
+ });
+
const router = Router();
router.get(
'/query',
@@ -116,7 +128,7 @@ export async function createRouter(
try {
const resultSet = await engine?.query(query, { token });
- res.send(filterResultSet(resultSet));
+ res.send(filterResultSet(toSearchResults(resultSet)));
} catch (err) {
throw new Error(
`There was a problem performing the search query. ${err}`,
diff --git a/plugins/search-common/api-report.md b/plugins/search-common/api-report.md
index 8ab25d5e42..bd5a56c5cc 100644
--- a/plugins/search-common/api-report.md
+++ b/plugins/search-common/api-report.md
@@ -30,14 +30,17 @@ export type DocumentTypeInfo = {
};
// @beta
-export interface IndexableDocument {
+export type IndexableDocument = SearchDocument & {
authorization?: {
resourceRef: string;
};
- location: string;
- text: string;
- title: string;
-}
+};
+
+// @beta (undocumented)
+export type IndexableResult = Result;
+
+// @beta (undocumented)
+export type IndexableResultSet = ResultSet;
// @beta
export type QueryRequestOptions = {
@@ -47,13 +50,38 @@ export type QueryRequestOptions = {
// @beta
export type QueryTranslator = (query: SearchQuery) => unknown;
+// @beta (undocumented)
+export interface Result {
+ // (undocumented)
+ document: TDocument;
+ // (undocumented)
+ type: string;
+}
+
+// @beta (undocumented)
+export interface ResultSet {
+ // (undocumented)
+ nextPageCursor?: string;
+ // (undocumented)
+ previousPageCursor?: string;
+ // (undocumented)
+ results: Result[];
+}
+
+// @beta
+export interface SearchDocument {
+ location: string;
+ text: string;
+ title: string;
+}
+
// @beta
export interface SearchEngine {
getIndexer(type: string): Promise;
query(
query: SearchQuery,
options?: QueryRequestOptions,
- ): Promise;
+ ): Promise;
setTranslator(translator: QueryTranslator): void;
}
@@ -70,20 +98,8 @@ export interface SearchQuery {
}
// @beta (undocumented)
-export interface SearchResult {
- // (undocumented)
- document: IndexableDocument;
- // (undocumented)
- type: string;
-}
+export type SearchResult = Result;
// @beta (undocumented)
-export interface SearchResultSet {
- // (undocumented)
- nextPageCursor?: string;
- // (undocumented)
- previousPageCursor?: string;
- // (undocumented)
- results: SearchResult[];
-}
+export type SearchResultSet = ResultSet;
```
diff --git a/plugins/search-common/src/types.ts b/plugins/search-common/src/types.ts
index 51ce45617b..4eedabeb71 100644
--- a/plugins/search-common/src/types.ts
+++ b/plugins/search-common/src/types.ts
@@ -31,26 +31,45 @@ export interface SearchQuery {
/**
* @beta
*/
-export interface SearchResult {
+export interface Result {
type: string;
- document: IndexableDocument;
+ document: TDocument;
}
/**
* @beta
*/
-export interface SearchResultSet {
- results: SearchResult[];
+export interface ResultSet {
+ results: Result[];
nextPageCursor?: string;
previousPageCursor?: string;
}
/**
- * Base properties that all indexed documents must include, as well as some
- * common properties that documents are encouraged to use where appropriate.
* @beta
*/
-export interface IndexableDocument {
+export type SearchResult = Result;
+
+/**
+ * @beta
+ */
+export type SearchResultSet = ResultSet;
+
+/**
+ * @beta
+ */
+export type IndexableResult = Result;
+
+/**
+ * @beta
+ */
+export type IndexableResultSet = ResultSet;
+
+/**
+ * Base properties that all search documents must include.
+ * @beta
+ */
+export interface SearchDocument {
/**
* The primary name of the document (e.g. name, title, identifier, etc).
*/
@@ -66,7 +85,16 @@ export interface IndexableDocument {
* is clicked).
*/
location: string;
+}
+/**
+ * Properties related to indexing of documents. This type is only useful for
+ * backends working directly with documents being inserted or retrieved from
+ * search indexes. When dealing with documents in the frontend, use
+ * {@link SearchDocument}.
+ * @beta
+ */
+export type IndexableDocument = SearchDocument & {
/**
* Optional authorization information to be used when determining whether this
* search result should be visible to a given user.
@@ -77,7 +105,7 @@ export interface IndexableDocument {
*/
resourceRef: string;
};
-}
+};
/**
* Information about a specific document type. Intended to be used in the
@@ -178,5 +206,5 @@ export interface SearchEngine {
query(
query: SearchQuery,
options?: QueryRequestOptions,
- ): Promise;
+ ): Promise;
}
diff --git a/plugins/search/api-report.md b/plugins/search/api-report.md
index 0a277dab85..1bdd918802 100644
--- a/plugins/search/api-report.md
+++ b/plugins/search/api-report.md
@@ -9,13 +9,13 @@ import { ApiRef } from '@backstage/core-plugin-api';
import { AsyncState } from 'react-use/lib/useAsync';
import { BackstagePlugin } from '@backstage/core-plugin-api';
import { IconComponent } from '@backstage/core-plugin-api';
-import { IndexableDocument } from '@backstage/plugin-search-common';
import { InputBaseProps } from '@material-ui/core';
import { JsonObject } from '@backstage/types';
import { default as React_2 } from 'react';
import { ReactElement } from 'react';
import { ReactNode } from 'react';
import { RouteRef } from '@backstage/core-plugin-api';
+import { SearchDocument } from '@backstage/plugin-search-common';
import { SearchQuery } from '@backstage/plugin-search-common';
import { SearchResult as SearchResult_2 } from '@backstage/plugin-search-common';
import { SearchResultSet } from '@backstage/plugin-search-common';
@@ -31,7 +31,7 @@ export const DefaultResultListItem: ({
}: {
icon?: ReactNode;
secondaryAction?: ReactNode;
- result: IndexableDocument;
+ result: SearchDocument;
lineClamp?: number | undefined;
}) => JSX.Element;
diff --git a/plugins/search/src/components/DefaultResultListItem/DefaultResultListItem.tsx b/plugins/search/src/components/DefaultResultListItem/DefaultResultListItem.tsx
index d9fbfe315e..46045f91ee 100644
--- a/plugins/search/src/components/DefaultResultListItem/DefaultResultListItem.tsx
+++ b/plugins/search/src/components/DefaultResultListItem/DefaultResultListItem.tsx
@@ -15,7 +15,7 @@
*/
import React, { ReactNode } from 'react';
-import { IndexableDocument } from '@backstage/plugin-search-common';
+import { SearchDocument } from '@backstage/plugin-search-common';
import {
ListItem,
ListItemIcon,
@@ -29,7 +29,7 @@ import TextTruncate from 'react-text-truncate';
type Props = {
icon?: ReactNode;
secondaryAction?: ReactNode;
- result: IndexableDocument;
+ result: SearchDocument;
lineClamp?: number;
};
diff --git a/plugins/user-settings/src/components/AuthProviders/DefaultProviderSettings.tsx b/plugins/user-settings/src/components/AuthProviders/DefaultProviderSettings.tsx
index 7025167658..019967cf55 100644
--- a/plugins/user-settings/src/components/AuthProviders/DefaultProviderSettings.tsx
+++ b/plugins/user-settings/src/components/AuthProviders/DefaultProviderSettings.tsx
@@ -24,6 +24,7 @@ import {
microsoftAuthApiRef,
bitbucketAuthApiRef,
atlassianAuthApiRef,
+ oneloginAuthApiRef,
} from '@backstage/core-plugin-api';
type Props = {
@@ -80,6 +81,14 @@ export const DefaultProviderSettings = ({ configuredProviders }: Props) => (
icon={Star}
/>
)}
+ {configuredProviders.includes('onelogin') && (
+
+ )}
{configuredProviders.includes('atlassian') && (