@keynv/core 0.1.0-rc.23

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 (78) hide show
  1. package/LICENSE +21 -0
  2. package/dist/audit/chain.d.ts +44 -0
  3. package/dist/audit/chain.d.ts.map +1 -0
  4. package/dist/audit/chain.js +134 -0
  5. package/dist/audit/chain.js.map +1 -0
  6. package/dist/audit/chain.test.d.ts +2 -0
  7. package/dist/audit/chain.test.d.ts.map +1 -0
  8. package/dist/audit/chain.test.js +192 -0
  9. package/dist/audit/chain.test.js.map +1 -0
  10. package/dist/audit/index.d.ts +5 -0
  11. package/dist/audit/index.d.ts.map +1 -0
  12. package/dist/audit/index.js +4 -0
  13. package/dist/audit/index.js.map +1 -0
  14. package/dist/audit/payload-schemas.d.ts +343 -0
  15. package/dist/audit/payload-schemas.d.ts.map +1 -0
  16. package/dist/audit/payload-schemas.js +112 -0
  17. package/dist/audit/payload-schemas.js.map +1 -0
  18. package/dist/audit/payload-schemas.test.d.ts +2 -0
  19. package/dist/audit/payload-schemas.test.d.ts.map +1 -0
  20. package/dist/audit/payload-schemas.test.js +93 -0
  21. package/dist/audit/payload-schemas.test.js.map +1 -0
  22. package/dist/audit/types.d.ts +34 -0
  23. package/dist/audit/types.d.ts.map +1 -0
  24. package/dist/audit/types.js +6 -0
  25. package/dist/audit/types.js.map +1 -0
  26. package/dist/crypto/envelope.d.ts +55 -0
  27. package/dist/crypto/envelope.d.ts.map +1 -0
  28. package/dist/crypto/envelope.js +108 -0
  29. package/dist/crypto/envelope.js.map +1 -0
  30. package/dist/crypto/envelope.test.d.ts +2 -0
  31. package/dist/crypto/envelope.test.d.ts.map +1 -0
  32. package/dist/crypto/envelope.test.js +163 -0
  33. package/dist/crypto/envelope.test.js.map +1 -0
  34. package/dist/crypto/index.d.ts +5 -0
  35. package/dist/crypto/index.d.ts.map +1 -0
  36. package/dist/crypto/index.js +4 -0
  37. package/dist/crypto/index.js.map +1 -0
  38. package/dist/crypto/sodium.d.ts +21 -0
  39. package/dist/crypto/sodium.d.ts.map +1 -0
  40. package/dist/crypto/sodium.js +43 -0
  41. package/dist/crypto/sodium.js.map +1 -0
  42. package/dist/crypto/types.d.ts +37 -0
  43. package/dist/crypto/types.d.ts.map +1 -0
  44. package/dist/crypto/types.js +11 -0
  45. package/dist/crypto/types.js.map +1 -0
  46. package/dist/index.d.ts +5 -0
  47. package/dist/index.d.ts.map +1 -0
  48. package/dist/index.js +5 -0
  49. package/dist/index.js.map +1 -0
  50. package/dist/reference/index.d.ts +4 -0
  51. package/dist/reference/index.d.ts.map +1 -0
  52. package/dist/reference/index.js +3 -0
  53. package/dist/reference/index.js.map +1 -0
  54. package/dist/reference/parser-property.test.d.ts +2 -0
  55. package/dist/reference/parser-property.test.d.ts.map +1 -0
  56. package/dist/reference/parser-property.test.js +115 -0
  57. package/dist/reference/parser-property.test.js.map +1 -0
  58. package/dist/reference/parser.d.ts +54 -0
  59. package/dist/reference/parser.d.ts.map +1 -0
  60. package/dist/reference/parser.js +144 -0
  61. package/dist/reference/parser.js.map +1 -0
  62. package/dist/reference/parser.test.d.ts +2 -0
  63. package/dist/reference/parser.test.d.ts.map +1 -0
  64. package/dist/reference/parser.test.js +195 -0
  65. package/dist/reference/parser.test.js.map +1 -0
  66. package/dist/reference/types.d.ts +52 -0
  67. package/dist/reference/types.d.ts.map +1 -0
  68. package/dist/reference/types.js +11 -0
  69. package/dist/reference/types.js.map +1 -0
  70. package/dist/validation/index.d.ts +33 -0
  71. package/dist/validation/index.d.ts.map +1 -0
  72. package/dist/validation/index.js +45 -0
  73. package/dist/validation/index.js.map +1 -0
  74. package/dist/validation/schemas.test.d.ts +2 -0
  75. package/dist/validation/schemas.test.d.ts.map +1 -0
  76. package/dist/validation/schemas.test.js +18 -0
  77. package/dist/validation/schemas.test.js.map +1 -0
  78. package/package.json +48 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025-2026 keynv-labs and contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,44 @@
