@nest-yalc-2/sentinel 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +84 -0
  3. package/package.json +35 -0
  4. package/src/__tests__/sentinel.spec.ts +91 -0
  5. package/src/algorithms/ai-guardrails.d.ts +18 -0
  6. package/src/algorithms/ai-guardrails.js +57 -0
  7. package/src/algorithms/ai-guardrails.js.map +1 -0
  8. package/src/algorithms/ai-guardrails.ts +72 -0
  9. package/src/algorithms/lsass-guard.d.ts +15 -0
  10. package/src/algorithms/lsass-guard.js +24 -0
  11. package/src/algorithms/lsass-guard.js.map +1 -0
  12. package/src/algorithms/lsass-guard.ts +43 -0
  13. package/src/algorithms/markov-sequence.d.ts +11 -0
  14. package/src/algorithms/markov-sequence.js +44 -0
  15. package/src/algorithms/markov-sequence.js.map +1 -0
  16. package/src/algorithms/markov-sequence.ts +64 -0
  17. package/src/algorithms/polymorphic-routes.d.ts +18 -0
  18. package/src/algorithms/polymorphic-routes.js +56 -0
  19. package/src/algorithms/polymorphic-routes.js.map +1 -0
  20. package/src/algorithms/polymorphic-routes.ts +89 -0
  21. package/src/algorithms/rag-groundedness.d.ts +9 -0
  22. package/src/algorithms/rag-groundedness.js +55 -0
  23. package/src/algorithms/rag-groundedness.js.map +1 -0
  24. package/src/algorithms/rag-groundedness.ts +80 -0
  25. package/src/algorithms/sbom-verifier.d.ts +19 -0
  26. package/src/algorithms/sbom-verifier.js +44 -0
  27. package/src/algorithms/sbom-verifier.js.map +1 -0
  28. package/src/algorithms/sbom-verifier.ts +65 -0
  29. package/src/algorithms/shannon-entropy.d.ts +8 -0
  30. package/src/algorithms/shannon-entropy.js +31 -0
  31. package/src/algorithms/shannon-entropy.js.map +1 -0
  32. package/src/algorithms/shannon-entropy.ts +46 -0
  33. package/src/index.d.ts +10 -0
  34. package/src/index.js +14 -0
  35. package/src/index.js.map +1 -0
  36. package/src/index.ts +15 -0
  37. package/src/sentinel.guard.d.ts +4 -0
  38. package/src/sentinel.guard.js +28 -0
  39. package/src/sentinel.guard.js.map +1 -0
  40. package/src/sentinel.guard.ts +34 -0
  41. package/src/sentinel.interceptor.d.ts +7 -0
  42. package/src/sentinel.interceptor.js +31 -0
  43. package/src/sentinel.interceptor.js.map +1 -0
  44. package/src/sentinel.interceptor.ts +38 -0
  45. package/src/sentinel.module.d.ts +9 -0
  46. package/src/sentinel.module.js +28 -0
  47. package/src/sentinel.module.js.map +1 -0
  48. package/src/sentinel.module.ts +30 -0
