Make GitHub environment Scaffolder action use auth to resolve reviewers

Changes the github:environment:create Scaffolder action to request and
use a backend auth token when resolving the reviewer entityRefs from the
Backstage catalog.

This is because previously it would throw a 401 error when backend auth
was not disabled.

The logic for requesting the token is copied from the existing
catalog:fetch action, which needs to do a similar thing.

Also slightly clarifies that Backstage entityRefs are expected in the
reviewers list for this action.

Signed-off-by: Jason Liu <a.jason.liu21@gmail.com>
This commit is contained in:
Jason Liu
2024-11-23 14:14:17 +11:00
parent 77c7ce05d6
commit b5e002b1cc
4 changed files with 43 additions and 5 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder-backend-module-github': patch
---
Change `github:environment:create` action to request and use a token when resolving reviewer entity refs from the Backstage catalog.
@@ -3,6 +3,7 @@
> 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';
@@ -103,6 +104,7 @@ export function createGithubDeployKeyAction(options: {
export function createGithubEnvironmentAction(options: {
integrations: ScmIntegrationRegistry;
catalogClient?: CatalogApi;
auth?: AuthService;
}): TemplateAction<
{
repoUrl: string;
@@ -20,6 +20,7 @@ import { TemplateAction } from '@backstage/plugin-scaffolder-node';
import { ConfigReader } from '@backstage/config';
import { ScmIntegrations } from '@backstage/integration';
import { CatalogApi } from '@backstage/catalog-client';
import { mockCredentials, mockServices } from '@backstage/backend-test-utils';
const mockOctokit = {
rest: {
@@ -71,6 +72,14 @@ describe('github:environment:create', () => {
});
const integrations = ScmIntegrations.fromConfig(config);
const credentials = mockCredentials.user();
const token = mockCredentials.service.token({
onBehalfOf: credentials,
targetPluginId: 'catalog',
});
let action: TemplateAction<any>;
const mockContext = createMockActionContext({
@@ -78,6 +87,7 @@ describe('github:environment:create', () => {
repoUrl: 'github.com?repo=repository&owner=owner',
name: 'envname',
},
secrets: { backstageToken: token },
});
beforeEach(() => {
@@ -122,6 +132,7 @@ describe('github:environment:create', () => {
action = createGithubEnvironmentAction({
integrations,
catalogClient: mockCatalogClient as CatalogApi,
auth: mockServices.auth(),
});
});
@@ -453,6 +464,13 @@ describe('github:environment:create', () => {
},
});
expect(mockCatalogClient.getEntitiesByRefs).toHaveBeenCalledWith(
{
entityRefs: ['group:default/team-a', 'user:default/johndoe'],
},
{ token },
);
expect(
mockOctokit.rest.repos.createOrUpdateEnvironment,
).toHaveBeenCalledWith({
@@ -26,6 +26,7 @@ import Sodium from 'libsodium-wrappers';
import { examples } from './gitHubEnvironment.examples';
import { CatalogApi } from '@backstage/catalog-client';
import { Entity } from '@backstage/catalog-model';
import { AuthService } from '@backstage/backend-plugin-api';
/**
* Creates an `github:environment:create` Scaffolder action that creates a Github Environment.
@@ -35,8 +36,9 @@ import { Entity } from '@backstage/catalog-model';
export function createGithubEnvironmentAction(options: {
integrations: ScmIntegrationRegistry;
catalogClient?: CatalogApi;
auth?: AuthService;
}) {
const { integrations, catalogClient } = options;
const { integrations, catalogClient, auth } = options;
// For more information on how to define custom actions, see
// https://backstage.io/docs/features/software-templates/writing-custom-actions
return createTemplateAction<{
@@ -140,7 +142,8 @@ export function createGithubEnvironmentAction(options: {
reviewers: {
title: 'Reviewers',
type: 'array',
description: 'Reviewers for this environment',
description:
'Reviewers for this environment. Must be a list of Backstage entity references.',
items: {
type: 'string',
},
@@ -163,6 +166,11 @@ export function createGithubEnvironmentAction(options: {
reviewers,
} = ctx.input;
const { token } = (await auth?.getPluginRequestToken({
onBehalfOf: await ctx.getInitiatorCredentials(),
targetPluginId: 'catalog',
})) ?? { token: ctx.secrets?.backstageToken };
// When environment creation step is executed right after a repo publish step, the repository might not be available immediately.
// Add a 2-second delay before initiating the steps in this action.
await new Promise(resolve => setTimeout(resolve, 2000));
@@ -190,9 +198,14 @@ export function createGithubEnvironmentAction(options: {
if (reviewers) {
let reviewersEntityRefs: Array<Entity | undefined> = [];
// Fetch reviewers from Catalog
const catalogResponse = await catalogClient?.getEntitiesByRefs({
entityRefs: reviewers,
});
const catalogResponse = await catalogClient?.getEntitiesByRefs(
{
entityRefs: reviewers,
},
{
token,
},
);
if (catalogResponse?.items?.length) {
reviewersEntityRefs = catalogResponse.items;
}