@sentriflow/cli 0.4.0 → 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.
Files changed (3) hide show
  1. package/README.md +7 -3
  2. package/dist/index.js +118 -290
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @sentriflow/cli
2
2
 
3
- Command-line interface for SentriFlow - check network configurations for compliance against best practices or organization-specific policies.
3
+ Command-line interface for SentriFlow - validate network configurations against best practices or organization-specific policies.
4
4
 
5
5
  ## Installation
6
6
 
@@ -53,7 +53,7 @@ cat router.conf | sentriflow -
53
53
  ```
54
54
  Usage: sentriflow [options] [file]
55
55
 
56
- SentriFlow Network Configuration Compliance Checker
56
+ SentriFlow Network Configuration Validator
57
57
 
58
58
  Arguments:
59
59
  file Path to the configuration file (use - for stdin)
@@ -321,7 +321,11 @@ SentriFlow automatically looks for `.sentriflowrc` or `.sentriflowrc.json` in th
321
321
  ## Related Packages
322
322
 
323
323
  - [`@sentriflow/core`](https://github.com/sentriflow/sentriflow/tree/main/packages/core) - Core parsing and compliance engine
324
- - [`@sentriflow/rules-default`](https://github.com/sentriflow/sentriflow/tree/main/packages/rules-default) - Default compliance rules
324
+ - [`@sentriflow/rules-default`](https://github.com/sentriflow/sentriflow/tree/main/packages/rules-default) - Default validation rules
325
+
326
+ ## Disclaimer
327
+
328
+ SentriFlow provides automated configuration validation. Validation results indicate technical alignment with security standards but do not constitute compliance certification. Consult qualified auditors for official compliance assessments.
325
329
 
326
330
  ## License
327
331
 
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 as createDecipheriv2,
10540
+ createDecipheriv,
10742
10541
  createHash,
10743
- pbkdf2Sync as pbkdf2Sync2,
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 pbkdf2Sync2(licenseKey, combinedSalt, PBKDF2_ITERATIONS, AES_KEY_SIZE, "sha256");
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 = createDecipheriv2(AES_ALGORITHM, key, iv);
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 as createContext2, Script as Script2 } from "vm";
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 createContext2(Object.freeze(sandboxObj));
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 Script2(`(${expr})`, {
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 Script2(`(${expr})`, {
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 = createContext2({
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.0",
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.0",
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
- loadedPack = await loadExtendedPack(
16273
- validation.canonicalPath,
16126
+ const result = await loadGRX2Pack({
16127
+ filePath: validation.canonicalPath,
16274
16128
  licenseKey,
16275
- machineId2
16276
- );
16277
- loadedPack.priority = desc.priority;
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
- let errorMsg;
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.0").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(
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) (auto-detects format: .grx2, .grpx, or unencrypted)"
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 (e) {
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 = `
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sentriflow/cli",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "description": "SentriFlow CLI - Network configuration linter and validator",
5
5
  "license": "Apache-2.0",
6
6
  "main": "dist/index.js",