@coffre/db 0.6.2 → 0.8.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/dist/connect.d.ts +1 -1
- package/dist/{database-C63WjCrC.d.ts → database-BEnexh-3.d.ts} +1 -1
- package/dist/dialect.d.ts +1 -1
- package/dist/grants.d.ts +1 -1
- package/dist/hyperdrive.d.ts +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/log.d.ts +22 -1
- package/dist/log.js +37 -2
- package/dist/migrations/postgres/0004_environment_parents.sql +5 -0
- package/dist/migrations/postgres/0005_personal_tokens.sql +5 -0
- package/dist/migrations/postgres/0006_uploaded_keys.sql +2 -0
- package/dist/migrations/postgres/0007_personal_configs.sql +4 -0
- package/dist/migrations/postgres/0008_recipes.sql +19 -0
- package/dist/migrations/postgres/0009_handles.sql +3 -0
- package/dist/migrations/postgres/meta/0004_snapshot.json +2913 -0
- package/dist/migrations/postgres/meta/0005_snapshot.json +2929 -0
- package/dist/migrations/postgres/meta/0006_snapshot.json +2935 -0
- package/dist/migrations/postgres/meta/0007_snapshot.json +2967 -0
- package/dist/migrations/postgres/meta/0008_snapshot.json +2985 -0
- package/dist/migrations/postgres/meta/0009_snapshot.json +2985 -0
- package/dist/migrations/postgres/meta/_journal.json +42 -0
- package/dist/migrations/sqlite/0004_environment_parents.sql +3 -0
- package/dist/migrations/sqlite/0005_personal_tokens.sql +37 -0
- package/dist/migrations/sqlite/0006_uploaded_keys.sql +1 -0
- package/dist/migrations/sqlite/0007_personal_configs.sql +3 -0
- package/dist/migrations/sqlite/0008_recipes.sql +15 -0
- package/dist/migrations/sqlite/0009_handles.sql +36 -0
- package/dist/migrations/sqlite/meta/0004_snapshot.json +2641 -0
- package/dist/migrations/sqlite/meta/0005_snapshot.json +2656 -0
- package/dist/migrations/sqlite/meta/0006_snapshot.json +2663 -0
- package/dist/migrations/sqlite/meta/0007_snapshot.json +2683 -0
- package/dist/migrations/sqlite/meta/0008_snapshot.json +2704 -0
- package/dist/migrations/sqlite/meta/0009_snapshot.json +2704 -0
- package/dist/migrations/sqlite/meta/_journal.json +42 -0
- package/dist/portable.d.ts +2 -2
- package/dist/{schema-a7PkFgea.d.ts → schema-BZRkBJQZ.d.ts} +102 -0
- package/dist/schema-sqlite.d.ts +114 -0
- package/dist/schema-sqlite.js +20 -4
- package/dist/schema-version.d.ts +1 -1
- package/dist/schema-version.js +84 -0
- package/dist/schema.d.ts +1 -1
- package/dist/schema.js +20 -4
- package/package.json +2 -2
- package/src/log.ts +40 -1
- package/src/migrations/postgres/0004_environment_parents.sql +5 -0
- package/src/migrations/postgres/0005_personal_tokens.sql +5 -0
- package/src/migrations/postgres/0006_uploaded_keys.sql +2 -0
- package/src/migrations/postgres/0007_personal_configs.sql +4 -0
- package/src/migrations/postgres/0008_recipes.sql +19 -0
- package/src/migrations/postgres/0009_handles.sql +3 -0
- package/src/migrations/postgres/meta/0004_snapshot.json +2913 -0
- package/src/migrations/postgres/meta/0005_snapshot.json +2929 -0
- package/src/migrations/postgres/meta/0006_snapshot.json +2935 -0
- package/src/migrations/postgres/meta/0007_snapshot.json +2967 -0
- package/src/migrations/postgres/meta/0008_snapshot.json +2985 -0
- package/src/migrations/postgres/meta/0009_snapshot.json +2985 -0
- package/src/migrations/postgres/meta/_journal.json +42 -0
- package/src/migrations/sqlite/0004_environment_parents.sql +3 -0
- package/src/migrations/sqlite/0005_personal_tokens.sql +37 -0
- package/src/migrations/sqlite/0006_uploaded_keys.sql +1 -0
- package/src/migrations/sqlite/0007_personal_configs.sql +3 -0
- package/src/migrations/sqlite/0008_recipes.sql +15 -0
- package/src/migrations/sqlite/0009_handles.sql +36 -0
- package/src/migrations/sqlite/meta/0004_snapshot.json +2641 -0
- package/src/migrations/sqlite/meta/0005_snapshot.json +2656 -0
- package/src/migrations/sqlite/meta/0006_snapshot.json +2663 -0
- package/src/migrations/sqlite/meta/0007_snapshot.json +2683 -0
- package/src/migrations/sqlite/meta/0008_snapshot.json +2704 -0
- package/src/migrations/sqlite/meta/0009_snapshot.json +2704 -0
- package/src/migrations/sqlite/meta/_journal.json +42 -0
- package/src/schema.sqlite.ts +31 -3
- package/src/schema.ts +37 -3
|
@@ -29,6 +29,48 @@
|
|
|
29
29
|
"when": 1791676487593,
|
|
30
30
|
"tag": "0003_credential_scopes",
|
|
31
31
|
"breakpoints": true
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"idx": 4,
|
|
35
|
+
"version": "6",
|
|
36
|
+
"when": 1792244020959,
|
|
37
|
+
"tag": "0004_environment_parents",
|
|
38
|
+
"breakpoints": true
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"idx": 5,
|
|
42
|
+
"version": "6",
|
|
43
|
+
"when": 1792250910230,
|
|
44
|
+
"tag": "0005_personal_tokens",
|
|
45
|
+
"breakpoints": true
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"idx": 6,
|
|
49
|
+
"version": "6",
|
|
50
|
+
"when": 1792252693912,
|
|
51
|
+
"tag": "0006_uploaded_keys",
|
|
52
|
+
"breakpoints": true
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"idx": 7,
|
|
56
|
+
"version": "6",
|
|
57
|
+
"when": 1792253795070,
|
|
58
|
+
"tag": "0007_personal_configs",
|
|
59
|
+
"breakpoints": true
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"idx": 8,
|
|
63
|
+
"version": "6",
|
|
64
|
+
"when": 1792255560312,
|
|
65
|
+
"tag": "0008_recipes",
|
|
66
|
+
"breakpoints": true
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"idx": 9,
|
|
70
|
+
"version": "6",
|
|
71
|
+
"when": 1792281880190,
|
|
72
|
+
"tag": "0009_handles",
|
|
73
|
+
"breakpoints": true
|
|
32
74
|
}
|
|
33
75
|
]
|
|
34
76
|
}
|
package/dist/portable.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { m as schema_d_exports } from "./schema-
|
|
2
|
-
import { t as Database } from "./database-
|
|
1
|
+
import { m as schema_d_exports } from "./schema-BZRkBJQZ.js";
|
|
2
|
+
import { t as Database } from "./database-BEnexh-3.js";
|
|
3
3
|
import { t as schema_sqlite_d_exports } from "./schema-sqlite.js";
|
|
4
4
|
import { LibSQLDatabase } from "drizzle-orm/libsql";
|
|
5
5
|
//#region src/portable.d.ts
|
|
@@ -216,6 +216,40 @@ declare const environments: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
|
216
216
|
identity: undefined;
|
|
217
217
|
generated: undefined;
|
|
218
218
|
}, {}, {}>;
|
|
219
|
+
parentId: import("drizzle-orm/pg-core").PgColumn<{
|
|
220
|
+
name: "parent_id";
|
|
221
|
+
tableName: "environments";
|
|
222
|
+
dataType: "string";
|
|
223
|
+
columnType: "PgUUID";
|
|
224
|
+
data: string;
|
|
225
|
+
driverParam: string;
|
|
226
|
+
notNull: false;
|
|
227
|
+
hasDefault: false;
|
|
228
|
+
isPrimaryKey: false;
|
|
229
|
+
isAutoincrement: false;
|
|
230
|
+
hasRuntimeDefault: false;
|
|
231
|
+
enumValues: undefined;
|
|
232
|
+
baseColumn: never;
|
|
233
|
+
identity: undefined;
|
|
234
|
+
generated: undefined;
|
|
235
|
+
}, {}, {}>;
|
|
236
|
+
owner: import("drizzle-orm/pg-core").PgColumn<{
|
|
237
|
+
name: "owner";
|
|
238
|
+
tableName: "environments";
|
|
239
|
+
dataType: "string";
|
|
240
|
+
columnType: "PgText";
|
|
241
|
+
data: string;
|
|
242
|
+
driverParam: string;
|
|
243
|
+
notNull: false;
|
|
244
|
+
hasDefault: false;
|
|
245
|
+
isPrimaryKey: false;
|
|
246
|
+
isAutoincrement: false;
|
|
247
|
+
hasRuntimeDefault: false;
|
|
248
|
+
enumValues: [string, ...string[]];
|
|
249
|
+
baseColumn: never;
|
|
250
|
+
identity: undefined;
|
|
251
|
+
generated: undefined;
|
|
252
|
+
}, {}, {}>;
|
|
219
253
|
};
|
|
220
254
|
dialect: "pg";
|
|
221
255
|
}>;
|
|
@@ -629,6 +663,57 @@ declare const secretVersions: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
|
629
663
|
identity: undefined;
|
|
630
664
|
generated: undefined;
|
|
631
665
|
}, {}, {}>;
|
|
666
|
+
recipe: import("drizzle-orm/pg-core").PgColumn<{
|
|
667
|
+
name: "recipe";
|
|
668
|
+
tableName: "secret_versions";
|
|
669
|
+
dataType: "string";
|
|
670
|
+
columnType: "PgText";
|
|
671
|
+
data: string;
|
|
672
|
+
driverParam: string;
|
|
673
|
+
notNull: false;
|
|
674
|
+
hasDefault: false;
|
|
675
|
+
isPrimaryKey: false;
|
|
676
|
+
isAutoincrement: false;
|
|
677
|
+
hasRuntimeDefault: false;
|
|
678
|
+
enumValues: [string, ...string[]];
|
|
679
|
+
baseColumn: never;
|
|
680
|
+
identity: undefined;
|
|
681
|
+
generated: undefined;
|
|
682
|
+
}, {}, {}>;
|
|
683
|
+
pairId: import("drizzle-orm/pg-core").PgColumn<{
|
|
684
|
+
name: "pair_id";
|
|
685
|
+
tableName: "secret_versions";
|
|
686
|
+
dataType: "string";
|
|
687
|
+
columnType: "PgUUID";
|
|
688
|
+
data: string;
|
|
689
|
+
driverParam: string;
|
|
690
|
+
notNull: false;
|
|
691
|
+
hasDefault: false;
|
|
692
|
+
isPrimaryKey: false;
|
|
693
|
+
isAutoincrement: false;
|
|
694
|
+
hasRuntimeDefault: false;
|
|
695
|
+
enumValues: undefined;
|
|
696
|
+
baseColumn: never;
|
|
697
|
+
identity: undefined;
|
|
698
|
+
generated: undefined;
|
|
699
|
+
}, {}, {}>;
|
|
700
|
+
pairHalf: import("drizzle-orm/pg-core").PgColumn<{
|
|
701
|
+
name: "pair_half";
|
|
702
|
+
tableName: "secret_versions";
|
|
703
|
+
dataType: "string";
|
|
704
|
+
columnType: "PgText";
|
|
705
|
+
data: string;
|
|
706
|
+
driverParam: string;
|
|
707
|
+
notNull: false;
|
|
708
|
+
hasDefault: false;
|
|
709
|
+
isPrimaryKey: false;
|
|
710
|
+
isAutoincrement: false;
|
|
711
|
+
hasRuntimeDefault: false;
|
|
712
|
+
enumValues: [string, ...string[]];
|
|
713
|
+
baseColumn: never;
|
|
714
|
+
identity: undefined;
|
|
715
|
+
generated: undefined;
|
|
716
|
+
}, {}, {}>;
|
|
632
717
|
};
|
|
633
718
|
dialect: "pg";
|
|
634
719
|
}>;
|
|
@@ -2123,6 +2208,23 @@ declare const serviceBindings: import("drizzle-orm/pg-core").PgTableWithColumns<
|
|
|
2123
2208
|
identity: undefined;
|
|
2124
2209
|
generated: undefined;
|
|
2125
2210
|
}, {}, {}>;
|
|
2211
|
+
jwks: import("drizzle-orm/pg-core").PgColumn<{
|
|
2212
|
+
name: "jwks";
|
|
2213
|
+
tableName: "service_bindings";
|
|
2214
|
+
dataType: "string";
|
|
2215
|
+
columnType: "PgText";
|
|
2216
|
+
data: string;
|
|
2217
|
+
driverParam: string;
|
|
2218
|
+
notNull: false;
|
|
2219
|
+
hasDefault: false;
|
|
2220
|
+
isPrimaryKey: false;
|
|
2221
|
+
isAutoincrement: false;
|
|
2222
|
+
hasRuntimeDefault: false;
|
|
2223
|
+
enumValues: [string, ...string[]];
|
|
2224
|
+
baseColumn: never;
|
|
2225
|
+
identity: undefined;
|
|
2226
|
+
generated: undefined;
|
|
2227
|
+
}, {}, {}>;
|
|
2126
2228
|
claims: import("drizzle-orm/pg-core").PgColumn<{
|
|
2127
2229
|
name: "claims";
|
|
2128
2230
|
tableName: "service_bindings";
|
package/dist/schema-sqlite.d.ts
CHANGED
|
@@ -232,6 +232,44 @@ export declare const environments: import("drizzle-orm/sqlite-core").SQLiteTable
|
|
|
232
232
|
identity: undefined;
|
|
233
233
|
generated: undefined;
|
|
234
234
|
}, {}, {}>;
|
|
235
|
+
parentId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
236
|
+
name: "parent_id";
|
|
237
|
+
tableName: "environments";
|
|
238
|
+
dataType: "string";
|
|
239
|
+
columnType: "SQLiteText";
|
|
240
|
+
data: string;
|
|
241
|
+
driverParam: string;
|
|
242
|
+
notNull: false;
|
|
243
|
+
hasDefault: false;
|
|
244
|
+
isPrimaryKey: false;
|
|
245
|
+
isAutoincrement: false;
|
|
246
|
+
hasRuntimeDefault: false;
|
|
247
|
+
enumValues: [string, ...string[]];
|
|
248
|
+
baseColumn: never;
|
|
249
|
+
identity: undefined;
|
|
250
|
+
generated: undefined;
|
|
251
|
+
}, {}, {
|
|
252
|
+
length: number | undefined;
|
|
253
|
+
}>;
|
|
254
|
+
owner: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
255
|
+
name: "owner";
|
|
256
|
+
tableName: "environments";
|
|
257
|
+
dataType: "string";
|
|
258
|
+
columnType: "SQLiteText";
|
|
259
|
+
data: string;
|
|
260
|
+
driverParam: string;
|
|
261
|
+
notNull: false;
|
|
262
|
+
hasDefault: false;
|
|
263
|
+
isPrimaryKey: false;
|
|
264
|
+
isAutoincrement: false;
|
|
265
|
+
hasRuntimeDefault: false;
|
|
266
|
+
enumValues: [string, ...string[]];
|
|
267
|
+
baseColumn: never;
|
|
268
|
+
identity: undefined;
|
|
269
|
+
generated: undefined;
|
|
270
|
+
}, {}, {
|
|
271
|
+
length: undefined;
|
|
272
|
+
}>;
|
|
235
273
|
};
|
|
236
274
|
dialect: "sqlite";
|
|
237
275
|
}>;
|
|
@@ -661,6 +699,63 @@ export declare const secretVersions: import("drizzle-orm/sqlite-core").SQLiteTab
|
|
|
661
699
|
}, {}, {
|
|
662
700
|
length: number | undefined;
|
|
663
701
|
}>;
|
|
702
|
+
recipe: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
703
|
+
name: "recipe";
|
|
704
|
+
tableName: "secret_versions";
|
|
705
|
+
dataType: "string";
|
|
706
|
+
columnType: "SQLiteText";
|
|
707
|
+
data: string;
|
|
708
|
+
driverParam: string;
|
|
709
|
+
notNull: false;
|
|
710
|
+
hasDefault: false;
|
|
711
|
+
isPrimaryKey: false;
|
|
712
|
+
isAutoincrement: false;
|
|
713
|
+
hasRuntimeDefault: false;
|
|
714
|
+
enumValues: [string, ...string[]];
|
|
715
|
+
baseColumn: never;
|
|
716
|
+
identity: undefined;
|
|
717
|
+
generated: undefined;
|
|
718
|
+
}, {}, {
|
|
719
|
+
length: undefined;
|
|
720
|
+
}>;
|
|
721
|
+
pairId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
722
|
+
name: "pair_id";
|
|
723
|
+
tableName: "secret_versions";
|
|
724
|
+
dataType: "string";
|
|
725
|
+
columnType: "SQLiteText";
|
|
726
|
+
data: string;
|
|
727
|
+
driverParam: string;
|
|
728
|
+
notNull: false;
|
|
729
|
+
hasDefault: false;
|
|
730
|
+
isPrimaryKey: false;
|
|
731
|
+
isAutoincrement: false;
|
|
732
|
+
hasRuntimeDefault: false;
|
|
733
|
+
enumValues: [string, ...string[]];
|
|
734
|
+
baseColumn: never;
|
|
735
|
+
identity: undefined;
|
|
736
|
+
generated: undefined;
|
|
737
|
+
}, {}, {
|
|
738
|
+
length: number | undefined;
|
|
739
|
+
}>;
|
|
740
|
+
pairHalf: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
741
|
+
name: "pair_half";
|
|
742
|
+
tableName: "secret_versions";
|
|
743
|
+
dataType: "string";
|
|
744
|
+
columnType: "SQLiteText";
|
|
745
|
+
data: string;
|
|
746
|
+
driverParam: string;
|
|
747
|
+
notNull: false;
|
|
748
|
+
hasDefault: false;
|
|
749
|
+
isPrimaryKey: false;
|
|
750
|
+
isAutoincrement: false;
|
|
751
|
+
hasRuntimeDefault: false;
|
|
752
|
+
enumValues: [string, ...string[]];
|
|
753
|
+
baseColumn: never;
|
|
754
|
+
identity: undefined;
|
|
755
|
+
generated: undefined;
|
|
756
|
+
}, {}, {
|
|
757
|
+
length: number | undefined;
|
|
758
|
+
}>;
|
|
664
759
|
};
|
|
665
760
|
dialect: "sqlite";
|
|
666
761
|
}>;
|
|
@@ -2212,6 +2307,25 @@ export declare const serviceBindings: import("drizzle-orm/sqlite-core").SQLiteTa
|
|
|
2212
2307
|
}, {}, {
|
|
2213
2308
|
length: number | undefined;
|
|
2214
2309
|
}>;
|
|
2310
|
+
jwks: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
2311
|
+
name: "jwks";
|
|
2312
|
+
tableName: "service_bindings";
|
|
2313
|
+
dataType: "string";
|
|
2314
|
+
columnType: "SQLiteText";
|
|
2315
|
+
data: string;
|
|
2316
|
+
driverParam: string;
|
|
2317
|
+
notNull: false;
|
|
2318
|
+
hasDefault: false;
|
|
2319
|
+
isPrimaryKey: false;
|
|
2320
|
+
isAutoincrement: false;
|
|
2321
|
+
hasRuntimeDefault: false;
|
|
2322
|
+
enumValues: [string, ...string[]];
|
|
2323
|
+
baseColumn: never;
|
|
2324
|
+
identity: undefined;
|
|
2325
|
+
generated: undefined;
|
|
2326
|
+
}, {}, {
|
|
2327
|
+
length: undefined;
|
|
2328
|
+
}>;
|
|
2215
2329
|
claims: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
2216
2330
|
name: "claims";
|
|
2217
2331
|
tableName: "service_bindings";
|
package/dist/schema-sqlite.js
CHANGED
|
@@ -54,16 +54,27 @@ const environments = sqliteTable("environments", {
|
|
|
54
54
|
slug: text().notNull(),
|
|
55
55
|
name: text().notNull(),
|
|
56
56
|
createdAt: createdAt(),
|
|
57
|
-
archivedAt: time("archived_at")
|
|
57
|
+
archivedAt: time("archived_at"),
|
|
58
|
+
parentId: text("parent_id"),
|
|
59
|
+
owner: text()
|
|
58
60
|
}, (table) => [
|
|
59
61
|
unique("environments_project_id_slug_key").on(table.projectId, table.slug),
|
|
60
62
|
unique("environments_project_scoped").on(table.id, table.projectId),
|
|
61
63
|
check("environments_slug_check", isPlaceSlug(table.slug)),
|
|
64
|
+
check("environments_parent_check", sql`${table.parentId} IS NULL OR ${table.parentId} <> ${table.id}`),
|
|
65
|
+
check("environments_owner_check", sql`${table.owner} IS NULL OR (${table.parentId} IS NOT NULL AND ${table.owner} LIKE 'user:_%')`),
|
|
66
|
+
uniqueIndex("environments_parent_id_owner_key").on(table.parentId, table.owner).where(sql`instr(${table.slug}, '~') = 0`),
|
|
62
67
|
foreignKey({
|
|
63
68
|
name: "environments_project_id_fkey",
|
|
64
69
|
columns: [table.projectId],
|
|
65
70
|
foreignColumns: [projects.id]
|
|
66
|
-
}).onDelete("restrict")
|
|
71
|
+
}).onDelete("restrict"),
|
|
72
|
+
foreignKey({
|
|
73
|
+
name: "environments_parent_in_project",
|
|
74
|
+
columns: [table.parentId, table.projectId],
|
|
75
|
+
foreignColumns: [table.id, table.projectId]
|
|
76
|
+
}).onDelete("no action"),
|
|
77
|
+
index("environments_parent_idx").on(table.parentId)
|
|
67
78
|
]);
|
|
68
79
|
const secrets = sqliteTable("secrets", {
|
|
69
80
|
id: text().primaryKey(),
|
|
@@ -110,7 +121,10 @@ const secretVersions = sqliteTable("secret_versions", {
|
|
|
110
121
|
kekId: text("kek_id").notNull(),
|
|
111
122
|
kekVersion: text("kek_version").notNull(),
|
|
112
123
|
createdAt: createdAt(),
|
|
113
|
-
createdBy: text("created_by").notNull()
|
|
124
|
+
createdBy: text("created_by").notNull(),
|
|
125
|
+
recipe: text(),
|
|
126
|
+
pairId: text("pair_id"),
|
|
127
|
+
pairHalf: text("pair_half")
|
|
114
128
|
}, (table) => [
|
|
115
129
|
unique("secret_versions_secret_id_version_key").on(table.secretId, table.version),
|
|
116
130
|
check("secret_versions_version_check", sql`${table.version} > 0`),
|
|
@@ -267,6 +281,7 @@ const auditLog = sqliteTable("audit_log", {
|
|
|
267
281
|
index("audit_log_subject_idx").on(table.author, table.subjectPrincipal, table.seq),
|
|
268
282
|
index("audit_log_unbind_idx").on(sql`json_extract(${table.metadata}, '$.bindingId')`).where(sql`${table.author} = 'app' AND ${table.action} = 'token.unbind' AND ${table.decision} = 'allow'`),
|
|
269
283
|
index("audit_log_exchange_idx").on(sql`json_extract(${table.metadata}, '$.credentialId')`).where(sql`${table.author} = 'app' AND ${table.action} = 'token.exchange' AND ${table.decision} = 'allow'`),
|
|
284
|
+
index("audit_log_token_create_idx").on(sql`json_extract(${table.metadata}, '$.targetCredentialId')`).where(sql`${table.author} = 'app' AND ${table.action} = 'token.create' AND ${table.decision} = 'allow'`),
|
|
270
285
|
index("audit_log_reference_end_idx").on(table.relatedSeq).where(sql`${table.author} = 'vault' AND ${table.action} = 'reference.end' AND ${table.decision} = 'allow'`),
|
|
271
286
|
index("audit_log_also_project_idx").on(sql`json_extract(${table.metadata}, '$.also.projectId')`, table.seq).where(sql`json_extract(${table.metadata}, '$.also') IS NOT NULL`),
|
|
272
287
|
index("audit_log_also_environment_idx").on(sql`json_extract(${table.metadata}, '$.also.environmentId')`, table.seq).where(sql`json_extract(${table.metadata}, '$.also') IS NOT NULL`),
|
|
@@ -351,6 +366,7 @@ const serviceBindings = sqliteTable("service_bindings", {
|
|
|
351
366
|
profile: text().notNull(),
|
|
352
367
|
issuer: text().notNull(),
|
|
353
368
|
jwksUri: text("jwks_uri").notNull(),
|
|
369
|
+
jwks: text(),
|
|
354
370
|
claims: text().notNull(),
|
|
355
371
|
scope: text(),
|
|
356
372
|
label: text(),
|
|
@@ -481,7 +497,7 @@ const credentials = sqliteTable("credentials", {
|
|
|
481
497
|
revokedBy: text("revoked_by")
|
|
482
498
|
}, (table) => [
|
|
483
499
|
unique("credentials_token_hash_key").on(table.tokenHash),
|
|
484
|
-
check("credentials_kind_check", sql`${table.kind} IN ('browser', 'cli', 'service')`),
|
|
500
|
+
check("credentials_kind_check", sql`${table.kind} IN ('browser', 'cli', 'service', 'personal', 'handle')`),
|
|
485
501
|
check("credentials_principal_check", sql`${table.principal} LIKE 'user:%' OR ${table.principal} LIKE 'token:%'`),
|
|
486
502
|
check("credentials_kind_matches_principal", sql`(${table.kind} = 'service') = (${table.principal} LIKE 'token:%')`),
|
|
487
503
|
check("credentials_token_hash_check", sql`octet_length(${table.tokenHash}) = 32`),
|
package/dist/schema-version.d.ts
CHANGED
package/dist/schema-version.js
CHANGED
|
@@ -36,6 +36,48 @@ const KNOWN_MIGRATIONS = {
|
|
|
36
36
|
"when": 1791676486914,
|
|
37
37
|
"tag": "0003_credential_scopes",
|
|
38
38
|
"breakpoints": true
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"idx": 4,
|
|
42
|
+
"version": "7",
|
|
43
|
+
"when": 1792244020330,
|
|
44
|
+
"tag": "0004_environment_parents",
|
|
45
|
+
"breakpoints": true
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"idx": 5,
|
|
49
|
+
"version": "7",
|
|
50
|
+
"when": 1792250909587,
|
|
51
|
+
"tag": "0005_personal_tokens",
|
|
52
|
+
"breakpoints": true
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"idx": 6,
|
|
56
|
+
"version": "7",
|
|
57
|
+
"when": 1792252693050,
|
|
58
|
+
"tag": "0006_uploaded_keys",
|
|
59
|
+
"breakpoints": true
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"idx": 7,
|
|
63
|
+
"version": "7",
|
|
64
|
+
"when": 1792253794481,
|
|
65
|
+
"tag": "0007_personal_configs",
|
|
66
|
+
"breakpoints": true
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"idx": 8,
|
|
70
|
+
"version": "7",
|
|
71
|
+
"when": 1792255559691,
|
|
72
|
+
"tag": "0008_recipes",
|
|
73
|
+
"breakpoints": true
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"idx": 9,
|
|
77
|
+
"version": "7",
|
|
78
|
+
"when": 1792281879553,
|
|
79
|
+
"tag": "0009_handles",
|
|
80
|
+
"breakpoints": true
|
|
39
81
|
}
|
|
40
82
|
].map((entry) => entry.tag),
|
|
41
83
|
sqlite: [
|
|
@@ -66,6 +108,48 @@ const KNOWN_MIGRATIONS = {
|
|
|
66
108
|
"when": 1791676487593,
|
|
67
109
|
"tag": "0003_credential_scopes",
|
|
68
110
|
"breakpoints": true
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"idx": 4,
|
|
114
|
+
"version": "6",
|
|
115
|
+
"when": 1792244020959,
|
|
116
|
+
"tag": "0004_environment_parents",
|
|
117
|
+
"breakpoints": true
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"idx": 5,
|
|
121
|
+
"version": "6",
|
|
122
|
+
"when": 1792250910230,
|
|
123
|
+
"tag": "0005_personal_tokens",
|
|
124
|
+
"breakpoints": true
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
"idx": 6,
|
|
128
|
+
"version": "6",
|
|
129
|
+
"when": 1792252693912,
|
|
130
|
+
"tag": "0006_uploaded_keys",
|
|
131
|
+
"breakpoints": true
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"idx": 7,
|
|
135
|
+
"version": "6",
|
|
136
|
+
"when": 1792253795070,
|
|
137
|
+
"tag": "0007_personal_configs",
|
|
138
|
+
"breakpoints": true
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
"idx": 8,
|
|
142
|
+
"version": "6",
|
|
143
|
+
"when": 1792255560312,
|
|
144
|
+
"tag": "0008_recipes",
|
|
145
|
+
"breakpoints": true
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"idx": 9,
|
|
149
|
+
"version": "6",
|
|
150
|
+
"when": 1792281880190,
|
|
151
|
+
"tag": "0009_handles",
|
|
152
|
+
"breakpoints": true
|
|
69
153
|
}
|
|
70
154
|
].map((entry) => entry.tag)
|
|
71
155
|
};
|
package/dist/schema.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { _ as secrets, a as deviceAuthorizations, b as vaultGrants, c as environmentsRelations, d as mcpConnections, f as oauthClients, g as secretVersions, h as secretReferences, i as credentials, l as identities, n as auditLog, o as dismissedKeys, p as projects, r as consumedTokens, s as environments, t as auditChainHead, u as mcpApprovals, v as secretsRelations, x as vaultMembers, y as serviceBindings } from "./schema-
|
|
1
|
+
import { _ as secrets, a as deviceAuthorizations, b as vaultGrants, c as environmentsRelations, d as mcpConnections, f as oauthClients, g as secretVersions, h as secretReferences, i as credentials, l as identities, n as auditLog, o as dismissedKeys, p as projects, r as consumedTokens, s as environments, t as auditChainHead, u as mcpApprovals, v as secretsRelations, x as vaultMembers, y as serviceBindings } from "./schema-BZRkBJQZ.js";
|
|
2
2
|
export { auditChainHead, auditLog, consumedTokens, credentials, deviceAuthorizations, dismissedKeys, environments, environmentsRelations, identities, mcpApprovals, mcpConnections, oauthClients, projects, secretReferences, secretVersions, secrets, secretsRelations, serviceBindings, vaultGrants, vaultMembers };
|
package/dist/schema.js
CHANGED
|
@@ -59,16 +59,27 @@ const environments = pgTable("environments", {
|
|
|
59
59
|
slug: text().notNull(),
|
|
60
60
|
name: text().notNull(),
|
|
61
61
|
createdAt: createdAt(),
|
|
62
|
-
archivedAt: timestamp("archived_at", { withTimezone: true })
|
|
62
|
+
archivedAt: timestamp("archived_at", { withTimezone: true }),
|
|
63
|
+
parentId: uuid("parent_id"),
|
|
64
|
+
owner: text()
|
|
63
65
|
}, (table) => [
|
|
64
66
|
unique("environments_project_id_slug_key").on(table.projectId, table.slug),
|
|
65
67
|
unique("environments_project_scoped").on(table.id, table.projectId),
|
|
66
68
|
check("environments_slug_check", sql`${table.slug} ~ ${PLACE_SLUG}`),
|
|
69
|
+
check("environments_parent_check", sql`${table.parentId} IS NULL OR ${table.parentId} <> ${table.id}`),
|
|
70
|
+
check("environments_owner_check", sql`${table.owner} IS NULL OR (${table.parentId} IS NOT NULL AND ${table.owner} LIKE 'user:_%')`),
|
|
71
|
+
uniqueIndex("environments_parent_id_owner_key").on(table.parentId, table.owner).where(sql`strpos(${table.slug}, '~') = 0`),
|
|
67
72
|
foreignKey({
|
|
68
73
|
name: "environments_project_id_fkey",
|
|
69
74
|
columns: [table.projectId],
|
|
70
75
|
foreignColumns: [projects.id]
|
|
71
|
-
}).onDelete("restrict")
|
|
76
|
+
}).onDelete("restrict"),
|
|
77
|
+
foreignKey({
|
|
78
|
+
name: "environments_parent_in_project",
|
|
79
|
+
columns: [table.parentId, table.projectId],
|
|
80
|
+
foreignColumns: [table.id, table.projectId]
|
|
81
|
+
}).onDelete("no action"),
|
|
82
|
+
index("environments_parent_idx").on(table.parentId)
|
|
72
83
|
]);
|
|
73
84
|
const secrets = pgTable("secrets", {
|
|
74
85
|
id: uuid().primaryKey().defaultRandom(),
|
|
@@ -115,7 +126,10 @@ const secretVersions = pgTable("secret_versions", {
|
|
|
115
126
|
kekId: text("kek_id").notNull(),
|
|
116
127
|
kekVersion: text("kek_version").notNull(),
|
|
117
128
|
createdAt: createdAt(),
|
|
118
|
-
createdBy: text("created_by").notNull()
|
|
129
|
+
createdBy: text("created_by").notNull(),
|
|
130
|
+
recipe: text(),
|
|
131
|
+
pairId: uuid("pair_id"),
|
|
132
|
+
pairHalf: text("pair_half")
|
|
119
133
|
}, (table) => [
|
|
120
134
|
unique("secret_versions_secret_id_version_key").on(table.secretId, table.version),
|
|
121
135
|
check("secret_versions_version_check", sql`${table.version} > 0`),
|
|
@@ -292,6 +306,7 @@ const auditLog = pgTable("audit_log", {
|
|
|
292
306
|
index("audit_log_subject_idx").on(table.author, table.subjectPrincipal, table.seq),
|
|
293
307
|
index("audit_log_unbind_idx").on(sql`((${table.metadata})::jsonb ->> 'bindingId')`).where(sql`${table.author} = 'app' AND ${table.action} = 'token.unbind' AND ${table.decision} = 'allow'`),
|
|
294
308
|
index("audit_log_exchange_idx").on(sql`((${table.metadata})::jsonb ->> 'credentialId')`).where(sql`${table.author} = 'app' AND ${table.action} = 'token.exchange' AND ${table.decision} = 'allow'`),
|
|
309
|
+
index("audit_log_token_create_idx").on(sql`((${table.metadata})::jsonb ->> 'targetCredentialId')`).where(sql`${table.author} = 'app' AND ${table.action} = 'token.create' AND ${table.decision} = 'allow'`),
|
|
295
310
|
index("audit_log_reference_end_idx").on(table.relatedSeq).where(sql`${table.author} = 'vault' AND ${table.action} = 'reference.end' AND ${table.decision} = 'allow'`),
|
|
296
311
|
index("audit_log_also_project_idx").on(sql`(((${table.metadata})::jsonb -> 'also') ->> 'projectId')`, table.seq).where(sql`((${table.metadata})::jsonb -> 'also') IS NOT NULL`),
|
|
297
312
|
index("audit_log_also_environment_idx").on(sql`(((${table.metadata})::jsonb -> 'also') ->> 'environmentId')`, table.seq).where(sql`((${table.metadata})::jsonb -> 'also') IS NOT NULL`),
|
|
@@ -399,6 +414,7 @@ const serviceBindings = pgTable("service_bindings", {
|
|
|
399
414
|
profile: text().notNull(),
|
|
400
415
|
issuer: text().notNull(),
|
|
401
416
|
jwksUri: text("jwks_uri").notNull(),
|
|
417
|
+
jwks: text(),
|
|
402
418
|
claims: text().notNull(),
|
|
403
419
|
scope: text(),
|
|
404
420
|
label: text(),
|
|
@@ -547,7 +563,7 @@ const credentials = pgTable("credentials", {
|
|
|
547
563
|
revokedBy: text("revoked_by")
|
|
548
564
|
}, (table) => [
|
|
549
565
|
unique("credentials_token_hash_key").on(table.tokenHash),
|
|
550
|
-
check("credentials_kind_check", sql`${table.kind} IN ('browser', 'cli', 'service')`),
|
|
566
|
+
check("credentials_kind_check", sql`${table.kind} IN ('browser', 'cli', 'service', 'personal', 'handle')`),
|
|
551
567
|
check("credentials_principal_check", sql`${table.principal} LIKE 'user:%' OR ${table.principal} LIKE 'token:%'`),
|
|
552
568
|
check("credentials_kind_matches_principal", sql`(${table.kind} = 'service') = (${table.principal} LIKE 'token:%')`),
|
|
553
569
|
check("credentials_token_hash_check", sql`octet_length(${table.tokenHash}) = 32`),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coffre/db",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "coffre's database: the schema, its migrations and the connections, on Postgres or SQLite.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -79,7 +79,7 @@
|
|
|
79
79
|
"drizzle-orm": "0.45.2",
|
|
80
80
|
"pg": "8.16.3",
|
|
81
81
|
"pg-connection-string": "2.14.0",
|
|
82
|
-
"@coffre/core": "0.
|
|
82
|
+
"@coffre/core": "0.8.0"
|
|
83
83
|
},
|
|
84
84
|
"devDependencies": {
|
|
85
85
|
"@types/node": "26.1.1",
|
package/src/log.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { GENESIS_HASH, sealEntry, type LogFields, type LogKey, type StoredEntry } from '@coffre/core/audit';
|
|
2
|
-
import { and, desc, eq, lt } from 'drizzle-orm';
|
|
2
|
+
import { and, asc, desc, eq, lt, sql, type SQL } from 'drizzle-orm';
|
|
3
3
|
|
|
4
4
|
import { afterCommit } from './commits.ts';
|
|
5
5
|
import { tablesOf, type Queryable, type Transaction } from './database.ts';
|
|
@@ -218,6 +218,45 @@ export function entryColumns(db: Queryable) {
|
|
|
218
218
|
};
|
|
219
219
|
}
|
|
220
220
|
|
|
221
|
+
/**
|
|
222
|
+
* Metadata a reader of many entries holds at once, at most: an entry about
|
|
223
|
+
* a read of several secrets lists them, a thousand some 150 kilobytes, so a
|
|
224
|
+
* count of entries alone does not bound a batch's or a page's memory within
|
|
225
|
+
* a Worker's 128 megabytes.
|
|
226
|
+
*/
|
|
227
|
+
export const BATCH_BYTES = 8 * 1024 * 1024;
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Of the entries `where` matches, in `order` of seq, the first `limit` or
|
|
231
|
+
* fewer that hold no more than `BATCH_BYTES` of metadata between them, but
|
|
232
|
+
* always the first: the seqs they run from and to, and whether the bytes
|
|
233
|
+
* cut the run short of `limit`. Null when none matches. A reader asks this
|
|
234
|
+
* first, then reads `where` between the two.
|
|
235
|
+
*/
|
|
236
|
+
export async function withinBytes(
|
|
237
|
+
db: Queryable,
|
|
238
|
+
where: SQL | undefined,
|
|
239
|
+
limit: number,
|
|
240
|
+
order: 'asc' | 'desc' = 'asc',
|
|
241
|
+
): Promise<{ from: bigint; to: bigint; cut: boolean; count: number } | null> {
|
|
242
|
+
const { auditLog } = tablesOf(db);
|
|
243
|
+
const sizes = await db
|
|
244
|
+
.select({ seq: auditLog.seq, bytes: sql<number | string>`length(${auditLog.metadata})` })
|
|
245
|
+
.from(auditLog)
|
|
246
|
+
.where(where)
|
|
247
|
+
.orderBy(order === 'asc' ? asc(auditLog.seq) : desc(auditLog.seq))
|
|
248
|
+
.limit(limit);
|
|
249
|
+
let held = 0;
|
|
250
|
+
let count = 0;
|
|
251
|
+
for (const { bytes } of sizes) {
|
|
252
|
+
held += Number(bytes);
|
|
253
|
+
if (count > 0 && held > BATCH_BYTES) break;
|
|
254
|
+
count += 1;
|
|
255
|
+
}
|
|
256
|
+
if (count === 0) return null;
|
|
257
|
+
return { from: sizes[0]!.seq, to: sizes[count - 1]!.seq, cut: count < sizes.length, count };
|
|
258
|
+
}
|
|
259
|
+
|
|
221
260
|
/**
|
|
222
261
|
* How a reader tells the vault's own entries from those forged in its name:
|
|
223
262
|
* by their MAC, which only the vault holds the key to check. Each it finds
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
-- The app sets parent_id when it makes an environment, and never after: it gets no UPDATE grant, so a parent cannot change.
|
|
2
|
+
ALTER TABLE "environments" ADD COLUMN "parent_id" uuid;--> statement-breakpoint
|
|
3
|
+
ALTER TABLE "environments" ADD CONSTRAINT "environments_parent_in_project" FOREIGN KEY ("parent_id","project_id") REFERENCES "public"."environments"("id","project_id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
|
4
|
+
CREATE INDEX "environments_parent_idx" ON "environments" USING btree ("parent_id");--> statement-breakpoint
|
|
5
|
+
ALTER TABLE "environments" ADD CONSTRAINT "environments_parent_check" CHECK ("environments"."parent_id" IS NULL OR "environments"."parent_id" <> "environments"."id");
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
-- Personal tokens (0.7). The check widens to their kind: the release before makes none, and refuses one, whose prefix, coffre_pat_, it does not take for a token.
|
|
2
|
+
ALTER TABLE "credentials" DROP CONSTRAINT "credentials_kind_check";--> statement-breakpoint
|
|
3
|
+
ALTER TABLE "credentials" ADD CONSTRAINT "credentials_kind_check" CHECK ("credentials"."kind" IN ('browser', 'cli', 'service', 'personal'));--> statement-breakpoint
|
|
4
|
+
-- A token's creation, by the credential's ID: the label a personal token's entries are shown with.
|
|
5
|
+
CREATE INDEX "audit_log_token_create_idx" ON "audit_log" USING btree ((("metadata")::jsonb ->> 'targetCredentialId')) WHERE "audit_log"."author" = 'app' AND "audit_log"."action" = 'token.create' AND "audit_log"."decision" = 'allow';
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
-- The app sets owner when it makes a personal config, and never after: it gets no UPDATE grant, so an owner cannot change. The vault binds each value to it, so a forged owner opens nothing.
|
|
2
|
+
ALTER TABLE "environments" ADD COLUMN "owner" text;--> statement-breakpoint
|
|
3
|
+
CREATE UNIQUE INDEX "environments_parent_id_owner_key" ON "environments" USING btree ("parent_id","owner") WHERE strpos("environments"."slug", '~') = 0;--> statement-breakpoint
|
|
4
|
+
ALTER TABLE "environments" ADD CONSTRAINT "environments_owner_check" CHECK ("environments"."owner" IS NULL OR ("environments"."parent_id" IS NOT NULL AND "environments"."owner" LIKE 'user:_%'));
|