cli: Expand admin command to setup basic authenticaton for gihub
Signed-off-by: Marcus Eide <eide@spotify.com>
This commit is contained in:
committed by
Philipp Hugenroth
parent
1322688118
commit
7af6c36adf
@@ -17,15 +17,61 @@
|
||||
import chalk from 'chalk';
|
||||
import inquirer from 'inquirer';
|
||||
import { Task } from '../../lib/tasks';
|
||||
import { github } from './github';
|
||||
import { updateConfigFile, updateEnvFile } from './file';
|
||||
|
||||
export async function command(): Promise<void> {
|
||||
const answers = await inquirer.prompt<{ github: boolean }>([
|
||||
const answers = await inquirer.prompt<{
|
||||
shouldSetupAuth: boolean;
|
||||
useEnvForSecrets?: boolean;
|
||||
provider?: string;
|
||||
}>([
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'github',
|
||||
message: chalk.blue('Do you want to set up GitHub Authentication?'),
|
||||
name: 'shouldSetupAuth',
|
||||
message: chalk.blue(
|
||||
'Do you want to set up Authentication for this project?',
|
||||
),
|
||||
},
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'useEnvForSecrets',
|
||||
message:
|
||||
'Would you like to store sensitive configuration details such as secrets as environment variables? (recommended)',
|
||||
when: ({ shouldSetupAuth }) => shouldSetupAuth,
|
||||
},
|
||||
{
|
||||
type: 'list',
|
||||
name: 'provider',
|
||||
message: 'Please select a provider:',
|
||||
choices: ['github'],
|
||||
when: ({ shouldSetupAuth }) => shouldSetupAuth,
|
||||
},
|
||||
]);
|
||||
|
||||
Task.log(answers.github ? 'Ok!' : 'Maybe next time');
|
||||
if (!answers.shouldSetupAuth) {
|
||||
// TODO(eide): Can we add a Task.warning() method?
|
||||
console.log(
|
||||
chalk.yellow(
|
||||
'If you change your mind, feel free to re-run this command.',
|
||||
),
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
switch (answers.provider) {
|
||||
case 'github': {
|
||||
const { useEnvForSecrets } = answers;
|
||||
const config = await github(useEnvForSecrets);
|
||||
await updateConfigFile(config);
|
||||
if (useEnvForSecrets) {
|
||||
await updateEnvFile(config);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new Error(`Provider ${answers.provider} not implemented yet.`);
|
||||
}
|
||||
|
||||
Task.log(`Done setting up ${answers.provider}!`);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs-extra';
|
||||
import yaml from 'yaml';
|
||||
import { findPaths } from '@backstage/cli-common';
|
||||
import { GithubAuthConfig } from './github';
|
||||
|
||||
/* eslint-disable-next-line no-restricted-syntax */
|
||||
const { targetRoot } = findPaths(__dirname);
|
||||
const APP_CONFIG_FILE = path.join(targetRoot, 'app-config.development.yaml');
|
||||
const ENV_CONFIG_FILE = path.join(targetRoot, '.env.development');
|
||||
|
||||
// export const readAppConfig = async (file: string) => {
|
||||
// return yaml.parse(await fs.readFile(file, 'utf8'));
|
||||
// };
|
||||
|
||||
export const updateConfigFile = async (config: GithubAuthConfig) => {
|
||||
return await fs.writeFile(
|
||||
APP_CONFIG_FILE,
|
||||
yaml.stringify(config, {
|
||||
indent: 2,
|
||||
}),
|
||||
'utf8',
|
||||
);
|
||||
};
|
||||
|
||||
export const updateEnvFile = async (config: GithubAuthConfig) => {
|
||||
const content = `
|
||||
AUTH_GITHUB_CLIENT_ID=${config.auth.providers.github.clientId}
|
||||
AUTH_GITHUB_CLIENT_SECRET=${config.auth.providers.github.clientId}`;
|
||||
|
||||
return await fs.writeFile(ENV_CONFIG_FILE, content, 'utf8');
|
||||
};
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import chalk from 'chalk';
|
||||
import inquirer from 'inquirer';
|
||||
import { Task } from '../../lib/tasks';
|
||||
|
||||
export type GithubAuthConfig = {
|
||||
auth: {
|
||||
providers: {
|
||||
github: {
|
||||
clientId: string;
|
||||
clientSecret: string;
|
||||
enterpriseInstanceUrl?: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
export const github = async (
|
||||
useEnvForSecrets?: boolean,
|
||||
): Promise<GithubAuthConfig> => {
|
||||
Task.log(`
|
||||
To add GitHub authentication, you must create an OAuth App from the GitHub developer settings: ${chalk.blue(
|
||||
'https://github.com/settings/developers',
|
||||
)}
|
||||
The Homepage URL should point to Backstage's frontend, while the Authorization callback URL will point to the auth backend.
|
||||
|
||||
You can find the full documentation page here: ${chalk.blue(
|
||||
'https://backstage.io/docs/auth/github/provider',
|
||||
)}
|
||||
`);
|
||||
|
||||
const answers = await inquirer.prompt<{
|
||||
clientSecret: string;
|
||||
clientId: string;
|
||||
hasGithubEnterprise: boolean;
|
||||
enterpriseInstanceUrl?: string;
|
||||
}>([
|
||||
{
|
||||
type: 'input',
|
||||
name: 'clientSecret',
|
||||
message: 'What is your Client Secret?',
|
||||
// TODO(eide): Is there another way to validate?
|
||||
// validate(input) {
|
||||
// if (/([a-f0-9]{40})/g.test(input)) {
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// throw Error('Please provide a valid client secret.');
|
||||
// },
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
name: 'clientId',
|
||||
message: 'What is your Client Id?',
|
||||
},
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'hasGithubEnterprise',
|
||||
message: 'Are you using Github Enterprise?',
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
name: 'enterpriseInstanceUrl',
|
||||
message: 'What is your URL for Github Enterprise?',
|
||||
when: ({ hasGithubEnterprise }) => hasGithubEnterprise,
|
||||
validate(input: string) {
|
||||
return Boolean(new URL(input));
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
return {
|
||||
auth: {
|
||||
providers: {
|
||||
github: {
|
||||
clientId: useEnvForSecrets
|
||||
? '${AUTH_GITHUB_CLIENT_ID}'
|
||||
: answers.clientId,
|
||||
clientSecret: useEnvForSecrets
|
||||
? '${AUTH_GITHUB_CLIENT_SECRET}'
|
||||
: answers.clientSecret,
|
||||
...(answers.hasGithubEnterprise && {
|
||||
enterpriseInstanceUrl: answers.enterpriseInstanceUrl,
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user