@opentrust/db 7.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.
Files changed (83) hide show
  1. package/dist/client.d.ts +3 -0
  2. package/dist/client.d.ts.map +1 -0
  3. package/dist/client.js +51 -0
  4. package/dist/dialect.d.ts +3 -0
  5. package/dist/dialect.d.ts.map +1 -0
  6. package/dist/dialect.js +12 -0
  7. package/dist/generate.d.ts +2 -0
  8. package/dist/generate.d.ts.map +1 -0
  9. package/dist/generate.js +20 -0
  10. package/dist/helpers.d.ts +11 -0
  11. package/dist/helpers.d.ts.map +1 -0
  12. package/dist/helpers.js +32 -0
  13. package/dist/index.d.ts +13 -0
  14. package/dist/index.d.ts.map +1 -0
  15. package/dist/index.js +12 -0
  16. package/dist/migrate.d.ts +2 -0
  17. package/dist/migrate.d.ts.map +1 -0
  18. package/dist/migrate.js +61 -0
  19. package/dist/queries/agents.d.ts +25 -0
  20. package/dist/queries/agents.d.ts.map +1 -0
  21. package/dist/queries/agents.js +46 -0
  22. package/dist/queries/auth.d.ts +18 -0
  23. package/dist/queries/auth.d.ts.map +1 -0
  24. package/dist/queries/auth.js +77 -0
  25. package/dist/queries/detection-results.d.ts +24 -0
  26. package/dist/queries/detection-results.d.ts.map +1 -0
  27. package/dist/queries/detection-results.js +43 -0
  28. package/dist/queries/observations.d.ts +58 -0
  29. package/dist/queries/observations.d.ts.map +1 -0
  30. package/dist/queries/observations.js +212 -0
  31. package/dist/queries/policies.d.ts +25 -0
  32. package/dist/queries/policies.d.ts.map +1 -0
  33. package/dist/queries/policies.js +38 -0
  34. package/dist/queries/scanners.d.ts +25 -0
  35. package/dist/queries/scanners.d.ts.map +1 -0
  36. package/dist/queries/scanners.js +56 -0
  37. package/dist/queries/settings.d.ts +8 -0
  38. package/dist/queries/settings.d.ts.map +1 -0
  39. package/dist/queries/settings.js +30 -0
  40. package/dist/queries/usage.d.ts +18 -0
  41. package/dist/queries/usage.d.ts.map +1 -0
  42. package/dist/queries/usage.js +54 -0
  43. package/dist/schema/index.d.ts +4415 -0
  44. package/dist/schema/index.d.ts.map +1 -0
  45. package/dist/schema/index.js +19 -0
  46. package/dist/schema/mysql.d.ts +1479 -0
  47. package/dist/schema/mysql.d.ts.map +1 -0
  48. package/dist/schema/mysql.js +151 -0
  49. package/dist/schema/pg.d.ts +1479 -0
  50. package/dist/schema/pg.d.ts.map +1 -0
  51. package/dist/schema/pg.js +151 -0
  52. package/dist/schema/sqlite.d.ts +1479 -0
  53. package/dist/schema/sqlite.d.ts.map +1 -0
  54. package/dist/schema/sqlite.js +153 -0
  55. package/dist/seed.d.ts +2 -0
  56. package/dist/seed.d.ts.map +1 -0
  57. package/dist/seed.js +49 -0
  58. package/drizzle/sqlite/0000_serious_martin_li.sql +143 -0
  59. package/drizzle/sqlite/meta/0000_snapshot.json +945 -0
  60. package/drizzle/sqlite/meta/_journal.json +13 -0
  61. package/drizzle.config.mysql.ts +10 -0
  62. package/drizzle.config.pg.ts +10 -0
  63. package/drizzle.config.sqlite.ts +10 -0
  64. package/package.json +55 -0
  65. package/src/client.ts +66 -0
  66. package/src/dialect.ts +13 -0
  67. package/src/generate.ts +26 -0
  68. package/src/helpers.ts +47 -0
  69. package/src/index.ts +12 -0
  70. package/src/migrate.ts +74 -0
  71. package/src/queries/agents.ts +68 -0
  72. package/src/queries/auth.ts +94 -0
  73. package/src/queries/detection-results.ts +58 -0
  74. package/src/queries/observations.ts +275 -0
  75. package/src/queries/policies.ts +59 -0
  76. package/src/queries/scanners.ts +74 -0
  77. package/src/queries/settings.ts +34 -0
  78. package/src/queries/usage.ts +69 -0
  79. package/src/schema/index.ts +22 -0
  80. package/src/schema/mysql.ts +207 -0
  81. package/src/schema/pg.ts +208 -0
  82. package/src/schema/sqlite.ts +199 -0
  83. package/src/seed.ts +56 -0
