cognium-dev 3.202.0 → 3.204.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 +234 -19
  2. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -45953,6 +45953,112 @@ function parseNpmDependencies(packageJson) {
45953
45953
  }
45954
45954
  return out2;
45955
45955
  }
45956
+ function parsePep508(spec) {
45957
+ let s = spec.trim();
45958
+ s = s.split(";")[0].trim();
45959
+ if (!s)
45960
+ return null;
45961
+ const m = s.match(/^([A-Za-z0-9._-]+)\s*(?:\[[^\]]*\])?\s*(.*)$/);
45962
+ if (!m)
45963
+ return null;
45964
+ const rest = m[2].trim();
45965
+ const verMatch = rest.replace(/^\(/, "").match(/^(?:==|>=|<=|~=|!=|>|<|===)?\s*([^,\s)]+)/);
45966
+ const version = verMatch && verMatch[1] ? verMatch[1] : "unknown";
45967
+ return { name: m[1], version };
45968
+ }
45969
+ function parseNpmLockDependencies(packageLock) {
45970
+ if (!packageLock)
45971
+ return [];
45972
+ let parsed;
45973
+ try {
45974
+ parsed = JSON.parse(packageLock);
45975
+ } catch {
45976
+ return [];
45977
+ }
45978
+ if (!parsed || typeof parsed !== "object")
45979
+ return [];
45980
+ const root = parsed;
45981
+ const out2 = [];
45982
+ const scopeOf = (info2) => info2.dev === true ? "dev" : info2.optional === true ? "optional" : "required";
45983
+ const packages = root.packages;
45984
+ if (packages && typeof packages === "object") {
45985
+ for (const [path, raw] of Object.entries(packages)) {
45986
+ if (!path || !raw || typeof raw !== "object")
45987
+ continue;
45988
+ const info2 = raw;
45989
+ const marker = "node_modules/";
45990
+ const idx = path.lastIndexOf(marker);
45991
+ const name2 = idx >= 0 ? path.slice(idx + marker.length) : typeof info2.name === "string" ? info2.name : path;
45992
+ if (!name2)
45993
+ continue;
45994
+ const version = typeof info2.version === "string" ? info2.version : "unknown";
45995
+ out2.push(dep("npm", name2, version, scopeOf(info2)));
45996
+ }
45997
+ } else if (root.dependencies && typeof root.dependencies === "object") {
45998
+ const walk = (deps) => {
45999
+ for (const [name2, raw] of Object.entries(deps)) {
46000
+ if (!raw || typeof raw !== "object")
46001
+ continue;
46002
+ const info2 = raw;
46003
+ const version = typeof info2.version === "string" ? info2.version : "unknown";
46004
+ out2.push(dep("npm", name2, version, scopeOf(info2)));
46005
+ if (info2.dependencies && typeof info2.dependencies === "object") {
46006
+ walk(info2.dependencies);
46007
+ }
46008
+ }
46009
+ };
46010
+ walk(root.dependencies);
46011
+ }
46012
+ const seen = new Set;
46013
+ return out2.filter((d) => {
46014
+ const key = `${d.name}|${d.version}|${d.scope}`;
46015
+ if (seen.has(key))
46016
+ return false;
46017
+ seen.add(key);
46018
+ return true;
46019
+ });
46020
+ }
46021
+ function parseTomlPackageArray(content, ecosystem) {
46022
+ const out2 = [];
46023
+ let name2 = null;
46024
+ let version = null;
46025
+ let inPackage = false;
46026
+ const flush = () => {
46027
+ if (inPackage && name2 && version)
46028
+ out2.push(dep(ecosystem, name2, version, "required"));
46029
+ name2 = null;
46030
+ version = null;
46031
+ };
46032
+ for (const raw of content.split(/\r?\n/)) {
46033
+ const line = raw.trim();
46034
+ if (line === "[[package]]") {
46035
+ flush();
46036
+ inPackage = true;
46037
+ continue;
46038
+ }
46039
+ if (line.startsWith("[")) {
46040
+ flush();
46041
+ inPackage = false;
46042
+ continue;
46043
+ }
46044
+ if (!inPackage)
46045
+ continue;
46046
+ const nm = line.match(/^name\s*=\s*"([^"]+)"/);
46047
+ if (nm)
46048
+ name2 = nm[1];
46049
+ const vm = line.match(/^version\s*=\s*"([^"]+)"/);
46050
+ if (vm)
46051
+ version = vm[1];
46052
+ }
46053
+ flush();
46054
+ return out2;
46055
+ }
46056
+ function parseCargoLockDependencies(cargoLock) {
46057
+ return cargoLock ? parseTomlPackageArray(cargoLock, "cargo") : [];
46058
+ }
46059
+ function parsePoetryLockDependencies(poetryLock) {
46060
+ return poetryLock ? parseTomlPackageArray(poetryLock, "pypi") : [];
46061
+ }
45956
46062
  function parsePypiDependencies(requirementsTxt) {
45957
46063
  if (!requirementsTxt)
45958
46064
  return [];
@@ -45964,17 +46070,101 @@ function parsePypiDependencies(requirementsTxt) {
45964
46070
  if (line.startsWith("-") || /^[a-z]+:\/\//i.test(line))
45965
46071
  continue;
45966
46072
  line = line.split("#")[0].trim();
45967
- line = line.split(";")[0].trim();
45968
46073
  if (!line)
45969
46074
  continue;
45970
- const m = line.match(/^([A-Za-z0-9._-]+)\s*(?:\[[^\]]*\])?\s*(.*)$/);
45971
- if (!m)
46075
+ const parsed = parsePep508(line);
46076
+ if (parsed)
46077
+ out2.push(dep("pypi", parsed.name, parsed.version, "required"));
46078
+ }
46079
+ return out2;
46080
+ }
46081
+ function parsePyprojectDependencies(pyprojectToml) {
46082
+ if (!pyprojectToml)
46083
+ return [];
46084
+ const out2 = [];
46085
+ const lines = pyprojectToml.split(/\r?\n/);
46086
+ let table = "";
46087
+ let poetryScope = null;
46088
+ let inArray = false;
46089
+ let arrayScope = "required";
46090
+ const pushReq = (raw, scope) => {
46091
+ const cleaned = raw.trim().replace(/^["']|["'],?$/g, "").replace(/,$/, "").trim();
46092
+ if (!cleaned)
46093
+ return;
46094
+ const parsed = parsePep508(cleaned);
46095
+ if (parsed && parsed.name.toLowerCase() !== "python")
46096
+ out2.push(dep("pypi", parsed.name, parsed.version, scope));
46097
+ };
46098
+ for (const raw of lines) {
46099
+ const line = raw.trim();
46100
+ if (!line || line.startsWith("#"))
45972
46101
  continue;
45973
- const name2 = m[1];
45974
- const rest = m[2].trim();
45975
- const verMatch = rest.match(/^(?:==|>=|<=|~=|!=|>|<|===)?\s*([^,\s]+)/);
45976
- const version = verMatch && verMatch[1] ? verMatch[1] : "unknown";
45977
- out2.push(dep("pypi", name2, version, "required"));
46102
+ if (inArray) {
46103
+ if (line.startsWith("]")) {
46104
+ inArray = false;
46105
+ continue;
46106
+ }
46107
+ pushReq(line, arrayScope);
46108
+ continue;
46109
+ }
46110
+ const header = line.match(/^\[([^\]]+)\]$/);
46111
+ if (header) {
46112
+ table = header[1];
46113
+ if (table === "tool.poetry.dependencies")
46114
+ poetryScope = "required";
46115
+ else if (/^tool\.poetry\.(dev-dependencies|group\..+\.dependencies)$/.test(table))
46116
+ poetryScope = "dev";
46117
+ else
46118
+ poetryScope = null;
46119
+ continue;
46120
+ }
46121
+ const arrayOpen = line.match(/^(dependencies|[A-Za-z0-9._-]+)\s*=\s*\[(.*)$/);
46122
+ if (arrayOpen && (arrayOpen[1] === "dependencies" || table === "project.optional-dependencies")) {
46123
+ arrayScope = arrayOpen[1] === "dependencies" ? "required" : "optional";
46124
+ const inline = arrayOpen[2];
46125
+ if (inline.includes("]")) {
46126
+ for (const item of inline.slice(0, inline.indexOf("]")).split(","))
46127
+ pushReq(item, arrayScope);
46128
+ } else {
46129
+ inArray = true;
46130
+ if (inline.trim())
46131
+ pushReq(inline, arrayScope);
46132
+ }
46133
+ continue;
46134
+ }
46135
+ if (poetryScope) {
46136
+ const kv = line.match(/^([A-Za-z0-9._-]+)\s*=\s*(.+)$/);
46137
+ if (!kv || kv[1].toLowerCase() === "python")
46138
+ continue;
46139
+ let version = "unknown";
46140
+ const strv = kv[2].match(/^["']([^"']+)["']/);
46141
+ if (strv)
46142
+ version = strv[1];
46143
+ else {
46144
+ const inlinev = kv[2].match(/version\s*=\s*["']([^"']+)["']/);
46145
+ if (inlinev)
46146
+ version = inlinev[1];
46147
+ }
46148
+ out2.push(dep("pypi", kv[1], version, poetryScope));
46149
+ }
46150
+ }
46151
+ return out2;
46152
+ }
46153
+ function parseGradleDependencies(buildGradle) {
46154
+ if (!buildGradle)
46155
+ return [];
46156
+ const out2 = [];
46157
+ const re = /\b(implementation|api|compileOnly|compileOnlyApi|runtimeOnly|testImplementation|testCompileOnly|testRuntimeOnly|annotationProcessor|kapt|classpath)\s*[(\s]\s*['"]([\w.-]+:[\w.-]+(?::[\w.\-+]+)?)['"]/g;
46158
+ let m;
46159
+ while ((m = re.exec(buildGradle)) !== null) {
46160
+ const config = m[1];
46161
+ const coord = m[2].split(":");
46162
+ if (coord.length < 2)
46163
+ continue;
46164
+ const name2 = `${coord[0]}:${coord[1]}`;
46165
+ const version = coord[2] ?? "unknown";
46166
+ const scope = config.startsWith("test") ? "dev" : "required";
46167
+ out2.push(dep("maven", name2, version, scope));
45978
46168
  }
45979
46169
  return out2;
45980
46170
  }
@@ -46753,7 +46943,7 @@ var colors = {
46753
46943
  };
46754
46944
 
46755
46945
  // src/version.ts
46756
- var version = "3.202.0";
46946
+ var version = "3.204.0";
46757
46947
 
46758
46948
  // src/formatters.ts
46759
46949
  var LIBRARY_API_SURFACE_TAG2 = "library-api-surface:caller-responsibility";
@@ -47411,7 +47601,10 @@ SBOM OPTIONS:
47411
47601
  --prod-only Exclude dev/test dependencies
47412
47602
  --deterministic Omit timestamp / serialNumber / namespace for reproducible output
47413
47603
  -o, --output <file> Write the document to a file (default: stdout)
47414
- Discovers package.json / requirements.txt / pom.xml / Cargo.toml / go.mod.
47604
+ Discovers package.json / requirements.txt / pyproject.toml /
47605
+ pom.xml / build.gradle(.kts) / Cargo.toml / go.mod.
47606
+ A package-lock.json supersedes its package.json
47607
+ (exact + transitive versions).
47415
47608
  CVE matching is out of scope (deterministic SAST — no network).
47416
47609
 
47417
47610
  EXAMPLES:
@@ -48451,11 +48644,24 @@ function parseCrossFileBudgetMs(raw) {
48451
48644
  }
48452
48645
  var SBOM_MANIFESTS = {
48453
48646
  "package.json": parseNpmDependencies,
48647
+ "package-lock.json": parseNpmLockDependencies,
48648
+ "npm-shrinkwrap.json": parseNpmLockDependencies,
48454
48649
  "requirements.txt": parsePypiDependencies,
48650
+ "pyproject.toml": parsePyprojectDependencies,
48651
+ "poetry.lock": parsePoetryLockDependencies,
48455
48652
  "pom.xml": parseMavenDependencies,
48653
+ "build.gradle": parseGradleDependencies,
48654
+ "build.gradle.kts": parseGradleDependencies,
48456
48655
  "Cargo.toml": parseCargoDependencies,
48656
+ "Cargo.lock": parseCargoLockDependencies,
48457
48657
  "go.mod": parseGoDependencies
48458
48658
  };
48659
+ var SBOM_SUPERSEDES = {
48660
+ "package-lock.json": "package.json",
48661
+ "npm-shrinkwrap.json": "package.json",
48662
+ "poetry.lock": "pyproject.toml",
48663
+ "Cargo.lock": "Cargo.toml"
48664
+ };
48459
48665
  var SBOM_SKIP_DIRS = /^(node_modules|vendor|target|dist|build|out|coverage)$/;
48460
48666
  async function collectManifestFiles(targetPath) {
48461
48667
  const found = [];
@@ -48489,22 +48695,31 @@ async function runSbom(targetPath, options) {
48489
48695
  }
48490
48696
  const manifests = await collectManifestFiles(absPath);
48491
48697
  if (manifests.length === 0) {
48492
- console.error(colors.red("Error: no supported manifests found (package.json, requirements.txt, pom.xml, Cargo.toml, go.mod)"));
48698
+ console.error(colors.red("Error: no supported manifests found (package.json/-lock, requirements.txt, pyproject.toml, poetry.lock, pom.xml, build.gradle, Cargo.toml/.lock, go.mod)"));
48493
48699
  process.exit(1);
48494
48700
  }
48495
- let deps = [];
48496
- let projectName = options.name;
48701
+ const supersededInDir = new Set;
48497
48702
  for (const m of manifests) {
48498
- const content = readFileSync(m, "utf-8");
48499
- deps.push(...SBOM_MANIFESTS[basename(m)](content));
48500
- if (!projectName && basename(m) === "package.json") {
48703
+ const superseded = SBOM_SUPERSEDES[basename(m)];
48704
+ if (superseded)
48705
+ supersededInDir.add(`${dirname3(m)}\x00${superseded}`);
48706
+ }
48707
+ const effective = manifests.filter((m) => !supersededInDir.has(`${dirname3(m)}\x00${basename(m)}`));
48708
+ let projectName = options.name;
48709
+ if (!projectName) {
48710
+ const pkg = manifests.find((m) => basename(m) === "package.json");
48711
+ if (pkg) {
48501
48712
  try {
48502
- const n = JSON.parse(content).name;
48713
+ const n = JSON.parse(readFileSync(pkg, "utf-8")).name;
48503
48714
  if (typeof n === "string" && n)
48504
48715
  projectName = n;
48505
48716
  } catch {}
48506
48717
  }
48507
48718
  }
48719
+ let deps = [];
48720
+ for (const m of effective) {
48721
+ deps.push(...SBOM_MANIFESTS[basename(m)](readFileSync(m, "utf-8")));
48722
+ }
48508
48723
  const seen = new Set;
48509
48724
  deps = deps.filter((d) => {
48510
48725
  const key = `${d.ecosystem}|${d.name}|${d.version}|${d.scope}`;
@@ -48528,10 +48743,10 @@ async function runSbom(targetPath, options) {
48528
48743
  const out2 = JSON.stringify(doc, null, 2);
48529
48744
  if (options.output) {
48530
48745
  writeFileSync(options.output, out2);
48531
- console.error(colors.green(`SBOM written to ${options.output} — ${deps.length} dependencies from ${manifests.length} manifest(s)`));
48746
+ console.error(colors.green(`SBOM written to ${options.output} — ${deps.length} dependencies from ${effective.length} manifest(s)`));
48532
48747
  } else {
48533
48748
  console.log(out2);
48534
- console.error(colors.green(`SBOM: ${deps.length} dependencies from ${manifests.length} manifest(s)`));
48749
+ console.error(colors.green(`SBOM: ${deps.length} dependencies from ${effective.length} manifest(s)`));
48535
48750
  }
48536
48751
  process.exit(0);
48537
48752
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cognium-dev",
3
- "version": "3.202.0",
3
+ "version": "3.204.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",
@@ -66,7 +66,7 @@
66
66
  },
67
67
  "dependencies": {
68
68
  "@cognium/project-profile-detect": "^1.1.0",
69
- "circle-ir": "^3.202.0"
69
+ "circle-ir": "^3.204.0"
70
70
  },
71
71
  "devDependencies": {
72
72
  "@types/node": "^25.5.0",