Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: deprecate request lib #189

Open
wants to merge 17 commits into
base: staging
Choose a base branch
from
219 changes: 3 additions & 216 deletions dist/index.js

Large diffs are not rendered by default.

198 changes: 124 additions & 74 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
const core = require('@actions/core')
const { exec } = require('@actions/exec')
const request = require('request-promise-native')
const chalk = require('chalk')
chalk.level = 1 // Chalk doesn't detect that GitHub Actions supports color. This forces chalk to use color.
import * as core from '@actions/core'
import { exec } from '@actions/exec'
import { styleText } from 'node:util'

const divvycloudLoginUrl = 'https://byu.customer.divvycloud.com/v2/public/user/login'
const divvycloudScanUrl = 'https://byu.customer.divvycloud.com/v3/iac/scan'

async function jsonFromPlan (workDir, planFileName) {
const exitCode = await exec('which tofu', undefined, { silent: true, ignoreReturnCode: true })
const exitCode = await exec('which tofu', undefined, {
silent: true,
ignoreReturnCode: true
})
const hasTofu = exitCode === 0
const command = hasTofu ? 'tofu' : 'terraform'

Expand All @@ -34,7 +35,9 @@ async function jsonFromPlan (workDir, planFileName) {
core.debug('** start of output **')
core.debug(output)
core.debug('** end of output **')
throw Error('There was an error while parsing your Terraform plan. The output from "terraform show -json" didn\'t match with /{.*}/ as expected.')
throw new Error(
'There was an error while parsing your Terraform plan. The output from "terraform show -json" didn\'t match with /{.*}/ as expected.'
)
}

core.debug('** matched json **')
Expand All @@ -45,99 +48,134 @@ async function jsonFromPlan (workDir, planFileName) {
}

async function getAuthToken (username, password) {
try {
const { session_id: token } = await request({
method: 'POST',
uri: divvycloudLoginUrl,
body: { username, password },
json: true
})
core.setSecret(token)
return token
} catch (e) {
throw Error('An error occurred while getting a token for DivvyCloud. Did you provide a valid username/password?')
const data = { username, password }
const response = await fetch(divvycloudLoginUrl, {
method: 'POST',
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json;charset=UTF-8'
}
})

if (!response.ok) {
const message = `An error occurred while getting a token for DivvyCloud: ${response.status}`
core.debug(`Response Object: ${JSON.stringify(response)}`)
throw new Error(message)
}
const { session_id: token } = await response.json()
core.setSecret(token)
return token
}

async function getScan (authToken, author, scanName, json) {
const { statusCode, body } = await request({
const data = {
scan_name: scanName,
author_name: author,
scan_template: json,
config_name: 'Github Scan',
iac_provider: 'terraform'
}
const response = await fetch(divvycloudScanUrl, {
method: 'POST',
uri: divvycloudScanUrl,
body: {
scan_name: scanName,
author_name: author,
scan_template: json,
config_name: 'Github Scan',
iac_provider: 'terraform'
},
json: true,
resolveWithFullResponse: true,
simple: false,
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json;charset=UTF-8',
Accept: 'application/json',
'X-Auth-Token': authToken
}
})
return { statusCode, body }

// Normal Responses: 200, 202, 406
const status = response.status
if (![200, 202, 406].includes(status)) {
const message = `[DivvyCloud]: Scan returned an unexpected response. Please contact the DivvyCloud Admins. Response: ${status}`
core.debug(`DivvyCloud Response: ${JSON.stringify(await response.json(), null, 2)}`)
throw new Error(message)
}
const scanResult = await response.json()
return { status, scanResult }
}

function printSummary (scanResult) {
core.debug('Printing summary')

core.info(chalk.bold.underline('\nSummary:'))
core.info(styleText(['bold', 'underline'], '\nSummary:'))

core.debug('Printing passed insights')
if (scanResult.details.passed_insights.length > 0) {
core.info(chalk.bold.green(`Passed Insights (${scanResult.details.passed_insights.length})`))
core.info(
styleText(
['bold', 'green'],
`Passed Insights (${scanResult.details.passed_insights.length})`
)
)
} else {
core.info('Passed Insights (0)')
}
scanResult.details.passed_insights.forEach(insight => {
core.startGroup(chalk.bold.green(insight.name))
core.info(chalk.italic.greenBright(insight.description))
core.info(chalk.green(`Severity: ${insight.severity}`))
core.info(chalk.greenBright(insight.notes))
scanResult.details.passed_insights.forEach((insight) => {
core.startGroup(styleText(['bold', 'green'], insight.name))
core.info(styleText(['italic', 'greenBright'], insight.description))
core.info(styleText('green', `Severity: ${insight.severity}`))
core.info(styleText('greenBright', insight.notes))
core.endGroup()
insight.success.forEach(resourceId => {
const { address: terraformId, name } = scanResult.resource_mapping[resourceId]
core.info(` • ${chalk.greenBright(terraformId || `name = ${name}`)}`)
insight.success.forEach((resourceId) => {
const { address: terraformId, name } =
scanResult.resource_mapping[resourceId]
core.info(
` • ${styleText('greenBright', terraformId || `name = ${name}`)}`
)
})
})

core.debug('Printing warned insights')
if (scanResult.details.warned_insights.length > 0) {
core.info(chalk.bold.yellow(`Warned Insights (${scanResult.details.warned_insights.length})`))
core.info(
styleText(
['bold', 'yellow'],
`Warned Insights (${scanResult.details.warned_insights.length})`
)
)
} else {
core.info('Warned Insights (0)')
}
scanResult.details.warned_insights.forEach(insight => {
core.startGroup(chalk.bold.yellow(insight.name))
core.info(chalk.italic.yellowBright(insight.description))
core.info(chalk.yellow(`Severity: ${insight.severity}`))
core.info(chalk.yellowBright(insight.notes))
scanResult.details.warned_insights.forEach((insight) => {
core.startGroup(styleText(['bold', 'yellow'], insight.name))
core.info(styleText(['italic', 'yellowBright'], insight.description))
core.info(styleText('yellow', `Severity: ${insight.severity}`))
core.info(styleText('yellowBright', insight.notes))
core.endGroup()
insight.warning.forEach(resourceId => {
const { address: terraformId, name } = scanResult.resource_mapping[resourceId]
core.info(` • ${chalk.yellowBright(terraformId || `name = ${name}`)}`)
insight.warning.forEach((resourceId) => {
const { address: terraformId, name } =
scanResult.resource_mapping[resourceId]
core.info(
` • ${styleText('yellowBright', terraformId || `name = ${name}`)}`
)
})
})

core.debug('Printing failed insights')
if (scanResult.details.failed_insights.length > 0) {
core.info(chalk.bold.red(`Failed Insights (${scanResult.details.failed_insights.length})`))
core.info(
styleText(
['bold', 'red'],
`Failed Insights (${scanResult.details.failed_insights.length})`
)
)
} else {
core.info('Failed Insights (0)')
}
scanResult.details.failed_insights.forEach(insight => {
core.startGroup(chalk.bold.red(insight.name))
core.info(chalk.italic.redBright(insight.description))
core.info(chalk.red(`Severity: ${insight.severity}`))
core.info(chalk.redBright(insight.notes))
scanResult.details.failed_insights.forEach((insight) => {
core.startGroup(styleText(['bold', 'red'], insight.name))
core.info(styleText(['italic', 'redBright'], insight.description))
core.info(styleText('red', `Severity: ${insight.severity}`))
core.info(styleText('redBright', insight.notes))
core.endGroup()
insight.failure.forEach(resourceId => {
const { address: terraformId, name } = scanResult.resource_mapping[resourceId]
core.info(` • ${chalk.redBright(terraformId || `name = ${name}`)}`)
insight.failure.forEach((resourceId) => {
const { address: terraformId, name } =
scanResult.resource_mapping[resourceId]
core.info(
` • ${styleText('redBright', terraformId || `name = ${name}`)}`
)
})
})
}
Expand All @@ -146,43 +184,55 @@ function printSummary (scanResult) {
async function run () {
try {
// Workflow Inputs
const planFileName = core.getInput('terraform-plan-file', { required: true })
const planFileName = core.getInput('terraform-plan-file', {
required: true
})
const workDir = core.getInput('working-directory', { required: true })
const username = core.getInput('divvycloud-username', { required: true })
const password = core.getInput('divvycloud-password', { required: true })

// Environment variables
const scanName = process.env.GITHUB_REPOSITORY + '.' + process.env.GITHUB_RUN_ID + '.' + process.env.GITHUB_RUN_NUMBER
const scanName =
process.env.GITHUB_REPOSITORY +
'.' +
process.env.GITHUB_RUN_ID +
'.' +
process.env.GITHUB_RUN_NUMBER
const author = process.env.GITHUB_ACTOR

// Get Terraform plan
const json = await jsonFromPlan(workDir, planFileName)

// DivvyCloud Auth token
const authToken = await getAuthToken(username, password)
const authToken = await getAuthToken(username, password).catch((error) => {
core.error(error.message)
})

// Send JSON plan to DivvyCloud
const { statusCode, body: scanResult } = await getScan(authToken, author, scanName, json)
const { status, scanResult } = await getScan(authToken, author, scanName, json).catch((error) => {
core.error(error.message)
})

core.info(`Status Code: ${statusCode}`)
core.info(`Status Code: ${status}`)
core.startGroup('Full Scan Results')
core.info(JSON.stringify(scanResult, null, 2))
core.endGroup()

const normalStatusCodesFromScan = [200, 202, 406]
if (!normalStatusCodesFromScan.includes(statusCode)) {
core.error('[DivvyCloud]: Scan returned an unexpected response. Please contact the DivvyCloud Admins.')
return
}

printSummary(scanResult)

core.info('')

switch (statusCode) {
case 200: core.info('[DivvyCloud]: Scan completed. All checks have passed!'); break
case 202: core.warning('[DivvyCloud]: Scan completed, but with warnings.'); break
case 406: core.setFailed('[DivvyCloud]: Scan completed, but one or more checks failed. Please check the log for more information.')
switch (status) {
case 200:
core.info('[DivvyCloud]: Scan completed. All checks have passed!')
break
case 202:
core.warning('[DivvyCloud]: Scan completed, but with warnings.')
break
case 406:
core.setFailed(
'[DivvyCloud]: Scan completed, but one or more checks failed. Please check the log for more information.'
)
}
} catch (error) {
core.setFailed(error)
Expand Down
Loading
Loading