cli: Add user entity to local catalog in auth flow

Signed-off-by: Marcus Eide <eide@spotify.com>
This commit is contained in:
Marcus Eide
2023-02-16 16:18:22 +01:00
committed by Philipp Hugenroth
parent 2f851a3945
commit 5663de4a37
4 changed files with 96 additions and 25 deletions
@@ -29,6 +29,13 @@ type GithubAuthConfig = {
};
};
};
catalog?: {
locations: Array<{
type: string;
target: string;
rules: Array<{ allow: Array<string> }>;
}>;
};
};
const readYaml = async (file: string) => {
@@ -67,3 +74,27 @@ AUTH_GITHUB_CLIENT_SECRET=${clientSecret}`;
return await fs.writeFile(file, content, 'utf8');
};
export const addUserEntity = async (file: string, username: string) => {
const content = {
apiVersion: 'backstage.io/v1alpha1',
kind: 'User',
metadata: {
name: username,
annotations: {
'github.com/user-login': username,
},
},
spec: {
memberOf: [],
},
};
return await fs.writeFile(
file,
yaml.stringify(content, {
indent: 2,
}),
'utf8',
);
};
@@ -21,6 +21,8 @@ import * as path from 'path';
const { targetRoot, resolveTargetRoot } = findPaths(__dirname);
export const APP_CONFIG_FILE = path.join(targetRoot, 'app-config.local.yaml');
export const ENV_CONFIG_FILE = path.join(targetRoot, '.env.local');
export const USER_ENTITY_FILE = path.join(targetRoot, 'user-info.yaml');
export const APP_TSX_FILE = path.join(
resolveTargetRoot('packages/app'),
'src',
@@ -17,13 +17,15 @@
import { OAuthApp } from '@octokit/oauth-app';
import chalk from 'chalk';
import inquirer from 'inquirer';
import fetch from 'node-fetch';
import { Task } from '../../../../lib/tasks';
import { updateConfigFile, updateEnvFile } from '../config';
import { addUserEntity, updateConfigFile, updateEnvFile } from '../config';
import {
APP_CONFIG_FILE,
APP_TSX_FILE,
AUTH_BACKEND_PLUGIN_FILE,
ENV_CONFIG_FILE,
USER_ENTITY_FILE,
} from '../files';
import { patch } from '../patch';
import { addSignInPageDiff, replaceSignInResolverDiff } from './diffs';
@@ -53,6 +55,46 @@ const validateCredentials = async (clientId: string, clientSecret: string) => {
}
};
const getConfig = (answers: Answers, useEnvForSecrets: boolean) => {
const { clientId, clientSecret, hasEnterprise, enterpriseInstanceUrl } =
answers;
return {
auth: {
providers: {
github: {
development: {
clientId: useEnvForSecrets ? '${AUTH_GITHUB_CLIENT_ID}' : clientId,
clientSecret: useEnvForSecrets
? '${AUTH_GITHUB_CLIENT_SECRET}'
: clientSecret,
...(hasEnterprise && {
enterpriseInstanceUrl: enterpriseInstanceUrl,
}),
},
},
},
},
catalog: {
locations: [
{
type: 'file',
target: '../../user-info.yaml',
rules: [{ allow: ['User'] }],
},
],
},
};
};
type Answers = {
username: string;
clientSecret: string;
clientId: string;
hasEnterprise: boolean;
enterpriseInstanceUrl?: string;
};
export const oauth = async (useEnvForSecrets: boolean) => {
Task.log(`
To add GitHub authentication, you must create an OAuth App from the GitHub developer settings: ${chalk.blue(
@@ -69,12 +111,19 @@ export const oauth = async (useEnvForSecrets: boolean) => {
'https://backstage.io/docs/auth/github/provider',
)}`);
const answers = await inquirer.prompt<{
clientSecret: string;
clientId: string;
hasEnterprise: boolean;
enterpriseInstanceUrl?: string;
}>([
const answers = await inquirer.prompt<Answers>([
{
type: 'input',
name: 'username',
message: 'What is your Github username?',
validate: async (input: string) => {
const response = await fetch(`https://api.github.com/users/${input}`);
if (!response.ok) {
return chalk.red('Unknown user. Please try again.');
}
return true;
},
},
{
type: 'input',
name: 'clientId',
@@ -101,32 +150,19 @@ export const oauth = async (useEnvForSecrets: boolean) => {
},
]);
const { clientId, clientSecret, hasEnterprise, enterpriseInstanceUrl } =
answers;
const { username, clientId, clientSecret } = answers;
await validateCredentials(clientId, clientSecret);
const auth = {
providers: {
github: {
development: {
clientId: useEnvForSecrets ? '${AUTH_GITHUB_CLIENT_ID}' : clientId,
clientSecret: useEnvForSecrets
? '${AUTH_GITHUB_CLIENT_SECRET}'
: clientSecret,
...(hasEnterprise && {
enterpriseInstanceUrl: enterpriseInstanceUrl,
}),
},
},
},
};
const config = getConfig(answers, useEnvForSecrets);
await updateConfigFile(APP_CONFIG_FILE, config);
await updateConfigFile(APP_CONFIG_FILE, { auth });
if (useEnvForSecrets) {
await updateEnvFile(ENV_CONFIG_FILE, clientId, clientSecret);
}
await addUserEntity(USER_ENTITY_FILE, username);
await patch(APP_TSX_FILE, addSignInPageDiff);
await patch(AUTH_BACKEND_PLUGIN_FILE, replaceSignInResolverDiff);
};
@@ -14,6 +14,7 @@
* limitations under the License.
*/
import chalk from 'chalk';
import inquirer from 'inquirer';
import { Task } from '../../../lib/tasks';
import { github } from './github';
@@ -42,4 +43,5 @@ export async function auth(): Promise<void> {
}
Task.log(`Done setting up ${provider}!`);
Task.log(`You can now start you app with ${chalk.inverse('yarn dev')}`);
}