Skip to content

Commit

Permalink
Merge pull request #40 from AikidoSec/feat/advanced-post-comment-mode
Browse files Browse the repository at this point in the history
Add advanced post comment mode
  • Loading branch information
willem-delbare authored Mar 29, 2024
2 parents 02ed445 + e2dcd85 commit 6bb94f1
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 13 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
fail-on-iac-scan: false
minimum-severity: 'CRITICAL'
timeout-seconds: 180
post-scan-status-comment: false
post-scan-status-comment: 'off'
github-token: ${{ secrets.GITHUB_TOKEN }}
```
Expand Down
4 changes: 2 additions & 2 deletions action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ inputs:
required: false
default: "120"
post-scan-status-comment:
description: 'Let Aikido post a comment on the PR with a summary of the status, this comment will be updated for each scan.'
description: 'Let Aikido post a comment on the PR with a summary of the status, this comment will be updated for each scan. Can be one of "on", "off" or "only_if_new_findings". When setting this value to "only_if_new_findings" Aikido will only post a comment once new findings are found, and keep it updated afterwards.'
required: false
default: "false"
default: "off"
github-token:
description: 'A token that the action can use to post the status comment, this can be the default GITHUB_TOKEN from the environment with permissions to list and post comments, or a custom PAT.'
required: false
Expand Down
48 changes: 43 additions & 5 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,13 @@ const github = __importStar(__nccwpck_require__(5438));
const api_1 = __nccwpck_require__(8947);
const time_1 = __nccwpck_require__(5597);
const postMessage_1 = __nccwpck_require__(7965);
const transformPostScanStatusAsComment_1 = __nccwpck_require__(3654);
const STATUS_FAILED = 'FAILED';
const STATUS_SUCCEEDED = 'SUCCEEDED';
const STATUS_TIMED_OUT = 'TIMED_OUT';
const ALLOWED_POST_SCAN_STATUS_OPTIONS = ['on', 'off', 'only_if_new_findings'];
async function run() {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0;
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1;
try {
const secretKey = core.getInput('secret-key');
const fromSeverity = core.getInput('minimum-severity');
Expand All @@ -127,12 +129,18 @@ async function run() {
const failOnSastScan = core.getInput('fail-on-sast-scan');
const failOnIacScan = core.getInput('fail-on-iac-scan');
const timeoutInSeconds = parseTimeoutDuration(core.getInput('timeout-seconds'));
const postScanStatusAsComment = core.getInput('post-scan-status-comment');
let postScanStatusAsComment = core.getInput('post-scan-status-comment');
if (!['LOW', 'MEDIUM', 'HIGH', 'CRITICAL'].includes(fromSeverity.toUpperCase())) {
core.setOutput('output', STATUS_FAILED);
core.info(`Invalid property value for minimum-severity. Allowed values are: LOW, MEDIUM, HIGH, CRITICAL`);
return;
}
postScanStatusAsComment = (0, transformPostScanStatusAsComment_1.transformPostScanStatusAsComment)(postScanStatusAsComment);
if (!ALLOWED_POST_SCAN_STATUS_OPTIONS.includes(postScanStatusAsComment)) {
core.setOutput('ouput', STATUS_FAILED);
core.error(`Invalid property value for post-scan-status-comment. Allowed values are: ${ALLOWED_POST_SCAN_STATUS_OPTIONS.join(', ')}`);
return;
}
const startScanPayload = {
version: '1.0.5',
branch_name: ((_c = (_b = (_a = github.context.payload) === null || _a === void 0 ? void 0 : _a.pull_request) === null || _b === void 0 ? void 0 : _b.head) === null || _c === void 0 ? void 0 : _c.ref) || ((_d = github.context.payload) === null || _d === void 0 ? void 0 : _d.ref),
Expand All @@ -156,6 +164,12 @@ async function run() {
core.info(`starting a scan with secret key: "${redactedToken}"`);
}
else {
const isLikelyDependabotPr = ((_z = startScanPayload.branch_name) !== null && _z !== void 0 ? _z : '').starts_with('dependabot/');
if (isLikelyDependabotPr) {
core.info(`it looks like the action is running on a dependabot PR, this means that secret variables are not available in this context and thus we can not start a scan. Please see: https://github.blog/changelog/2021-02-19-github-actions-workflows-triggered-by-dependabot-prs-will-run-with-read-only-permissions/`);
core.setOutput('outcome', STATUS_SUCCEEDED);
return;
}
core.info(`secret key not set.`);
}
const scanId = await (0, api_1.startScan)(secretKey, startScanPayload);
Expand Down Expand Up @@ -187,9 +201,11 @@ async function run() {
if (result.diff_url) {
moreDetailsText = ` More details at ${result.diff_url}`;
}
if (postScanStatusAsComment === 'true' && !!((_z = result.outcome) === null || _z === void 0 ? void 0 : _z.human_readable_message)) {
const shouldPostComment = (postScanStatusAsComment === 'on' || postScanStatusAsComment === 'only_if_new_findings');
if (shouldPostComment && !!((_0 = result.outcome) === null || _0 === void 0 ? void 0 : _0.human_readable_message)) {
try {
await (0, postMessage_1.postScanStatusMessage)((_0 = result.outcome) === null || _0 === void 0 ? void 0 : _0.human_readable_message);
const options = { onlyIfNewFindings: postScanStatusAsComment === 'only_if_new_findings', hasNewFindings: !!result.gate_passed };
await (0, postMessage_1.postScanStatusMessage)((_1 = result.outcome) === null || _1 === void 0 ? void 0 : _1.human_readable_message, options);
}
catch (error) {
if (error instanceof Error) {
Expand Down Expand Up @@ -274,7 +290,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.postScanStatusMessage = void 0;
const core = __importStar(__nccwpck_require__(2186));
const github = __importStar(__nccwpck_require__(5438));
const postScanStatusMessage = async (messageBody) => {
const postScanStatusMessage = async (messageBody, options) => {
var _a, _b;
const githubToken = core.getInput('github-token');
if (!githubToken || githubToken === '') {
Expand Down Expand Up @@ -303,6 +319,9 @@ const postScanStatusMessage = async (messageBody) => {
intialBotComment = comment;
break;
}
// we should only post comment in case of new findings, but there are none: dont create comment
if (!intialBotComment && options.onlyIfNewFindings && options.hasNewFindings)
return;
// no initial comment, let's create one!
if (typeof intialBotComment === 'undefined') {
await octokit.rest.issues.createComment({
Expand Down Expand Up @@ -342,6 +361,25 @@ const getCurrentUnixTime = () => {
exports.getCurrentUnixTime = getCurrentUnixTime;


/***/ }),

/***/ 3654:
/***/ ((__unused_webpack_module, exports) => {

"use strict";

Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.transformPostScanStatusAsComment = void 0;
const transformPostScanStatusAsComment = (value) => {
if (value === 'true')
return 'on';
if (value === 'false')
return 'off';
return value;
};
exports.transformPostScanStatusAsComment = transformPostScanStatusAsComment;


/***/ }),

/***/ 7351:
Expand Down
2 changes: 1 addition & 1 deletion dist/index.js.map

Large diffs are not rendered by default.

18 changes: 15 additions & 3 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@ import * as github from '@actions/github';
import { getScanStatus, startScan } from './api';
import { getCurrentUnixTime, sleep } from './time';
import { postScanStatusMessage } from './postMessage';
import { transformPostScanStatusAsComment } from './transformers/transformPostScanStatusAsComment';

const STATUS_FAILED = 'FAILED';
const STATUS_SUCCEEDED = 'SUCCEEDED';
const STATUS_TIMED_OUT = 'TIMED_OUT';

const ALLOWED_POST_SCAN_STATUS_OPTIONS = ['on' , 'off' , 'only_if_new_findings'];

async function run(): Promise<void> {
try {
const secretKey: string = core.getInput('secret-key');
Expand All @@ -18,14 +21,21 @@ async function run(): Promise<void> {
const failOnSastScan: string = core.getInput('fail-on-sast-scan');
const failOnIacScan: string = core.getInput('fail-on-iac-scan');
const timeoutInSeconds = parseTimeoutDuration(core.getInput('timeout-seconds'));
const postScanStatusAsComment = core.getInput('post-scan-status-comment');
let postScanStatusAsComment = core.getInput('post-scan-status-comment');

if (!['LOW', 'MEDIUM', 'HIGH', 'CRITICAL'].includes(fromSeverity.toUpperCase())) {
core.setOutput('output', STATUS_FAILED);
core.info(`Invalid property value for minimum-severity. Allowed values are: LOW, MEDIUM, HIGH, CRITICAL`);
return;
}

postScanStatusAsComment = transformPostScanStatusAsComment(postScanStatusAsComment);
if (!ALLOWED_POST_SCAN_STATUS_OPTIONS.includes(postScanStatusAsComment)) {
core.setOutput('ouput', STATUS_FAILED);
core.error(`Invalid property value for post-scan-status-comment. Allowed values are: ${ALLOWED_POST_SCAN_STATUS_OPTIONS.join(', ')}`);
return;
}

const startScanPayload = {
version: '1.0.5',
branch_name: github.context.payload?.pull_request?.head?.ref || github.context.payload?.ref,
Expand Down Expand Up @@ -105,9 +115,11 @@ async function run(): Promise<void> {
moreDetailsText = ` More details at ${result.diff_url}`;
}

if (postScanStatusAsComment === 'true' && !!result.outcome?.human_readable_message) {
const shouldPostComment = (postScanStatusAsComment === 'on' || postScanStatusAsComment === 'only_if_new_findings');
if (shouldPostComment && !!result.outcome?.human_readable_message) {
try {
await postScanStatusMessage(result.outcome?.human_readable_message);
const options = { onlyIfNewFindings: postScanStatusAsComment === 'only_if_new_findings', hasNewFindings: !!result.gate_passed };
await postScanStatusMessage(result.outcome?.human_readable_message, options);
} catch (error) {
if (error instanceof Error) {
core.info(`unable to post scan status comment due to error: ${error.message}`);
Expand Down
7 changes: 6 additions & 1 deletion src/postMessage.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import * as core from '@actions/core';
import * as github from '@actions/github';

export const postScanStatusMessage = async (messageBody: string): Promise<void> => {
type TPostScanStatusMessageOptions = { onlyIfNewFindings: boolean, hasNewFindings: boolean }

export const postScanStatusMessage = async (messageBody: string, options: TPostScanStatusMessageOptions): Promise<void> => {
const githubToken = core.getInput('github-token');
if (!githubToken || githubToken === '') {
core.error('unable to post scan status: missing github-token input parameter');
Expand Down Expand Up @@ -36,6 +38,9 @@ export const postScanStatusMessage = async (messageBody: string): Promise<void>
break;
}

// we should only post comment in case of new findings, but there are none: dont create comment
if (!intialBotComment && options.onlyIfNewFindings && options.hasNewFindings) return;

// no initial comment, let's create one!
if (typeof intialBotComment === 'undefined') {
await octokit.rest.issues.createComment({
Expand Down
5 changes: 5 additions & 0 deletions src/transformers/transformPostScanStatusAsComment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const transformPostScanStatusAsComment = (value: string): string => {
if (value === 'true') return 'on';
if (value === 'false') return 'off';
return value;
}

0 comments on commit 6bb94f1

Please sign in to comment.