Skip to content

Commit 6bb94f1

Browse files
Merge pull request #40 from AikidoSec/feat/advanced-post-comment-mode
Add advanced post comment mode
2 parents 02ed445 + e2dcd85 commit 6bb94f1

File tree

7 files changed

+73
-13
lines changed

7 files changed

+73
-13
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ jobs:
3030
fail-on-iac-scan: false
3131
minimum-severity: 'CRITICAL'
3232
timeout-seconds: 180
33-
post-scan-status-comment: false
33+
post-scan-status-comment: 'off'
3434
github-token: ${{ secrets.GITHUB_TOKEN }}
3535
```
3636

action.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ inputs:
3030
required: false
3131
default: "120"
3232
post-scan-status-comment:
33-
description: 'Let Aikido post a comment on the PR with a summary of the status, this comment will be updated for each scan.'
33+
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.'
3434
required: false
35-
default: "false"
35+
default: "off"
3636
github-token:
3737
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.'
3838
required: false

dist/index.js

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -114,11 +114,13 @@ const github = __importStar(__nccwpck_require__(5438));
114114
const api_1 = __nccwpck_require__(8947);
115115
const time_1 = __nccwpck_require__(5597);
116116
const postMessage_1 = __nccwpck_require__(7965);
117+
const transformPostScanStatusAsComment_1 = __nccwpck_require__(3654);
117118
const STATUS_FAILED = 'FAILED';
118119
const STATUS_SUCCEEDED = 'SUCCEEDED';
119120
const STATUS_TIMED_OUT = 'TIMED_OUT';
121+
const ALLOWED_POST_SCAN_STATUS_OPTIONS = ['on', 'off', 'only_if_new_findings'];
120122
async function run() {
121-
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;
123+
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;
122124
try {
123125
const secretKey = core.getInput('secret-key');
124126
const fromSeverity = core.getInput('minimum-severity');
@@ -127,12 +129,18 @@ async function run() {
127129
const failOnSastScan = core.getInput('fail-on-sast-scan');
128130
const failOnIacScan = core.getInput('fail-on-iac-scan');
129131
const timeoutInSeconds = parseTimeoutDuration(core.getInput('timeout-seconds'));
130-
const postScanStatusAsComment = core.getInput('post-scan-status-comment');
132+
let postScanStatusAsComment = core.getInput('post-scan-status-comment');
131133
if (!['LOW', 'MEDIUM', 'HIGH', 'CRITICAL'].includes(fromSeverity.toUpperCase())) {
132134
core.setOutput('output', STATUS_FAILED);
133135
core.info(`Invalid property value for minimum-severity. Allowed values are: LOW, MEDIUM, HIGH, CRITICAL`);
134136
return;
135137
}
138+
postScanStatusAsComment = (0, transformPostScanStatusAsComment_1.transformPostScanStatusAsComment)(postScanStatusAsComment);
139+
if (!ALLOWED_POST_SCAN_STATUS_OPTIONS.includes(postScanStatusAsComment)) {
140+
core.setOutput('ouput', STATUS_FAILED);
141+
core.error(`Invalid property value for post-scan-status-comment. Allowed values are: ${ALLOWED_POST_SCAN_STATUS_OPTIONS.join(', ')}`);
142+
return;
143+
}
136144
const startScanPayload = {
137145
version: '1.0.5',
138146
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),
@@ -156,6 +164,12 @@ async function run() {
156164
core.info(`starting a scan with secret key: "${redactedToken}"`);
157165
}
158166
else {
167+
const isLikelyDependabotPr = ((_z = startScanPayload.branch_name) !== null && _z !== void 0 ? _z : '').starts_with('dependabot/');
168+
if (isLikelyDependabotPr) {
169+
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/`);
170+
core.setOutput('outcome', STATUS_SUCCEEDED);
171+
return;
172+
}
159173
core.info(`secret key not set.`);
160174
}
161175
const scanId = await (0, api_1.startScan)(secretKey, startScanPayload);
@@ -187,9 +201,11 @@ async function run() {
187201
if (result.diff_url) {
188202
moreDetailsText = ` More details at ${result.diff_url}`;
189203
}
190-
if (postScanStatusAsComment === 'true' && !!((_z = result.outcome) === null || _z === void 0 ? void 0 : _z.human_readable_message)) {
204+
const shouldPostComment = (postScanStatusAsComment === 'on' || postScanStatusAsComment === 'only_if_new_findings');
205+
if (shouldPostComment && !!((_0 = result.outcome) === null || _0 === void 0 ? void 0 : _0.human_readable_message)) {
191206
try {
192-
await (0, postMessage_1.postScanStatusMessage)((_0 = result.outcome) === null || _0 === void 0 ? void 0 : _0.human_readable_message);
207+
const options = { onlyIfNewFindings: postScanStatusAsComment === 'only_if_new_findings', hasNewFindings: !!result.gate_passed };
208+
await (0, postMessage_1.postScanStatusMessage)((_1 = result.outcome) === null || _1 === void 0 ? void 0 : _1.human_readable_message, options);
193209
}
194210
catch (error) {
195211
if (error instanceof Error) {
@@ -274,7 +290,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
274290
exports.postScanStatusMessage = void 0;
275291
const core = __importStar(__nccwpck_require__(2186));
276292
const github = __importStar(__nccwpck_require__(5438));
277-
const postScanStatusMessage = async (messageBody) => {
293+
const postScanStatusMessage = async (messageBody, options) => {
278294
var _a, _b;
279295
const githubToken = core.getInput('github-token');
280296
if (!githubToken || githubToken === '') {
@@ -303,6 +319,9 @@ const postScanStatusMessage = async (messageBody) => {
303319
intialBotComment = comment;
304320
break;
305321
}
322+
// we should only post comment in case of new findings, but there are none: dont create comment
323+
if (!intialBotComment && options.onlyIfNewFindings && options.hasNewFindings)
324+
return;
306325
// no initial comment, let's create one!
307326
if (typeof intialBotComment === 'undefined') {
308327
await octokit.rest.issues.createComment({
@@ -342,6 +361,25 @@ const getCurrentUnixTime = () => {
342361
exports.getCurrentUnixTime = getCurrentUnixTime;
343362

344363

364+
/***/ }),
365+
366+
/***/ 3654:
367+
/***/ ((__unused_webpack_module, exports) => {
368+
369+
"use strict";
370+
371+
Object.defineProperty(exports, "__esModule", ({ value: true }));
372+
exports.transformPostScanStatusAsComment = void 0;
373+
const transformPostScanStatusAsComment = (value) => {
374+
if (value === 'true')
375+
return 'on';
376+
if (value === 'false')
377+
return 'off';
378+
return value;
379+
};
380+
exports.transformPostScanStatusAsComment = transformPostScanStatusAsComment;
381+
382+
345383
/***/ }),
346384

347385
/***/ 7351:

dist/index.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/main.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@ import * as github from '@actions/github';
44
import { getScanStatus, startScan } from './api';
55
import { getCurrentUnixTime, sleep } from './time';
66
import { postScanStatusMessage } from './postMessage';
7+
import { transformPostScanStatusAsComment } from './transformers/transformPostScanStatusAsComment';
78

89
const STATUS_FAILED = 'FAILED';
910
const STATUS_SUCCEEDED = 'SUCCEEDED';
1011
const STATUS_TIMED_OUT = 'TIMED_OUT';
1112

13+
const ALLOWED_POST_SCAN_STATUS_OPTIONS = ['on' , 'off' , 'only_if_new_findings'];
14+
1215
async function run(): Promise<void> {
1316
try {
1417
const secretKey: string = core.getInput('secret-key');
@@ -18,14 +21,21 @@ async function run(): Promise<void> {
1821
const failOnSastScan: string = core.getInput('fail-on-sast-scan');
1922
const failOnIacScan: string = core.getInput('fail-on-iac-scan');
2023
const timeoutInSeconds = parseTimeoutDuration(core.getInput('timeout-seconds'));
21-
const postScanStatusAsComment = core.getInput('post-scan-status-comment');
24+
let postScanStatusAsComment = core.getInput('post-scan-status-comment');
2225

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

32+
postScanStatusAsComment = transformPostScanStatusAsComment(postScanStatusAsComment);
33+
if (!ALLOWED_POST_SCAN_STATUS_OPTIONS.includes(postScanStatusAsComment)) {
34+
core.setOutput('ouput', STATUS_FAILED);
35+
core.error(`Invalid property value for post-scan-status-comment. Allowed values are: ${ALLOWED_POST_SCAN_STATUS_OPTIONS.join(', ')}`);
36+
return;
37+
}
38+
2939
const startScanPayload = {
3040
version: '1.0.5',
3141
branch_name: github.context.payload?.pull_request?.head?.ref || github.context.payload?.ref,
@@ -105,9 +115,11 @@ async function run(): Promise<void> {
105115
moreDetailsText = ` More details at ${result.diff_url}`;
106116
}
107117

108-
if (postScanStatusAsComment === 'true' && !!result.outcome?.human_readable_message) {
118+
const shouldPostComment = (postScanStatusAsComment === 'on' || postScanStatusAsComment === 'only_if_new_findings');
119+
if (shouldPostComment && !!result.outcome?.human_readable_message) {
109120
try {
110-
await postScanStatusMessage(result.outcome?.human_readable_message);
121+
const options = { onlyIfNewFindings: postScanStatusAsComment === 'only_if_new_findings', hasNewFindings: !!result.gate_passed };
122+
await postScanStatusMessage(result.outcome?.human_readable_message, options);
111123
} catch (error) {
112124
if (error instanceof Error) {
113125
core.info(`unable to post scan status comment due to error: ${error.message}`);

src/postMessage.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import * as core from '@actions/core';
22
import * as github from '@actions/github';
33

4-
export const postScanStatusMessage = async (messageBody: string): Promise<void> => {
4+
type TPostScanStatusMessageOptions = { onlyIfNewFindings: boolean, hasNewFindings: boolean }
5+
6+
export const postScanStatusMessage = async (messageBody: string, options: TPostScanStatusMessageOptions): Promise<void> => {
57
const githubToken = core.getInput('github-token');
68
if (!githubToken || githubToken === '') {
79
core.error('unable to post scan status: missing github-token input parameter');
@@ -36,6 +38,9 @@ export const postScanStatusMessage = async (messageBody: string): Promise<void>
3638
break;
3739
}
3840

41+
// we should only post comment in case of new findings, but there are none: dont create comment
42+
if (!intialBotComment && options.onlyIfNewFindings && options.hasNewFindings) return;
43+
3944
// no initial comment, let's create one!
4045
if (typeof intialBotComment === 'undefined') {
4146
await octokit.rest.issues.createComment({
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export const transformPostScanStatusAsComment = (value: string): string => {
2+
if (value === 'true') return 'on';
3+
if (value === 'false') return 'off';
4+
return value;
5+
}

0 commit comments

Comments
 (0)