cognium-dev 3.91.0 → 3.95.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 +136 -77
  2. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -17789,6 +17789,124 @@ function normalizeCondition(cond) {
17789
17789
  }
17790
17790
  return normalized;
17791
17791
  }
17792
+ // ../circle-ir/dist/utils/logger.js
17793
+ var LOG_LEVELS = {
17794
+ trace: 0,
17795
+ debug: 1,
17796
+ info: 2,
17797
+ warn: 3,
17798
+ error: 4,
17799
+ fatal: 5,
17800
+ silent: 6
17801
+ };
17802
+ var currentLevel = "silent";
17803
+ var customLogger = null;
17804
+ function shouldLog(level) {
17805
+ return LOG_LEVELS[level] >= LOG_LEVELS[currentLevel];
17806
+ }
17807
+ function setLogLevel(level) {
17808
+ currentLevel = level;
17809
+ }
17810
+ var logger = {
17811
+ trace: (msg, obj) => {
17812
+ if (customLogger) {
17813
+ customLogger.trace(msg, obj);
17814
+ return;
17815
+ }
17816
+ if (shouldLog("trace"))
17817
+ console.debug(obj ? `[TRACE] ${msg} ${JSON.stringify(obj)}` : `[TRACE] ${msg}`);
17818
+ },
17819
+ debug: (msg, obj) => {
17820
+ if (customLogger) {
17821
+ customLogger.debug(msg, obj);
17822
+ return;
17823
+ }
17824
+ if (shouldLog("debug"))
17825
+ console.debug(obj ? `[DEBUG] ${msg} ${JSON.stringify(obj)}` : `[DEBUG] ${msg}`);
17826
+ },
17827
+ info: (msg, obj) => {
17828
+ if (customLogger) {
17829
+ customLogger.info(msg, obj);
17830
+ return;
17831
+ }
17832
+ if (shouldLog("info"))
17833
+ console.error(obj ? `[INFO] ${msg} ${JSON.stringify(obj)}` : `[INFO] ${msg}`);
17834
+ },
17835
+ warn: (msg, obj) => {
17836
+ if (customLogger) {
17837
+ customLogger.warn(msg, obj);
17838
+ return;
17839
+ }
17840
+ if (shouldLog("warn"))
17841
+ console.warn(obj ? `[WARN] ${msg} ${JSON.stringify(obj)}` : `[WARN] ${msg}`);
17842
+ },
17843
+ error: (msg, obj) => {
17844
+ if (customLogger) {
17845
+ customLogger.error(msg, obj);
17846
+ return;
17847
+ }
17848
+ if (shouldLog("error"))
17849
+ console.error(obj ? `[ERROR] ${msg} ${JSON.stringify(obj)}` : `[ERROR] ${msg}`);
17850
+ },
17851
+ fatal: (msg, obj) => {
17852
+ if (customLogger) {
17853
+ customLogger.fatal(msg, obj);
17854
+ return;
17855
+ }
17856
+ if (shouldLog("fatal"))
17857
+ console.error(obj ? `[FATAL] ${msg} ${JSON.stringify(obj)}` : `[FATAL] ${msg}`);
17858
+ },
17859
+ isLevelEnabled: (level) => {
17860
+ return shouldLog(level);
17861
+ }
17862
+ };
17863
+
17864
+ // ../circle-ir/dist/analysis/per-file-finding-cap.js
17865
+ var DEFAULT_PER_FILE_FINDING_CAP = 1000;
17866
+ var SATURATED_FILE_RULE_ID = "saturated-file";
17867
+ function applyPerFileFindingCap(filePath, findings, cap) {
17868
+ if (cap <= 0)
17869
+ return findings;
17870
+ if (findings.length <= cap)
17871
+ return findings;
17872
+ const suppressedCount = findings.length;
17873
+ const byRule = {};
17874
+ const bySeverity = {};
17875
+ for (const f of findings) {
17876
+ byRule[f.rule_id] = (byRule[f.rule_id] ?? 0) + 1;
17877
+ bySeverity[f.severity] = (bySeverity[f.severity] ?? 0) + 1;
17878
+ }
17879
+ logger.warn(`File ${filePath} produced ${suppressedCount} findings (cap=${cap}); ` + "suppressing individual findings and emitting saturated-file advisory.", { file: filePath, suppressedCount, cap, byRule, bySeverity });
17880
+ const advisory = {
17881
+ id: `${SATURATED_FILE_RULE_ID}-${filePath}-1`,
17882
+ pass: SATURATED_FILE_RULE_ID,
17883
+ category: "maintainability",
17884
+ rule_id: SATURATED_FILE_RULE_ID,
17885
+ severity: "low",
17886
+ level: "note",
17887
+ message: `File suppressed: produced ${suppressedCount} findings, exceeding the ` + `per-file cap of ${cap}. This typically indicates cross-product noise, ` + "mislabelled sink class, or pathological generated code rather than a " + "legitimate detection burst. Individual findings dropped; re-run with " + "`perFileFindingCap: 0` to bypass the cap if the volume is intentional.",
17888
+ file: filePath,
17889
+ line: 1,
17890
+ evidence: {
17891
+ suppressed_count: suppressedCount,
17892
+ cap,
17893
+ by_rule: byRule,
17894
+ by_severity: bySeverity
17895
+ }
17896
+ };
17897
+ return [advisory];
17898
+ }
17899
+
17900
+ // ../circle-ir/dist/analysis/confidence-filter.js
17901
+ function applyConfidenceFilter(findings, includeSpeculative) {
17902
+ if (includeSpeculative)
17903
+ return findings;
17904
+ return findings.filter(isHighConfidence);
17905
+ }
17906
+ function isHighConfidence(finding) {
17907
+ return finding.confidence === undefined || finding.confidence === "high";
17908
+ }
17909
+
17792
17910
  // ../circle-ir/dist/languages/registry.js
