cognium-dev 3.105.0 → 3.106.0

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/cli.js +746 -45
  2. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -4,8 +4,8 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
4
4
 
5
5
  // src/cli.ts
6
6
  import { readFileSync, existsSync } from "fs";
7
- import { stat, readdir } from "fs/promises";
8
- import { join, dirname as dirname2, extname, resolve, relative } from "path";
7
+ import { stat as stat2, readdir as readdir2 } from "fs/promises";
8
+ import { join as join2, dirname as dirname2, extname, resolve, relative as relative3 } from "path";
9
9
  import { createRequire as createRequire2 } from "module";
10
10
 
11
11
  // ../../node_modules/web-tree-sitter/web-tree-sitter.js
@@ -18068,7 +18068,74 @@ function applyLibraryApiSurfaceDowngrade(findings) {
18068
18068
  return f;
18069
18069
  if (f.severity === "medium" || f.severity === "low")
18070
18070
  return f;
18071
- return { ...f, severity: "medium", level: "warning" };
18071
+ return {
18072
+ ...f,
18073
+ original_severity: f.severity,
18074
+ severity: "medium",
18075
+ level: "warning"
18076
+ };
18077
+ });
18078
+ }
18079
+
18080
+ // ../circle-ir/dist/analysis/project-profile-transform.js
18081
+ var DOWNGRADE_ELIGIBLE_RULE_IDS = new Set([
18082
+ "code_injection",
18083
+ "template_injection",
18084
+ "xpath_injection",
18085
+ "sql_injection"
18086
+ ]);
18087
+ function libraryDowngrade(severity) {
18088
+ switch (severity) {
18089
+ case "critical":
18090
+ return { severity: "medium", level: "warning" };
18091
+ case "high":
18092
+ return { severity: "low", level: "note" };
18093
+ case "medium":
18094
+ return { severity: "low", level: "note" };
18095
+ case "low":
18096
+ return { severity: "low", level: "note" };
18097
+ }
18098
+ }
18099
+ function levelForSeverity(severity) {
18100
+ switch (severity) {
18101
+ case "critical":
18102
+ return "error";
18103
+ case "high":
18104
+ return "error";
18105
+ case "medium":
18106
+ return "warning";
18107
+ case "low":
18108
+ return "note";
18109
+ }
18110
+ }
18111
+ function applyProjectProfileTransform(findings, resolveProfile) {
18112
+ return findings.map((f) => {
18113
+ if (!f.tags?.includes(LIBRARY_API_SURFACE_TAG))
18114
+ return f;
18115
+ const profile = resolveProfile(f.file);
18116
+ if (profile === "unknown")
18117
+ return f;
18118
+ const shape = profile.split("/")[0];
18119
+ if (shape === "library") {
18120
+ if (!DOWNGRADE_ELIGIBLE_RULE_IDS.has(f.rule_id))
18121
+ return f;
18122
+ const { severity, level } = libraryDowngrade(f.severity);
18123
+ if (severity === f.severity && level === f.level)
18124
+ return f;
18125
+ return { ...f, severity, level };
18126
+ }
18127
+ if (shape === "application") {
18128
+ if (!f.original_severity)
18129
+ return f;
18130
+ if (f.original_severity === f.severity)
18131
+ return f;
18132
+ return {
18133
+ ...f,
18134
+ severity: f.original_severity,
18135
+ level: levelForSeverity(f.original_severity)
18136
+ };
18137
+ }
18138
+ return f;
18072
18139
  });
18073
18140
  }
18074
18141
 
@@ -34933,6 +35000,13 @@ function getNodeTypesForLanguage(language) {
34933
35000
  ]);
34934
35001
  }
34935
35002
  }
