diff --git a/README.md b/README.md index fc17d00..8375eb9 100644 --- a/README.md +++ b/README.md @@ -26,16 +26,18 @@ In your Github action workflow file (eg: `.github/workflows/build.yml`), insert appknox_access_token: ${{ secrets.APPKNOX_ACCESS_TOKEN }} file_path: app/build/outputs/apk/debug/app-debug.apk risk_threshold: HIGH + region: Global ``` ## Inputs -| Key | Value | -|-------------------------|------------------------------| -| `appknox_access_token` | Personal access token secret | -| `file_path` | File path to the mobile application binary to be uploaded | -| `risk_threshold` | Risk threshold value for which the CI should fail.

Accepted values: `CRITICAL, HIGH, MEDIUM & LOW`

Default: `LOW` | -| `sarif` | Enables SARIF report generation.

Accepted values: `Enable & Disable`

Default: `Disable` | +| Key | Value | +|------------------------|----------------------------------------------------------------------------------------------------------------------------------| +| `appknox_access_token` | Personal access token secret | +| `file_path` | File path to the mobile application binary to be uploaded | +| `risk_threshold` | Risk threshold value for which the CI should fail.

Accepted values: `CRITICAL, HIGH, MEDIUM & LOW`

Default: `LOW`| +| `sarif` | Enables SARIF report generation.

Accepted values: `Enable & Disable`

Default: `Disable` | +| `region` | The Appknox Regions to use. Can be a region like `"Global"`, `"Saudi"`. By default it is `"Global"` | --- @@ -67,6 +69,7 @@ jobs: appknox_access_token: ${{ secrets.APPKNOX_ACCESS_TOKEN }} file_path: app/build/outputs/apk/debug/app-debug.apk risk_threshold: MEDIUM + region: Global ``` ### Appknox Scan with Downloadable SARIF File _This example demonstrates how to run Appknox Scan to generate a SARIF report and download it as an artifact._ diff --git a/action.yml b/action.yml index b383661..77304f3 100644 --- a/action.yml +++ b/action.yml @@ -3,7 +3,7 @@ description: 'Ensure your mobile application are secure' author: 'Appknox' inputs: appknox_access_token: - description: 'Pesonal Access token on Appknox' + description: 'Personal Access Token on Appknox' required: true file_path: description: 'Path to the mobile application binary (apk/ipa)' @@ -19,6 +19,10 @@ inputs: description: 'Static scan timeout duration in minutes. If not provided defaults to 30 mins' required: false default: 30 + region: # New input parameter + description: 'The Appknox Regions to use. Can be a region like `"Global"`, `"Saudi"`. By default it is `"Global"`' + required: false + default: 'secure.appknox.com' # Default to the standard region branding: icon: 'shield' color: 'blue' diff --git a/src/appknox-inputs.ts b/src/appknox-inputs.ts index 7633503..2897713 100644 --- a/src/appknox-inputs.ts +++ b/src/appknox-inputs.ts @@ -20,8 +20,11 @@ export interface AppknoxInputs { * Enable SARIF format */ sarif: SarifOptions; + /** * Timeout duration in minutes for the static scan */ sastTimeout: number; + + region?: string; // Optional Region parameter } diff --git a/src/constants.ts b/src/constants.ts index decee60..80b9488 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -3,7 +3,8 @@ export enum Inputs { Path = 'file_path', RiskThreshold = 'risk_threshold', Sarif = 'sarif', - SastTimeout = 'sast_timeout' + SastTimeout = 'sast_timeout', + Region = 'region' // New input for Region } export enum SarifOptions { diff --git a/src/index.ts b/src/index.ts index fa9dab1..69fc987 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,17 +6,32 @@ async function run(): Promise { try { const inputs = getInputs(); core.exportVariable('APPKNOX_ACCESS_TOKEN', inputs.appknoxAccessToken); - await whoami(); - const fileID = await upload(inputs.filePath); - const sarif = inputs.sarif; - const sastTimeout=inputs.sastTimeout; - if (sarif == 'Enable'){ - await sarifReport(fileID); + + // Log the region value + core.info(`Region: ${inputs.region}`); + + // Set the Region if provided + if (inputs.region) { + core.exportVariable('APPKNOX_REGION', inputs.region); + } + + // Ensure Region is used in the whoami function or any other function that requires it + await whoami(inputs.region); + + // Upload file and get file ID + const fileID = await upload(inputs.filePath, inputs.region); + + // Generate SARIF report if enabled + if (inputs.sarif === 'Enable') { + await sarifReport(fileID, inputs.region); } - await cicheck(inputs.riskThreshold, fileID, sastTimeout); + + // Run CICheck with the specified risk threshold + await cicheck(inputs.riskThreshold, fileID, sastTimeout, inputs.region); + } catch (err: any) { core.setFailed(err.message); } } -run(); \ No newline at end of file +run(); diff --git a/src/input-helper.ts b/src/input-helper.ts index f4c563f..f1d611e 100644 --- a/src/input-helper.ts +++ b/src/input-helper.ts @@ -37,12 +37,15 @@ export function getInputs(): AppknoxInputs { )}` ); } + + const region = core.getInput(Inputs.Region) || 'secure.appknox.com'; // Default to the standard Region const inputs = { appknoxAccessToken: accessToken, filePath: path, riskThreshold: riskThreshold, sarif: sarifString, - sastTimeout: sastTimeout + sastTimeout: sastTimeout, + region: region } as AppknoxInputs; return inputs; diff --git a/src/tool.ts b/src/tool.ts index 24da0b5..07c8b4f 100644 --- a/src/tool.ts +++ b/src/tool.ts @@ -61,15 +61,30 @@ interface ExecOutput { async function execBinary( path: string, - args: Array + args: Array, + region?: string // Optional region parameter ): Promise { let output = ''; let err = ''; + const filteredEnv: { [key: string]: string } = {}; + for (const key in process.env) { + if (process.env[key] !== undefined) { + filteredEnv[key] = process.env[key] as string; + } + } + + // Add the Region to the environment if provided + if (region) { + filteredEnv['APPKNOX_REGION'] = region; + } + const options = { listeners: {}, - ignoreReturnCode: true + ignoreReturnCode: true, + env: filteredEnv // Use the filtered environment variables }; + options.listeners = { stdout: (data: Buffer) => { output += data.toString(); @@ -86,17 +101,17 @@ async function execBinary( }; } -export async function whoami(): Promise { +export async function whoami(region?: string): Promise { const toolPath = await getAppknoxToolPath(); - const combinedOutput = await execBinary(toolPath, ['whoami']); + const combinedOutput = await execBinary(toolPath, ['whoami'], region); if (combinedOutput.err.indexOf('Invalid token') > -1) { throw new Error('Invalid token'); } } -export async function upload(file_path: string): Promise { +export async function upload(file_path: string, region?: string): Promise { const toolPath = await getAppknoxToolPath(); - const combinedOutput = await execBinary(toolPath, ['upload', file_path]); + const combinedOutput = await execBinary(toolPath, ['upload', file_path],region); if (combinedOutput.code > 0) { const errArr = combinedOutput.err.split('\n').filter(_ => _); throw new Error(errArr[errArr.length - 1]); @@ -105,14 +120,15 @@ export async function upload(file_path: string): Promise { } export async function sarifReport( - fileID: number + fileID: number, + region?: string ): Promise { const toolPath = await getAppknoxToolPath(); const args = [ 'sarif', fileID.toString(), ]; - const combinedOutput = await execBinary(toolPath, args); + const combinedOutput = await execBinary(toolPath, args, region); if (combinedOutput.code > 0) { const errArr = combinedOutput.err.split('\n').filter(_ => _); const outArr = combinedOutput.output.split('\n').filter(_ => _); @@ -126,7 +142,8 @@ export async function sarifReport( export async function cicheck( riskThreshold: RiskThresholdOptions, fileID: number, - sastTimeout: number + sastTimeout: number, + region?: string ): Promise { const toolPath = await getAppknoxToolPath(); const args = [ @@ -137,7 +154,7 @@ export async function cicheck( '--timeout', sastTimeout.toString() ]; - const combinedOutput = await execBinary(toolPath, args); + const combinedOutput = await execBinary(toolPath, args, region); if (combinedOutput.code > 0) { const errArr = combinedOutput.err.split('\n').filter(_ => _); const outArr = combinedOutput.output.split('\n').filter(_ => _); @@ -145,4 +162,4 @@ export async function cicheck( const outMes = outArr[outArr.length - 1]; throw new Error(errMes + '. ' + outMes); } -} \ No newline at end of file +}