atabey-shared 0.1.0-beta.0 → 0.1.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.
- package/README.md +63 -24
- package/dist/agent-identity.d.ts +1 -34
- package/dist/agent-identity.js +1 -76
- package/dist/agent-identity.js.map +1 -1
- package/dist/api-catalog.d.ts +1 -57
- package/dist/api-catalog.js +1 -253
- package/dist/api-catalog.js.map +1 -1
- package/dist/audit-chain.d.ts +1 -80
- package/dist/audit-chain.js +1 -261
- package/dist/audit-chain.js.map +1 -1
- package/dist/audit.d.ts +1 -121
- package/dist/audit.js +1 -321
- package/dist/audit.js.map +1 -1
- package/dist/constants.d.ts +1 -153
- package/dist/constants.js +1 -214
- package/dist/constants.js.map +1 -1
- package/dist/database.d.ts +1 -5
- package/dist/database.js +1 -12
- package/dist/database.js.map +1 -1
- package/dist/errors.d.ts +1 -46
- package/dist/errors.js +1 -68
- package/dist/errors.js.map +1 -1
- package/dist/file-lock.d.ts +1 -93
- package/dist/file-lock.js +1 -239
- package/dist/file-lock.js.map +1 -1
- package/dist/fs.d.ts +1 -9
- package/dist/fs.js +1 -53
- package/dist/fs.js.map +1 -1
- package/dist/index.d.ts +2 -31
- package/dist/index.js +2 -31
- package/dist/index.js.map +1 -1
- package/dist/job-queue.d.ts +1 -53
- package/dist/job-queue.js +1 -126
- package/dist/job-queue.js.map +1 -1
- package/dist/lock.d.ts +1 -82
- package/dist/lock.js +1 -158
- package/dist/lock.js.map +1 -1
- package/dist/logger.d.ts +1 -31
- package/dist/logger.js +1 -152
- package/dist/logger.js.map +1 -1
- package/dist/memory-prune.d.ts +1 -18
- package/dist/memory-prune.js +1 -47
- package/dist/memory-prune.js.map +1 -1
- package/dist/migrations.d.ts +1 -69
- package/dist/migrations.js +1 -374
- package/dist/migrations.js.map +1 -1
- package/dist/modules/agent/agent-identity.d.ts +34 -0
- package/dist/modules/agent/agent-identity.js +77 -0
- package/dist/modules/agent/agent-identity.js.map +1 -0
- package/dist/modules/agent/api-catalog.d.ts +57 -0
- package/dist/modules/agent/api-catalog.js +254 -0
- package/dist/modules/agent/api-catalog.js.map +1 -0
- package/dist/modules/agent/index.d.ts +3 -0
- package/dist/modules/agent/index.js +4 -0
- package/dist/modules/agent/index.js.map +1 -0
- package/dist/modules/agent/tokenizer.d.ts +54 -0
- package/dist/modules/agent/tokenizer.js +272 -0
- package/dist/modules/agent/tokenizer.js.map +1 -0
- package/dist/modules/concurrency/file-lock.d.ts +93 -0
- package/dist/modules/concurrency/file-lock.js +240 -0
- package/dist/modules/concurrency/file-lock.js.map +1 -0
- package/dist/modules/concurrency/index.d.ts +6 -0
- package/dist/modules/concurrency/index.js +7 -0
- package/dist/modules/concurrency/index.js.map +1 -0
- package/dist/modules/concurrency/job-queue.d.ts +76 -0
- package/dist/modules/concurrency/job-queue.js +200 -0
- package/dist/modules/concurrency/job-queue.js.map +1 -0
- package/dist/modules/concurrency/lock.d.ts +82 -0
- package/dist/modules/concurrency/lock.js +159 -0
- package/dist/modules/concurrency/lock.js.map +1 -0
- package/dist/modules/concurrency/resilience.d.ts +84 -0
- package/dist/modules/concurrency/resilience.js +217 -0
- package/dist/modules/concurrency/resilience.js.map +1 -0
- package/dist/modules/concurrency/worker-pool.d.ts +52 -0
- package/dist/modules/concurrency/worker-pool.js +229 -0
- package/dist/modules/concurrency/worker-pool.js.map +1 -0
- package/dist/modules/concurrency/worker-thread.d.ts +21 -0
- package/dist/modules/concurrency/worker-thread.js +67 -0
- package/dist/modules/concurrency/worker-thread.js.map +1 -0
- package/dist/modules/index.d.ts +14 -0
- package/dist/modules/index.js +15 -0
- package/dist/modules/index.js.map +1 -0
- package/dist/modules/observability/audit-chain.d.ts +80 -0
- package/dist/modules/observability/audit-chain.js +262 -0
- package/dist/modules/observability/audit-chain.js.map +1 -0
- package/dist/modules/observability/audit.d.ts +121 -0
- package/dist/modules/observability/audit.js +322 -0
- package/dist/modules/observability/audit.js.map +1 -0
- package/dist/modules/observability/index.d.ts +4 -0
- package/dist/modules/observability/index.js +5 -0
- package/dist/modules/observability/index.js.map +1 -0
- package/dist/modules/observability/logger.d.ts +31 -0
- package/dist/modules/observability/logger.js +153 -0
- package/dist/modules/observability/logger.js.map +1 -0
- package/dist/modules/observability/otel.d.ts +39 -0
- package/dist/modules/observability/otel.js +93 -0
- package/dist/modules/observability/otel.js.map +1 -0
- package/dist/modules/primitives/constants.d.ts +150 -0
- package/dist/modules/primitives/constants.js +212 -0
- package/dist/modules/primitives/constants.js.map +1 -0
- package/dist/modules/primitives/errors.d.ts +46 -0
- package/dist/modules/primitives/errors.js +69 -0
- package/dist/modules/primitives/errors.js.map +1 -0
- package/dist/modules/primitives/fs.d.ts +9 -0
- package/dist/modules/primitives/fs.js +54 -0
- package/dist/modules/primitives/fs.js.map +1 -0
- package/dist/modules/primitives/index.d.ts +7 -0
- package/dist/modules/primitives/index.js +8 -0
- package/dist/modules/primitives/index.js.map +1 -0
- package/dist/modules/primitives/outbound-http.d.ts +32 -0
- package/dist/modules/primitives/outbound-http.js +88 -0
- package/dist/modules/primitives/outbound-http.js.map +1 -0
- package/dist/modules/primitives/string.d.ts +1 -0
- package/dist/modules/primitives/string.js +30 -0
- package/dist/modules/primitives/string.js.map +1 -0
- package/dist/modules/primitives/time.d.ts +5 -0
- package/dist/modules/primitives/time.js +35 -0
- package/dist/modules/primitives/time.js.map +1 -0
- package/dist/modules/primitives/types.d.ts +27 -0
- package/dist/modules/primitives/types.js +17 -0
- package/dist/modules/primitives/types.js.map +1 -0
- package/dist/modules/sandbox/index.d.ts +3 -0
- package/dist/modules/sandbox/index.js +4 -0
- package/dist/modules/sandbox/index.js.map +1 -0
- package/dist/modules/sandbox/sandbox-fs.d.ts +28 -0
- package/dist/modules/sandbox/sandbox-fs.js +143 -0
- package/dist/modules/sandbox/sandbox-fs.js.map +1 -0
- package/dist/modules/sandbox/sandbox-runtime.d.ts +78 -0
- package/dist/modules/sandbox/sandbox-runtime.js +282 -0
- package/dist/modules/sandbox/sandbox-runtime.js.map +1 -0
- package/dist/modules/sandbox/sandbox.d.ts +54 -0
- package/dist/modules/sandbox/sandbox.js +179 -0
- package/dist/modules/sandbox/sandbox.js.map +1 -0
- package/dist/modules/security/index.d.ts +5 -0
- package/dist/modules/security/index.js +6 -0
- package/dist/modules/security/index.js.map +1 -0
- package/dist/modules/security/pii.d.ts +70 -0
- package/dist/modules/security/pii.js +276 -0
- package/dist/modules/security/pii.js.map +1 -0
- package/dist/modules/security/policy-gate.d.ts +42 -0
- package/dist/modules/security/policy-gate.js +172 -0
- package/dist/modules/security/policy-gate.js.map +1 -0
- package/dist/modules/security/retention.d.ts +68 -0
- package/dist/modules/security/retention.js +218 -0
- package/dist/modules/security/retention.js.map +1 -0
- package/dist/modules/security/secrets.d.ts +99 -0
- package/dist/modules/security/secrets.js +371 -0
- package/dist/modules/security/secrets.js.map +1 -0
- package/dist/modules/security/tls.d.ts +87 -0
- package/dist/modules/security/tls.js +154 -0
- package/dist/modules/security/tls.js.map +1 -0
- package/dist/modules/storage/database.d.ts +6 -0
- package/dist/modules/storage/database.js +16 -0
- package/dist/modules/storage/database.js.map +1 -0
- package/dist/modules/storage/index.d.ts +4 -0
- package/dist/modules/storage/index.js +5 -0
- package/dist/modules/storage/index.js.map +1 -0
- package/dist/modules/storage/memory-prune.d.ts +18 -0
- package/dist/modules/storage/memory-prune.js +48 -0
- package/dist/modules/storage/memory-prune.js.map +1 -0
- package/dist/modules/storage/migrations.d.ts +69 -0
- package/dist/modules/storage/migrations.js +394 -0
- package/dist/modules/storage/migrations.js.map +1 -0
- package/dist/modules/storage/storage.d.ts +341 -0
- package/dist/modules/storage/storage.js +1004 -0
- package/dist/modules/storage/storage.js.map +1 -0
- package/dist/otel.d.ts +1 -39
- package/dist/otel.js +1 -92
- package/dist/otel.js.map +1 -1
- package/dist/outbound-http.d.ts +1 -32
- package/dist/outbound-http.js +1 -87
- package/dist/outbound-http.js.map +1 -1
- package/dist/pii.d.ts +1 -70
- package/dist/pii.js +1 -275
- package/dist/pii.js.map +1 -1
- package/dist/policy-gate.d.ts +1 -42
- package/dist/policy-gate.js +1 -171
- package/dist/policy-gate.js.map +1 -1
- package/dist/resilience.d.ts +1 -84
- package/dist/resilience.js +1 -216
- package/dist/resilience.js.map +1 -1
- package/dist/retention.d.ts +1 -68
- package/dist/retention.js +1 -217
- package/dist/retention.js.map +1 -1
- package/dist/sandbox-fs.d.ts +1 -28
- package/dist/sandbox-fs.js +1 -142
- package/dist/sandbox-fs.js.map +1 -1
- package/dist/sandbox-runtime.d.ts +1 -78
- package/dist/sandbox-runtime.js +1 -281
- package/dist/sandbox-runtime.js.map +1 -1
- package/dist/sandbox.d.ts +1 -54
- package/dist/sandbox.js +1 -178
- package/dist/sandbox.js.map +1 -1
- package/dist/secrets.d.ts +1 -99
- package/dist/secrets.js +1 -370
- package/dist/secrets.js.map +1 -1
- package/dist/storage.d.ts +1 -341
- package/dist/storage.js +1 -1003
- package/dist/storage.js.map +1 -1
- package/dist/string.d.ts +1 -1
- package/dist/string.js +1 -29
- package/dist/string.js.map +1 -1
- package/dist/time.d.ts +1 -5
- package/dist/time.js +1 -34
- package/dist/time.js.map +1 -1
- package/dist/tls.d.ts +1 -87
- package/dist/tls.js +1 -153
- package/dist/tls.js.map +1 -1
- package/dist/tokenizer.d.ts +1 -54
- package/dist/tokenizer.js +1 -271
- package/dist/tokenizer.js.map +1 -1
- package/dist/types.d.ts +1 -27
- package/dist/types.js +1 -16
- package/dist/types.js.map +1 -1
- package/dist/worker-pool.d.ts +1 -52
- package/dist/worker-pool.js +1 -228
- package/dist/worker-pool.js.map +1 -1
- package/dist/worker-thread.d.ts +1 -21
- package/dist/worker-thread.js +1 -66
- package/dist/worker-thread.js.map +1 -1
- package/package.json +44 -34
package/dist/migrations.js
CHANGED
|
@@ -1,375 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
* SQLite Schema Migration Runner, Startup Integrity Check & Online Backup/Restore (Phase 1.5)
|
|
3
|
-
*
|
|
4
|
-
* Provides:
|
|
5
|
-
* 1. Versioned, checksummed schema migrations (`schema_migrations` table).
|
|
6
|
-
* 2. Startup integrity verification (`PRAGMA quick_check` / `PRAGMA integrity_check`).
|
|
7
|
-
* 3. Atomic online backup (`VACUUM INTO` + `.sha256` manifest) and verified restore.
|
|
8
|
-
*/
|
|
9
|
-
import Database from "better-sqlite3";
|
|
10
|
-
import crypto from "crypto";
|
|
11
|
-
import fs from "fs";
|
|
12
|
-
import path from "path";
|
|
13
|
-
export const BUILTIN_MIGRATIONS = [
|
|
14
|
-
{
|
|
15
|
-
version: 1,
|
|
16
|
-
name: "001_initial_core_tables",
|
|
17
|
-
sql: `
|
|
18
|
-
CREATE TABLE IF NOT EXISTS agents (
|
|
19
|
-
name TEXT PRIMARY KEY,
|
|
20
|
-
state TEXT DEFAULT 'READY',
|
|
21
|
-
task TEXT DEFAULT 'Idle',
|
|
22
|
-
description TEXT DEFAULT '',
|
|
23
|
-
skills TEXT DEFAULT '[]',
|
|
24
|
-
last_updated DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
25
|
-
);
|
|
26
|
-
CREATE TABLE IF NOT EXISTS messages (
|
|
27
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
28
|
-
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
29
|
-
sender TEXT,
|
|
30
|
-
receiver TEXT,
|
|
31
|
-
category TEXT,
|
|
32
|
-
content TEXT,
|
|
33
|
-
trace_id TEXT,
|
|
34
|
-
parent_id TEXT,
|
|
35
|
-
status TEXT DEFAULT 'PENDING',
|
|
36
|
-
priority TEXT DEFAULT 'NORMAL',
|
|
37
|
-
requires_approval BOOLEAN DEFAULT 0
|
|
38
|
-
);
|
|
39
|
-
CREATE TABLE IF NOT EXISTS tasks (
|
|
40
|
-
id TEXT PRIMARY KEY,
|
|
41
|
-
trace_id TEXT,
|
|
42
|
-
description TEXT,
|
|
43
|
-
agent TEXT,
|
|
44
|
-
status TEXT DEFAULT 'PENDING',
|
|
45
|
-
priority TEXT DEFAULT 'NORMAL',
|
|
46
|
-
dependencies TEXT,
|
|
47
|
-
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
48
|
-
);
|
|
49
|
-
CREATE TABLE IF NOT EXISTS logs (
|
|
50
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
51
|
-
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
52
|
-
agent TEXT,
|
|
53
|
-
action TEXT,
|
|
54
|
-
trace_id TEXT,
|
|
55
|
-
status TEXT,
|
|
56
|
-
summary TEXT,
|
|
57
|
-
findings TEXT,
|
|
58
|
-
prev_hash TEXT,
|
|
59
|
-
hash TEXT
|
|
60
|
-
);
|
|
61
|
-
CREATE TABLE IF NOT EXISTS metadata (
|
|
62
|
-
key TEXT PRIMARY KEY,
|
|
63
|
-
value TEXT
|
|
64
|
-
);
|
|
65
|
-
CREATE TABLE IF NOT EXISTS costs (
|
|
66
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
67
|
-
provider TEXT,
|
|
68
|
-
model TEXT,
|
|
69
|
-
input_tokens INTEGER,
|
|
70
|
-
output_tokens INTEGER,
|
|
71
|
-
cost REAL,
|
|
72
|
-
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
73
|
-
trace_id TEXT
|
|
74
|
-
);
|
|
75
|
-
CREATE TABLE IF NOT EXISTS knowledge (
|
|
76
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
77
|
-
filename TEXT UNIQUE,
|
|
78
|
-
content TEXT,
|
|
79
|
-
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
80
|
-
);
|
|
81
|
-
CREATE TABLE IF NOT EXISTS users (
|
|
82
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
83
|
-
name TEXT UNIQUE,
|
|
84
|
-
token TEXT UNIQUE,
|
|
85
|
-
role TEXT DEFAULT 'user',
|
|
86
|
-
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
87
|
-
);
|
|
88
|
-
`,
|
|
89
|
-
},
|
|
90
|
-
{
|
|
91
|
-
version: 2,
|
|
92
|
-
name: "002_governance_approvals_discipline_cooldowns",
|
|
93
|
-
sql: `
|
|
94
|
-
CREATE TABLE IF NOT EXISTS loop_cooldowns (
|
|
95
|
-
agent TEXT PRIMARY KEY,
|
|
96
|
-
cooldown_until INTEGER NOT NULL,
|
|
97
|
-
detail TEXT,
|
|
98
|
-
cooldown_count INTEGER DEFAULT 1,
|
|
99
|
-
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
100
|
-
);
|
|
101
|
-
CREATE TABLE IF NOT EXISTS approvals (
|
|
102
|
-
trace_id TEXT PRIMARY KEY,
|
|
103
|
-
tool_name TEXT NOT NULL,
|
|
104
|
-
agent TEXT NOT NULL,
|
|
105
|
-
risk_score INTEGER NOT NULL,
|
|
106
|
-
risk_level TEXT NOT NULL,
|
|
107
|
-
reason TEXT NOT NULL,
|
|
108
|
-
args TEXT NOT NULL,
|
|
109
|
-
created_at INTEGER NOT NULL,
|
|
110
|
-
expires_at INTEGER NOT NULL,
|
|
111
|
-
status TEXT DEFAULT 'PENDING',
|
|
112
|
-
passcode TEXT
|
|
113
|
-
);
|
|
114
|
-
CREATE TABLE IF NOT EXISTS discipline (
|
|
115
|
-
agent TEXT PRIMARY KEY,
|
|
116
|
-
total_calls INTEGER DEFAULT 0,
|
|
117
|
-
violations INTEGER DEFAULT 0,
|
|
118
|
-
last_violation TEXT,
|
|
119
|
-
cooldown_until INTEGER DEFAULT 0,
|
|
120
|
-
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
121
|
-
);
|
|
122
|
-
`,
|
|
123
|
-
},
|
|
124
|
-
{
|
|
125
|
-
version: 3,
|
|
126
|
-
name: "003_performance_indexes",
|
|
127
|
-
sql: `
|
|
128
|
-
CREATE INDEX IF NOT EXISTS idx_messages_receiver_status ON messages(receiver, status);
|
|
129
|
-
CREATE INDEX IF NOT EXISTS idx_messages_trace ON messages(trace_id);
|
|
130
|
-
CREATE INDEX IF NOT EXISTS idx_tasks_trace ON tasks(trace_id);
|
|
131
|
-
CREATE INDEX IF NOT EXISTS idx_logs_trace ON logs(trace_id);
|
|
132
|
-
CREATE INDEX IF NOT EXISTS idx_costs_timestamp ON costs(timestamp);
|
|
133
|
-
CREATE INDEX IF NOT EXISTS idx_costs_trace ON costs(trace_id);
|
|
134
|
-
`,
|
|
135
|
-
},
|
|
136
|
-
{
|
|
137
|
-
version: 4,
|
|
138
|
-
name: "004_api_catalog",
|
|
139
|
-
sql: `
|
|
140
|
-
CREATE TABLE IF NOT EXISTS api_endpoints (
|
|
141
|
-
method TEXT NOT NULL,
|
|
142
|
-
path TEXT NOT NULL,
|
|
143
|
-
tag TEXT,
|
|
144
|
-
summary TEXT,
|
|
145
|
-
auth_required INTEGER DEFAULT 0,
|
|
146
|
-
request_schema TEXT,
|
|
147
|
-
response_schema TEXT,
|
|
148
|
-
source TEXT,
|
|
149
|
-
updated_at TEXT NOT NULL,
|
|
150
|
-
PRIMARY KEY (method, path)
|
|
151
|
-
);
|
|
152
|
-
CREATE INDEX IF NOT EXISTS idx_api_endpoints_tag ON api_endpoints(tag);
|
|
153
|
-
`,
|
|
154
|
-
},
|
|
155
|
-
{
|
|
156
|
-
version: 5,
|
|
157
|
-
name: "005_discipline_call_history",
|
|
158
|
-
sql: `
|
|
159
|
-
CREATE TABLE IF NOT EXISTS discipline_calls (
|
|
160
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
161
|
-
agent TEXT NOT NULL,
|
|
162
|
-
tool TEXT NOT NULL,
|
|
163
|
-
ts INTEGER NOT NULL,
|
|
164
|
-
args_size INTEGER DEFAULT 0
|
|
165
|
-
);
|
|
166
|
-
CREATE INDEX IF NOT EXISTS idx_discipline_calls_agent_ts ON discipline_calls(agent, ts);
|
|
167
|
-
`,
|
|
168
|
-
},
|
|
169
|
-
{
|
|
170
|
-
version: 6,
|
|
171
|
-
name: "006_code_graph",
|
|
172
|
-
sql: `
|
|
173
|
-
CREATE TABLE IF NOT EXISTS code_files (
|
|
174
|
-
path TEXT PRIMARY KEY,
|
|
175
|
-
hash TEXT NOT NULL,
|
|
176
|
-
updated_at TEXT NOT NULL
|
|
177
|
-
);
|
|
178
|
-
CREATE TABLE IF NOT EXISTS code_symbols (
|
|
179
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
180
|
-
file TEXT NOT NULL,
|
|
181
|
-
name TEXT NOT NULL,
|
|
182
|
-
kind TEXT NOT NULL,
|
|
183
|
-
start_line INTEGER,
|
|
184
|
-
end_line INTEGER,
|
|
185
|
-
signature TEXT,
|
|
186
|
-
exported INTEGER DEFAULT 0
|
|
187
|
-
);
|
|
188
|
-
CREATE INDEX IF NOT EXISTS idx_code_symbols_name ON code_symbols(name);
|
|
189
|
-
CREATE INDEX IF NOT EXISTS idx_code_symbols_file ON code_symbols(file);
|
|
190
|
-
CREATE TABLE IF NOT EXISTS code_imports (
|
|
191
|
-
file TEXT NOT NULL,
|
|
192
|
-
specifier TEXT NOT NULL
|
|
193
|
-
);
|
|
194
|
-
CREATE INDEX IF NOT EXISTS idx_code_imports_file ON code_imports(file);
|
|
195
|
-
`,
|
|
196
|
-
},
|
|
197
|
-
];
|
|
198
|
-
function migrationChecksum(sql) {
|
|
199
|
-
return crypto.createHash("sha256").update(sql.trim(), "utf8").digest("hex");
|
|
200
|
-
}
|
|
201
|
-
function ensureMigrationsTable(db) {
|
|
202
|
-
db.exec(`
|
|
203
|
-
CREATE TABLE IF NOT EXISTS schema_migrations (
|
|
204
|
-
version INTEGER PRIMARY KEY,
|
|
205
|
-
name TEXT NOT NULL,
|
|
206
|
-
checksum TEXT NOT NULL,
|
|
207
|
-
applied_at TEXT NOT NULL
|
|
208
|
-
)
|
|
209
|
-
`);
|
|
210
|
-
}
|
|
211
|
-
/**
|
|
212
|
-
* Run all pending schema migrations transactionally and return applied version numbers.
|
|
213
|
-
*/
|
|
214
|
-
export function runPendingMigrations(db, migrations = BUILTIN_MIGRATIONS) {
|
|
215
|
-
ensureMigrationsTable(db);
|
|
216
|
-
const existingRows = db
|
|
217
|
-
.prepare("SELECT version, name, checksum, applied_at FROM schema_migrations ORDER BY version ASC")
|
|
218
|
-
.all();
|
|
219
|
-
const existingMap = new Map(existingRows.map((r) => [r.version, r]));
|
|
220
|
-
const sorted = [...migrations].sort((a, b) => a.version - b.version);
|
|
221
|
-
const applied = [];
|
|
222
|
-
for (const m of sorted) {
|
|
223
|
-
const prev = existingMap.get(m.version);
|
|
224
|
-
const checksum = migrationChecksum(m.sql);
|
|
225
|
-
if (prev) {
|
|
226
|
-
if (prev.checksum !== checksum) {
|
|
227
|
-
throw new Error(`[MIGRATION] Checksum mismatch for migration v${m.version} (${m.name}): ` +
|
|
228
|
-
`expected ${prev.checksum}, got ${checksum}.`);
|
|
229
|
-
}
|
|
230
|
-
continue;
|
|
231
|
-
}
|
|
232
|
-
const applyOne = db.transaction(() => {
|
|
233
|
-
db.exec(m.sql);
|
|
234
|
-
db.prepare("INSERT INTO schema_migrations (version, name, checksum, applied_at) VALUES (?, ?, ?, ?)").run(m.version, m.name, checksum, new Date().toISOString());
|
|
235
|
-
});
|
|
236
|
-
applyOne();
|
|
237
|
-
applied.push(m.version);
|
|
238
|
-
}
|
|
239
|
-
// Legacy column backfill for older databases that predate v1 hash columns
|
|
240
|
-
try {
|
|
241
|
-
const tableInfo = db.prepare("PRAGMA table_info(logs)").all();
|
|
242
|
-
const colNames = tableInfo.map((c) => c.name);
|
|
243
|
-
if (colNames.length > 0) {
|
|
244
|
-
if (!colNames.includes("prev_hash"))
|
|
245
|
-
db.exec("ALTER TABLE logs ADD COLUMN prev_hash TEXT");
|
|
246
|
-
if (!colNames.includes("hash"))
|
|
247
|
-
db.exec("ALTER TABLE logs ADD COLUMN hash TEXT");
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
catch {
|
|
251
|
-
/* ignore if logs table does not exist in custom migration test */
|
|
252
|
-
}
|
|
253
|
-
const latest = db.prepare("SELECT MAX(version) as v FROM schema_migrations").get();
|
|
254
|
-
return {
|
|
255
|
-
applied,
|
|
256
|
-
currentVersion: latest?.v ?? 0,
|
|
257
|
-
};
|
|
258
|
-
}
|
|
259
|
-
/**
|
|
260
|
-
* Return applied and pending migrations for diagnostics/CLI.
|
|
261
|
-
*/
|
|
262
|
-
export function getMigrationStatus(db, migrations = BUILTIN_MIGRATIONS) {
|
|
263
|
-
ensureMigrationsTable(db);
|
|
264
|
-
const applied = db
|
|
265
|
-
.prepare("SELECT version, name, checksum, applied_at FROM schema_migrations ORDER BY version ASC")
|
|
266
|
-
.all();
|
|
267
|
-
const appliedSet = new Set(applied.map((a) => a.version));
|
|
268
|
-
const pending = migrations
|
|
269
|
-
.filter((m) => !appliedSet.has(m.version))
|
|
270
|
-
.map((m) => ({ version: m.version, name: m.name }));
|
|
271
|
-
const currentVersion = applied.length > 0 ? applied[applied.length - 1].version : 0;
|
|
272
|
-
return { currentVersion, applied, pending };
|
|
273
|
-
}
|
|
274
|
-
/**
|
|
275
|
-
* Run SQLite integrity_check / quick_check and foreign_key_check.
|
|
276
|
-
*/
|
|
277
|
-
export function verifyDatabaseIntegrity(db, mode = "quick") {
|
|
278
|
-
const pragma = mode === "full" ? "integrity_check" : "quick_check";
|
|
279
|
-
const rows = db.prepare(`PRAGMA ${pragma}`).all();
|
|
280
|
-
const messages = rows.map((r) => Object.values(r)[0] || "");
|
|
281
|
-
const fkRows = db.prepare("PRAGMA foreign_key_check").all();
|
|
282
|
-
const ok = messages.length === 1 && messages[0].toLowerCase() === "ok" && fkRows.length === 0;
|
|
283
|
-
return {
|
|
284
|
-
ok,
|
|
285
|
-
messages,
|
|
286
|
-
foreignKeyViolations: fkRows.length,
|
|
287
|
-
};
|
|
288
|
-
}
|
|
289
|
-
/**
|
|
290
|
-
* Perform a consistent online backup using SQLite `VACUUM INTO` and write a `.sha256` sidecar.
|
|
291
|
-
*/
|
|
292
|
-
export function backupDatabase(db, destinationPath) {
|
|
293
|
-
const absDest = path.resolve(destinationPath);
|
|
294
|
-
const parentDir = path.dirname(absDest);
|
|
295
|
-
fs.mkdirSync(parentDir, { recursive: true });
|
|
296
|
-
if (fs.existsSync(absDest)) {
|
|
297
|
-
fs.unlinkSync(absDest);
|
|
298
|
-
}
|
|
299
|
-
// Escape single quotes in path for SQLite VACUUM INTO literal
|
|
300
|
-
const escapedPath = absDest.replace(/'/g, "''");
|
|
301
|
-
db.exec(`VACUUM INTO '${escapedPath}'`);
|
|
302
|
-
const bytes = fs.readFileSync(absDest);
|
|
303
|
-
const sha256 = crypto.createHash("sha256").update(bytes).digest("hex");
|
|
304
|
-
fs.writeFileSync(`${absDest}.sha256`, `${sha256} ${path.basename(absDest)}\n`, { mode: 0o600 });
|
|
305
|
-
const status = getMigrationStatus(db);
|
|
306
|
-
return {
|
|
307
|
-
backupPath: absDest,
|
|
308
|
-
sha256,
|
|
309
|
-
sizeBytes: bytes.length,
|
|
310
|
-
createdAt: new Date().toISOString(),
|
|
311
|
-
schemaVersion: status.currentVersion,
|
|
312
|
-
};
|
|
313
|
-
}
|
|
314
|
-
/**
|
|
315
|
-
* Verify a backup file (checksum sidecar + SQLite integrity_check) and atomically restore it.
|
|
316
|
-
*/
|
|
317
|
-
export function restoreDatabase(backupPath, targetDbPath, options = {}) {
|
|
318
|
-
const absBackup = path.resolve(backupPath);
|
|
319
|
-
const absTarget = path.resolve(targetDbPath);
|
|
320
|
-
if (!fs.existsSync(absBackup)) {
|
|
321
|
-
throw new Error(`Backup file does not exist: ${absBackup}`);
|
|
322
|
-
}
|
|
323
|
-
const bytes = fs.readFileSync(absBackup);
|
|
324
|
-
const actualSha256 = crypto.createHash("sha256").update(bytes).digest("hex");
|
|
325
|
-
const sidecarPath = `${absBackup}.sha256`;
|
|
326
|
-
if (options.verifyChecksum !== false && fs.existsSync(sidecarPath)) {
|
|
327
|
-
const expected = fs.readFileSync(sidecarPath, "utf8").trim().split(/\s+/)[0];
|
|
328
|
-
if (expected && expected !== actualSha256) {
|
|
329
|
-
throw new Error(`Backup checksum mismatch for ${absBackup}: expected ${expected}, got ${actualSha256}`);
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
// Open backup in read-only mode to verify SQLite integrity before overwriting target
|
|
333
|
-
const tempCheckDb = new Database(absBackup, { readonly: true });
|
|
334
|
-
let schemaVersion = 0;
|
|
335
|
-
try {
|
|
336
|
-
const integrity = verifyDatabaseIntegrity(tempCheckDb, "full");
|
|
337
|
-
if (!integrity.ok) {
|
|
338
|
-
throw new Error(`Backup file failed SQLite integrity check: ${integrity.messages.join("; ")}`);
|
|
339
|
-
}
|
|
340
|
-
try {
|
|
341
|
-
const row = tempCheckDb
|
|
342
|
-
.prepare("SELECT MAX(version) as v FROM schema_migrations")
|
|
343
|
-
.get();
|
|
344
|
-
schemaVersion = row?.v ?? 0;
|
|
345
|
-
}
|
|
346
|
-
catch {
|
|
347
|
-
/* schema_migrations table may not exist in older backups */
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
finally {
|
|
351
|
-
tempCheckDb.close();
|
|
352
|
-
}
|
|
353
|
-
fs.mkdirSync(path.dirname(absTarget), { recursive: true });
|
|
354
|
-
const stagingPath = `${absTarget}.restore.${process.pid}`;
|
|
355
|
-
fs.copyFileSync(absBackup, stagingPath);
|
|
356
|
-
// Remove stale WAL/SHM files before atomic swap
|
|
357
|
-
for (const suffix of ["-wal", "-shm"]) {
|
|
358
|
-
const walFile = `${absTarget}${suffix}`;
|
|
359
|
-
if (fs.existsSync(walFile)) {
|
|
360
|
-
try {
|
|
361
|
-
fs.unlinkSync(walFile);
|
|
362
|
-
}
|
|
363
|
-
catch {
|
|
364
|
-
/* ignore */
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
fs.renameSync(stagingPath, absTarget);
|
|
369
|
-
return {
|
|
370
|
-
restoredPath: absTarget,
|
|
371
|
-
sha256: actualSha256,
|
|
372
|
-
schemaVersion,
|
|
373
|
-
};
|
|
374
|
-
}
|
|
1
|
+
export * from "./modules/storage/migrations.js";
|
|
375
2
|
//# sourceMappingURL=migrations.js.map
|
package/dist/migrations.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrations.js","sourceRoot":"","sources":["../src/migrations.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"migrations.js","sourceRoot":"","sources":["../src/migrations.ts"],"names":[],"mappings":"AAAA,cAAc,iCAAiC,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Identity — cryptographically signed agent tokens.
|
|
3
|
+
*
|
|
4
|
+
* Problem: `ATABEY_ACTIVE_AGENT` is a plain env var, so any tool/subprocess can
|
|
5
|
+
* impersonate `@manager` or `@security`. When `ATABEY_AGENT_SECRET` is set,
|
|
6
|
+
* Atabey accepts an HMAC-signed `ATABEY_AGENT_TOKEN` and verifies it
|
|
7
|
+
* (fail-closed on tampering/expiry). Set `ATABEY_AGENT_IDENTITY_REQUIRED=true`
|
|
8
|
+
* to refuse plain-env identity entirely.
|
|
9
|
+
*
|
|
10
|
+
* Token format: `${agent}.${issuedAt}.${expiresAt}.${hmacSha256Base64url}`
|
|
11
|
+
*/
|
|
12
|
+
export interface AgentIdentity {
|
|
13
|
+
agent: string;
|
|
14
|
+
issuedAt: number;
|
|
15
|
+
expiresAt: number;
|
|
16
|
+
}
|
|
17
|
+
export interface AgentTokenResult {
|
|
18
|
+
valid: boolean;
|
|
19
|
+
agent?: string;
|
|
20
|
+
reason?: string;
|
|
21
|
+
}
|
|
22
|
+
/** True when agent-token verification is mandatory (plain env rejected). */
|
|
23
|
+
export declare function isAgentIdentityEnforced(): boolean;
|
|
24
|
+
/** Sign an agent identity into a compact token. */
|
|
25
|
+
export declare function signAgentToken(agent: string, options?: {
|
|
26
|
+
ttlMs?: number;
|
|
27
|
+
key?: string | Buffer;
|
|
28
|
+
}): string;
|
|
29
|
+
/** Verify an agent token (signature + expiry). */
|
|
30
|
+
export declare function verifyAgentToken(token: string, options?: {
|
|
31
|
+
key?: string | Buffer;
|
|
32
|
+
}): AgentTokenResult;
|
|
33
|
+
/** Decode a token's identity without verification (for diagnostics only). */
|
|
34
|
+
export declare function decodeAgentToken(token: string): AgentIdentity | null;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Identity — cryptographically signed agent tokens.
|
|
3
|
+
*
|
|
4
|
+
* Problem: `ATABEY_ACTIVE_AGENT` is a plain env var, so any tool/subprocess can
|
|
5
|
+
* impersonate `@manager` or `@security`. When `ATABEY_AGENT_SECRET` is set,
|
|
6
|
+
* Atabey accepts an HMAC-signed `ATABEY_AGENT_TOKEN` and verifies it
|
|
7
|
+
* (fail-closed on tampering/expiry). Set `ATABEY_AGENT_IDENTITY_REQUIRED=true`
|
|
8
|
+
* to refuse plain-env identity entirely.
|
|
9
|
+
*
|
|
10
|
+
* Token format: `${agent}.${issuedAt}.${expiresAt}.${hmacSha256Base64url}`
|
|
11
|
+
*/
|
|
12
|
+
import crypto from "crypto";
|
|
13
|
+
import { resolveAuditChainKey } from "../observability/audit-chain.js";
|
|
14
|
+
function resolveKey(explicit) {
|
|
15
|
+
if (explicit) {
|
|
16
|
+
return Buffer.isBuffer(explicit) ? explicit : crypto.createHash("sha256").update(explicit, "utf8").digest();
|
|
17
|
+
}
|
|
18
|
+
const envSecret = process.env.ATABEY_AGENT_SECRET;
|
|
19
|
+
if (envSecret && envSecret.trim()) {
|
|
20
|
+
return crypto.createHash("sha256").update(envSecret.trim(), "utf8").digest();
|
|
21
|
+
}
|
|
22
|
+
return resolveAuditChainKey();
|
|
23
|
+
}
|
|
24
|
+
function timingSafeEqual(a, b) {
|
|
25
|
+
const ba = Buffer.from(a);
|
|
26
|
+
const bb = Buffer.from(b);
|
|
27
|
+
if (ba.length !== bb.length)
|
|
28
|
+
return false;
|
|
29
|
+
return crypto.timingSafeEqual(ba, bb);
|
|
30
|
+
}
|
|
31
|
+
/** True when agent-token verification is mandatory (plain env rejected). */
|
|
32
|
+
export function isAgentIdentityEnforced() {
|
|
33
|
+
return process.env.ATABEY_AGENT_IDENTITY_REQUIRED === "true";
|
|
34
|
+
}
|
|
35
|
+
/** Sign an agent identity into a compact token. */
|
|
36
|
+
export function signAgentToken(agent, options = {}) {
|
|
37
|
+
const key = resolveKey(options.key);
|
|
38
|
+
if (!key) {
|
|
39
|
+
throw new Error("[AGENT_IDENTITY] No signing key. Set ATABEY_AGENT_SECRET.");
|
|
40
|
+
}
|
|
41
|
+
const name = agent.replace(/^@/, "");
|
|
42
|
+
const issuedAt = Date.now();
|
|
43
|
+
const expiresAt = issuedAt + (options.ttlMs ?? 60 * 60 * 1000);
|
|
44
|
+
const payload = `${name}.${issuedAt}.${expiresAt}`;
|
|
45
|
+
const sig = crypto.createHmac("sha256", key).update(payload).digest("base64url");
|
|
46
|
+
return `${payload}.${sig}`;
|
|
47
|
+
}
|
|
48
|
+
/** Verify an agent token (signature + expiry). */
|
|
49
|
+
export function verifyAgentToken(token, options = {}) {
|
|
50
|
+
const key = resolveKey(options.key);
|
|
51
|
+
if (!key)
|
|
52
|
+
return { valid: false, reason: "No signing key configured." };
|
|
53
|
+
if (!token || typeof token !== "string")
|
|
54
|
+
return { valid: false, reason: "Empty token." };
|
|
55
|
+
const parts = token.split(".");
|
|
56
|
+
if (parts.length !== 4)
|
|
57
|
+
return { valid: false, reason: "Malformed token." };
|
|
58
|
+
const [name, issuedAt, expiresAt, sig] = parts;
|
|
59
|
+
const payload = `${name}.${issuedAt}.${expiresAt}`;
|
|
60
|
+
const expected = crypto.createHmac("sha256", key).update(payload).digest("base64url");
|
|
61
|
+
if (!timingSafeEqual(sig, expected))
|
|
62
|
+
return { valid: false, reason: "Signature mismatch." };
|
|
63
|
+
const exp = Number(expiresAt);
|
|
64
|
+
if (!Number.isFinite(exp))
|
|
65
|
+
return { valid: false, reason: "Invalid expiry." };
|
|
66
|
+
if (Date.now() > exp)
|
|
67
|
+
return { valid: false, reason: "Token expired." };
|
|
68
|
+
return { valid: true, agent: `@${name}` };
|
|
69
|
+
}
|
|
70
|
+
/** Decode a token's identity without verification (for diagnostics only). */
|
|
71
|
+
export function decodeAgentToken(token) {
|
|
72
|
+
const parts = token.split(".");
|
|
73
|
+
if (parts.length !== 4)
|
|
74
|
+
return null;
|
|
75
|
+
return { agent: `@${parts[0]}`, issuedAt: Number(parts[1]), expiresAt: Number(parts[2]) };
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=agent-identity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-identity.js","sourceRoot":"","sources":["../../../src/modules/agent/agent-identity.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Catalog — endpoint registry, route/OpenAPI scanner, and drift detection.
|
|
3
|
+
*
|
|
4
|
+
* Purpose: let frontend/mobile agents integrate against the backend API using
|
|
5
|
+
* a compact JSON catalog instead of reading large route source files (token
|
|
6
|
+
* savings + zero context pollution).
|
|
7
|
+
*
|
|
8
|
+
* The scanner is HEURISTIC (regex/AST-lite) and covers:
|
|
9
|
+
* - Express / Fastify: app|router|server|fastify.get('/path', ...)
|
|
10
|
+
* - Fastify route(): fastify.route({ method, url, ... })
|
|
11
|
+
* - NestJS decorators: @Get('path') / @Post('path')
|
|
12
|
+
* - OpenAPI v3 / Swagger v2 JSON specs
|
|
13
|
+
*/
|
|
14
|
+
export interface ApiEndpoint {
|
|
15
|
+
method: string;
|
|
16
|
+
path: string;
|
|
17
|
+
tag?: string;
|
|
18
|
+
summary?: string;
|
|
19
|
+
authRequired: boolean;
|
|
20
|
+
requestSchema?: string;
|
|
21
|
+
responseSchema?: string;
|
|
22
|
+
source?: string;
|
|
23
|
+
updatedAt: string;
|
|
24
|
+
}
|
|
25
|
+
export interface ApiCatalog {
|
|
26
|
+
version: 1;
|
|
27
|
+
generatedAt: string;
|
|
28
|
+
endpoints: ApiEndpoint[];
|
|
29
|
+
}
|
|
30
|
+
export interface ApiDrift {
|
|
31
|
+
added: ApiEndpoint[];
|
|
32
|
+
removed: ApiEndpoint[];
|
|
33
|
+
changed: Array<{
|
|
34
|
+
previous: ApiEndpoint;
|
|
35
|
+
current: ApiEndpoint;
|
|
36
|
+
}>;
|
|
37
|
+
}
|
|
38
|
+
export declare function endpointKey(e: {
|
|
39
|
+
method: string;
|
|
40
|
+
path: string;
|
|
41
|
+
}): string;
|
|
42
|
+
export declare function normalizePath(p: string): string;
|
|
43
|
+
/** Parse an OpenAPI v3 or Swagger v2 spec object into endpoints. */
|
|
44
|
+
export declare function parseOpenApiSpec(spec: unknown): ApiEndpoint[];
|
|
45
|
+
/**
|
|
46
|
+
* Walk a project tree and collect endpoints from route source files and any
|
|
47
|
+
* OpenAPI/Swagger JSON specs.
|
|
48
|
+
*/
|
|
49
|
+
export declare function scanProjectForEndpoints(rootDir: string, options?: {
|
|
50
|
+
maxFiles?: number;
|
|
51
|
+
}): ApiEndpoint[];
|
|
52
|
+
export declare function dedupe(endpoints: ApiEndpoint[]): ApiEndpoint[];
|
|
53
|
+
/**
|
|
54
|
+
* Diff a previous catalog against a freshly scanned one.
|
|
55
|
+
*/
|
|
56
|
+
export declare function detectApiDrift(previous: ApiEndpoint[], current: ApiEndpoint[]): ApiDrift;
|
|
57
|
+
export declare function isApiDriftClean(drift: ApiDrift): boolean;
|