@@ -0,0 +1,207 @@
1
+ import {
2
+ mysqlTable,
3
+ varchar,
4
+ text,
5
+ boolean,
6
+ int,
7
+ float,
8
+ datetime,
9
+ json,
10
+ index,
11
+ } from "drizzle-orm/mysql-core";
12
+
13
+ // ─── Settings ─────────────────────────────────────────────────
14
+ export const settings = mysqlTable("settings", {
15
+ key: varchar("key", { length: 255 }).primaryKey(),
16
+ value: text("value").notNull(),
17
+ updatedAt: datetime("updated_at").notNull().$defaultFn(() => new Date()),
18
+ });
19
+
20
+ // ─── Agents ─────────────────────────────────────────────────────
21
+ export const agents = mysqlTable(
22
+ "agents",
23
+ {
24
+ id: varchar("id", { length: 36 }).primaryKey().$defaultFn(() => crypto.randomUUID()),
25
+ tenantId: varchar("tenant_id", { length: 64 }).notNull().default("default"),
26
+ name: varchar("name", { length: 255 }).notNull(),
27
+ description: text("description"),
28
+ provider: varchar("provider", { length: 50 }).notNull().default("custom"),
29
+ status: varchar("status", { length: 50 }).notNull().default("inactive"),
30
+ lastSeenAt: datetime("last_seen_at"),
31
+ metadata: json("metadata").notNull().default({}),
32
+ createdAt: datetime("created_at").notNull().$defaultFn(() => new Date()),
33
+ updatedAt: datetime("updated_at").notNull().$defaultFn(() => new Date()),
34
+ },
35
+ (table) => ({
36
+ statusIdx: index("idx_agents_status").on(table.status),
37
+ tenantIdIdx: index("idx_agents_tenant_id").on(table.tenantId),
38
+ })
39
+ );
40
+
41
+ // ─── Scanner Definitions ────────────────────────────────────────
42
+ export const scannerDefinitions = mysqlTable(
43
+ "scanner_definitions",
44
+ {
45
+ id: varchar("id", { length: 36 }).primaryKey().$defaultFn(() => crypto.randomUUID()),
46
+ tenantId: varchar("tenant_id", { length: 64 }).notNull().default("default"),
47
+ scannerId: varchar("scanner_id", { length: 10 }).notNull(),
48
+ name: varchar("name", { length: 255 }).notNull(),
49
+ description: text("description").notNull(),
50
+ config: json("config").notNull().default({}),
51
+ isEnabled: boolean("is_enabled").notNull().default(true),
52
+ isDefault: boolean("is_default").notNull().default(false),
53
+ },
54
+ (table) => ({
55
+ scannerIdIdx: index("idx_scanner_defs_scanner_id").on(table.scannerId),
56
+ tenantIdIdx: index("idx_scanner_defs_tenant_id").on(table.tenantId),
57
+ })
58
+ );
59
+
60
+ // ─── Policies ───────────────────────────────────────────────────
61
+ export const policies = mysqlTable(
62
+ "policies",
63
+ {
64
+ id: varchar("id", { length: 36 }).primaryKey().$defaultFn(() => crypto.randomUUID()),
65
+ tenantId: varchar("tenant_id", { length: 64 }).notNull().default("default"),
66
+ name: varchar("name", { length: 255 }).notNull(),
67
+ description: text("description"),
68
+ scannerIds: json("scanner_ids").notNull().default([]),
69
+ action: varchar("action", { length: 50 }).notNull().default("log"),
70
+ sensitivityThreshold: float("sensitivity_threshold").notNull().default(0.5),
71
+ isEnabled: boolean("is_enabled").notNull().default(true),
72
+ createdAt: datetime("created_at").notNull().$defaultFn(() => new Date()),
73
+ updatedAt: datetime("updated_at").notNull().$defaultFn(() => new Date()),
74
+ },
75
+ (table) => ({
76
+ tenantIdIdx: index("idx_policies_tenant_id").on(table.tenantId),
77
+ })
78
+ );
79
+
80
+ // ─── Usage Logs ─────────────────────────────────────────────────
81
+ export const usageLogs = mysqlTable(
82
+ "usage_logs",
83
+ {
84
+ id: varchar("id", { length: 36 }).primaryKey().$defaultFn(() => crypto.randomUUID()),
85
+ tenantId: varchar("tenant_id", { length: 64 }).notNull().default("default"),
86
+ agentId: varchar("agent_id", { length: 36 }),
87
+ endpoint: varchar("endpoint", { length: 255 }).notNull(),
88
+ statusCode: int("status_code").notNull(),
89
+ responseSafe: boolean("response_safe"),
90
+ categories: json("categories").notNull().default([]),
91
+ latencyMs: int("latency_ms").notNull(),
92
+ requestId: varchar("request_id", { length: 64 }).notNull(),
93
+ createdAt: datetime("created_at").notNull().$defaultFn(() => new Date()),
94
+ },
95
+ (table) => ({
96
+ agentIdIdx: index("idx_usage_logs_agent_id").on(table.agentId),
97
+ createdAtIdx: index("idx_usage_logs_created_at").on(table.createdAt),
98
+ tenantIdIdx: index("idx_usage_logs_tenant_id").on(table.tenantId),
99
+ })
100
+ );
101
+
102
+ // ─── Detection Results ──────────────────────────────────────────
103
+ export const detectionResults = mysqlTable(
104
+ "detection_results",
105
+ {
106
+ id: varchar("id", { length: 36 }).primaryKey().$defaultFn(() => crypto.randomUUID()),
107
+ tenantId: varchar("tenant_id", { length: 64 }).notNull().default("default"),
108
+ agentId: varchar("agent_id", { length: 36 }),
109
+ safe: boolean("safe").notNull(),
110
+ categories: json("categories").notNull().default([]),
111
+ sensitivityScore: float("sensitivity_score").notNull().default(0),
112
+ findings: json("findings").notNull().default([]),
113
+ latencyMs: int("latency_ms").notNull(),
114
+ requestId: varchar("request_id", { length: 64 }).notNull(),
115
+ createdAt: datetime("created_at").notNull().$defaultFn(() => new Date()),
116
+ },
117
+ (table) => ({
118
+ agentIdIdx: index("idx_detection_results_agent_id").on(table.agentId),
119
+ createdAtIdx: index("idx_detection_results_created_at").on(table.createdAt),
120
+ tenantIdIdx: index("idx_detection_results_tenant_id").on(table.tenantId),
121
+ })
122
+ );
123
+
124
+ // ─── Tool Call Observations ─────────────────────────────────────
125
+ export const toolCallObservations = mysqlTable(
126
+ "tool_call_observations",
127
+ {
128
+ id: varchar("id", { length: 36 }).primaryKey().$defaultFn(() => crypto.randomUUID()),
129
+ tenantId: varchar("tenant_id", { length: 64 }).notNull().default("default"),
130
+ agentId: varchar("agent_id", { length: 36 }).notNull(),
131
+ sessionKey: varchar("session_key", { length: 255 }),
132
+ toolName: varchar("tool_name", { length: 255 }).notNull(),
133
+ category: varchar("category", { length: 64 }),
134
+ accessPattern: varchar("access_pattern", { length: 32 }),
135
+ paramsJson: json("params_json"),
136
+ phase: varchar("phase", { length: 16 }).notNull(),
137
+ resultJson: json("result_json"),
138
+ error: text("error"),
139
+ durationMs: int("duration_ms"),
140
+ blocked: boolean("blocked").notNull().default(false),
141
+ blockReason: text("block_reason"),
142
+ timestamp: datetime("timestamp").notNull().$defaultFn(() => new Date()),
143
+ },
144
+ (table) => ({
145
+ agentIdIdx: index("idx_tool_obs_agent_id").on(table.agentId),
146
+ toolNameIdx: index("idx_tool_obs_tool_name").on(table.toolName),
147
+ timestampIdx: index("idx_tool_obs_timestamp").on(table.timestamp),
148
+ tenantIdIdx: index("idx_tool_obs_tenant_id").on(table.tenantId),
149
+ })
150
+ );
151
+
152
+ // ─── Agent Permissions ────────────────────────────────────────
153
+ export const agentPermissions = mysqlTable(
154
+ "agent_permissions",
155
+ {
156
+ id: varchar("id", { length: 36 }).primaryKey().$defaultFn(() => crypto.randomUUID()),
157
+ tenantId: varchar("tenant_id", { length: 64 }).notNull().default("default"),
158
+ agentId: varchar("agent_id", { length: 36 }).notNull(),
159
+ toolName: varchar("tool_name", { length: 255 }).notNull(),
160
+ category: varchar("category", { length: 64 }),
161
+ accessPattern: varchar("access_pattern", { length: 32 }),
162
+ targetsJson: json("targets_json").notNull().default([]),
163
+ callCount: int("call_count").notNull().default(0),
164
+ errorCount: int("error_count").notNull().default(0),
165
+ firstSeen: datetime("first_seen").notNull().$defaultFn(() => new Date()),
166
+ lastSeen: datetime("last_seen").notNull().$defaultFn(() => new Date()),
167
+ },
168
+ (table) => ({
169
+ agentIdIdx: index("idx_agent_perms_agent_id").on(table.agentId),
170
+ toolNameIdx: index("idx_agent_perms_tool_name").on(table.toolName),
171
+ tenantIdIdx: index("idx_agent_perms_tenant_id").on(table.tenantId),
172
+ uniqueAgentTool: index("idx_agent_perms_unique").on(table.tenantId, table.agentId, table.toolName),
173
+ })
174
+ );
175
+
176
+ // ─── Magic Links ─────────────────────────────────────────────
177
+ export const magicLinks = mysqlTable(
178
+ "magic_links",
179
+ {
180
+ id: varchar("id", { length: 36 }).primaryKey(),
181
+ email: varchar("email", { length: 255 }).notNull(),
182
+ token: text("token").notNull(),
183
+ expiresAt: varchar("expires_at", { length: 32 }).notNull(),
184
+ usedAt: varchar("used_at", { length: 32 }),
185
+ createdAt: varchar("created_at", { length: 32 }).notNull(),
186
+ },
187
+ (table) => ({
188
+ tokenIdx: index("idx_magic_links_token").on(table.token),
189
+ emailIdx: index("idx_magic_links_email").on(table.email),
190
+ })
191
+ );
192
+
193
+ // ─── User Sessions ────────────────────────────────────────────
194
+ export const userSessions = mysqlTable(
195
+ "user_sessions",
196
+ {
197
+ id: varchar("id", { length: 36 }).primaryKey(),
198
+ email: varchar("email", { length: 255 }).notNull(),
199
+ token: text("token").notNull(),
200
+ expiresAt: varchar("expires_at", { length: 32 }).notNull(),
201
+ createdAt: varchar("created_at", { length: 32 }).notNull(),
202
+ },
203
+ (table) => ({
204
+ tokenIdx: index("idx_user_sessions_token").on(table.token),
205
+ emailIdx: index("idx_user_sessions_email").on(table.email),
206
+ })
207
+ );
@@ -0,0 +1,208 @@
1
+ import {
2
+ pgTable,
3
+ uuid,
4
+ varchar,
5
+ text,
6
+ boolean,
7
+ integer,
8
+ real,
9
+ timestamp,
10
+ jsonb,
11
+ index,
12
+ } from "drizzle-orm/pg-core";
13
+
14
+ // ─── Settings ─────────────────────────────────────────────────
15
+ export const settings = pgTable("settings", {
16
+ key: varchar("key", { length: 255 }).primaryKey(),
17
+ value: text("value").notNull(),
18
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
19
+ });
20
+
21
+ // ─── Agents ─────────────────────────────────────────────────────
22
+ export const agents = pgTable(
23
+ "agents",
24
+ {
25
+ id: uuid("id").primaryKey().defaultRandom(),
26
+ tenantId: varchar("tenant_id", { length: 64 }).notNull().default("default"),
27
+ name: varchar("name", { length: 255 }).notNull(),
28
+ description: text("description"),
29
+ provider: varchar("provider", { length: 50 }).notNull().default("custom"),
30
+ status: varchar("status", { length: 50 }).notNull().default("inactive"),
31
+ lastSeenAt: timestamp("last_seen_at", { withTimezone: true }),
32
+ metadata: jsonb("metadata").notNull().default({}),
33
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
34
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
35
+ },
36
+ (table) => ({
37
+ statusIdx: index("idx_agents_status").on(table.status),
38
+ tenantIdIdx: index("idx_agents_tenant_id").on(table.tenantId),
39
+ })
40
+ );
41
+
42
+ // ─── Scanner Definitions ────────────────────────────────────────
43
+ export const scannerDefinitions = pgTable(
44
+ "scanner_definitions",
45
+ {
46
+ id: uuid("id").primaryKey().defaultRandom(),
47
+ tenantId: varchar("tenant_id", { length: 64 }).notNull().default("default"),
48
+ scannerId: varchar("scanner_id", { length: 10 }).notNull(),
49
+ name: varchar("name", { length: 255 }).notNull(),
50
+ description: text("description").notNull(),
51
+ config: jsonb("config").notNull().default({}),
52
+ isEnabled: boolean("is_enabled").notNull().default(true),
53
+ isDefault: boolean("is_default").notNull().default(false),
54
+ },
55
+ (table) => ({
56
+ scannerIdIdx: index("idx_scanner_defs_scanner_id").on(table.scannerId),
57
+ tenantIdIdx: index("idx_scanner_defs_tenant_id").on(table.tenantId),
58
+ })
59
+ );
60
+
61
+ // ─── Policies ───────────────────────────────────────────────────
62
+ export const policies = pgTable(
63
+ "policies",
64
+ {
65
+ id: uuid("id").primaryKey().defaultRandom(),
66
+ tenantId: varchar("tenant_id", { length: 64 }).notNull().default("default"),
67
+ name: varchar("name", { length: 255 }).notNull(),
68
+ description: text("description"),
69
+ scannerIds: jsonb("scanner_ids").notNull().default([]),
70
+ action: varchar("action", { length: 50 }).notNull().default("log"),
71
+ sensitivityThreshold: real("sensitivity_threshold").notNull().default(0.5),
72
+ isEnabled: boolean("is_enabled").notNull().default(true),
73
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
74
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
75
+ },
76
+ (table) => ({
77
+ tenantIdIdx: index("idx_policies_tenant_id").on(table.tenantId),
78
+ })
79
+ );
80
+
81
+ // ─── Usage Logs ─────────────────────────────────────────────────
82
+ export const usageLogs = pgTable(
83
+ "usage_logs",
84
+ {
85
+ id: uuid("id").primaryKey().defaultRandom(),
86
+ tenantId: varchar("tenant_id", { length: 64 }).notNull().default("default"),
87
+ agentId: uuid("agent_id"),
88
+ endpoint: varchar("endpoint", { length: 255 }).notNull(),
89
+ statusCode: integer("status_code").notNull(),
90
+ responseSafe: boolean("response_safe"),
91
+ categories: jsonb("categories").notNull().default([]),
92
+ latencyMs: integer("latency_ms").notNull(),
93
+ requestId: varchar("request_id", { length: 64 }).notNull(),
94
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
95
+ },
96
+ (table) => ({
97
+ agentIdIdx: index("idx_usage_logs_agent_id").on(table.agentId),
98
+ createdAtIdx: index("idx_usage_logs_created_at").on(table.createdAt),
99
+ tenantIdIdx: index("idx_usage_logs_tenant_id").on(table.tenantId),
100
+ })
101
+ );
102
+
103
+ // ─── Detection Results ──────────────────────────────────────────
104
+ export const detectionResults = pgTable(
105
+ "detection_results",
106
+ {
107
+ id: uuid("id").primaryKey().defaultRandom(),
108
+ tenantId: varchar("tenant_id", { length: 64 }).notNull().default("default"),
109
+ agentId: uuid("agent_id"),
110
+ safe: boolean("safe").notNull(),
111
+ categories: jsonb("categories").notNull().default([]),
112
+ sensitivityScore: real("sensitivity_score").notNull().default(0),
113
+ findings: jsonb("findings").notNull().default([]),
114
+ latencyMs: integer("latency_ms").notNull(),
115
+ requestId: varchar("request_id", { length: 64 }).notNull(),
116
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
117
+ },
118
+ (table) => ({
119
+ agentIdIdx: index("idx_detection_results_agent_id").on(table.agentId),
120
+ createdAtIdx: index("idx_detection_results_created_at").on(table.createdAt),
121
+ tenantIdIdx: index("idx_detection_results_tenant_id").on(table.tenantId),
122
+ })
123
+ );
124
+
125
+ // ─── Tool Call Observations ─────────────────────────────────────
126
+ export const toolCallObservations = pgTable(
127
+ "tool_call_observations",
128
+ {
129
+ id: uuid("id").primaryKey().defaultRandom(),
130
+ tenantId: varchar("tenant_id", { length: 64 }).notNull().default("default"),
131
+ agentId: uuid("agent_id").notNull(),
132
+ sessionKey: varchar("session_key", { length: 255 }),
133
+ toolName: varchar("tool_name", { length: 255 }).notNull(),
134
+ category: varchar("category", { length: 64 }),
135
+ accessPattern: varchar("access_pattern", { length: 32 }),
136
+ paramsJson: jsonb("params_json"),
137
+ phase: varchar("phase", { length: 16 }).notNull(),
138
+ resultJson: jsonb("result_json"),
139
+ error: text("error"),
140
+ durationMs: integer("duration_ms"),
141
+ blocked: boolean("blocked").notNull().default(false),
142
+ blockReason: text("block_reason"),
143
+ timestamp: timestamp("timestamp", { withTimezone: true }).notNull().defaultNow(),
144
+ },
145
+ (table) => ({
146
+ agentIdIdx: index("idx_tool_obs_agent_id").on(table.agentId),
147
+ toolNameIdx: index("idx_tool_obs_tool_name").on(table.toolName),
148
+ timestampIdx: index("idx_tool_obs_timestamp").on(table.timestamp),
149
+ tenantIdIdx: index("idx_tool_obs_tenant_id").on(table.tenantId),
150
+ })
151
+ );
152
+
153
+ // ─── Agent Permissions ────────────────────────────────────────
154
+ export const agentPermissions = pgTable(
155
+ "agent_permissions",
156
+ {
157
+ id: uuid("id").primaryKey().defaultRandom(),
158
+ tenantId: varchar("tenant_id", { length: 64 }).notNull().default("default"),
159
+ agentId: uuid("agent_id").notNull(),
160
+ toolName: varchar("tool_name", { length: 255 }).notNull(),
161
+ category: varchar("category", { length: 64 }),
162
+ accessPattern: varchar("access_pattern", { length: 32 }),
163
+ targetsJson: jsonb("targets_json").notNull().default([]),
164
+ callCount: integer("call_count").notNull().default(0),
165
+ errorCount: integer("error_count").notNull().default(0),
166
+ firstSeen: timestamp("first_seen", { withTimezone: true }).notNull().defaultNow(),
167
+ lastSeen: timestamp("last_seen", { withTimezone: true }).notNull().defaultNow(),
168
+ },
169
+ (table) => ({
170
+ agentIdIdx: index("idx_agent_perms_agent_id").on(table.agentId),
171
+ toolNameIdx: index("idx_agent_perms_tool_name").on(table.toolName),
172
+ tenantIdIdx: index("idx_agent_perms_tenant_id").on(table.tenantId),
173
+ uniqueAgentTool: index("idx_agent_perms_unique").on(table.tenantId, table.agentId, table.toolName),
174
+ })
175
+ );
176
+
177
+ // ─── Magic Links ─────────────────────────────────────────────
178
+ export const magicLinks = pgTable(
179
+ "magic_links",
180
+ {
181
+ id: uuid("id").primaryKey().defaultRandom(),
182
+ email: varchar("email", { length: 255 }).notNull(),
183
+ token: text("token").notNull().unique(),
184
+ expiresAt: timestamp("expires_at", { withTimezone: true }).notNull(),
185
+ usedAt: timestamp("used_at", { withTimezone: true }),
186
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
187
+ },
188
+ (table) => ({
189
+ tokenIdx: index("idx_magic_links_token").on(table.token),
190
+ emailIdx: index("idx_magic_links_email").on(table.email),
191
+ })
192
+ );
193
+
194
+ // ─── User Sessions ────────────────────────────────────────────
195
+ export const userSessions = pgTable(
196
+ "user_sessions",
197
+ {
198
+ id: uuid("id").primaryKey().defaultRandom(),
199
+ email: varchar("email", { length: 255 }).notNull(),
200
+ token: text("token").notNull().unique(),
201
+ expiresAt: timestamp("expires_at", { withTimezone: true }).notNull(),
202
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
203
+ },
204
+ (table) => ({
205
+ tokenIdx: index("idx_user_sessions_token").on(table.token),
206
+ emailIdx: index("idx_user_sessions_email").on(table.email),
207
+ })
208
+ );
@@ -0,0 +1,199 @@
1
+ import { sqliteTable, text, integer, real, index } from "drizzle-orm/sqlite-core";
2
+
3
+ // ─── Settings ─────────────────────────────────────────────────
4
+ export const settings = sqliteTable("settings", {
5
+ key: text("key").primaryKey(),
6
+ value: text("value").notNull(),
7
+ updatedAt: text("updated_at").notNull().$defaultFn(() => new Date().toISOString()),
8
+ });
9
+
10
+ // ─── Agents ─────────────────────────────────────────────────────
11
+ export const agents = sqliteTable(
12
+ "agents",
13
+ {
14
+ id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
15
+ tenantId: text("tenant_id").notNull().default("default"),
16
+ name: text("name").notNull(),
17
+ description: text("description"),
18
+ provider: text("provider").notNull().default("custom"),
19
+ status: text("status").notNull().default("inactive"),
20
+ lastSeenAt: text("last_seen_at"),
21
+ metadata: text("metadata", { mode: "json" }).notNull().default({}),
22
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString()),
23
+ updatedAt: text("updated_at").notNull().$defaultFn(() => new Date().toISOString()),
24
+ },
25
+ (table) => ({
26
+ statusIdx: index("idx_agents_status").on(table.status),
27
+ tenantIdIdx: index("idx_agents_tenant_id").on(table.tenantId),
28
+ })
29
+ );
30
+
31
+ // ─── Scanner Definitions ────────────────────────────────────────
32
+ export const scannerDefinitions = sqliteTable(
33
+ "scanner_definitions",
34
+ {
35
+ id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
36
+ tenantId: text("tenant_id").notNull().default("default"),
37
+ scannerId: text("scanner_id").notNull(),
38
+ name: text("name").notNull(),
39
+ description: text("description").notNull(),
40
+ config: text("config", { mode: "json" }).notNull().default({}),
41
+ isEnabled: integer("is_enabled", { mode: "boolean" }).notNull().default(true),
42
+ isDefault: integer("is_default", { mode: "boolean" }).notNull().default(false),
43
+ },
44
+ (table) => ({
45
+ scannerIdIdx: index("idx_scanner_defs_scanner_id").on(table.scannerId),
46
+ tenantIdIdx: index("idx_scanner_defs_tenant_id").on(table.tenantId),
47
+ })
48
+ );
49
+
50
+ // ─── Policies ───────────────────────────────────────────────────
51
+ export const policies = sqliteTable(
52
+ "policies",
53
+ {
54
+ id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
55
+ tenantId: text("tenant_id").notNull().default("default"),
56
+ name: text("name").notNull(),
57
+ description: text("description"),
58
+ scannerIds: text("scanner_ids", { mode: "json" }).notNull().default([]),
59
+ action: text("action").notNull().default("log"),
60
+ sensitivityThreshold: real("sensitivity_threshold").notNull().default(0.5),
61
+ isEnabled: integer("is_enabled", { mode: "boolean" }).notNull().default(true),
62
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString()),
63
+ updatedAt: text("updated_at").notNull().$defaultFn(() => new Date().toISOString()),
64
+ },
65
+ (table) => ({
66
+ tenantIdIdx: index("idx_policies_tenant_id").on(table.tenantId),
67
+ })
68
+ );
69
+
70
+ // ─── Usage Logs ─────────────────────────────────────────────────
71
+ export const usageLogs = sqliteTable(
72
+ "usage_logs",
73
+ {
74
+ id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
75
+ tenantId: text("tenant_id").notNull().default("default"),
76
+ agentId: text("agent_id"),
77
+ endpoint: text("endpoint").notNull(),
78
+ statusCode: integer("status_code").notNull(),
79
+ responseSafe: integer("response_safe", { mode: "boolean" }),
80
+ categories: text("categories", { mode: "json" }).notNull().default([]),
81
+ latencyMs: integer("latency_ms").notNull(),
82
+ requestId: text("request_id").notNull(),
83
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString()),
84
+ },
85
+ (table) => ({
86
+ agentIdIdx: index("idx_usage_logs_agent_id").on(table.agentId),
87
+ createdAtIdx: index("idx_usage_logs_created_at").on(table.createdAt),
88
+ tenantIdIdx: index("idx_usage_logs_tenant_id").on(table.tenantId),
89
+ })
90
+ );
91
+
92
+ // ─── Detection Results ──────────────────────────────────────────
93
+ export const detectionResults = sqliteTable(
94
+ "detection_results",
95
+ {
96
+ id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
97
+ tenantId: text("tenant_id").notNull().default("default"),
98
+ agentId: text("agent_id"),
99
+ safe: integer("safe", { mode: "boolean" }).notNull(),
100
+ categories: text("categories", { mode: "json" }).notNull().default([]),
101
+ sensitivityScore: real("sensitivity_score").notNull().default(0),
102
+ findings: text("findings", { mode: "json" }).notNull().default([]),
103
+ latencyMs: integer("latency_ms").notNull(),
104
+ requestId: text("request_id").notNull(),
105
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString()),
106
+ },
107
+ (table) => ({
108
+ agentIdIdx: index("idx_detection_results_agent_id").on(table.agentId),
109
+ createdAtIdx: index("idx_detection_results_created_at").on(table.createdAt),
110
+ tenantIdIdx: index("idx_detection_results_tenant_id").on(table.tenantId),
111
+ })
112
+ );
113
+
114
+ // ─── Tool Call Observations ─────────────────────────────────────
115
+ export const toolCallObservations = sqliteTable(
116
+ "tool_call_observations",
117
+ {
118
+ id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
119
+ tenantId: text("tenant_id").notNull().default("default"),
120
+ agentId: text("agent_id").notNull(),
121
+ sessionKey: text("session_key"),
122
+ toolName: text("tool_name").notNull(),
123
+ category: text("category"),
124
+ accessPattern: text("access_pattern"),
125
+ paramsJson: text("params_json", { mode: "json" }),
126
+ phase: text("phase").notNull(),
127
+ resultJson: text("result_json", { mode: "json" }),
128
+ error: text("error"),
129
+ durationMs: integer("duration_ms"),
130
+ blocked: integer("blocked", { mode: "boolean" }).notNull().default(false),
131
+ blockReason: text("block_reason"),
132
+ timestamp: text("timestamp").notNull().$defaultFn(() => new Date().toISOString()),
133
+ },
134
+ (table) => ({
135
+ agentIdIdx: index("idx_tool_obs_agent_id").on(table.agentId),
136
+ toolNameIdx: index("idx_tool_obs_tool_name").on(table.toolName),
137
+ timestampIdx: index("idx_tool_obs_timestamp").on(table.timestamp),
138
+ tenantIdIdx: index("idx_tool_obs_tenant_id").on(table.tenantId),
139
+ })
140
+ );
141
+
142
+ // ─── Magic Links ─────────────────────────────────────────────
143
+ // One-time login tokens sent via email (15-min TTL)
144
+ export const magicLinks = sqliteTable(
145
+ "magic_links",
146
+ {
147
+ id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
148
+ email: text("email").notNull(),
149
+ token: text("token").notNull().unique(),
150
+ expiresAt: text("expires_at").notNull(),
151
+ usedAt: text("used_at"),
152
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString()),
153
+ },
154
+ (table) => ({
155
+ tokenIdx: index("idx_magic_links_token").on(table.token),
156
+ emailIdx: index("idx_magic_links_email").on(table.email),
157
+ })
158
+ );
159
+
160
+ // ─── User Sessions ────────────────────────────────────────────
161
+ // Persistent sessions created after magic link verification (30-day TTL)
162
+ export const userSessions = sqliteTable(
163
+ "user_sessions",
164
+ {
165
+ id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
166
+ email: text("email").notNull(),
167
+ token: text("token").notNull().unique(),
168
+ expiresAt: text("expires_at").notNull(),
169
+ createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString()),
170
+ },
171
+ (table) => ({
172
+ tokenIdx: index("idx_user_sessions_token").on(table.token),
173
+ emailIdx: index("idx_user_sessions_email").on(table.email),
174
+ })
175
+ );
176
+
177
+ // ─── Agent Permissions ────────────────────────────────────────
178
+ export const agentPermissions = sqliteTable(
179
+ "agent_permissions",
180
+ {
181
+ id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
182
+ tenantId: text("tenant_id").notNull().default("default"),
183
+ agentId: text("agent_id").notNull(),
184
+ toolName: text("tool_name").notNull(),
185
+ category: text("category"),
186
+ accessPattern: text("access_pattern"),
187
+ targetsJson: text("targets_json", { mode: "json" }).notNull().default([]),
188
+ callCount: integer("call_count").notNull().default(0),
189
+ errorCount: integer("error_count").notNull().default(0),
190
+ firstSeen: text("first_seen").notNull().$defaultFn(() => new Date().toISOString()),
191
+ lastSeen: text("last_seen").notNull().$defaultFn(() => new Date().toISOString()),
192
+ },
193
+ (table) => ({
194
+ agentIdIdx: index("idx_agent_perms_agent_id").on(table.agentId),
195
+ toolNameIdx: index("idx_agent_perms_tool_name").on(table.toolName),
196
+ tenantIdIdx: index("idx_agent_perms_tenant_id").on(table.tenantId),
197
+ uniqueAgentTool: index("idx_agent_perms_unique").on(table.tenantId, table.agentId, table.toolName),
198
+ })
199
+ );
package/src/seed.ts ADDED
@@ -0,0 +1,56 @@
1
+ import { config } from "dotenv";
2
+ import { resolve, dirname } from "path";
3
+ import { fileURLToPath } from "url";
4
+
5
+ const __filename = fileURLToPath(import.meta.url);
6
+ const __dirname = dirname(__filename);
7
+
8
+ config({ path: resolve(__dirname, "../../../.env") });
9
+
10
+ async function seed() {
11
+ const { db } = await import("./client.js");
12
+ const { scannerDefinitions } = await import("./schema/index.js");
13
+ const { DEFAULT_SCANNERS, DEFAULT_TENANT_ID } = await import("@opentrust/shared");
14
+ const { getDialect } = await import("./dialect.js");
15
+ const { eq } = await import("drizzle-orm");
16
+
17
+ console.log(`Seeding default scanners (dialect: ${getDialect()})...`);
18
+
19
+ for (const scanner of DEFAULT_SCANNERS) {
20
+ const id = crypto.randomUUID();
21
+ const values = {
22
+ id,
23
+ scannerId: scanner.scannerId,
24
+ name: scanner.name,
25
+ description: scanner.description,
26
+ isEnabled: true,
27
+ isDefault: true,
28
+ tenantId: DEFAULT_TENANT_ID,
29
+ };
30
+
31
+ try {
32
+ const existing = await db
33
+ .select()
34
+ .from(scannerDefinitions)
35
+ .where(eq(scannerDefinitions.scannerId, scanner.scannerId))
36
+ .limit(1);
37
+
38
+ if (existing.length === 0) {
39
+ await db.insert(scannerDefinitions).values(values);
40
+ console.log(` Seeded ${scanner.scannerId}: ${scanner.name}`);
41
+ } else {
42
+ console.log(` Skipped ${scanner.scannerId}: already exists`);
43
+ }
44
+ } catch (err) {
45
+ console.warn(` Warning: ${scanner.scannerId} seed failed:`, err);
46
+ }
47
+ }
48
+
49
+ console.log("Seeding complete.");
50
+ process.exit(0);
51
+ }
52
+
53
+ seed().catch((err) => {
54
+ console.error("Seed failed:", err);
55
+ process.exit(1);
56
+ });