1
+ import { type AuditEntry, type AuditInput } from './types.js';
2
+ export declare function configureChainKey(key: Uint8Array | null): void;
3
+ /** True once a tamper-evident chain key has been configured. */
4
+ export declare function isChainKeyConfigured(): boolean;
5
+ /**
6
+ * Computes the hash for a NEW audit entry. When a chain key is configured
7
+ * (via configureChainKey) this is an HMAC-SHA-256 tagged with the `v1:`
8
+ * prefix; otherwise it is a plain SHA-256 (not tamper-evident, legacy/test
9
+ * only).
10
+ */
11
+ export declare function computeHash(prevHash: string, input: AuditInput): string;
12
+ /**
13
+ * Builds the next chain entry. The caller persists the returned object
14
+ * verbatim (id is the auto-incremented row id from the DB).
15
+ *
16
+ * Pass `null` as `prev` when appending the very first entry.
17
+ */
18
+ export declare function appendEntry(prev: AuditEntry | null, input: AuditInput, id: number): AuditEntry;
19
+ export interface VerifyResult {
20
+ readonly ok: boolean;
21
+ /** Index (0-based, into `entries`) of the first inconsistent row. */
22
+ readonly brokenAt?: number;
23
+ readonly reason?: 'prev_hash_mismatch' | 'hash_mismatch';
24
+ }
25
+ export interface VerifyOptions {
26
+ /**
27
+ * The expected `prev_hash` of the first entry in `entries`. Defaults
28
+ * to GENESIS_HASH (the start of the chain). Set to the tail hash of
29
+ * the previous page when verifying a paginated chain so the cross-
30
+ * page boundary is checked. Without this, verifying any chain of
31
+ * more than one page produces a false `prev_hash_mismatch`.
32
+ */
33
+ readonly startingPrevHash?: string;
34
+ }
35
+ /**
36
+ * Walks an audit chain and reports the first inconsistency, if any.
37
+ *
38
+ * Verifies two invariants per row:
39
+ * 1. row.prev_hash equals the predecessor's hash (or
40
+ * `opts.startingPrevHash` / GENESIS_HASH for the first row).
41
+ * 2. row.hash equals the recomputed hash over (prev_hash, inputs).
42
+ */
43
+ export declare function verifyChain(entries: readonly AuditEntry[], opts?: VerifyOptions): VerifyResult;
44
+ //# sourceMappingURL=chain.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chain.d.ts","sourceRoot":"","sources":["../../src/audit/chain.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,UAAU,EAAgB,MAAM,YAAY,CAAC;AAwB5E,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,UAAU,GAAG,IAAI,GAAG,IAAI,CAE9D;AAED,gEAAgE;AAChE,wBAAgB,oBAAoB,IAAI,OAAO,CAE9C;AAgCD;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,MAAM,CAMvE;AAoBD;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,GAAG,UAAU,CAa9F;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,qEAAqE;IACrE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,CAAC,EAAE,oBAAoB,GAAG,eAAe,CAAC;CAC1D;AAED,MAAM,WAAW,aAAa;IAC5B;;;;;;OAMG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CACpC;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,SAAS,UAAU,EAAE,EAC9B,IAAI,GAAE,aAAkB,GACvB,YAAY,CAcd"}
@@ -0,0 +1,134 @@
1
+ import { createHash, createHmac } from 'node:crypto';
2
+ import { GENESIS_HASH } from './types.js';
3
+ /**
4
+ * HMAC key that makes the chain tamper-evident: an attacker with DB write
5
+ * access cannot recompute hashes without it. The server configures it from
6
+ * the KEK at startup (see configureChainKey). When no key is set, hashing
7
+ * uses a plain SHA-256 that is NOT tamper-evident — used only by tests.
8
+ *
9
+ * Keyed hashes carry a `v1:` prefix. Verification is STRICT and symmetric to
10
+ * the current configuration to defeat downgrade attacks: when a key IS
11
+ * configured every row must be a keyed (`v1:`) HMAC (a bare hash is rejected
12
+ * as a downgrade); when NO key is configured every row must be a bare keyless
13
+ * hash. There is intentionally no keyless fallback while a key is present, so
14
+ * an attacker cannot strip the prefix and recompute keyless to forge a row.
15
+ *
16
+ * Migration note: turning the key on establishes tamper-evidence for rows
17
+ * written from then on. A chain that contains rows written by an older
18
+ * keyless build will not HMAC-verify under a configured key — those rows are
19
+ * retained but reported as not verifiable.
20
+ */
21
+ let chainHmacKey = null;
22
+ const HMAC_PREFIX = 'v1:';
23
+ export function configureChainKey(key) {
24
+ chainHmacKey = key;
25
+ }
26
+ /** True once a tamper-evident chain key has been configured. */
27
+ export function isChainKeyConfigured() {
28
+ return chainHmacKey !== null;
29
+ }
30
+ /**
31
+ * JSON-canonicalize a payload so the hash is reproducible regardless of
32
+ * key insertion order. Sorts object keys at every level; arrays keep
33
+ * their original order. Undefined values are normalised to null to
34
+ * avoid JSON.stringify inconsistencies.
35
+ */
36
+ function canonicalize(value) {
37
+ if (value === null || typeof value !== 'object') {
38
+ return value === undefined ? 'null' : JSON.stringify(value);
39
+ }
40
+ if (Array.isArray(value)) {
41
+ return `[${value.map(canonicalize).join(',')}]`;
42
+ }
43
+ const obj = value;
44
+ const keys = Object.keys(obj).sort();
45
+ const parts = keys.map((k) => `${JSON.stringify(k)}:${canonicalize(obj[k])}`);
46
+ return `{${parts.join(',')}}`;
47
+ }
48
+ function canonicalOf(prevHash, input) {
49
+ return canonicalize({
50
+ prev_hash: prevHash,
51
+ ts: input.ts,
52
+ actor_user_id: input.actor_user_id,
53
+ actor_agent: input.actor_agent,
54
+ event_type: input.event_type,
55
+ payload: input.payload,
56
+ });
57
+ }
58
+ /**
59
+ * Computes the hash for a NEW audit entry. When a chain key is configured
60
+ * (via configureChainKey) this is an HMAC-SHA-256 tagged with the `v1:`
61
+ * prefix; otherwise it is a plain SHA-256 (not tamper-evident, legacy/test
62
+ * only).
63
+ */
64
+ export function computeHash(prevHash, input) {
65
+ const canonical = canonicalOf(prevHash, input);
66
+ if (chainHmacKey) {
67
+ return HMAC_PREFIX + createHmac('sha256', chainHmacKey).update(canonical, 'utf8').digest('hex');
68
+ }
69
+ return createHash('sha256').update(canonical, 'utf8').digest('hex');
70
+ }
71
+ /**
72
+ * Recomputes a stored hash and reports whether it matches, STRICTLY in the
73
+ * current key mode so a downgrade is impossible:
74
+ * - key configured → the row MUST be a `v1:` HMAC; a bare hash is rejected.
75
+ * - no key configured → the row MUST be a bare keyless SHA-256; a `v1:` row
76
+ * cannot be verified without the key and is rejected.
77
+ */
78
+ function hashMatches(prevHash, input, storedHash) {
79
+ const canonical = canonicalOf(prevHash, input);
80
+ if (chainHmacKey) {
81
+ if (!storedHash.startsWith(HMAC_PREFIX))
82
+ return false; // downgrade attempt
83
+ const h = `${HMAC_PREFIX}${createHmac('sha256', chainHmacKey).update(canonical, 'utf8').digest('hex')}`;
84
+ return h === storedHash;
85
+ }
86
+ if (storedHash.startsWith(HMAC_PREFIX))
87
+ return false; // keyed row, no key to verify
88
+ return createHash('sha256').update(canonical, 'utf8').digest('hex') === storedHash;
89
+ }
90
+ /**
91
+ * Builds the next chain entry. The caller persists the returned object
92
+ * verbatim (id is the auto-incremented row id from the DB).
93
+ *
94
+ * Pass `null` as `prev` when appending the very first entry.
95
+ */
96
+ export function appendEntry(prev, input, id) {
97
+ const prevHash = prev?.hash ?? GENESIS_HASH;
98
+ const hash = computeHash(prevHash, input);
99
+ return {
100
+ id,
101
+ prev_hash: prevHash,
102
+ hash,
103
+ ts: input.ts,
104
+ actor_user_id: input.actor_user_id,
105
+ actor_agent: input.actor_agent,
106
+ event_type: input.event_type,
107
+ payload: input.payload,
108
+ };
109
+ }
110
+ /**
111
+ * Walks an audit chain and reports the first inconsistency, if any.
112
+ *
113
+ * Verifies two invariants per row:
114
+ * 1. row.prev_hash equals the predecessor's hash (or
115
+ * `opts.startingPrevHash` / GENESIS_HASH for the first row).
116
+ * 2. row.hash equals the recomputed hash over (prev_hash, inputs).
117
+ */
118
+ export function verifyChain(entries, opts = {}) {
119
+ const expectedFirstPrevHash = opts.startingPrevHash ?? GENESIS_HASH;
120
+ for (let i = 0; i < entries.length; i++) {
121
+ const cur = entries[i];
122
+ if (!cur)
123
+ continue;
124
+ const expectedPrevHash = i === 0 ? expectedFirstPrevHash : entries[i - 1]?.hash;
125
+ if (cur.prev_hash !== expectedPrevHash) {
126
+ return { ok: false, brokenAt: i, reason: 'prev_hash_mismatch' };
127
+ }
128
+ if (!hashMatches(cur.prev_hash, cur, cur.hash)) {
129
+ return { ok: false, brokenAt: i, reason: 'hash_mismatch' };
130
+ }
131
+ }
132
+ return { ok: true };
133
+ }
134
+ //# sourceMappingURL=chain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chain.js","sourceRoot":"","sources":["../../src/audit/chain.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAoC,YAAY,EAAE,MAAM,YAAY,CAAC;AAE5E;;;;;;;;;;;;;;;;;GAiBG;AACH,IAAI,YAAY,GAAsB,IAAI,CAAC;AAE3C,MAAM,WAAW,GAAG,KAAK,CAAC;AAE1B,MAAM,UAAU,iBAAiB,CAAC,GAAsB;IACtD,YAAY,GAAG,GAAG,CAAC;AACrB,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,oBAAoB;IAClC,OAAO,YAAY,KAAK,IAAI,CAAC;AAC/B,CAAC;AAED;;;;;GAKG;AACH,SAAS,YAAY,CAAC,KAAc;IAClC,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAChD,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC9D,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,IAAI,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;IAClD,CAAC;IACD,MAAM,GAAG,GAAG,KAAgC,CAAC;IAC7C,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IACrC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAC9E,OAAO,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;AAChC,CAAC;AAED,SAAS,WAAW,CAAC,QAAgB,EAAE,KAAiB;IACtD,OAAO,YAAY,CAAC;QAClB,SAAS,EAAE,QAAQ;QACnB,EAAE,EAAE,KAAK,CAAC,EAAE;QACZ,aAAa,EAAE,KAAK,CAAC,aAAa;QAClC,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,OAAO,EAAE,KAAK,CAAC,OAAO;KACvB,CAAC,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,QAAgB,EAAE,KAAiB;IAC7D,MAAM,SAAS,GAAG,WAAW,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAC/C,IAAI,YAAY,EAAE,CAAC;QACjB,OAAO,WAAW,GAAG,UAAU,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAClG,CAAC;IACD,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACtE,CAAC;AAED;;;;;;GAMG;AACH,SAAS,WAAW,CAAC,QAAgB,EAAE,KAAiB,EAAE,UAAkB;IAC1E,MAAM,SAAS,GAAG,WAAW,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAC/C,IAAI,YAAY,EAAE,CAAC;QACjB,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,WAAW,CAAC;YAAE,OAAO,KAAK,CAAC,CAAC,oBAAoB;QAC3E,MAAM,CAAC,GAAG,GAAG,WAAW,GAAG,UAAU,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QACxG,OAAO,CAAC,KAAK,UAAU,CAAC;IAC1B,CAAC;IACD,IAAI,UAAU,CAAC,UAAU,CAAC,WAAW,CAAC;QAAE,OAAO,KAAK,CAAC,CAAC,8BAA8B;IACpF,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,UAAU,CAAC;AACrF,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,IAAuB,EAAE,KAAiB,EAAE,EAAU;IAChF,MAAM,QAAQ,GAAG,IAAI,EAAE,IAAI,IAAI,YAAY,CAAC;IAC5C,MAAM,IAAI,GAAG,WAAW,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAC1C,OAAO;QACL,EAAE;QACF,SAAS,EAAE,QAAQ;QACnB,IAAI;QACJ,EAAE,EAAE,KAAK,CAAC,EAAE;QACZ,aAAa,EAAE,KAAK,CAAC,aAAa;QAClC,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,OAAO,EAAE,KAAK,CAAC,OAAO;KACvB,CAAC;AACJ,CAAC;AAoBD;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CACzB,OAA8B,EAC9B,OAAsB,EAAE;IAExB,MAAM,qBAAqB,GAAG,IAAI,CAAC,gBAAgB,IAAI,YAAY,CAAC;IACpE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACxC,MAAM,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QACvB,IAAI,CAAC,GAAG;YAAE,SAAS;QACnB,MAAM,gBAAgB,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC;QAChF,IAAI,GAAG,CAAC,SAAS,KAAK,gBAAgB,EAAE,CAAC;YACvC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,oBAAoB,EAAE,CAAC;QAClE,CAAC;QACD,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAC/C,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC;QAC7D,CAAC;IACH,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;AACtB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=chain.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chain.test.d.ts","sourceRoot":"","sources":["../../src/audit/chain.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,192 @@
1
+ import { afterEach, describe, expect, it } from 'vitest';
2
+ import { GENESIS_HASH, appendEntry, computeHash, configureChainKey, isChainKeyConfigured, verifyChain, } from './index.js';
3
+ function input(seed) {
4
+ return {
5
+ ts: `2026-05-09T12:00:${String(seed).padStart(2, '0')}.000Z`,
6
+ actor_user_id: 'u_alice',
7
+ actor_agent: 'cli-0.0.0',
8
+ event_type: 'secret.read.allowed',
9
+ payload: { alias: `@p.dev.k${seed}`, version: 1 },
10
+ };
11
+ }
12
+ function buildChain(n) {
13
+ const entries = [];
14
+ let prev = null;
15
+ for (let i = 0; i < n; i++) {
16
+ const e = appendEntry(prev, input(i), i + 1);
17
+ entries.push(e);
18
+ prev = e;
19
+ }
20
+ return entries;
21
+ }
22
+ describe('computeHash', () => {
23
+ it('is deterministic for equal inputs', () => {
24
+ const a = computeHash(GENESIS_HASH, input(1));
25
+ const b = computeHash(GENESIS_HASH, input(1));
26
+ expect(a).toBe(b);
27
+ });
28
+ it('changes when prev_hash changes', () => {
29
+ const a = computeHash(GENESIS_HASH, input(1));
30
+ const b = computeHash(`${'1'.repeat(64)}`, input(1));
31
+ expect(a).not.toBe(b);
32
+ });
33
+ it('is independent of payload key insertion order', () => {
34
+ const i = {
35
+ ts: '2026-05-09T12:00:00.000Z',
36
+ actor_user_id: 'u',
37
+ actor_agent: 'cli',
38
+ event_type: 'secret.read.allowed',
39
+ payload: { alias: '@p.d.k', version: 1, extra: { a: 1, b: 2 } },
40
+ };
41
+ const j = {
42
+ ...i,
43
+ payload: { extra: { b: 2, a: 1 }, version: 1, alias: '@p.d.k' },
44
+ };
45
+ expect(computeHash(GENESIS_HASH, i)).toBe(computeHash(GENESIS_HASH, j));
46
+ });
47
+ it('is 64 hex chars (SHA-256)', () => {
48
+ expect(computeHash(GENESIS_HASH, input(1))).toMatch(/^[0-9a-f]{64}$/);
49
+ });
50
+ });
51
+ describe('appendEntry', () => {
52
+ it('uses GENESIS_HASH for the first entry', () => {
53
+ const e = appendEntry(null, input(1), 1);
54
+ expect(e.prev_hash).toBe(GENESIS_HASH);
55
+ expect(e.hash).toMatch(/^[0-9a-f]{64}$/);
56
+ });
57
+ it('chains subsequent entries to the previous hash', () => {
58
+ const a = appendEntry(null, input(1), 1);
59
+ const b = appendEntry(a, input(2), 2);
60
+ expect(b.prev_hash).toBe(a.hash);
61
+ });
62
+ it('returns identical entries for the same input + prev', () => {
63
+ const a1 = appendEntry(null, input(1), 1);
64
+ const a2 = appendEntry(null, input(1), 1);
65
+ expect(a1.hash).toBe(a2.hash);
66
+ });
67
+ });
68
+ describe('verifyChain', () => {
69
+ it('returns ok for a valid chain', () => {
70
+ const chain = buildChain(50);
71
+ expect(verifyChain(chain)).toEqual({ ok: true });
72
+ });
73
+ it('returns ok for an empty chain', () => {
74
+ expect(verifyChain([])).toEqual({ ok: true });
75
+ });
76
+ it('detects a flipped payload byte (hash mismatch)', () => {
77
+ const chain = buildChain(10);
78
+ const tampered = chain.map((e, i) => i === 5 ? { ...e, payload: { ...e.payload, version: 999 } } : e);
79
+ const result = verifyChain(tampered);
80
+ expect(result.ok).toBe(false);
81
+ expect(result.brokenAt).toBe(5);
82
+ expect(result.reason).toBe('hash_mismatch');
83
+ });
84
+ it('detects a removed entry (prev_hash mismatch on the row that follows)', () => {
85
+ const chain = buildChain(10);
86
+ const truncated = [...chain.slice(0, 5), ...chain.slice(6)];
87
+ const result = verifyChain(truncated);
88
+ expect(result.ok).toBe(false);
89
+ expect(result.brokenAt).toBe(5);
90
+ expect(result.reason).toBe('prev_hash_mismatch');
91
+ });
92
+ it('detects a re-ordered entry', () => {
93
+ const chain = buildChain(10);
94
+ const swapped = [...chain.slice(0, 3), chain[4], chain[3], ...chain.slice(5)];
95
+ const result = verifyChain(swapped);
96
+ expect(result.ok).toBe(false);
97
+ expect(result.brokenAt).toBeGreaterThanOrEqual(3);
98
+ });
99
+ it('detects a forged entry inserted in the middle', () => {
100
+ const chain = buildChain(10);
101
+ const forged = {
102
+ id: 999,
103
+ prev_hash: chain[4].hash,
104
+ hash: '0'.repeat(64),
105
+ ...input(99),
106
+ };
107
+ const tampered = [...chain.slice(0, 5), forged, ...chain.slice(5)];
108
+ const result = verifyChain(tampered);
109
+ expect(result.ok).toBe(false);
110
+ expect(result.brokenAt).toBe(5);
111
+ });
112
+ it('handles a 1000-entry chain without false positives', () => {
113
+ const chain = buildChain(1000);
114
+ expect(verifyChain(chain)).toEqual({ ok: true });
115
+ });
116
+ it('verifies across page boundaries when startingPrevHash is threaded (regression for audit B1)', () => {
117
+ const chain = buildChain(2500);
118
+ const page1 = chain.slice(0, 1000);
119
+ const page2 = chain.slice(1000, 2000);
120
+ const page3 = chain.slice(2000);
121
+ expect(verifyChain(page1)).toEqual({ ok: true });
122
+ // Without startingPrevHash the second page falsely reports a
123
+ // mismatch — exactly the bug audit B1 caught.
124
+ expect(verifyChain(page2)).toMatchObject({ ok: false, reason: 'prev_hash_mismatch' });
125
+ // With startingPrevHash threaded, every page boundary checks out.
126
+ const tail1 = page1.at(-1);
127
+ const tail2 = page2.at(-1);
128
+ if (!tail1 || !tail2)
129
+ throw new Error('expected non-empty pages');
130
+ expect(verifyChain(page2, { startingPrevHash: tail1.hash })).toEqual({ ok: true });
131
+ expect(verifyChain(page3, { startingPrevHash: tail2.hash })).toEqual({ ok: true });
132
+ });
133
+ it('flags a tampered cross-page boundary', () => {
134
+ const chain = buildChain(2000);
135
+ const page1 = chain.slice(0, 1000);
136
+ const tail1 = page1.at(-1);
137
+ if (!tail1)
138
+ throw new Error('expected page1 non-empty');
139
+ const tamperedPage2 = chain
140
+ .slice(1000)
141
+ .map((e, i) => (i === 0 ? { ...e, prev_hash: 'a'.repeat(64) } : e));
142
+ const result = verifyChain(tamperedPage2, { startingPrevHash: tail1.hash });
143
+ expect(result.ok).toBe(false);
144
+ expect(result.brokenAt).toBe(0);
145
+ expect(result.reason).toBe('prev_hash_mismatch');
146
+ });
147
+ });
148
+ describe('tamper-evident (HMAC) chain key', () => {
149
+ const KEY = new Uint8Array(32).fill(7);
150
+ afterEach(() => configureChainKey(null)); // reset module-global between tests
151
+ it('tags keyed hashes with the v1: prefix and verifies them', () => {
152
+ configureChainKey(KEY);
153
+ expect(isChainKeyConfigured()).toBe(true);
154
+ const chain = buildChain(20);
155
+ expect(chain[0]?.hash.startsWith('v1:')).toBe(true);
156
+ expect(verifyChain(chain)).toEqual({ ok: true });
157
+ });
158
+ it('cannot be re-forged by recomputing keyless after a payload edit', () => {
159
+ configureChainKey(KEY);
160
+ const chain = buildChain(10);
161
+ // Attacker (no key) edits a payload and recomputes the hash keyless.
162
+ configureChainKey(null);
163
+ const forgedHash = computeHash(chain[5].prev_hash, {
164
+ ...input(5),
165
+ payload: { alias: '@p.dev.k5', version: 999 },
166
+ });
167
+ const tampered = chain.map((e, i) => i === 5 ? { ...e, payload: { alias: '@p.dev.k5', version: 999 }, hash: forgedHash } : e);
168
+ // Verifier (with the key) rejects it: the row is a v1: row, so a keyless
169
+ // recompute can never match.
170
+ configureChainKey(KEY);
171
+ const result = verifyChain(tampered);
172
+ expect(result.ok).toBe(false);
173
+ expect(result.reason).toBe('hash_mismatch');
174
+ expect(result.brokenAt).toBe(5);
175
+ });
176
+ it('reports a keyed chain as broken when the key is absent at verify time', () => {
177
+ configureChainKey(KEY);
178
+ const chain = buildChain(5);
179
+ configureChainKey(null);
180
+ expect(verifyChain(chain).ok).toBe(false);
181
+ });
182
+ it('rejects an entirely keyless chain when a key is configured (full-downgrade protection)', () => {
183
+ // An attacker who rewrites every row as keyless must NOT pass verification
184
+ // once the verifier holds the key.
185
+ configureChainKey(null);
186
+ const keyless = buildChain(5); // all bare SHA-256
187
+ expect(keyless[0]?.hash.startsWith('v1:')).toBe(false);
188
+ configureChainKey(KEY);
189
+ expect(verifyChain(keyless).ok).toBe(false);
190
+ });
191
+ });
192
+ //# sourceMappingURL=chain.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chain.test.js","sourceRoot":"","sources":["../../src/audit/chain.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export type { AuditEntry, AuditEventType, AuditInput } from './types.js';
2
+ export { GENESIS_HASH } from './types.js';
3
+ export { appendEntry, computeHash, configureChainKey, isChainKeyConfigured, verifyChain, type VerifyOptions, type VerifyResult, } from './chain.js';
4
+ export { PAYLOAD_SCHEMAS, validateAuditPayload } from './payload-schemas.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/audit/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACzE,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EACL,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,oBAAoB,EACpB,WAAW,EACX,KAAK,aAAa,EAClB,KAAK,YAAY,GAClB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { GENESIS_HASH } from './types.js';
2
+ export { appendEntry, computeHash, configureChainKey, isChainKeyConfigured, verifyChain, } from './chain.js';
3
+ export { PAYLOAD_SCHEMAS, validateAuditPayload } from './payload-schemas.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/audit/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EACL,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,oBAAoB,EACpB,WAAW,GAGZ,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC"}