atabey 0.0.13 → 0.0.15
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/ATABEY.md +1 -1
- package/PRIVACY.md +8 -14
- package/README.md +405 -56
- package/bin/cli.js +72 -5
- package/dist/framework-mcp/src/index.js +988 -63
- package/dist/framework-mcp/src/index.js.map +1 -1
- package/dist/framework-mcp/src/tools/compliance/mask_pii.d.ts +17 -0
- package/dist/framework-mcp/src/tools/compliance/mask_pii.js +56 -0
- package/dist/framework-mcp/src/tools/compliance/mask_pii.js.map +1 -0
- package/dist/framework-mcp/src/tools/definitions.js +10 -9
- package/dist/framework-mcp/src/tools/definitions.js.map +1 -1
- package/dist/framework-mcp/src/tools/framework/run_tests.js +25 -0
- package/dist/framework-mcp/src/tools/framework/run_tests.js.map +1 -1
- package/dist/framework-mcp/src/tools/index.js +7 -8
- package/dist/framework-mcp/src/tools/index.js.map +1 -1
- package/dist/framework-mcp/src/tools/messaging/approve_operation.d.ts +22 -0
- package/dist/framework-mcp/src/tools/messaging/approve_operation.js +81 -0
- package/dist/framework-mcp/src/tools/messaging/approve_operation.js.map +1 -0
- package/dist/framework-mcp/src/tools/messaging/ask_human.d.ts +15 -0
- package/dist/framework-mcp/src/tools/messaging/ask_human.js +89 -20
- package/dist/framework-mcp/src/tools/messaging/ask_human.js.map +1 -1
- package/dist/framework-mcp/src/tools/observability/check_ports.d.ts +1 -0
- package/dist/framework-mcp/src/tools/observability/check_ports.js +24 -8
- package/dist/framework-mcp/src/tools/observability/check_ports.js.map +1 -1
- package/dist/framework-mcp/src/tools/quality/analyze_code_quality.js +13 -64
- package/dist/framework-mcp/src/tools/quality/analyze_code_quality.js.map +1 -1
- package/dist/framework-mcp/src/tools/schemas.d.ts +48 -53
- package/dist/framework-mcp/src/tools/schemas.js +18 -22
- package/dist/framework-mcp/src/tools/schemas.js.map +1 -1
- package/dist/framework-mcp/src/tools/shell/run_command.js +146 -90
- package/dist/framework-mcp/src/tools/shell/run_command.js.map +1 -1
- package/dist/framework-mcp/src/tools/types.d.ts +11 -105
- package/dist/framework-mcp/src/tools/types.js +1 -0
- package/dist/framework-mcp/src/tools/types.js.map +1 -1
- package/dist/framework-mcp/src/utils/auth.d.ts +36 -0
- package/dist/framework-mcp/src/utils/auth.js +79 -0
- package/dist/framework-mcp/src/utils/auth.js.map +1 -0
- package/dist/framework-mcp/src/utils/auto-rollback.d.ts +71 -0
- package/dist/framework-mcp/src/utils/auto-rollback.js +266 -0
- package/dist/framework-mcp/src/utils/auto-rollback.js.map +1 -0
- package/dist/framework-mcp/src/utils/compliance.js +12 -4
- package/dist/framework-mcp/src/utils/compliance.js.map +1 -1
- package/dist/framework-mcp/src/utils/context-optimizer.d.ts +69 -0
- package/dist/framework-mcp/src/utils/context-optimizer.js +157 -0
- package/dist/framework-mcp/src/utils/context-optimizer.js.map +1 -0
- package/dist/framework-mcp/src/utils/discipline.d.ts +68 -0
- package/dist/framework-mcp/src/utils/discipline.js +218 -0
- package/dist/framework-mcp/src/utils/discipline.js.map +1 -0
- package/dist/framework-mcp/src/utils/finops.d.ts +143 -0
- package/dist/framework-mcp/src/utils/finops.js +326 -0
- package/dist/framework-mcp/src/utils/finops.js.map +1 -0
- package/dist/framework-mcp/src/utils/human-in-loop.d.ts +95 -0
- package/dist/framework-mcp/src/utils/human-in-loop.js +216 -0
- package/dist/framework-mcp/src/utils/human-in-loop.js.map +1 -0
- package/dist/framework-mcp/src/utils/license-scanner.d.ts +71 -0
- package/dist/framework-mcp/src/utils/license-scanner.js +284 -0
- package/dist/framework-mcp/src/utils/license-scanner.js.map +1 -0
- package/dist/framework-mcp/src/utils/loop-detector.d.ts +105 -0
- package/dist/framework-mcp/src/utils/loop-detector.js +362 -0
- package/dist/framework-mcp/src/utils/loop-detector.js.map +1 -0
- package/dist/framework-mcp/src/utils/quality.d.ts +19 -0
- package/dist/framework-mcp/src/utils/quality.js +125 -0
- package/dist/framework-mcp/src/utils/quality.js.map +1 -0
- package/dist/framework-mcp/src/utils/rules-engine.d.ts +78 -0
- package/dist/framework-mcp/src/utils/rules-engine.js +232 -0
- package/dist/framework-mcp/src/utils/rules-engine.js.map +1 -0
- package/dist/framework-mcp/src/utils/silent-router.d.ts +49 -0
- package/dist/framework-mcp/src/utils/silent-router.js +155 -0
- package/dist/framework-mcp/src/utils/silent-router.js.map +1 -0
- package/dist/framework-mcp/src/utils/storage.d.ts +1 -0
- package/dist/framework-mcp/src/utils/storage.js +2 -2
- package/dist/framework-mcp/src/utils/storage.js.map +1 -1
- package/dist/framework-mcp/src/utils/telemetry-streamer.d.ts +133 -0
- package/dist/framework-mcp/src/utils/telemetry-streamer.js +397 -0
- package/dist/framework-mcp/src/utils/telemetry-streamer.js.map +1 -0
- package/dist/framework-mcp/tests/tools/file_system/file_system_tools.test.js +2 -2
- package/dist/framework-mcp/tests/tools/file_system/file_system_tools.test.js.map +1 -1
- package/dist/framework-mcp/tests/tools/framework/run_tests.test.d.ts +1 -0
- package/dist/framework-mcp/tests/tools/framework/run_tests.test.js +49 -0
- package/dist/framework-mcp/tests/tools/framework/run_tests.test.js.map +1 -0
- package/dist/framework-mcp/tests/tools/messaging/send_message.test.js +14 -5
- package/dist/framework-mcp/tests/tools/messaging/send_message.test.js.map +1 -1
- package/dist/framework-mcp/tests/tools/observability/check_ports.test.d.ts +1 -0
- package/dist/framework-mcp/tests/tools/observability/check_ports.test.js +44 -0
- package/dist/framework-mcp/tests/tools/observability/check_ports.test.js.map +1 -0
- package/dist/framework-mcp/tests/tools/shell/run_command.test.js +44 -14
- package/dist/framework-mcp/tests/tools/shell/run_command.test.js.map +1 -1
- package/dist/framework-mcp/tests/utils/auto-rollback.test.d.ts +7 -0
- package/dist/framework-mcp/tests/utils/auto-rollback.test.js +178 -0
- package/dist/framework-mcp/tests/utils/auto-rollback.test.js.map +1 -0
- package/dist/framework-mcp/tests/utils/context-optimizer.test.d.ts +1 -0
- package/dist/framework-mcp/tests/utils/context-optimizer.test.js +62 -0
- package/dist/framework-mcp/tests/utils/context-optimizer.test.js.map +1 -0
- package/dist/framework-mcp/tests/utils/finops.test.d.ts +7 -0
- package/dist/framework-mcp/tests/utils/finops.test.js +157 -0
- package/dist/framework-mcp/tests/utils/finops.test.js.map +1 -0
- package/dist/framework-mcp/tests/utils/human-in-loop.test.d.ts +1 -0
- package/dist/framework-mcp/tests/utils/human-in-loop.test.js +59 -0
- package/dist/framework-mcp/tests/utils/human-in-loop.test.js.map +1 -0
- package/dist/framework-mcp/tests/utils/license-scanner.test.d.ts +7 -0
- package/dist/framework-mcp/tests/utils/license-scanner.test.js +131 -0
- package/dist/framework-mcp/tests/utils/license-scanner.test.js.map +1 -0
- package/dist/framework-mcp/tests/utils/loop-detector.test.d.ts +7 -0
- package/dist/framework-mcp/tests/utils/loop-detector.test.js +204 -0
- package/dist/framework-mcp/tests/utils/loop-detector.test.js.map +1 -0
- package/dist/framework-mcp/tests/utils/rules-engine.test.d.ts +1 -0
- package/dist/framework-mcp/tests/utils/rules-engine.test.js +106 -0
- package/dist/framework-mcp/tests/utils/rules-engine.test.js.map +1 -0
- package/dist/framework-mcp/tests/utils/telemetry-streamer.test.d.ts +7 -0
- package/dist/framework-mcp/tests/utils/telemetry-streamer.test.js +201 -0
- package/dist/framework-mcp/tests/utils/telemetry-streamer.test.js.map +1 -0
- package/dist/src/cli/commands/check.js +16 -1
- package/dist/src/cli/commands/check.js.map +1 -1
- package/dist/src/cli/commands/dashboard.js +188 -164
- package/dist/src/cli/commands/dashboard.js.map +1 -1
- package/dist/src/cli/commands/gateway.js +2 -2
- package/dist/src/cli/commands/gateway.js.map +1 -1
- package/dist/src/cli/commands/init/scaffold-core.d.ts +2 -0
- package/dist/src/cli/commands/init/scaffold-core.js +16 -1
- package/dist/src/cli/commands/init/scaffold-core.js.map +1 -1
- package/dist/src/cli/commands/init/scaffold-ops.js +2 -2
- package/dist/src/cli/commands/init/scaffold-ops.js.map +1 -1
- package/dist/src/cli/commands/init/scaffold-standards.js +13 -1
- package/dist/src/cli/commands/init/scaffold-standards.js.map +1 -1
- package/dist/src/cli/commands/init.d.ts +4 -0
- package/dist/src/cli/commands/init.js +94 -31
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/commands/mcp.js +3 -1
- package/dist/src/cli/commands/mcp.js.map +1 -1
- package/dist/src/cli/commands/quickstart.d.ts +1 -1
- package/dist/src/cli/commands/quickstart.js +12 -24
- package/dist/src/cli/commands/quickstart.js.map +1 -1
- package/dist/src/cli/commands/script.js +8 -1
- package/dist/src/cli/commands/script.js.map +1 -1
- package/dist/src/cli/index.js +24 -23
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/cli/shims.js +7 -7
- package/dist/src/cli/utils/pkg.js +2 -3
- package/dist/src/cli/utils/pkg.js.map +1 -1
- package/dist/src/cli/utils/quality.d.ts +10 -0
- package/dist/src/cli/utils/quality.js +10 -0
- package/dist/src/cli/utils/quality.js.map +1 -0
- package/dist/src/modules/agents/definitions.js +45 -40
- package/dist/src/modules/agents/definitions.js.map +1 -1
- package/dist/src/modules/agents/registry/manager.js +6 -1
- package/dist/src/modules/agents/registry/manager.js.map +1 -1
- package/dist/src/modules/engines/agent-executor.d.ts +6 -10
- package/dist/src/modules/engines/agent-executor.js +63 -21
- package/dist/src/modules/engines/agent-executor.js.map +1 -1
- package/dist/src/modules/engines/agent-loop.d.ts +34 -0
- package/dist/src/modules/engines/agent-loop.js +102 -0
- package/dist/src/modules/engines/agent-loop.js.map +1 -0
- package/dist/src/modules/engines/evaluation-engine.d.ts +12 -2
- package/dist/src/modules/engines/evaluation-engine.js +78 -11
- package/dist/src/modules/engines/evaluation-engine.js.map +1 -1
- package/dist/src/modules/engines/quality-gate.d.ts +13 -5
- package/dist/src/modules/engines/quality-gate.js +39 -31
- package/dist/src/modules/engines/quality-gate.js.map +1 -1
- package/dist/src/modules/engines/routing-engine.d.ts +5 -3
- package/dist/src/modules/engines/routing-engine.js +16 -9
- package/dist/src/modules/engines/routing-engine.js.map +1 -1
- package/dist/src/modules/gateway/cost-tracker.d.ts +5 -0
- package/dist/src/modules/gateway/cost-tracker.js +71 -0
- package/dist/src/modules/gateway/cost-tracker.js.map +1 -1
- package/dist/src/modules/gateway/gateway.d.ts +4 -0
- package/dist/src/modules/gateway/gateway.js +8 -0
- package/dist/src/modules/gateway/gateway.js.map +1 -1
- package/dist/src/shared/audit.js +3 -2
- package/dist/src/shared/audit.js.map +1 -1
- package/dist/src/shared/pii.d.ts +41 -9
- package/dist/src/shared/pii.js +122 -31
- package/dist/src/shared/pii.js.map +1 -1
- package/dist/src/shared/storage.d.ts +62 -0
- package/dist/src/shared/storage.js +47 -7
- package/dist/src/shared/storage.js.map +1 -1
- package/dist/tests/embedding.test.d.ts +1 -0
- package/dist/tests/embedding.test.js +82 -0
- package/dist/tests/embedding.test.js.map +1 -0
- package/dist/tests/engines/evaluation-engine.test.d.ts +1 -0
- package/dist/tests/engines/evaluation-engine.test.js +71 -0
- package/dist/tests/engines/evaluation-engine.test.js.map +1 -0
- package/dist/tests/engines/planning-engine.test.d.ts +1 -0
- package/dist/tests/engines/planning-engine.test.js +100 -0
- package/dist/tests/engines/planning-engine.test.js.map +1 -0
- package/dist/tests/engines/quality-gate.test.d.ts +1 -0
- package/dist/tests/engines/quality-gate.test.js +59 -0
- package/dist/tests/engines/quality-gate.test.js.map +1 -0
- package/dist/tests/engines/risk-engine.test.d.ts +1 -0
- package/dist/tests/engines/risk-engine.test.js +80 -0
- package/dist/tests/engines/risk-engine.test.js.map +1 -0
- package/dist/tests/engines/routing-engine.test.d.ts +1 -0
- package/dist/tests/engines/routing-engine.test.js +78 -0
- package/dist/tests/engines/routing-engine.test.js.map +1 -0
- package/dist/tests/integration/hermes_locking.test.js +1 -0
- package/dist/tests/integration/hermes_locking.test.js.map +1 -1
- package/dist/tests/modules/engines/agent-executor.test.js +1 -1
- package/dist/tests/modules/engines/agent-executor.test.js.map +1 -1
- package/dist/tests/modules/gateway/cost-tracker.test.js +20 -1
- package/dist/tests/modules/gateway/cost-tracker.test.js.map +1 -1
- package/dist/tests/shared/lock.test.d.ts +1 -0
- package/dist/tests/shared/lock.test.js +95 -0
- package/dist/tests/shared/lock.test.js.map +1 -0
- package/dist/tests/shared/pii.test.d.ts +1 -0
- package/dist/tests/shared/pii.test.js +183 -0
- package/dist/tests/shared/pii.test.js.map +1 -0
- package/framework-mcp/README.md +307 -35
- package/framework-mcp/dist/dashboard/assets/index-B_rK57vi.js +1221 -0
- package/framework-mcp/dist/dashboard/index.html +1 -1
- package/framework-mcp/dist/framework-mcp/src/index.js +988 -63
- package/framework-mcp/dist/framework-mcp/src/tools/compliance/mask_pii.js +55 -0
- package/framework-mcp/dist/framework-mcp/src/tools/definitions.js +10 -9
- package/framework-mcp/dist/framework-mcp/src/tools/framework/run_tests.js +25 -0
- package/framework-mcp/dist/framework-mcp/src/tools/index.js +7 -8
- package/framework-mcp/dist/framework-mcp/src/tools/messaging/approve_operation.js +80 -0
- package/framework-mcp/dist/framework-mcp/src/tools/messaging/ask_human.js +89 -20
- package/framework-mcp/dist/framework-mcp/src/tools/observability/check_ports.js +24 -8
- package/framework-mcp/dist/framework-mcp/src/tools/quality/analyze_code_quality.js +13 -64
- package/framework-mcp/dist/framework-mcp/src/tools/schemas.js +18 -22
- package/framework-mcp/dist/framework-mcp/src/tools/shell/run_command.js +146 -90
- package/framework-mcp/dist/framework-mcp/src/tools/types.js +1 -0
- package/framework-mcp/dist/framework-mcp/src/utils/auth.js +78 -0
- package/framework-mcp/dist/framework-mcp/src/utils/auto-rollback.js +265 -0
- package/framework-mcp/dist/framework-mcp/src/utils/compliance.js +12 -4
- package/framework-mcp/dist/framework-mcp/src/utils/context-optimizer.js +156 -0
- package/framework-mcp/dist/framework-mcp/src/utils/discipline.js +217 -0
- package/framework-mcp/dist/framework-mcp/src/utils/finops.js +325 -0
- package/framework-mcp/dist/framework-mcp/src/utils/human-in-loop.js +215 -0
- package/framework-mcp/dist/framework-mcp/src/utils/license-scanner.js +283 -0
- package/framework-mcp/dist/framework-mcp/src/utils/loop-detector.js +361 -0
- package/framework-mcp/dist/framework-mcp/src/utils/quality.js +124 -0
- package/framework-mcp/dist/framework-mcp/src/utils/rules-engine.js +231 -0
- package/framework-mcp/dist/framework-mcp/src/utils/silent-router.js +154 -0
- package/framework-mcp/dist/framework-mcp/src/utils/storage.js +2 -2
- package/framework-mcp/dist/framework-mcp/src/utils/telemetry-streamer.js +396 -0
- package/framework-mcp/dist/src/cli/platforms/core.js +72 -0
- package/framework-mcp/dist/src/cli/platforms/index.js +5 -0
- package/framework-mcp/dist/src/cli/platforms/paths.js +101 -0
- package/framework-mcp/dist/src/cli/platforms/scaffold.js +72 -0
- package/framework-mcp/dist/src/cli/platforms/utils.js +75 -0
- package/framework-mcp/dist/src/cli/utils/claude.js +57 -0
- package/framework-mcp/dist/src/cli/utils/compliance.js +12 -0
- package/framework-mcp/dist/src/cli/utils/fs.js +138 -0
- package/framework-mcp/dist/src/cli/utils/pkg.js +282 -0
- package/framework-mcp/dist/src/cli/utils/quality.js +9 -0
- package/framework-mcp/dist/src/modules/agents/definitions.js +563 -0
- package/framework-mcp/dist/src/modules/agents/registry/analyst.js +39 -0
- package/framework-mcp/dist/src/modules/agents/registry/architect.js +42 -0
- package/framework-mcp/dist/src/modules/agents/registry/backend.js +50 -0
- package/framework-mcp/dist/src/modules/agents/registry/database.js +45 -0
- package/framework-mcp/dist/src/modules/agents/registry/devops.js +45 -0
- package/framework-mcp/dist/src/modules/agents/registry/explorer.js +37 -0
- package/framework-mcp/dist/src/modules/agents/registry/frontend.js +52 -0
- package/framework-mcp/dist/src/modules/agents/registry/git.js +36 -0
- package/framework-mcp/dist/src/modules/agents/registry/manager.js +64 -0
- package/framework-mcp/dist/src/modules/agents/registry/mobile.js +41 -0
- package/framework-mcp/dist/src/modules/agents/registry/native.js +41 -0
- package/framework-mcp/dist/src/modules/agents/registry/quality.js +43 -0
- package/framework-mcp/dist/src/modules/agents/registry/security.js +42 -0
- package/framework-mcp/dist/src/modules/agents/types.js +1 -0
- package/framework-mcp/dist/src/modules/engines/evaluation-engine.js +169 -0
- package/framework-mcp/dist/src/modules/engines/quality-gate.js +92 -0
- package/framework-mcp/dist/src/modules/engines/risk-engine.js +105 -0
- package/framework-mcp/dist/src/modules/engines/routing-engine.js +408 -0
- package/framework-mcp/dist/src/modules/engines/types.js +1 -0
- package/framework-mcp/dist/src/modules/providers/definitions.js +140 -0
- package/framework-mcp/dist/src/modules/providers/registry.js +18 -0
- package/framework-mcp/dist/src/modules/providers/shared.js +104 -0
- package/framework-mcp/dist/src/modules/providers/types.js +1 -0
- package/framework-mcp/dist/src/modules/skills/adapter-skills.js +449 -0
- package/framework-mcp/dist/src/modules/skills/definitions.js +70 -0
- package/framework-mcp/dist/src/shared/audit.js +220 -0
- package/framework-mcp/dist/src/shared/errors.js +68 -0
- package/framework-mcp/dist/src/shared/lock.js +159 -0
- package/framework-mcp/dist/src/shared/pii.js +122 -31
- package/framework-mcp/dist/src/shared/retention.js +170 -0
- package/framework-mcp/dist/src/shared/storage.js +47 -7
- package/framework-mcp/dist/src/shared/string.js +29 -0
- package/framework-mcp/package.json +8 -2
- package/mcp.json +12 -6
- package/package.json +11 -5
- package/templates/full/ATABEY_FULL.md +1 -1
- package/framework-mcp/dist/dashboard/assets/index-BAPGLiWE.js +0 -267
|
@@ -0,0 +1,220 @@
|
|
|
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 { maskObject, maskText } from "./pii.js";
|
|
17
|
+
import { Storage } from "./storage.js";
|
|
18
|
+
import { logger } from "./logger.js";
|
|
19
|
+
export class Audit {
|
|
20
|
+
static TABLE = "audit_log";
|
|
21
|
+
/** [KVKK] Default data retention period: 30 days */
|
|
22
|
+
static DEFAULT_RETENTION_DAYS = parseInt(process.env.ATABEY_DATA_RETENTION_DAYS || "30", 10);
|
|
23
|
+
/** [KVKK] Maximum retention for sensitive categories: 90 days */
|
|
24
|
+
static MAX_RETENTION_DAYS = 90;
|
|
25
|
+
static initialize() {
|
|
26
|
+
const db = Storage.getDB();
|
|
27
|
+
db.exec(`
|
|
28
|
+
CREATE TABLE IF NOT EXISTS ${this.TABLE} (
|
|
29
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
30
|
+
timestamp TEXT NOT NULL,
|
|
31
|
+
action TEXT NOT NULL,
|
|
32
|
+
status TEXT NOT NULL,
|
|
33
|
+
agent TEXT NOT NULL,
|
|
34
|
+
traceId TEXT,
|
|
35
|
+
details TEXT,
|
|
36
|
+
errorMessage TEXT,
|
|
37
|
+
durationMs INTEGER,
|
|
38
|
+
dataCategory TEXT DEFAULT 'OPERATIONAL',
|
|
39
|
+
retentionDays INTEGER DEFAULT ${this.DEFAULT_RETENTION_DAYS}
|
|
40
|
+
)
|
|
41
|
+
`);
|
|
42
|
+
// Indexes for performance
|
|
43
|
+
db.exec(`
|
|
44
|
+
CREATE INDEX IF NOT EXISTS idx_audit_action ON ${this.TABLE}(action);
|
|
45
|
+
CREATE INDEX IF NOT EXISTS idx_audit_status ON ${this.TABLE}(status);
|
|
46
|
+
CREATE INDEX IF NOT EXISTS idx_audit_trace ON ${this.TABLE}(traceId);
|
|
47
|
+
CREATE INDEX IF NOT EXISTS idx_audit_timestamp ON ${this.TABLE}(timestamp);
|
|
48
|
+
CREATE INDEX IF NOT EXISTS idx_audit_category ON ${this.TABLE}(dataCategory);
|
|
49
|
+
`);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Logs a structured audit entry.
|
|
53
|
+
* [KVKK] Sensitive data is automatically masked.
|
|
54
|
+
*/
|
|
55
|
+
static log(action, status, options = {}) {
|
|
56
|
+
const db = Storage.getDB();
|
|
57
|
+
const retentionDays = Math.min(options.retentionDays || this.DEFAULT_RETENTION_DAYS, this.MAX_RETENTION_DAYS);
|
|
58
|
+
// [KVKK] PII Masking — mask sensitive data in the details field
|
|
59
|
+
const maskedDetails = options.details
|
|
60
|
+
? maskObject(options.details)
|
|
61
|
+
: undefined;
|
|
62
|
+
const maskedError = options.errorMessage
|
|
63
|
+
? maskText(options.errorMessage)
|
|
64
|
+
: undefined;
|
|
65
|
+
const entry = {
|
|
66
|
+
timestamp: new Date().toISOString(),
|
|
67
|
+
action,
|
|
68
|
+
status,
|
|
69
|
+
agent: options.agent || "@manager",
|
|
70
|
+
traceId: options.traceId,
|
|
71
|
+
details: maskedDetails,
|
|
72
|
+
errorMessage: maskedError,
|
|
73
|
+
durationMs: options.durationMs,
|
|
74
|
+
dataCategory: options.dataCategory || "OPERATIONAL",
|
|
75
|
+
retentionDays,
|
|
76
|
+
};
|
|
77
|
+
db.prepare(`
|
|
78
|
+
INSERT INTO ${this.TABLE}
|
|
79
|
+
(timestamp, action, status, agent, traceId, details, errorMessage, durationMs, dataCategory, retentionDays)
|
|
80
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
81
|
+
`).run(entry.timestamp, entry.action, entry.status, entry.agent, entry.traceId || null, entry.details ? JSON.stringify(entry.details) : null, entry.errorMessage || null, entry.durationMs || null, entry.dataCategory, entry.retentionDays);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Queries audit logs with filters.
|
|
85
|
+
*/
|
|
86
|
+
static query(options = {}) {
|
|
87
|
+
const db = Storage.getDB();
|
|
88
|
+
const conditions = [];
|
|
89
|
+
const params = [];
|
|
90
|
+
if (options.action) {
|
|
91
|
+
conditions.push("action = ?");
|
|
92
|
+
params.push(options.action);
|
|
93
|
+
}
|
|
94
|
+
if (options.status) {
|
|
95
|
+
conditions.push("status = ?");
|
|
96
|
+
params.push(options.status);
|
|
97
|
+
}
|
|
98
|
+
if (options.agent) {
|
|
99
|
+
conditions.push("agent = ?");
|
|
100
|
+
params.push(options.agent);
|
|
101
|
+
}
|
|
102
|
+
if (options.traceId) {
|
|
103
|
+
conditions.push("traceId = ?");
|
|
104
|
+
params.push(options.traceId);
|
|
105
|
+
}
|
|
106
|
+
if (options.dataCategory) {
|
|
107
|
+
conditions.push("dataCategory = ?");
|
|
108
|
+
params.push(options.dataCategory);
|
|
109
|
+
}
|
|
110
|
+
if (options.since) {
|
|
111
|
+
conditions.push("timestamp >= ?");
|
|
112
|
+
params.push(options.since);
|
|
113
|
+
}
|
|
114
|
+
if (options.until) {
|
|
115
|
+
conditions.push("timestamp <= ?");
|
|
116
|
+
params.push(options.until);
|
|
117
|
+
}
|
|
118
|
+
const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
119
|
+
const limit = options.limit || 50;
|
|
120
|
+
const offset = options.offset || 0;
|
|
121
|
+
const rows = db.prepare(`SELECT * FROM ${this.TABLE} ${where} ORDER BY timestamp DESC LIMIT ? OFFSET ?`).all(...params, limit, offset);
|
|
122
|
+
return rows.map(row => ({
|
|
123
|
+
...row,
|
|
124
|
+
details: row.details ? JSON.parse(row.details) : undefined,
|
|
125
|
+
}));
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* [KVKK Art. 11] Deletes records upon data subject request.
|
|
129
|
+
* Clears all records matching a given traceId or agent.
|
|
130
|
+
*
|
|
131
|
+
* @param filter Which records to delete
|
|
132
|
+
* @returns Number of deleted records
|
|
133
|
+
*/
|
|
134
|
+
static deleteByFilter(filter) {
|
|
135
|
+
const db = Storage.getDB();
|
|
136
|
+
const conditions = [];
|
|
137
|
+
const params = [];
|
|
138
|
+
if (filter.traceId) {
|
|
139
|
+
conditions.push("traceId = ?");
|
|
140
|
+
params.push(filter.traceId);
|
|
141
|
+
}
|
|
142
|
+
if (filter.agent) {
|
|
143
|
+
conditions.push("agent = ?");
|
|
144
|
+
params.push(filter.agent);
|
|
145
|
+
}
|
|
146
|
+
if (filter.action) {
|
|
147
|
+
conditions.push("action = ?");
|
|
148
|
+
params.push(filter.action);
|
|
149
|
+
}
|
|
150
|
+
if (filter.olderThanDays) {
|
|
151
|
+
conditions.push("timestamp < datetime('now', ? || ' days')");
|
|
152
|
+
params.push(`-${filter.olderThanDays}`);
|
|
153
|
+
}
|
|
154
|
+
if (conditions.length === 0)
|
|
155
|
+
return 0;
|
|
156
|
+
const result = db.prepare(`DELETE FROM ${this.TABLE} WHERE ${conditions.join(" AND ")}`).run(...params);
|
|
157
|
+
return result.changes;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* [KVKK/GDPR] Cleans expired records.
|
|
161
|
+
* Operates based on each audit record's retentionDays field.
|
|
162
|
+
* Can be auto-triggered by cron job or each Audit.log() call.
|
|
163
|
+
*
|
|
164
|
+
* @returns Number of cleaned records
|
|
165
|
+
*/
|
|
166
|
+
static cleanExpired() {
|
|
167
|
+
const db = Storage.getDB();
|
|
168
|
+
const result = db.prepare(`
|
|
169
|
+
DELETE FROM ${this.TABLE}
|
|
170
|
+
WHERE retentionDays IS NOT NULL
|
|
171
|
+
AND timestamp < datetime('now', '-' || retentionDays || ' days')
|
|
172
|
+
`).run();
|
|
173
|
+
if (result.changes > 0) {
|
|
174
|
+
logger.info(`[AUDIT] Expired records cleaned: ${result.changes}`);
|
|
175
|
+
}
|
|
176
|
+
return result.changes;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Returns audit statistics.
|
|
180
|
+
*/
|
|
181
|
+
static getStats() {
|
|
182
|
+
const db = Storage.getDB();
|
|
183
|
+
this.cleanExpired();
|
|
184
|
+
const total = db.prepare(`SELECT COUNT(*) as count FROM ${this.TABLE}`).get().count;
|
|
185
|
+
const byStatusRows = db.prepare(`SELECT status, COUNT(*) as count FROM ${this.TABLE} GROUP BY status`).all();
|
|
186
|
+
const byActionRows = db.prepare(`SELECT action, COUNT(*) as count FROM ${this.TABLE} GROUP BY action ORDER BY count DESC LIMIT 10`).all();
|
|
187
|
+
const byCategoryRows = db.prepare(`SELECT dataCategory, COUNT(*) as count FROM ${this.TABLE} GROUP BY dataCategory`).all();
|
|
188
|
+
const errors = db.prepare(`SELECT * FROM ${this.TABLE} WHERE status IN ('FAILED', 'BLOCKED') ORDER BY timestamp DESC LIMIT 10`).all();
|
|
189
|
+
const expiredCount = db.prepare(`
|
|
190
|
+
SELECT COUNT(*) as count FROM ${this.TABLE}
|
|
191
|
+
WHERE retentionDays IS NOT NULL
|
|
192
|
+
AND timestamp < datetime('now', '-' || retentionDays || ' days')
|
|
193
|
+
`).get().count;
|
|
194
|
+
return {
|
|
195
|
+
total,
|
|
196
|
+
byStatus: Object.fromEntries(byStatusRows.map(r => [r.status, r.count])),
|
|
197
|
+
byAction: Object.fromEntries(byActionRows.map(r => [r.action, r.count])),
|
|
198
|
+
byCategory: Object.fromEntries(byCategoryRows.map(r => [r.dataCategory, r.count])),
|
|
199
|
+
recentErrors: errors.map(row => ({
|
|
200
|
+
...row,
|
|
201
|
+
details: row.details ? JSON.parse(row.details) : undefined,
|
|
202
|
+
})),
|
|
203
|
+
expiredCount,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* [KVKK Art. 7] Clears all audit records.
|
|
208
|
+
* Used under the "Right to Erasure" provision.
|
|
209
|
+
* Only authorized users may call this.
|
|
210
|
+
*/
|
|
211
|
+
static clearAll(confirmationCode) {
|
|
212
|
+
if (confirmationCode !== "KVKK-RIGHT-TO-ERASURE") {
|
|
213
|
+
throw new Error("[AUDIT] Invalid confirmation code for data erasure");
|
|
214
|
+
}
|
|
215
|
+
const db = Storage.getDB();
|
|
216
|
+
const result = db.prepare(`DELETE FROM ${this.TABLE}`).run();
|
|
217
|
+
logger.info(`[AUDIT] All records cleared (${result.changes} records). KVKK Article 7 compliance.`);
|
|
218
|
+
return result.changes;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enterprise Base Error class for the Agent Atabey Framework.
|
|
3
|
+
*/
|
|
4
|
+
export class AtabeyBaseError extends Error {
|
|
5
|
+
code;
|
|
6
|
+
timestamp;
|
|
7
|
+
details;
|
|
8
|
+
solution;
|
|
9
|
+
constructor(message, code = "ATABEY_INTERNAL_ERROR", details, solution) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.name = this.constructor.name;
|
|
12
|
+
this.code = code;
|
|
13
|
+
this.timestamp = new Date();
|
|
14
|
+
this.details = details;
|
|
15
|
+
this.solution = solution;
|
|
16
|
+
// Ensure proper prototype chain and capture stack trace
|
|
17
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
18
|
+
if (Error.captureStackTrace) {
|
|
19
|
+
Error.captureStackTrace(this, this.constructor);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Converts the error into a structured JSON log format.
|
|
24
|
+
*/
|
|
25
|
+
toJSON() {
|
|
26
|
+
return {
|
|
27
|
+
name: this.name,
|
|
28
|
+
message: this.message,
|
|
29
|
+
code: this.code,
|
|
30
|
+
timestamp: this.timestamp.toISOString(),
|
|
31
|
+
details: this.details,
|
|
32
|
+
solution: this.solution,
|
|
33
|
+
stack: this.stack,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Thrown when configuration loading or validation fails.
|
|
39
|
+
*/
|
|
40
|
+
export class ConfigurationError extends AtabeyBaseError {
|
|
41
|
+
constructor(message, details, solution) {
|
|
42
|
+
super(message, "CONFIGURATION_ERROR", details, solution);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Thrown when data schema or payload validation fails.
|
|
47
|
+
*/
|
|
48
|
+
export class ValidationError extends AtabeyBaseError {
|
|
49
|
+
constructor(message, details, solution) {
|
|
50
|
+
super(message, "VALIDATION_ERROR", details, solution);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Thrown when adapter initialization or execution fails.
|
|
55
|
+
*/
|
|
56
|
+
export class AdapterError extends AtabeyBaseError {
|
|
57
|
+
constructor(message, adapterId, details, solution) {
|
|
58
|
+
super(`Adapter '${adapterId}' failure: ${message}`, "ADAPTER_ERROR", details, solution);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Thrown when orchestration or agent communication fails.
|
|
63
|
+
*/
|
|
64
|
+
export class OrchestrationError extends AtabeyBaseError {
|
|
65
|
+
constructor(message, details, solution) {
|
|
66
|
+
super(message, "ORCHESTRATION_ERROR", details, solution);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* [LOCK] Multi-user Distributed Lock Mechanism
|
|
3
|
+
*
|
|
4
|
+
* Git-based lock system. Enables team members to work on the same
|
|
5
|
+
* files/resources without conflicts.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* const lock = new DistributedLock("database/schema.sql");
|
|
9
|
+
* if (lock.acquire("user-123", 60000)) {
|
|
10
|
+
* // Apply changes
|
|
11
|
+
* lock.release("user-123");
|
|
12
|
+
* }
|
|
13
|
+
*/
|
|
14
|
+
import { execSync } from "child_process";
|
|
15
|
+
import os from "os";
|
|
16
|
+
import { Storage } from "./storage.js";
|
|
17
|
+
export class DistributedLock {
|
|
18
|
+
static TABLE = "distributed_locks";
|
|
19
|
+
/**
|
|
20
|
+
* Initialize the locks table (run once at startup).
|
|
21
|
+
*/
|
|
22
|
+
static initialize() {
|
|
23
|
+
const db = Storage.getDB();
|
|
24
|
+
db.exec(`
|
|
25
|
+
CREATE TABLE IF NOT EXISTS ${this.TABLE} (
|
|
26
|
+
resource TEXT PRIMARY KEY,
|
|
27
|
+
ownerId TEXT NOT NULL,
|
|
28
|
+
ownerName TEXT NOT NULL,
|
|
29
|
+
acquiredAt TEXT NOT NULL,
|
|
30
|
+
expiresAt TEXT NOT NULL,
|
|
31
|
+
reason TEXT,
|
|
32
|
+
traceId TEXT
|
|
33
|
+
)
|
|
34
|
+
`);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Attempts to acquire a lock on a resource.
|
|
38
|
+
*
|
|
39
|
+
* @param resource - Lock resource name (e.g., "apps/backend/src/types/user.ts")
|
|
40
|
+
* @param ownerId - Unique owner identifier (e.g., "yusuf", "ci-bot-01")
|
|
41
|
+
* @param options - Optional parameters
|
|
42
|
+
* @returns true if lock acquired, false if already locked
|
|
43
|
+
*/
|
|
44
|
+
static acquire(resource, ownerId, options = {}) {
|
|
45
|
+
const db = Storage.getDB();
|
|
46
|
+
const now = new Date();
|
|
47
|
+
const expiresAt = new Date(now.getTime() + (options.ttlMs || 60000)).toISOString();
|
|
48
|
+
const ownerName = options.ownerName || ownerId;
|
|
49
|
+
const reason = options.reason || "No reason provided";
|
|
50
|
+
// Clean up stale locks first
|
|
51
|
+
this.releaseStaleLocks();
|
|
52
|
+
// Check current lock status
|
|
53
|
+
const existing = db.prepare(`SELECT * FROM ${this.TABLE} WHERE resource = ?`).get(resource);
|
|
54
|
+
if (existing) {
|
|
55
|
+
// If force=true, override existing lock
|
|
56
|
+
if (options.force) {
|
|
57
|
+
db.prepare(`
|
|
58
|
+
INSERT OR REPLACE INTO ${this.TABLE} (resource, ownerId, ownerName, acquiredAt, expiresAt, reason, traceId)
|
|
59
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
60
|
+
`).run(resource, ownerId, ownerName, now.toISOString(), expiresAt, reason, options.traceId || null);
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
return false; // Already locked
|
|
64
|
+
}
|
|
65
|
+
// Acquire new lock
|
|
66
|
+
db.prepare(`
|
|
67
|
+
INSERT INTO ${this.TABLE} (resource, ownerId, ownerName, acquiredAt, expiresAt, reason, traceId)
|
|
68
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
69
|
+
`).run(resource, ownerId, ownerName, now.toISOString(), expiresAt, reason, options.traceId || null);
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Releases a lock. Only the lock owner can release.
|
|
74
|
+
*
|
|
75
|
+
* @param resource - Lock resource name
|
|
76
|
+
* @param ownerId - Owner identifier for verification
|
|
77
|
+
* @returns true if released successfully
|
|
78
|
+
*/
|
|
79
|
+
static release(resource, ownerId) {
|
|
80
|
+
const db = Storage.getDB();
|
|
81
|
+
const result = db.prepare(`DELETE FROM ${this.TABLE} WHERE resource = ? AND ownerId = ?`).run(resource, ownerId);
|
|
82
|
+
return result.changes > 0;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Checks if a resource is locked.
|
|
86
|
+
*/
|
|
87
|
+
static isLocked(resource) {
|
|
88
|
+
const db = Storage.getDB();
|
|
89
|
+
const lock = db.prepare(`SELECT * FROM ${this.TABLE} WHERE resource = ? AND expiresAt > datetime('now')`).get(resource);
|
|
90
|
+
return !!lock;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Gets lock information for a resource.
|
|
94
|
+
*/
|
|
95
|
+
static getLock(resource) {
|
|
96
|
+
const db = Storage.getDB();
|
|
97
|
+
this.releaseStaleLocks();
|
|
98
|
+
const lock = db.prepare(`SELECT * FROM ${this.TABLE} WHERE resource = ?`).get(resource);
|
|
99
|
+
return lock || null;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Lists all active locks.
|
|
103
|
+
*/
|
|
104
|
+
static listActiveLocks() {
|
|
105
|
+
const db = Storage.getDB();
|
|
106
|
+
this.releaseStaleLocks();
|
|
107
|
+
return db.prepare(`SELECT * FROM ${this.TABLE} WHERE expiresAt > datetime('now') ORDER BY acquiredAt DESC`).all();
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Lists all locks owned by a specific owner.
|
|
111
|
+
*/
|
|
112
|
+
static listOwnerLocks(ownerId) {
|
|
113
|
+
const db = Storage.getDB();
|
|
114
|
+
return db.prepare(`SELECT * FROM ${this.TABLE} WHERE ownerId = ? ORDER BY acquiredAt DESC`).all(ownerId);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Releases all locks owned by a specific owner (e.g., on disconnect).
|
|
118
|
+
*/
|
|
119
|
+
static releaseAllByOwner(ownerId) {
|
|
120
|
+
const db = Storage.getDB();
|
|
121
|
+
const result = db.prepare(`DELETE FROM ${this.TABLE} WHERE ownerId = ?`).run(ownerId);
|
|
122
|
+
return result.changes;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Releases all expired/stale locks.
|
|
126
|
+
*/
|
|
127
|
+
static releaseStaleLocks() {
|
|
128
|
+
const db = Storage.getDB();
|
|
129
|
+
const result = db.prepare(`DELETE FROM ${this.TABLE} WHERE expiresAt < datetime('now')`).run();
|
|
130
|
+
return result.changes;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Generates a unique owner ID for the current user/machine.
|
|
134
|
+
* Uses git config user.name or hostname as fallback.
|
|
135
|
+
*/
|
|
136
|
+
static getLocalOwnerId() {
|
|
137
|
+
// Try git config
|
|
138
|
+
try {
|
|
139
|
+
const name = execSync("git config user.name", { encoding: "utf8" }).trim();
|
|
140
|
+
if (name)
|
|
141
|
+
return name;
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
// Fallback
|
|
145
|
+
}
|
|
146
|
+
// Try environment
|
|
147
|
+
if (process.env.USER)
|
|
148
|
+
return process.env.USER;
|
|
149
|
+
if (process.env.USERNAME)
|
|
150
|
+
return process.env.USERNAME;
|
|
151
|
+
// Fallback to hostname
|
|
152
|
+
try {
|
|
153
|
+
return os.hostname();
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
return "unknown-user";
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
@@ -2,46 +2,79 @@
|
|
|
2
2
|
* [PII] Personally Identifiable Information Masking Service
|
|
3
3
|
*
|
|
4
4
|
* Detects and masks sensitive data in compliance with KVKK/GDPR.
|
|
5
|
-
* Used in audit log, logger, and
|
|
5
|
+
* Used in audit log, logger, storage layers, and MCP middleware.
|
|
6
6
|
*
|
|
7
7
|
* Supported patterns:
|
|
8
8
|
* - Email addresses
|
|
9
|
-
* - Phone numbers
|
|
10
|
-
* - TC Identification number
|
|
11
|
-
* - API keys / tokens
|
|
12
|
-
* -
|
|
13
|
-
* -
|
|
14
|
-
* -
|
|
9
|
+
* - Phone numbers (international, Turkish, US, UK)
|
|
10
|
+
* - TC Identification number (11 digits)
|
|
11
|
+
* - API keys / tokens (OpenAI, Anthropic, Google, GitHub, generic)
|
|
12
|
+
* - Bearer tokens / JWTs
|
|
13
|
+
* - IP addresses (IPv4, IPv6)
|
|
14
|
+
* - Credit card numbers (AMEX, Visa, Mastercard, etc.)
|
|
15
|
+
* - Password / secret fields in structured data
|
|
16
|
+
* - Bank account / IBAN
|
|
17
|
+
* - Date of birth / full address patterns
|
|
18
|
+
* - Custom names (configurable)
|
|
15
19
|
*/
|
|
16
20
|
// Sensitive patterns to detect and mask
|
|
21
|
+
// IMPORTANT: More specific patterns MUST come before generic ones
|
|
17
22
|
const SENSITIVE_PATTERNS = [
|
|
23
|
+
// JWT tokens (complete JWT format) - must be before Bearer
|
|
24
|
+
{ pattern: /eyJ[a-zA-Z0-9_-]+\.eyJ[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+/g, replacement: "***-JWT-REDACTED-***" },
|
|
25
|
+
// Bearer tokens in Authorization headers
|
|
26
|
+
{ pattern: /Bearer\s+[a-zA-Z0-9._-]+/g, replacement: "Bearer ***-REDACTED-***" },
|
|
27
|
+
// Basic auth in Authorization headers
|
|
28
|
+
{ pattern: /Basic\s+[a-zA-Z0-9=+/]+/g, replacement: "Basic ***-REDACTED-***" },
|
|
29
|
+
// API keys (common formats) - must be before generic patterns
|
|
30
|
+
// Note: ghp_ tokens can contain digits that look like phone numbers, so we mask the entire prefix + suffix
|
|
31
|
+
{ pattern: /\b(sk-[a-zA-Z0-9]{20,}|pk-[a-zA-Z0-9]{20,}|xai-[a-zA-Z0-9]{20,}|AIza[0-9A-Za-z_-]{35}|ghp_[a-zA-Z0-9]{36,}|gho_[a-zA-Z0-9]{36,}|ghu_[a-zA-Z0-9]{36,}|ghb_[a-zA-Z0-9]{36,}|github_pat_[a-zA-Z0-9]{36,}|sk-[a-zA-Z0-9_-]{32,}|sk-[a-zA-Z0-9]{48,}|whsec_[a-zA-Z0-9]{16,})\b/g, replacement: "***-REDACTED-***" },
|
|
32
|
+
// Social Security Number (US SSN: XXX-XX-XXXX) - must be before generic phone
|
|
33
|
+
{ pattern: /\b(?!000|666|9[0-9]{2})\d{3}-(?!00)\d{2}-(?!0000)\d{4}\b/g, replacement: "***-**-****" },
|
|
34
|
+
// Date of birth patterns - must be before generic phone
|
|
35
|
+
{ pattern: /\b(0[1-9]|[12][0-9]|3[01])[/.-](0[1-9]|1[0-2])[/.-](19[0-9]{2}|20[0-9]{2})\b/g, replacement: "**/**/****" },
|
|
36
|
+
// IBAN (international bank account) - must be before generic alphanumeric patterns
|
|
37
|
+
// Only matches valid IBAN format: 2 letters + 2 digits + 4-30 alphanumeric chars
|
|
38
|
+
// More specific: requires minimum 8 chars total, starts with country code
|
|
39
|
+
{ pattern: /\b[A-Z]{2}[0-9]{2}[A-Z0-9]{4,30}\b/g, replacement: "****-IBAN-REDACTED-****" },
|
|
40
|
+
// TC Kimlik (11 digits starting with 1-9, isolated word boundary) - must be before phone
|
|
41
|
+
{ pattern: /\b[1-9][0-9]{10}\b/g, replacement: "***********" },
|
|
18
42
|
// Email
|
|
19
43
|
{ pattern: /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g, replacement: "***@***" },
|
|
20
|
-
// Phone (
|
|
44
|
+
// Phone (Turkish: +90 5xx xxx xx xx) - specific before generic
|
|
21
45
|
{ pattern: /(\+90|0)?\s?[0-9]{3}\s?[0-9]{3}\s?[0-9]{2}\s?[0-9]{2}/g, replacement: "***-***-****" },
|
|
22
|
-
//
|
|
23
|
-
{ pattern:
|
|
24
|
-
//
|
|
25
|
-
{ pattern: /\b(sk-[a-zA-Z0-9]{20,}|pk-[a-zA-Z0-9]{20,}|xai-[a-zA-Z0-9]{20,}|AIza[0-9A-Za-z_-]{35}|ghp_[a-zA-Z0-9]{36,}|gho_[a-zA-Z0-9]{36,})\b/g, replacement: "***-REDACTED-***" },
|
|
26
|
-
// Bearer tokens in Authorization headers
|
|
27
|
-
{ pattern: /Bearer\s+[a-zA-Z0-9._-]+/g, replacement: "Bearer ***-REDACTED-***" },
|
|
28
|
-
// IP addresses
|
|
46
|
+
// Phone (international: +90, +1, +44, +49, +33, etc.) - generic, keep last among phones
|
|
47
|
+
{ pattern: /(\+\d{1,2}[\s-]?)?\(?\d{2,4}\)?[\s-]?\d{2,4}[\s-]?\d{2,4}[\s-]?\d{2,4}/g, replacement: "***-***-****" },
|
|
48
|
+
// IP addresses (IPv4)
|
|
29
49
|
{ pattern: /\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b/g, replacement: "***.***.***.***" },
|
|
50
|
+
// IP addresses (IPv6 - simplified)
|
|
51
|
+
{ pattern: /\b(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}\b/g, replacement: "****:****:****:****" },
|
|
52
|
+
// IPv6 compressed
|
|
53
|
+
{ pattern: /\b(?:[0-9a-fA-F]{0,4}:){2,7}[0-9a-fA-F]{0,4}\b/g, replacement: "****:****:****" },
|
|
30
54
|
// Credit card (16 digits, optional spaces/dashes)
|
|
31
55
|
{ pattern: /\b(?:\d[ -]*?){13,16}\b/g, replacement: "****-****-****-****" },
|
|
32
|
-
//
|
|
33
|
-
{ pattern:
|
|
56
|
+
// AMEX (15 digits, starts with 34/37)
|
|
57
|
+
{ pattern: /\b3[47][0-9\s-]{13,14}\b/g, replacement: "****-****-***" },
|
|
34
58
|
// Password fields in JSON
|
|
35
|
-
{ pattern: /"(password|passwd|secret|api_key|apiKey|apikey)"\s*:\s*"[^"]+"/gi, replacement: "\"$1\": \"***-REDACTED-***\"" },
|
|
59
|
+
{ pattern: /"(password|passwd|secret|api_key|apiKey|apikey|auth_token|refresh_token|access_token)"\s*:\s*"[^"]+"/gi, replacement: "\"$1\": \"***-REDACTED-***\"" },
|
|
60
|
+
// Turkish address patterns (optional - sokak, cadde, mahalle, no:)
|
|
61
|
+
{ pattern: /(?:no|no:|numara)[:\s]*\d+/gi, replacement: "no: ****" },
|
|
36
62
|
];
|
|
37
63
|
// Fields that are considered sensitive and should always be redacted in structured data
|
|
38
64
|
const SENSITIVE_FIELDS = [
|
|
39
65
|
"password", "passwd", "secret", "apiKey", "api_key", "apikey",
|
|
40
|
-
"token", "accessToken", "refreshToken", "authToken",
|
|
41
|
-
"authorization", "Authorization",
|
|
42
|
-
"email", "
|
|
43
|
-
"
|
|
44
|
-
"
|
|
66
|
+
"token", "accessToken", "access_token", "refreshToken", "refresh_token", "authToken", "auth_token",
|
|
67
|
+
"authorization", "Authorization", "bearer",
|
|
68
|
+
"email", "e_mail", "eMail",
|
|
69
|
+
"phone", "phoneNumber", "phone_number", "telephone", "telephoneNumber", "mobile", "mobilePhone", "cellPhone",
|
|
70
|
+
"creditCard", "credit_card", "ccNumber", "cc_number", "ccn", "cvv", "cvv2", "cvc",
|
|
71
|
+
"ssn", "socialSecurity", "social_security",
|
|
72
|
+
"tcKimlik", "tc_kimlik", "identityNumber", "identity_number", "idNumber", "id_number", "nationalId",
|
|
73
|
+
"ipAddress", "ip_address", "ip",
|
|
74
|
+
"dob", "dateOfBirth", "date_of_birth", "birthDate", "birth_date",
|
|
75
|
+
"iban", "IBAN", "bankAccount", "bank_account",
|
|
76
|
+
"address", "homeAddress", "workAddress", "billingAddress", "shippingAddress",
|
|
77
|
+
"fullName", "firstName", "lastName", "surname", "middleName",
|
|
45
78
|
];
|
|
46
79
|
/**
|
|
47
80
|
* Mask sensitive data in a text string.
|
|
@@ -58,8 +91,10 @@ export function maskText(text) {
|
|
|
58
91
|
/**
|
|
59
92
|
* Recursively mask sensitive fields in an object.
|
|
60
93
|
* Returns a new object with sensitive values redacted.
|
|
94
|
+
* Strict mode: when true, also masks values in objects even if the key
|
|
95
|
+
* is not a known sensitive field name (catches data passed to unknown schemas).
|
|
61
96
|
*/
|
|
62
|
-
export function maskObject(obj, depth = 0) {
|
|
97
|
+
export function maskObject(obj, depth = 0, strictMode = false) {
|
|
63
98
|
if (depth > 10)
|
|
64
99
|
return obj; // Prevent infinite recursion
|
|
65
100
|
if (obj === null || obj === undefined)
|
|
@@ -69,19 +104,19 @@ export function maskObject(obj, depth = 0) {
|
|
|
69
104
|
if (typeof obj !== "object")
|
|
70
105
|
return obj;
|
|
71
106
|
if (Array.isArray(obj)) {
|
|
72
|
-
return obj.map(item => maskObject(item, depth + 1));
|
|
107
|
+
return obj.map(item => maskObject(item, depth + 1, strictMode));
|
|
73
108
|
}
|
|
74
109
|
const result = {};
|
|
75
110
|
for (const [key, value] of Object.entries(obj)) {
|
|
76
111
|
// Check if the key itself is a sensitive field
|
|
77
112
|
if (SENSITIVE_FIELDS.includes(key)) {
|
|
78
|
-
result[key] = typeof value === "string" ? "***-REDACTED-***" : maskObject(value, depth + 1);
|
|
113
|
+
result[key] = typeof value === "string" ? "***-REDACTED-***" : maskObject(value, depth + 1, strictMode);
|
|
79
114
|
}
|
|
80
115
|
else if (typeof value === "string") {
|
|
81
116
|
result[key] = maskText(value);
|
|
82
117
|
}
|
|
83
118
|
else if (typeof value === "object") {
|
|
84
|
-
result[key] = maskObject(value, depth + 1);
|
|
119
|
+
result[key] = maskObject(value, depth + 1, strictMode);
|
|
85
120
|
}
|
|
86
121
|
else {
|
|
87
122
|
result[key] = value;
|
|
@@ -100,22 +135,78 @@ export function containsPII(text) {
|
|
|
100
135
|
}
|
|
101
136
|
return false;
|
|
102
137
|
}
|
|
138
|
+
/**
|
|
139
|
+
* Check if an object contains PII in any of its string values (recursive).
|
|
140
|
+
*/
|
|
141
|
+
export function containsPIIInObject(obj, depth = 0) {
|
|
142
|
+
if (depth > 10)
|
|
143
|
+
return false;
|
|
144
|
+
if (obj === null || obj === undefined)
|
|
145
|
+
return false;
|
|
146
|
+
if (typeof obj === "string")
|
|
147
|
+
return containsPII(obj);
|
|
148
|
+
if (typeof obj !== "object")
|
|
149
|
+
return false;
|
|
150
|
+
if (Array.isArray(obj)) {
|
|
151
|
+
return obj.some(item => containsPIIInObject(item, depth + 1));
|
|
152
|
+
}
|
|
153
|
+
for (const [, value] of Object.entries(obj)) {
|
|
154
|
+
if (typeof value === "string") {
|
|
155
|
+
if (containsPII(value))
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
else if (typeof value === "object") {
|
|
159
|
+
if (containsPIIInObject(value, depth + 1))
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
103
165
|
/**
|
|
104
166
|
* Classify a piece of data based on content analysis.
|
|
105
167
|
*/
|
|
106
168
|
export function classifyData(text) {
|
|
107
169
|
if (!text)
|
|
108
170
|
return "public";
|
|
109
|
-
// Check for highly sensitive data
|
|
171
|
+
// Check for highly sensitive / critical data
|
|
110
172
|
if (/\b(sk-[a-zA-Z0-9]{20,}|Bearer\s+|eyJ[a-zA-Z0-9_-]+\.)/.test(text) ||
|
|
111
173
|
/\b[1-9][0-9]{10}\b/.test(text) ||
|
|
112
|
-
/"(password|secret|apiKey)"/i.test(text)
|
|
174
|
+
/"(password|secret|apiKey)"/i.test(text) ||
|
|
175
|
+
/\b[A-Z]{2}[0-9]{2}[A-Z0-9]{1,30}\b/.test(text) // IBAN
|
|
176
|
+
) {
|
|
113
177
|
return "restricted";
|
|
114
178
|
}
|
|
115
|
-
// Check for
|
|
179
|
+
// Check for personally identifiable / confidential data
|
|
116
180
|
if (/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/.test(text) ||
|
|
117
|
-
/(\+90|0)?\s?[0-9]{3}\s?[0-9]{3}\s?[0-9]{2}\s?[0-9]{2}/.test(text)
|
|
181
|
+
/(\+90|0)?\s?[0-9]{3}\s?[0-9]{3}\s?[0-9]{2}\s?[0-9]{2}/.test(text) ||
|
|
182
|
+
/\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b/.test(text) ||
|
|
183
|
+
/\b(0[1-9]|[12][0-9]|3[01])[/.-](0[1-9]|1[0-2])[/.-](19[0-9]{2}|20[0-9]{2})\b/.test(text)) {
|
|
118
184
|
return "confidential";
|
|
119
185
|
}
|
|
120
186
|
return "internal";
|
|
121
187
|
}
|
|
188
|
+
/**
|
|
189
|
+
* Mask the content field of an MCP tool result.
|
|
190
|
+
* This is used by the MCP middleware layer to automatically
|
|
191
|
+
* sanitize all tool outputs before they reach the AI.
|
|
192
|
+
*/
|
|
193
|
+
export function maskToolResult(result) {
|
|
194
|
+
if (!result || !result.content)
|
|
195
|
+
return result;
|
|
196
|
+
return {
|
|
197
|
+
...result,
|
|
198
|
+
content: result.content.map(block => ({
|
|
199
|
+
...block,
|
|
200
|
+
text: block.type === "text" ? maskText(block.text) : block.text,
|
|
201
|
+
})),
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Mask sensitive arguments in an MCP tool call.
|
|
206
|
+
* This is applied BEFORE the tool handler executes, ensuring
|
|
207
|
+
* PII never reaches any processing layer unnecessarily.
|
|
208
|
+
*/
|
|
209
|
+
export function maskToolArgs(args) {
|
|
210
|
+
const masked = maskObject(args, 0, true);
|
|
211
|
+
return masked;
|
|
212
|
+
}
|