@sentriflow/cli 0.1.7 → 0.1.8
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/index.js +422 -14
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -10334,6 +10334,350 @@ function validateRegex(pattern, flags, path, ctx) {
|
|
|
10334
10334
|
}
|
|
10335
10335
|
}
|
|
10336
10336
|
|
|
10337
|
+
// ../core/src/ip/extractor.ts
|
|
10338
|
+
function isValidIPv4(ip) {
|
|
10339
|
+
if (!ip || typeof ip !== "string") return false;
|
|
10340
|
+
const octets = ip.split(".");
|
|
10341
|
+
if (octets.length !== 4) return false;
|
|
10342
|
+
for (const octet of octets) {
|
|
10343
|
+
if (!/^\d+$/.test(octet)) return false;
|
|
10344
|
+
if (octet.length > 1 && octet.startsWith("0")) return false;
|
|
10345
|
+
const num = parseInt(octet, 10);
|
|
10346
|
+
if (isNaN(num) || num < 0 || num > 255) return false;
|
|
10347
|
+
}
|
|
10348
|
+
return true;
|
|
10349
|
+
}
|
|
10350
|
+
function isValidIPv6(ip) {
|
|
10351
|
+
if (!ip || typeof ip !== "string") return false;
|
|
10352
|
+
let addr = ip;
|
|
10353
|
+
const zoneIndex = ip.indexOf("%");
|
|
10354
|
+
if (zoneIndex !== -1) {
|
|
10355
|
+
addr = ip.substring(0, zoneIndex);
|
|
10356
|
+
}
|
|
10357
|
+
if (!addr.includes(":")) return false;
|
|
10358
|
+
if (addr.includes(":::")) return false;
|
|
10359
|
+
const doubleColonCount = (addr.match(/::/g) || []).length;
|
|
10360
|
+
if (doubleColonCount > 1) return false;
|
|
10361
|
+
const parts = addr.split(":");
|
|
10362
|
+
if (doubleColonCount === 1) {
|
|
10363
|
+
const nonEmptyParts = parts.filter((p) => p !== "");
|
|
10364
|
+
for (const part of nonEmptyParts) {
|
|
10365
|
+
if (!/^[0-9a-fA-F]{1,4}$/.test(part)) return false;
|
|
10366
|
+
}
|
|
10367
|
+
if (nonEmptyParts.length > 7) return false;
|
|
10368
|
+
} else {
|
|
10369
|
+
if (parts.length !== 8) return false;
|
|
10370
|
+
for (const part of parts) {
|
|
10371
|
+
if (!/^[0-9a-fA-F]{1,4}$/.test(part)) return false;
|
|
10372
|
+
}
|
|
10373
|
+
}
|
|
10374
|
+
return true;
|
|
10375
|
+
}
|
|
10376
|
+
function isValidSubnet(subnet) {
|
|
10377
|
+
if (!subnet || typeof subnet !== "string") return false;
|
|
10378
|
+
const slashIndex = subnet.lastIndexOf("/");
|
|
10379
|
+
if (slashIndex === -1) return false;
|
|
10380
|
+
const ip = subnet.substring(0, slashIndex);
|
|
10381
|
+
const prefixStr = subnet.substring(slashIndex + 1);
|
|
10382
|
+
if (!/^\d+$/.test(prefixStr)) return false;
|
|
10383
|
+
const prefix = parseInt(prefixStr, 10);
|
|
10384
|
+
if (isValidIPv4(ip)) {
|
|
10385
|
+
return prefix >= 0 && prefix <= 32;
|
|
10386
|
+
} else if (isValidIPv6(ip)) {
|
|
10387
|
+
return prefix >= 0 && prefix <= 128;
|
|
10388
|
+
}
|
|
10389
|
+
return false;
|
|
10390
|
+
}
|
|
10391
|
+
function normalizeIPv4(ip) {
|
|
10392
|
+
return ip.split(".").map((octet) => parseInt(octet, 10).toString()).join(".");
|
|
10393
|
+
}
|
|
10394
|
+
function normalizeIPv6(ip) {
|
|
10395
|
+
let addr = ip;
|
|
10396
|
+
const zoneIndex = ip.indexOf("%");
|
|
10397
|
+
if (zoneIndex !== -1) {
|
|
10398
|
+
addr = ip.substring(0, zoneIndex);
|
|
10399
|
+
}
|
|
10400
|
+
addr = addr.toLowerCase();
|
|
10401
|
+
if (addr.includes("::")) {
|
|
10402
|
+
const sides = addr.split("::");
|
|
10403
|
+
const left = sides[0] ? sides[0].split(":").filter((p) => p !== "") : [];
|
|
10404
|
+
const right = sides[1] ? sides[1].split(":").filter((p) => p !== "") : [];
|
|
10405
|
+
const zerosNeeded = 8 - left.length - right.length;
|
|
10406
|
+
const expanded = [];
|
|
10407
|
+
for (const part of left) {
|
|
10408
|
+
expanded.push(parseInt(part, 16).toString(16));
|
|
10409
|
+
}
|
|
10410
|
+
for (let i = 0; i < zerosNeeded; i++) {
|
|
10411
|
+
expanded.push("0");
|
|
10412
|
+
}
|
|
10413
|
+
for (const part of right) {
|
|
10414
|
+
expanded.push(parseInt(part, 16).toString(16));
|
|
10415
|
+
}
|
|
10416
|
+
return expanded.join(":");
|
|
10417
|
+
}
|
|
10418
|
+
const parts = addr.split(":");
|
|
10419
|
+
const result = [];
|
|
10420
|
+
for (const part of parts) {
|
|
10421
|
+
if (part !== "") {
|
|
10422
|
+
result.push(parseInt(part, 16).toString(16));
|
|
10423
|
+
}
|
|
10424
|
+
}
|
|
10425
|
+
return result.join(":");
|
|
10426
|
+
}
|
|
10427
|
+
function ipv4ToNumber(ip) {
|
|
10428
|
+
const octets = ip.split(".").map(Number);
|
|
10429
|
+
const o0 = octets[0] ?? 0;
|
|
10430
|
+
const o1 = octets[1] ?? 0;
|
|
10431
|
+
const o2 = octets[2] ?? 0;
|
|
10432
|
+
const o3 = octets[3] ?? 0;
|
|
10433
|
+
return (o0 << 24 >>> 0) + (o1 << 16) + (o2 << 8) + o3;
|
|
10434
|
+
}
|
|
10435
|
+
function compareIPv4(a, b) {
|
|
10436
|
+
const numA = ipv4ToNumber(a);
|
|
10437
|
+
const numB = ipv4ToNumber(b);
|
|
10438
|
+
return numA < numB ? -1 : numA > numB ? 1 : 0;
|
|
10439
|
+
}
|
|
10440
|
+
function expandIPv6(ip) {
|
|
10441
|
+
let addr = ip;
|
|
10442
|
+
const zoneIndex = ip.indexOf("%");
|
|
10443
|
+
if (zoneIndex !== -1) {
|
|
10444
|
+
addr = ip.substring(0, zoneIndex);
|
|
10445
|
+
}
|
|
10446
|
+
const parts = addr.split(":");
|
|
10447
|
+
const result = [];
|
|
10448
|
+
for (let i = 0; i < parts.length; i++) {
|
|
10449
|
+
if (parts[i] === "" && i > 0 && i < parts.length - 1) {
|
|
10450
|
+
const nonEmpty = parts.filter((p) => p !== "").length;
|
|
10451
|
+
const zeros = 8 - nonEmpty;
|
|
10452
|
+
for (let j = 0; j < zeros; j++) {
|
|
10453
|
+
result.push("0");
|
|
10454
|
+
}
|
|
10455
|
+
} else if (parts[i] !== "") {
|
|
10456
|
+
result.push(parts[i] ?? "0");
|
|
10457
|
+
} else if (i === 0 && parts[1] === "") {
|
|
10458
|
+
const nonEmpty = parts.filter((p) => p !== "").length;
|
|
10459
|
+
const zeros = 8 - nonEmpty;
|
|
10460
|
+
for (let j = 0; j < zeros; j++) {
|
|
10461
|
+
result.push("0");
|
|
10462
|
+
}
|
|
10463
|
+
} else if (i === parts.length - 1 && parts[i - 1] === "") {
|
|
10464
|
+
}
|
|
10465
|
+
}
|
|
10466
|
+
while (result.length < 8) {
|
|
10467
|
+
result.push("0");
|
|
10468
|
+
}
|
|
10469
|
+
return result.slice(0, 8);
|
|
10470
|
+
}
|
|
10471
|
+
function ipv6ToBigInt(ip) {
|
|
10472
|
+
const parts = expandIPv6(ip);
|
|
10473
|
+
let result = 0n;
|
|
10474
|
+
for (const part of parts) {
|
|
10475
|
+
result = (result << 16n) + BigInt(parseInt(part, 16) || 0);
|
|
10476
|
+
}
|
|
10477
|
+
return result;
|
|
10478
|
+
}
|
|
10479
|
+
function compareIPv6(a, b) {
|
|
10480
|
+
const bigA = ipv6ToBigInt(a);
|
|
10481
|
+
const bigB = ipv6ToBigInt(b);
|
|
10482
|
+
return bigA < bigB ? -1 : bigA > bigB ? 1 : 0;
|
|
10483
|
+
}
|
|
10484
|
+
function sortIPv4Addresses(ips) {
|
|
10485
|
+
return [...ips].sort(compareIPv4);
|
|
10486
|
+
}
|
|
10487
|
+
function sortIPv6Addresses(ips) {
|
|
10488
|
+
return [...ips].sort(compareIPv6);
|
|
10489
|
+
}
|
|
10490
|
+
function parseSubnet(subnet) {
|
|
10491
|
+
const slashIndex = subnet.lastIndexOf("/");
|
|
10492
|
+
return {
|
|
10493
|
+
network: subnet.substring(0, slashIndex),
|
|
10494
|
+
prefix: parseInt(subnet.substring(slashIndex + 1), 10)
|
|
10495
|
+
};
|
|
10496
|
+
}
|
|
10497
|
+
function sortSubnets(subnets, type) {
|
|
10498
|
+
const compare = type === "ipv4" ? compareIPv4 : compareIPv6;
|
|
10499
|
+
return [...subnets].sort((a, b) => {
|
|
10500
|
+
const subA = parseSubnet(a);
|
|
10501
|
+
const subB = parseSubnet(b);
|
|
10502
|
+
const netCompare = compare(subA.network, subB.network);
|
|
10503
|
+
if (netCompare !== 0) return netCompare;
|
|
10504
|
+
return subA.prefix - subB.prefix;
|
|
10505
|
+
});
|
|
10506
|
+
}
|
|
10507
|
+
function isSubnetMask(ip) {
|
|
10508
|
+
if (!ip.startsWith("255.")) return false;
|
|
10509
|
+
const octets = ip.split(".").map(Number);
|
|
10510
|
+
const num = ((octets[0] ?? 0) << 24) + ((octets[1] ?? 0) << 16) + ((octets[2] ?? 0) << 8) + (octets[3] ?? 0);
|
|
10511
|
+
const inverted = ~num >>> 0;
|
|
10512
|
+
return inverted === 0 || (inverted & inverted + 1) === 0;
|
|
10513
|
+
}
|
|
10514
|
+
function isWildcardMask(ip) {
|
|
10515
|
+
if (!ip.startsWith("0.")) return false;
|
|
10516
|
+
const octets = ip.split(".").map(Number);
|
|
10517
|
+
const num = ((octets[0] ?? 0) << 24) + ((octets[1] ?? 0) << 16) + ((octets[2] ?? 0) << 8) + (octets[3] ?? 0);
|
|
10518
|
+
return num === 0 || (num + 1 & num) === 0;
|
|
10519
|
+
}
|
|
10520
|
+
function maskToCidr(mask) {
|
|
10521
|
+
if (!isSubnetMask(mask)) return -1;
|
|
10522
|
+
const octets = mask.split(".").map(Number);
|
|
10523
|
+
const num = ((octets[0] ?? 0) << 24) + ((octets[1] ?? 0) << 16) + ((octets[2] ?? 0) << 8) + (octets[3] ?? 0);
|
|
10524
|
+
let prefix = 0;
|
|
10525
|
+
let n = num >>> 0;
|
|
10526
|
+
while (n & 2147483648) {
|
|
10527
|
+
prefix++;
|
|
10528
|
+
n = n << 1 >>> 0;
|
|
10529
|
+
}
|
|
10530
|
+
return prefix;
|
|
10531
|
+
}
|
|
10532
|
+
function wildcardToCidr(wildcard) {
|
|
10533
|
+
if (!isWildcardMask(wildcard)) return -1;
|
|
10534
|
+
const octets = wildcard.split(".").map(Number);
|
|
10535
|
+
const num = ((octets[0] ?? 0) << 24) + ((octets[1] ?? 0) << 16) + ((octets[2] ?? 0) << 8) + (octets[3] ?? 0);
|
|
10536
|
+
let prefix = 0;
|
|
10537
|
+
let n = num >>> 0;
|
|
10538
|
+
while (prefix < 32 && !(n & 2147483648)) {
|
|
10539
|
+
prefix++;
|
|
10540
|
+
n = n << 1 >>> 0;
|
|
10541
|
+
}
|
|
10542
|
+
return prefix;
|
|
10543
|
+
}
|
|
10544
|
+
var IPV4_PATTERN = /\b(?:(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\b/g;
|
|
10545
|
+
var IPV4_CIDR_PATTERN = /\b(?:(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\/(?:3[0-2]|[12]?[0-9])\b/g;
|
|
10546
|
+
var IPV4_WITH_MASK_PATTERN = /\b((?:(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9]))\s+(255\.(?:(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\.){2}(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9]))\b/g;
|
|
10547
|
+
var IPV4_WITH_MASK_KEYWORD_PATTERN = /\b((?:(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9]))\s+mask\s+(255\.(?:(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\.){2}(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9]))\b/gi;
|
|
10548
|
+
var IPV4_WITH_WILDCARD_PATTERN = /\b((?:(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9]))\s+(0\.(?:(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\.){2}(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9]))\b/g;
|
|
10549
|
+
var IPV6_PATTERN = /(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|:(?::[0-9a-fA-F]{1,4}){1,7}|(?:[0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,5}(?::[0-9a-fA-F]{1,4}){1,2}|(?:[0-9a-fA-F]{1,4}:){1,4}(?::[0-9a-fA-F]{1,4}){1,3}|(?:[0-9a-fA-F]{1,4}:){1,3}(?::[0-9a-fA-F]{1,4}){1,4}|(?:[0-9a-fA-F]{1,4}:){1,2}(?::[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:(?::[0-9a-fA-F]{1,4}){1,6}|(?:[0-9a-fA-F]{1,4}:){1,7}:|::/g;
|
|
10550
|
+
var IPV6_CIDR_PATTERN = /(?:(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|:(?::[0-9a-fA-F]{1,4}){1,7}|(?:[0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,5}(?::[0-9a-fA-F]{1,4}){1,2}|(?:[0-9a-fA-F]{1,4}:){1,4}(?::[0-9a-fA-F]{1,4}){1,3}|(?:[0-9a-fA-F]{1,4}:){1,3}(?::[0-9a-fA-F]{1,4}){1,4}|(?:[0-9a-fA-F]{1,4}:){1,2}(?::[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:(?::[0-9a-fA-F]{1,4}){1,6}|(?:[0-9a-fA-F]{1,4}:){1,7}:|::)\/(?:12[0-8]|1[01][0-9]|[1-9]?[0-9])/g;
|
|
10551
|
+
function createEmptyIPSummary() {
|
|
10552
|
+
return {
|
|
10553
|
+
ipv4Addresses: [],
|
|
10554
|
+
ipv6Addresses: [],
|
|
10555
|
+
ipv4Subnets: [],
|
|
10556
|
+
ipv6Subnets: [],
|
|
10557
|
+
counts: {
|
|
10558
|
+
ipv4: 0,
|
|
10559
|
+
ipv6: 0,
|
|
10560
|
+
ipv4Subnets: 0,
|
|
10561
|
+
ipv6Subnets: 0,
|
|
10562
|
+
total: 0
|
|
10563
|
+
}
|
|
10564
|
+
};
|
|
10565
|
+
}
|
|
10566
|
+
function extractIPSummary(content, options = {}) {
|
|
10567
|
+
if (!content || typeof content !== "string") {
|
|
10568
|
+
return createEmptyIPSummary();
|
|
10569
|
+
}
|
|
10570
|
+
const ipv4Set = /* @__PURE__ */ new Set();
|
|
10571
|
+
const ipv6Set = /* @__PURE__ */ new Set();
|
|
10572
|
+
const ipv4SubnetSet = /* @__PURE__ */ new Set();
|
|
10573
|
+
const ipv6SubnetSet = /* @__PURE__ */ new Set();
|
|
10574
|
+
const subnetNetworks = /* @__PURE__ */ new Set();
|
|
10575
|
+
const ipsWithMasks = /* @__PURE__ */ new Set();
|
|
10576
|
+
if (!options.skipSubnets) {
|
|
10577
|
+
const ipv4CidrMatches = content.matchAll(IPV4_CIDR_PATTERN);
|
|
10578
|
+
for (const match of ipv4CidrMatches) {
|
|
10579
|
+
const subnet = match[0];
|
|
10580
|
+
if (isValidSubnet(subnet)) {
|
|
10581
|
+
const { network } = parseSubnet(subnet);
|
|
10582
|
+
const normalizedNetwork = normalizeIPv4(network);
|
|
10583
|
+
ipv4SubnetSet.add(`${normalizedNetwork}/${parseSubnet(subnet).prefix}`);
|
|
10584
|
+
subnetNetworks.add(normalizedNetwork);
|
|
10585
|
+
}
|
|
10586
|
+
}
|
|
10587
|
+
const ipMaskMatches = content.matchAll(IPV4_WITH_MASK_PATTERN);
|
|
10588
|
+
for (const match of ipMaskMatches) {
|
|
10589
|
+
const ip = match[1];
|
|
10590
|
+
const mask = match[2];
|
|
10591
|
+
if (ip && mask && isValidIPv4(ip) && isSubnetMask(mask)) {
|
|
10592
|
+
const normalizedIP = normalizeIPv4(ip);
|
|
10593
|
+
const prefix = maskToCidr(mask);
|
|
10594
|
+
if (prefix >= 0) {
|
|
10595
|
+
ipv4SubnetSet.add(`${normalizedIP}/${prefix}`);
|
|
10596
|
+
ipsWithMasks.add(normalizedIP);
|
|
10597
|
+
}
|
|
10598
|
+
}
|
|
10599
|
+
}
|
|
10600
|
+
const ipMaskKeywordMatches = content.matchAll(IPV4_WITH_MASK_KEYWORD_PATTERN);
|
|
10601
|
+
for (const match of ipMaskKeywordMatches) {
|
|
10602
|
+
const ip = match[1];
|
|
10603
|
+
const mask = match[2];
|
|
10604
|
+
if (ip && mask && isValidIPv4(ip) && isSubnetMask(mask)) {
|
|
10605
|
+
const normalizedIP = normalizeIPv4(ip);
|
|
10606
|
+
const prefix = maskToCidr(mask);
|
|
10607
|
+
if (prefix >= 0) {
|
|
10608
|
+
ipv4SubnetSet.add(`${normalizedIP}/${prefix}`);
|
|
10609
|
+
ipsWithMasks.add(normalizedIP);
|
|
10610
|
+
}
|
|
10611
|
+
}
|
|
10612
|
+
}
|
|
10613
|
+
const ipWildcardMatches = content.matchAll(IPV4_WITH_WILDCARD_PATTERN);
|
|
10614
|
+
for (const match of ipWildcardMatches) {
|
|
10615
|
+
const ip = match[1];
|
|
10616
|
+
const wildcard = match[2];
|
|
10617
|
+
if (ip && wildcard && isValidIPv4(ip) && isWildcardMask(wildcard)) {
|
|
10618
|
+
const normalizedIP = normalizeIPv4(ip);
|
|
10619
|
+
const prefix = wildcardToCidr(wildcard);
|
|
10620
|
+
if (prefix >= 0) {
|
|
10621
|
+
ipv4SubnetSet.add(`${normalizedIP}/${prefix}`);
|
|
10622
|
+
ipsWithMasks.add(normalizedIP);
|
|
10623
|
+
}
|
|
10624
|
+
}
|
|
10625
|
+
}
|
|
10626
|
+
}
|
|
10627
|
+
const ipv4Matches = content.matchAll(IPV4_PATTERN);
|
|
10628
|
+
for (const match of ipv4Matches) {
|
|
10629
|
+
const ip = match[0];
|
|
10630
|
+
if (isValidIPv4(ip)) {
|
|
10631
|
+
const normalized = normalizeIPv4(ip);
|
|
10632
|
+
if (!subnetNetworks.has(normalized) && !ipsWithMasks.has(normalized) && !isSubnetMask(normalized) && !isWildcardMask(normalized)) {
|
|
10633
|
+
ipv4Set.add(normalized);
|
|
10634
|
+
}
|
|
10635
|
+
}
|
|
10636
|
+
}
|
|
10637
|
+
if (!options.skipIPv6) {
|
|
10638
|
+
if (!options.skipSubnets) {
|
|
10639
|
+
const ipv6CidrMatches = content.matchAll(IPV6_CIDR_PATTERN);
|
|
10640
|
+
for (const match of ipv6CidrMatches) {
|
|
10641
|
+
const subnet = match[0];
|
|
10642
|
+
if (isValidSubnet(subnet)) {
|
|
10643
|
+
const { network, prefix } = parseSubnet(subnet);
|
|
10644
|
+
const normalizedNetwork = normalizeIPv6(network);
|
|
10645
|
+
ipv6SubnetSet.add(`${normalizedNetwork}/${prefix}`);
|
|
10646
|
+
subnetNetworks.add(normalizedNetwork);
|
|
10647
|
+
}
|
|
10648
|
+
}
|
|
10649
|
+
}
|
|
10650
|
+
const ipv6Matches = content.matchAll(IPV6_PATTERN);
|
|
10651
|
+
for (const match of ipv6Matches) {
|
|
10652
|
+
const ip = match[0];
|
|
10653
|
+
if (isValidIPv6(ip)) {
|
|
10654
|
+
const normalized = normalizeIPv6(ip);
|
|
10655
|
+
if (!subnetNetworks.has(normalized)) {
|
|
10656
|
+
ipv6Set.add(normalized);
|
|
10657
|
+
}
|
|
10658
|
+
}
|
|
10659
|
+
}
|
|
10660
|
+
}
|
|
10661
|
+
const ipv4Addresses = sortIPv4Addresses([...ipv4Set]);
|
|
10662
|
+
const ipv6Addresses = sortIPv6Addresses([...ipv6Set]);
|
|
10663
|
+
const ipv4Subnets = sortSubnets([...ipv4SubnetSet], "ipv4");
|
|
10664
|
+
const ipv6Subnets = sortSubnets([...ipv6SubnetSet], "ipv6");
|
|
10665
|
+
const counts = {
|
|
10666
|
+
ipv4: ipv4Addresses.length,
|
|
10667
|
+
ipv6: ipv6Addresses.length,
|
|
10668
|
+
ipv4Subnets: ipv4Subnets.length,
|
|
10669
|
+
ipv6Subnets: ipv6Subnets.length,
|
|
10670
|
+
total: ipv4Addresses.length + ipv6Addresses.length + ipv4Subnets.length + ipv6Subnets.length
|
|
10671
|
+
};
|
|
10672
|
+
return {
|
|
10673
|
+
ipv4Addresses,
|
|
10674
|
+
ipv6Addresses,
|
|
10675
|
+
ipv4Subnets,
|
|
10676
|
+
ipv6Subnets,
|
|
10677
|
+
counts
|
|
10678
|
+
};
|
|
10679
|
+
}
|
|
10680
|
+
|
|
10337
10681
|
// index.ts
|
|
10338
10682
|
import { readFile } from "fs/promises";
|
|
10339
10683
|
import { statSync as statSync2 } from "fs";
|
|
@@ -10341,7 +10685,7 @@ import { resolve as resolve4, dirname as dirname2, basename } from "path";
|
|
|
10341
10685
|
|
|
10342
10686
|
// src/sarif.ts
|
|
10343
10687
|
import { relative } from "path";
|
|
10344
|
-
function generateSarif(results, filePath, rules, options = {}) {
|
|
10688
|
+
function generateSarif(results, filePath, rules, options = {}, ipSummary) {
|
|
10345
10689
|
const fileUri = options.relativePaths ? relative(options.baseDir ?? process.cwd(), filePath) : filePath;
|
|
10346
10690
|
const sarifResults = results.map((result) => {
|
|
10347
10691
|
return {
|
|
@@ -10408,7 +10752,7 @@ function generateSarif(results, filePath, rules, options = {}) {
|
|
|
10408
10752
|
tool: {
|
|
10409
10753
|
driver: {
|
|
10410
10754
|
name: "Sentriflow",
|
|
10411
|
-
version: "0.1.
|
|
10755
|
+
version: "0.1.8",
|
|
10412
10756
|
informationUri: "https://github.com/sentriflow/sentriflow",
|
|
10413
10757
|
rules: sarifRules,
|
|
10414
10758
|
// SEC-007: Include CWE taxonomy when rules reference it
|
|
@@ -10435,13 +10779,61 @@ function generateSarif(results, filePath, rules, options = {}) {
|
|
|
10435
10779
|
}
|
|
10436
10780
|
]
|
|
10437
10781
|
},
|
|
10438
|
-
results: sarifResults
|
|
10782
|
+
results: sarifResults,
|
|
10783
|
+
// Include IP summary in properties if available
|
|
10784
|
+
...ipSummary && {
|
|
10785
|
+
properties: {
|
|
10786
|
+
ipSummary
|
|
10787
|
+
}
|
|
10788
|
+
}
|
|
10439
10789
|
}
|
|
10440
10790
|
]
|
|
10441
10791
|
};
|
|
10442
10792
|
return JSON.stringify(report, null, 2);
|
|
10443
10793
|
}
|
|
10794
|
+
function aggregateIPSummaries(summaries) {
|
|
10795
|
+
if (summaries.length === 0) return void 0;
|
|
10796
|
+
const ipv4Set = /* @__PURE__ */ new Set();
|
|
10797
|
+
const ipv6Set = /* @__PURE__ */ new Set();
|
|
10798
|
+
const ipv4SubnetSet = /* @__PURE__ */ new Set();
|
|
10799
|
+
const ipv6SubnetSet = /* @__PURE__ */ new Set();
|
|
10800
|
+
for (const summary of summaries) {
|
|
10801
|
+
for (const ip of summary.ipv4Addresses) ipv4Set.add(ip);
|
|
10802
|
+
for (const ip of summary.ipv6Addresses) ipv6Set.add(ip);
|
|
10803
|
+
for (const subnet of summary.ipv4Subnets) ipv4SubnetSet.add(subnet);
|
|
10804
|
+
for (const subnet of summary.ipv6Subnets) ipv6SubnetSet.add(subnet);
|
|
10805
|
+
}
|
|
10806
|
+
const ipv4Addresses = [...ipv4Set].sort((a, b) => {
|
|
10807
|
+
const aParts = a.split(".").map(Number);
|
|
10808
|
+
const bParts = b.split(".").map(Number);
|
|
10809
|
+
for (let i = 0; i < 4; i++) {
|
|
10810
|
+
if ((aParts[i] ?? 0) !== (bParts[i] ?? 0)) {
|
|
10811
|
+
return (aParts[i] ?? 0) - (bParts[i] ?? 0);
|
|
10812
|
+
}
|
|
10813
|
+
}
|
|
10814
|
+
return 0;
|
|
10815
|
+
});
|
|
10816
|
+
const ipv6Addresses = [...ipv6Set].sort();
|
|
10817
|
+
const ipv4Subnets = [...ipv4SubnetSet].sort();
|
|
10818
|
+
const ipv6Subnets = [...ipv6SubnetSet].sort();
|
|
10819
|
+
return {
|
|
10820
|
+
ipv4Addresses,
|
|
10821
|
+
ipv6Addresses,
|
|
10822
|
+
ipv4Subnets,
|
|
10823
|
+
ipv6Subnets,
|
|
10824
|
+
counts: {
|
|
10825
|
+
ipv4: ipv4Addresses.length,
|
|
10826
|
+
ipv6: ipv6Addresses.length,
|
|
10827
|
+
ipv4Subnets: ipv4Subnets.length,
|
|
10828
|
+
ipv6Subnets: ipv6Subnets.length,
|
|
10829
|
+
total: ipv4Addresses.length + ipv6Addresses.length + ipv4Subnets.length + ipv6Subnets.length
|
|
10830
|
+
}
|
|
10831
|
+
};
|
|
10832
|
+
}
|
|
10444
10833
|
function generateMultiFileSarif(fileResults, rules, options = {}) {
|
|
10834
|
+
const aggregatedIpSummary = aggregateIPSummaries(
|
|
10835
|
+
fileResults.map((fr) => fr.ipSummary).filter((s) => !!s)
|
|
10836
|
+
);
|
|
10445
10837
|
const allSarifResults = fileResults.flatMap(({ filePath, results }) => {
|
|
10446
10838
|
const fileUri = options.relativePaths ? relative(options.baseDir ?? process.cwd(), filePath) : filePath;
|
|
10447
10839
|
return results.map((result) => ({
|
|
@@ -10514,7 +10906,7 @@ function generateMultiFileSarif(fileResults, rules, options = {}) {
|
|
|
10514
10906
|
tool: {
|
|
10515
10907
|
driver: {
|
|
10516
10908
|
name: "Sentriflow",
|
|
10517
|
-
version: "0.1.
|
|
10909
|
+
version: "0.1.8",
|
|
10518
10910
|
informationUri: "https://github.com/sentriflow/sentriflow",
|
|
10519
10911
|
rules: sarifRules,
|
|
10520
10912
|
// SEC-007: Include CWE taxonomy when rules reference it
|
|
@@ -10545,7 +10937,13 @@ function generateMultiFileSarif(fileResults, rules, options = {}) {
|
|
|
10545
10937
|
}
|
|
10546
10938
|
]
|
|
10547
10939
|
},
|
|
10548
|
-
results: allSarifResults
|
|
10940
|
+
results: allSarifResults,
|
|
10941
|
+
// Include aggregated IP summary in properties if available
|
|
10942
|
+
...aggregatedIpSummary && {
|
|
10943
|
+
properties: {
|
|
10944
|
+
ipSummary: aggregatedIpSummary
|
|
10945
|
+
}
|
|
10946
|
+
}
|
|
10549
10947
|
}
|
|
10550
10948
|
]
|
|
10551
10949
|
};
|
|
@@ -14459,7 +14857,7 @@ function isStdinRequested(files) {
|
|
|
14459
14857
|
|
|
14460
14858
|
// index.ts
|
|
14461
14859
|
var program = new Command();
|
|
14462
|
-
program.name("sentriflow").description("SentriFlow Network Configuration Validator").version("0.1.
|
|
14860
|
+
program.name("sentriflow").description("SentriFlow Network Configuration Validator").version("0.1.8").argument("[files...]", "Path(s) to configuration file(s) (supports multiple files)").option("--ast", "Output the AST instead of rule results").option("-f, --format <format>", "Output format (json, sarif)", "json").option("-q, --quiet", "Only output failures (suppress passed results)").option("-c, --config <path>", "Path to config file (default: auto-detect)").option("--no-config", "Ignore config file").option("-r, --rules <path>", "Additional rules file to load (legacy)").option("-p, --rule-pack <path>", "Rule pack file to load").option(
|
|
14463
14861
|
"--encrypted-pack <path...>",
|
|
14464
14862
|
"SEC-012: Path(s) to encrypted rule pack(s) (.grpx), can specify multiple"
|
|
14465
14863
|
).option(
|
|
@@ -14752,10 +15150,12 @@ Parsing complete: ${allAsts.length} files`);
|
|
|
14752
15150
|
const passed = results2.filter((r) => r.passed).length;
|
|
14753
15151
|
totalFailures += failures;
|
|
14754
15152
|
totalPassed += passed;
|
|
15153
|
+
const fileIpSummary = extractIPSummary(content2);
|
|
14755
15154
|
allFileResults.push({
|
|
14756
15155
|
filePath: filePath2,
|
|
14757
15156
|
results: results2,
|
|
14758
|
-
vendor: { id: vendor2.id, name: vendor2.name }
|
|
15157
|
+
vendor: { id: vendor2.id, name: vendor2.name },
|
|
15158
|
+
ipSummary: fileIpSummary
|
|
14759
15159
|
});
|
|
14760
15160
|
} catch (err) {
|
|
14761
15161
|
const errMsg = err instanceof Error ? err.message : "Unknown error";
|
|
@@ -14787,7 +15187,8 @@ Parsing complete: ${allAsts.length} files`);
|
|
|
14787
15187
|
files: allFileResults.map((fr) => ({
|
|
14788
15188
|
file: fr.filePath,
|
|
14789
15189
|
vendor: fr.vendor,
|
|
14790
|
-
results: fr.results
|
|
15190
|
+
results: fr.results,
|
|
15191
|
+
ipSummary: fr.ipSummary
|
|
14791
15192
|
}))
|
|
14792
15193
|
};
|
|
14793
15194
|
console.log(JSON.stringify(output, null, 2));
|
|
@@ -14863,17 +15264,19 @@ Scan complete: ${allFileResults.length} files, ${totalFailures} failures, ${tota
|
|
|
14863
15264
|
if (options.quiet) {
|
|
14864
15265
|
results2 = results2.filter((r) => !r.passed);
|
|
14865
15266
|
}
|
|
15267
|
+
const stdinIpSummary = extractIPSummary(content2);
|
|
14866
15268
|
if (options.format === "sarif") {
|
|
14867
15269
|
const sarifOptions = {
|
|
14868
15270
|
relativePaths: options.relativePaths,
|
|
14869
15271
|
baseDir: process.cwd()
|
|
14870
15272
|
};
|
|
14871
|
-
console.log(generateSarif(results2, "<stdin>", stdinRules, sarifOptions));
|
|
15273
|
+
console.log(generateSarif(results2, "<stdin>", stdinRules, sarifOptions, stdinIpSummary));
|
|
14872
15274
|
} else {
|
|
14873
15275
|
const output = {
|
|
14874
15276
|
file: "<stdin>",
|
|
14875
15277
|
vendor: { id: vendor2.id, name: vendor2.name },
|
|
14876
|
-
results: results2
|
|
15278
|
+
results: results2,
|
|
15279
|
+
ipSummary: stdinIpSummary
|
|
14877
15280
|
};
|
|
14878
15281
|
console.log(JSON.stringify(output, null, 2));
|
|
14879
15282
|
}
|
|
@@ -14932,10 +15335,12 @@ Scan complete: ${allFileResults.length} files, ${totalFailures} failures, ${tota
|
|
|
14932
15335
|
const passed = results2.filter((r) => r.passed).length;
|
|
14933
15336
|
totalFailures += failures;
|
|
14934
15337
|
totalPassed += passed;
|
|
15338
|
+
const fileIpSummary = extractIPSummary(content2);
|
|
14935
15339
|
allFileResults.push({
|
|
14936
15340
|
filePath: filePath2,
|
|
14937
15341
|
results: results2,
|
|
14938
|
-
vendor: { id: vendor2.id, name: vendor2.name }
|
|
15342
|
+
vendor: { id: vendor2.id, name: vendor2.name },
|
|
15343
|
+
ipSummary: fileIpSummary
|
|
14939
15344
|
});
|
|
14940
15345
|
} catch (err) {
|
|
14941
15346
|
const errMsg = err instanceof Error ? err.message : "Unknown error";
|
|
@@ -14962,7 +15367,8 @@ Scan complete: ${allFileResults.length} files, ${totalFailures} failures, ${tota
|
|
|
14962
15367
|
files: allFileResults.map((fr) => ({
|
|
14963
15368
|
file: fr.filePath,
|
|
14964
15369
|
vendor: fr.vendor,
|
|
14965
|
-
results: fr.results
|
|
15370
|
+
results: fr.results,
|
|
15371
|
+
ipSummary: fr.ipSummary
|
|
14966
15372
|
}))
|
|
14967
15373
|
};
|
|
14968
15374
|
console.log(JSON.stringify(output, null, 2));
|
|
@@ -15047,13 +15453,14 @@ Scan complete: ${allFileResults.length} files, ${totalFailures} failures, ${tota
|
|
|
15047
15453
|
if (options.quiet) {
|
|
15048
15454
|
results = results.filter((r) => !r.passed);
|
|
15049
15455
|
}
|
|
15456
|
+
const ipSummary = extractIPSummary(content);
|
|
15050
15457
|
if (options.format === "sarif") {
|
|
15051
15458
|
const sarifOptions = {
|
|
15052
15459
|
relativePaths: options.relativePaths,
|
|
15053
15460
|
baseDir: process.cwd()
|
|
15054
15461
|
};
|
|
15055
15462
|
console.log(
|
|
15056
|
-
generateSarif(results, filePath, singleFileRules, sarifOptions)
|
|
15463
|
+
generateSarif(results, filePath, singleFileRules, sarifOptions, ipSummary)
|
|
15057
15464
|
);
|
|
15058
15465
|
} else {
|
|
15059
15466
|
const output = {
|
|
@@ -15061,7 +15468,8 @@ Scan complete: ${allFileResults.length} files, ${totalFailures} failures, ${tota
|
|
|
15061
15468
|
id: vendor.id,
|
|
15062
15469
|
name: vendor.name
|
|
15063
15470
|
},
|
|
15064
|
-
results
|
|
15471
|
+
results,
|
|
15472
|
+
ipSummary
|
|
15065
15473
|
};
|
|
15066
15474
|
console.log(JSON.stringify(output, null, 2));
|
|
15067
15475
|
}
|