kodingo-cli 1.1.7 → 1.1.9
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/commands/init.js
CHANGED
|
@@ -41,16 +41,13 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
41
41
|
return result;
|
|
42
42
|
};
|
|
43
43
|
})();
|
|
44
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
45
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
46
|
-
};
|
|
47
44
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
45
|
exports.registerInitCommand = registerInitCommand;
|
|
49
46
|
const readline = __importStar(require("node:readline"));
|
|
50
47
|
const fs = __importStar(require("fs"));
|
|
51
48
|
const path = __importStar(require("path"));
|
|
52
49
|
const os = __importStar(require("os"));
|
|
53
|
-
|
|
50
|
+
// open is imported dynamically to avoid ESM/CJS compatibility issues on Windows
|
|
54
51
|
const persistence_config_1 = require("../utils/persistence-config");
|
|
55
52
|
const API_BASE = "https://kodingo-api.onrender.com";
|
|
56
53
|
const APP_URL = "https://kodingo.xyz";
|
|
@@ -140,7 +137,8 @@ async function browserLogin(rl) {
|
|
|
140
137
|
});
|
|
141
138
|
// Open browser
|
|
142
139
|
try {
|
|
143
|
-
await (
|
|
140
|
+
const { default: open } = await Promise.resolve().then(() => __importStar(require("open")));
|
|
141
|
+
await open(loginUrl);
|
|
144
142
|
}
|
|
145
143
|
catch { }
|
|
146
144
|
console.log("Waiting for login...");
|
|
@@ -130,7 +130,15 @@ async function securityScanCommand(options = {}) {
|
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
132
|
catch { }
|
|
133
|
-
const
|
|
133
|
+
const allCandidates = (0, security_code_analyzer_1.analyzeForSecurityCandidates)(repoRoot, graph, symbols, dynamicRules);
|
|
134
|
+
// Cap at 30 candidates for LLM judgment — prioritise critical and high severity
|
|
135
|
+
const SEVERITY_ORDER = { critical: 0, high: 1, moderate: 2, low: 3 };
|
|
136
|
+
const candidates = allCandidates
|
|
137
|
+
.sort((a, b) => (SEVERITY_ORDER[a.severity ?? 'low'] ?? 3) - (SEVERITY_ORDER[b.severity ?? 'low'] ?? 3))
|
|
138
|
+
.slice(0, 30);
|
|
139
|
+
if (!options.silent && allCandidates.length > 30) {
|
|
140
|
+
console.log(` Found ${allCandidates.length} candidates — reviewing top 30 by severity\n`);
|
|
141
|
+
}
|
|
134
142
|
if (candidates.length === 0) {
|
|
135
143
|
if (!options.silent)
|
|
136
144
|
console.log(" ✔ No suspicious patterns detected.");
|
|
@@ -14,10 +14,16 @@
|
|
|
14
14
|
* server for Layer 2 — an LLM judgment with full visibility, which is what
|
|
15
15
|
* actually adjudicates real risk vs false positive.
|
|
16
16
|
*/
|
|
17
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
18
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
19
|
+
};
|
|
17
20
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
21
|
exports.findMissingAuthCandidatesLocal = findMissingAuthCandidatesLocal;
|
|
19
22
|
exports.analyzeForSecurityCandidates = analyzeForSecurityCandidates;
|
|
20
23
|
const context_assembler_1 = require("./context-assembler");
|
|
24
|
+
const fs_1 = __importDefault(require("fs"));
|
|
25
|
+
const path_1 = __importDefault(require("path"));
|
|
26
|
+
const child_process_1 = require("child_process");
|
|
21
27
|
const code_pattern_scanner_1 = require("./code-pattern-scanner");
|
|
22
28
|
const ROUTE_REGISTRATION_METHOD_NAMES = new Set(["get", "post", "put", "delete", "patch", "addhook", "all"]);
|
|
23
29
|
const AUTH_FUNCTION_HINTS = [
|
|
@@ -80,6 +86,77 @@ function analyzeForSecurityCandidates(repoRoot, graph, symbols, dynamicRules = [
|
|
|
80
86
|
const candidates = [];
|
|
81
87
|
// ── Code pattern findings — static + dynamic rules ────────────────────────
|
|
82
88
|
const patternFindings = (0, code_pattern_scanner_1.scanAllSymbolsForPatterns)(symbols);
|
|
89
|
+
// ── Tier 1: Fast file-level scan (no LLM, runs on all files) ─────────────
|
|
90
|
+
// Catches vulnerabilities in procedural code outside named functions.
|
|
91
|
+
// Only high-confidence patterns are included — no ambiguous matches.
|
|
92
|
+
// File selection is smart: recently changed files first, then unscanned,
|
|
93
|
+
// capped at 100 files per run to stay fast and avoid timeouts.
|
|
94
|
+
const HIGH_CONFIDENCE_PATTERNS = new Set(["sql_injection", "command_injection", "hardcoded_secret", "path_traversal"]);
|
|
95
|
+
const SUPPORTED_EXTS = new Set([".php", ".py", ".go", ".rs", ".java", ".kt", ".rb", ".c", ".cpp", ".html", ".phtml", ".js", ".ts", ".jsx", ".tsx"]);
|
|
96
|
+
const EXT_TO_LANG = {
|
|
97
|
+
".php": "php", ".phtml": "php", ".py": "python", ".go": "go", ".rs": "rust",
|
|
98
|
+
".java": "java", ".kt": "kotlin", ".rb": "ruby", ".c": "c", ".cpp": "cpp",
|
|
99
|
+
".html": "html", ".js": "javascript", ".ts": "typescript", ".jsx": "javascript", ".tsx": "typescript"
|
|
100
|
+
};
|
|
101
|
+
const IGNORED_DIRS = new Set(["node_modules", ".git", "dist", "build", "vendor", "__pycache__", ".next", "out", "coverage"]);
|
|
102
|
+
// Get recently changed files from git (last 30 days) — scan these first
|
|
103
|
+
let priorityFiles = [];
|
|
104
|
+
try {
|
|
105
|
+
const gitOut = (0, child_process_1.execSync)("git log --since=30.days --name-only --pretty=format: --diff-filter=AM", { cwd: repoRoot, timeout: 5000 }).toString();
|
|
106
|
+
priorityFiles = gitOut.split("\n").filter(f => f.trim() && SUPPORTED_EXTS.has(path_1.default.extname(f)))
|
|
107
|
+
.map(f => path_1.default.join(repoRoot, f)).filter(f => fs_1.default.existsSync(f)).slice(0, 50);
|
|
108
|
+
}
|
|
109
|
+
catch { }
|
|
110
|
+
// Walk repo for remaining files — skip already-in-priority
|
|
111
|
+
const prioritySet = new Set(priorityFiles);
|
|
112
|
+
const allWalked = [];
|
|
113
|
+
const walk = (dir) => {
|
|
114
|
+
try {
|
|
115
|
+
for (const entry of fs_1.default.readdirSync(dir, { withFileTypes: true })) {
|
|
116
|
+
const full = path_1.default.join(dir, entry.name);
|
|
117
|
+
if (entry.isDirectory() && !IGNORED_DIRS.has(entry.name))
|
|
118
|
+
walk(full);
|
|
119
|
+
else if (entry.isFile() && SUPPORTED_EXTS.has(path_1.default.extname(entry.name)) && !prioritySet.has(full)) {
|
|
120
|
+
allWalked.push(full);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
catch { }
|
|
125
|
+
};
|
|
126
|
+
walk(repoRoot);
|
|
127
|
+
// Priority files first, then remaining up to cap of 100 total
|
|
128
|
+
const filesToScan = [...priorityFiles, ...allWalked].slice(0, 100);
|
|
129
|
+
const alreadyScannedFiles = new Set(symbols.map(s => s.file));
|
|
130
|
+
for (const filePath of filesToScan) {
|
|
131
|
+
if (alreadyScannedFiles.has(filePath))
|
|
132
|
+
continue; // already covered by symbol scan
|
|
133
|
+
try {
|
|
134
|
+
const source = fs_1.default.readFileSync(filePath, "utf-8");
|
|
135
|
+
const ext = path_1.default.extname(filePath);
|
|
136
|
+
const language = EXT_TO_LANG[ext] ?? "javascript";
|
|
137
|
+
const syntheticSymbol = {
|
|
138
|
+
name: path_1.default.basename(filePath),
|
|
139
|
+
file: filePath,
|
|
140
|
+
startLine: 1,
|
|
141
|
+
body: source.slice(0, 10000),
|
|
142
|
+
fingerprint: `file:${filePath}`,
|
|
143
|
+
calls: [],
|
|
144
|
+
routes: [],
|
|
145
|
+
imports: [],
|
|
146
|
+
language,
|
|
147
|
+
type: "function",
|
|
148
|
+
endLine: source.split("\n").length,
|
|
149
|
+
};
|
|
150
|
+
const fileFindings = (0, code_pattern_scanner_1.scanSymbolForPatterns)(syntheticSymbol, language)
|
|
151
|
+
.filter(f => HIGH_CONFIDENCE_PATTERNS.has(f.patternType)); // Tier 1: high-confidence only
|
|
152
|
+
for (const f of fileFindings) {
|
|
153
|
+
patternFindings.push(f);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
83
160
|
// Apply dynamic rules generated from OSV vulnerability data
|
|
84
161
|
for (const sym of symbols) {
|
|
85
162
|
const language = sym.language ?? "unknown";
|