@kinosec/cli 0.10.1 → 0.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +122 -64
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -8048,12 +8048,8 @@ import { join as join2, dirname as dirname2 } from "path";
|
|
|
8048
8048
|
// src/lib/config.ts
|
|
8049
8049
|
import { existsSync, mkdirSync, readFileSync, writeFileSync, openSync, writeSync, closeSync, unlinkSync, constants } from "fs";
|
|
8050
8050
|
import { join, dirname } from "path";
|
|
8051
|
-
import { homedir
|
|
8051
|
+
import { homedir } from "os";
|
|
8052
8052
|
function getConfigDir() {
|
|
8053
|
-
const p = platform();
|
|
8054
|
-
if (p === "win32") {
|
|
8055
|
-
return join(process.env.APPDATA ?? join(homedir(), "AppData", "Roaming"), "kinosec");
|
|
8056
|
-
}
|
|
8057
8053
|
const xdg = process.env.XDG_CONFIG_HOME;
|
|
8058
8054
|
if (xdg) return join(xdg, "kinosec");
|
|
8059
8055
|
return join(homedir(), ".config", "kinosec");
|
|
@@ -8074,7 +8070,7 @@ function readJsonFile(path) {
|
|
|
8074
8070
|
function writeJsonFile(path, data, restrictPermissions = false) {
|
|
8075
8071
|
ensureDir(dirname(path));
|
|
8076
8072
|
const content = JSON.stringify(data, null, 2) + "\n";
|
|
8077
|
-
if (restrictPermissions
|
|
8073
|
+
if (restrictPermissions) {
|
|
8078
8074
|
const fd = openSync(path, constants.O_WRONLY | constants.O_CREAT | constants.O_TRUNC, 384);
|
|
8079
8075
|
writeSync(fd, content);
|
|
8080
8076
|
closeSync(fd);
|
|
@@ -12019,10 +12015,9 @@ function extractPhase(entries) {
|
|
|
12019
12015
|
return null;
|
|
12020
12016
|
}
|
|
12021
12017
|
function printActivityLines(entries, tty3) {
|
|
12022
|
-
for (
|
|
12023
|
-
const
|
|
12024
|
-
const
|
|
12025
|
-
const text = tty3 ? isLastEntry ? import_picocolors5.default.green(entries[i]) : import_picocolors5.default.dim(import_picocolors5.default.green(entries[i])) : entries[i];
|
|
12018
|
+
for (const entry of entries) {
|
|
12019
|
+
const prompt = tty3 ? import_picocolors5.default.dim(import_picocolors5.default.green(">")) : ">";
|
|
12020
|
+
const text = tty3 ? import_picocolors5.default.dim(import_picocolors5.default.green(entry)) : entry;
|
|
12026
12021
|
console.log(`${prompt} ${text}`);
|
|
12027
12022
|
}
|
|
12028
12023
|
}
|
|
@@ -12049,7 +12044,7 @@ async function watchPentest(client, profileId, options) {
|
|
|
12049
12044
|
spinner.text = import_picocolors5.default.green(currentPhase ? `[${currentPhase}] ${buzz}...` : `${buzz}...`);
|
|
12050
12045
|
}
|
|
12051
12046
|
if (!useJson && tty3) {
|
|
12052
|
-
spinner = ora({ text: "Fetching pentest status...", color: "green", isEnabled: true }).start();
|
|
12047
|
+
spinner = ora({ text: "Fetching pentest status...", color: "green", isEnabled: true, discardStdin: false }).start();
|
|
12053
12048
|
cycler = createBuzzwordCycler(SCAN_EXECUTION_PHRASES, 2500, () => {
|
|
12054
12049
|
updateSpinnerText();
|
|
12055
12050
|
});
|
|
@@ -12064,71 +12059,134 @@ async function watchPentest(client, profileId, options) {
|
|
|
12064
12059
|
process.exit(0);
|
|
12065
12060
|
});
|
|
12066
12061
|
const showFullDetails = await resolveShowFullDetails(client);
|
|
12067
|
-
|
|
12068
|
-
|
|
12069
|
-
|
|
12070
|
-
|
|
12071
|
-
|
|
12072
|
-
|
|
12073
|
-
|
|
12074
|
-
|
|
12075
|
-
|
|
12076
|
-
|
|
12077
|
-
|
|
12078
|
-
|
|
12079
|
-
|
|
12080
|
-
|
|
12081
|
-
|
|
12082
|
-
|
|
12083
|
-
|
|
12084
|
-
|
|
12085
|
-
|
|
12086
|
-
|
|
12087
|
-
|
|
12088
|
-
|
|
12089
|
-
|
|
12090
|
-
|
|
12091
|
-
|
|
12062
|
+
let consecutiveErrors = 0;
|
|
12063
|
+
const MAX_CONSECUTIVE_ERRORS = 2;
|
|
12064
|
+
let deferredExitCode = null;
|
|
12065
|
+
try {
|
|
12066
|
+
while (true) {
|
|
12067
|
+
let scanDetail;
|
|
12068
|
+
try {
|
|
12069
|
+
scanDetail = await client.scans.get(profileId);
|
|
12070
|
+
consecutiveErrors = 0;
|
|
12071
|
+
} catch (error2) {
|
|
12072
|
+
if (error2 instanceof ApiError) {
|
|
12073
|
+
if (error2.status === 401 || error2.status === 403) {
|
|
12074
|
+
throw error2;
|
|
12075
|
+
}
|
|
12076
|
+
if (error2.status === 404) {
|
|
12077
|
+
if (!useJson) {
|
|
12078
|
+
const icon2 = tty3 ? import_picocolors5.default.yellow(sym.warn) : sym.warn;
|
|
12079
|
+
console.log(`
|
|
12080
|
+
${icon2} Pentest is no longer available.`);
|
|
12081
|
+
console.log(` Check status: kinosec pentest get ${profileId}`);
|
|
12082
|
+
}
|
|
12083
|
+
break;
|
|
12084
|
+
}
|
|
12085
|
+
}
|
|
12086
|
+
consecutiveErrors++;
|
|
12087
|
+
if (consecutiveErrors >= MAX_CONSECUTIVE_ERRORS) {
|
|
12088
|
+
if (!useJson) {
|
|
12089
|
+
const icon2 = tty3 ? import_picocolors5.default.red(sym.fail) : sym.fail;
|
|
12090
|
+
console.log(`
|
|
12091
|
+
${icon2} Lost connection to pentest.`);
|
|
12092
|
+
console.log(` Check status: kinosec pentest get ${profileId}`);
|
|
12093
|
+
}
|
|
12094
|
+
break;
|
|
12095
|
+
}
|
|
12096
|
+
if (spinner) {
|
|
12097
|
+
spinner.text = import_picocolors5.default.yellow("Connection lost, retrying...");
|
|
12098
|
+
}
|
|
12099
|
+
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
12100
|
+
continue;
|
|
12101
|
+
}
|
|
12102
|
+
const totalMs = Date.now() - loopStart;
|
|
12103
|
+
if (useJson) {
|
|
12104
|
+
const elapsed = Math.round(totalMs / 1e3);
|
|
12105
|
+
process.stdout.write(
|
|
12106
|
+
JSON.stringify({ ...scanDetail, elapsed_seconds: elapsed }) + "\n"
|
|
12107
|
+
);
|
|
12108
|
+
} else {
|
|
12109
|
+
const normalized = normalizeActivityHistory(scanDetail.activity_history);
|
|
12110
|
+
const filtered = filterActivityForTier(normalized, showFullDetails);
|
|
12111
|
+
if (printedCount > filtered.length) printedCount = 0;
|
|
12112
|
+
const newEntries = filtered.slice(printedCount);
|
|
12113
|
+
if (newEntries.length > 0) {
|
|
12114
|
+
if (spinner) spinner.stop();
|
|
12115
|
+
printActivityLines(newEntries, tty3);
|
|
12116
|
+
printedCount += newEntries.length;
|
|
12117
|
+
if (spinner) spinner = ora({ color: "green", isEnabled: true, discardStdin: false }).start();
|
|
12118
|
+
}
|
|
12119
|
+
currentPhase = extractPhase(filtered);
|
|
12120
|
+
updateSpinnerText();
|
|
12121
|
+
}
|
|
12122
|
+
const status = scanDetail.scan_status;
|
|
12123
|
+
if (status === "Running...") {
|
|
12124
|
+
if (Date.now() - loopStart > timeoutMs) {
|
|
12125
|
+
const secs = Math.round(timeoutMs / 1e3);
|
|
12126
|
+
console.error(`
|
|
12127
|
+
Timeout: pentest still running after ${secs}s.`);
|
|
12128
|
+
console.error(`Check status: kinosec pentest get ${profileId}`);
|
|
12129
|
+
deferredExitCode = 3;
|
|
12130
|
+
break;
|
|
12131
|
+
}
|
|
12132
|
+
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
12133
|
+
continue;
|
|
12134
|
+
}
|
|
12092
12135
|
if (useJson) break;
|
|
12093
|
-
if (
|
|
12136
|
+
if (status === "Completed") {
|
|
12137
|
+
const totalDur = formatDuration(Date.now() - loopStart);
|
|
12138
|
+
const domain = tty3 ? import_picocolors5.default.bold(scanDetail.domain_or_ip) : scanDetail.domain_or_ip;
|
|
12139
|
+
const icon2 = tty3 ? import_picocolors5.default.green(sym.success) : sym.success;
|
|
12140
|
+
const dur = tty3 ? import_picocolors5.default.dim(totalDur) : totalDur;
|
|
12141
|
+
console.log(`
|
|
12142
|
+
${icon2} Pentest completed: ${domain} ${dur}`);
|
|
12143
|
+
if (showFindingsSummary) {
|
|
12144
|
+
await printFindingsSummary(client, profileId, tty3);
|
|
12145
|
+
}
|
|
12146
|
+
const cmd = `kinosec finding list ${profileId}`;
|
|
12147
|
+
const viewLabel = tty3 ? import_picocolors5.default.dim("View details:") : "View details:";
|
|
12148
|
+
const viewCmd = tty3 ? import_picocolors5.default.cyan(cmd) : cmd;
|
|
12149
|
+
console.log(`
|
|
12150
|
+
${viewLabel} ${viewCmd}`);
|
|
12151
|
+
console.log();
|
|
12152
|
+
break;
|
|
12153
|
+
}
|
|
12154
|
+
if (status === "Failed") {
|
|
12094
12155
|
const icon2 = tty3 ? import_picocolors5.default.red(sym.fail) : sym.fail;
|
|
12095
12156
|
const reason = scanDetail.failure_reason || "unknown reason";
|
|
12096
12157
|
console.log(`
|
|
12097
12158
|
${icon2} Pentest failed: ${reason}`);
|
|
12098
|
-
|
|
12159
|
+
deferredExitCode = 1;
|
|
12160
|
+
break;
|
|
12099
12161
|
}
|
|
12100
|
-
if (
|
|
12162
|
+
if (status === "Stopping...") {
|
|
12101
12163
|
const icon2 = tty3 ? import_picocolors5.default.yellow(sym.warn) : sym.warn;
|
|
12102
12164
|
console.log(`
|
|
12103
|
-
${icon2} Pentest
|
|
12165
|
+
${icon2} Pentest is being stopped.`);
|
|
12104
12166
|
break;
|
|
12105
12167
|
}
|
|
12106
|
-
|
|
12107
|
-
|
|
12108
|
-
|
|
12109
|
-
|
|
12110
|
-
|
|
12111
|
-
${icon} Pentest completed: ${domain} ${dur}`);
|
|
12112
|
-
if (showFindingsSummary) {
|
|
12113
|
-
await printFindingsSummary(client, profileId, tty3);
|
|
12168
|
+
if (status === "Not Yet Started") {
|
|
12169
|
+
const icon2 = tty3 ? import_picocolors5.default.yellow(sym.warn) : sym.warn;
|
|
12170
|
+
console.log(`
|
|
12171
|
+
${icon2} Pentest was stopped.`);
|
|
12172
|
+
break;
|
|
12114
12173
|
}
|
|
12115
|
-
|
|
12116
|
-
|
|
12117
|
-
|
|
12174
|
+
if (status === "Scheduled") {
|
|
12175
|
+
const icon2 = tty3 ? import_picocolors5.default.yellow(sym.warn) : sym.warn;
|
|
12176
|
+
console.log(`
|
|
12177
|
+
${icon2} Pentest is scheduled, not currently running.`);
|
|
12178
|
+
break;
|
|
12179
|
+
}
|
|
12180
|
+
const icon = tty3 ? import_picocolors5.default.yellow(sym.warn) : sym.warn;
|
|
12118
12181
|
console.log(`
|
|
12119
|
-
|
|
12120
|
-
console.log();
|
|
12182
|
+
${icon} Unexpected status: ${status}`);
|
|
12121
12183
|
break;
|
|
12122
12184
|
}
|
|
12123
|
-
|
|
12124
|
-
|
|
12125
|
-
|
|
12126
|
-
|
|
12127
|
-
|
|
12128
|
-
console.error(`Check status: kinosec pentest get ${profileId}`);
|
|
12129
|
-
process.exit(3);
|
|
12130
|
-
}
|
|
12131
|
-
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
12185
|
+
} finally {
|
|
12186
|
+
cleanup();
|
|
12187
|
+
}
|
|
12188
|
+
if (deferredExitCode !== null) {
|
|
12189
|
+
process.exit(deferredExitCode);
|
|
12132
12190
|
}
|
|
12133
12191
|
}
|
|
12134
12192
|
async function printFindingsSummary(client, profileId, tty3) {
|
|
@@ -13732,7 +13790,7 @@ Examples:
|
|
|
13732
13790
|
|
|
13733
13791
|
// src/cli.ts
|
|
13734
13792
|
var program2 = new Command();
|
|
13735
|
-
program2.name("kinosec").description("KinoSec CLI \u2014 run pentests from your terminal").version("0.10.
|
|
13793
|
+
program2.name("kinosec").description("KinoSec CLI \u2014 run pentests from your terminal").version("0.10.2", "-v, --version").option("--token <pat>", "API token (overrides KINOSEC_TOKEN)").option("--output <format>", "Output format: text or json", "text").option("--json", "Shorthand for --output json").option("--no-color", "Disable colors");
|
|
13736
13794
|
registerAuthCommand(program2);
|
|
13737
13795
|
registerMeCommand(program2);
|
|
13738
13796
|
registerCreditsCommand(program2);
|
|
@@ -13741,7 +13799,7 @@ registerAssetCommand(program2);
|
|
|
13741
13799
|
registerFindingCommand(program2);
|
|
13742
13800
|
registerReportCommand(program2);
|
|
13743
13801
|
registerTokenCommand(program2);
|
|
13744
|
-
program2.parseAsync(process.argv).then(() => checkForUpdate("0.10.
|
|
13802
|
+
program2.parseAsync(process.argv).then(() => checkForUpdate("0.10.2")).catch(handleError);
|
|
13745
13803
|
/*! Bundled license information:
|
|
13746
13804
|
|
|
13747
13805
|
ky/distribution/index.js:
|