@sentriflow/cli 0.1.5 → 0.1.7
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 +493 -12
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -9975,6 +9975,7 @@ var JsonRuleCompiler = class {
|
|
|
9975
9975
|
id: jsonRule.id,
|
|
9976
9976
|
selector: jsonRule.selector,
|
|
9977
9977
|
vendor: jsonRule.vendor,
|
|
9978
|
+
category: jsonRule.category,
|
|
9978
9979
|
metadata: jsonRule.metadata,
|
|
9979
9980
|
check: (node, _ctx) => {
|
|
9980
9981
|
const passed = !this.evaluateCheck(jsonRule.check, node);
|
|
@@ -10407,7 +10408,7 @@ function generateSarif(results, filePath, rules, options = {}) {
|
|
|
10407
10408
|
tool: {
|
|
10408
10409
|
driver: {
|
|
10409
10410
|
name: "Sentriflow",
|
|
10410
|
-
version: "0.1.
|
|
10411
|
+
version: "0.1.7",
|
|
10411
10412
|
informationUri: "https://github.com/sentriflow/sentriflow",
|
|
10412
10413
|
rules: sarifRules,
|
|
10413
10414
|
// SEC-007: Include CWE taxonomy when rules reference it
|
|
@@ -10513,7 +10514,7 @@ function generateMultiFileSarif(fileResults, rules, options = {}) {
|
|
|
10513
10514
|
tool: {
|
|
10514
10515
|
driver: {
|
|
10515
10516
|
name: "Sentriflow",
|
|
10516
|
-
version: "0.1.
|
|
10517
|
+
version: "0.1.7",
|
|
10517
10518
|
informationUri: "https://github.com/sentriflow/sentriflow",
|
|
10518
10519
|
rules: sarifRules,
|
|
10519
10520
|
// SEC-007: Include CWE taxonomy when rules reference it
|
|
@@ -10556,10 +10557,12 @@ var NoMulticastBroadcastIp = {
|
|
|
10556
10557
|
id: "NET-IP-001",
|
|
10557
10558
|
selector: "ip address",
|
|
10558
10559
|
vendor: "common",
|
|
10560
|
+
category: "IP-Addressing",
|
|
10559
10561
|
metadata: {
|
|
10560
10562
|
level: "error",
|
|
10561
10563
|
obu: "Network Engineering",
|
|
10562
10564
|
owner: "NetOps",
|
|
10565
|
+
description: "Ensure IP addresses are not Multicast, Broadcast, or Network ID addresses.",
|
|
10563
10566
|
remediation: "Configure a valid unicast IP address. Do not use Multicast, Broadcast, or Network ID addresses."
|
|
10564
10567
|
},
|
|
10565
10568
|
check: (node) => {
|
|
@@ -10669,10 +10672,12 @@ var InterfaceDescriptionRequired = {
|
|
|
10669
10672
|
id: "NET-DOC-001",
|
|
10670
10673
|
selector: "interface",
|
|
10671
10674
|
vendor: "common",
|
|
10675
|
+
category: "Documentation",
|
|
10672
10676
|
metadata: {
|
|
10673
10677
|
level: "warning",
|
|
10674
10678
|
obu: "Network Engineering",
|
|
10675
10679
|
owner: "NetOps",
|
|
10680
|
+
description: "Ensure interfaces have descriptive labels for operational clarity.",
|
|
10676
10681
|
remediation: 'Add a description to the interface using the "description" command.'
|
|
10677
10682
|
},
|
|
10678
10683
|
check: (node) => {
|
|
@@ -10750,6 +10755,7 @@ var TrunkNoDTP = {
|
|
|
10750
10755
|
id: "NET-TRUNK-001",
|
|
10751
10756
|
selector: "interface",
|
|
10752
10757
|
vendor: "cisco-ios",
|
|
10758
|
+
category: "Network-Segmentation",
|
|
10753
10759
|
metadata: {
|
|
10754
10760
|
level: "warning",
|
|
10755
10761
|
obu: "Network Engineering",
|
|
@@ -10783,6 +10789,7 @@ var AccessExplicitMode = {
|
|
|
10783
10789
|
id: "NET-ACCESS-001",
|
|
10784
10790
|
selector: "interface",
|
|
10785
10791
|
vendor: "cisco-ios",
|
|
10792
|
+
category: "Network-Segmentation",
|
|
10786
10793
|
metadata: {
|
|
10787
10794
|
level: "warning",
|
|
10788
10795
|
obu: "Network Engineering",
|
|
@@ -10812,6 +10819,7 @@ var EnableSecretStrong = {
|
|
|
10812
10819
|
id: "NET-AAA-003",
|
|
10813
10820
|
selector: "enable",
|
|
10814
10821
|
vendor: "cisco-ios",
|
|
10822
|
+
category: "Authentication",
|
|
10815
10823
|
metadata: {
|
|
10816
10824
|
level: "error",
|
|
10817
10825
|
obu: "Security",
|
|
@@ -10848,6 +10856,7 @@ var CiscoNoPlaintextPasswords = {
|
|
|
10848
10856
|
id: "NET-SEC-001",
|
|
10849
10857
|
selector: "password",
|
|
10850
10858
|
vendor: ["cisco-ios", "cisco-nxos"],
|
|
10859
|
+
category: "Authentication",
|
|
10851
10860
|
metadata: {
|
|
10852
10861
|
level: "error",
|
|
10853
10862
|
obu: "Security",
|
|
@@ -10935,6 +10944,7 @@ var RootAuthRequired = {
|
|
|
10935
10944
|
id: "JUN-SYS-001",
|
|
10936
10945
|
selector: "system",
|
|
10937
10946
|
vendor: "juniper-junos",
|
|
10947
|
+
category: "Authentication",
|
|
10938
10948
|
metadata: {
|
|
10939
10949
|
level: "error",
|
|
10940
10950
|
obu: "Security",
|
|
@@ -10979,6 +10989,7 @@ var JunosBgpRouterId = {
|
|
|
10979
10989
|
id: "JUN-BGP-001",
|
|
10980
10990
|
selector: "routing-options",
|
|
10981
10991
|
vendor: "juniper-junos",
|
|
10992
|
+
category: "Routing",
|
|
10982
10993
|
metadata: {
|
|
10983
10994
|
level: "warning",
|
|
10984
10995
|
obu: "Network Engineering",
|
|
@@ -11011,6 +11022,7 @@ var JunosFirewallDefaultDeny = {
|
|
|
11011
11022
|
id: "JUN-FW-001",
|
|
11012
11023
|
selector: "firewall",
|
|
11013
11024
|
vendor: "juniper-junos",
|
|
11025
|
+
category: "Network-Segmentation",
|
|
11014
11026
|
metadata: {
|
|
11015
11027
|
level: "warning",
|
|
11016
11028
|
obu: "Security",
|
|
@@ -11082,6 +11094,7 @@ var SshEnabled = {
|
|
|
11082
11094
|
id: "ARU-SEC-001",
|
|
11083
11095
|
selector: "ssh",
|
|
11084
11096
|
vendor: ["aruba-aoscx", "aruba-aosswitch", "aruba-wlc"],
|
|
11097
|
+
category: "Session-Management",
|
|
11085
11098
|
metadata: {
|
|
11086
11099
|
level: "error",
|
|
11087
11100
|
obu: "Security",
|
|
@@ -11114,6 +11127,7 @@ var NtpConfigured = {
|
|
|
11114
11127
|
id: "ARU-NTP-001",
|
|
11115
11128
|
selector: "ntp",
|
|
11116
11129
|
vendor: ["aruba-aoscx", "aruba-aosswitch", "aruba-wlc"],
|
|
11130
|
+
category: "Time-Synchronization",
|
|
11117
11131
|
metadata: {
|
|
11118
11132
|
level: "warning",
|
|
11119
11133
|
obu: "Network Engineering",
|
|
@@ -11154,6 +11168,7 @@ var AosCxInterfaceDescription = {
|
|
|
11154
11168
|
id: "AOSCX-IF-001",
|
|
11155
11169
|
selector: "interface",
|
|
11156
11170
|
vendor: "aruba-aoscx",
|
|
11171
|
+
category: "Documentation",
|
|
11157
11172
|
metadata: {
|
|
11158
11173
|
level: "warning",
|
|
11159
11174
|
obu: "Network Engineering",
|
|
@@ -11195,6 +11210,7 @@ var AosCxTrunkAllowedVlans = {
|
|
|
11195
11210
|
id: "AOSCX-L2-001",
|
|
11196
11211
|
selector: "interface",
|
|
11197
11212
|
vendor: "aruba-aoscx",
|
|
11213
|
+
category: "Network-Segmentation",
|
|
11198
11214
|
metadata: {
|
|
11199
11215
|
level: "warning",
|
|
11200
11216
|
obu: "Network Engineering",
|
|
@@ -11245,6 +11261,7 @@ var AosSwitchVlanName = {
|
|
|
11245
11261
|
id: "AOSSW-L2-001",
|
|
11246
11262
|
selector: "vlan",
|
|
11247
11263
|
vendor: "aruba-aosswitch",
|
|
11264
|
+
category: "Documentation",
|
|
11248
11265
|
metadata: {
|
|
11249
11266
|
level: "warning",
|
|
11250
11267
|
obu: "Network Engineering",
|
|
@@ -11286,6 +11303,7 @@ var AosSwitchManagerPassword = {
|
|
|
11286
11303
|
id: "AOSSW-SEC-001",
|
|
11287
11304
|
selector: "password",
|
|
11288
11305
|
vendor: "aruba-aosswitch",
|
|
11306
|
+
category: "Authentication",
|
|
11289
11307
|
metadata: {
|
|
11290
11308
|
level: "error",
|
|
11291
11309
|
obu: "Security",
|
|
@@ -11326,6 +11344,7 @@ var WlcSsidEncryption = {
|
|
|
11326
11344
|
id: "ARUWLC-WLAN-001",
|
|
11327
11345
|
selector: "wlan ssid-profile",
|
|
11328
11346
|
vendor: "aruba-wlc",
|
|
11347
|
+
category: "Wireless",
|
|
11329
11348
|
metadata: {
|
|
11330
11349
|
level: "error",
|
|
11331
11350
|
obu: "Security",
|
|
@@ -11379,6 +11398,7 @@ var WlcRadiusHost = {
|
|
|
11379
11398
|
id: "ARUWLC-AAA-001",
|
|
11380
11399
|
selector: "aaa authentication-server radius",
|
|
11381
11400
|
vendor: "aruba-wlc",
|
|
11401
|
+
category: "Authentication",
|
|
11382
11402
|
metadata: {
|
|
11383
11403
|
level: "error",
|
|
11384
11404
|
obu: "Security",
|
|
@@ -11440,6 +11460,7 @@ var HostnameRequired = {
|
|
|
11440
11460
|
id: "PAN-SYS-001",
|
|
11441
11461
|
selector: "deviceconfig",
|
|
11442
11462
|
vendor: "paloalto-panos",
|
|
11463
|
+
category: "Documentation",
|
|
11443
11464
|
metadata: {
|
|
11444
11465
|
level: "warning",
|
|
11445
11466
|
obu: "Network Engineering",
|
|
@@ -11483,6 +11504,7 @@ var SecurityRuleLogging = {
|
|
|
11483
11504
|
id: "PAN-SEC-001",
|
|
11484
11505
|
selector: "rulebase",
|
|
11485
11506
|
vendor: "paloalto-panos",
|
|
11507
|
+
category: "Logging",
|
|
11486
11508
|
metadata: {
|
|
11487
11509
|
level: "warning",
|
|
11488
11510
|
obu: "Security",
|
|
@@ -11533,6 +11555,7 @@ var ZoneProtectionRequired = {
|
|
|
11533
11555
|
id: "PAN-ZONE-001",
|
|
11534
11556
|
selector: "zone",
|
|
11535
11557
|
vendor: "paloalto-panos",
|
|
11558
|
+
category: "Network-Segmentation",
|
|
11536
11559
|
metadata: {
|
|
11537
11560
|
level: "error",
|
|
11538
11561
|
obu: "Security",
|
|
@@ -11595,6 +11618,7 @@ var HostnameRequired2 = {
|
|
|
11595
11618
|
id: "ARI-SYS-001",
|
|
11596
11619
|
selector: "hostname",
|
|
11597
11620
|
vendor: "arista-eos",
|
|
11621
|
+
category: "Documentation",
|
|
11598
11622
|
metadata: {
|
|
11599
11623
|
level: "warning",
|
|
11600
11624
|
obu: "Network Engineering",
|
|
@@ -11629,6 +11653,7 @@ var MlagConfigComplete = {
|
|
|
11629
11653
|
id: "ARI-MLAG-001",
|
|
11630
11654
|
selector: "mlag configuration",
|
|
11631
11655
|
vendor: "arista-eos",
|
|
11656
|
+
category: "High-Availability",
|
|
11632
11657
|
metadata: {
|
|
11633
11658
|
level: "error",
|
|
11634
11659
|
obu: "Network Engineering",
|
|
@@ -11674,6 +11699,7 @@ var InterfaceDescription = {
|
|
|
11674
11699
|
id: "ARI-INT-001",
|
|
11675
11700
|
selector: "interface Ethernet",
|
|
11676
11701
|
vendor: "arista-eos",
|
|
11702
|
+
category: "Documentation",
|
|
11677
11703
|
metadata: {
|
|
11678
11704
|
level: "info",
|
|
11679
11705
|
obu: "Network Engineering",
|
|
@@ -11731,6 +11757,7 @@ var VyosHostnameRequired = {
|
|
|
11731
11757
|
id: "VYOS-SYS-001",
|
|
11732
11758
|
selector: "system",
|
|
11733
11759
|
vendor: "vyos",
|
|
11760
|
+
category: "Documentation",
|
|
11734
11761
|
metadata: {
|
|
11735
11762
|
level: "warning",
|
|
11736
11763
|
obu: "Network Engineering",
|
|
@@ -11763,6 +11790,7 @@ var VyosNoPlaintextPassword = {
|
|
|
11763
11790
|
id: "VYOS-SEC-001",
|
|
11764
11791
|
selector: "authentication",
|
|
11765
11792
|
vendor: "vyos",
|
|
11793
|
+
category: "Authentication",
|
|
11766
11794
|
metadata: {
|
|
11767
11795
|
level: "error",
|
|
11768
11796
|
obu: "Security",
|
|
@@ -11797,6 +11825,7 @@ var VyosInterfaceDescription = {
|
|
|
11797
11825
|
id: "VYOS-IF-001",
|
|
11798
11826
|
selector: "interfaces",
|
|
11799
11827
|
vendor: "vyos",
|
|
11828
|
+
category: "Documentation",
|
|
11800
11829
|
metadata: {
|
|
11801
11830
|
level: "warning",
|
|
11802
11831
|
obu: "Network Engineering",
|
|
@@ -11840,6 +11869,7 @@ var VyosFirewallDefaultAction = {
|
|
|
11840
11869
|
id: "VYOS-FW-001",
|
|
11841
11870
|
selector: "firewall",
|
|
11842
11871
|
vendor: "vyos",
|
|
11872
|
+
category: "Network-Segmentation",
|
|
11843
11873
|
metadata: {
|
|
11844
11874
|
level: "warning",
|
|
11845
11875
|
obu: "Security",
|
|
@@ -11907,6 +11937,7 @@ var HostnameRequired3 = {
|
|
|
11907
11937
|
id: "FGT-SYS-001",
|
|
11908
11938
|
selector: "config system global",
|
|
11909
11939
|
vendor: "fortinet-fortigate",
|
|
11940
|
+
category: "Documentation",
|
|
11910
11941
|
metadata: {
|
|
11911
11942
|
level: "warning",
|
|
11912
11943
|
obu: "Network Engineering",
|
|
@@ -11939,6 +11970,7 @@ var AdminTrustedHostRequired = {
|
|
|
11939
11970
|
id: "FGT-ADMIN-001",
|
|
11940
11971
|
selector: "config system admin",
|
|
11941
11972
|
vendor: "fortinet-fortigate",
|
|
11973
|
+
category: "Authentication",
|
|
11942
11974
|
metadata: {
|
|
11943
11975
|
level: "error",
|
|
11944
11976
|
obu: "Security",
|
|
@@ -11993,6 +12025,7 @@ var PolicyLoggingRequired = {
|
|
|
11993
12025
|
id: "FGT-POL-001",
|
|
11994
12026
|
selector: "config firewall policy",
|
|
11995
12027
|
vendor: "fortinet-fortigate",
|
|
12028
|
+
category: "Logging",
|
|
11996
12029
|
metadata: {
|
|
11997
12030
|
level: "warning",
|
|
11998
12031
|
obu: "Security",
|
|
@@ -12059,6 +12092,7 @@ var ExosSysnameRequired = {
|
|
|
12059
12092
|
id: "EXOS-SYS-001",
|
|
12060
12093
|
selector: "configure snmp sysname",
|
|
12061
12094
|
vendor: "extreme-exos",
|
|
12095
|
+
category: "Documentation",
|
|
12062
12096
|
metadata: {
|
|
12063
12097
|
level: "warning",
|
|
12064
12098
|
obu: "Network Engineering",
|
|
@@ -12092,6 +12126,7 @@ var ExosSsh2Enabled = {
|
|
|
12092
12126
|
id: "EXOS-SEC-001",
|
|
12093
12127
|
selector: "enable ssh2",
|
|
12094
12128
|
vendor: "extreme-exos",
|
|
12129
|
+
category: "Session-Management",
|
|
12095
12130
|
metadata: {
|
|
12096
12131
|
level: "warning",
|
|
12097
12132
|
obu: "Security",
|
|
@@ -12123,6 +12158,7 @@ var ExosVlanNaming = {
|
|
|
12123
12158
|
id: "EXOS-VLAN-001",
|
|
12124
12159
|
selector: "create vlan",
|
|
12125
12160
|
vendor: "extreme-exos",
|
|
12161
|
+
category: "Documentation",
|
|
12126
12162
|
metadata: {
|
|
12127
12163
|
level: "info",
|
|
12128
12164
|
obu: "Network Engineering",
|
|
@@ -12179,6 +12215,7 @@ var VossSysNameRequired = {
|
|
|
12179
12215
|
id: "VOSS-SYS-001",
|
|
12180
12216
|
selector: "snmp-server name",
|
|
12181
12217
|
vendor: "extreme-voss",
|
|
12218
|
+
category: "Documentation",
|
|
12182
12219
|
metadata: {
|
|
12183
12220
|
level: "warning",
|
|
12184
12221
|
obu: "Network Engineering",
|
|
@@ -12212,6 +12249,7 @@ var VossVlanIsidRequired = {
|
|
|
12212
12249
|
id: "VOSS-VLAN-001",
|
|
12213
12250
|
selector: "vlan create",
|
|
12214
12251
|
vendor: "extreme-voss",
|
|
12252
|
+
category: "Network-Segmentation",
|
|
12215
12253
|
metadata: {
|
|
12216
12254
|
level: "info",
|
|
12217
12255
|
obu: "Network Engineering",
|
|
@@ -12264,6 +12302,7 @@ var VossInterfaceDefaultVlan = {
|
|
|
12264
12302
|
id: "VOSS-INT-001",
|
|
12265
12303
|
selector: "interface GigabitEthernet",
|
|
12266
12304
|
vendor: "extreme-voss",
|
|
12305
|
+
category: "Network-Segmentation",
|
|
12267
12306
|
metadata: {
|
|
12268
12307
|
level: "info",
|
|
12269
12308
|
obu: "Network Engineering",
|
|
@@ -12348,6 +12387,7 @@ var SysnameRequired = {
|
|
|
12348
12387
|
id: "HUAWEI-SYS-001",
|
|
12349
12388
|
selector: "sysname",
|
|
12350
12389
|
vendor: "huawei-vrp",
|
|
12390
|
+
category: "Documentation",
|
|
12351
12391
|
metadata: {
|
|
12352
12392
|
level: "warning",
|
|
12353
12393
|
obu: "Network Engineering",
|
|
@@ -12380,6 +12420,7 @@ var InterfaceDescriptionRequired2 = {
|
|
|
12380
12420
|
id: "HUAWEI-IF-001",
|
|
12381
12421
|
selector: "interface",
|
|
12382
12422
|
vendor: "huawei-vrp",
|
|
12423
|
+
category: "Documentation",
|
|
12383
12424
|
metadata: {
|
|
12384
12425
|
level: "warning",
|
|
12385
12426
|
obu: "Network Engineering",
|
|
@@ -12432,6 +12473,7 @@ var VtySshRequired = {
|
|
|
12432
12473
|
id: "HUAWEI-VTY-002",
|
|
12433
12474
|
selector: "user-interface vty",
|
|
12434
12475
|
vendor: "huawei-vrp",
|
|
12476
|
+
category: "Session-Management",
|
|
12435
12477
|
metadata: {
|
|
12436
12478
|
level: "error",
|
|
12437
12479
|
obu: "Security",
|
|
@@ -12496,6 +12538,7 @@ var MikrotikSystemIdentity = {
|
|
|
12496
12538
|
id: "MIK-SYS-001",
|
|
12497
12539
|
selector: "/system identity",
|
|
12498
12540
|
vendor: "mikrotik-routeros",
|
|
12541
|
+
category: "Documentation",
|
|
12499
12542
|
metadata: {
|
|
12500
12543
|
level: "warning",
|
|
12501
12544
|
obu: "Network Engineering",
|
|
@@ -12528,6 +12571,7 @@ var MikrotikDisableUnusedServices = {
|
|
|
12528
12571
|
id: "MIK-SEC-001",
|
|
12529
12572
|
selector: "/ip service",
|
|
12530
12573
|
vendor: "mikrotik-routeros",
|
|
12574
|
+
category: "Service-Hardening",
|
|
12531
12575
|
metadata: {
|
|
12532
12576
|
level: "warning",
|
|
12533
12577
|
obu: "Security",
|
|
@@ -12572,6 +12616,7 @@ var MikrotikInputChainDrop = {
|
|
|
12572
12616
|
id: "MIK-FW-001",
|
|
12573
12617
|
selector: "/ip firewall filter",
|
|
12574
12618
|
vendor: "mikrotik-routeros",
|
|
12619
|
+
category: "Network-Segmentation",
|
|
12575
12620
|
metadata: {
|
|
12576
12621
|
level: "error",
|
|
12577
12622
|
obu: "Security",
|
|
@@ -12625,6 +12670,7 @@ var SystemNameRequired = {
|
|
|
12625
12670
|
id: "NOKIA-SYS-001",
|
|
12626
12671
|
selector: "system",
|
|
12627
12672
|
vendor: "nokia-sros",
|
|
12673
|
+
category: "Documentation",
|
|
12628
12674
|
metadata: {
|
|
12629
12675
|
level: "warning",
|
|
12630
12676
|
obu: "Network Engineering",
|
|
@@ -12657,6 +12703,7 @@ var PortDescriptionRequired = {
|
|
|
12657
12703
|
id: "NOKIA-PORT-001",
|
|
12658
12704
|
selector: "port",
|
|
12659
12705
|
vendor: "nokia-sros",
|
|
12706
|
+
category: "Documentation",
|
|
12660
12707
|
metadata: {
|
|
12661
12708
|
level: "warning",
|
|
12662
12709
|
obu: "Network Engineering",
|
|
@@ -12709,6 +12756,7 @@ var BgpRouterIdRequired = {
|
|
|
12709
12756
|
id: "NOKIA-BGP-001",
|
|
12710
12757
|
selector: "bgp",
|
|
12711
12758
|
vendor: "nokia-sros",
|
|
12759
|
+
category: "Routing",
|
|
12712
12760
|
metadata: {
|
|
12713
12761
|
level: "warning",
|
|
12714
12762
|
obu: "Network Engineering",
|
|
@@ -12765,6 +12813,7 @@ var CumulusInterfaceDescription = {
|
|
|
12765
12813
|
id: "CUM-IF-001",
|
|
12766
12814
|
selector: "iface",
|
|
12767
12815
|
vendor: "cumulus-linux",
|
|
12816
|
+
category: "Documentation",
|
|
12768
12817
|
metadata: {
|
|
12769
12818
|
level: "warning",
|
|
12770
12819
|
obu: "Network Engineering",
|
|
@@ -12807,6 +12856,7 @@ var CumulusBridgeVlans = {
|
|
|
12807
12856
|
id: "CUM-BR-001",
|
|
12808
12857
|
selector: "iface",
|
|
12809
12858
|
vendor: "cumulus-linux",
|
|
12859
|
+
category: "Network-Segmentation",
|
|
12810
12860
|
metadata: {
|
|
12811
12861
|
level: "warning",
|
|
12812
12862
|
obu: "Network Engineering",
|
|
@@ -12859,6 +12909,7 @@ var CumulusBgpRouterId = {
|
|
|
12859
12909
|
id: "CUM-BGP-001",
|
|
12860
12910
|
selector: "router bgp",
|
|
12861
12911
|
vendor: "cumulus-linux",
|
|
12912
|
+
category: "Routing",
|
|
12862
12913
|
metadata: {
|
|
12863
12914
|
level: "warning",
|
|
12864
12915
|
obu: "Network Engineering",
|
|
@@ -12915,6 +12966,7 @@ var cisco_json_rules_default = {
|
|
|
12915
12966
|
id: "JSON-CISCO-001",
|
|
12916
12967
|
selector: "interface",
|
|
12917
12968
|
vendor: "cisco-ios",
|
|
12969
|
+
category: "Network-Segmentation",
|
|
12918
12970
|
metadata: {
|
|
12919
12971
|
level: "warning",
|
|
12920
12972
|
obu: "Network Engineering",
|
|
@@ -12953,6 +13005,7 @@ var cisco_json_rules_default = {
|
|
|
12953
13005
|
id: "JSON-CISCO-002",
|
|
12954
13006
|
selector: "interface",
|
|
12955
13007
|
vendor: "cisco-ios",
|
|
13008
|
+
category: "Network-Segmentation",
|
|
12956
13009
|
metadata: {
|
|
12957
13010
|
level: "info",
|
|
12958
13011
|
obu: "Network Engineering",
|
|
@@ -12991,6 +13044,7 @@ var cisco_json_rules_default = {
|
|
|
12991
13044
|
id: "JSON-CISCO-003",
|
|
12992
13045
|
selector: "interface",
|
|
12993
13046
|
vendor: "cisco-ios",
|
|
13047
|
+
category: "Documentation",
|
|
12994
13048
|
metadata: {
|
|
12995
13049
|
level: "warning",
|
|
12996
13050
|
obu: "Network Engineering",
|
|
@@ -13024,6 +13078,7 @@ var cisco_json_rules_default = {
|
|
|
13024
13078
|
id: "JSON-CISCO-004",
|
|
13025
13079
|
selector: "interface",
|
|
13026
13080
|
vendor: "cisco-ios",
|
|
13081
|
+
category: "Protocol-Security",
|
|
13027
13082
|
metadata: {
|
|
13028
13083
|
level: "error",
|
|
13029
13084
|
obu: "Security",
|
|
@@ -13066,6 +13121,7 @@ var cisco_json_rules_default = {
|
|
|
13066
13121
|
id: "JSON-CISCO-005",
|
|
13067
13122
|
selector: "line vty",
|
|
13068
13123
|
vendor: "cisco-ios",
|
|
13124
|
+
category: "Session-Management",
|
|
13069
13125
|
metadata: {
|
|
13070
13126
|
level: "error",
|
|
13071
13127
|
obu: "Security",
|
|
@@ -13101,6 +13157,7 @@ var common_json_rules_default = {
|
|
|
13101
13157
|
id: "JSON-COMMON-001",
|
|
13102
13158
|
selector: "interface",
|
|
13103
13159
|
vendor: "common",
|
|
13160
|
+
category: "Documentation",
|
|
13104
13161
|
metadata: {
|
|
13105
13162
|
level: "info",
|
|
13106
13163
|
obu: "Network Engineering",
|
|
@@ -13148,6 +13205,7 @@ var juniper_json_rules_default = {
|
|
|
13148
13205
|
id: "JSON-JUNOS-001",
|
|
13149
13206
|
selector: "system services",
|
|
13150
13207
|
vendor: "juniper-junos",
|
|
13208
|
+
category: "Session-Management",
|
|
13151
13209
|
metadata: {
|
|
13152
13210
|
level: "error",
|
|
13153
13211
|
obu: "Security",
|
|
@@ -13180,6 +13238,7 @@ var juniper_json_rules_default = {
|
|
|
13180
13238
|
id: "JSON-JUNOS-002",
|
|
13181
13239
|
selector: "system services",
|
|
13182
13240
|
vendor: "juniper-junos",
|
|
13241
|
+
category: "Service-Hardening",
|
|
13183
13242
|
metadata: {
|
|
13184
13243
|
level: "error",
|
|
13185
13244
|
obu: "Security",
|
|
@@ -13202,6 +13261,7 @@ var juniper_json_rules_default = {
|
|
|
13202
13261
|
id: "JSON-JUNOS-003",
|
|
13203
13262
|
selector: "system",
|
|
13204
13263
|
vendor: "juniper-junos",
|
|
13264
|
+
category: "Session-Management",
|
|
13205
13265
|
metadata: {
|
|
13206
13266
|
level: "warning",
|
|
13207
13267
|
obu: "Security",
|
|
@@ -13221,6 +13281,7 @@ var juniper_json_rules_default = {
|
|
|
13221
13281
|
id: "JSON-JUNOS-004",
|
|
13222
13282
|
selector: "protocols ospf area",
|
|
13223
13283
|
vendor: "juniper-junos",
|
|
13284
|
+
category: "Routing",
|
|
13224
13285
|
metadata: {
|
|
13225
13286
|
level: "warning",
|
|
13226
13287
|
obu: "Network Engineering",
|
|
@@ -13240,6 +13301,7 @@ var juniper_json_rules_default = {
|
|
|
13240
13301
|
id: "JSON-JUNOS-005",
|
|
13241
13302
|
selector: "system syslog",
|
|
13242
13303
|
vendor: "juniper-junos",
|
|
13304
|
+
category: "Logging",
|
|
13243
13305
|
metadata: {
|
|
13244
13306
|
level: "warning",
|
|
13245
13307
|
obu: "Operations",
|
|
@@ -13602,8 +13664,110 @@ function isValidSentriflowConfig(config) {
|
|
|
13602
13664
|
}
|
|
13603
13665
|
}
|
|
13604
13666
|
}
|
|
13667
|
+
if (obj.directory !== void 0) {
|
|
13668
|
+
if (!isValidDirectoryConfig(obj.directory)) {
|
|
13669
|
+
return false;
|
|
13670
|
+
}
|
|
13671
|
+
}
|
|
13672
|
+
return true;
|
|
13673
|
+
}
|
|
13674
|
+
function isValidDirectoryConfig(config) {
|
|
13675
|
+
if (config === null || config === void 0) {
|
|
13676
|
+
return false;
|
|
13677
|
+
}
|
|
13678
|
+
if (typeof config !== "object") {
|
|
13679
|
+
return false;
|
|
13680
|
+
}
|
|
13681
|
+
const obj = config;
|
|
13682
|
+
if (obj.excludePatterns !== void 0) {
|
|
13683
|
+
if (!Array.isArray(obj.excludePatterns)) {
|
|
13684
|
+
return false;
|
|
13685
|
+
}
|
|
13686
|
+
for (const pattern of obj.excludePatterns) {
|
|
13687
|
+
if (typeof pattern !== "string") {
|
|
13688
|
+
return false;
|
|
13689
|
+
}
|
|
13690
|
+
try {
|
|
13691
|
+
new RegExp(pattern);
|
|
13692
|
+
} catch {
|
|
13693
|
+
return false;
|
|
13694
|
+
}
|
|
13695
|
+
}
|
|
13696
|
+
}
|
|
13697
|
+
if (obj.extensions !== void 0) {
|
|
13698
|
+
if (!Array.isArray(obj.extensions)) {
|
|
13699
|
+
return false;
|
|
13700
|
+
}
|
|
13701
|
+
for (const ext of obj.extensions) {
|
|
13702
|
+
if (typeof ext !== "string") {
|
|
13703
|
+
return false;
|
|
13704
|
+
}
|
|
13705
|
+
}
|
|
13706
|
+
}
|
|
13707
|
+
if (obj.recursive !== void 0 && typeof obj.recursive !== "boolean") {
|
|
13708
|
+
return false;
|
|
13709
|
+
}
|
|
13710
|
+
if (obj.maxDepth !== void 0) {
|
|
13711
|
+
if (typeof obj.maxDepth !== "number") {
|
|
13712
|
+
return false;
|
|
13713
|
+
}
|
|
13714
|
+
if (obj.maxDepth < 0 || obj.maxDepth > 1e3) {
|
|
13715
|
+
return false;
|
|
13716
|
+
}
|
|
13717
|
+
}
|
|
13718
|
+
if (obj.exclude !== void 0) {
|
|
13719
|
+
if (!Array.isArray(obj.exclude)) {
|
|
13720
|
+
return false;
|
|
13721
|
+
}
|
|
13722
|
+
for (const pattern of obj.exclude) {
|
|
13723
|
+
if (typeof pattern !== "string") {
|
|
13724
|
+
return false;
|
|
13725
|
+
}
|
|
13726
|
+
}
|
|
13727
|
+
}
|
|
13605
13728
|
return true;
|
|
13606
13729
|
}
|
|
13730
|
+
function mergeDirectoryOptions(cliOptions, configOptions) {
|
|
13731
|
+
const result = {};
|
|
13732
|
+
if (cliOptions.excludePatterns) {
|
|
13733
|
+
result.excludePatterns = [...cliOptions.excludePatterns];
|
|
13734
|
+
} else {
|
|
13735
|
+
result.excludePatterns = [];
|
|
13736
|
+
}
|
|
13737
|
+
if (configOptions?.excludePatterns) {
|
|
13738
|
+
for (const pattern of configOptions.excludePatterns) {
|
|
13739
|
+
try {
|
|
13740
|
+
const regex = new RegExp(pattern);
|
|
13741
|
+
result.excludePatterns.push(regex);
|
|
13742
|
+
} catch {
|
|
13743
|
+
}
|
|
13744
|
+
}
|
|
13745
|
+
}
|
|
13746
|
+
const excludeSet = /* @__PURE__ */ new Set();
|
|
13747
|
+
if (cliOptions.exclude) {
|
|
13748
|
+
for (const p of cliOptions.exclude) excludeSet.add(p);
|
|
13749
|
+
}
|
|
13750
|
+
if (configOptions?.exclude) {
|
|
13751
|
+
for (const p of configOptions.exclude) excludeSet.add(p);
|
|
13752
|
+
}
|
|
13753
|
+
result.exclude = [...excludeSet];
|
|
13754
|
+
if (cliOptions.recursive !== void 0) {
|
|
13755
|
+
result.recursive = cliOptions.recursive;
|
|
13756
|
+
} else if (configOptions?.recursive !== void 0) {
|
|
13757
|
+
result.recursive = configOptions.recursive;
|
|
13758
|
+
}
|
|
13759
|
+
if (cliOptions.maxDepth !== void 0) {
|
|
13760
|
+
result.maxDepth = cliOptions.maxDepth;
|
|
13761
|
+
} else if (configOptions?.maxDepth !== void 0) {
|
|
13762
|
+
result.maxDepth = configOptions.maxDepth;
|
|
13763
|
+
}
|
|
13764
|
+
if (cliOptions.extensions !== void 0) {
|
|
13765
|
+
result.extensions = cliOptions.extensions;
|
|
13766
|
+
} else if (configOptions?.extensions !== void 0) {
|
|
13767
|
+
result.extensions = configOptions.extensions;
|
|
13768
|
+
}
|
|
13769
|
+
return result;
|
|
13770
|
+
}
|
|
13607
13771
|
function isValidRule(rule) {
|
|
13608
13772
|
if (typeof rule !== "object" || rule === null) {
|
|
13609
13773
|
return false;
|
|
@@ -14048,6 +14212,19 @@ function isExcluded(relativePath, excludePatterns) {
|
|
|
14048
14212
|
if (excludePatterns.length === 0) return false;
|
|
14049
14213
|
return excludePatterns.some((pattern) => matchesPattern(relativePath, pattern));
|
|
14050
14214
|
}
|
|
14215
|
+
function validateRegexPattern(pattern) {
|
|
14216
|
+
try {
|
|
14217
|
+
const regex = new RegExp(pattern);
|
|
14218
|
+
return { valid: true, regex };
|
|
14219
|
+
} catch (error) {
|
|
14220
|
+
const message = error instanceof Error ? error.message : "Invalid regex pattern";
|
|
14221
|
+
return { valid: false, error: message };
|
|
14222
|
+
}
|
|
14223
|
+
}
|
|
14224
|
+
function isExcludedByRegex(relativePath, patterns) {
|
|
14225
|
+
if (patterns.length === 0 || relativePath === "") return false;
|
|
14226
|
+
return patterns.some((pattern) => pattern.test(relativePath));
|
|
14227
|
+
}
|
|
14051
14228
|
async function scanDirectory(dirPath, options = {}) {
|
|
14052
14229
|
const {
|
|
14053
14230
|
recursive = false,
|
|
@@ -14056,7 +14233,8 @@ async function scanDirectory(dirPath, options = {}) {
|
|
|
14056
14233
|
maxFileSize = MAX_CONFIG_SIZE,
|
|
14057
14234
|
maxDepth = 100,
|
|
14058
14235
|
allowedBaseDirs,
|
|
14059
|
-
exclude = []
|
|
14236
|
+
exclude = [],
|
|
14237
|
+
excludePatterns = []
|
|
14060
14238
|
} = options;
|
|
14061
14239
|
const result = {
|
|
14062
14240
|
files: [],
|
|
@@ -14102,7 +14280,11 @@ async function scanDirectory(dirPath, options = {}) {
|
|
|
14102
14280
|
for (const entry of entries) {
|
|
14103
14281
|
const fullPath = join(currentDir, entry);
|
|
14104
14282
|
const relativePath = join(basePath, entry);
|
|
14105
|
-
|
|
14283
|
+
const normalizedRelativePath = normalizeSeparators2(relativePath);
|
|
14284
|
+
if (isExcluded(normalizedRelativePath, exclude)) {
|
|
14285
|
+
continue;
|
|
14286
|
+
}
|
|
14287
|
+
if (isExcludedByRegex(normalizedRelativePath, excludePatterns)) {
|
|
14106
14288
|
continue;
|
|
14107
14289
|
}
|
|
14108
14290
|
let stats;
|
|
@@ -14188,9 +14370,96 @@ function validateDirectoryPath(dirPath, allowedBaseDirs) {
|
|
|
14188
14370
|
}
|
|
14189
14371
|
}
|
|
14190
14372
|
|
|
14373
|
+
// src/loaders/stdin.ts
|
|
14374
|
+
async function readStdin() {
|
|
14375
|
+
return new Promise((resolve5) => {
|
|
14376
|
+
const stdin = process.stdin;
|
|
14377
|
+
const chunks = [];
|
|
14378
|
+
let totalSize = 0;
|
|
14379
|
+
let sizeLimitExceeded = false;
|
|
14380
|
+
stdin.setEncoding("utf8");
|
|
14381
|
+
if (stdin.isTTY) {
|
|
14382
|
+
resolve5({
|
|
14383
|
+
success: false,
|
|
14384
|
+
error: "No input received from stdin"
|
|
14385
|
+
});
|
|
14386
|
+
return;
|
|
14387
|
+
}
|
|
14388
|
+
stdin.on("data", (chunk) => {
|
|
14389
|
+
if (sizeLimitExceeded) return;
|
|
14390
|
+
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, "utf8");
|
|
14391
|
+
totalSize += buffer.length;
|
|
14392
|
+
if (totalSize > MAX_CONFIG_SIZE) {
|
|
14393
|
+
sizeLimitExceeded = true;
|
|
14394
|
+
resolve5({
|
|
14395
|
+
success: false,
|
|
14396
|
+
error: `Input exceeds maximum size (${totalSize} > ${MAX_CONFIG_SIZE} bytes)`
|
|
14397
|
+
});
|
|
14398
|
+
stdin.destroy();
|
|
14399
|
+
return;
|
|
14400
|
+
}
|
|
14401
|
+
chunks.push(buffer);
|
|
14402
|
+
});
|
|
14403
|
+
stdin.on("end", () => {
|
|
14404
|
+
if (sizeLimitExceeded) return;
|
|
14405
|
+
const content = Buffer.concat(chunks).toString("utf8");
|
|
14406
|
+
if (content.length === 0) {
|
|
14407
|
+
resolve5({
|
|
14408
|
+
success: false,
|
|
14409
|
+
error: "No input received from stdin"
|
|
14410
|
+
});
|
|
14411
|
+
return;
|
|
14412
|
+
}
|
|
14413
|
+
resolve5({
|
|
14414
|
+
success: true,
|
|
14415
|
+
content
|
|
14416
|
+
});
|
|
14417
|
+
});
|
|
14418
|
+
stdin.on("error", (err) => {
|
|
14419
|
+
resolve5({
|
|
14420
|
+
success: false,
|
|
14421
|
+
error: `Failed to read from stdin: ${err.message}`
|
|
14422
|
+
});
|
|
14423
|
+
});
|
|
14424
|
+
const timeout = setTimeout(() => {
|
|
14425
|
+
if (chunks.length === 0 && !sizeLimitExceeded) {
|
|
14426
|
+
stdin.destroy();
|
|
14427
|
+
resolve5({
|
|
14428
|
+
success: false,
|
|
14429
|
+
error: "No input received from stdin (timeout)"
|
|
14430
|
+
});
|
|
14431
|
+
}
|
|
14432
|
+
}, 100);
|
|
14433
|
+
stdin.on("end", () => clearTimeout(timeout));
|
|
14434
|
+
stdin.on("error", () => clearTimeout(timeout));
|
|
14435
|
+
});
|
|
14436
|
+
}
|
|
14437
|
+
function validateStdinArgument(files, hasDirectory) {
|
|
14438
|
+
const hasStdin = files.includes("-");
|
|
14439
|
+
if (!hasStdin) {
|
|
14440
|
+
return { valid: true };
|
|
14441
|
+
}
|
|
14442
|
+
if (files.length > 1) {
|
|
14443
|
+
return {
|
|
14444
|
+
valid: false,
|
|
14445
|
+
error: "Cannot combine stdin (-) with other file arguments"
|
|
14446
|
+
};
|
|
14447
|
+
}
|
|
14448
|
+
if (hasDirectory) {
|
|
14449
|
+
return {
|
|
14450
|
+
valid: false,
|
|
14451
|
+
error: "Cannot combine stdin (-) with directory mode (-D)"
|
|
14452
|
+
};
|
|
14453
|
+
}
|
|
14454
|
+
return { valid: true };
|
|
14455
|
+
}
|
|
14456
|
+
function isStdinRequested(files) {
|
|
14457
|
+
return files.length === 1 && files[0] === "-";
|
|
14458
|
+
}
|
|
14459
|
+
|
|
14191
14460
|
// index.ts
|
|
14192
14461
|
var program = new Command();
|
|
14193
|
-
program.name("sentriflow").description("SentriFlow Network Configuration Validator").version("0.1.
|
|
14462
|
+
program.name("sentriflow").description("SentriFlow Network Configuration Validator").version("0.1.7").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(
|
|
14194
14463
|
"--encrypted-pack <path...>",
|
|
14195
14464
|
"SEC-012: Path(s) to encrypted rule pack(s) (.grpx), can specify multiple"
|
|
14196
14465
|
).option(
|
|
@@ -14231,7 +14500,14 @@ program.name("sentriflow").description("SentriFlow Network Configuration Validat
|
|
|
14231
14500
|
"--exclude <patterns>",
|
|
14232
14501
|
"Exclude patterns (comma-separated glob patterns)",
|
|
14233
14502
|
(val) => val.split(",")
|
|
14234
|
-
).option(
|
|
14503
|
+
).option(
|
|
14504
|
+
"--exclude-pattern <pattern...>",
|
|
14505
|
+
"Regex pattern(s) to exclude files (JavaScript regex syntax, can specify multiple)"
|
|
14506
|
+
).option(
|
|
14507
|
+
"--max-depth <number>",
|
|
14508
|
+
"Maximum recursion depth for directory scanning (use with -R)",
|
|
14509
|
+
(val) => parseInt(val, 10)
|
|
14510
|
+
).option("--progress", "Show progress during directory scanning").action(async (files, options) => {
|
|
14235
14511
|
try {
|
|
14236
14512
|
if (options.listVendors) {
|
|
14237
14513
|
console.log("Supported vendors:\n");
|
|
@@ -14258,8 +14534,21 @@ Use: sentriflow --vendor <vendor> <file>`);
|
|
|
14258
14534
|
}
|
|
14259
14535
|
const workingDir = process.cwd();
|
|
14260
14536
|
const allowedBaseDirs = options.allowExternal ? void 0 : [workingDir];
|
|
14537
|
+
const excludePatterns = [];
|
|
14538
|
+
if (options.excludePattern) {
|
|
14539
|
+
for (const pattern of options.excludePattern) {
|
|
14540
|
+
const result = validateRegexPattern(pattern);
|
|
14541
|
+
if (!result.valid) {
|
|
14542
|
+
console.error(`Error: Invalid regex pattern '${pattern}'`);
|
|
14543
|
+
console.error(` ${result.error}`);
|
|
14544
|
+
process.exit(2);
|
|
14545
|
+
}
|
|
14546
|
+
excludePatterns.push(result.regex);
|
|
14547
|
+
}
|
|
14548
|
+
}
|
|
14261
14549
|
const licenseKey = options.licenseKey || process.env.SENTRIFLOW_LICENSE_KEY;
|
|
14262
|
-
const
|
|
14550
|
+
const firstFile = files.length > 0 ? files[0] : void 0;
|
|
14551
|
+
const configSearchDir = firstFile ? dirname2(resolve4(firstFile)) : workingDir;
|
|
14263
14552
|
const rules = await resolveRules({
|
|
14264
14553
|
configPath: options.config,
|
|
14265
14554
|
noConfig: options.config === false,
|
|
@@ -14313,18 +14602,44 @@ Config file: ${configFile}`);
|
|
|
14313
14602
|
process.exit(2);
|
|
14314
14603
|
}
|
|
14315
14604
|
const canonicalDir = dirValidation.canonicalPath;
|
|
14605
|
+
let directoryConfig;
|
|
14606
|
+
if (options.config !== false) {
|
|
14607
|
+
const configPath = options.config ?? findConfigFile(canonicalDir);
|
|
14608
|
+
if (configPath) {
|
|
14609
|
+
try {
|
|
14610
|
+
const config = await loadConfigFile(configPath, allowedBaseDirs);
|
|
14611
|
+
directoryConfig = config.directory;
|
|
14612
|
+
} catch (err) {
|
|
14613
|
+
if (options.progress) {
|
|
14614
|
+
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
14615
|
+
console.error(`Warning: Failed to load config: ${msg}`);
|
|
14616
|
+
}
|
|
14617
|
+
}
|
|
14618
|
+
}
|
|
14619
|
+
}
|
|
14620
|
+
const cliDirOptions = {
|
|
14621
|
+
recursive: options.recursive,
|
|
14622
|
+
extensions: options.extensions,
|
|
14623
|
+
exclude: options.exclude,
|
|
14624
|
+
excludePatterns: excludePatterns.length > 0 ? excludePatterns : void 0,
|
|
14625
|
+
maxDepth: options.maxDepth
|
|
14626
|
+
};
|
|
14627
|
+
const mergedOptions = mergeDirectoryOptions(cliDirOptions, directoryConfig);
|
|
14316
14628
|
if (options.progress) {
|
|
14629
|
+
const recursive = mergedOptions.recursive ?? false;
|
|
14317
14630
|
console.error(
|
|
14318
|
-
`Scanning directory: ${canonicalDir}${
|
|
14631
|
+
`Scanning directory: ${canonicalDir}${recursive ? " (recursive)" : ""}`
|
|
14319
14632
|
);
|
|
14320
14633
|
}
|
|
14321
14634
|
const scanResult = await scanDirectory(canonicalDir, {
|
|
14322
|
-
recursive:
|
|
14635
|
+
recursive: mergedOptions.recursive ?? false,
|
|
14323
14636
|
patterns: options.glob ? [options.glob] : [],
|
|
14324
|
-
extensions:
|
|
14637
|
+
extensions: mergedOptions.extensions ?? DEFAULT_CONFIG_EXTENSIONS,
|
|
14325
14638
|
maxFileSize: MAX_CONFIG_SIZE,
|
|
14639
|
+
maxDepth: mergedOptions.maxDepth,
|
|
14326
14640
|
allowedBaseDirs,
|
|
14327
|
-
exclude:
|
|
14641
|
+
exclude: mergedOptions.exclude ?? [],
|
|
14642
|
+
excludePatterns: mergedOptions.excludePatterns ?? []
|
|
14328
14643
|
});
|
|
14329
14644
|
if (scanResult.errors.length > 0 && options.progress) {
|
|
14330
14645
|
console.error(`
|
|
@@ -14488,10 +14803,176 @@ Scan complete: ${allFileResults.length} files, ${totalFailures} failures, ${tota
|
|
|
14488
14803
|
}
|
|
14489
14804
|
return;
|
|
14490
14805
|
}
|
|
14491
|
-
if (
|
|
14806
|
+
if (files.length === 0) {
|
|
14492
14807
|
program.help();
|
|
14493
14808
|
return;
|
|
14494
14809
|
}
|
|
14810
|
+
const stdinValidation = validateStdinArgument(files, !!options.directory);
|
|
14811
|
+
if (!stdinValidation.valid) {
|
|
14812
|
+
console.error(`Error: ${stdinValidation.error}`);
|
|
14813
|
+
process.exit(2);
|
|
14814
|
+
}
|
|
14815
|
+
if (isStdinRequested(files)) {
|
|
14816
|
+
const stdinResult = await readStdin();
|
|
14817
|
+
if (!stdinResult.success) {
|
|
14818
|
+
console.error(`Error: ${stdinResult.error}`);
|
|
14819
|
+
process.exit(2);
|
|
14820
|
+
}
|
|
14821
|
+
const content2 = stdinResult.content;
|
|
14822
|
+
let vendor2;
|
|
14823
|
+
if (options.vendor === "auto") {
|
|
14824
|
+
vendor2 = detectVendor(content2);
|
|
14825
|
+
if (!options.quiet && !options.ast) {
|
|
14826
|
+
console.error(`Detected vendor: ${vendor2.name} (${vendor2.id})`);
|
|
14827
|
+
}
|
|
14828
|
+
} else {
|
|
14829
|
+
try {
|
|
14830
|
+
vendor2 = getVendor(options.vendor);
|
|
14831
|
+
} catch {
|
|
14832
|
+
console.error(`Error: Unknown vendor '${options.vendor}'`);
|
|
14833
|
+
console.error(`Available vendors: ${getAvailableVendors().join(", ")}, auto`);
|
|
14834
|
+
process.exit(2);
|
|
14835
|
+
}
|
|
14836
|
+
}
|
|
14837
|
+
const stdinRules = await resolveRules({
|
|
14838
|
+
configPath: options.config,
|
|
14839
|
+
noConfig: options.config === false,
|
|
14840
|
+
rulesPath: options.rules,
|
|
14841
|
+
rulePackPath: options.rulePack,
|
|
14842
|
+
encryptedPackPaths: options.encryptedPack,
|
|
14843
|
+
licenseKey,
|
|
14844
|
+
strictPacks: options.strictPacks,
|
|
14845
|
+
jsonRulesPaths: options.jsonRules,
|
|
14846
|
+
disableIds: options.disable ?? [],
|
|
14847
|
+
vendorId: vendor2.id,
|
|
14848
|
+
cwd: workingDir,
|
|
14849
|
+
allowedBaseDirs
|
|
14850
|
+
});
|
|
14851
|
+
const parser2 = new SchemaAwareParser({ vendor: vendor2 });
|
|
14852
|
+
const nodes2 = parser2.parse(content2);
|
|
14853
|
+
if (options.ast) {
|
|
14854
|
+
const output = {
|
|
14855
|
+
vendor: { id: vendor2.id, name: vendor2.name },
|
|
14856
|
+
ast: nodes2
|
|
14857
|
+
};
|
|
14858
|
+
console.log(JSON.stringify(output, null, 2));
|
|
14859
|
+
return;
|
|
14860
|
+
}
|
|
14861
|
+
const engine2 = new RuleEngine();
|
|
14862
|
+
let results2 = engine2.run(nodes2, stdinRules);
|
|
14863
|
+
if (options.quiet) {
|
|
14864
|
+
results2 = results2.filter((r) => !r.passed);
|
|
14865
|
+
}
|
|
14866
|
+
if (options.format === "sarif") {
|
|
14867
|
+
const sarifOptions = {
|
|
14868
|
+
relativePaths: options.relativePaths,
|
|
14869
|
+
baseDir: process.cwd()
|
|
14870
|
+
};
|
|
14871
|
+
console.log(generateSarif(results2, "<stdin>", stdinRules, sarifOptions));
|
|
14872
|
+
} else {
|
|
14873
|
+
const output = {
|
|
14874
|
+
file: "<stdin>",
|
|
14875
|
+
vendor: { id: vendor2.id, name: vendor2.name },
|
|
14876
|
+
results: results2
|
|
14877
|
+
};
|
|
14878
|
+
console.log(JSON.stringify(output, null, 2));
|
|
14879
|
+
}
|
|
14880
|
+
const hasFailures2 = results2.some((r) => !r.passed);
|
|
14881
|
+
if (hasFailures2) {
|
|
14882
|
+
process.exit(1);
|
|
14883
|
+
}
|
|
14884
|
+
return;
|
|
14885
|
+
}
|
|
14886
|
+
if (files.length > 1) {
|
|
14887
|
+
const allFileResults = [];
|
|
14888
|
+
let totalFailures = 0;
|
|
14889
|
+
let totalPassed = 0;
|
|
14890
|
+
const engine2 = new RuleEngine();
|
|
14891
|
+
for (let i = 0; i < files.length; i++) {
|
|
14892
|
+
const file2 = files[i];
|
|
14893
|
+
if (!file2) continue;
|
|
14894
|
+
const fileValidation2 = validateInputFilePath(
|
|
14895
|
+
file2,
|
|
14896
|
+
MAX_CONFIG_SIZE,
|
|
14897
|
+
allowedBaseDirs
|
|
14898
|
+
);
|
|
14899
|
+
if (!fileValidation2.valid) {
|
|
14900
|
+
console.error(`Error processing ${file2}: ${fileValidation2.error}`);
|
|
14901
|
+
allFileResults.push({
|
|
14902
|
+
filePath: file2,
|
|
14903
|
+
results: []
|
|
14904
|
+
});
|
|
14905
|
+
continue;
|
|
14906
|
+
}
|
|
14907
|
+
const filePath2 = fileValidation2.canonicalPath;
|
|
14908
|
+
try {
|
|
14909
|
+
const stats2 = statSync2(filePath2);
|
|
14910
|
+
if (stats2.size > MAX_CONFIG_SIZE) {
|
|
14911
|
+
console.error(`Error: ${file2} exceeds maximum size`);
|
|
14912
|
+
allFileResults.push({ filePath: file2, results: [] });
|
|
14913
|
+
continue;
|
|
14914
|
+
}
|
|
14915
|
+
const content2 = await readFile(filePath2, "utf-8");
|
|
14916
|
+
let vendor2;
|
|
14917
|
+
if (options.vendor === "auto") {
|
|
14918
|
+
vendor2 = detectVendor(content2);
|
|
14919
|
+
} else {
|
|
14920
|
+
vendor2 = getVendor(options.vendor);
|
|
14921
|
+
}
|
|
14922
|
+
const fileRules = rules.filter(
|
|
14923
|
+
(rule) => ruleAppliesToVendor(rule, vendor2.id)
|
|
14924
|
+
);
|
|
14925
|
+
const parser2 = new SchemaAwareParser({ vendor: vendor2 });
|
|
14926
|
+
const nodes2 = parser2.parse(content2);
|
|
14927
|
+
let results2 = engine2.run(nodes2, fileRules);
|
|
14928
|
+
if (options.quiet) {
|
|
14929
|
+
results2 = results2.filter((r) => !r.passed);
|
|
14930
|
+
}
|
|
14931
|
+
const failures = results2.filter((r) => !r.passed).length;
|
|
14932
|
+
const passed = results2.filter((r) => r.passed).length;
|
|
14933
|
+
totalFailures += failures;
|
|
14934
|
+
totalPassed += passed;
|
|
14935
|
+
allFileResults.push({
|
|
14936
|
+
filePath: filePath2,
|
|
14937
|
+
results: results2,
|
|
14938
|
+
vendor: { id: vendor2.id, name: vendor2.name }
|
|
14939
|
+
});
|
|
14940
|
+
} catch (err) {
|
|
14941
|
+
const errMsg = err instanceof Error ? err.message : "Unknown error";
|
|
14942
|
+
console.error(`Error processing ${basename(file2)}: ${errMsg}`);
|
|
14943
|
+
allFileResults.push({ filePath: file2, results: [] });
|
|
14944
|
+
}
|
|
14945
|
+
}
|
|
14946
|
+
if (options.format === "sarif") {
|
|
14947
|
+
const sarifOptions = {
|
|
14948
|
+
relativePaths: options.relativePaths,
|
|
14949
|
+
baseDir: process.cwd()
|
|
14950
|
+
};
|
|
14951
|
+
console.log(
|
|
14952
|
+
generateMultiFileSarif(allFileResults, rules, sarifOptions)
|
|
14953
|
+
);
|
|
14954
|
+
} else {
|
|
14955
|
+
const output = {
|
|
14956
|
+
summary: {
|
|
14957
|
+
filesScanned: allFileResults.length,
|
|
14958
|
+
totalResults: totalFailures + totalPassed,
|
|
14959
|
+
failures: totalFailures,
|
|
14960
|
+
passed: totalPassed
|
|
14961
|
+
},
|
|
14962
|
+
files: allFileResults.map((fr) => ({
|
|
14963
|
+
file: fr.filePath,
|
|
14964
|
+
vendor: fr.vendor,
|
|
14965
|
+
results: fr.results
|
|
14966
|
+
}))
|
|
14967
|
+
};
|
|
14968
|
+
console.log(JSON.stringify(output, null, 2));
|
|
14969
|
+
}
|
|
14970
|
+
if (totalFailures > 0) {
|
|
14971
|
+
process.exit(1);
|
|
14972
|
+
}
|
|
14973
|
+
return;
|
|
14974
|
+
}
|
|
14975
|
+
const file = files[0];
|
|
14495
14976
|
const fileValidation = validateInputFilePath(
|
|
14496
14977
|
file,
|
|
14497
14978
|
MAX_CONFIG_SIZE,
|