@coffre/db 0.10.1 → 0.11.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-DBtn3jqp.d.ts → database-Dh4W2pAj.d.ts} +1 -1
- package/dist/dialect.d.ts +7 -1
- package/dist/dialect.js +10 -1
- package/dist/grants.d.ts +12 -5
- package/dist/grants.js +13 -8
- package/dist/hyperdrive.d.ts +9 -2
- package/dist/hyperdrive.js +16 -2
- package/dist/index.d.ts +2 -2
- package/dist/log.d.ts +65 -3
- package/dist/log.js +26 -14
- package/dist/migrations/postgres/0015_workload_access.sql +43 -0
- package/dist/migrations/postgres/0016_spent_tokens.sql +12 -0
- package/dist/migrations/postgres/meta/0015_snapshot.json +3256 -0
- package/dist/migrations/postgres/meta/0016_snapshot.json +3256 -0
- package/dist/migrations/postgres/meta/_journal.json +14 -0
- package/dist/migrations/sqlite/0015_workload_access.sql +70 -0
- package/dist/migrations/sqlite/meta/0015_snapshot.json +2959 -0
- package/dist/migrations/sqlite/meta/_journal.json +7 -0
- package/dist/portable.d.ts +2 -2
- package/dist/{schema-NBVA9q-s.d.ts → schema-DG2t57Kf.d.ts} +327 -2
- package/dist/schema-sqlite.d.ts +346 -1
- package/dist/schema-sqlite.js +53 -5
- package/dist/schema-version.d.ts +1 -1
- package/dist/schema-version.js +21 -0
- package/dist/schema.d.ts +2 -2
- package/dist/schema.js +54 -5
- package/package.json +2 -2
- package/src/dialect.ts +10 -0
- package/src/grants.ts +18 -9
- package/src/hyperdrive.ts +16 -2
- package/src/log.ts +35 -10
- package/src/migrations/postgres/0015_workload_access.sql +43 -0
- package/src/migrations/postgres/0016_spent_tokens.sql +12 -0
- package/src/migrations/postgres/meta/0015_snapshot.json +3256 -0
- package/src/migrations/postgres/meta/0016_snapshot.json +3256 -0
- package/src/migrations/postgres/meta/_journal.json +14 -0
- package/src/migrations/sqlite/0015_workload_access.sql +70 -0
- package/src/migrations/sqlite/meta/0015_snapshot.json +2959 -0
- package/src/migrations/sqlite/meta/_journal.json +7 -0
- package/src/schema.sqlite.ts +73 -2
- package/src/schema.ts +73 -2
package/dist/schema-sqlite.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
declare namespace schema_sqlite_d_exports {
|
|
2
|
-
export { auditChainHead, auditLog, consumedTokens, credentials, deviceAuthorizations, dismissedKeys, environments, environmentsRelations, identities, mcpApprovals, mcpConnections, oauthClients, projects, secretReferences, secretVersions, secrets, secretsRelations, serviceBindings, vaultGrants, vaultMembers };
|
|
2
|
+
export { auditChainHead, auditLog, consumedTokens, credentials, deviceAuthorizations, dismissedKeys, enrollments, environments, environmentsRelations, identities, mcpApprovals, mcpConnections, oauthClients, projects, secretReferences, secretVersions, secrets, secretsRelations, serviceBindings, vaultGrants, vaultMembers };
|
|
3
3
|
}
|
|
4
4
|
export declare const projects: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
|
|
5
5
|
name: "projects";
|
|
@@ -2400,6 +2400,25 @@ export declare const serviceBindings: import("drizzle-orm/sqlite-core").SQLiteTa
|
|
|
2400
2400
|
}, {}, {
|
|
2401
2401
|
length: undefined;
|
|
2402
2402
|
}>;
|
|
2403
|
+
policy: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
2404
|
+
name: "policy";
|
|
2405
|
+
tableName: "service_bindings";
|
|
2406
|
+
dataType: "string";
|
|
2407
|
+
columnType: "SQLiteText";
|
|
2408
|
+
data: string;
|
|
2409
|
+
driverParam: string;
|
|
2410
|
+
notNull: false;
|
|
2411
|
+
hasDefault: false;
|
|
2412
|
+
isPrimaryKey: false;
|
|
2413
|
+
isAutoincrement: false;
|
|
2414
|
+
hasRuntimeDefault: false;
|
|
2415
|
+
enumValues: [string, ...string[]];
|
|
2416
|
+
baseColumn: never;
|
|
2417
|
+
identity: undefined;
|
|
2418
|
+
generated: undefined;
|
|
2419
|
+
}, {}, {
|
|
2420
|
+
length: undefined;
|
|
2421
|
+
}>;
|
|
2403
2422
|
label: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
2404
2423
|
name: "label";
|
|
2405
2424
|
tableName: "service_bindings";
|
|
@@ -3294,6 +3313,203 @@ export declare const mcpApprovals: import("drizzle-orm/sqlite-core").SQLiteTable
|
|
|
3294
3313
|
};
|
|
3295
3314
|
dialect: "sqlite";
|
|
3296
3315
|
}>;
|
|
3316
|
+
/**
|
|
3317
|
+
* Enrollment codes (docs/design/workload-access.md, section 4.4): what CI
|
|
3318
|
+
* mints for a platform that signs no identity, and the app exchanges for a
|
|
3319
|
+
* workload's session at `/api/auth/workload`. Never a credential itself, and
|
|
3320
|
+
* only ever added: the log says which code a promote superseded. Its scope,
|
|
3321
|
+
* fixed at minting, is the binding's within what the minter held; the MAC
|
|
3322
|
+
* covers everything but its hint and creation time (auth-rows.ts in the server).
|
|
3323
|
+
*/
|
|
3324
|
+
export declare const enrollments: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
|
|
3325
|
+
name: "enrollments";
|
|
3326
|
+
schema: undefined;
|
|
3327
|
+
columns: {
|
|
3328
|
+
id: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
3329
|
+
name: "id";
|
|
3330
|
+
tableName: "enrollments";
|
|
3331
|
+
dataType: "string";
|
|
3332
|
+
columnType: "SQLiteText";
|
|
3333
|
+
data: string;
|
|
3334
|
+
driverParam: string;
|
|
3335
|
+
notNull: true;
|
|
3336
|
+
hasDefault: false;
|
|
3337
|
+
isPrimaryKey: true;
|
|
3338
|
+
isAutoincrement: false;
|
|
3339
|
+
hasRuntimeDefault: false;
|
|
3340
|
+
enumValues: [string, ...string[]];
|
|
3341
|
+
baseColumn: never;
|
|
3342
|
+
identity: undefined;
|
|
3343
|
+
generated: undefined;
|
|
3344
|
+
}, {}, {
|
|
3345
|
+
length: undefined;
|
|
3346
|
+
}>;
|
|
3347
|
+
authMac: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
3348
|
+
name: string;
|
|
3349
|
+
tableName: "enrollments";
|
|
3350
|
+
dataType: "buffer";
|
|
3351
|
+
columnType: "SQLiteBlobBuffer";
|
|
3352
|
+
data: Buffer<ArrayBufferLike>;
|
|
3353
|
+
driverParam: Buffer<ArrayBufferLike>;
|
|
3354
|
+
notNull: true;
|
|
3355
|
+
hasDefault: false;
|
|
3356
|
+
isPrimaryKey: false;
|
|
3357
|
+
isAutoincrement: false;
|
|
3358
|
+
hasRuntimeDefault: false;
|
|
3359
|
+
enumValues: undefined;
|
|
3360
|
+
baseColumn: never;
|
|
3361
|
+
identity: undefined;
|
|
3362
|
+
generated: undefined;
|
|
3363
|
+
}, {}, {}>;
|
|
3364
|
+
bindingId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
3365
|
+
name: "binding_id";
|
|
3366
|
+
tableName: "enrollments";
|
|
3367
|
+
dataType: "string";
|
|
3368
|
+
columnType: "SQLiteText";
|
|
3369
|
+
data: string;
|
|
3370
|
+
driverParam: string;
|
|
3371
|
+
notNull: true;
|
|
3372
|
+
hasDefault: false;
|
|
3373
|
+
isPrimaryKey: false;
|
|
3374
|
+
isAutoincrement: false;
|
|
3375
|
+
hasRuntimeDefault: false;
|
|
3376
|
+
enumValues: [string, ...string[]];
|
|
3377
|
+
baseColumn: never;
|
|
3378
|
+
identity: undefined;
|
|
3379
|
+
generated: undefined;
|
|
3380
|
+
}, {}, {
|
|
3381
|
+
length: number | undefined;
|
|
3382
|
+
}>;
|
|
3383
|
+
codeHash: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
3384
|
+
name: string;
|
|
3385
|
+
tableName: "enrollments";
|
|
3386
|
+
dataType: "buffer";
|
|
3387
|
+
columnType: "SQLiteBlobBuffer";
|
|
3388
|
+
data: Buffer<ArrayBufferLike>;
|
|
3389
|
+
driverParam: Buffer<ArrayBufferLike>;
|
|
3390
|
+
notNull: true;
|
|
3391
|
+
hasDefault: false;
|
|
3392
|
+
isPrimaryKey: false;
|
|
3393
|
+
isAutoincrement: false;
|
|
3394
|
+
hasRuntimeDefault: false;
|
|
3395
|
+
enumValues: undefined;
|
|
3396
|
+
baseColumn: never;
|
|
3397
|
+
identity: undefined;
|
|
3398
|
+
generated: undefined;
|
|
3399
|
+
}, {}, {}>;
|
|
3400
|
+
codeHint: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
3401
|
+
name: "code_hint";
|
|
3402
|
+
tableName: "enrollments";
|
|
3403
|
+
dataType: "string";
|
|
3404
|
+
columnType: "SQLiteText";
|
|
3405
|
+
data: string;
|
|
3406
|
+
driverParam: string;
|
|
3407
|
+
notNull: true;
|
|
3408
|
+
hasDefault: false;
|
|
3409
|
+
isPrimaryKey: false;
|
|
3410
|
+
isAutoincrement: false;
|
|
3411
|
+
hasRuntimeDefault: false;
|
|
3412
|
+
enumValues: [string, ...string[]];
|
|
3413
|
+
baseColumn: never;
|
|
3414
|
+
identity: undefined;
|
|
3415
|
+
generated: undefined;
|
|
3416
|
+
}, {}, {
|
|
3417
|
+
length: number | undefined;
|
|
3418
|
+
}>;
|
|
3419
|
+
scope: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
3420
|
+
name: "scope";
|
|
3421
|
+
tableName: "enrollments";
|
|
3422
|
+
dataType: "string";
|
|
3423
|
+
columnType: "SQLiteText";
|
|
3424
|
+
data: string;
|
|
3425
|
+
driverParam: string;
|
|
3426
|
+
notNull: true;
|
|
3427
|
+
hasDefault: false;
|
|
3428
|
+
isPrimaryKey: false;
|
|
3429
|
+
isAutoincrement: false;
|
|
3430
|
+
hasRuntimeDefault: false;
|
|
3431
|
+
enumValues: [string, ...string[]];
|
|
3432
|
+
baseColumn: never;
|
|
3433
|
+
identity: undefined;
|
|
3434
|
+
generated: undefined;
|
|
3435
|
+
}, {}, {
|
|
3436
|
+
length: undefined;
|
|
3437
|
+
}>;
|
|
3438
|
+
createdAt: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
3439
|
+
name: string;
|
|
3440
|
+
tableName: "enrollments";
|
|
3441
|
+
dataType: "date";
|
|
3442
|
+
columnType: "SQLiteTimestamp";
|
|
3443
|
+
data: Date;
|
|
3444
|
+
driverParam: number;
|
|
3445
|
+
notNull: true;
|
|
3446
|
+
hasDefault: true;
|
|
3447
|
+
isPrimaryKey: false;
|
|
3448
|
+
isAutoincrement: false;
|
|
3449
|
+
hasRuntimeDefault: false;
|
|
3450
|
+
enumValues: undefined;
|
|
3451
|
+
baseColumn: never;
|
|
3452
|
+
identity: undefined;
|
|
3453
|
+
generated: undefined;
|
|
3454
|
+
}, {}, {}>;
|
|
3455
|
+
createdBy: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
3456
|
+
name: "created_by";
|
|
3457
|
+
tableName: "enrollments";
|
|
3458
|
+
dataType: "string";
|
|
3459
|
+
columnType: "SQLiteText";
|
|
3460
|
+
data: string;
|
|
3461
|
+
driverParam: string;
|
|
3462
|
+
notNull: true;
|
|
3463
|
+
hasDefault: false;
|
|
3464
|
+
isPrimaryKey: false;
|
|
3465
|
+
isAutoincrement: false;
|
|
3466
|
+
hasRuntimeDefault: false;
|
|
3467
|
+
enumValues: [string, ...string[]];
|
|
3468
|
+
baseColumn: never;
|
|
3469
|
+
identity: undefined;
|
|
3470
|
+
generated: undefined;
|
|
3471
|
+
}, {}, {
|
|
3472
|
+
length: number | undefined;
|
|
3473
|
+
}>;
|
|
3474
|
+
createdWith: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
3475
|
+
name: "created_with";
|
|
3476
|
+
tableName: "enrollments";
|
|
3477
|
+
dataType: "string";
|
|
3478
|
+
columnType: "SQLiteText";
|
|
3479
|
+
data: string;
|
|
3480
|
+
driverParam: string;
|
|
3481
|
+
notNull: false;
|
|
3482
|
+
hasDefault: false;
|
|
3483
|
+
isPrimaryKey: false;
|
|
3484
|
+
isAutoincrement: false;
|
|
3485
|
+
hasRuntimeDefault: false;
|
|
3486
|
+
enumValues: [string, ...string[]];
|
|
3487
|
+
baseColumn: never;
|
|
3488
|
+
identity: undefined;
|
|
3489
|
+
generated: undefined;
|
|
3490
|
+
}, {}, {
|
|
3491
|
+
length: number | undefined;
|
|
3492
|
+
}>;
|
|
3493
|
+
expiresAt: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
3494
|
+
name: string;
|
|
3495
|
+
tableName: "enrollments";
|
|
3496
|
+
dataType: "date";
|
|
3497
|
+
columnType: "SQLiteTimestamp";
|
|
3498
|
+
data: Date;
|
|
3499
|
+
driverParam: number;
|
|
3500
|
+
notNull: true;
|
|
3501
|
+
hasDefault: false;
|
|
3502
|
+
isPrimaryKey: false;
|
|
3503
|
+
isAutoincrement: false;
|
|
3504
|
+
hasRuntimeDefault: false;
|
|
3505
|
+
enumValues: undefined;
|
|
3506
|
+
baseColumn: never;
|
|
3507
|
+
identity: undefined;
|
|
3508
|
+
generated: undefined;
|
|
3509
|
+
}, {}, {}>;
|
|
3510
|
+
};
|
|
3511
|
+
dialect: "sqlite";
|
|
3512
|
+
}>;
|
|
3297
3513
|
export declare const credentials: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
|
|
3298
3514
|
name: "credentials";
|
|
3299
3515
|
schema: undefined;
|
|
@@ -3626,6 +3842,135 @@ export declare const credentials: import("drizzle-orm/sqlite-core").SQLiteTableW
|
|
|
3626
3842
|
}, {}, {
|
|
3627
3843
|
length: number | undefined;
|
|
3628
3844
|
}>;
|
|
3845
|
+
jkt: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
3846
|
+
name: "jkt";
|
|
3847
|
+
tableName: "credentials";
|
|
3848
|
+
dataType: "string";
|
|
3849
|
+
columnType: "SQLiteText";
|
|
3850
|
+
data: string;
|
|
3851
|
+
driverParam: string;
|
|
3852
|
+
notNull: false;
|
|
3853
|
+
hasDefault: false;
|
|
3854
|
+
isPrimaryKey: false;
|
|
3855
|
+
isAutoincrement: false;
|
|
3856
|
+
hasRuntimeDefault: false;
|
|
3857
|
+
enumValues: [string, ...string[]];
|
|
3858
|
+
baseColumn: never;
|
|
3859
|
+
identity: undefined;
|
|
3860
|
+
generated: undefined;
|
|
3861
|
+
}, {}, {
|
|
3862
|
+
length: undefined;
|
|
3863
|
+
}>;
|
|
3864
|
+
notAfter: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
3865
|
+
name: string;
|
|
3866
|
+
tableName: "credentials";
|
|
3867
|
+
dataType: "date";
|
|
3868
|
+
columnType: "SQLiteTimestamp";
|
|
3869
|
+
data: Date;
|
|
3870
|
+
driverParam: number;
|
|
3871
|
+
notNull: false;
|
|
3872
|
+
hasDefault: false;
|
|
3873
|
+
isPrimaryKey: false;
|
|
3874
|
+
isAutoincrement: false;
|
|
3875
|
+
hasRuntimeDefault: false;
|
|
3876
|
+
enumValues: undefined;
|
|
3877
|
+
baseColumn: never;
|
|
3878
|
+
identity: undefined;
|
|
3879
|
+
generated: undefined;
|
|
3880
|
+
}, {}, {}>;
|
|
3881
|
+
ancestors: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
3882
|
+
name: "ancestors";
|
|
3883
|
+
tableName: "credentials";
|
|
3884
|
+
dataType: "string";
|
|
3885
|
+
columnType: "SQLiteText";
|
|
3886
|
+
data: string;
|
|
3887
|
+
driverParam: string;
|
|
3888
|
+
notNull: false;
|
|
3889
|
+
hasDefault: false;
|
|
3890
|
+
isPrimaryKey: false;
|
|
3891
|
+
isAutoincrement: false;
|
|
3892
|
+
hasRuntimeDefault: false;
|
|
3893
|
+
enumValues: [string, ...string[]];
|
|
3894
|
+
baseColumn: never;
|
|
3895
|
+
identity: undefined;
|
|
3896
|
+
generated: undefined;
|
|
3897
|
+
}, {}, {
|
|
3898
|
+
length: undefined;
|
|
3899
|
+
}>;
|
|
3900
|
+
constraints: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
3901
|
+
name: "constraints";
|
|
3902
|
+
tableName: "credentials";
|
|
3903
|
+
dataType: "string";
|
|
3904
|
+
columnType: "SQLiteText";
|
|
3905
|
+
data: string;
|
|
3906
|
+
driverParam: string;
|
|
3907
|
+
notNull: false;
|
|
3908
|
+
hasDefault: false;
|
|
3909
|
+
isPrimaryKey: false;
|
|
3910
|
+
isAutoincrement: false;
|
|
3911
|
+
hasRuntimeDefault: false;
|
|
3912
|
+
enumValues: [string, ...string[]];
|
|
3913
|
+
baseColumn: never;
|
|
3914
|
+
identity: undefined;
|
|
3915
|
+
generated: undefined;
|
|
3916
|
+
}, {}, {
|
|
3917
|
+
length: undefined;
|
|
3918
|
+
}>;
|
|
3919
|
+
enrollmentId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
3920
|
+
name: "enrollment_id";
|
|
3921
|
+
tableName: "credentials";
|
|
3922
|
+
dataType: "string";
|
|
3923
|
+
columnType: "SQLiteText";
|
|
3924
|
+
data: string;
|
|
3925
|
+
driverParam: string;
|
|
3926
|
+
notNull: false;
|
|
3927
|
+
hasDefault: false;
|
|
3928
|
+
isPrimaryKey: false;
|
|
3929
|
+
isAutoincrement: false;
|
|
3930
|
+
hasRuntimeDefault: false;
|
|
3931
|
+
enumValues: [string, ...string[]];
|
|
3932
|
+
baseColumn: never;
|
|
3933
|
+
identity: undefined;
|
|
3934
|
+
generated: undefined;
|
|
3935
|
+
}, {}, {
|
|
3936
|
+
length: number | undefined;
|
|
3937
|
+
}>;
|
|
3938
|
+
approvedAt: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
3939
|
+
name: string;
|
|
3940
|
+
tableName: "credentials";
|
|
3941
|
+
dataType: "date";
|
|
3942
|
+
columnType: "SQLiteTimestamp";
|
|
3943
|
+
data: Date;
|
|
3944
|
+
driverParam: number;
|
|
3945
|
+
notNull: false;
|
|
3946
|
+
hasDefault: false;
|
|
3947
|
+
isPrimaryKey: false;
|
|
3948
|
+
isAutoincrement: false;
|
|
3949
|
+
hasRuntimeDefault: false;
|
|
3950
|
+
enumValues: undefined;
|
|
3951
|
+
baseColumn: never;
|
|
3952
|
+
identity: undefined;
|
|
3953
|
+
generated: undefined;
|
|
3954
|
+
}, {}, {}>;
|
|
3955
|
+
approvedBy: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
3956
|
+
name: "approved_by";
|
|
3957
|
+
tableName: "credentials";
|
|
3958
|
+
dataType: "string";
|
|
3959
|
+
columnType: "SQLiteText";
|
|
3960
|
+
data: string;
|
|
3961
|
+
driverParam: string;
|
|
3962
|
+
notNull: false;
|
|
3963
|
+
hasDefault: false;
|
|
3964
|
+
isPrimaryKey: false;
|
|
3965
|
+
isAutoincrement: false;
|
|
3966
|
+
hasRuntimeDefault: false;
|
|
3967
|
+
enumValues: [string, ...string[]];
|
|
3968
|
+
baseColumn: never;
|
|
3969
|
+
identity: undefined;
|
|
3970
|
+
generated: undefined;
|
|
3971
|
+
}, {}, {
|
|
3972
|
+
length: number | undefined;
|
|
3973
|
+
}>;
|
|
3629
3974
|
};
|
|
3630
3975
|
dialect: "sqlite";
|
|
3631
3976
|
}>;
|
package/dist/schema-sqlite.js
CHANGED
|
@@ -278,6 +278,8 @@ const auditLog = sqliteTable("audit_log", {
|
|
|
278
278
|
index("audit_log_releases_idx").on(table.author, table.actor, table.action, table.decision, table.occurredAt),
|
|
279
279
|
index("audit_log_subject_idx").on(table.author, table.subjectPrincipal, table.seq),
|
|
280
280
|
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'`),
|
|
281
|
+
index("audit_log_freeze_idx").on(sql`json_extract(${table.metadata}, '$.target')`, table.seq).where(sql`${table.author} = 'app' AND ${table.action} IN ('workload.freeze', 'workload.unfreeze') AND ${table.decision} = 'allow'`),
|
|
282
|
+
index("audit_log_supersede_idx").on(sql`json_extract(${table.metadata}, '$.enrollmentId')`).where(sql`${table.author} = 'app' AND ${table.action} = 'enrollment.supersede' AND ${table.decision} = 'allow'`),
|
|
281
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'`),
|
|
282
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'`),
|
|
283
285
|
index("audit_log_reference_end_idx").on(table.relatedSeq).where(sql`${table.author} = 'vault' AND ${table.action} = 'reference.end' AND ${table.decision} = 'allow'`),
|
|
@@ -367,6 +369,7 @@ const serviceBindings = sqliteTable("service_bindings", {
|
|
|
367
369
|
jwks: text(),
|
|
368
370
|
claims: text().notNull(),
|
|
369
371
|
scope: text(),
|
|
372
|
+
policy: text(),
|
|
370
373
|
label: text(),
|
|
371
374
|
createdAt: createdAt(),
|
|
372
375
|
createdBy: text("created_by").notNull(),
|
|
@@ -475,6 +478,37 @@ const mcpApprovals = sqliteTable("mcp_approvals", {
|
|
|
475
478
|
}).onDelete("restrict"),
|
|
476
479
|
index("mcp_approvals_open_idx").on(table.connectionId, table.digest).where(sql`${table.reportedAt} IS NULL`)
|
|
477
480
|
]);
|
|
481
|
+
/**
|
|
482
|
+
* Enrollment codes (docs/design/workload-access.md, section 4.4): what CI
|
|
483
|
+
* mints for a platform that signs no identity, and the app exchanges for a
|
|
484
|
+
* workload's session at `/api/auth/workload`. Never a credential itself, and
|
|
485
|
+
* only ever added: the log says which code a promote superseded. Its scope,
|
|
486
|
+
* fixed at minting, is the binding's within what the minter held; the MAC
|
|
487
|
+
* covers everything but its hint and creation time (auth-rows.ts in the server).
|
|
488
|
+
*/
|
|
489
|
+
const enrollments = sqliteTable("enrollments", {
|
|
490
|
+
id: text().primaryKey(),
|
|
491
|
+
authMac: bytes("auth_mac").notNull(),
|
|
492
|
+
bindingId: text("binding_id").notNull(),
|
|
493
|
+
codeHash: bytes("code_hash").notNull(),
|
|
494
|
+
codeHint: text("code_hint").notNull(),
|
|
495
|
+
scope: text().notNull(),
|
|
496
|
+
createdAt: createdAt(),
|
|
497
|
+
createdBy: text("created_by").notNull(),
|
|
498
|
+
createdWith: text("created_with"),
|
|
499
|
+
expiresAt: time("expires_at").notNull()
|
|
500
|
+
}, (table) => [
|
|
501
|
+
unique("enrollments_code_hash_key").on(table.codeHash),
|
|
502
|
+
check("enrollments_auth_mac_check", sql`octet_length(${table.authMac}) = 32`),
|
|
503
|
+
check("enrollments_code_hash_check", sql`octet_length(${table.codeHash}) = 32`),
|
|
504
|
+
check("enrollments_scope_check", sql`json_valid(${table.scope})`),
|
|
505
|
+
foreignKey({
|
|
506
|
+
name: "enrollments_binding_id_fkey",
|
|
507
|
+
columns: [table.bindingId],
|
|
508
|
+
foreignColumns: [serviceBindings.id]
|
|
509
|
+
}).onDelete("restrict"),
|
|
510
|
+
index("enrollments_binding_idx").on(table.bindingId, table.createdAt)
|
|
511
|
+
]);
|
|
478
512
|
const credentials = sqliteTable("credentials", {
|
|
479
513
|
id: text().primaryKey(),
|
|
480
514
|
kind: text().notNull(),
|
|
@@ -493,12 +527,20 @@ const credentials = sqliteTable("credentials", {
|
|
|
493
527
|
lastUsedAt: time("last_used_at"),
|
|
494
528
|
lastUsedIp: text("last_used_ip"),
|
|
495
529
|
revokedAt: time("revoked_at"),
|
|
496
|
-
revokedBy: text("revoked_by")
|
|
530
|
+
revokedBy: text("revoked_by"),
|
|
531
|
+
jkt: text(),
|
|
532
|
+
notAfter: time("not_after"),
|
|
533
|
+
ancestors: text(),
|
|
534
|
+
constraints: text(),
|
|
535
|
+
enrollmentId: text("enrollment_id"),
|
|
536
|
+
approvedAt: time("approved_at"),
|
|
537
|
+
approvedBy: text("approved_by")
|
|
497
538
|
}, (table) => [
|
|
498
539
|
unique("credentials_token_hash_key").on(table.tokenHash),
|
|
499
|
-
check("credentials_kind_check", sql`${table.kind} IN ('browser', 'cli', 'service', 'personal', 'handle')`),
|
|
540
|
+
check("credentials_kind_check", sql`${table.kind} IN ('browser', 'cli', 'service', 'personal', 'handle', 'workload')`),
|
|
500
541
|
check("credentials_principal_check", sql`${table.principal} LIKE 'user:%' OR ${table.principal} LIKE 'token:%'`),
|
|
501
|
-
check("credentials_kind_matches_principal", sql`(${table.kind}
|
|
542
|
+
check("credentials_kind_matches_principal", sql`(${table.kind} IN ('service', 'workload')) = (${table.principal} LIKE 'token:%')`),
|
|
543
|
+
check("credentials_workload_jkt_check", sql`${table.kind} <> 'workload' OR ${table.jkt} IS NOT NULL`),
|
|
502
544
|
check("credentials_token_hash_check", sql`octet_length(${table.tokenHash}) = 32`),
|
|
503
545
|
check("credentials_auth_mac_check", sql`octet_length(${table.authMac}) = 32`),
|
|
504
546
|
foreignKey({
|
|
@@ -521,7 +563,13 @@ const credentials = sqliteTable("credentials", {
|
|
|
521
563
|
}).onDelete("restrict"),
|
|
522
564
|
index("credentials_principal_idx").on(table.principal, table.generation),
|
|
523
565
|
index("credentials_live_idx").on(table.principal, table.expiresAt).where(sql`${table.revokedAt} IS NULL`),
|
|
524
|
-
index("credentials_issued_by_idx").on(table.principal, table.createdBy, table.createdAt)
|
|
566
|
+
index("credentials_issued_by_idx").on(table.principal, table.createdBy, table.createdAt),
|
|
567
|
+
foreignKey({
|
|
568
|
+
name: "credentials_enrollment_id_fkey",
|
|
569
|
+
columns: [table.enrollmentId],
|
|
570
|
+
foreignColumns: [enrollments.id]
|
|
571
|
+
}).onDelete("restrict"),
|
|
572
|
+
index("credentials_enrollment_roots_idx").on(table.enrollmentId, table.createdAt).where(sql`${table.kind} = 'workload' AND ${table.ancestors} IS NULL`)
|
|
525
573
|
]);
|
|
526
574
|
const deviceAuthorizations = sqliteTable("device_authorizations", {
|
|
527
575
|
id: text().primaryKey(),
|
|
@@ -560,4 +608,4 @@ const { environmentsRelations, secretsRelations } = relationsOf(asPostgres({
|
|
|
560
608
|
secretVersions
|
|
561
609
|
}));
|
|
562
610
|
//#endregion
|
|
563
|
-
export { auditChainHead, auditLog, consumedTokens, credentials, deviceAuthorizations, dismissedKeys, environments, environmentsRelations, identities, mcpApprovals, mcpConnections, oauthClients, projects, secretReferences, secretVersions, secrets, secretsRelations, serviceBindings, vaultGrants, vaultMembers };
|
|
611
|
+
export { auditChainHead, auditLog, consumedTokens, credentials, deviceAuthorizations, dismissedKeys, enrollments, environments, environmentsRelations, identities, mcpApprovals, mcpConnections, oauthClients, projects, secretReferences, secretVersions, secrets, secretsRelations, serviceBindings, vaultGrants, vaultMembers };
|
package/dist/schema-version.d.ts
CHANGED
package/dist/schema-version.js
CHANGED
|
@@ -113,6 +113,20 @@ const KNOWN_MIGRATIONS = {
|
|
|
113
113
|
"when": 1792345776262,
|
|
114
114
|
"tag": "0014_custom_roles",
|
|
115
115
|
"breakpoints": true
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"idx": 15,
|
|
119
|
+
"version": "7",
|
|
120
|
+
"when": 1792803757287,
|
|
121
|
+
"tag": "0015_workload_access",
|
|
122
|
+
"breakpoints": true
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
"idx": 16,
|
|
126
|
+
"version": "7",
|
|
127
|
+
"when": 1792814038307,
|
|
128
|
+
"tag": "0016_spent_tokens",
|
|
129
|
+
"breakpoints": true
|
|
116
130
|
}
|
|
117
131
|
].map((entry) => entry.tag),
|
|
118
132
|
sqlite: [
|
|
@@ -220,6 +234,13 @@ const KNOWN_MIGRATIONS = {
|
|
|
220
234
|
"when": 1792345777255,
|
|
221
235
|
"tag": "0014_custom_roles",
|
|
222
236
|
"breakpoints": true
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
"idx": 15,
|
|
240
|
+
"version": "6",
|
|
241
|
+
"when": 1792803757926,
|
|
242
|
+
"tag": "0015_workload_access",
|
|
243
|
+
"breakpoints": true
|
|
223
244
|
}
|
|
224
245
|
].map((entry) => entry.tag)
|
|
225
246
|
};
|
package/dist/schema.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { _ as
|
|
2
|
-
export { auditChainHead, auditLog, consumedTokens, credentials, deviceAuthorizations, dismissedKeys, environments, environmentsRelations, identities, mcpApprovals, mcpConnections, oauthClients, projects, secretReferences, secretVersions, secrets, secretsRelations, serviceBindings, vaultGrants, vaultMembers };
|
|
1
|
+
import { S as vaultMembers, _ as secretVersions, a as deviceAuthorizations, b as serviceBindings, c as environments, d as mcpApprovals, f as mcpConnections, g as secretReferences, i as credentials, l as environmentsRelations, m as projects, n as auditLog, o as dismissedKeys, p as oauthClients, r as consumedTokens, s as enrollments, t as auditChainHead, u as identities, v as secrets, x as vaultGrants, y as secretsRelations } from "./schema-DG2t57Kf.js";
|
|
2
|
+
export { auditChainHead, auditLog, consumedTokens, credentials, deviceAuthorizations, dismissedKeys, enrollments, environments, environmentsRelations, identities, mcpApprovals, mcpConnections, oauthClients, projects, secretReferences, secretVersions, secrets, secretsRelations, serviceBindings, vaultGrants, vaultMembers };
|
package/dist/schema.js
CHANGED
|
@@ -10,6 +10,7 @@ var schema_exports = /* @__PURE__ */ __exportAll({
|
|
|
10
10
|
credentials: () => credentials,
|
|
11
11
|
deviceAuthorizations: () => deviceAuthorizations,
|
|
12
12
|
dismissedKeys: () => dismissedKeys,
|
|
13
|
+
enrollments: () => enrollments,
|
|
13
14
|
environments: () => environments,
|
|
14
15
|
environmentsRelations: () => environmentsRelations,
|
|
15
16
|
identities: () => identities,
|
|
@@ -302,6 +303,8 @@ const auditLog = pgTable("audit_log", {
|
|
|
302
303
|
index("audit_log_releases_idx").on(table.author, table.actor, table.action, table.decision, table.occurredAt),
|
|
303
304
|
index("audit_log_subject_idx").on(table.author, table.subjectPrincipal, table.seq),
|
|
304
305
|
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'`),
|
|
306
|
+
index("audit_log_freeze_idx").on(sql`((${table.metadata})::jsonb ->> 'target')`, table.seq.desc()).where(sql`${table.author} = 'app' AND ${table.action} IN ('workload.freeze', 'workload.unfreeze') AND ${table.decision} = 'allow'`),
|
|
307
|
+
index("audit_log_supersede_idx").on(sql`((${table.metadata})::jsonb ->> 'enrollmentId')`).where(sql`${table.author} = 'app' AND ${table.action} = 'enrollment.supersede' AND ${table.decision} = 'allow'`),
|
|
305
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'`),
|
|
306
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'`),
|
|
307
310
|
index("audit_log_reference_end_idx").on(table.relatedSeq).where(sql`${table.author} = 'vault' AND ${table.action} = 'reference.end' AND ${table.decision} = 'allow'`),
|
|
@@ -414,6 +417,7 @@ const serviceBindings = pgTable("service_bindings", {
|
|
|
414
417
|
jwks: text(),
|
|
415
418
|
claims: text().notNull(),
|
|
416
419
|
scope: text(),
|
|
420
|
+
policy: text(),
|
|
417
421
|
label: text(),
|
|
418
422
|
createdAt: createdAt(),
|
|
419
423
|
createdBy: text("created_by").notNull(),
|
|
@@ -533,6 +537,37 @@ const mcpApprovals = pgTable("mcp_approvals", {
|
|
|
533
537
|
index("mcp_approvals_open_idx").on(table.connectionId, table.digest).where(sql`${table.reportedAt} IS NULL`)
|
|
534
538
|
]);
|
|
535
539
|
/**
|
|
540
|
+
* Enrollment codes (docs/design/workload-access.md, section 4.4): what CI
|
|
541
|
+
* mints for a platform that signs no identity, and the app exchanges for a
|
|
542
|
+
* workload's session at `/api/auth/workload`. Never a credential itself, and
|
|
543
|
+
* only ever added: the log says which code a promote superseded. Its scope,
|
|
544
|
+
* fixed at minting, is the binding's within what the minter held; the MAC
|
|
545
|
+
* covers everything but its hint and creation time (auth-rows.ts in the server).
|
|
546
|
+
*/
|
|
547
|
+
const enrollments = pgTable("enrollments", {
|
|
548
|
+
id: uuid().primaryKey(),
|
|
549
|
+
authMac: bytea("auth_mac").notNull(),
|
|
550
|
+
bindingId: uuid("binding_id").notNull(),
|
|
551
|
+
codeHash: bytea("code_hash").notNull(),
|
|
552
|
+
codeHint: text("code_hint").notNull(),
|
|
553
|
+
scope: text().notNull(),
|
|
554
|
+
createdAt: createdAt(),
|
|
555
|
+
createdBy: text("created_by").notNull(),
|
|
556
|
+
createdWith: uuid("created_with"),
|
|
557
|
+
expiresAt: timestamp("expires_at", { withTimezone: true }).notNull()
|
|
558
|
+
}, (table) => [
|
|
559
|
+
unique("enrollments_code_hash_key").on(table.codeHash),
|
|
560
|
+
check("enrollments_auth_mac_check", sql`octet_length(${table.authMac}) = 32`),
|
|
561
|
+
check("enrollments_code_hash_check", sql`octet_length(${table.codeHash}) = 32`),
|
|
562
|
+
check("enrollments_scope_check", sql`${table.scope}::jsonb IS NOT NULL`),
|
|
563
|
+
foreignKey({
|
|
564
|
+
name: "enrollments_binding_id_fkey",
|
|
565
|
+
columns: [table.bindingId],
|
|
566
|
+
foreignColumns: [serviceBindings.id]
|
|
567
|
+
}).onDelete("restrict"),
|
|
568
|
+
index("enrollments_binding_idx").on(table.bindingId, table.createdAt.desc())
|
|
569
|
+
]);
|
|
570
|
+
/**
|
|
536
571
|
* Bearer credentials coffre issues itself: browser sessions, CLI sessions and
|
|
537
572
|
* service tokens.
|
|
538
573
|
*
|
|
@@ -558,12 +593,20 @@ const credentials = pgTable("credentials", {
|
|
|
558
593
|
lastUsedAt: timestamp("last_used_at", { withTimezone: true }),
|
|
559
594
|
lastUsedIp: text("last_used_ip"),
|
|
560
595
|
revokedAt: timestamp("revoked_at", { withTimezone: true }),
|
|
561
|
-
revokedBy: text("revoked_by")
|
|
596
|
+
revokedBy: text("revoked_by"),
|
|
597
|
+
jkt: text(),
|
|
598
|
+
notAfter: timestamp("not_after", { withTimezone: true }),
|
|
599
|
+
ancestors: text(),
|
|
600
|
+
constraints: text(),
|
|
601
|
+
enrollmentId: uuid("enrollment_id"),
|
|
602
|
+
approvedAt: timestamp("approved_at", { withTimezone: true }),
|
|
603
|
+
approvedBy: text("approved_by")
|
|
562
604
|
}, (table) => [
|
|
563
605
|
unique("credentials_token_hash_key").on(table.tokenHash),
|
|
564
|
-
check("credentials_kind_check", sql`${table.kind} IN ('browser', 'cli', 'service', 'personal', 'handle')`),
|
|
606
|
+
check("credentials_kind_check", sql`${table.kind} IN ('browser', 'cli', 'service', 'personal', 'handle', 'workload')`),
|
|
565
607
|
check("credentials_principal_check", sql`${table.principal} LIKE 'user:%' OR ${table.principal} LIKE 'token:%'`),
|
|
566
|
-
check("credentials_kind_matches_principal", sql`(${table.kind}
|
|
608
|
+
check("credentials_kind_matches_principal", sql`(${table.kind} IN ('service', 'workload')) = (${table.principal} LIKE 'token:%')`),
|
|
609
|
+
check("credentials_workload_jkt_check", sql`${table.kind} <> 'workload' OR ${table.jkt} IS NOT NULL`),
|
|
567
610
|
check("credentials_token_hash_check", sql`octet_length(${table.tokenHash}) = 32`),
|
|
568
611
|
check("credentials_auth_mac_check", sql`octet_length(${table.authMac}) = 32`),
|
|
569
612
|
foreignKey({
|
|
@@ -586,7 +629,13 @@ const credentials = pgTable("credentials", {
|
|
|
586
629
|
}).onDelete("restrict"),
|
|
587
630
|
index("credentials_principal_idx").on(table.principal, table.generation),
|
|
588
631
|
index("credentials_live_idx").on(table.principal, table.expiresAt).where(sql`${table.revokedAt} IS NULL`),
|
|
589
|
-
index("credentials_issued_by_idx").on(table.principal, table.createdBy, table.createdAt)
|
|
632
|
+
index("credentials_issued_by_idx").on(table.principal, table.createdBy, table.createdAt),
|
|
633
|
+
foreignKey({
|
|
634
|
+
name: "credentials_enrollment_id_fkey",
|
|
635
|
+
columns: [table.enrollmentId],
|
|
636
|
+
foreignColumns: [enrollments.id]
|
|
637
|
+
}).onDelete("restrict"),
|
|
638
|
+
index("credentials_enrollment_roots_idx").on(table.enrollmentId, table.createdAt).where(sql`${table.kind} = 'workload' AND ${table.ancestors} IS NULL`)
|
|
590
639
|
]);
|
|
591
640
|
/**
|
|
592
641
|
* A CLI asking to be signed in from a browser (RFC 8628, device flow).
|
|
@@ -632,4 +681,4 @@ const { environmentsRelations, secretsRelations } = relationsOf({
|
|
|
632
681
|
secretVersions
|
|
633
682
|
});
|
|
634
683
|
//#endregion
|
|
635
|
-
export { auditChainHead, auditLog, consumedTokens, credentials, deviceAuthorizations, dismissedKeys, environments, environmentsRelations, identities, mcpApprovals, mcpConnections, oauthClients, projects, secretReferences, secretVersions, secrets, secretsRelations, serviceBindings, schema_exports as t, vaultGrants, vaultMembers };
|
|
684
|
+
export { auditChainHead, auditLog, consumedTokens, credentials, deviceAuthorizations, dismissedKeys, enrollments, environments, environmentsRelations, identities, mcpApprovals, mcpConnections, oauthClients, projects, secretReferences, secretVersions, secrets, secretsRelations, serviceBindings, schema_exports as t, vaultGrants, vaultMembers };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coffre/db",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.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.11.0"
|
|
83
83
|
},
|
|
84
84
|
"devDependencies": {
|
|
85
85
|
"@types/node": "26.1.1",
|
package/src/dialect.ts
CHANGED
|
@@ -49,6 +49,16 @@ export function forUpdate<Query extends { for: (strength: 'update' | 'no key upd
|
|
|
49
49
|
return query.for(strength) as ReturnType<Query['for']>;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
/**
|
|
53
|
+
* The rows a hand-written query answers, as the driver gives them: what
|
|
54
|
+
* Postgres's `execute` and SQLite's `all` each call a result. Column names
|
|
55
|
+
* are the query's own, unmapped.
|
|
56
|
+
*/
|
|
57
|
+
export async function rowsOf<Row>(db: Queryable, query: SQL): Promise<Row[]> {
|
|
58
|
+
if (engineOf(db) === 'postgres') return (await (db as unknown as { execute(query: SQL): Promise<{ rows: Row[] }> }).execute(query)).rows;
|
|
59
|
+
return (db as unknown as { all<R>(query: SQL): Promise<R[]> }).all<Row>(query);
|
|
60
|
+
}
|
|
61
|
+
|
|
52
62
|
/** Insert the rows whose unique keys are free; returns how many that was. */
|
|
53
63
|
export async function insertIfAbsent(db: Queryable, table: Table, rows: object[]): Promise<number> {
|
|
54
64
|
return changedRows(await db.insert(table).values(rows as never).onConflictDoNothing());
|