atabey 0.1.1-beta → 0.1.3
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/README.md +145 -79
- package/dist/atabey/src/cli/commands/coverage.js +17 -12
- package/dist/atabey/src/cli/commands/coverage.js.map +1 -1
- package/dist/atabey/src/cli/commands/lint.d.ts +2 -1
- package/dist/atabey/src/cli/commands/lint.js +20 -1
- package/dist/atabey/src/cli/commands/lint.js.map +1 -1
- package/dist/atabey/src/cli/commands/mcp.js +56 -23
- package/dist/atabey/src/cli/commands/mcp.js.map +1 -1
- package/dist/atabey/src/cli/commands/orchestrate.d.ts +6 -6
- package/dist/atabey/src/cli/index.js +1 -1
- package/dist/shared/src/agent-identity.d.ts +1 -34
- package/dist/shared/src/agent-identity.js +1 -76
- package/dist/shared/src/agent-identity.js.map +1 -1
- package/dist/shared/src/api-catalog.d.ts +1 -57
- package/dist/shared/src/api-catalog.js +1 -253
- package/dist/shared/src/api-catalog.js.map +1 -1
- package/dist/shared/src/audit-chain.d.ts +1 -80
- package/dist/shared/src/audit-chain.js +1 -261
- package/dist/shared/src/audit-chain.js.map +1 -1
- package/dist/shared/src/audit.d.ts +1 -121
- package/dist/shared/src/audit.js +1 -321
- package/dist/shared/src/audit.js.map +1 -1
- package/dist/shared/src/constants.d.ts +1 -150
- package/dist/shared/src/constants.js +1 -211
- package/dist/shared/src/constants.js.map +1 -1
- package/dist/shared/src/database.d.ts +1 -6
- package/dist/shared/src/database.js +1 -15
- package/dist/shared/src/database.js.map +1 -1
- package/dist/shared/src/errors.d.ts +1 -46
- package/dist/shared/src/errors.js +1 -68
- package/dist/shared/src/errors.js.map +1 -1
- package/dist/shared/src/file-lock.d.ts +1 -93
- package/dist/shared/src/file-lock.js +1 -239
- package/dist/shared/src/file-lock.js.map +1 -1
- package/dist/shared/src/fs.d.ts +1 -9
- package/dist/shared/src/fs.js +1 -53
- package/dist/shared/src/fs.js.map +1 -1
- package/dist/shared/src/index.d.ts +2 -31
- package/dist/shared/src/index.js +2 -31
- package/dist/shared/src/index.js.map +1 -1
- package/dist/shared/src/job-queue.d.ts +1 -76
- package/dist/shared/src/job-queue.js +1 -199
- package/dist/shared/src/job-queue.js.map +1 -1
- package/dist/shared/src/lock.d.ts +1 -82
- package/dist/shared/src/lock.js +1 -158
- package/dist/shared/src/lock.js.map +1 -1
- package/dist/shared/src/logger.d.ts +1 -31
- package/dist/shared/src/logger.js +1 -152
- package/dist/shared/src/logger.js.map +1 -1
- package/dist/shared/src/memory-prune.d.ts +1 -18
- package/dist/shared/src/memory-prune.js +1 -47
- package/dist/shared/src/memory-prune.js.map +1 -1
- package/dist/shared/src/migrations.d.ts +1 -69
- package/dist/shared/src/migrations.js +1 -393
- package/dist/shared/src/migrations.js.map +1 -1
- package/dist/shared/src/modules/agent/agent-identity.d.ts +34 -0
- package/dist/shared/src/modules/agent/agent-identity.js +77 -0
- package/dist/shared/src/modules/agent/agent-identity.js.map +1 -0
- package/dist/shared/src/modules/agent/api-catalog.d.ts +57 -0
- package/dist/shared/src/modules/agent/api-catalog.js +254 -0
- package/dist/shared/src/modules/agent/api-catalog.js.map +1 -0
- package/dist/shared/src/modules/agent/index.d.ts +3 -0
- package/dist/shared/src/modules/agent/index.js +4 -0
- package/dist/shared/src/modules/agent/index.js.map +1 -0
- package/dist/shared/src/modules/agent/tokenizer.d.ts +54 -0
- package/dist/shared/src/modules/agent/tokenizer.js +272 -0
- package/dist/shared/src/modules/agent/tokenizer.js.map +1 -0
- package/dist/shared/src/modules/concurrency/file-lock.d.ts +93 -0
- package/dist/shared/src/modules/concurrency/file-lock.js +240 -0
- package/dist/shared/src/modules/concurrency/file-lock.js.map +1 -0
- package/dist/shared/src/modules/concurrency/index.d.ts +6 -0
- package/dist/shared/src/modules/concurrency/index.js +7 -0
- package/dist/shared/src/modules/concurrency/index.js.map +1 -0
- package/dist/shared/src/modules/concurrency/job-queue.d.ts +76 -0
- package/dist/shared/src/modules/concurrency/job-queue.js +200 -0
- package/dist/shared/src/modules/concurrency/job-queue.js.map +1 -0
- package/dist/shared/src/modules/concurrency/lock.d.ts +82 -0
- package/dist/shared/src/modules/concurrency/lock.js +159 -0
- package/dist/shared/src/modules/concurrency/lock.js.map +1 -0
- package/dist/shared/src/modules/concurrency/resilience.d.ts +84 -0
- package/dist/shared/src/modules/concurrency/resilience.js +217 -0
- package/dist/shared/src/modules/concurrency/resilience.js.map +1 -0
- package/dist/shared/src/modules/concurrency/worker-pool.d.ts +52 -0
- package/dist/shared/src/modules/concurrency/worker-pool.js +229 -0
- package/dist/shared/src/modules/concurrency/worker-pool.js.map +1 -0
- package/dist/shared/src/modules/concurrency/worker-thread.d.ts +21 -0
- package/dist/shared/src/modules/concurrency/worker-thread.js +67 -0
- package/dist/shared/src/modules/concurrency/worker-thread.js.map +1 -0
- package/dist/shared/src/modules/index.d.ts +14 -0
- package/dist/shared/src/modules/index.js +15 -0
- package/dist/shared/src/modules/index.js.map +1 -0
- package/dist/shared/src/modules/observability/audit-chain.d.ts +80 -0
- package/dist/shared/src/modules/observability/audit-chain.js +262 -0
- package/dist/shared/src/modules/observability/audit-chain.js.map +1 -0
- package/dist/shared/src/modules/observability/audit.d.ts +121 -0
- package/dist/shared/src/modules/observability/audit.js +322 -0
- package/dist/shared/src/modules/observability/audit.js.map +1 -0
- package/dist/shared/src/modules/observability/index.d.ts +4 -0
- package/dist/shared/src/modules/observability/index.js +5 -0
- package/dist/shared/src/modules/observability/index.js.map +1 -0
- package/dist/shared/src/modules/observability/logger.d.ts +31 -0
- package/dist/shared/src/modules/observability/logger.js +153 -0
- package/dist/shared/src/modules/observability/logger.js.map +1 -0
- package/dist/shared/src/modules/observability/otel.d.ts +39 -0
- package/dist/shared/src/modules/observability/otel.js +93 -0
- package/dist/shared/src/modules/observability/otel.js.map +1 -0
- package/dist/shared/src/modules/primitives/constants.d.ts +150 -0
- package/dist/shared/src/modules/primitives/constants.js +212 -0
- package/dist/shared/src/modules/primitives/constants.js.map +1 -0
- package/dist/shared/src/modules/primitives/errors.d.ts +46 -0
- package/dist/shared/src/modules/primitives/errors.js +69 -0
- package/dist/shared/src/modules/primitives/errors.js.map +1 -0
- package/dist/shared/src/modules/primitives/fs.d.ts +9 -0
- package/dist/shared/src/modules/primitives/fs.js +54 -0
- package/dist/shared/src/modules/primitives/fs.js.map +1 -0
- package/dist/shared/src/modules/primitives/index.d.ts +7 -0
- package/dist/shared/src/modules/primitives/index.js +8 -0
- package/dist/shared/src/modules/primitives/index.js.map +1 -0
- package/dist/shared/src/modules/primitives/outbound-http.d.ts +32 -0
- package/dist/shared/src/modules/primitives/outbound-http.js +88 -0
- package/dist/shared/src/modules/primitives/outbound-http.js.map +1 -0
- package/dist/shared/src/modules/primitives/string.d.ts +1 -0
- package/dist/shared/src/modules/primitives/string.js +30 -0
- package/dist/shared/src/modules/primitives/string.js.map +1 -0
- package/dist/shared/src/modules/primitives/time.d.ts +5 -0
- package/dist/shared/src/modules/primitives/time.js +35 -0
- package/dist/shared/src/modules/primitives/time.js.map +1 -0
- package/dist/shared/src/modules/primitives/types.d.ts +27 -0
- package/dist/shared/src/modules/primitives/types.js +17 -0
- package/dist/shared/src/modules/primitives/types.js.map +1 -0
- package/dist/shared/src/modules/sandbox/index.d.ts +3 -0
- package/dist/shared/src/modules/sandbox/index.js +4 -0
- package/dist/shared/src/modules/sandbox/index.js.map +1 -0
- package/dist/shared/src/modules/sandbox/sandbox-fs.d.ts +28 -0
- package/dist/shared/src/modules/sandbox/sandbox-fs.js +143 -0
- package/dist/shared/src/modules/sandbox/sandbox-fs.js.map +1 -0
- package/dist/shared/src/modules/sandbox/sandbox-runtime.d.ts +78 -0
- package/dist/shared/src/modules/sandbox/sandbox-runtime.js +282 -0
- package/dist/shared/src/modules/sandbox/sandbox-runtime.js.map +1 -0
- package/dist/shared/src/modules/sandbox/sandbox.d.ts +54 -0
- package/dist/shared/src/modules/sandbox/sandbox.js +179 -0
- package/dist/shared/src/modules/sandbox/sandbox.js.map +1 -0
- package/dist/shared/src/modules/security/index.d.ts +5 -0
- package/dist/shared/src/modules/security/index.js +6 -0
- package/dist/shared/src/modules/security/index.js.map +1 -0
- package/dist/shared/src/modules/security/pii.d.ts +70 -0
- package/dist/shared/src/modules/security/pii.js +276 -0
- package/dist/shared/src/modules/security/pii.js.map +1 -0
- package/dist/shared/src/modules/security/policy-gate.d.ts +42 -0
- package/dist/shared/src/modules/security/policy-gate.js +172 -0
- package/dist/shared/src/modules/security/policy-gate.js.map +1 -0
- package/dist/shared/src/modules/security/retention.d.ts +68 -0
- package/dist/shared/src/modules/security/retention.js +218 -0
- package/dist/shared/src/modules/security/retention.js.map +1 -0
- package/dist/shared/src/modules/security/secrets.d.ts +99 -0
- package/dist/shared/src/modules/security/secrets.js +371 -0
- package/dist/shared/src/modules/security/secrets.js.map +1 -0
- package/dist/shared/src/modules/security/tls.d.ts +87 -0
- package/dist/shared/src/modules/security/tls.js +154 -0
- package/dist/shared/src/modules/security/tls.js.map +1 -0
- package/dist/shared/src/modules/storage/database.d.ts +6 -0
- package/dist/shared/src/modules/storage/database.js +16 -0
- package/dist/shared/src/modules/storage/database.js.map +1 -0
- package/dist/shared/src/modules/storage/index.d.ts +4 -0
- package/dist/shared/src/modules/storage/index.js +5 -0
- package/dist/shared/src/modules/storage/index.js.map +1 -0
- package/dist/shared/src/modules/storage/memory-prune.d.ts +18 -0
- package/dist/shared/src/modules/storage/memory-prune.js +48 -0
- package/dist/shared/src/modules/storage/memory-prune.js.map +1 -0
- package/dist/shared/src/modules/storage/migrations.d.ts +69 -0
- package/dist/shared/src/modules/storage/migrations.js +394 -0
- package/dist/shared/src/modules/storage/migrations.js.map +1 -0
- package/dist/shared/src/modules/storage/storage.d.ts +341 -0
- package/dist/shared/src/modules/storage/storage.js +1004 -0
- package/dist/shared/src/modules/storage/storage.js.map +1 -0
- package/dist/shared/src/otel.d.ts +1 -39
- package/dist/shared/src/otel.js +1 -92
- package/dist/shared/src/otel.js.map +1 -1
- package/dist/shared/src/outbound-http.d.ts +1 -32
- package/dist/shared/src/outbound-http.js +1 -87
- package/dist/shared/src/outbound-http.js.map +1 -1
- package/dist/shared/src/pii.d.ts +1 -70
- package/dist/shared/src/pii.js +1 -275
- package/dist/shared/src/pii.js.map +1 -1
- package/dist/shared/src/policy-gate.d.ts +1 -42
- package/dist/shared/src/policy-gate.js +1 -171
- package/dist/shared/src/policy-gate.js.map +1 -1
- package/dist/shared/src/resilience.d.ts +1 -84
- package/dist/shared/src/resilience.js +1 -216
- package/dist/shared/src/resilience.js.map +1 -1
- package/dist/shared/src/retention.d.ts +1 -68
- package/dist/shared/src/retention.js +1 -217
- package/dist/shared/src/retention.js.map +1 -1
- package/dist/shared/src/sandbox-fs.d.ts +1 -28
- package/dist/shared/src/sandbox-fs.js +1 -142
- package/dist/shared/src/sandbox-fs.js.map +1 -1
- package/dist/shared/src/sandbox-runtime.d.ts +1 -78
- package/dist/shared/src/sandbox-runtime.js +1 -281
- package/dist/shared/src/sandbox-runtime.js.map +1 -1
- package/dist/shared/src/sandbox.d.ts +1 -54
- package/dist/shared/src/sandbox.js +1 -178
- package/dist/shared/src/sandbox.js.map +1 -1
- package/dist/shared/src/secrets.d.ts +1 -99
- package/dist/shared/src/secrets.js +1 -370
- package/dist/shared/src/secrets.js.map +1 -1
- package/dist/shared/src/storage.d.ts +1 -341
- package/dist/shared/src/storage.js +1 -1003
- package/dist/shared/src/storage.js.map +1 -1
- package/dist/shared/src/string.d.ts +1 -1
- package/dist/shared/src/string.js +1 -29
- package/dist/shared/src/string.js.map +1 -1
- package/dist/shared/src/time.d.ts +1 -5
- package/dist/shared/src/time.js +1 -34
- package/dist/shared/src/time.js.map +1 -1
- package/dist/shared/src/tls.d.ts +1 -87
- package/dist/shared/src/tls.js +1 -153
- package/dist/shared/src/tls.js.map +1 -1
- package/dist/shared/src/tokenizer.d.ts +1 -54
- package/dist/shared/src/tokenizer.js +1 -271
- package/dist/shared/src/tokenizer.js.map +1 -1
- package/dist/shared/src/types.d.ts +1 -27
- package/dist/shared/src/types.js +1 -16
- package/dist/shared/src/types.js.map +1 -1
- package/dist/shared/src/worker-pool.d.ts +1 -52
- package/dist/shared/src/worker-pool.js +1 -228
- package/dist/shared/src/worker-pool.js.map +1 -1
- package/dist/shared/src/worker-thread.d.ts +1 -21
- package/dist/shared/src/worker-thread.js +1 -66
- package/dist/shared/src/worker-thread.js.map +1 -1
- package/package.json +4 -4
|
@@ -1,262 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
* Tamper-evident audit hash chain helpers (Phase 1.4).
|
|
3
|
-
*
|
|
4
|
-
* Chain: each entry stores prev_hash (previous entry hash or GENESIS) and hash = SHA-256(payload).
|
|
5
|
-
* Any mutation of historical rows fails verification.
|
|
6
|
-
*/
|
|
7
|
-
import crypto from "crypto";
|
|
8
|
-
import fs from "fs";
|
|
9
|
-
import os from "os";
|
|
10
|
-
import path from "path";
|
|
11
|
-
import { databaseHolder } from "./database.js";
|
|
12
|
-
export const AUDIT_CHAIN_GENESIS = "GENESIS";
|
|
13
|
-
/**
|
|
14
|
-
* Resolve the HMAC key for the audit chain (memoized).
|
|
15
|
-
*
|
|
16
|
-
* Priority:
|
|
17
|
-
* 1. ATABEY_AUDIT_HMAC_KEY env var (recommended for production / secret managers)
|
|
18
|
-
* 2. `.atabey/audit-hmac.key` next to the SQLite DB (created 0600 on first use)
|
|
19
|
-
* 3. null → falls back to unkeyed SHA-256 (insecure; warned once)
|
|
20
|
-
*
|
|
21
|
-
* A key is required for the chain to be genuinely tamper-evident. Without it,
|
|
22
|
-
* anyone who can write the DB can also recompute the hashes.
|
|
23
|
-
*/
|
|
24
|
-
let cachedKey;
|
|
25
|
-
let warnedUnkeyed = false;
|
|
26
|
-
const inMemoryAnchors = new Map();
|
|
27
|
-
/** Directory holding the HMAC key and chain anchor (next to the SQLite DB), or null for :memory: DBs. */
|
|
28
|
-
function resolveChainDir() {
|
|
29
|
-
const envDir = process.env.ATABEY_TEST_DIR || process.env.ATABEY_FRAMEWORK_DIR;
|
|
30
|
-
if (envDir && envDir.trim()) {
|
|
31
|
-
return envDir.trim();
|
|
32
|
-
}
|
|
33
|
-
try {
|
|
34
|
-
const db = databaseHolder.getDB();
|
|
35
|
-
if (db) {
|
|
36
|
-
if (db.memory === true || db.name === ":memory:" || db.name === "") {
|
|
37
|
-
return null;
|
|
38
|
-
}
|
|
39
|
-
if (typeof db.name === "string" && db.name) {
|
|
40
|
-
return path.dirname(db.name);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
catch {
|
|
45
|
-
/* DB not initialized yet */
|
|
46
|
-
}
|
|
47
|
-
return process.env.VITEST
|
|
48
|
-
? path.join(os.tmpdir(), `atabey-vitest-worker-${process.pid}`, ".atabey")
|
|
49
|
-
: path.join(process.cwd(), ".atabey");
|
|
50
|
-
}
|
|
51
|
-
export function resolveAuditChainKey() {
|
|
52
|
-
if (cachedKey !== undefined)
|
|
53
|
-
return cachedKey;
|
|
54
|
-
const envKey = process.env.ATABEY_AUDIT_HMAC_KEY;
|
|
55
|
-
if (envKey && envKey.trim()) {
|
|
56
|
-
cachedKey = Buffer.from(envKey.trim(), "utf8");
|
|
57
|
-
return cachedKey;
|
|
58
|
-
}
|
|
59
|
-
const dir = resolveChainDir();
|
|
60
|
-
if (!dir) {
|
|
61
|
-
cachedKey = null;
|
|
62
|
-
return cachedKey;
|
|
63
|
-
}
|
|
64
|
-
const keyFile = path.join(dir, "audit-hmac.key");
|
|
65
|
-
try {
|
|
66
|
-
if (fs.existsSync(keyFile)) {
|
|
67
|
-
cachedKey = fs.readFileSync(keyFile);
|
|
68
|
-
return cachedKey;
|
|
69
|
-
}
|
|
70
|
-
if (process.env.ATABEY_AUDIT_HMAC_AUTOCREATE !== "false" && !process.env.VITEST) {
|
|
71
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
72
|
-
const generated = crypto.randomBytes(32);
|
|
73
|
-
fs.writeFileSync(keyFile, generated, { mode: 0o600 });
|
|
74
|
-
cachedKey = generated;
|
|
75
|
-
return cachedKey;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
catch {
|
|
79
|
-
/* fall through to unkeyed */
|
|
80
|
-
}
|
|
81
|
-
cachedKey = null;
|
|
82
|
-
return cachedKey;
|
|
83
|
-
}
|
|
84
|
-
/** Test helper — clears the memoized key. */
|
|
85
|
-
export function clearAuditChainKeyCache() {
|
|
86
|
-
cachedKey = undefined;
|
|
87
|
-
warnedUnkeyed = false;
|
|
88
|
-
inMemoryAnchors.clear();
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* Keyed digest for audit chain entries.
|
|
92
|
-
* Uses HMAC-SHA256 when a key is available; otherwise falls back to plain
|
|
93
|
-
* SHA-256 with a one-time warning (degraded, not recommended).
|
|
94
|
-
*/
|
|
95
|
-
export function chainDigest(payload) {
|
|
96
|
-
const key = resolveAuditChainKey();
|
|
97
|
-
if (key) {
|
|
98
|
-
return crypto.createHmac("sha256", key).update(payload, "utf8").digest("hex");
|
|
99
|
-
}
|
|
100
|
-
if (!warnedUnkeyed) {
|
|
101
|
-
warnedUnkeyed = true;
|
|
102
|
-
process.stderr.write("[AUDIT] WARNING: no audit HMAC key configured — chain is unkeyed (SHA-256 only). " +
|
|
103
|
-
"Set ATABEY_AUDIT_HMAC_KEY or allow key-file creation for tamper-evidence.\n");
|
|
104
|
-
}
|
|
105
|
-
return crypto.createHash("sha256").update(payload, "utf8").digest("hex");
|
|
106
|
-
}
|
|
107
|
-
/** @deprecated Use chainDigest() — unkeyed SHA-256 is not tamper-evident. */
|
|
108
|
-
export function sha256Hex(payload) {
|
|
109
|
-
return crypto.createHash("sha256").update(payload, "utf8").digest("hex");
|
|
110
|
-
}
|
|
111
|
-
function anchorFile(dir, name) {
|
|
112
|
-
return path.join(dir, `audit-chain-${name}.anchor.json`);
|
|
113
|
-
}
|
|
114
|
-
export function writeChainAnchor(name, tip, count) {
|
|
115
|
-
const data = { tip, count, updatedAt: new Date().toISOString() };
|
|
116
|
-
const dir = resolveChainDir();
|
|
117
|
-
if (!dir) {
|
|
118
|
-
inMemoryAnchors.set(name, data);
|
|
119
|
-
return;
|
|
120
|
-
}
|
|
121
|
-
try {
|
|
122
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
123
|
-
fs.writeFileSync(anchorFile(dir, name), JSON.stringify(data), { mode: 0o600 });
|
|
124
|
-
}
|
|
125
|
-
catch {
|
|
126
|
-
/* non-fatal: verification will report "no anchor" */
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
export function readChainAnchor(name) {
|
|
130
|
-
const dir = resolveChainDir();
|
|
131
|
-
if (!dir) {
|
|
132
|
-
return inMemoryAnchors.get(name) ?? null;
|
|
133
|
-
}
|
|
134
|
-
try {
|
|
135
|
-
const f = anchorFile(dir, name);
|
|
136
|
-
if (!fs.existsSync(f))
|
|
137
|
-
return null;
|
|
138
|
-
return JSON.parse(fs.readFileSync(f, "utf8"));
|
|
139
|
-
}
|
|
140
|
-
catch {
|
|
141
|
-
return null;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
export function clearChainAnchor(name) {
|
|
145
|
-
inMemoryAnchors.delete(name);
|
|
146
|
-
const dir = resolveChainDir();
|
|
147
|
-
if (!dir)
|
|
148
|
-
return;
|
|
149
|
-
try {
|
|
150
|
-
const f = anchorFile(dir, name);
|
|
151
|
-
if (fs.existsSync(f))
|
|
152
|
-
fs.unlinkSync(f);
|
|
153
|
-
}
|
|
154
|
-
catch {
|
|
155
|
-
/* ignore */
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
/**
|
|
159
|
-
* Canonical payload for agent execution logs (Storage.saveLog).
|
|
160
|
-
*
|
|
161
|
-
* v2: fields are length-delimited via JSON to remove `|`-join boundary
|
|
162
|
-
* ambiguity (previously agent="a|b" collided with action="b|c"). Changing this
|
|
163
|
-
* invalidates verification of rows written by older (v1) builds.
|
|
164
|
-
*/
|
|
165
|
-
export function buildAgentLogChainPayload(fields) {
|
|
166
|
-
return JSON.stringify([
|
|
167
|
-
"v2",
|
|
168
|
-
fields.prevHash,
|
|
169
|
-
fields.agent,
|
|
170
|
-
fields.action,
|
|
171
|
-
fields.traceId,
|
|
172
|
-
fields.status,
|
|
173
|
-
fields.summary,
|
|
174
|
-
fields.timestamp,
|
|
175
|
-
]);
|
|
176
|
-
}
|
|
177
|
-
/**
|
|
178
|
-
* Canonical payload for structured Audit.log entries (v2, length-delimited).
|
|
179
|
-
*/
|
|
180
|
-
export function buildStructuredAuditChainPayload(fields) {
|
|
181
|
-
return JSON.stringify([
|
|
182
|
-
"v2",
|
|
183
|
-
fields.prevHash,
|
|
184
|
-
fields.agent,
|
|
185
|
-
fields.action,
|
|
186
|
-
fields.status,
|
|
187
|
-
fields.traceId,
|
|
188
|
-
fields.timestamp,
|
|
189
|
-
fields.detailsJson,
|
|
190
|
-
fields.errorMessage,
|
|
191
|
-
]);
|
|
192
|
-
}
|
|
193
|
-
/**
|
|
194
|
-
* Verify a sequence of rows already ordered by id ASC.
|
|
195
|
-
* `computePayload(row, prevHash)` must rebuild the exact string used at insert time.
|
|
196
|
-
*
|
|
197
|
-
* @param options.digest keyed digest used at insert time (default: chainDigest)
|
|
198
|
-
* @param options.expectedTip last appended hash (from an external anchor) — detects truncation
|
|
199
|
-
* @param options.expectedCount number of chained rows expected — detects deletion at the tail
|
|
200
|
-
*/
|
|
201
|
-
export function verifyHashChain(rows, computePayload, options = {}) {
|
|
202
|
-
const digest = options.digest ?? chainDigest;
|
|
203
|
-
let expectedPrev = rows.length > 0 ? (rows[0].prev_hash || AUDIT_CHAIN_GENESIS) : AUDIT_CHAIN_GENESIS;
|
|
204
|
-
let checked = 0;
|
|
205
|
-
for (const row of rows) {
|
|
206
|
-
checked++;
|
|
207
|
-
const prev = row.prev_hash || "";
|
|
208
|
-
if (prev !== expectedPrev) {
|
|
209
|
-
return {
|
|
210
|
-
valid: false,
|
|
211
|
-
checked,
|
|
212
|
-
failedLogId: row.id,
|
|
213
|
-
reason: `prev_hash mismatch at row ${row.id}`,
|
|
214
|
-
tip: "A log was deleted, reordered, or inserted out of chain order.",
|
|
215
|
-
};
|
|
216
|
-
}
|
|
217
|
-
if (!row.hash) {
|
|
218
|
-
return {
|
|
219
|
-
valid: false,
|
|
220
|
-
checked,
|
|
221
|
-
failedLogId: row.id,
|
|
222
|
-
reason: `Missing hash at row ${row.id}`,
|
|
223
|
-
tip: "Legacy row without hash; re-seed or accept and re-hash from tip.",
|
|
224
|
-
};
|
|
225
|
-
}
|
|
226
|
-
const payload = computePayload(row, prev);
|
|
227
|
-
const calculated = digest(payload);
|
|
228
|
-
if (calculated !== row.hash) {
|
|
229
|
-
return {
|
|
230
|
-
valid: false,
|
|
231
|
-
checked,
|
|
232
|
-
failedLogId: row.id,
|
|
233
|
-
reason: `Hash corruption at row ${row.id}`,
|
|
234
|
-
tip: "Row content was modified after append (or the HMAC key changed).",
|
|
235
|
-
};
|
|
236
|
-
}
|
|
237
|
-
expectedPrev = row.hash;
|
|
238
|
-
}
|
|
239
|
-
// Truncation detection against an external anchor.
|
|
240
|
-
if (options.expectedCount !== undefined && rows.length < options.expectedCount) {
|
|
241
|
-
return {
|
|
242
|
-
valid: false,
|
|
243
|
-
checked,
|
|
244
|
-
reason: `Chain truncated: expected ${options.expectedCount} rows, found ${rows.length}.`,
|
|
245
|
-
tip: "Tail audit rows were deleted after append.",
|
|
246
|
-
};
|
|
247
|
-
}
|
|
248
|
-
if (options.expectedTip !== undefined && rows.length > 0) {
|
|
249
|
-
const actualTip = rows[rows.length - 1].hash;
|
|
250
|
-
if (actualTip !== options.expectedTip) {
|
|
251
|
-
return {
|
|
252
|
-
valid: false,
|
|
253
|
-
checked,
|
|
254
|
-
failedLogId: rows[rows.length - 1].id,
|
|
255
|
-
reason: "Chain tip does not match the anchored tip.",
|
|
256
|
-
tip: "Rows were appended/replaced outside the audited writer, or deleted.",
|
|
257
|
-
};
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
return { valid: true, checked, tip: rows.length > 0 ? rows[rows.length - 1].hash ?? undefined : undefined };
|
|
261
|
-
}
|
|
1
|
+
export * from "./modules/observability/audit-chain.js";
|
|
262
2
|
//# sourceMappingURL=audit-chain.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit-chain.js","sourceRoot":"","sources":["../../../../shared/src/audit-chain.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"audit-chain.js","sourceRoot":"","sources":["../../../../shared/src/audit-chain.ts"],"names":[],"mappings":"AAAA,cAAc,wCAAwC,CAAC"}
|
|
@@ -1,121 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* [AUDIT] Structured Audit Log Service
|
|
3
|
-
*
|
|
4
|
-
* Records all critical operations in structured JSON format to SQLite.
|
|
5
|
-
* Queryable, filterable, and traceable.
|
|
6
|
-
*
|
|
7
|
-
* [KVKK/GDPR] GDPR and KVKK Art. 4, 5, 11, 12 compliant:
|
|
8
|
-
* - Sensitive data automatically masked (PII masking)
|
|
9
|
-
* - Data retention limited (TTL)
|
|
10
|
-
* - Data subject rights supported (erasure, query)
|
|
11
|
-
*
|
|
12
|
-
* Usage:
|
|
13
|
-
* Audit.log("user.create", "SUCCESS", { userId: "usr_123" });
|
|
14
|
-
* Audit.query({ action: "user.create", status: "FAILED" });
|
|
15
|
-
*/
|
|
16
|
-
import { type ChainVerifyResult } from "./audit-chain.js";
|
|
17
|
-
export type AuditStatus = "SUCCESS" | "FAILED" | "BLOCKED" | "APPROVED" | "REJECTED";
|
|
18
|
-
export type DataCategory = "OPERATIONAL" | "USER_DATA" | "API_CALL" | "SECURITY" | "COMPLIANCE";
|
|
19
|
-
export interface AuditEntry {
|
|
20
|
-
id?: number;
|
|
21
|
-
timestamp: string;
|
|
22
|
-
action: string;
|
|
23
|
-
status: AuditStatus;
|
|
24
|
-
agent: string;
|
|
25
|
-
traceId?: string;
|
|
26
|
-
details?: Record<string, unknown>;
|
|
27
|
-
errorMessage?: string;
|
|
28
|
-
durationMs?: number;
|
|
29
|
-
dataCategory?: DataCategory;
|
|
30
|
-
/** [KVKK] Data retention period (days). null = unlimited (not recommended) */
|
|
31
|
-
retentionDays?: number;
|
|
32
|
-
/** Tamper-evident chain (Phase 1.4) */
|
|
33
|
-
prev_hash?: string;
|
|
34
|
-
hash?: string;
|
|
35
|
-
}
|
|
36
|
-
export declare class Audit {
|
|
37
|
-
private static TABLE;
|
|
38
|
-
/** Out-of-DB anchor file name for the structured audit chain. */
|
|
39
|
-
private static ANCHOR_NAME;
|
|
40
|
-
/** [KVKK] Default data retention period: 30 days */
|
|
41
|
-
private static DEFAULT_RETENTION_DAYS;
|
|
42
|
-
/** [KVKK] Maximum retention for sensitive categories: 90 days */
|
|
43
|
-
private static MAX_RETENTION_DAYS;
|
|
44
|
-
static initialize(): void;
|
|
45
|
-
/**
|
|
46
|
-
* Refresh the out-of-DB chain anchor after a legitimate deletion
|
|
47
|
-
* (retention / right-to-erasure). Without this, legitimate deletions would
|
|
48
|
-
* be indistinguishable from tampering.
|
|
49
|
-
*/
|
|
50
|
-
private static refreshAnchor;
|
|
51
|
-
/**
|
|
52
|
-
* Logs a structured audit entry.
|
|
53
|
-
* [KVKK] Sensitive data is automatically masked.
|
|
54
|
-
*/
|
|
55
|
-
static log(action: string, status: AuditStatus, options?: {
|
|
56
|
-
agent?: string;
|
|
57
|
-
traceId?: string;
|
|
58
|
-
details?: Record<string, unknown>;
|
|
59
|
-
errorMessage?: string;
|
|
60
|
-
durationMs?: number;
|
|
61
|
-
dataCategory?: DataCategory;
|
|
62
|
-
/** [KVKK] Custom retention period (days). Default: 30 */
|
|
63
|
-
retentionDays?: number;
|
|
64
|
-
}): void;
|
|
65
|
-
/**
|
|
66
|
-
* Verify tamper-evident chain for structured audit_log table.
|
|
67
|
-
*/
|
|
68
|
-
static verifyIntegrity(): ChainVerifyResult;
|
|
69
|
-
/**
|
|
70
|
-
* Queries audit logs with filters.
|
|
71
|
-
*/
|
|
72
|
-
static query(options?: {
|
|
73
|
-
action?: string;
|
|
74
|
-
status?: AuditStatus;
|
|
75
|
-
agent?: string;
|
|
76
|
-
traceId?: string;
|
|
77
|
-
dataCategory?: DataCategory;
|
|
78
|
-
limit?: number;
|
|
79
|
-
offset?: number;
|
|
80
|
-
since?: string;
|
|
81
|
-
until?: string;
|
|
82
|
-
}): AuditEntry[];
|
|
83
|
-
/**
|
|
84
|
-
* [KVKK Art. 11] Deletes records upon data subject request.
|
|
85
|
-
* Clears all records matching a given traceId or agent.
|
|
86
|
-
*
|
|
87
|
-
* @param filter Which records to delete
|
|
88
|
-
* @returns Number of deleted records
|
|
89
|
-
*/
|
|
90
|
-
static deleteByFilter(filter: {
|
|
91
|
-
traceId?: string;
|
|
92
|
-
agent?: string;
|
|
93
|
-
action?: string;
|
|
94
|
-
olderThanDays?: number;
|
|
95
|
-
}): number;
|
|
96
|
-
/**
|
|
97
|
-
* [KVKK/GDPR] Cleans expired records.
|
|
98
|
-
* Operates based on each audit record's retentionDays field.
|
|
99
|
-
* Can be auto-triggered by cron job or each Audit.log() call.
|
|
100
|
-
*
|
|
101
|
-
* @returns Number of cleaned records
|
|
102
|
-
*/
|
|
103
|
-
static cleanExpired(): number;
|
|
104
|
-
/**
|
|
105
|
-
* Returns audit statistics.
|
|
106
|
-
*/
|
|
107
|
-
static getStats(): {
|
|
108
|
-
total: number;
|
|
109
|
-
byStatus: Record<string, number>;
|
|
110
|
-
byAction: Record<string, number>;
|
|
111
|
-
byCategory: Record<string, number>;
|
|
112
|
-
recentErrors: AuditEntry[];
|
|
113
|
-
expiredCount: number;
|
|
114
|
-
};
|
|
115
|
-
/**
|
|
116
|
-
* [KVKK Art. 7] Clears all audit records.
|
|
117
|
-
* Used under the "Right to Erasure" provision.
|
|
118
|
-
* Only authorized users may call this.
|
|
119
|
-
*/
|
|
120
|
-
static clearAll(confirmationCode: string): number;
|
|
121
|
-
}
|
|
1
|
+
export * from "./modules/observability/audit.js";
|