17793
17911
  class DefaultLanguageRegistry {
17794
17912
  plugins = new Map;
@@ -20800,78 +20918,6 @@ function registerBuiltinPlugins() {
20800
20918
  registerLanguage(new HtmlPlugin);
20801
20919
  registerLanguage(new GoPlugin);
20802
20920
  }
20803
- // ../circle-ir/dist/utils/logger.js
20804
- var LOG_LEVELS = {
20805
- trace: 0,
20806
- debug: 1,
20807
- info: 2,
20808
- warn: 3,
20809
- error: 4,
20810
- fatal: 5,
20811
- silent: 6
20812
- };
20813
- var currentLevel = "silent";
20814
- var customLogger = null;
20815
- function shouldLog(level) {
20816
- return LOG_LEVELS[level] >= LOG_LEVELS[currentLevel];
20817
- }
20818
- function setLogLevel(level) {
20819
- currentLevel = level;
20820
- }
20821
- var logger = {
20822
- trace: (msg, obj) => {
20823
- if (customLogger) {
20824
- customLogger.trace(msg, obj);
20825
- return;
20826
- }
20827
- if (shouldLog("trace"))
20828
- console.debug(obj ? `[TRACE] ${msg} ${JSON.stringify(obj)}` : `[TRACE] ${msg}`);
20829
- },
20830
- debug: (msg, obj) => {
20831
- if (customLogger) {
20832
- customLogger.debug(msg, obj);
20833
- return;
20834
- }
20835
- if (shouldLog("debug"))
20836
- console.debug(obj ? `[DEBUG] ${msg} ${JSON.stringify(obj)}` : `[DEBUG] ${msg}`);
20837
- },
20838
- info: (msg, obj) => {
20839
- if (customLogger) {
20840
- customLogger.info(msg, obj);
20841
- return;
20842
- }
20843
- if (shouldLog("info"))
20844
- console.error(obj ? `[INFO] ${msg} ${JSON.stringify(obj)}` : `[INFO] ${msg}`);
20845
- },
20846
- warn: (msg, obj) => {
20847
- if (customLogger) {
20848
- customLogger.warn(msg, obj);
20849
- return;
20850
- }
20851
- if (shouldLog("warn"))
20852
- console.warn(obj ? `[WARN] ${msg} ${JSON.stringify(obj)}` : `[WARN] ${msg}`);
20853
- },
20854
- error: (msg, obj) => {
20855
- if (customLogger) {
20856
- customLogger.error(msg, obj);
20857
- return;
20858
- }
20859
- if (shouldLog("error"))
20860
- console.error(obj ? `[ERROR] ${msg} ${JSON.stringify(obj)}` : `[ERROR] ${msg}`);
20861
- },
20862
- fatal: (msg, obj) => {
20863
- if (customLogger) {
20864
- customLogger.fatal(msg, obj);
20865
- return;
20866
- }
20867
- if (shouldLog("fatal"))
20868
- console.error(obj ? `[FATAL] ${msg} ${JSON.stringify(obj)}` : `[FATAL] ${msg}`);
20869
- },
20870
- isLevelEnabled: (level) => {
20871
- return shouldLog(level);
20872
- }
20873
- };
20874
-
20875
20921
  // ../circle-ir/dist/analysis/passes/cross-file-pass.js
20876
20922
  class CrossFilePass {
20877
20923
  run(projectGraph, sourceLines, options = {}) {
@@ -25016,7 +25062,12 @@ var TIER_1_BY_SUPERTYPE = new Map([
25016
25062
  ["HandlerInterceptor", new Set(["preHandle", "postHandle", "afterCompletion"])],
25017
25063
  ["AsyncHandlerInterceptor", new Set(["preHandle", "postHandle", "afterCompletion", "afterConcurrentHandlingStarted"])],
25018
25064
  ["CommandLineRunner", new Set(["run"])],
25019
- ["ApplicationRunner", new Set(["run"])]
25065
+ ["ApplicationRunner", new Set(["run"])],
25066
+ ["SimpleChannelInboundHandler", new Set(["channelRead0", "messageReceived"])],
25067
+ ["ChannelInboundHandler", new Set(["channelRead", "channelReadComplete"])],
25068
+ ["ChannelInboundHandlerAdapter", new Set(["channelRead", "channelReadComplete"])],
25069
+ ["ChannelDuplexHandler", new Set(["channelRead", "channelReadComplete"])],
25070
+ ["NettyRequestProcessor", new Set(["process"])]
25020
25071
  ]);
25021
25072
  var TIER_3_CLASS_SUFFIXES = [
25022
25073
  "Util",
@@ -25164,6 +25215,10 @@ function shouldGateInterproceduralParam(sourceType, enclosingMethod, enclosingTy
25164
25215
  class InterproceduralPass {
25165
25216
  name = "interprocedural";
25166
25217
  category = "security";
25218
+ enableEntryPointGate;
25219
+ constructor(options) {
25220
+ this.enableEntryPointGate = options?.enableEntryPointGate ?? true;
25221
+ }
25167
25222
  run(ctx) {
25168
25223
  const { graph } = ctx;
25169
25224
  const constProp = ctx.getResult("constant-propagation");
@@ -25222,7 +25277,7 @@ class InterproceduralPass {
25222
25277
  continue;
25223
25278
  if (source.type === "interprocedural_param" && source.confidence < 0.6)
25224
25279
  continue;
25225
- if (source.type === "interprocedural_param" && source.in_method) {
25280
+ if (this.enableEntryPointGate && source.type === "interprocedural_param" && source.in_method) {
25226
25281
  const enclosing = methodNameIndex.get(source.in_method);
25227
25282
  if (shouldGateInterproceduralParam(source.type, enclosing?.method, enclosing?.type, { language, types: graph.ir.types })) {
25228
25283
  continue;
@@ -34212,7 +34267,9 @@ async function analyze(code, filePath, language, options = {}) {
34212
34267
  pipeline.add(new LanguageSourcesPass);
34213
34268
  pipeline.add(new SinkFilterPass);
34214
34269
  pipeline.add(new TaintPropagationPass);
34215
- pipeline.add(new InterproceduralPass);
34270
+ pipeline.add(new InterproceduralPass({
34271
+ enableEntryPointGate: options.enableEntryPointGate ?? true
34272
+ }));
34216
34273
  if (!disabledPasses.has("scan-secrets"))
34217
34274
  pipeline.add(new ScanSecretsPass);
34218
34275
  if (!disabledPasses.has("dead-code"))
@@ -34342,6 +34399,8 @@ async function analyze(code, filePath, language, options = {}) {
34342
34399
  unresolvedItems: unresolved.length
34343
34400
  });
34344
34401
  emitFindingsInstrumentation(filePath, findings, taint);
34402
+ const verifiedFindings = applyConfidenceFilter(findings, options.includeSpeculative === true);
34403
+ const cappedFindings = applyPerFileFindingCap(filePath, verifiedFindings, options.perFileFindingCap ?? DEFAULT_PER_FILE_FINDING_CAP);
34345
34404
  return {
34346
34405
  meta,
34347
34406
  types,
@@ -34353,7 +34412,7 @@ async function analyze(code, filePath, language, options = {}) {
34353
34412
  exports,
34354
34413
  unresolved,
34355
34414
  enriched,
34356
- findings: findings.length > 0 ? findings : undefined,
34415
+ findings: cappedFindings.length > 0 ? cappedFindings : undefined,
34357
34416
  metrics: { file: filePath, metrics: metricValues },
34358
34417
  runtime_registrations: runtimeRegistrations.length > 0 ? runtimeRegistrations : undefined,
34359
34418
  parse_status: parseStatus
@@ -34520,7 +34579,7 @@ var colors = {
34520
34579
  };
34521
34580
 
34522
34581
  // src/version.ts
34523
- var version = "3.91.0";
34582
+ var version = "3.95.0";
34524
34583
 
34525
34584
  // src/formatters.ts
34526
34585
  var SINK_SEVERITY = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cognium-dev",
3
- "version": "3.91.0",
3
+ "version": "3.95.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.91.0"
68
+ "circle-ir": "^3.95.0"
69
69
  },
70
70
  "devDependencies": {
71
71
  "@types/node": "^25.5.0",