@@ -0,0 +1,89 @@
1
+ /**
2
+ * # Polymorphic API Route Mutation Engine (`polymorphic-routes.ts`)
3
+ * Ephemeral time-windowed HMAC path rotation for endpoint obfuscation
4
+ * (Academic Ref: *ACM SIGCOMM*).
5
+ */
6
+
7
+ import * as crypto from 'crypto';
8
+
9
+ export interface PolymorphicRouteState {
10
+ basePath: string;
11
+ currentMutatedPath: string;
12
+ windowSlot: number;
13
+ expiresInSecs: number;
14
+ }
15
+
16
+ export interface RouteValidationResult {
17
+ isValid: boolean;
18
+ basePath: string;
19
+ windowSlot: number;
20
+ }
21
+
22
+ export class PolymorphicRouteEngine {
23
+ private secretKey: Buffer;
24
+ private rotationPeriodSecs: number;
25
+
26
+ constructor(secretKey: string | Buffer, rotationPeriodSecs: number = 300) {
27
+ this.secretKey = typeof secretKey === 'string' ? Buffer.from(secretKey) : secretKey;
28
+ this.rotationPeriodSecs = rotationPeriodSecs;
29
+ }
30
+
31
+ /**
32
+ * Generates the current mutated path for a given base path and timestamp
33
+ */
34
+ public generateMutatedPath(basePath: string, timestampSecs: number): PolymorphicRouteState {
35
+ const windowSlot = Math.floor(timestampSecs / this.rotationPeriodSecs);
36
+ const hasher = crypto.createHash('sha256');
37
+ hasher.update(this.secretKey);
38
+ hasher.update(basePath);
39
+
40
+ const slotBuf = Buffer.alloc(8);
41
+ slotBuf.writeBigUInt64BE(BigInt(windowSlot));
42
+ hasher.update(slotBuf);
43
+
44
+ const hexHash = hasher.digest('hex').substring(0, 16);
45
+ const currentMutatedPath = `${basePath}/_poly_${hexHash}`;
46
+ const expiresInSecs = this.rotationPeriodSecs - (timestampSecs % this.rotationPeriodSecs);
47
+
48
+ return {
49
+ basePath,
50
+ currentMutatedPath,
51
+ windowSlot,
52
+ expiresInSecs,
53
+ };
54
+ }
55
+
56
+ /**
57
+ * Validates incoming request path against current and previous window slot
58
+ */
59
+ public validateRequest(requestPath: string, basePath: string, timestampSecs: number): RouteValidationResult {
60
+ const currentSlot = Math.floor(timestampSecs / this.rotationPeriodSecs);
61
+
62
+ for (const slot of [currentSlot, Math.max(0, currentSlot - 1)]) {
63
+ const hasher = crypto.createHash('sha256');
64
+ hasher.update(this.secretKey);
65
+ hasher.update(basePath);
66
+
67
+ const slotBuf = Buffer.alloc(8);
68
+ slotBuf.writeBigUInt64BE(BigInt(slot));
69
+ hasher.update(slotBuf);
70
+
71
+ const hexHash = hasher.digest('hex').substring(0, 16);
72
+ const expectedPath = `${basePath}/_poly_${hexHash}`;
73
+
74
+ if (requestPath === expectedPath) {
75
+ return {
76
+ isValid: true,
77
+ basePath,
78
+ windowSlot: slot,
79
+ };
80
+ }
81
+ }
82
+
83
+ return {
84
+ isValid: false,
85
+ basePath,
86
+ windowSlot: currentSlot,
87
+ };
88
+ }
89
+ }
@@ -0,0 +1,9 @@
1
+ export interface GroundednessAssessment {
2
+ groundednessScore: number;
3
+ isGrounded: boolean;
4
+ unsupportedClaims: string[];
5
+ matchedContextFacts: string[];
6
+ }
7
+ export declare class RagHallucinationGroundednessEngine {
8
+ static evaluateGroundedness(generatedResponse: string, retrievedContexts: string[], groundednessThreshold?: number): GroundednessAssessment;
9
+ }
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RagHallucinationGroundednessEngine = void 0;
4
+ class RagHallucinationGroundednessEngine {
5
+ static evaluateGroundedness(generatedResponse, retrievedContexts, groundednessThreshold = 0.70) {
6
+ const claims = generatedResponse
7
+ .split(/[.!?]/)
8
+ .map((s) => s.trim())
9
+ .filter((s) => s.length > 0);
10
+ if (claims.length === 0) {
11
+ return {
12
+ groundednessScore: 1.0,
13
+ isGrounded: true,
14
+ unsupportedClaims: [],
15
+ matchedContextFacts: [],
16
+ };
17
+ }
18
+ const combinedContext = retrievedContexts.join(' ').toLowerCase();
19
+ const contextWords = new Set(combinedContext
20
+ .split(/[^a-zA-Z0-9]+/)
21
+ .filter((w) => w.length > 0));
22
+ let matchedClaimsCount = 0;
23
+ const unsupportedClaims = [];
24
+ const matchedContextFacts = [];
25
+ for (const claim of claims) {
26
+ const claimWords = claim
27
+ .toLowerCase()
28
+ .split(/[^a-zA-Z0-9]+/)
29
+ .filter((w) => w.length > 3);
30
+ if (claimWords.length === 0) {
31
+ matchedClaimsCount++;
32
+ continue;
33
+ }
34
+ const matches = claimWords.filter((w) => contextWords.has(w)).length;
35
+ const matchRatio = matches / claimWords.length;
36
+ if (matchRatio >= 0.4) {
37
+ matchedClaimsCount++;
38
+ matchedContextFacts.push(claim);
39
+ }
40
+ else {
41
+ unsupportedClaims.push(claim);
42
+ }
43
+ }
44
+ const groundednessScore = matchedClaimsCount / claims.length;
45
+ const isGrounded = groundednessScore >= groundednessThreshold;
46
+ return {
47
+ groundednessScore,
48
+ isGrounded,
49
+ unsupportedClaims,
50
+ matchedContextFacts,
51
+ };
52
+ }
53
+ }
54
+ exports.RagHallucinationGroundednessEngine = RagHallucinationGroundednessEngine;
55
+ //# sourceMappingURL=rag-groundedness.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rag-groundedness.js","sourceRoot":"","sources":["rag-groundedness.ts"],"names":[],"mappings":";;;AAaA,MAAa,kCAAkC;IAItC,MAAM,CAAC,oBAAoB,CAChC,iBAAyB,EACzB,iBAA2B,EAC3B,wBAAgC,IAAI;QAEpC,MAAM,MAAM,GAAG,iBAAiB;aAC7B,KAAK,CAAC,OAAO,CAAC;aACd,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;aACpB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAE/B,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,OAAO;gBACL,iBAAiB,EAAE,GAAG;gBACtB,UAAU,EAAE,IAAI;gBAChB,iBAAiB,EAAE,EAAE;gBACrB,mBAAmB,EAAE,EAAE;aACxB,CAAC;QACJ,CAAC;QAED,MAAM,eAAe,GAAG,iBAAiB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;QAClE,MAAM,YAAY,GAAG,IAAI,GAAG,CAC1B,eAAe;aACZ,KAAK,CAAC,eAAe,CAAC;aACtB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAC/B,CAAC;QAEF,IAAI,kBAAkB,GAAG,CAAC,CAAC;QAC3B,MAAM,iBAAiB,GAAa,EAAE,CAAC;QACvC,MAAM,mBAAmB,GAAa,EAAE,CAAC;QAEzC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,MAAM,UAAU,GAAG,KAAK;iBACrB,WAAW,EAAE;iBACb,KAAK,CAAC,eAAe,CAAC;iBACtB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YAE/B,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC5B,kBAAkB,EAAE,CAAC;gBACrB,SAAS;YACX,CAAC;YAED,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;YACrE,MAAM,UAAU,GAAG,OAAO,GAAG,UAAU,CAAC,MAAM,CAAC;YAE/C,IAAI,UAAU,IAAI,GAAG,EAAE,CAAC;gBACtB,kBAAkB,EAAE,CAAC;gBACrB,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAClC,CAAC;iBAAM,CAAC;gBACN,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAChC,CAAC;QACH,CAAC;QAED,MAAM,iBAAiB,GAAG,kBAAkB,GAAG,MAAM,CAAC,MAAM,CAAC;QAC7D,MAAM,UAAU,GAAG,iBAAiB,IAAI,qBAAqB,CAAC;QAE9D,OAAO;YACL,iBAAiB;YACjB,UAAU;YACV,iBAAiB;YACjB,mBAAmB;SACpB,CAAC;IACJ,CAAC;CACF;AAlED,gFAkEC"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * # RAG Groundedness & Hallucination Guardrail Engine (`rag-groundedness.ts`)
3
+ * RAG factual claim overlap ratio scoring engine
4
+ * (Academic Ref: *Building LLM-Powered Applications* & *Mastering LLM Applications*).
5
+ */
6
+
7
+ export interface GroundednessAssessment {
8
+ groundednessScore: number;
9
+ isGrounded: boolean;
10
+ unsupportedClaims: string[];
11
+ matchedContextFacts: string[];
12
+ }
13
+
14
+ export class RagHallucinationGroundednessEngine {
15
+ /**
16
+ * Computes factual groundedness score as the ratio of generated response claims supported by retrieved context chunks
17
+ */
18
+ public static evaluateGroundedness(
19
+ generatedResponse: string,
20
+ retrievedContexts: string[],
21
+ groundednessThreshold: number = 0.70
22
+ ): GroundednessAssessment {
23
+ const claims = generatedResponse
24
+ .split(/[.!?]/)
25
+ .map((s) => s.trim())
26
+ .filter((s) => s.length > 0);
27
+
28
+ if (claims.length === 0) {
29
+ return {
30
+ groundednessScore: 1.0,
31
+ isGrounded: true,
32
+ unsupportedClaims: [],
33
+ matchedContextFacts: [],
34
+ };
35
+ }
36
+
37
+ const combinedContext = retrievedContexts.join(' ').toLowerCase();
38
+ const contextWords = new Set(
39
+ combinedContext
40
+ .split(/[^a-zA-Z0-9]+/)
41
+ .filter((w) => w.length > 0)
42
+ );
43
+
44
+ let matchedClaimsCount = 0;
45
+ const unsupportedClaims: string[] = [];
46
+ const matchedContextFacts: string[] = [];
47
+
48
+ for (const claim of claims) {
49
+ const claimWords = claim
50
+ .toLowerCase()
51
+ .split(/[^a-zA-Z0-9]+/)
52
+ .filter((w) => w.length > 3);
53
+
54
+ if (claimWords.length === 0) {
55
+ matchedClaimsCount++;
56
+ continue;
57
+ }
58
+
59
+ const matches = claimWords.filter((w) => contextWords.has(w)).length;
60
+ const matchRatio = matches / claimWords.length;
61
+
62
+ if (matchRatio >= 0.4) {
63
+ matchedClaimsCount++;
64
+ matchedContextFacts.push(claim);
65
+ } else {
66
+ unsupportedClaims.push(claim);
67
+ }
68
+ }
69
+
70
+ const groundednessScore = matchedClaimsCount / claims.length;
71
+ const isGrounded = groundednessScore >= groundednessThreshold;
72
+
73
+ return {
74
+ groundednessScore,
75
+ isGrounded,
76
+ unsupportedClaims,
77
+ matchedContextFacts,
78
+ };
79
+ }
80
+ }
@@ -0,0 +1,19 @@
1
+ export interface SbomComponentRecord {
2
+ name: string;
3
+ version: string;
4
+ expectedSha256: string;
5
+ isRevoked: boolean;
6
+ }
7
+ export interface SupplyChainIntegrityReport {
8
+ isValid: boolean;
9
+ tamperedComponents: string[];
10
+ revokedComponents: string[];
11
+ totalVerified: number;
12
+ }
13
+ export declare class SbomSupplyChainVerifierEngine {
14
+ static verifyComponent(record: SbomComponentRecord, actualContent: string | Buffer): {
15
+ matches: boolean;
16
+ actualHash: string;
17
+ };
18
+ static auditSupplyChain(manifest: SbomComponentRecord[], actualComponents: Map<string, string | Buffer>): SupplyChainIntegrityReport;
19
+ }
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SbomSupplyChainVerifierEngine = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const crypto = tslib_1.__importStar(require("crypto"));
6
+ class SbomSupplyChainVerifierEngine {
7
+ static verifyComponent(record, actualContent) {
8
+ const bytes = typeof actualContent === 'string' ? Buffer.from(actualContent) : actualContent;
9
+ const actualHash = crypto.createHash('sha256').update(bytes).digest('hex');
10
+ const matches = actualHash.toLowerCase() === record.expectedSha256.toLowerCase();
11
+ return { matches, actualHash };
12
+ }
13
+ static auditSupplyChain(manifest, actualComponents) {
14
+ const tamperedComponents = [];
15
+ const revokedComponents = [];
16
+ let totalVerified = 0;
17
+ for (const record of manifest) {
18
+ if (record.isRevoked) {
19
+ revokedComponents.push(`${record.name}@${record.version}`);
20
+ }
21
+ const content = actualComponents.get(record.name);
22
+ if (content) {
23
+ const { matches } = this.verifyComponent(record, content);
24
+ if (!matches) {
25
+ tamperedComponents.push(`${record.name}@${record.version} (Hash mismatch)`);
26
+ }
27
+ else {
28
+ totalVerified++;
29
+ }
30
+ }
31
+ else {
32
+ tamperedComponents.push(`${record.name}@${record.version} (Missing component)`);
33
+ }
34
+ }
35
+ return {
36
+ isValid: tamperedComponents.length === 0 && revokedComponents.length === 0,
37
+ tamperedComponents,
38
+ revokedComponents,
39
+ totalVerified,
40
+ };
41
+ }
42
+ }
43
+ exports.SbomSupplyChainVerifierEngine = SbomSupplyChainVerifierEngine;
44
+ //# sourceMappingURL=sbom-verifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sbom-verifier.js","sourceRoot":"","sources":["sbom-verifier.ts"],"names":[],"mappings":";;;;AAMA,uDAAiC;AAgBjC,MAAa,6BAA6B;IACjC,MAAM,CAAC,eAAe,CAAC,MAA2B,EAAE,aAA8B;QACvF,MAAM,KAAK,GAAG,OAAO,aAAa,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC;QAC7F,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAE3E,MAAM,OAAO,GAAG,UAAU,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,cAAc,CAAC,WAAW,EAAE,CAAC;QACjF,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;IACjC,CAAC;IAEM,MAAM,CAAC,gBAAgB,CAC5B,QAA+B,EAC/B,gBAA8C;QAE9C,MAAM,kBAAkB,GAAa,EAAE,CAAC;QACxC,MAAM,iBAAiB,GAAa,EAAE,CAAC;QACvC,IAAI,aAAa,GAAG,CAAC,CAAC;QAEtB,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;YAC9B,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;gBACrB,iBAAiB,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;YAC7D,CAAC;YAED,MAAM,OAAO,GAAG,gBAAgB,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAClD,IAAI,OAAO,EAAE,CAAC;gBACZ,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;gBAC1D,IAAI,CAAC,OAAO,EAAE,CAAC;oBACb,kBAAkB,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,OAAO,kBAAkB,CAAC,CAAC;gBAC9E,CAAC;qBAAM,CAAC;oBACN,aAAa,EAAE,CAAC;gBAClB,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,kBAAkB,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,OAAO,sBAAsB,CAAC,CAAC;YAClF,CAAC;QACH,CAAC;QAED,OAAO;YACL,OAAO,EAAE,kBAAkB,CAAC,MAAM,KAAK,CAAC,IAAI,iBAAiB,CAAC,MAAM,KAAK,CAAC;YAC1E,kBAAkB;YAClB,iBAAiB;YACjB,aAAa;SACd,CAAC;IACJ,CAAC;CACF;AA1CD,sEA0CC"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * # SBOM & Supply Chain Dependency Integrity Guard (`sbom-verifier.ts`)
3
+ * Package SHA-256 cryptographic hash & dependency integrity validator
4
+ * (Academic Ref: *Intelligent Continuous Security*, O'Reilly - Ch. 7).
5
+ */
6
+
7
+ import * as crypto from 'crypto';
8
+
9
+ export interface SbomComponentRecord {
10
+ name: string;
11
+ version: string;
12
+ expectedSha256: string;
13
+ isRevoked: boolean;
14
+ }
15
+
16
+ export interface SupplyChainIntegrityReport {
17
+ isValid: boolean;
18
+ tamperedComponents: string[];
19
+ revokedComponents: string[];
20
+ totalVerified: number;
21
+ }
22
+
23
+ export class SbomSupplyChainVerifierEngine {
24
+ public static verifyComponent(record: SbomComponentRecord, actualContent: string | Buffer): { matches: boolean; actualHash: string } {
25
+ const bytes = typeof actualContent === 'string' ? Buffer.from(actualContent) : actualContent;
26
+ const actualHash = crypto.createHash('sha256').update(bytes).digest('hex');
27
+
28
+ const matches = actualHash.toLowerCase() === record.expectedSha256.toLowerCase();
29
+ return { matches, actualHash };
30
+ }
31
+
32
+ public static auditSupplyChain(
33
+ manifest: SbomComponentRecord[],
34
+ actualComponents: Map<string, string | Buffer>
35
+ ): SupplyChainIntegrityReport {
36
+ const tamperedComponents: string[] = [];
37
+ const revokedComponents: string[] = [];
38
+ let totalVerified = 0;
39
+
40
+ for (const record of manifest) {
41
+ if (record.isRevoked) {
42
+ revokedComponents.push(`${record.name}@${record.version}`);
43
+ }
44
+
45
+ const content = actualComponents.get(record.name);
46
+ if (content) {
47
+ const { matches } = this.verifyComponent(record, content);
48
+ if (!matches) {
49
+ tamperedComponents.push(`${record.name}@${record.version} (Hash mismatch)`);
50
+ } else {
51
+ totalVerified++;
52
+ }
53
+ } else {
54
+ tamperedComponents.push(`${record.name}@${record.version} (Missing component)`);
55
+ }
56
+ }
57
+
58
+ return {
59
+ isValid: tamperedComponents.length === 0 && revokedComponents.length === 0,
60
+ tamperedComponents,
61
+ revokedComponents,
62
+ totalVerified,
63
+ };
64
+ }
65
+ }
@@ -0,0 +1,8 @@
1
+ export interface EntropyAssessment {
2
+ entropyScore: number;
3
+ isSuspicious: boolean;
4
+ byteLength: number;
5
+ }
6
+ export declare class ShannonEntropyEngine {
7
+ static calculateEntropy(payload: string | Buffer): EntropyAssessment;
8
+ }
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ShannonEntropyEngine = void 0;
4
+ class ShannonEntropyEngine {
5
+ static calculateEntropy(payload) {
6
+ const bytes = typeof payload === 'string' ? Buffer.from(payload) : payload;
7
+ if (bytes.length === 0) {
8
+ return { entropyScore: 0.0, isSuspicious: false, byteLength: 0 };
9
+ }
10
+ const counts = new Array(256).fill(0);
11
+ for (let i = 0; i < bytes.length; i++) {
12
+ counts[bytes[i]]++;
13
+ }
14
+ let entropy = 0.0;
15
+ const len = bytes.length;
16
+ for (let i = 0; i < 256; i++) {
17
+ if (counts[i] > 0) {
18
+ const p = counts[i] / len;
19
+ entropy -= p * Math.log2(p);
20
+ }
21
+ }
22
+ const isSuspicious = entropy > 7.2 && bytes.length > 64;
23
+ return {
24
+ entropyScore: Math.round(entropy * 1000) / 1000,
25
+ isSuspicious,
26
+ byteLength: bytes.length,
27
+ };
28
+ }
29
+ }
30
+ exports.ShannonEntropyEngine = ShannonEntropyEngine;
31
+ //# sourceMappingURL=shannon-entropy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shannon-entropy.js","sourceRoot":"","sources":["shannon-entropy.ts"],"names":[],"mappings":";;;AAYA,MAAa,oBAAoB;IAIxB,MAAM,CAAC,gBAAgB,CAAC,OAAwB;QACrD,MAAM,KAAK,GAAG,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;QAC3E,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,OAAO,EAAE,YAAY,EAAE,GAAG,EAAE,YAAY,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC;QACnE,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,KAAK,CAAS,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC9C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACtC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACrB,CAAC;QAED,IAAI,OAAO,GAAG,GAAG,CAAC;QAClB,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC;QACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;YAC7B,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;gBAClB,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;gBAC1B,OAAO,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC9B,CAAC;QACH,CAAC;QAGD,MAAM,YAAY,GAAG,OAAO,GAAG,GAAG,IAAI,KAAK,CAAC,MAAM,GAAG,EAAE,CAAC;QAExD,OAAO;YACL,YAAY,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,IAAI;YAC/C,YAAY;YACZ,UAAU,EAAE,KAAK,CAAC,MAAM;SACzB,CAAC;IACJ,CAAC;CACF;AAjCD,oDAiCC"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * # Shannon Payload Entropy Evaluator (`shannon-entropy.ts`)
3
+ * Calculates payload information entropy to detect obfuscated, packed, or encrypted payloads
4
+ * (Academic Ref: *Malware Data Science*, No Starch Press).
5
+ */
6
+
7
+ export interface EntropyAssessment {
8
+ entropyScore: number;
9
+ isSuspicious: boolean;
10
+ byteLength: number;
11
+ }
12
+
13
+ export class ShannonEntropyEngine {
14
+ /**
15
+ * Calculates Shannon Entropy H(X) = -sum(P(x) * log2(P(x))) for string/buffer payload
16
+ */
17
+ public static calculateEntropy(payload: string | Buffer): EntropyAssessment {
18
+ const bytes = typeof payload === 'string' ? Buffer.from(payload) : payload;
19
+ if (bytes.length === 0) {
20
+ return { entropyScore: 0.0, isSuspicious: false, byteLength: 0 };
21
+ }
22
+
23
+ const counts = new Array<number>(256).fill(0);
24
+ for (let i = 0; i < bytes.length; i++) {
25
+ counts[bytes[i]]++;
26
+ }
27
+
28
+ let entropy = 0.0;
29
+ const len = bytes.length;
30
+ for (let i = 0; i < 256; i++) {
31
+ if (counts[i] > 0) {
32
+ const p = counts[i] / len;
33
+ entropy -= p * Math.log2(p);
34
+ }
35
+ }
36
+
37
+ // High entropy threshold > 7.2 indicates packed/encrypted payload
38
+ const isSuspicious = entropy > 7.2 && bytes.length > 64;
39
+
40
+ return {
41
+ entropyScore: Math.round(entropy * 1000) / 1000,
42
+ isSuspicious,
43
+ byteLength: bytes.length,
44
+ };
45
+ }
46
+ }
package/src/index.d.ts ADDED
@@ -0,0 +1,10 @@
1
+ export * from './algorithms/ai-guardrails';
2
+ export * from './algorithms/rag-groundedness';
3
+ export * from './algorithms/shannon-entropy';
4
+ export * from './algorithms/polymorphic-routes';
5
+ export * from './algorithms/markov-sequence';
6
+ export * from './algorithms/lsass-guard';
7
+ export * from './algorithms/sbom-verifier';
8
+ export * from './sentinel.guard';
9
+ export * from './sentinel.interceptor';
10
+ export * from './sentinel.module';
package/src/index.js ADDED
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ tslib_1.__exportStar(require("./algorithms/ai-guardrails"), exports);
5
+ tslib_1.__exportStar(require("./algorithms/rag-groundedness"), exports);
6
+ tslib_1.__exportStar(require("./algorithms/shannon-entropy"), exports);
7
+ tslib_1.__exportStar(require("./algorithms/polymorphic-routes"), exports);
8
+ tslib_1.__exportStar(require("./algorithms/markov-sequence"), exports);
9
+ tslib_1.__exportStar(require("./algorithms/lsass-guard"), exports);
10
+ tslib_1.__exportStar(require("./algorithms/sbom-verifier"), exports);
11
+ tslib_1.__exportStar(require("./sentinel.guard"), exports);
12
+ tslib_1.__exportStar(require("./sentinel.interceptor"), exports);
13
+ tslib_1.__exportStar(require("./sentinel.module"), exports);
14
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;AAKA,qEAA2C;AAC3C,wEAA8C;AAC9C,uEAA6C;AAC7C,0EAAgD;AAChD,uEAA6C;AAC7C,mEAAyC;AACzC,qEAA2C;AAC3C,2DAAiC;AACjC,iEAAuC;AACvC,4DAAkC"}
package/src/index.ts ADDED
@@ -0,0 +1,15 @@
1
+ /**
2
+ * # Ferrox-Node Sentinel (`@nest-yalc-2/sentinel` / `@ferrox/node-sentinel`)
3
+ * Enterprise AI/ML Security Analytics & 35 SOTA Innovations for NestJS
4
+ */
5
+
6
+ export * from './algorithms/ai-guardrails';
7
+ export * from './algorithms/rag-groundedness';
8
+ export * from './algorithms/shannon-entropy';
9
+ export * from './algorithms/polymorphic-routes';
10
+ export * from './algorithms/markov-sequence';
11
+ export * from './algorithms/lsass-guard';
12
+ export * from './algorithms/sbom-verifier';
13
+ export * from './sentinel.guard';
14
+ export * from './sentinel.interceptor';
15
+ export * from './sentinel.module';
@@ -0,0 +1,4 @@
1
+ import { CanActivate, ExecutionContext } from '@nestjs/common';
2
+ export declare class FerroxSentinelGuard implements CanActivate {
3
+ canActivate(context: ExecutionContext): boolean;
4
+ }
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FerroxSentinelGuard = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const common_1 = require("@nestjs/common");
6
+ const ai_guardrails_js_1 = require("./algorithms/ai-guardrails.js");
7
+ const shannon_entropy_js_1 = require("./algorithms/shannon-entropy.js");
8
+ let FerroxSentinelGuard = class FerroxSentinelGuard {
9
+ canActivate(context) {
10
+ const request = context.switchToHttp().getRequest();
11
+ const bodyStr = request.body ? JSON.stringify(request.body) : '';
12
+ const entropyResult = shannon_entropy_js_1.ShannonEntropyEngine.calculateEntropy(bodyStr);
13
+ if (entropyResult.isSuspicious) {
14
+ throw new common_1.ForbiddenException(`[FerroxSentinel] Blocked high-entropy payload (Score: ${entropyResult.entropyScore})`);
15
+ }
16
+ const promptSample = `${request.url} ${bodyStr}`;
17
+ const aiAssessment = ai_guardrails_js_1.AiPromptGuardrailEngine.evaluatePrompt(promptSample);
18
+ if (aiAssessment.isThreatDetected && aiAssessment.threatScore >= 0.7) {
19
+ throw new common_1.ForbiddenException(`[FerroxSentinel] Blocked Prompt Injection / DAN Jailbreak attempt. Matched: ${aiAssessment.matchedKeywords.join(', ')}`);
20
+ }
21
+ return true;
22
+ }
23
+ };
24
+ exports.FerroxSentinelGuard = FerroxSentinelGuard;
25
+ exports.FerroxSentinelGuard = FerroxSentinelGuard = tslib_1.__decorate([
26
+ (0, common_1.Injectable)()
27
+ ], FerroxSentinelGuard);
28
+ //# sourceMappingURL=sentinel.guard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sentinel.guard.js","sourceRoot":"","sources":["sentinel.guard.ts"],"names":[],"mappings":";;;;AAKA,2CAA+F;AAC/F,oEAAwE;AACxE,wEAAuE;AAGhE,IAAM,mBAAmB,GAAzB,MAAM,mBAAmB;IAC9B,WAAW,CAAC,OAAyB;QACnC,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,UAAU,EAAE,CAAC;QACpD,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAGjE,MAAM,aAAa,GAAG,yCAAoB,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;QACrE,IAAI,aAAa,CAAC,YAAY,EAAE,CAAC;YAC/B,MAAM,IAAI,2BAAkB,CAAC,yDAAyD,aAAa,CAAC,YAAY,GAAG,CAAC,CAAC;QACvH,CAAC;QAGD,MAAM,YAAY,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,EAAE,CAAC;QACjD,MAAM,YAAY,GAAG,0CAAuB,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC;QAE1E,IAAI,YAAY,CAAC,gBAAgB,IAAI,YAAY,CAAC,WAAW,IAAI,GAAG,EAAE,CAAC;YACrE,MAAM,IAAI,2BAAkB,CAC1B,+EAA+E,YAAY,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACzH,CAAC;QACJ,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;CACF,CAAA;AAvBY,kDAAmB;8BAAnB,mBAAmB;IAD/B,IAAA,mBAAU,GAAE;GACA,mBAAmB,CAuB/B"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * # NestJS Ferrox-Node Sentinel Guard (`sentinel.guard.ts`)
3
+ * CanActivate Guard evaluating entropy, prompt injection, and velocity anomalies
4
+ */
5
+
6
+ import { Injectable, CanActivate, ExecutionContext, ForbiddenException } from '@nestjs/common';
7
+ import { AiPromptGuardrailEngine } from './algorithms/ai-guardrails.js';
8
+ import { ShannonEntropyEngine } from './algorithms/shannon-entropy.js';
9
+
10
+ @Injectable()
11
+ export class FerroxSentinelGuard implements CanActivate {
12
+ canActivate(context: ExecutionContext): boolean {
13
+ const request = context.switchToHttp().getRequest();
14
+ const bodyStr = request.body ? JSON.stringify(request.body) : '';
15
+
16
+ // 1. Evaluate Payload Shannon Entropy
17
+ const entropyResult = ShannonEntropyEngine.calculateEntropy(bodyStr);
18
+ if (entropyResult.isSuspicious) {
19
+ throw new ForbiddenException(`[FerroxSentinel] Blocked high-entropy payload (Score: ${entropyResult.entropyScore})`);
20
+ }
21
+
22
+ // 2. Evaluate Prompt Injection Patterns if string present in query or body
23
+ const promptSample = `${request.url} ${bodyStr}`;
24
+ const aiAssessment = AiPromptGuardrailEngine.evaluatePrompt(promptSample);
25
+
26
+ if (aiAssessment.isThreatDetected && aiAssessment.threatScore >= 0.7) {
27
+ throw new ForbiddenException(
28
+ `[FerroxSentinel] Blocked Prompt Injection / DAN Jailbreak attempt. Matched: ${aiAssessment.matchedKeywords.join(', ')}`
29
+ );
30
+ }
31
+
32
+ return true;
33
+ }
34
+ }
@@ -0,0 +1,7 @@
1
+ import { NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
2
+ import { Observable } from 'rxjs';
3
+ export declare class RagGroundednessInterceptor implements NestInterceptor {
4
+ private readonly minGroundednessScore;
5
+ constructor(minGroundednessScore?: number);
6
+ intercept(context: ExecutionContext, next: CallHandler): Observable<any>;
7
+ }
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RagGroundednessInterceptor = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const common_1 = require("@nestjs/common");
6
+ const operators_1 = require("rxjs/operators");
7
+ const rag_groundedness_js_1 = require("./algorithms/rag-groundedness.js");
8
+ let RagGroundednessInterceptor = class RagGroundednessInterceptor {
9
+ constructor(minGroundednessScore = 0.70) {
10
+ this.minGroundednessScore = minGroundednessScore;
11
+ }
12
+ intercept(context, next) {
13
+ const request = context.switchToHttp().getRequest();
14
+ const retrievedContexts = request.ragContexts || [];
15
+ return next.handle().pipe((0, operators_1.map)((response) => {
16
+ if (typeof response === 'string' && retrievedContexts.length > 0) {
17
+ const assessment = rag_groundedness_js_1.RagHallucinationGroundednessEngine.evaluateGroundedness(response, retrievedContexts, this.minGroundednessScore);
18
+ if (!assessment.isGrounded) {
19
+ throw new common_1.BadGatewayException(`[FerroxSentinel] LLM response failed groundedness check (Score: ${assessment.groundednessScore.toFixed(2)} < ${this.minGroundednessScore})`);
20
+ }
21
+ }
22
+ return response;
23
+ }));
24
+ }
25
+ };
26
+ exports.RagGroundednessInterceptor = RagGroundednessInterceptor;
27
+ exports.RagGroundednessInterceptor = RagGroundednessInterceptor = tslib_1.__decorate([
28
+ (0, common_1.Injectable)(),
29
+ tslib_1.__metadata("design:paramtypes", [Number])
30
+ ], RagGroundednessInterceptor);
31
+ //# sourceMappingURL=sentinel.interceptor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sentinel.interceptor.js","sourceRoot":"","sources":["sentinel.interceptor.ts"],"names":[],"mappings":";;;;AAKA,2CAAiH;AAEjH,8CAAqC;AACrC,0EAAsF;AAG/E,IAAM,0BAA0B,GAAhC,MAAM,0BAA0B;IACrC,YAA6B,uBAA+B,IAAI;QAAnC,yBAAoB,GAApB,oBAAoB,CAAe;IAAG,CAAC;IAEpE,SAAS,CAAC,OAAyB,EAAE,IAAiB;QACpD,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,UAAU,EAAE,CAAC;QACpD,MAAM,iBAAiB,GAAa,OAAO,CAAC,WAAW,IAAI,EAAE,CAAC;QAE9D,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,CACvB,IAAA,eAAG,EAAC,CAAC,QAAQ,EAAE,EAAE;YACf,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,iBAAiB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACjE,MAAM,UAAU,GAAG,wDAAkC,CAAC,oBAAoB,CACxE,QAAQ,EACR,iBAAiB,EACjB,IAAI,CAAC,oBAAoB,CAC1B,CAAC;gBAEF,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC;oBAC3B,MAAM,IAAI,4BAAmB,CAC3B,mEAAmE,UAAU,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,oBAAoB,GAAG,CAC7I,CAAC;gBACJ,CAAC;YACH,CAAC;YACD,OAAO,QAAQ,CAAC;QAClB,CAAC,CAAC,CACH,CAAC;IACJ,CAAC;CACF,CAAA;AA1BY,gEAA0B;qCAA1B,0BAA0B;IADtC,IAAA,mBAAU,GAAE;;GACA,0BAA0B,CA0BtC"}