35003
+ function makeProfileResolver(p) {
35004
+ if (p === undefined)
35005
+ return () => "unknown";
35006
+ if (typeof p === "string")
35007
+ return () => p;
35008
+ return (file) => p.get(file) ?? "unknown";
35009
+ }
34936
35010
  async function analyze(code, filePath, language, options = {}) {
34937
35011
  if (!initialized) {
34938
35012
  await initAnalyzer(options);
@@ -35139,7 +35213,8 @@ async function analyze(code, filePath, language, options = {}) {
35139
35213
  emitFindingsInstrumentation(filePath, findings, taint);
35140
35214
  const verifiedFindings = applyConfidenceFilter(findings, options.includeSpeculative === true);
35141
35215
  const downgradedFindings = applyLibraryApiSurfaceDowngrade(verifiedFindings);
35142
- const cappedFindings = applyPerFileFindingCap(filePath, downgradedFindings, options.perFileFindingCap ?? DEFAULT_PER_FILE_FINDING_CAP);
35216
+ const profiledFindings = applyProjectProfileTransform(downgradedFindings, makeProfileResolver(options.projectProfile));
35217
+ const cappedFindings = applyPerFileFindingCap(filePath, profiledFindings, options.perFileFindingCap ?? DEFAULT_PER_FILE_FINDING_CAP);
35143
35218
  return {
35144
35219
  meta,
35145
35220
  types,
@@ -35297,6 +35372,491 @@ function deriveProjectRoot(paths) {
35297
35372
  }
35298
35373
  return common.join("/") || "/";
35299
35374
  }
35375
+ // src/project-profile-detect/index.ts
35376
+ import { relative as relative2 } from "path";
35377
+
35378
+ // src/project-profile-detect/walk.ts
35379
+ import { readdir, readFile, stat } from "fs/promises";
35380
+ import { join, relative } from "path";
35381
+
35382
+ // src/project-profile-detect/maven-parse.ts
35383
+ var TAG = (name2) => new RegExp(`<${name2}\\b[^>]*>([\\s\\S]*?)<\\/${name2}>`, "i");
35384
+ var ALL_TAGS = (name2) => new RegExp(`<${name2}\\b[^>]*>([\\s\\S]*?)<\\/${name2}>`, "gi");
35385
+ function firstTag(xml, name2) {
35386
+ const m = TAG(name2).exec(xml);
35387
+ return m?.[1].trim();
35388
+ }
35389
+ function allTags(xml, name2) {
35390
+ const out2 = [];
35391
+ let m;
35392
+ const re = ALL_TAGS(name2);
35393
+ while ((m = re.exec(xml)) !== null)
35394
+ out2.push(m[1].trim());
35395
+ return out2;
35396
+ }
35397
+ var MAVEN_PLUGIN_MAP = {
35398
+ "spring-boot-maven-plugin": "spring-boot",
35399
+ "maven-plugin-plugin": "maven-plugin",
35400
+ "maven-war-plugin": "war",
35401
+ "maven-ear-plugin": "ear",
35402
+ "maven-shade-plugin": "application",
35403
+ "exec-maven-plugin": "application",
35404
+ "maven-assembly-plugin": "application"
35405
+ };
35406
+ function parseMavenPom(xml, moduleRoot, buildFile, directorySignals) {
35407
+ const stripped = xml.replace(/<parent\b[\s\S]*?<\/parent>/i, "");
35408
+ const groupId = firstTag(stripped, "groupId");
35409
+ const artifactId = firstTag(stripped, "artifactId");
35410
+ const version = firstTag(stripped, "version");
35411
+ const packaging = firstTag(stripped, "packaging");
35412
+ const buildBlock = firstTag(xml, "build") ?? "";
35413
+ const pluginBlocks = allTags(buildBlock, "plugin");
35414
+ const plugins = new Set;
35415
+ for (const p of pluginBlocks) {
35416
+ const aid = firstTag(p, "artifactId");
35417
+ if (aid && MAVEN_PLUGIN_MAP[aid])
35418
+ plugins.add(MAVEN_PLUGIN_MAP[aid]);
35419
+ }
35420
+ if (/<parent\b[\s\S]*?<artifactId>\s*spring-boot-starter-parent\s*<\/artifactId>/i.test(xml)) {
35421
+ plugins.add("spring-boot");
35422
+ }
35423
+ if (packaging === "war")
35424
+ plugins.add("war");
35425
+ if (packaging === "ear")
35426
+ plugins.add("ear");
35427
+ if (packaging === "maven-plugin")
35428
+ plugins.add("maven-plugin");
35429
+ const distBlock = firstTag(xml, "distributionManagement") ?? "";
35430
+ const urls = [
35431
+ ...allTags(distBlock, "url")
35432
+ ].map((u) => u.trim()).filter(Boolean);
35433
+ const signals = {
35434
+ ...directorySignals,
35435
+ plugins: [...directorySignals.plugins, ...plugins],
35436
+ packaging,
35437
+ distributionUrls: [...directorySignals.distributionUrls, ...urls]
35438
+ };
35439
+ return {
35440
+ root: moduleRoot,
35441
+ buildSystem: "maven",
35442
+ buildFile,
35443
+ groupId,
35444
+ artifactId,
35445
+ version,
35446
+ signals
35447
+ };
35448
+ }
35449
+
35450
+ // src/project-profile-detect/gradle-parse.ts
35451
+ var GRADLE_PLUGIN_MAP = {
35452
+ "org.springframework.boot": "spring-boot",
35453
+ "io.spring.dependency-management": "spring-boot",
35454
+ "java-library": "java-library",
35455
+ application: "application",
35456
+ war: "war",
35457
+ ear: "ear",
35458
+ "maven-publish": "maven-publish",
35459
+ "java-gradle-plugin": "gradle-plugin",
35460
+ "com.gradle.plugin-publish": "gradle-plugin"
35461
+ };
35462
+ var PLUGIN_ID_RE = /\bid\s*[(\s]\s*['"]([^'"]+)['"]/g;
35463
+ var APPLY_PLUGIN_RE = /\bapply\s+plugin\s*:\s*['"]([^'"]+)['"]/g;
35464
+ var GROUP_RE = /\bgroup\s*[=(]\s*['"]([^'"]+)['"]/;
35465
+ var VERSION_RE = /\bversion\s*[=(]\s*['"]([^'"]+)['"]/;
35466
+ var URL_RE = /\burl\s*[=(]?\s*(?:uri\s*\(\s*)?['"]([^'"]+)['"]/g;
35467
+ function parsePlugins(text) {
35468
+ const ids = new Set;
35469
+ let m;
35470
+ PLUGIN_ID_RE.lastIndex = 0;
35471
+ while ((m = PLUGIN_ID_RE.exec(text)) !== null)
35472
+ ids.add(m[1]);
35473
+ APPLY_PLUGIN_RE.lastIndex = 0;
35474
+ while ((m = APPLY_PLUGIN_RE.exec(text)) !== null)
35475
+ ids.add(m[1]);
35476
+ const out2 = new Set;
35477
+ for (const id of ids) {
35478
+ const tag = GRADLE_PLUGIN_MAP[id];
35479
+ if (tag)
35480
+ out2.add(tag);
35481
+ }
35482
+ return out2;
35483
+ }
35484
+ function parseUrls(text) {
35485
+ const out2 = [];
35486
+ let m;
35487
+ URL_RE.lastIndex = 0;
35488
+ while ((m = URL_RE.exec(text)) !== null)
35489
+ out2.push(m[1]);
35490
+ return out2;
35491
+ }
35492
+ function parseGradleBuild(text, moduleRoot, buildFile, buildSystem, directorySignals) {
35493
+ const cleaned = text.replace(/\/\*[\s\S]*?\*\//g, "");
35494
+ const pluginsSet = parsePlugins(cleaned);
35495
+ const urls = parseUrls(cleaned);
35496
+ const groupId = GROUP_RE.exec(cleaned)?.[1];
35497
+ const version = VERSION_RE.exec(cleaned)?.[1];
35498
+ const artifactId = moduleRoot.split(/[\\/]/).filter(Boolean).pop();
35499
+ const signals = {
35500
+ ...directorySignals,
35501
+ plugins: [...directorySignals.plugins, ...pluginsSet],
35502
+ distributionUrls: [...directorySignals.distributionUrls, ...urls]
35503
+ };
35504
+ return {
35505
+ root: moduleRoot,
35506
+ buildSystem,
35507
+ buildFile,
35508
+ groupId,
35509
+ artifactId,
35510
+ version,
35511
+ signals
35512
+ };
35513
+ }
35514
+
35515
+ // src/project-profile-detect/walk.ts
35516
+ var BUILD_FILES = ["pom.xml", "build.gradle", "build.gradle.kts"];
35517
+ var SKIP_DIRS = new Set([
35518
+ "node_modules",
35519
+ ".git",
35520
+ ".svn",
35521
+ ".hg",
35522
+ "target",
35523
+ "build",
35524
+ "out",
35525
+ "dist",
35526
+ ".gradle",
35527
+ ".idea",
35528
+ ".vscode",
35529
+ "bin",
35530
+ "obj"
35531
+ ]);
35532
+ async function discoverBuildModules(scanRoot) {
35533
+ const modules = [];
35534
+ await walk(scanRoot, modules);
35535
+ return modules;
35536
+ }
35537
+ async function walk(dir, out2) {
35538
+ let entries;
35539
+ try {
35540
+ entries = await readdir(dir);
35541
+ } catch {
35542
+ return;
35543
+ }
35544
+ const buildFile = entries.find((e) => BUILD_FILES.includes(e));
35545
+ if (buildFile) {
35546
+ const buildFilePath = join(dir, buildFile);
35547
+ const buildSystem = buildFile === "pom.xml" ? "maven" : buildFile === "build.gradle.kts" ? "gradle-kts" : "gradle";
35548
+ const signals = await collectDirectorySignals(dir);
35549
+ let mod;
35550
+ try {
35551
+ const raw = await readFile(buildFilePath, "utf-8");
35552
+ mod = buildSystem === "maven" ? parseMavenPom(raw, dir, buildFilePath, signals) : parseGradleBuild(raw, dir, buildFilePath, buildSystem, signals);
35553
+ } catch {
35554
+ mod = { root: dir, buildSystem, buildFile: buildFilePath, signals };
35555
+ }
35556
+ out2.push(mod);
35557
+ }
35558
+ for (const entry of entries) {
35559
+ if (SKIP_DIRS.has(entry) || entry.startsWith("."))
35560
+ continue;
35561
+ const full = join(dir, entry);
35562
+ let s;
35563
+ try {
35564
+ s = await stat(full);
35565
+ } catch {
35566
+ continue;
35567
+ }
35568
+ if (s.isDirectory()) {
35569
+ await walk(full, out2);
35570
+ }
35571
+ }
35572
+ }
35573
+ async function collectDirectorySignals(moduleRoot) {
35574
+ const signals = {
35575
+ plugins: [],
35576
+ distributionUrls: [],
35577
+ hasJpmsModuleInfo: false,
35578
+ hasSpiServices: false,
35579
+ hasMainMethod: false
35580
+ };
35581
+ const javaRoot = join(moduleRoot, "src", "main", "java");
35582
+ const resourcesRoot = join(moduleRoot, "src", "main", "resources");
35583
+ try {
35584
+ await stat(join(javaRoot, "module-info.java"));
35585
+ signals.hasJpmsModuleInfo = true;
35586
+ } catch {}
35587
+ try {
35588
+ const s = await stat(join(resourcesRoot, "META-INF", "services"));
35589
+ if (s.isDirectory())
35590
+ signals.hasSpiServices = true;
35591
+ } catch {}
35592
+ try {
35593
+ signals.hasMainMethod = await scanForMainMethod(javaRoot, 200);
35594
+ } catch {}
35595
+ return signals;
35596
+ }
35597
+ var MAIN_METHOD_RE = /\bpublic\s+static\s+void\s+main\s*\(\s*(?:final\s+)?String\s*(?:\[\s*\]|\.{3})/;
35598
+ async function scanForMainMethod(root, maxFiles) {
35599
+ let visited = 0;
35600
+ const stack = [root];
35601
+ while (stack.length > 0 && visited < maxFiles) {
35602
+ const dir = stack.pop();
35603
+ let entries;
35604
+ try {
35605
+ entries = await readdir(dir);
35606
+ } catch {
35607
+ continue;
35608
+ }
35609
+ for (const e of entries) {
35610
+ const full = join(dir, e);
35611
+ let s;
35612
+ try {
35613
+ s = await stat(full);
35614
+ } catch {
35615
+ continue;
35616
+ }
35617
+ if (s.isDirectory()) {
35618
+ stack.push(full);
35619
+ } else if (s.isFile() && e.endsWith(".java")) {
35620
+ visited++;
35621
+ try {
35622
+ const text = await readFile(full, "utf-8");
35623
+ if (MAIN_METHOD_RE.test(text))
35624
+ return true;
35625
+ } catch {}
35626
+ if (visited >= maxFiles)
35627
+ break;
35628
+ }
35629
+ }
35630
+ }
35631
+ return false;
35632
+ }
35633
+ async function enumerateScanFiles(scanRoot) {
35634
+ const out2 = [];
35635
+ await enumerate(scanRoot, out2);
35636
+ return out2;
35637
+ }
35638
+ async function enumerate(dir, out2) {
35639
+ let entries;
35640
+ try {
35641
+ entries = await readdir(dir);
35642
+ } catch {
35643
+ return;
35644
+ }
35645
+ for (const e of entries) {
35646
+ if (SKIP_DIRS.has(e) || e.startsWith("."))
35647
+ continue;
35648
+ const full = join(dir, e);
35649
+ let s;
35650
+ try {
35651
+ s = await stat(full);
35652
+ } catch {
35653
+ continue;
35654
+ }
35655
+ if (s.isDirectory()) {
35656
+ await enumerate(full, out2);
35657
+ } else if (s.isFile()) {
35658
+ out2.push(full);
35659
+ }
35660
+ }
35661
+ }
35662
+ function ownerOf(file, modules) {
35663
+ let best;
35664
+ let bestLen = -1;
35665
+ for (const m of modules) {
35666
+ if (file === m.root || file.startsWith(m.root + "/")) {
35667
+ if (m.root.length > bestLen) {
35668
+ best = m;
35669
+ bestLen = m.root.length;
35670
+ }
35671
+ }
35672
+ }
35673
+ return best;
35674
+ }
35675
+
35676
+ // src/project-profile-detect/publication-detect.ts
35677
+ var PUBLIC_REGISTRY_HOSTS = new Set([
35678
+ "repo.maven.apache.org",
35679
+ "repo1.maven.org",
35680
+ "oss.sonatype.org",
35681
+ "s01.oss.sonatype.org",
35682
+ "central.sonatype.com",
35683
+ "central.sonatype.org",
35684
+ "plugins.gradle.org",
35685
+ "jcenter.bintray.com"
35686
+ ]);
35687
+ function isPubliclyPublished(urls) {
35688
+ for (const u of urls) {
35689
+ let host;
35690
+ try {
35691
+ host = new URL(u).hostname.toLowerCase();
35692
+ } catch {
35693
+ continue;
35694
+ }
35695
+ if (PUBLIC_REGISTRY_HOSTS.has(host))
35696
+ return true;
35697
+ }
35698
+ return false;
35699
+ }
35700
+
35701
+ // src/project-profile-detect/shape-resolve.ts
35702
+ function resolveShape(mod) {
35703
+ const sig = mod.signals;
35704
+ const has = (tag) => sig.plugins.includes(tag);
35705
+ const reasons = [];
35706
+ if (has("spring-boot")) {
35707
+ reasons.push("spring-boot plugin");
35708
+ return { shape: "server", reasons };
35709
+ }
35710
+ if (has("war") || has("ear")) {
35711
+ reasons.push(has("war") ? "war packaging" : "ear packaging");
35712
+ return { shape: "server", reasons };
35713
+ }
35714
+ if (has("maven-plugin") || has("gradle-plugin")) {
35715
+ reasons.push(has("maven-plugin") ? "maven-plugin packaging" : "gradle-plugin id");
35716
+ return { shape: "plugin", reasons };
35717
+ }
35718
+ if (has("application")) {
35719
+ reasons.push("application plugin");
35720
+ return { shape: "cli", reasons };
35721
+ }
35722
+ if (sig.hasMainMethod) {
35723
+ reasons.push("main(String[]) found");
35724
+ return { shape: "application", reasons };
35725
+ }
35726
+ const libSignals = [];
35727
+ if (has("java-library"))
35728
+ libSignals.push("java-library plugin");
35729
+ if (sig.hasJpmsModuleInfo)
35730
+ libSignals.push("JPMS module-info.java");
35731
+ if (sig.hasSpiServices)
35732
+ libSignals.push("META-INF/services SPI");
35733
+ if (libSignals.length > 0) {
35734
+ const published = isPubliclyPublished(sig.distributionUrls);
35735
+ if (published) {
35736
+ reasons.push(...libSignals, "public-registry distribution");
35737
+ return { shape: "library", reasons };
35738
+ }
35739
+ reasons.push(...libSignals, "no public-registry distribution (internal helper)");
35740
+ return { shape: "application", reasons };
35741
+ }
35742
+ reasons.push("no shape signals");
35743
+ return { shape: "unknown", reasons };
35744
+ }
35745
+
35746
+ // src/project-profile-detect/env-resolve.ts
35747
+ var TEST_RE = /(?:^|\/)tests?\//;
35748
+ var SAMPLE_RE = /(?:^|\/)(?:samples?|examples?|demos?|fixtures?)\//;
35749
+ var BENCHMARK_RE = /(?:^|\/)benchmarks?\//;
35750
+ var PROD_RE = /(?:^|\/)src\/main\//;
35751
+ function resolveEnv(absoluteFile) {
35752
+ const f = absoluteFile.replace(/\\/g, "/").toLowerCase();
35753
+ if (TEST_RE.test(f))
35754
+ return "test";
35755
+ if (BENCHMARK_RE.test(f))
35756
+ return "benchmark";
35757
+ if (SAMPLE_RE.test(f))
35758
+ return "sample";
35759
+ if (PROD_RE.test(f))
35760
+ return "production";
35761
+ return "dev";
35762
+ }
35763
+
35764
+ // src/project-profile-detect/overrides.ts
35765
+ function compileGlob(glob) {
35766
+ let re = "";
35767
+ let i2 = 0;
35768
+ while (i2 < glob.length) {
35769
+ const c = glob[i2];
35770
+ if (c === "*") {
35771
+ if (glob[i2 + 1] === "*") {
35772
+ re += ".*";
35773
+ i2 += 2;
35774
+ if (glob[i2] === "/")
35775
+ i2++;
35776
+ } else {
35777
+ re += "[^/]*";
35778
+ i2++;
35779
+ }
35780
+ } else if (c === "?") {
35781
+ re += "[^/]";
35782
+ i2++;
35783
+ } else if (/[.+^${}()|[\]\\]/.test(c)) {
35784
+ re += "\\" + c;
35785
+ i2++;
35786
+ } else {
35787
+ re += c;
35788
+ i2++;
35789
+ }
35790
+ }
35791
+ return new RegExp("^" + re + "$");
35792
+ }
35793
+ function compileOverrides(overrides) {
35794
+ if (!overrides)
35795
+ return [];
35796
+ return Object.entries(overrides).map(([glob, profile]) => ({
35797
+ re: compileGlob(glob),
35798
+ profile,
35799
+ glob
35800
+ }));
35801
+ }
35802
+ function applyOverrides(relativePath, compiled) {
35803
+ const p = relativePath.replace(/\\/g, "/");
35804
+ for (const { re, profile, glob } of compiled) {
35805
+ if (re.test(p))
35806
+ return { profile, glob };
35807
+ }
35808
+ return;
35809
+ }
35810
+
35811
+ // src/project-profile-detect/index.ts
35812
+ async function detectProjectProfiles(scanRoot, options = {}) {
35813
+ const modules = await discoverBuildModules(scanRoot);
35814
+ const files = await enumerateScanFiles(scanRoot);
35815
+ const compiledOverrides = compileOverrides(options.overrides);
35816
+ const resolvedByRoot = new Map;
35817
+ const resolvedModules = [];
35818
+ for (const m of modules) {
35819
+ const sr = resolveShape(m);
35820
+ const moduleEnv = resolveEnv(m.root);
35821
+ const profile = sr.shape === "unknown" ? "unknown" : `${sr.shape}/${moduleEnv}`;
35822
+ const r = { module: m, profile, reasons: sr.reasons };
35823
+ resolvedByRoot.set(m.root, r);
35824
+ resolvedModules.push(r);
35825
+ }
35826
+ const profileByFile = new Map;
35827
+ const unknownFiles = [];
35828
+ for (const file of files) {
35829
+ const rel = relative2(scanRoot, file);
35830
+ const ov = applyOverrides(rel, compiledOverrides);
35831
+ if (ov) {
35832
+ profileByFile.set(file, ov.profile);
35833
+ continue;
35834
+ }
35835
+ if (options.forcedProfile && options.forcedProfile !== "unknown") {
35836
+ const [shape2] = options.forcedProfile.split("/");
35837
+ const env2 = resolveEnv(file);
35838
+ profileByFile.set(file, `${shape2}/${env2}`);
35839
+ continue;
35840
+ }
35841
+ const owner = ownerOf(file, modules);
35842
+ if (!owner) {
35843
+ profileByFile.set(file, "unknown");
35844
+ unknownFiles.push(file);
35845
+ continue;
35846
+ }
35847
+ const ownerResolution = resolvedByRoot.get(owner.root);
35848
+ if (!ownerResolution || ownerResolution.profile === "unknown") {
35849
+ profileByFile.set(file, "unknown");
35850
+ unknownFiles.push(file);
35851
+ continue;
35852
+ }
35853
+ const [shape] = ownerResolution.profile.split("/");
35854
+ const env = resolveEnv(file);
35855
+ profileByFile.set(file, `${shape}/${env}`);
35856
+ }
35857
+ return { profileByFile, modules: resolvedModules, unknownFiles };
35858
+ }
35859
+
35300
35860
  // src/utils/colors.ts
35301
35861
  var RESET = "\x1B[0m";
35302
35862
  var BOLD = "\x1B[1m";
@@ -35318,7 +35878,7 @@ var colors = {
35318
35878
  };
35319
35879
 
35320
35880
  // src/version.ts
35321
- var version = "3.105.0";
35881
+ var version = "3.106.0";
35322
35882
 
35323
35883
  // src/formatters.ts
35324
35884
  var LIBRARY_API_SURFACE_TAG2 = "library-api-surface:caller-responsibility";
@@ -35650,8 +36210,22 @@ function formatCrossFilePaths(taintPaths) {
35650
36210
  return lines.join(`
35651
36211
  `);
35652
36212
  }
35653
- function formatResults(results, verbose, crossFileData) {
36213
+ function formatResults(results, verbose, crossFileData, profileSummary) {
35654
36214
  const lines = [];
36215
+ if (profileSummary && profileSummary.modules.length > 0) {
36216
+ lines.push(colors.bold("Project profile"));
36217
+ for (const m of profileSummary.modules) {
36218
+ const tag = m.root === "" || m.root === "." ? "." : m.root;
36219
+ lines.push(` ${colors.cyan(tag)} → ${colors.bold(m.profile)}`);
36220
+ if (verbose) {
36221
+ lines.push(` reasons: ${m.reasons.join(" → ")}`);
36222
+ }
36223
+ }
36224
+ if (profileSummary.unknownFileCount > 0) {
36225
+ lines.push(colors.dim(` ${profileSummary.unknownFileCount} file(s) outside any module → unknown`));
36226
+ }
36227
+ lines.push("");
36228
+ }
35655
36229
  for (const result of results) {
35656
36230
  if (result.error) {
35657
36231
  lines.push(colors.red(`[ERROR] ${result.file}: ${result.error}`));
@@ -35696,7 +36270,7 @@ function formatResults(results, verbose, crossFileData) {
35696
36270
  return lines.join(`
35697
36271
  `);
35698
36272
  }
35699
- function formatJSON(results, crossFileData) {
36273
+ function formatJSON(results, crossFileData, profileSummary) {
35700
36274
  const output = {
35701
36275
  version,
35702
36276
  timestamp: new Date().toISOString(),
@@ -35708,6 +36282,7 @@ function formatJSON(results, crossFileData) {
35708
36282
  cross_file_taint_paths: crossFileData?.taintPaths ?? [],
35709
36283
  cross_file_calls: crossFileData?.crossFileCalls ?? [],
35710
36284
  cross_file_budget_exceeded: crossFileData?.budgetExceeded ?? false,
36285
+ ...profileSummary ? { project_profile: profileSummary } : {},
35711
36286
  summary: {
35712
36287
  filesScanned: results.length,
35713
36288
  filesWithVulnerabilities: results.filter((r) => r.vulnerabilities.length > 0).length,
@@ -35719,7 +36294,7 @@ function formatJSON(results, crossFileData) {
35719
36294
  };
35720
36295
  return JSON.stringify(output, null, 2);
35721
36296
  }
35722
- function formatSARIF(results, crossFileData) {
36297
+ function formatSARIF(results, crossFileData, profileSummary) {
35723
36298
  const sarif = {
35724
36299
  $schema: "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",
35725
36300
  version: "2.1.0",
@@ -35733,7 +36308,8 @@ function formatSARIF(results, crossFileData) {
35733
36308
  rules: generateRules(results, crossFileData)
35734
36309
  }
35735
36310
  },
35736
- results: generateSarifResults(results, crossFileData)
36311
+ results: generateSarifResults(results, crossFileData),
36312
+ ...profileSummary ? { properties: { projectProfile: profileSummary } } : {}
35737
36313
  }
35738
36314
  ]
35739
36315
  };
@@ -35797,7 +36373,8 @@ function generateSarifResults(results, crossFileData) {
35797
36373
  cwe: vuln.cwe,
35798
36374
  severity: vuln.severity,
35799
36375
  ...vuln.fix ? { fix: vuln.fix } : {},
35800
- ...vuln.tags && vuln.tags.length > 0 ? { tags: vuln.tags } : {}
36376
+ ...vuln.tags && vuln.tags.length > 0 ? { tags: vuln.tags } : {},
36377
+ ...vuln.profile ? { profile: vuln.profile } : {}
35801
36378
  }
35802
36379
  });
35803
36380
  }
@@ -35907,6 +36484,13 @@ SCAN OPTIONS:
35907
36484
  --disable-pass <passes> Disable specific passes (comma-separated, e.g., "naming-convention,todo-in-prod")
35908
36485
  --exclude-tests Exclude test files and directories
35909
36486
  --profile <file> Load config from file [default: cognium.config.json]
36487
+ --project-profile <p> Force project profile (shape/env). Disables auto-detection.
36488
+ - shape: library|application|cli|server|plugin
36489
+ - env: production|dev|sample|benchmark|test
36490
+ - Example: --project-profile library/production
36491
+ - Default: auto-detect from build files (pom.xml, build.gradle)
36492
+ --no-project-profile Disable project-profile auto-detection (every file → unknown).
36493
+ --project-profile-explain Print detected per-module profiles + reason chain, then exit.
35910
36494
  -o, --output <file> Write results to file
35911
36495
  -q, --quiet Suppress progress output
35912
36496
  -v, --verbose Show detailed output
@@ -36095,7 +36679,7 @@ function applySuppressionsToResults(results, suppressions, basePath) {
36095
36679
  if (suppressions.length === 0)
36096
36680
  return results;
36097
36681
  return results.map((result) => {
36098
- const relativeFile = relative(basePath, result.file) || result.file;
36682
+ const relativeFile = relative3(basePath, result.file) || result.file;
36099
36683
  const filteredVulns = result.vulnerabilities.filter((vuln) => {
36100
36684
  for (const supp of suppressions) {
36101
36685
  if (supp.pass !== vuln.type)
@@ -36178,13 +36762,13 @@ function matchesAnyPattern(filePath, patterns) {
36178
36762
  async function collectFiles(targetPath, options = {}) {
36179
36763
  const { language, excludeTests = false, includePatterns, excludePatterns, basePath } = options;
36180
36764
  const files = [];
36181
- const pathStat = await stat(targetPath);
36765
+ const pathStat = await stat2(targetPath);
36182
36766
  if (pathStat.isFile()) {
36183
36767
  if (excludeTests && isTestFile2(targetPath)) {
36184
36768
  return files;
36185
36769
  }
36186
36770
  if (fileMatchesLanguage(targetPath, language)) {
36187
- const relativePath = basePath ? relative(basePath, targetPath) : targetPath;
36771
+ const relativePath = basePath ? relative3(basePath, targetPath) : targetPath;
36188
36772
  if (includePatterns && includePatterns.length > 0) {
36189
36773
  if (!matchesAnyPattern(relativePath, includePatterns)) {
36190
36774
  return files;
@@ -36196,14 +36780,14 @@ async function collectFiles(targetPath, options = {}) {
36196
36780
  files.push(targetPath);
36197
36781
  }
36198
36782
  } else if (pathStat.isDirectory()) {
36199
- const entries = await readdir(targetPath, { withFileTypes: true });
36783
+ const entries = await readdir2(targetPath, { withFileTypes: true });
36200
36784
  for (const entry of entries) {
36201
36785
  if (entry.name.startsWith(".") || entry.name === "node_modules")
36202
36786
  continue;
36203
36787
  if (excludeTests && /^(test|tests|__tests__|spec|__mocks__)$/i.test(entry.name))
36204
36788
  continue;
36205
- const fullPath = join(targetPath, entry.name);
36206
- const relativePath = basePath ? relative(basePath, fullPath) : fullPath;
36789
+ const fullPath = join2(targetPath, entry.name);
36790
+ const relativePath = basePath ? relative3(basePath, fullPath) : fullPath;
36207
36791
  if (excludePatterns && entry.isDirectory()) {
36208
36792
  const dirPattern = relativePath + "/";
36209
36793
  if (excludePatterns.some((p) => matchesGlob(dirPattern, p) || matchesGlob(relativePath, p))) {
@@ -36220,7 +36804,8 @@ async function scanFile(filePath, language, analyzeOpts) {
36220
36804
  const code = readFileSync(filePath, "utf-8");
36221
36805
  const result = await analyze(code, filePath, language, {
36222
36806
  passOptions: analyzeOpts?.passOptions,
36223
- disabledPasses: analyzeOpts?.disabledPasses
36807
+ disabledPasses: analyzeOpts?.disabledPasses,
36808
+ ...analyzeOpts?.projectProfile !== undefined ? { projectProfile: analyzeOpts.projectProfile } : {}
36224
36809
  });
36225
36810
  const vulnerabilities = (result.taint.flows || []).map((flow) => ({
36226
36811
  type: flow.sink_type,
@@ -36261,7 +36846,8 @@ async function scanProject(files, language, analyzeOpts, crossFileBudgetMs) {
36261
36846
  const projectResult = await analyzeProject(filesWithCode, {
36262
36847
  passOptions: analyzeOpts?.passOptions,
36263
36848
  disabledPasses: analyzeOpts?.disabledPasses,
36264
- ...crossFileBudgetMs !== undefined ? { crossFileBudgetMs } : {}
36849
+ ...crossFileBudgetMs !== undefined ? { crossFileBudgetMs } : {},
36850
+ ...analyzeOpts?.projectProfile !== undefined ? { projectProfile: analyzeOpts.projectProfile } : {}
36265
36851
  });
36266
36852
  const results = projectResult.files.map(({ file, analysis }) => {
36267
36853
  const vulnerabilities = (analysis.taint.flows || []).map((flow) => ({
@@ -36299,7 +36885,7 @@ async function scanProject(files, language, analyzeOpts, crossFileBudgetMs) {
36299
36885
  async function initWasm(spin) {
36300
36886
  const isStandalone = import.meta.url.includes("/$bunfs/");
36301
36887
  if (isStandalone) {
36302
- const { dirname: dirname3, join: join2 } = await import("path");
36888
+ const { dirname: dirname3, join: join3 } = await import("path");
36303
36889
  const binaryDir = dirname3(process.execPath);
36304
36890
  const cwd = process.cwd();
36305
36891
  let scriptDir = null;
@@ -36310,34 +36896,34 @@ async function initWasm(spin) {
36310
36896
  } catch {}
36311
36897
  }
36312
36898
  const wasmLocations = [
36313
- join2(binaryDir, "wasm"),
36314
- join2(cwd, "wasm"),
36315
- join2(binaryDir, "..", "wasm"),
36899
+ join3(binaryDir, "wasm"),
36900
+ join3(cwd, "wasm"),
36901
+ join3(binaryDir, "..", "wasm"),
36316
36902
  ...scriptDir ? [
36317
- join2(scriptDir, "wasm"),
36318
- join2(scriptDir, "..", "wasm"),
36319
- join2(scriptDir, "..", "node_modules", "circle-ir", "dist", "wasm")
36903
+ join3(scriptDir, "wasm"),
36904
+ join3(scriptDir, "..", "wasm"),
36905
+ join3(scriptDir, "..", "node_modules", "circle-ir", "dist", "wasm")
36320
36906
  ] : []
36321
36907
  ];
36322
36908
  let wasmDir = null;
36323
36909
  for (const location of wasmLocations) {
36324
- if (existsSync(location) && existsSync(join2(location, "web-tree-sitter.wasm"))) {
36910
+ if (existsSync(location) && existsSync(join3(location, "web-tree-sitter.wasm"))) {
36325
36911
  wasmDir = location;
36326
36912
  break;
36327
36913
  }
36328
36914
  }
36329
36915
  if (wasmDir) {
36330
36916
  await initAnalyzer({
36331
- wasmPath: join2(wasmDir, "web-tree-sitter.wasm"),
36917
+ wasmPath: join3(wasmDir, "web-tree-sitter.wasm"),
36332
36918
  languagePaths: {
36333
- bash: join2(wasmDir, "tree-sitter-bash.wasm"),
36334
- go: join2(wasmDir, "tree-sitter-go.wasm"),
36335
- java: join2(wasmDir, "tree-sitter-java.wasm"),
36336
- javascript: join2(wasmDir, "tree-sitter-javascript.wasm"),
36337
- typescript: join2(wasmDir, "tree-sitter-javascript.wasm"),
36338
- python: join2(wasmDir, "tree-sitter-python.wasm"),
36339
- rust: join2(wasmDir, "tree-sitter-rust.wasm"),
36340
- html: join2(wasmDir, "tree-sitter-html.wasm")
36919
+ bash: join3(wasmDir, "tree-sitter-bash.wasm"),
36920
+ go: join3(wasmDir, "tree-sitter-go.wasm"),
36921
+ java: join3(wasmDir, "tree-sitter-java.wasm"),
36922
+ javascript: join3(wasmDir, "tree-sitter-javascript.wasm"),
36923
+ typescript: join3(wasmDir, "tree-sitter-javascript.wasm"),
36924
+ python: join3(wasmDir, "tree-sitter-python.wasm"),
36925
+ rust: join3(wasmDir, "tree-sitter-rust.wasm"),
36926
+ html: join3(wasmDir, "tree-sitter-html.wasm")
36341
36927
  }
36342
36928
  });
36343
36929
  } else {
@@ -36359,7 +36945,7 @@ Please ensure the wasm/ directory is located next to the binary or in your curre
36359
36945
  } else {
36360
36946
  const require2 = createRequire2(import.meta.url);
36361
36947
  const circleIrPkg = require2.resolve("circle-ir/package.json");
36362
- const wasmBasePath = join(dirname2(circleIrPkg), "dist", "wasm") + "/";
36948
+ const wasmBasePath = join2(dirname2(circleIrPkg), "dist", "wasm") + "/";
36363
36949
  await initAnalyzer({
36364
36950
  wasmPath: wasmBasePath + "web-tree-sitter.wasm",
36365
36951
  languagePaths: {
@@ -36375,6 +36961,62 @@ Please ensure the wasm/ directory is located next to the binary or in your curre
36375
36961
  });
36376
36962
  }
36377
36963
  }
36964
+ function buildProfileSummary(scanRoot, modules, resolvedProfiles) {
36965
+ if (!resolvedProfiles)
36966
+ return;
36967
+ if (modules.length === 0 && resolvedProfiles.size === 0)
36968
+ return;
36969
+ let unknownFileCount = 0;
36970
+ for (const p of resolvedProfiles.values()) {
36971
+ if (p === "unknown")
36972
+ unknownFileCount++;
36973
+ }
36974
+ return {
36975
+ scanRoot,
36976
+ modules: modules.map((m) => ({
36977
+ root: relative3(scanRoot, m.module.root) || ".",
36978
+ profile: m.profile,
36979
+ reasons: m.reasons,
36980
+ buildSystem: m.module.buildSystem
36981
+ })),
36982
+ unknownFileCount
36983
+ };
36984
+ }
36985
+ function summarizeModules(modules) {
36986
+ if (modules.length === 0)
36987
+ return "no build files detected";
36988
+ const counts = new Map;
36989
+ for (const m of modules) {
36990
+ counts.set(m.profile, (counts.get(m.profile) ?? 0) + 1);
36991
+ }
36992
+ const parts2 = [...counts.entries()].map(([profile, count]) => `${profile}×${count}`).sort();
36993
+ return `${modules.length} module(s): ${parts2.join(", ")}`;
36994
+ }
36995
+ function printProfileExplain(scanRoot, detection) {
36996
+ const out2 = [];
36997
+ out2.push(colors.bold("Project profile detection"));
36998
+ out2.push(` Scan root: ${scanRoot}`);
36999
+ out2.push(` Modules: ${detection.modules.length}`);
37000
+ out2.push(` Unknown files (no enclosing module): ${detection.unknownFiles.length}`);
37001
+ out2.push("");
37002
+ if (detection.modules.length === 0) {
37003
+ out2.push(" (no pom.xml, build.gradle, or build.gradle.kts found)");
37004
+ } else {
37005
+ for (const r of detection.modules) {
37006
+ const rel = relative3(scanRoot, r.module.root) || ".";
37007
+ out2.push(` ${colors.cyan(rel || ".")} → ${colors.bold(r.profile)}`);
37008
+ out2.push(` build: ${r.module.buildSystem} (${relative3(scanRoot, r.module.buildFile)})`);
37009
+ if (r.module.artifactId) {
37010
+ out2.push(` coords: ${r.module.groupId ?? "?"}:${r.module.artifactId}:${r.module.version ?? "?"}`);
37011
+ }
37012
+ out2.push(` reasons: ${r.reasons.join(" → ")}`);
37013
+ out2.push("");
37014
+ }
37015
+ }
37016
+ process.stderr.write(out2.join(`
37017
+ `) + `
37018
+ `);
37019
+ }
36378
37020
  async function runScan(targetPath, options) {
36379
37021
  const spin = options.quiet ? null : spinner("Initializing analyzer...").start();
36380
37022
  const config = loadConfig(options.profile);
@@ -36428,8 +37070,39 @@ async function runScan(targetPath, options) {
36428
37070
  }
36429
37071
  let results;
36430
37072
  let crossFileData;
36431
- const analyzeOpts = { passOptions, disabledPasses };
36432
- if ((await stat(absPath)).isDirectory()) {
37073
+ const forcedProfile = options.projectProfile ?? config?.profile;
37074
+ const profileOverrides = config?.profileOverrides;
37075
+ const detectionEnabled = !options.noProjectProfile && (await stat2(absPath)).isDirectory();
37076
+ let resolvedProfiles;
37077
+ let detectedModules = [];
37078
+ if (detectionEnabled) {
37079
+ if (spin)
37080
+ spin.text = "Detecting project profile...";
37081
+ const detection = await detectProjectProfiles(absPath, {
37082
+ forcedProfile,
37083
+ overrides: profileOverrides
37084
+ });
37085
+ resolvedProfiles = detection.profileByFile;
37086
+ detectedModules = detection.modules;
37087
+ if (options.projectProfileExplain) {
37088
+ if (spin)
37089
+ spin.stop();
37090
+ printProfileExplain(absPath, detection);
37091
+ return;
37092
+ }
37093
+ if (!options.quiet && detectedModules.length > 0) {
37094
+ const summary = summarizeModules(detectedModules);
37095
+ console.error(colors.dim(`Project profile: ${summary}`));
37096
+ }
37097
+ } else if (forcedProfile && !options.noProjectProfile) {
37098
+ resolvedProfiles = undefined;
37099
+ }
37100
+ const analyzeOpts = {
37101
+ passOptions,
37102
+ disabledPasses,
37103
+ ...resolvedProfiles ? { projectProfile: resolvedProfiles } : forcedProfile && !options.noProjectProfile ? { projectProfile: forcedProfile } : {}
37104
+ };
37105
+ if ((await stat2(absPath)).isDirectory()) {
36433
37106
  if (spin)
36434
37107
  spin.text = `Running project analysis on ${files.length} file(s)...`;
36435
37108
  const projectScan = await scanProject(files, options.language, analyzeOpts, options.crossFileBudgetMs);
@@ -36441,7 +37114,7 @@ async function runScan(targetPath, options) {
36441
37114
  results = [];
36442
37115
  let processed = 0;
36443
37116
  const formatCurrentFile = (file) => {
36444
- const rel = relative(absPath, file) || file;
37117
+ const rel = relative3(absPath, file) || file;
36445
37118
  return rel.length > 80 ? `...${rel.slice(-77)}` : rel;
36446
37119
  };
36447
37120
  const concurrency = options.threads;
@@ -36539,17 +37212,27 @@ async function runScan(targetPath, options) {
36539
37212
  const errors = results.filter((r) => r.error).length;
36540
37213
  const crossFilePaths = crossFileData?.taintPaths.length ?? 0;
36541
37214
  const shouldOutput = totalVulns > 0 || crossFilePaths > 0 || errors > 0 || options.verbose || options.output || options.format !== "text";
37215
+ const profileSummary = buildProfileSummary(absPath, detectedModules, resolvedProfiles);
37216
+ if (resolvedProfiles) {
37217
+ for (const r of results) {
37218
+ const p = resolvedProfiles.get(r.file);
37219
+ if (!p || p === "unknown")
37220
+ continue;
37221
+ for (const v of r.vulnerabilities)
37222
+ v.profile = p;
37223
+ }
37224
+ }
36542
37225
  if (shouldOutput) {
36543
37226
  let output;
36544
37227
  switch (options.format) {
36545
37228
  case "json":
36546
- output = formatJSON(results, crossFileData);
37229
+ output = formatJSON(results, crossFileData, profileSummary);
36547
37230
  break;
36548
37231
  case "sarif":
36549
- output = formatSARIF(results, crossFileData);
37232
+ output = formatSARIF(results, crossFileData, profileSummary);
36550
37233
  break;
36551
37234
  default:
36552
- output = formatResults(results, options.verbose, crossFileData);
37235
+ output = formatResults(results, options.verbose, crossFileData, profileSummary);
36553
37236
  }
36554
37237
  if (options.output) {
36555
37238
  const { writeFileSync } = await import("fs");
@@ -36635,7 +37318,7 @@ async function runMetrics(targetPath, options) {
36635
37318
  continue;
36636
37319
  }
36637
37320
  if (spin) {
36638
- const rel = relative(absPath, file) || file;
37321
+ const rel = relative3(absPath, file) || file;
36639
37322
  const maxLen = 80;
36640
37323
  const label = rel.length > maxLen ? `...${rel.slice(-(maxLen - 3))}` : rel;
36641
37324
  spin.text = `Analyzing ${label}... (${processed}/${totalFiles})`;
@@ -36680,7 +37363,7 @@ async function runMetrics(targetPath, options) {
36680
37363
  } else {
36681
37364
  const lines = [];
36682
37365
  for (const fm of filtered) {
36683
- const rel = relative(absPath, fm.file) || fm.file;
37366
+ const rel = relative3(absPath, fm.file) || fm.file;
36684
37367
  lines.push(rel);
36685
37368
  const byCategory = new Map;
36686
37369
  for (const m of fm.metrics) {
@@ -36836,6 +37519,21 @@ function applyFindingsInstrumentation() {
36836
37519
  setFindingsInstrumentation(true);
36837
37520
  }
36838
37521
  }
37522
+ function parseProjectProfileArg(raw) {
37523
+ if (raw === undefined || raw === true || raw === "")
37524
+ return;
37525
+ const s = String(raw).toLowerCase();
37526
+ if (s === "unknown")
37527
+ return "unknown";
37528
+ const m = /^(library|application|cli|server|plugin)\/(production|dev|sample|benchmark|test)$/.exec(s);
37529
+ if (!m) {
37530
+ console.error(colors.yellow(`Warning: invalid --project-profile "${s}" — expected one of:
37531
+ ` + ` {library,application,cli,server,plugin}/{production,dev,sample,benchmark,test}
37532
+ or "unknown". Falling back to auto-detection.`));
37533
+ return;
37534
+ }
37535
+ return s;
37536
+ }
36839
37537
  function parseCrossFileBudgetMs(raw) {
36840
37538
  if (raw === undefined || raw === true || raw === "")
36841
37539
  return;
@@ -36908,7 +37606,10 @@ Usage: cognium-dev scan <path> [options]`);
36908
37606
  excludeCwe: options["exclude-cwe"],
36909
37607
  profile: options.profile || options.p,
36910
37608
  disablePass: options["disable-pass"],
36911
- crossFileBudgetMs: parseCrossFileBudgetMs(options["cross-file-budget-ms"])
37609
+ crossFileBudgetMs: parseCrossFileBudgetMs(options["cross-file-budget-ms"]),
37610
+ projectProfile: parseProjectProfileArg(options["project-profile"]),
37611
+ noProjectProfile: options["no-project-profile"] === true,
37612
+ projectProfileExplain: options["project-profile-explain"] === true
36912
37613
  };
36913
37614
  await runScan(targetPath, scanOptions);
36914
37615
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cognium-dev",
3
- "version": "3.105.0",
3
+ "version": "3.106.0",
4
4
  "description": "Static Application Security Testing CLI for detecting security vulnerabilities via taint tracking",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -65,7 +65,7 @@
65
65
  "registry": "https://registry.npmjs.org/"
66
66
  },
67
67
  "dependencies": {
68
- "circle-ir": "^3.105.0"
68
+ "circle-ir": "^3.106.0"
69
69
  },
70
70
  "devDependencies": {
71
71
  "@types/node": "^25.5.0",