code-coverage-backend: migrate to support new auth services

Co-authored-by: Fredrik Adelöw <freben@gmail.com>
Co-authored-by: Carl-Erik Bergström <cbergstrom@spotify.com>
Co-authored-by: blam <ben@blam.sh>
Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2024-02-15 19:06:49 +01:00
parent 58b5e450dd
commit 8efe690204
6 changed files with 60 additions and 24 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-code-coverage-backend': patch
---
Migrated to support new auth services.
@@ -3,10 +3,12 @@
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
import { AuthService } from '@backstage/backend-plugin-api';
import { BackendFeature } from '@backstage/backend-plugin-api';
import { CatalogApi } from '@backstage/catalog-client';
import { Config } from '@backstage/config';
import express from 'express';
import { HttpAuthService } from '@backstage/backend-plugin-api';
import { Logger } from 'winston';
import { PluginDatabaseManager } from '@backstage/backend-common';
import { PluginEndpointDiscovery } from '@backstage/backend-common';
@@ -21,6 +23,8 @@ export function createRouter(options: RouterOptions): Promise<express.Router>;
// @public
export interface RouterOptions {
// (undocumented)
auth?: AuthService;
// (undocumented)
catalogApi?: CatalogApi;
// (undocumented)
@@ -30,6 +34,8 @@ export interface RouterOptions {
// (undocumented)
discovery: PluginEndpointDiscovery;
// (undocumented)
httpAuth?: HttpAuthService;
// (undocumented)
logger: Logger;
// (undocumented)
urlReader: UrlReader;
@@ -48,6 +48,7 @@
"yn": "^4.0.0"
},
"devDependencies": {
"@backstage/backend-test-utils": "workspace:^",
"@backstage/cli": "workspace:^",
"@types/body-parser-xml": "^2.0.2",
"@types/supertest": "^2.0.8",
@@ -26,6 +26,7 @@ import {
import { ConfigReader } from '@backstage/config';
import { createRouter } from './router';
import { CatalogRequestOptions } from '@backstage/catalog-client';
import { mockCredentials, mockServices } from '@backstage/backend-test-utils';
jest.mock('./CodeCoverageDatabase');
@@ -96,6 +97,8 @@ describe('createRouter', () => {
discovery: testDiscovery,
urlReader: mockUrlReader,
logger: getVoidLogger(),
auth: mockServices.auth(),
httpAuth: mockServices.httpAuth(),
});
app = express().use(router);
});
@@ -118,21 +121,21 @@ describe('createRouter', () => {
'/history?entity=component:default/mycomponent',
].forEach(uri => {
describe(`GET ${uri}`, () => {
it('does not send token when calling catalog api and request is unauthenticated', async () => {
const response = await request(app).get(uri);
expect(response.status).toEqual(200);
expect(catalogRequestOptions.token).toBeUndefined();
});
it('includes auth token when calling catalog api', async () => {
const token = 'my-auth-token';
it('forwards request credentials to the catalog api call', async () => {
const response = await request(app)
.get(uri)
.set('Authorization', `Bearer ${token}`);
.set(
'Authorization',
mockCredentials.user.header('user:default/other'),
);
expect(response.status).toEqual(200);
expect(catalogRequestOptions.token).toEqual(token);
expect(catalogRequestOptions.token).toEqual(
mockCredentials.service.token({
onBehalfOf: mockCredentials.user('user:default/other'),
targetPluginId: 'catalog',
}),
);
});
});
});
@@ -21,6 +21,7 @@ import BodyParser from 'body-parser';
import bodyParserXml from 'body-parser-xml';
import { CatalogApi, CatalogClient } from '@backstage/catalog-client';
import {
createLegacyAuthAdapters,
errorHandler,
PluginDatabaseManager,
PluginEndpointDiscovery,
@@ -33,7 +34,7 @@ import { CodeCoverageDatabase } from './CodeCoverageDatabase';
import { aggregateCoverage, CoverageUtils } from './CoverageUtils';
import { Converter, Jacoco, Cobertura, Lcov } from './converter';
import { getEntitySourceLocation } from '@backstage/catalog-model';
import { getBearerTokenFromAuthorizationHeader } from '@backstage/plugin-auth-node';
import { AuthService, HttpAuthService } from '@backstage/backend-plugin-api';
/**
* Options for {@link createRouter}.
@@ -47,6 +48,8 @@ export interface RouterOptions {
urlReader: UrlReader;
logger: Logger;
catalogApi?: CatalogApi;
auth?: AuthService;
httpAuth?: HttpAuthService;
}
export interface CodeCoverageApi {
@@ -63,6 +66,7 @@ export const makeRouter = async (
const catalogApi =
options.catalogApi ?? new CatalogClient({ discoveryApi: discovery });
const scm = ScmIntegrations.fromConfig(config);
const { auth, httpAuth } = createLegacyAuthAdapters(options);
const bodySizeLimit =
config.getOptionalString('codeCoverage.bodySizeLimit') ?? '100kb';
@@ -92,9 +96,13 @@ export const makeRouter = async (
*/
router.get('/report', async (req, res) => {
const { entity } = req.query;
const entityLookup = await catalogApi.getEntityByRef(entity as string, {
token: getBearerTokenFromAuthorizationHeader(req.headers.authorization),
});
const entityLookup = await catalogApi.getEntityByRef(
entity as string,
await auth.getPluginRequestToken({
onBehalfOf: await httpAuth.credentials(req),
targetPluginId: 'catalog',
}),
);
if (!entityLookup) {
throw new NotFoundError(`No entity found matching ${entity}`);
}
@@ -116,9 +124,13 @@ export const makeRouter = async (
*/
router.get('/history', async (req, res) => {
const { entity } = req.query;
const entityLookup = await catalogApi.getEntityByRef(entity as string, {
token: getBearerTokenFromAuthorizationHeader(req.headers.authorization),
});
const entityLookup = await catalogApi.getEntityByRef(
entity as string,
await auth.getPluginRequestToken({
onBehalfOf: await httpAuth.credentials(req),
targetPluginId: 'catalog',
}),
);
if (!entityLookup) {
throw new NotFoundError(`No entity found matching ${entity}`);
}
@@ -136,9 +148,13 @@ export const makeRouter = async (
*/
router.get('/file-content', async (req, res) => {
const { entity, path } = req.query;
const entityLookup = await catalogApi.getEntityByRef(entity as string, {
token: getBearerTokenFromAuthorizationHeader(req.headers.authorization),
});
const entityLookup = await catalogApi.getEntityByRef(
entity as string,
await auth.getPluginRequestToken({
onBehalfOf: await httpAuth.credentials(req),
targetPluginId: 'catalog',
}),
);
if (!entityLookup) {
throw new NotFoundError(`No entity found matching ${entity}`);
}
@@ -189,9 +205,13 @@ export const makeRouter = async (
*/
router.post('/report', async (req, res) => {
const { entity: entityRef, coverageType } = req.query;
const entity = await catalogApi.getEntityByRef(entityRef as string, {
token: getBearerTokenFromAuthorizationHeader(req.headers.authorization),
});
const entity = await catalogApi.getEntityByRef(
entityRef as string,
await auth.getPluginRequestToken({
onBehalfOf: await httpAuth.credentials(req),
targetPluginId: 'catalog',
}),
);
if (!entity) {
throw new NotFoundError(`No entity found matching ${entityRef}`);
}
+1
View File
@@ -6014,6 +6014,7 @@ __metadata:
dependencies:
"@backstage/backend-common": "workspace:^"
"@backstage/backend-plugin-api": "workspace:^"
"@backstage/backend-test-utils": "workspace:^"
"@backstage/catalog-client": "workspace:^"
"@backstage/catalog-model": "workspace:^"
"@backstage/cli": "workspace:^"