pentesting 0.56.2 → 0.56.3

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.
Files changed (2) hide show
  1. package/dist/main.js +121 -24
  2. package/package.json +1 -1
package/dist/main.js CHANGED
@@ -711,7 +711,7 @@ var INPUT_PROMPT_PATTERNS = [
711
711
 
712
712
  // src/shared/constants/agent.ts
713
713
  var APP_NAME = "Pentest AI";
714
- var APP_VERSION = "0.56.2";
714
+ var APP_VERSION = "0.56.3";
715
715
  var APP_DESCRIPTION = "Autonomous Penetration Testing AI Agent";
716
716
  var LLM_ROLES = {
717
717
  SYSTEM: "system",
@@ -14929,6 +14929,15 @@ var boxLine = (content, width) => {
14929
14929
  const truncated = content.length > inner ? content.slice(0, inner - 1) + "\u2026" : content;
14930
14930
  return `\u2502 ${truncated.padEnd(inner - 1)}`;
14931
14931
  };
14932
+ var formatTargetLine = (target) => {
14933
+ if (target.ports.length === 0) return target.ip;
14934
+ const portList = target.ports.map((p) => `${p.port}`).join(", ");
14935
+ return `${target.ip} \u2192 ${target.ip}:${portList}`;
14936
+ };
14937
+ var formatServiceLabel = (target, port) => {
14938
+ const svc = port.version ? `${port.service}/${port.version}` : port.service;
14939
+ return `${target.ip}:${port.port} (${svc})`;
14940
+ };
14932
14941
  var formatFindingsWithFlags = (findings, flags) => {
14933
14942
  const findingsOutput = formatFindings(findings);
14934
14943
  const flagsOutput = formatFlags(flags);
@@ -14938,41 +14947,108 @@ ${flagsOutput}`;
14938
14947
  }
14939
14948
  return findingsOutput;
14940
14949
  };
14941
- var formatGraphWithSummary = (_graphASCII, findings, flags) => {
14950
+ var formatGraphWithSummary = (state, findings, flags) => {
14942
14951
  const lines = [];
14943
14952
  const w = getBoxWidth();
14944
14953
  const innerDash = w - 2;
14945
- lines.push(`\u250C${"\u2500".repeat(innerDash)}\u2510`);
14946
- lines.push(boxLine(`\u{1F5A5} 1 \u26A0 ${findings.length} \u2699 1`, w));
14947
- lines.push(boxLine("", w));
14948
- lines.push(boxLine("\u{1F5A5} HOST (1)", w));
14949
- lines.push(boxLine(` \u25CB 138.2.89.94 \u2192 138.2.89.94:443`, w));
14954
+ const targets = state.getAllTargets();
14955
+ const graphStats = state.attackGraph.getStats();
14956
+ const allNodes = state.attackGraph.getAllNodes();
14957
+ const hostNodes = allNodes.filter((n) => n.type === NODE_TYPE.HOST);
14958
+ const serviceNodes = allNodes.filter((n) => n.type === NODE_TYPE.SERVICE);
14959
+ const vulnNodes = allNodes.filter((n) => n.type === NODE_TYPE.VULNERABILITY);
14960
+ const hostCount = hostNodes.length || targets.length;
14961
+ const serviceCount = serviceNodes.length || targets.reduce((sum, t) => sum + t.ports.length, 0);
14962
+ const vulnCount = findings.length;
14963
+ const topTitle = "\u2500\u2500\u2500 Attack Graph ";
14964
+ lines.push(`\u250C${topTitle}${"\u2500".repeat(Math.max(0, innerDash - topTitle.length))}\u2510`);
14965
+ lines.push(boxLine(`\u{1F5A5} ${hostCount} \u26A0 ${vulnCount} \u2699 ${serviceCount}`, w));
14950
14966
  lines.push(boxLine("", w));
14951
- lines.push(boxLine(`\u26A0 VULNERABILITY (${findings.length})`, w));
14952
- const sortedFindings = [...findings].sort((a, b) => b.confidence - a.confidence).slice(0, 5);
14953
- for (const f of sortedFindings) {
14954
- const icon = confIcon(f.confidence);
14955
- const cat = f.category ? ` \u2502 ${f.category}` : "";
14956
- lines.push(boxLine(` \u25CB ${icon} ${f.title.slice(0, 60)}${f.title.length > 60 ? "..." : ""}`, w));
14957
- lines.push(boxLine(` ${confLabel(f.confidence).toUpperCase()} \u2502 ${f.severity.toUpperCase()}${cat}`, w));
14967
+ lines.push(boxLine(`\u{1F5A5} HOST (${hostCount})`, w));
14968
+ if (targets.length > 0) {
14969
+ for (const t of targets.slice(0, 5)) {
14970
+ lines.push(boxLine(` \u25CB ${formatTargetLine(t)}`, w));
14971
+ }
14972
+ if (targets.length > 5) {
14973
+ lines.push(boxLine(` ... and ${targets.length - 5} more hosts`, w));
14974
+ }
14975
+ } else if (hostNodes.length > 0) {
14976
+ for (const node of hostNodes.slice(0, 5)) {
14977
+ lines.push(boxLine(` \u25CB ${node.label}`, w));
14978
+ }
14979
+ if (hostNodes.length > 5) {
14980
+ lines.push(boxLine(` ... and ${hostNodes.length - 5} more hosts`, w));
14981
+ }
14982
+ } else {
14983
+ lines.push(boxLine(" (no hosts discovered)", w));
14958
14984
  }
14959
- if (findings.length > 5) {
14960
- lines.push(boxLine(` ... and ${findings.length - 5} more findings`, w));
14985
+ lines.push(boxLine("", w));
14986
+ lines.push(boxLine(`\u26A0 VULNERABILITY (${vulnCount})`, w));
14987
+ if (findings.length > 0) {
14988
+ const sortedFindings = [...findings].sort((a, b) => b.confidence - a.confidence).slice(0, 5);
14989
+ for (const f of sortedFindings) {
14990
+ const icon = confIcon(f.confidence);
14991
+ const cat = f.category ? ` \u2502 ${f.category}` : "";
14992
+ lines.push(boxLine(` \u25CB ${icon} ${f.title.slice(0, 60)}${f.title.length > 60 ? "..." : ""}`, w));
14993
+ lines.push(boxLine(` ${confLabel(f.confidence).toUpperCase()} \u2502 ${f.severity.toUpperCase()}${cat}`, w));
14994
+ }
14995
+ if (findings.length > 5) {
14996
+ lines.push(boxLine(` ... and ${findings.length - 5} more findings`, w));
14997
+ }
14998
+ } else if (vulnNodes.length > 0) {
14999
+ for (const node of vulnNodes.slice(0, 5)) {
15000
+ lines.push(boxLine(` \u25CB ${node.label}`, w));
15001
+ }
15002
+ if (vulnNodes.length > 5) {
15003
+ lines.push(boxLine(` ... and ${vulnNodes.length - 5} more`, w));
15004
+ }
15005
+ } else {
15006
+ lines.push(boxLine(" (no vulnerabilities found)", w));
14961
15007
  }
14962
15008
  const cveFindings = findings.filter((f) => f.title.includes("CVE"));
14963
15009
  if (cveFindings.length > 0) {
14964
- lines.push(boxLine(` \u25CB CVE search: https nginx/1.24.0 (Ubuntu) -> Apache CouchDB 3.5.1`, w));
15010
+ const cveList = cveFindings.slice(0, 3).map((f) => f.title.match(/CVE-\d{4}-\d+/)?.[0] ?? f.title).join(", ");
15011
+ const suffix = cveFindings.length > 3 ? ` (+${cveFindings.length - 3} more)` : "";
15012
+ lines.push(boxLine(` \u25CB CVE found: ${cveList}${suffix}`, w));
14965
15013
  }
14966
15014
  lines.push(boxLine("", w));
14967
- lines.push(boxLine("\u2699 SERVICE (1)", w));
14968
- lines.push(boxLine(` \u25CB 138.2.89.94:443 (nginx/1.24.0 (Ubuntu) -> Apache CouchDB 3.5.1)`, w));
15015
+ lines.push(boxLine(`\u2699 SERVICE (${serviceCount})`, w));
15016
+ if (targets.length > 0) {
15017
+ let shownServices = 0;
15018
+ const maxShow = 5;
15019
+ for (const t of targets) {
15020
+ for (const p of t.ports) {
15021
+ if (shownServices >= maxShow) break;
15022
+ lines.push(boxLine(` \u25CB ${formatServiceLabel(t, p)}`, w));
15023
+ shownServices++;
15024
+ }
15025
+ if (shownServices >= maxShow) break;
15026
+ }
15027
+ const totalServices = targets.reduce((sum, t) => sum + t.ports.length, 0);
15028
+ if (totalServices > maxShow) {
15029
+ lines.push(boxLine(` ... and ${totalServices - maxShow} more services`, w));
15030
+ }
15031
+ } else if (serviceNodes.length > 0) {
15032
+ for (const node of serviceNodes.slice(0, 5)) {
15033
+ lines.push(boxLine(` \u25CB ${node.label}`, w));
15034
+ }
15035
+ if (serviceNodes.length > 5) {
15036
+ lines.push(boxLine(` ... and ${serviceNodes.length - 5} more`, w));
15037
+ }
15038
+ } else {
15039
+ lines.push(boxLine(" (no services discovered)", w));
15040
+ }
14969
15041
  if (flags.length > 0) {
14970
15042
  lines.push(boxLine("", w));
14971
15043
  lines.push(boxLine(`\u{1F3F4} Captured: ${flags.length}`, w));
14972
15044
  }
14973
15045
  lines.push(boxLine("", w));
14974
- lines.push(`\u251C${"\u2500".repeat(innerDash)}\u2524`);
14975
- lines.push(boxLine(`Nodes: ${findings.length + 2} | Edges: 2 | Succeeded: 0 | Failed: 0 | Chains: 0`, w));
15046
+ const midTitle = "\u2500\u2500\u2500 Summary ";
15047
+ lines.push(`\u251C${midTitle}${"\u2500".repeat(Math.max(0, innerDash - midTitle.length))}\u2524`);
15048
+ lines.push(boxLine(
15049
+ `Nodes: ${graphStats.nodes} | Edges: ${graphStats.edges} | Succeeded: ${graphStats.succeeded} | Failed: ${graphStats.failed} | Chains: ${graphStats.chains}`,
15050
+ w
15051
+ ));
14976
15052
  lines.push(`\u2514${"\u2500".repeat(innerDash)}\u2518`);
14977
15053
  return lines.join("\n");
14978
15054
  };
@@ -15031,7 +15107,7 @@ ${procData.stdout || "(no output)"}
15031
15107
  const flags = state.getFlags();
15032
15108
  const graphASCII = state.attackGraph.toASCII();
15033
15109
  if (state.attackGraph.isEmpty() && (findings.length > 0 || flags.length > 0)) {
15034
- ctx.showModal("graph", formatGraphWithSummary(graphASCII, findings, flags));
15110
+ ctx.showModal("graph", formatGraphWithSummary(state, findings, flags));
15035
15111
  } else {
15036
15112
  let output = graphASCII;
15037
15113
  if (flags.length > 0) {
@@ -15046,7 +15122,7 @@ ${procData.stdout || "(no output)"}
15046
15122
  const flags = state.getFlags();
15047
15123
  const graphASCII = state.attackGraph.toASCII();
15048
15124
  if (state.attackGraph.isEmpty() && (findings.length > 0 || flags.length > 0)) {
15049
- ctx.showModal("graph", formatGraphWithSummary(graphASCII, findings, flags));
15125
+ ctx.showModal("graph", formatGraphWithSummary(state, findings, flags));
15050
15126
  } else {
15051
15127
  let output = graphASCII;
15052
15128
  if (flags.length > 0) {
@@ -16306,6 +16382,27 @@ var ChatInput = memo10(({
16306
16382
  setSelectedIdx(0);
16307
16383
  setInputKey((k) => k + 1);
16308
16384
  }, []);
16385
+ const onSubmitRef = useRef8(onSubmit);
16386
+ onSubmitRef.current = onSubmit;
16387
+ const wrappedOnSubmit = useCallback9((val) => {
16388
+ if (showPreviewRef.current) {
16389
+ const sug = suggestionsRef.current;
16390
+ if (!sug.length) {
16391
+ onSubmitRef.current(val);
16392
+ return;
16393
+ }
16394
+ const best = sug[Math.min(selectedIdxRef.current, sug.length - 1)];
16395
+ if (best.args) {
16396
+ completeCommand(selectedIdxRef.current);
16397
+ } else {
16398
+ const completed = `/${best.name}`;
16399
+ onChangeRef.current(completed);
16400
+ onSubmitRef.current(completed);
16401
+ }
16402
+ return;
16403
+ }
16404
+ onSubmitRef.current(val);
16405
+ }, [completeCommand]);
16309
16406
  useInput3(useCallback9((_input, key) => {
16310
16407
  if (inputRequestRef.current.status === "active") return;
16311
16408
  const sug = suggestionsRef.current;
@@ -16349,7 +16446,7 @@ var ChatInput = memo10(({
16349
16446
  inputKey,
16350
16447
  value,
16351
16448
  onChange,
16352
- onSubmit,
16449
+ onSubmit: wrappedOnSubmit,
16353
16450
  placeholder
16354
16451
  }
16355
16452
  )
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pentesting",
3
- "version": "0.56.2",
3
+ "version": "0.56.3",
4
4
  "description": "Autonomous Penetration Testing AI Agent",
5
5
  "type": "module",
6
6
  "main": "dist/main.js",