Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
24b6c22
commit b6fb192
Showing
22 changed files
with
1,043 additions
and
3 deletions.
There are no files selected for viewing
Validating CODEOWNERS rules …
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
# snyk apps -- Create and manage your Snyk Apps | ||
|
||
# Usage | ||
|
||
`snyk apps <COMMAND> [<OPTIONS>]` | ||
|
||
## Description | ||
|
||
Snyk Apps are integrations that extend the functionality of the Snyk platform. They provide you with an opportunity to mould your Snyk experience to suit your specific needs. | ||
|
||
[For more information see our user docs](https://docs.snyk.io/features/integrations/snyk-apps) | ||
|
||
## Commands | ||
|
||
**_Note: All `apps` commands are only accessible behind the `--experimental` flag and the behaviour can change at any time, without prior notice. You are kindly advised to use all the commands with caution_** | ||
|
||
### `create` | ||
|
||
Create a new Snyk App. | ||
|
||
## Options | ||
|
||
### `--interactive` | ||
|
||
Use the command in interactive mode. | ||
|
||
### `--org=<ORG_ID>` | ||
|
||
(Required for the `create` command) | ||
Specify the `<ORG_ID>` to create the Snyk App under. | ||
|
||
### `--name=<SNYK_APP_NAME>` | ||
|
||
(Required for the `create` command) | ||
The name of Snyk App that will be displayed to the user during the authentication flow. | ||
|
||
### `--redirect-uris=<REDIRECT_URIS>` | ||
|
||
(Required for the `create` command) | ||
A comma separated list of redirect URIs. This will form a list of allowed redirect URIs to call back after authentication. | ||
|
||
### `--scopes=<SCOPES>` | ||
|
||
(Required for the `create` command) | ||
A comma separated list of scopes required by your Snyk App. This will for a list of scopes that your app is allowed to request during authorization. | ||
|
||
## Examples | ||
|
||
### `Create Snyk App` | ||
|
||
\$ snyk apps create --experimental --org=48ebb069-472f-40f4-b5bf-d2d103bc02d4 --name='My Awesome App' --redirect-uris=https://example1.com,https://example2.com --scopes=apps:beta | ||
|
||
### `Create Snyk App Interactive Mode` | ||
|
||
\$ snyk apps create --experimental --interactive |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import * as Debug from 'debug'; | ||
import { | ||
EAppsURL, | ||
getAppsURL, | ||
handleCreateAppRes, | ||
handleV3Error, | ||
ICreateAppRequest, | ||
ICreateAppResponse, | ||
SNYK_APP_DEBUG, | ||
} from '../../../lib/apps'; | ||
import { makeRequestV3 } from '../../../lib/request/promise'; | ||
import { spinner } from '../../../lib/spinner'; | ||
|
||
const debug = Debug(SNYK_APP_DEBUG); | ||
|
||
/** | ||
* Function to process the app creation request and | ||
* handle any errors that are request error and print | ||
* in a formatted string. It throws is error is unknown | ||
* or cannot be handled. | ||
* @param {ICreateAppRequest} data to create the app | ||
* @returns {String} response formatted string | ||
*/ | ||
export async function createApp( | ||
data: ICreateAppRequest, | ||
): Promise<string | void> { | ||
debug('App data', data); | ||
const { | ||
orgId, | ||
snykAppName: name, | ||
snykAppRedirectUris: redirectUris, | ||
snykAppScopes: scopes, | ||
} = data; | ||
const payload = { | ||
method: 'POST', | ||
url: getAppsURL(EAppsURL.CREATE_APP, { orgId }), | ||
body: { | ||
name, | ||
redirectUris, | ||
scopes, | ||
}, | ||
qs: { | ||
version: '2021-08-11~experimental', | ||
}, | ||
}; | ||
|
||
try { | ||
await spinner('Creating your Snyk App'); | ||
const response = await makeRequestV3<ICreateAppResponse>(payload); | ||
debug(response); | ||
spinner.clearAll(); | ||
return handleCreateAppRes(response); | ||
} catch (error) { | ||
spinner.clearAll(); | ||
handleV3Error(error); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import * as Debug from 'debug'; | ||
import { MethodArgs } from '../../args'; | ||
import { processCommandArgs } from '../process-command-args'; | ||
import { | ||
EValidSubCommands, | ||
validAppsSubCommands, | ||
SNYK_APP_DEBUG, | ||
ICreateAppOptions, | ||
AppsErrorMessages, | ||
} from '../../../lib/apps'; | ||
|
||
import { createApp } from './create-app'; | ||
// import * as path from 'path'; | ||
import { | ||
createAppDataInteractive, | ||
createAppDataScriptable, | ||
} from '../../../lib/apps/create-app'; | ||
import help from '../help'; | ||
|
||
const debug = Debug(SNYK_APP_DEBUG); | ||
|
||
export default async function apps( | ||
...args0: MethodArgs | ||
): Promise<string | undefined | any> { | ||
debug('Snyk apps CLI called'); | ||
|
||
const { options, paths } = processCommandArgs<ICreateAppOptions>(...args0); | ||
debug(options, paths); | ||
|
||
const commandVerb1 = paths[0]; | ||
const validCommandVerb = | ||
commandVerb1 && validAppsSubCommands.includes(commandVerb1); | ||
if (!validCommandVerb) { | ||
// Display help md for apps | ||
debug(`Unknown subcommand: ${commandVerb1}`); | ||
return help('apps'); | ||
} | ||
// Check if experimental flag is being used | ||
if (!options.experimental) throw new Error(AppsErrorMessages.useExperimental); | ||
|
||
if (commandVerb1 === EValidSubCommands.CREATE) { | ||
const createAppData = options.interactive | ||
? await createAppDataInteractive() | ||
: createAppDataScriptable(options); | ||
return await createApp(createAppData); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import chalk from 'chalk'; | ||
|
||
export const SNYK_APP_NAME = 'snykAppName'; | ||
export const SNYK_APP_REDIRECT_URIS = 'snykAppRedirectUris'; | ||
export const SNYK_APP_SCOPES = 'snykAppScopes'; | ||
export const SNYK_APP_CLIENT_ID = 'snykAppClientId'; | ||
export const SNYK_APP_ORG_ID = 'snykAppOrgId'; | ||
export const SNYK_APP_DEBUG = 'snyk:apps'; | ||
|
||
export enum EValidSubCommands { | ||
CREATE = 'create', | ||
} | ||
|
||
export enum EAppsURL { | ||
CREATE_APP, | ||
} | ||
|
||
export const validAppsSubCommands = Object.values<string>(EValidSubCommands); | ||
|
||
export const AppsErrorMessages = { | ||
orgRequired: `Option '--org' is required! For interactive mode, please use '--interactive' or '-i' flag. For more information please run the help command 'snyk apps --help' or 'snyk apps -h'.`, | ||
nameRequired: `Option '--name' is required! For interactive mode, please use '--interactive' or '-i' flag. For more information please run the help command 'snyk apps --help' or 'snyk apps -h'.`, | ||
redirectUrisRequired: `Option '--redirect-uris' is required! For interactive mode, please use '--interactive' or '-i' flag. For more information please run the help command 'snyk apps --help' or 'snyk apps -h'.`, | ||
scopesRequired: `Option '--scopes' is required! For interactive mode, please use '--interactive' or '-i' flag. For more information please run the help command 'snyk apps --help' or 'snyk apps -h'.`, | ||
useExperimental: `\n${chalk.redBright( | ||
"All 'apps' commands are only accessible behind the '--experimental' flag.", | ||
)}\n | ||
The behaviour can change at any time, without prior notice. | ||
You are kindly advised to use all the commands with caution. | ||
${chalk.bold('Usage')} | ||
${chalk.italic('snyk apps <COMMAND> --experimental')}\n`, | ||
}; | ||
|
||
export const CreateAppPromptData = { | ||
SNYK_APP_NAME: { | ||
name: SNYK_APP_NAME, | ||
message: `Name of the Snyk App (visible to users when they install the Snyk App)?`, | ||
}, | ||
SNYK_APP_REDIRECT_URIS: { | ||
name: SNYK_APP_REDIRECT_URIS, | ||
message: `Your Snyk App's redirect URIs (comma seprated list. ${chalk.yellowBright( | ||
' Ex: https://example1.com,https://example2.com', | ||
)})?: `, | ||
}, | ||
SNYK_APP_SCOPES: { | ||
name: SNYK_APP_SCOPES, | ||
message: `Your Snyk App's permission scopes (comma separated list. ${chalk.yellowBright( | ||
' Ex: apps:beta', | ||
)})?: `, | ||
}, | ||
SNYK_APP_ORG_ID: { | ||
name: SNYK_APP_ORG_ID, | ||
message: | ||
'Please provide the org id under which you want to create your Snyk App: ', | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import { | ||
AppsErrorMessages, | ||
createAppPrompts, | ||
ICreateAppRequest, | ||
ICreateAppOptions, | ||
SNYK_APP_NAME, | ||
SNYK_APP_REDIRECT_URIS, | ||
SNYK_APP_SCOPES, | ||
SNYK_APP_ORG_ID, | ||
validateUUID, | ||
validateAllURL, | ||
} from '..'; | ||
import * as inquirer from '@snyk/inquirer'; | ||
import { ValidationError } from '../../errors'; | ||
|
||
/** | ||
* Validates and parsed the data required to create app. | ||
* Throws error if option is not provided or is invalid | ||
* @param {ICreateAppOptions} options required to create an app | ||
* @returns {ICreateAppRequest} data that is used to make the request | ||
*/ | ||
export function createAppDataScriptable( | ||
options: ICreateAppOptions, | ||
): ICreateAppRequest { | ||
if (!options.org) { | ||
throw new ValidationError(AppsErrorMessages.orgRequired); | ||
} else if (typeof validateUUID(options.org) === 'string') { | ||
// Combines to form "Invalid UUID provided for org id" | ||
throw new ValidationError(`${validateUUID(options.org)} for org id`); | ||
} else if (!options.name) { | ||
throw new ValidationError(AppsErrorMessages.nameRequired); | ||
} else if (!options['redirect-uris']) { | ||
throw new ValidationError(AppsErrorMessages.redirectUrisRequired); | ||
} else if (typeof validateAllURL(options['redirect-uris']) === 'string') { | ||
throw new ValidationError( | ||
validateAllURL(options['redirect-uris']) as string, | ||
); | ||
} else if (!options.scopes) { | ||
throw new ValidationError(AppsErrorMessages.scopesRequired); | ||
} else { | ||
return { | ||
orgId: options.org, | ||
snykAppName: options.name, | ||
snykAppRedirectUris: options['redirect-uris'] | ||
.replace(/\s+/g, '') | ||
.split(','), | ||
snykAppScopes: options.scopes.replace(/\s+/g, '').split(','), | ||
}; | ||
} | ||
} | ||
|
||
// Interactive format | ||
export async function createAppDataInteractive(): Promise<ICreateAppRequest> { | ||
// Proceed with interactive | ||
const answers = await inquirer.prompt(createAppPrompts); | ||
// Process answers | ||
const snykAppName = answers[SNYK_APP_NAME].trim() as string; | ||
const snykAppRedirectUris = answers[SNYK_APP_REDIRECT_URIS].replace( | ||
/\s+/g, | ||
'', | ||
).split(',') as string[]; | ||
const snykAppScopes = answers[SNYK_APP_SCOPES].replace(/\s+/g, '').split( | ||
',', | ||
) as string[]; | ||
const orgId = answers[SNYK_APP_ORG_ID].trim() as string; | ||
// POST: to create an app | ||
return { | ||
orgId, | ||
snykAppName, | ||
snykAppRedirectUris, | ||
snykAppScopes, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
export * from './constants'; | ||
export * from './prompts'; | ||
export * from './types'; | ||
export * from './v3-utils'; | ||
export * from './utils'; | ||
export * from './input-validator'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import * as uuid from 'uuid'; | ||
|
||
/** | ||
* | ||
* @param {String} input of space separated URL/URI passed by | ||
* user for redirect URIs | ||
* @returns { String | Boolean } complying with inquirer return values, the function | ||
* separates the string on space and validates each to see | ||
* if a valid URL/URI. Return a string if invalid and | ||
* boolean true if valid | ||
*/ | ||
export function validateAllURL(input: string): string | boolean { | ||
const trimmedInput = input.trim(); | ||
let errMessage = ''; | ||
for (const i of trimmedInput.split(',')) { | ||
if (typeof validURL(i) == 'string') | ||
errMessage = errMessage + `\n${validURL(i)}`; | ||
} | ||
|
||
if (errMessage) return errMessage; | ||
return true; | ||
} | ||
|
||
/** | ||
* Custom validation logic which takes in consideration | ||
* creation of Snyk Apps and thus allows localhost.com | ||
* as a valid URL. | ||
* @param {String} input of URI/URL value to validate using | ||
* regex | ||
* @returns {String | Boolean } string message is not valid | ||
* and boolean true if valid | ||
*/ | ||
export function validURL(input: string): boolean | string { | ||
try { | ||
new URL(input); | ||
return true; | ||
} catch (error) { | ||
return `${input} is not a valid URL`; | ||
} | ||
} | ||
|
||
/** | ||
* Function validates if a valid UUID (version of UUID not tacken into account) | ||
* @param {String} input UUID to be validated | ||
* @returns {String | Boolean } string message is not valid | ||
* and boolean true if valid | ||
*/ | ||
export function validateUUID(input: string): boolean | string { | ||
return uuid.validate(input) ? true : 'Invalid UUID provided'; | ||
} | ||
|
||
/** | ||
* @param {String} input | ||
* @returns {String | Boolean } string message is not valid | ||
* and boolean true if valid | ||
*/ | ||
export function validInput(input: string): string | boolean { | ||
if (!input) return 'Please enter something'; | ||
return true; | ||
} |
Oops, something went wrong.