-
Notifications
You must be signed in to change notification settings - Fork 1
/
app.js
150 lines (130 loc) · 4.38 KB
/
app.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
//import dependencies
import fs from "fs";
import yaml from "js-yaml";
import readline from "readline";
import path from "path";
import chalk from "chalk";
//import modules
import { extractCommands } from "./src/modules/extractCommands.js";
import { extractEnv } from "./src/modules/extractEnv.js";
import { extractUses } from "./src/modules/extractUses.js";
import { checkKeysPresence } from "./src/modules/extractKeys.js";
import { downloadWorkflowsFromRepo } from "./src/modules/downloadWorkflowsFromRepo.js";
import { evaluateWorkflowCommands } from "./src/modules/evaluateWorkflowCommands.js";
import { cleanupWorkflows } from "./src/modules/cleanupWorkflows.js";
// //import models
import { commands } from "./src/models/Commands.js";
// import { commands } from "./src/modules/extractCommands.js";//new command array
import { environments } from "./src/models/Environments.js";
//import { workerData } from "worker_threads";
import { uses } from "./src/models/Uses.js";
//action file src
const directoryPath = "./src/workflows/";
//Welcome
console.log(
chalk.black.bgGreenBright("Welcome to Github Actions Security Scanner!")
);
console.log(
chalk.yellow.italic(
"A tool to scan Github Actions (.yml) files for malicious content"
)
);
console.log();
//check if /src/workflows exists
if (!fs.existsSync(directoryPath)) {
//if not, create dir
console.log("/src/workflows does not exist, creating directory.");
fs.mkdirSync(directoryPath);
console.log(`${directoryPath} created successfully.`);
console.log();
} else {
//already exists then proceed
console.log(`${directoryPath} already exists. Proceeding...`);
console.log();
}
//input github link
const input = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
const promptForGitHubLink = async () => {
return new Promise((resolve) => {
input.question("Enter the Github repository link: ", (githubLink) => {
resolve(githubLink);
});
});
};
// Define an asynchronous function to handle the entire process
const main = async () => {
let validLink = false;
let githubLink = "";
const outputDirectory = "./src/workflows";
//while function to loop until valid github link is received
while (!validLink) {
githubLink = await promptForGitHubLink();
validLink = await downloadWorkflowsFromRepo(githubLink, outputDirectory);
if (!validLink) {
console.log("Invalid GitHub link format or workflow doesn't exist");
validLink=false;
}
else{
validLink=true;
}
console.log();
}
input.close();
fs.readdir(directoryPath, (err, files) => {
if (err) {
console.error("Error reading directory: ", err);
console.log();
return;
}
files.forEach((file) => {
const filePath = path.join(directoryPath, file);
const fileContent = fs.readFileSync(filePath, "utf-8");
try {
const actionFile = yaml.load(fileContent);
const missingKeys = checkKeysPresence(actionFile);
// console.log(missingKeys.length)
if (missingKeys.length === 5) {
console.log();
console.log(
`${chalk.yellow(file)}: ` +
"0 Keys Matched: The YAML file does not appear to be a valid Github Actions file."
);
} else {
console.log();
console.log(
`${chalk.yellow(file)}: ` +
(5 - missingKeys.length) +
"/5 Keys Matched: The file appears to be a valid Github Actions workflow."
);
extractEnv(actionFile);
console.log(
`${chalk.yellow(file)}: Host system is running: ` +
chalk.yellow(environments)
);
commands.splice(0, commands.length);
// console.log(commands)
extractCommands(actionFile);
console.log(
`${chalk.yellow(file)}: Found ${chalk.yellow(
commands.length
)} commands/scripts`
);
extractUses(actionFile);
console.log();
console.log(chalk.yellow("Linked file(s): "+uses.length+"\n"+uses));
console.log();
//console.log(commands);
evaluateWorkflowCommands(commands, file);
//delete all files in /src/workflow after evaluation
}
} catch (error) {
console.log(`${file}: Error processing ${file}: ` + error);
}
});
cleanupWorkflows("src/workflows");
});
};
main();