diff --git a/plugins/cloudbuild/src/api/CloudbuildApi.ts b/plugins/cloudbuild/src/api/CloudbuildApi.ts index e9760677fb..7091ddf1be 100644 --- a/plugins/cloudbuild/src/api/CloudbuildApi.ts +++ b/plugins/cloudbuild/src/api/CloudbuildApi.ts @@ -26,15 +26,10 @@ export const cloudbuildApiRef = createApiRef({ }); export type CloudbuildApi = { - listWorkflowRuns: ({ - token, - projectId, - }: { - token: string; + listWorkflowRuns: (request: { projectId: string; }) => Promise; getWorkflow: ({ - token, projectId, id, }: { @@ -43,20 +38,16 @@ export type CloudbuildApi = { id: string; }) => Promise; getWorkflowRun: ({ - token, projectId, id, }: { - token: string; projectId: string; id: string; }) => Promise; reRunWorkflow: ({ - token, projectId, runId, }: { - token: string; projectId: string; runId: string; }) => Promise; diff --git a/plugins/cloudbuild/src/api/CloudbuildClient.ts b/plugins/cloudbuild/src/api/CloudbuildClient.ts index 4219ecabc1..572d29b6b8 100644 --- a/plugins/cloudbuild/src/api/CloudbuildClient.ts +++ b/plugins/cloudbuild/src/api/CloudbuildClient.ts @@ -20,40 +20,43 @@ import { ActionsGetWorkflowResponseData, Builds, } from '../api/types'; +import { OAuthApi } from '@backstage/core'; export class CloudbuildClient implements CloudbuildApi { + constructor(private readonly googleAuthApi: OAuthApi) {} + async reRunWorkflow({ - token, projectId, runId, }: { - token: string; projectId: string; runId: string; }): Promise { return await fetch( - `https://cloudbuild.googleapis.com/v1/projects/${projectId}/builds/${runId}:retry`, + `https://cloudbuild.googleapis.com/v1/projects/${encodeURIComponent( + projectId, + )}/builds/${encodeURIComponent(runId)}:retry`, { headers: new Headers({ Accept: '*/*', - Authorization: `Bearer ${token}`, + Authorization: `Bearer ${await this.getToken()}`, }), }, ); } async listWorkflowRuns({ - token, projectId, }: { - token: string; projectId: string; }): Promise { const workflowRuns = await fetch( - `https://cloudbuild.googleapis.com/v1/projects/${projectId}/builds`, + `https://cloudbuild.googleapis.com/v1/projects/${encodeURIComponent( + projectId, + )}/builds`, { headers: new Headers({ Accept: '*/*', - Authorization: `Bearer ${token}`, + Authorization: `Bearer ${await this.getToken()}`, }), }, ); @@ -68,20 +71,20 @@ export class CloudbuildClient implements CloudbuildApi { return response; } async getWorkflow({ - token, projectId, id, }: { - token: string; projectId: string; id: string; }): Promise { const workflow = await fetch( - `https://cloudbuild.googleapis.com/v1/projects/${projectId}/builds/${id}`, + `https://cloudbuild.googleapis.com/v1/projects/${encodeURIComponent( + projectId, + )}/builds/${encodeURIComponent(id)}`, { headers: new Headers({ Accept: '*/*', - Authorization: `Bearer ${token}`, + Authorization: `Bearer ${await this.getToken()}`, }), }, ); @@ -91,20 +94,20 @@ export class CloudbuildClient implements CloudbuildApi { return build; } async getWorkflowRun({ - token, projectId, id, }: { - token: string; projectId: string; id: string; }): Promise { const workflow = await fetch( - `https://cloudbuild.googleapis.com/v1/projects/${projectId}/builds/${id}`, + `https://cloudbuild.googleapis.com/v1/projects/${encodeURIComponent( + projectId, + )}/builds/${encodeURIComponent(id)}`, { headers: new Headers({ Accept: '*/*', - Authorization: `Bearer ${token}`, + Authorization: `Bearer ${await this.getToken()}`, }), }, ); @@ -112,4 +115,14 @@ export class CloudbuildClient implements CloudbuildApi { return build; } + + async getToken(): Promise { + // NOTE(freben - gcp-projects): There's a .read-only variant of this scope that we could + // use for readonly operations, but that means we would ask the user for a + // second auth during creation and I decided to keep the wider scope for + // all ops for now + return this.googleAuthApi.getAccessToken( + 'https://www.googleapis.com/auth/cloud-platform', + ); + } } diff --git a/plugins/cloudbuild/src/components/WorkflowRunDetails/useWorkflowRunsDetails.ts b/plugins/cloudbuild/src/components/WorkflowRunDetails/useWorkflowRunsDetails.ts index ca0f843f11..ae5e750d15 100644 --- a/plugins/cloudbuild/src/components/WorkflowRunDetails/useWorkflowRunsDetails.ts +++ b/plugins/cloudbuild/src/components/WorkflowRunDetails/useWorkflowRunsDetails.ts @@ -13,22 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { useApi, googleAuthApiRef } from '@backstage/core'; +import { useApi } from '@backstage/core'; import { useParams } from 'react-router-dom'; import { useAsync } from 'react-use'; import { cloudbuildApiRef } from '../../api'; export const useWorkflowRunsDetails = (projectId: string) => { const api = useApi(cloudbuildApiRef); - const auth = useApi(googleAuthApiRef); const { id } = useParams(); const details = useAsync(async () => { - const token = await auth.getAccessToken([ - 'https://www.googleapis.com/auth/cloud-platform', - ]); return projectId ? api.getWorkflowRun({ - token, projectId, id: id, }) diff --git a/plugins/cloudbuild/src/components/useWorkflowRuns.ts b/plugins/cloudbuild/src/components/useWorkflowRuns.ts index bc887f9a1a..7086ba1c02 100644 --- a/plugins/cloudbuild/src/components/useWorkflowRuns.ts +++ b/plugins/cloudbuild/src/components/useWorkflowRuns.ts @@ -17,12 +17,11 @@ import { useState } from 'react'; import { useAsyncRetry } from 'react-use'; import { WorkflowRun } from './WorkflowRunsTable/WorkflowRunsTable'; import { cloudbuildApiRef } from '../api/CloudbuildApi'; -import { useApi, googleAuthApiRef, errorApiRef } from '@backstage/core'; +import { useApi, errorApiRef } from '@backstage/core'; import { ActionsListWorkflowRunsForRepoResponseData } from '../api/types'; export function useWorkflowRuns({ projectId }: { projectId: string }) { const api = useApi(cloudbuildApiRef); - const auth = useApi(googleAuthApiRef); const errorApi = useApi(errorApiRef); const [total, setTotal] = useState(0); @@ -32,12 +31,8 @@ export function useWorkflowRuns({ projectId }: { projectId: string }) { const { loading, value: runs, retry, error } = useAsyncRetry< WorkflowRun[] >(async () => { - const token = await auth.getAccessToken([ - 'https://www.googleapis.com/auth/cloud-platform', - ]); return api .listWorkflowRuns({ - token, projectId, }) .then( @@ -52,7 +47,6 @@ export function useWorkflowRuns({ projectId }: { projectId: string }) { onReRunClick: async () => { try { await api.reRunWorkflow({ - token, projectId, runId: run.id, }); diff --git a/plugins/cloudbuild/src/plugin.ts b/plugins/cloudbuild/src/plugin.ts index 61ff78198f..ee997cc7ec 100644 --- a/plugins/cloudbuild/src/plugin.ts +++ b/plugins/cloudbuild/src/plugin.ts @@ -17,6 +17,7 @@ import { createPlugin, createRouteRef, createApiFactory, + googleAuthApiRef, } from '@backstage/core'; import { cloudbuildApiRef, CloudbuildClient } from './api'; @@ -32,5 +33,13 @@ export const buildRouteRef = createRouteRef({ export const plugin = createPlugin({ id: 'cloudbuild', - apis: [createApiFactory(cloudbuildApiRef, new CloudbuildClient())], + apis: [ + createApiFactory({ + api: cloudbuildApiRef, + deps: { googleAuthApi: googleAuthApiRef }, + factory({ googleAuthApi }) { + return new CloudbuildClient(googleAuthApi); + }, + }), + ], });