Merge pull request #6719 from ssaraswati/sonarqube-authenticate-calls
Add auth token to SonarQubeClient via IdentityApi
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-sonarqube': minor
|
||||
---
|
||||
|
||||
Use IdentityApi to provide Auth Token for SonarQubeClient Api calls
|
||||
@@ -20,9 +20,39 @@ import { setupServer } from 'msw/node';
|
||||
import { FindingSummary, SonarQubeClient } from './index';
|
||||
import { ComponentWrapper, MeasuresWrapper } from './types';
|
||||
import { UrlPatternDiscovery } from '@backstage/core-app-api';
|
||||
import { IdentityApi } from '@backstage/core-plugin-api';
|
||||
|
||||
const server = setupServer();
|
||||
|
||||
const identityApiAuthenticated: IdentityApi = {
|
||||
getUserId() {
|
||||
return 'jane-fonda';
|
||||
},
|
||||
getProfile() {
|
||||
return { email: 'jane-fonda@spotify.com' };
|
||||
},
|
||||
async getIdToken() {
|
||||
return Promise.resolve('fake-id-token');
|
||||
},
|
||||
async signOut() {
|
||||
return Promise.resolve();
|
||||
},
|
||||
};
|
||||
const identityApiGuest: IdentityApi = {
|
||||
getUserId() {
|
||||
return 'guest';
|
||||
},
|
||||
getProfile() {
|
||||
return {};
|
||||
},
|
||||
async getIdToken() {
|
||||
return Promise.resolve(undefined);
|
||||
},
|
||||
async signOut() {
|
||||
return Promise.resolve();
|
||||
},
|
||||
};
|
||||
|
||||
describe('SonarQubeClient', () => {
|
||||
msw.setupDefaultHandlers(server);
|
||||
|
||||
@@ -161,7 +191,10 @@ describe('SonarQubeClient', () => {
|
||||
it('should report finding summary', async () => {
|
||||
setupHandlers();
|
||||
|
||||
const client = new SonarQubeClient({ discoveryApi });
|
||||
const client = new SonarQubeClient({
|
||||
discoveryApi,
|
||||
identityApi: identityApiAuthenticated,
|
||||
});
|
||||
|
||||
const summary = await client.getFindingSummary('our:service');
|
||||
expect(summary).toEqual(
|
||||
@@ -197,6 +230,7 @@ describe('SonarQubeClient', () => {
|
||||
const client = new SonarQubeClient({
|
||||
discoveryApi,
|
||||
baseUrl: 'http://a.instance.local',
|
||||
identityApi: identityApiAuthenticated,
|
||||
});
|
||||
|
||||
const summary = await client.getFindingSummary('our:service');
|
||||
@@ -234,6 +268,7 @@ describe('SonarQubeClient', () => {
|
||||
const client = new SonarQubeClient({
|
||||
discoveryApi,
|
||||
baseUrl: 'http://a.instance.local',
|
||||
identityApi: identityApiAuthenticated,
|
||||
});
|
||||
|
||||
const summary = await client.getFindingSummary('our:service');
|
||||
@@ -255,4 +290,56 @@ describe('SonarQubeClient', () => {
|
||||
'http://a.instance.local/component_measures?id=our%3Aservice&metric=coverage&resolved=false&view=list',
|
||||
);
|
||||
});
|
||||
|
||||
it('should add identity token for logged in users', async () => {
|
||||
setupHandlers();
|
||||
server.use(
|
||||
rest.get(`${mockBaseUrl}/sonarqube/components/show`, (req, res, ctx) => {
|
||||
expect(req.url.searchParams.toString()).toBe('component=our%3Aservice');
|
||||
expect(req.headers.get('Authorization')).toBe('Bearer fake-id-token');
|
||||
return res(
|
||||
ctx.json({
|
||||
component: {
|
||||
analysisDate: '2020-01-01T00:00:00Z',
|
||||
},
|
||||
} as ComponentWrapper),
|
||||
);
|
||||
}),
|
||||
);
|
||||
|
||||
const client = new SonarQubeClient({
|
||||
discoveryApi,
|
||||
baseUrl: 'http://a.instance.local',
|
||||
identityApi: identityApiAuthenticated,
|
||||
});
|
||||
const summary = await client.getFindingSummary('our:service');
|
||||
|
||||
expect(summary?.lastAnalysis).toBe('2020-01-01T00:00:00Z');
|
||||
});
|
||||
|
||||
it('should omit identity token for guest users', async () => {
|
||||
setupHandlers();
|
||||
server.use(
|
||||
rest.get(`${mockBaseUrl}/sonarqube/components/show`, (req, res, ctx) => {
|
||||
expect(req.url.searchParams.toString()).toBe('component=our%3Aservice');
|
||||
expect(req.headers.has('Authorization')).toBeFalsy();
|
||||
return res(
|
||||
ctx.json({
|
||||
component: {
|
||||
analysisDate: '2020-01-01T00:00:00Z',
|
||||
},
|
||||
} as ComponentWrapper),
|
||||
);
|
||||
}),
|
||||
);
|
||||
|
||||
const client = new SonarQubeClient({
|
||||
discoveryApi,
|
||||
baseUrl: 'http://a.instance.local',
|
||||
identityApi: identityApiGuest,
|
||||
});
|
||||
const summary = await client.getFindingSummary('our:service');
|
||||
|
||||
expect(summary?.lastAnalysis).toBe('2020-01-01T00:00:00Z');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -17,20 +17,24 @@
|
||||
import fetch from 'cross-fetch';
|
||||
import { FindingSummary, Metrics, SonarQubeApi } from './SonarQubeApi';
|
||||
import { ComponentWrapper, MeasuresWrapper } from './types';
|
||||
import { DiscoveryApi } from '@backstage/core-plugin-api';
|
||||
import { DiscoveryApi, IdentityApi } from '@backstage/core-plugin-api';
|
||||
|
||||
export class SonarQubeClient implements SonarQubeApi {
|
||||
discoveryApi: DiscoveryApi;
|
||||
baseUrl: string;
|
||||
identityApi: IdentityApi;
|
||||
|
||||
constructor({
|
||||
discoveryApi,
|
||||
identityApi,
|
||||
baseUrl = 'https://sonarcloud.io/',
|
||||
}: {
|
||||
discoveryApi: DiscoveryApi;
|
||||
identityApi: IdentityApi;
|
||||
baseUrl?: string;
|
||||
}) {
|
||||
this.discoveryApi = discoveryApi;
|
||||
this.identityApi = identityApi;
|
||||
this.baseUrl = baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`;
|
||||
}
|
||||
|
||||
@@ -38,9 +42,17 @@ export class SonarQubeClient implements SonarQubeApi {
|
||||
path: string,
|
||||
query: { [key in string]: any },
|
||||
): Promise<T | undefined> {
|
||||
const idToken = await this.identityApi.getIdToken();
|
||||
|
||||
const apiUrl = `${await this.discoveryApi.getBaseUrl('proxy')}/sonarqube`;
|
||||
const response = await fetch(
|
||||
`${apiUrl}/${path}?${new URLSearchParams(query).toString()}`,
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...(idToken && { Authorization: `Bearer ${idToken}` }),
|
||||
},
|
||||
},
|
||||
);
|
||||
if (response.status === 200) {
|
||||
return (await response.json()) as T;
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
createComponentExtension,
|
||||
createPlugin,
|
||||
discoveryApiRef,
|
||||
identityApiRef,
|
||||
} from '@backstage/core-plugin-api';
|
||||
|
||||
export const sonarQubePlugin = createPlugin({
|
||||
@@ -28,11 +29,16 @@ export const sonarQubePlugin = createPlugin({
|
||||
apis: [
|
||||
createApiFactory({
|
||||
api: sonarQubeApiRef,
|
||||
deps: { configApi: configApiRef, discoveryApi: discoveryApiRef },
|
||||
factory: ({ configApi, discoveryApi }) =>
|
||||
deps: {
|
||||
configApi: configApiRef,
|
||||
discoveryApi: discoveryApiRef,
|
||||
identityApi: identityApiRef,
|
||||
},
|
||||
factory: ({ configApi, discoveryApi, identityApi }) =>
|
||||
new SonarQubeClient({
|
||||
discoveryApi,
|
||||
baseUrl: configApi.getOptionalString('sonarQube.baseUrl'),
|
||||
identityApi,
|
||||
}),
|
||||
}),
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user