@sentriflow/cli 0.4.1 → 0.4.2
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 +118 -290
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4698,36 +4698,6 @@ var RuleEngine = class {
|
|
|
4698
4698
|
}
|
|
4699
4699
|
};
|
|
4700
4700
|
|
|
4701
|
-
// ../core/src/pack-loader/types.ts
|
|
4702
|
-
var PackLoadError = class extends Error {
|
|
4703
|
-
constructor(code, message, details) {
|
|
4704
|
-
super(message);
|
|
4705
|
-
this.code = code;
|
|
4706
|
-
this.details = details;
|
|
4707
|
-
this.name = "PackLoadError";
|
|
4708
|
-
if (Error.captureStackTrace) {
|
|
4709
|
-
Error.captureStackTrace(this, this.constructor);
|
|
4710
|
-
}
|
|
4711
|
-
}
|
|
4712
|
-
};
|
|
4713
|
-
var GRPX_CONSTANTS = {
|
|
4714
|
-
MAGIC: "GRPX",
|
|
4715
|
-
HEADER_SIZE: 76,
|
|
4716
|
-
CURRENT_VERSION: 1,
|
|
4717
|
-
ALG_AES_256_GCM: 1,
|
|
4718
|
-
KDF_PBKDF2: 1,
|
|
4719
|
-
KDF_ARGON2ID: 2,
|
|
4720
|
-
PBKDF2_ITERATIONS: 1e5,
|
|
4721
|
-
KEY_LENGTH: 32,
|
|
4722
|
-
IV_LENGTH: 12,
|
|
4723
|
-
TAG_LENGTH: 16,
|
|
4724
|
-
SALT_LENGTH: 32
|
|
4725
|
-
};
|
|
4726
|
-
|
|
4727
|
-
// ../core/src/pack-loader/PackLoader.ts
|
|
4728
|
-
import { createDecipheriv, pbkdf2Sync } from "crypto";
|
|
4729
|
-
import { createContext, Script } from "vm";
|
|
4730
|
-
|
|
4731
4701
|
// ../core/src/helpers/index.ts
|
|
4732
4702
|
var helpers_exports = {};
|
|
4733
4703
|
__export(helpers_exports, {
|
|
@@ -10470,110 +10440,6 @@ function buildAllHelpers() {
|
|
|
10470
10440
|
return result;
|
|
10471
10441
|
}
|
|
10472
10442
|
var allHelpers = buildAllHelpers();
|
|
10473
|
-
async function loadEncryptedPack(packData, options) {
|
|
10474
|
-
const { licenseKey, machineId: machineId2, getActivationCount, timeout = 5e3 } = options;
|
|
10475
|
-
if (packData.length < GRPX_CONSTANTS.HEADER_SIZE) {
|
|
10476
|
-
throw new PackLoadError("INVALID_FORMAT", "Pack file too small");
|
|
10477
|
-
}
|
|
10478
|
-
const magic = packData.toString("utf8", 0, 4);
|
|
10479
|
-
if (magic !== GRPX_CONSTANTS.MAGIC) {
|
|
10480
|
-
throw new PackLoadError("INVALID_FORMAT", "Invalid pack format (bad magic)");
|
|
10481
|
-
}
|
|
10482
|
-
const version = packData.readUInt8(4);
|
|
10483
|
-
const algorithm = packData.readUInt8(5);
|
|
10484
|
-
const kdf = packData.readUInt8(6);
|
|
10485
|
-
const iv = packData.subarray(12, 24);
|
|
10486
|
-
const tag = packData.subarray(24, 40);
|
|
10487
|
-
const salt = packData.subarray(40, 72);
|
|
10488
|
-
const payloadLength = packData.readUInt32BE(72);
|
|
10489
|
-
const encryptedPayload = packData.subarray(
|
|
10490
|
-
GRPX_CONSTANTS.HEADER_SIZE,
|
|
10491
|
-
GRPX_CONSTANTS.HEADER_SIZE + payloadLength
|
|
10492
|
-
);
|
|
10493
|
-
if (version !== GRPX_CONSTANTS.CURRENT_VERSION) {
|
|
10494
|
-
throw new PackLoadError("INVALID_FORMAT", `Unsupported version: ${version}`);
|
|
10495
|
-
}
|
|
10496
|
-
if (algorithm !== GRPX_CONSTANTS.ALG_AES_256_GCM) {
|
|
10497
|
-
throw new PackLoadError("INVALID_FORMAT", `Unsupported algorithm: ${algorithm}`);
|
|
10498
|
-
}
|
|
10499
|
-
let key;
|
|
10500
|
-
if (kdf === GRPX_CONSTANTS.KDF_PBKDF2) {
|
|
10501
|
-
key = pbkdf2Sync(
|
|
10502
|
-
licenseKey,
|
|
10503
|
-
salt,
|
|
10504
|
-
GRPX_CONSTANTS.PBKDF2_ITERATIONS,
|
|
10505
|
-
GRPX_CONSTANTS.KEY_LENGTH,
|
|
10506
|
-
"sha256"
|
|
10507
|
-
);
|
|
10508
|
-
} else {
|
|
10509
|
-
throw new PackLoadError("INVALID_FORMAT", `Unsupported KDF: ${kdf}`);
|
|
10510
|
-
}
|
|
10511
|
-
let decryptedSource;
|
|
10512
|
-
try {
|
|
10513
|
-
const decipher = createDecipheriv("aes-256-gcm", key, iv);
|
|
10514
|
-
decipher.setAuthTag(tag);
|
|
10515
|
-
const decrypted = Buffer.concat([
|
|
10516
|
-
decipher.update(encryptedPayload),
|
|
10517
|
-
decipher.final()
|
|
10518
|
-
]);
|
|
10519
|
-
decryptedSource = decrypted.toString("utf8");
|
|
10520
|
-
} catch (error) {
|
|
10521
|
-
const errorType = error instanceof Error ? error.name : "Unknown";
|
|
10522
|
-
const errorMsg = error instanceof Error ? error.message : "Unknown error";
|
|
10523
|
-
if (process.env.DEBUG) {
|
|
10524
|
-
console.error(`[PackLoader] Decryption failed: ${errorType} - ${errorMsg}`);
|
|
10525
|
-
}
|
|
10526
|
-
throw new PackLoadError(
|
|
10527
|
-
"DECRYPTION_FAILED",
|
|
10528
|
-
"Invalid license key or corrupted pack"
|
|
10529
|
-
);
|
|
10530
|
-
}
|
|
10531
|
-
const sandbox = createValidationSandbox({ machineId: machineId2, getActivationCount });
|
|
10532
|
-
const context = createContext(sandbox);
|
|
10533
|
-
let vmResult;
|
|
10534
|
-
try {
|
|
10535
|
-
const script = new Script(decryptedSource, {
|
|
10536
|
-
filename: "pack.js",
|
|
10537
|
-
timeout
|
|
10538
|
-
});
|
|
10539
|
-
const factory = script.runInContext(context);
|
|
10540
|
-
vmResult = factory(sandbox);
|
|
10541
|
-
if (!vmResult || !Array.isArray(vmResult.rules)) {
|
|
10542
|
-
throw new PackLoadError("VALIDATION_FAILED", "Invalid pack structure");
|
|
10543
|
-
}
|
|
10544
|
-
} catch (error) {
|
|
10545
|
-
if (error instanceof PackLoadError) {
|
|
10546
|
-
throw error;
|
|
10547
|
-
}
|
|
10548
|
-
const msg = error instanceof Error ? error.message : String(error);
|
|
10549
|
-
if (msg.includes("EXPIRED")) {
|
|
10550
|
-
throw new PackLoadError("EXPIRED", msg);
|
|
10551
|
-
}
|
|
10552
|
-
if (msg.includes("MACHINE_MISMATCH")) {
|
|
10553
|
-
throw new PackLoadError("MACHINE_MISMATCH", msg);
|
|
10554
|
-
}
|
|
10555
|
-
if (msg.includes("ACTIVATION_LIMIT")) {
|
|
10556
|
-
throw new PackLoadError("ACTIVATION_LIMIT", msg);
|
|
10557
|
-
}
|
|
10558
|
-
throw new PackLoadError("VALIDATION_FAILED", msg);
|
|
10559
|
-
}
|
|
10560
|
-
const nativeRules = vmResult.rules.map((ruleDef) => {
|
|
10561
|
-
const checkFn = compileNativeCheckFunction(ruleDef.checkSource);
|
|
10562
|
-
return {
|
|
10563
|
-
id: ruleDef.id,
|
|
10564
|
-
selector: ruleDef.selector,
|
|
10565
|
-
vendor: ruleDef.vendor,
|
|
10566
|
-
metadata: ruleDef.metadata,
|
|
10567
|
-
check: checkFn
|
|
10568
|
-
};
|
|
10569
|
-
});
|
|
10570
|
-
return {
|
|
10571
|
-
metadata: vmResult.metadata,
|
|
10572
|
-
rules: nativeRules,
|
|
10573
|
-
validUntil: vmResult.validUntil,
|
|
10574
|
-
licenseInfo: vmResult.licenseInfo ?? void 0
|
|
10575
|
-
};
|
|
10576
|
-
}
|
|
10577
10443
|
var helperNames = Object.keys(allHelpers).filter(
|
|
10578
10444
|
(key) => typeof allHelpers[key] === "function" || typeof allHelpers[key] === "object"
|
|
10579
10445
|
);
|
|
@@ -10589,68 +10455,6 @@ function compileNativeCheckFunction(source) {
|
|
|
10589
10455
|
const compiledFn = wrapperFn(allHelpers);
|
|
10590
10456
|
return compiledFn;
|
|
10591
10457
|
}
|
|
10592
|
-
function createValidationSandbox(options) {
|
|
10593
|
-
const RealDate = Date;
|
|
10594
|
-
return Object.freeze({
|
|
10595
|
-
// Safe Date access (read-only, can't be mocked)
|
|
10596
|
-
Date: Object.freeze({
|
|
10597
|
-
now: () => RealDate.now(),
|
|
10598
|
-
parse: (s) => RealDate.parse(s)
|
|
10599
|
-
}),
|
|
10600
|
-
// Safe JSON access
|
|
10601
|
-
JSON: Object.freeze({
|
|
10602
|
-
parse: JSON.parse,
|
|
10603
|
-
stringify: JSON.stringify
|
|
10604
|
-
}),
|
|
10605
|
-
// Safe Math access
|
|
10606
|
-
Math: Object.freeze(Math),
|
|
10607
|
-
// No-op console (for debugging in pack factory)
|
|
10608
|
-
console: Object.freeze({
|
|
10609
|
-
log: () => {
|
|
10610
|
-
},
|
|
10611
|
-
warn: () => {
|
|
10612
|
-
},
|
|
10613
|
-
error: () => {
|
|
10614
|
-
}
|
|
10615
|
-
}),
|
|
10616
|
-
// Provided context for validation
|
|
10617
|
-
machineId: options.machineId,
|
|
10618
|
-
getActivationCount: options.getActivationCount,
|
|
10619
|
-
// Basic primitives
|
|
10620
|
-
undefined: void 0,
|
|
10621
|
-
null: null,
|
|
10622
|
-
NaN: NaN,
|
|
10623
|
-
Infinity: Infinity,
|
|
10624
|
-
// Required for error throwing in factory
|
|
10625
|
-
Error
|
|
10626
|
-
});
|
|
10627
|
-
}
|
|
10628
|
-
function validatePackFormat(packData) {
|
|
10629
|
-
if (packData.length < GRPX_CONSTANTS.HEADER_SIZE) {
|
|
10630
|
-
return false;
|
|
10631
|
-
}
|
|
10632
|
-
const magic = packData.toString("utf8", 0, 4);
|
|
10633
|
-
if (magic !== GRPX_CONSTANTS.MAGIC) {
|
|
10634
|
-
return false;
|
|
10635
|
-
}
|
|
10636
|
-
const version = packData.readUInt8(4);
|
|
10637
|
-
if (version !== GRPX_CONSTANTS.CURRENT_VERSION) {
|
|
10638
|
-
return false;
|
|
10639
|
-
}
|
|
10640
|
-
const algorithm = packData.readUInt8(5);
|
|
10641
|
-
if (algorithm !== GRPX_CONSTANTS.ALG_AES_256_GCM) {
|
|
10642
|
-
return false;
|
|
10643
|
-
}
|
|
10644
|
-
const kdf = packData.readUInt8(6);
|
|
10645
|
-
if (kdf !== GRPX_CONSTANTS.KDF_PBKDF2) {
|
|
10646
|
-
return false;
|
|
10647
|
-
}
|
|
10648
|
-
const payloadLength = packData.readUInt32BE(72);
|
|
10649
|
-
if (packData.length < GRPX_CONSTANTS.HEADER_SIZE + payloadLength) {
|
|
10650
|
-
return false;
|
|
10651
|
-
}
|
|
10652
|
-
return true;
|
|
10653
|
-
}
|
|
10654
10458
|
|
|
10655
10459
|
// ../core/src/pack-loader/format-detector.ts
|
|
10656
10460
|
import { open } from "node:fs/promises";
|
|
@@ -10658,12 +10462,10 @@ import { resolve } from "node:path";
|
|
|
10658
10462
|
var FORMAT_PRIORITIES = {
|
|
10659
10463
|
unknown: 0,
|
|
10660
10464
|
unencrypted: 100,
|
|
10661
|
-
grpx: 200,
|
|
10662
10465
|
grx2: 300
|
|
10663
10466
|
};
|
|
10664
10467
|
var MAGIC_BYTES = {
|
|
10665
|
-
GRX2: Buffer.from("GRX2", "ascii")
|
|
10666
|
-
GRPX: Buffer.from("GRPX", "ascii")
|
|
10468
|
+
GRX2: Buffer.from("GRX2", "ascii")
|
|
10667
10469
|
};
|
|
10668
10470
|
var MAGIC_BYTES_LENGTH = 4;
|
|
10669
10471
|
async function detectPackFormat(filePath) {
|
|
@@ -10688,9 +10490,6 @@ async function detectPackFormat(filePath) {
|
|
|
10688
10490
|
if (buffer.equals(MAGIC_BYTES.GRX2)) {
|
|
10689
10491
|
return "grx2";
|
|
10690
10492
|
}
|
|
10691
|
-
if (buffer.equals(MAGIC_BYTES.GRPX)) {
|
|
10692
|
-
return "grpx";
|
|
10693
|
-
}
|
|
10694
10493
|
return "unencrypted";
|
|
10695
10494
|
} catch (error) {
|
|
10696
10495
|
if (error instanceof Error) {
|
|
@@ -10738,9 +10537,9 @@ async function getMachineId() {
|
|
|
10738
10537
|
|
|
10739
10538
|
// ../core/src/grx2-loader/GRX2ExtendedLoader.ts
|
|
10740
10539
|
import {
|
|
10741
|
-
createDecipheriv
|
|
10540
|
+
createDecipheriv,
|
|
10742
10541
|
createHash,
|
|
10743
|
-
pbkdf2Sync
|
|
10542
|
+
pbkdf2Sync,
|
|
10744
10543
|
timingSafeEqual
|
|
10745
10544
|
} from "node:crypto";
|
|
10746
10545
|
import { readFile, readdir } from "node:fs/promises";
|
|
@@ -10756,11 +10555,11 @@ function deriveLDK(licenseKey, ldkSalt, machineId2) {
|
|
|
10756
10555
|
ldkSalt,
|
|
10757
10556
|
Buffer.from(machineId2, "utf-8")
|
|
10758
10557
|
]);
|
|
10759
|
-
return
|
|
10558
|
+
return pbkdf2Sync(licenseKey, combinedSalt, PBKDF2_ITERATIONS, AES_KEY_SIZE, "sha256");
|
|
10760
10559
|
}
|
|
10761
10560
|
function decrypt(ciphertext, key, iv, authTag) {
|
|
10762
10561
|
try {
|
|
10763
|
-
const decipher =
|
|
10562
|
+
const decipher = createDecipheriv(AES_ALGORITHM, key, iv);
|
|
10764
10563
|
decipher.setAuthTag(authTag);
|
|
10765
10564
|
const plaintext = Buffer.concat([
|
|
10766
10565
|
decipher.update(ciphertext),
|
|
@@ -11151,7 +10950,7 @@ function getHelperRegistry() {
|
|
|
11151
10950
|
}
|
|
11152
10951
|
|
|
11153
10952
|
// ../core/src/json-rules/ExpressionEvaluator.ts
|
|
11154
|
-
import { createContext
|
|
10953
|
+
import { createContext, Script } from "vm";
|
|
11155
10954
|
var MAX_EXPR_LENGTH = 1e3;
|
|
11156
10955
|
var EXPR_TIMEOUT_MS = 50;
|
|
11157
10956
|
var BLOCKED_PATTERNS = [
|
|
@@ -11271,7 +11070,7 @@ var ExpressionEvaluator = class {
|
|
|
11271
11070
|
sandboxObj[namespace] = Object.freeze({ ...vendorHelpers });
|
|
11272
11071
|
}
|
|
11273
11072
|
}
|
|
11274
|
-
return
|
|
11073
|
+
return createContext(Object.freeze(sandboxObj));
|
|
11275
11074
|
}
|
|
11276
11075
|
/**
|
|
11277
11076
|
* Pre-compile an expression for later evaluation.
|
|
@@ -11288,7 +11087,7 @@ var ExpressionEvaluator = class {
|
|
|
11288
11087
|
return true;
|
|
11289
11088
|
}
|
|
11290
11089
|
try {
|
|
11291
|
-
const script = new
|
|
11090
|
+
const script = new Script(`(${expr})`, {
|
|
11292
11091
|
filename: "expr.js"
|
|
11293
11092
|
});
|
|
11294
11093
|
scriptCache.set(expr, script);
|
|
@@ -11311,7 +11110,7 @@ var ExpressionEvaluator = class {
|
|
|
11311
11110
|
let script = scriptCache.get(expr);
|
|
11312
11111
|
if (!script) {
|
|
11313
11112
|
try {
|
|
11314
|
-
script = new
|
|
11113
|
+
script = new Script(`(${expr})`, {
|
|
11315
11114
|
filename: "expr.js"
|
|
11316
11115
|
});
|
|
11317
11116
|
scriptCache.set(expr, script);
|
|
@@ -11319,7 +11118,7 @@ var ExpressionEvaluator = class {
|
|
|
11319
11118
|
return false;
|
|
11320
11119
|
}
|
|
11321
11120
|
}
|
|
11322
|
-
const evalContext =
|
|
11121
|
+
const evalContext = createContext({
|
|
11323
11122
|
...this.sandbox,
|
|
11324
11123
|
node: createSafeNode(node)
|
|
11325
11124
|
});
|
|
@@ -12524,7 +12323,7 @@ function generateSarif(results, filePath, rules, options = {}, ipSummary) {
|
|
|
12524
12323
|
tool: {
|
|
12525
12324
|
driver: {
|
|
12526
12325
|
name: "Sentriflow",
|
|
12527
|
-
version: "0.4.
|
|
12326
|
+
version: "0.4.2",
|
|
12528
12327
|
informationUri: "https://github.com/sentriflow/sentriflow",
|
|
12529
12328
|
rules: sarifRules,
|
|
12530
12329
|
// SEC-007: Include CWE taxonomy when rules reference it
|
|
@@ -12684,7 +12483,7 @@ function generateMultiFileSarif(fileResults, rules, options = {}) {
|
|
|
12684
12483
|
tool: {
|
|
12685
12484
|
driver: {
|
|
12686
12485
|
name: "Sentriflow",
|
|
12687
|
-
version: "0.4.
|
|
12486
|
+
version: "0.4.2",
|
|
12688
12487
|
informationUri: "https://github.com/sentriflow/sentriflow",
|
|
12689
12488
|
rules: sarifRules,
|
|
12690
12489
|
// SEC-007: Include CWE taxonomy when rules reference it
|
|
@@ -15767,6 +15566,101 @@ async function createPackDescriptors(packPaths) {
|
|
|
15767
15566
|
return descriptors;
|
|
15768
15567
|
}
|
|
15769
15568
|
|
|
15569
|
+
// src/loaders/pack-loader.ts
|
|
15570
|
+
async function loadGRX2Pack(options) {
|
|
15571
|
+
const { filePath, licenseKey, machineId: machineId2, cacheDir } = options;
|
|
15572
|
+
try {
|
|
15573
|
+
const rulePack = await loadExtendedPack(filePath, licenseKey, machineId2);
|
|
15574
|
+
return {
|
|
15575
|
+
rulePack,
|
|
15576
|
+
usedLicensingLoader: false
|
|
15577
|
+
};
|
|
15578
|
+
} catch (coreError) {
|
|
15579
|
+
const errorCode = coreError?.code;
|
|
15580
|
+
if (errorCode !== "NOT_EXTENDED_FORMAT") {
|
|
15581
|
+
throw coreError;
|
|
15582
|
+
}
|
|
15583
|
+
try {
|
|
15584
|
+
const licensingModulePath = "@sentriflow/licensing";
|
|
15585
|
+
const licensing = await import(
|
|
15586
|
+
/* @vite-ignore */
|
|
15587
|
+
licensingModulePath
|
|
15588
|
+
);
|
|
15589
|
+
const effectiveCacheDir = cacheDir ?? licensing.getDefaultCacheDir();
|
|
15590
|
+
const cacheManager = licensing.createCacheManager(licenseKey, machineId2, effectiveCacheDir);
|
|
15591
|
+
let tierTMK;
|
|
15592
|
+
let tierTMKs;
|
|
15593
|
+
try {
|
|
15594
|
+
const cachedTMK = await cacheManager.getTierTMK();
|
|
15595
|
+
if (cachedTMK) {
|
|
15596
|
+
tierTMK = Buffer.from(cachedTMK.tmk, "base64");
|
|
15597
|
+
}
|
|
15598
|
+
const allTMKs = await cacheManager.tmkCache.getAllTierTMKs();
|
|
15599
|
+
if (allTMKs.size > 0) {
|
|
15600
|
+
tierTMKs = /* @__PURE__ */ new Map();
|
|
15601
|
+
for (const [tierId, tmkData] of allTMKs) {
|
|
15602
|
+
tierTMKs.set(tierId, Buffer.from(tmkData.tmk, "base64"));
|
|
15603
|
+
}
|
|
15604
|
+
}
|
|
15605
|
+
} catch (cacheError) {
|
|
15606
|
+
if (process.env.DEBUG) {
|
|
15607
|
+
console.debug(
|
|
15608
|
+
"[pack-loader] TMK cache retrieval skipped:",
|
|
15609
|
+
cacheError instanceof Error ? cacheError.message : "Unknown error"
|
|
15610
|
+
);
|
|
15611
|
+
}
|
|
15612
|
+
}
|
|
15613
|
+
const loader = new licensing.GRX2Loader({
|
|
15614
|
+
formatPolicy: "auto",
|
|
15615
|
+
licenseKey,
|
|
15616
|
+
machineId: machineId2,
|
|
15617
|
+
tierTMK,
|
|
15618
|
+
tierTMKs
|
|
15619
|
+
});
|
|
15620
|
+
const result = await loader.loadFromFile(filePath);
|
|
15621
|
+
return {
|
|
15622
|
+
rulePack: result.rulePack,
|
|
15623
|
+
usedLicensingLoader: true
|
|
15624
|
+
};
|
|
15625
|
+
} catch (licensingError) {
|
|
15626
|
+
if (isModuleNotFoundError(licensingError)) {
|
|
15627
|
+
throw new Error('Pack requires v2 format support - run "sentriflow activate" first');
|
|
15628
|
+
}
|
|
15629
|
+
throw licensingError;
|
|
15630
|
+
}
|
|
15631
|
+
}
|
|
15632
|
+
}
|
|
15633
|
+
function isModuleNotFoundError(error) {
|
|
15634
|
+
return error instanceof Error && (error.message.includes("Cannot find module") || error.message.includes("Cannot find package") || error.code === "ERR_MODULE_NOT_FOUND");
|
|
15635
|
+
}
|
|
15636
|
+
function sanitizeErrorMessage(msg) {
|
|
15637
|
+
const sanitized = msg.replace(/(?:\/[\w.-]+)+\/([\w.-]+)/g, "$1");
|
|
15638
|
+
return sanitized.replace(/\s+at\s+.+/g, "").trim();
|
|
15639
|
+
}
|
|
15640
|
+
function mapGRX2LoadError(error) {
|
|
15641
|
+
if (error instanceof Error && "code" in error) {
|
|
15642
|
+
const code = error.code;
|
|
15643
|
+
const messages = {
|
|
15644
|
+
// GRX2LoaderError codes (from licensing)
|
|
15645
|
+
HEADER_INVALID: "Pack file is corrupted or invalid",
|
|
15646
|
+
DECRYPTION_FAILED: "Failed to decrypt pack (invalid key or corrupted data)",
|
|
15647
|
+
PARSE_ERROR: "Pack content is malformed",
|
|
15648
|
+
FILE_READ_ERROR: "Cannot read pack file",
|
|
15649
|
+
HASH_MISMATCH: "Pack integrity check failed",
|
|
15650
|
+
TMK_NOT_AVAILABLE: 'License not activated - run "sentriflow activate" first',
|
|
15651
|
+
// EncryptedPackError codes (from core)
|
|
15652
|
+
LICENSE_MISSING: "Invalid or missing license key",
|
|
15653
|
+
LICENSE_EXPIRED: "License has expired",
|
|
15654
|
+
LICENSE_INVALID: "License key is invalid for this pack",
|
|
15655
|
+
MACHINE_MISMATCH: "License is not valid for this machine",
|
|
15656
|
+
PACK_CORRUPTED: "Pack file is corrupted or invalid",
|
|
15657
|
+
NOT_EXTENDED_FORMAT: "Pack requires extended format (v3) - activate license for v2 pack support"
|
|
15658
|
+
};
|
|
15659
|
+
return messages[code] ?? "Pack load failed";
|
|
15660
|
+
}
|
|
15661
|
+
return error instanceof Error ? sanitizeErrorMessage(error.message) : "Pack load failed";
|
|
15662
|
+
}
|
|
15663
|
+
|
|
15770
15664
|
// src/loaders/index.ts
|
|
15771
15665
|
function validatePathOrThrow(path, pathValidator, errorContext, baseDirs) {
|
|
15772
15666
|
const validation = pathValidator(path, baseDirs);
|
|
@@ -16083,44 +15977,6 @@ async function loadRulePackFile(packPath, baseDirs) {
|
|
|
16083
15977
|
errorContext: "rule pack"
|
|
16084
15978
|
});
|
|
16085
15979
|
}
|
|
16086
|
-
function mapPackLoadError(error) {
|
|
16087
|
-
const messages = {
|
|
16088
|
-
DECRYPTION_FAILED: "Invalid license key for encrypted pack",
|
|
16089
|
-
EXPIRED: "Encrypted pack has expired",
|
|
16090
|
-
MACHINE_MISMATCH: "License is not valid for this machine",
|
|
16091
|
-
ACTIVATION_LIMIT: "Maximum activations exceeded for this license"
|
|
16092
|
-
};
|
|
16093
|
-
throw new SentriflowConfigError(
|
|
16094
|
-
messages[error.code] ?? `Failed to load encrypted pack: ${error.message}`
|
|
16095
|
-
);
|
|
16096
|
-
}
|
|
16097
|
-
async function loadEncryptedRulePack(packPath, licenseKey, baseDirs) {
|
|
16098
|
-
const canonicalPath = validatePathOrThrow(
|
|
16099
|
-
packPath,
|
|
16100
|
-
validatePackPath,
|
|
16101
|
-
"encrypted pack",
|
|
16102
|
-
baseDirs
|
|
16103
|
-
);
|
|
16104
|
-
try {
|
|
16105
|
-
const packData = await readFileAsync(canonicalPath);
|
|
16106
|
-
if (!validatePackFormat(packData)) {
|
|
16107
|
-
throw new SentriflowConfigError("Invalid encrypted pack format");
|
|
16108
|
-
}
|
|
16109
|
-
const loadedPack = await loadEncryptedPack(packData, {
|
|
16110
|
-
licenseKey,
|
|
16111
|
-
timeout: 1e4
|
|
16112
|
-
});
|
|
16113
|
-
return {
|
|
16114
|
-
...loadedPack.metadata,
|
|
16115
|
-
priority: 200,
|
|
16116
|
-
rules: loadedPack.rules
|
|
16117
|
-
};
|
|
16118
|
-
} catch (error) {
|
|
16119
|
-
if (error instanceof PackLoadError) mapPackLoadError(error);
|
|
16120
|
-
if (error instanceof SentriflowConfigError) throw error;
|
|
16121
|
-
throw new SentriflowConfigError("Failed to load encrypted rule pack");
|
|
16122
|
-
}
|
|
16123
|
-
}
|
|
16124
15980
|
async function resolveRules(options = {}) {
|
|
16125
15981
|
const {
|
|
16126
15982
|
configPath,
|
|
@@ -16226,9 +16082,7 @@ async function resolveRules(options = {}) {
|
|
|
16226
16082
|
console.error(`Warning: Pack detection failed: ${errorMsg}`);
|
|
16227
16083
|
packDescriptors = [];
|
|
16228
16084
|
}
|
|
16229
|
-
const hasEncryptedPacks = packDescriptors.some(
|
|
16230
|
-
(d) => d.format === "grx2" || d.format === "grpx"
|
|
16231
|
-
);
|
|
16085
|
+
const hasEncryptedPacks = packDescriptors.some((d) => d.format === "grx2");
|
|
16232
16086
|
if (hasEncryptedPacks && !licenseKey) {
|
|
16233
16087
|
const errorMsg = "License key required for encrypted packs (use --license-key or set SENTRIFLOW_LICENSE_KEY)";
|
|
16234
16088
|
if (strictPacks) {
|
|
@@ -16269,24 +16123,12 @@ async function resolveRules(options = {}) {
|
|
|
16269
16123
|
console.error(`Warning: Skipping GRX2 pack (no machine ID): ${desc.path}`);
|
|
16270
16124
|
continue;
|
|
16271
16125
|
}
|
|
16272
|
-
|
|
16273
|
-
validation.canonicalPath,
|
|
16126
|
+
const result = await loadGRX2Pack({
|
|
16127
|
+
filePath: validation.canonicalPath,
|
|
16274
16128
|
licenseKey,
|
|
16275
|
-
machineId2
|
|
16276
|
-
);
|
|
16277
|
-
loadedPack
|
|
16278
|
-
break;
|
|
16279
|
-
}
|
|
16280
|
-
case "grpx": {
|
|
16281
|
-
if (!licenseKey) {
|
|
16282
|
-
console.error(`Warning: Skipping GRPX pack (no license key): ${desc.path}`);
|
|
16283
|
-
continue;
|
|
16284
|
-
}
|
|
16285
|
-
loadedPack = await loadEncryptedRulePack(
|
|
16286
|
-
validation.canonicalPath,
|
|
16287
|
-
licenseKey,
|
|
16288
|
-
allowedBaseDirs
|
|
16289
|
-
);
|
|
16129
|
+
machineId: machineId2
|
|
16130
|
+
});
|
|
16131
|
+
loadedPack = result.rulePack;
|
|
16290
16132
|
loadedPack.priority = desc.priority;
|
|
16291
16133
|
break;
|
|
16292
16134
|
}
|
|
@@ -16306,21 +16148,7 @@ async function resolveRules(options = {}) {
|
|
|
16306
16148
|
loadedCount++;
|
|
16307
16149
|
totalRules += loadedPack.rules.length;
|
|
16308
16150
|
} catch (error) {
|
|
16309
|
-
|
|
16310
|
-
if (error instanceof EncryptedPackError) {
|
|
16311
|
-
const messages = {
|
|
16312
|
-
LICENSE_MISSING: "Invalid or missing license key",
|
|
16313
|
-
LICENSE_EXPIRED: "License has expired",
|
|
16314
|
-
LICENSE_INVALID: "License key is invalid for this pack",
|
|
16315
|
-
DECRYPTION_FAILED: "Failed to decrypt pack (invalid key or corrupted data)",
|
|
16316
|
-
MACHINE_MISMATCH: "License is not valid for this machine",
|
|
16317
|
-
PACK_CORRUPTED: "Pack file is corrupted or invalid",
|
|
16318
|
-
NOT_EXTENDED_FORMAT: "Pack is not in extended GRX2 format"
|
|
16319
|
-
};
|
|
16320
|
-
errorMsg = messages[error.code] ?? `Pack load error: ${error.message}`;
|
|
16321
|
-
} else {
|
|
16322
|
-
errorMsg = error instanceof Error ? error.message : "Unknown error";
|
|
16323
|
-
}
|
|
16151
|
+
const errorMsg = mapGRX2LoadError(error);
|
|
16324
16152
|
if (strictPacks) {
|
|
16325
16153
|
throw new SentriflowConfigError(
|
|
16326
16154
|
`Failed to load pack '${desc.path}': ${errorMsg}`
|
|
@@ -16682,9 +16510,9 @@ function enrichResultsWithRuleMetadata(results, rules) {
|
|
|
16682
16510
|
});
|
|
16683
16511
|
}
|
|
16684
16512
|
var program = new Command();
|
|
16685
|
-
program.name("sentriflow").description("SentriFlow Network Configuration Validator").version("0.4.
|
|
16513
|
+
program.name("sentriflow").description("SentriFlow Network Configuration Validator").version("0.4.2").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(
|
|
16686
16514
|
"--pack <path...>",
|
|
16687
|
-
"Path(s) to rule pack(s) (
|
|
16515
|
+
"Path(s) to rule pack(s) (.grx2 encrypted or unencrypted JS/TS modules)"
|
|
16688
16516
|
).option(
|
|
16689
16517
|
"--license-key <key>",
|
|
16690
16518
|
"License key for encrypted rule packs (or set SENTRIFLOW_LICENSE_KEY)"
|
|
@@ -17380,7 +17208,7 @@ Scan complete: ${allFileResults.length} files, ${totalFailures} failures, ${tota
|
|
|
17380
17208
|
} else {
|
|
17381
17209
|
try {
|
|
17382
17210
|
vendor = getVendor(options.vendor);
|
|
17383
|
-
} catch
|
|
17211
|
+
} catch {
|
|
17384
17212
|
console.error(`Error: Unknown vendor '${options.vendor}'`);
|
|
17385
17213
|
console.error(
|
|
17386
17214
|
`Available vendors: ${getAvailableVendors().join(", ")}, auto`
|
|
@@ -17477,7 +17305,7 @@ async function loadLicensingExtension() {
|
|
|
17477
17305
|
licensingModulePath
|
|
17478
17306
|
);
|
|
17479
17307
|
if (licensing.registerCommands) {
|
|
17480
|
-
licensing.registerCommands(program);
|
|
17308
|
+
licensing.registerCommands(program, { cliVersion: "0.4.2" });
|
|
17481
17309
|
}
|
|
17482
17310
|
} catch {
|
|
17483
17311
|
const licensingMessage = `
|