@coffre/db 0.2.0 → 0.4.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-Cq_52uUo.d.ts → database-edkMkG02.d.ts} +1 -1
- package/dist/dialect.d.ts +10 -2
- package/dist/dialect.js +34 -1
- package/dist/grants.d.ts +32 -0
- package/dist/grants.js +27 -0
- package/dist/hyperdrive.d.ts +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/log.d.ts +1 -1
- package/dist/migrate.js +6 -1
- package/dist/migrations/postgres/0000_baseline.sql +174 -46
- package/dist/migrations/postgres/0001_mcp_approvals.sql +24 -0
- package/dist/migrations/postgres/meta/0000_snapshot.json +963 -185
- package/dist/migrations/postgres/meta/0001_snapshot.json +1171 -30
- package/dist/migrations/postgres/meta/_journal.json +3 -24
- package/dist/migrations/sqlite/0000_baseline.sql +142 -35
- package/dist/migrations/sqlite/0001_mcp_approvals.sql +19 -0
- package/dist/migrations/sqlite/meta/0000_snapshot.json +878 -235
- package/dist/migrations/sqlite/meta/0001_snapshot.json +1062 -57
- package/dist/migrations/sqlite/meta/_journal.json +3 -24
- package/dist/portable.d.ts +2 -2
- package/dist/{schema-Wt-p8AOh.d.ts → schema-BqCB3XFm.d.ts} +1153 -83
- package/dist/schema-sqlite.d.ts +1171 -60
- package/dist/schema-sqlite.js +173 -11
- package/dist/schema-version.d.ts +9 -13
- package/dist/schema-version.js +38 -90
- package/dist/schema.d.ts +2 -2
- package/dist/schema.js +208 -15
- package/package.json +7 -2
- package/src/baseline/postgres.sql +46 -10
- package/src/baseline/sqlite.sql +15 -0
- package/src/baseline.ts +7 -3
- package/src/dialect.ts +25 -1
- package/src/grants.ts +51 -0
- package/src/migrate.ts +5 -0
- package/src/migrations/postgres/0000_baseline.sql +174 -46
- package/src/migrations/postgres/0001_mcp_approvals.sql +24 -0
- package/src/migrations/postgres/meta/0000_snapshot.json +963 -185
- package/src/migrations/postgres/meta/0001_snapshot.json +1171 -30
- package/src/migrations/postgres/meta/_journal.json +3 -24
- package/src/migrations/sqlite/0000_baseline.sql +142 -35
- package/src/migrations/sqlite/0001_mcp_approvals.sql +19 -0
- package/src/migrations/sqlite/meta/0000_snapshot.json +878 -235
- package/src/migrations/sqlite/meta/0001_snapshot.json +1062 -57
- package/src/migrations/sqlite/meta/_journal.json +3 -24
- package/src/schema-version.ts +26 -18
- package/src/schema.sqlite.ts +223 -8
- package/src/schema.ts +263 -11
- package/dist/migrations/postgres/0001_remove_syncs.sql +0 -13
- package/dist/migrations/postgres/0002_service_bindings.sql +0 -28
- package/dist/migrations/postgres/0003_exchanges.sql +0 -10
- package/dist/migrations/postgres/0004_live_indexes.sql +0 -3
- package/dist/migrations/postgres/meta/0002_snapshot.json +0 -1870
- package/dist/migrations/postgres/meta/0003_snapshot.json +0 -1917
- package/dist/migrations/postgres/meta/0004_snapshot.json +0 -2006
- package/dist/migrations/sqlite/0001_remove_syncs.sql +0 -13
- package/dist/migrations/sqlite/0002_service_bindings.sql +0 -23
- package/dist/migrations/sqlite/0003_exchanges.sql +0 -7
- package/dist/migrations/sqlite/0004_live_indexes.sql +0 -3
- package/dist/migrations/sqlite/meta/0002_snapshot.json +0 -1736
- package/dist/migrations/sqlite/meta/0003_snapshot.json +0 -1781
- package/dist/migrations/sqlite/meta/0004_snapshot.json +0 -1811
- package/src/migrations/postgres/0001_remove_syncs.sql +0 -13
- package/src/migrations/postgres/0002_service_bindings.sql +0 -28
- package/src/migrations/postgres/0003_exchanges.sql +0 -10
- package/src/migrations/postgres/0004_live_indexes.sql +0 -3
- package/src/migrations/postgres/meta/0002_snapshot.json +0 -1870
- package/src/migrations/postgres/meta/0003_snapshot.json +0 -1917
- package/src/migrations/postgres/meta/0004_snapshot.json +0 -2006
- package/src/migrations/sqlite/0001_remove_syncs.sql +0 -13
- package/src/migrations/sqlite/0002_service_bindings.sql +0 -23
- package/src/migrations/sqlite/0003_exchanges.sql +0 -7
- package/src/migrations/sqlite/0004_live_indexes.sql +0 -3
- package/src/migrations/sqlite/meta/0002_snapshot.json +0 -1736
- package/src/migrations/sqlite/meta/0003_snapshot.json +0 -1781
- package/src/migrations/sqlite/meta/0004_snapshot.json +0 -1811
|
@@ -33,7 +33,7 @@ CREATE TABLE "audit_log" (
|
|
|
33
33
|
"mac" "bytea" NOT NULL,
|
|
34
34
|
"hash" "bytea" NOT NULL,
|
|
35
35
|
CONSTRAINT "audit_log_author_check" CHECK ("audit_log"."author" IN ('app', 'vault')),
|
|
36
|
-
CONSTRAINT "audit_log_actor_check" CHECK ("audit_log"."actor" ~ '^(user|token|
|
|
36
|
+
CONSTRAINT "audit_log_actor_check" CHECK ("audit_log"."actor" ~ '^(user|token|system):.+$'),
|
|
37
37
|
CONSTRAINT "audit_log_decision_check" CHECK ("audit_log"."decision" IN ('allow', 'deny')),
|
|
38
38
|
CONSTRAINT "audit_log_metadata_check" CHECK ("audit_log"."metadata"::jsonb IS NOT NULL),
|
|
39
39
|
CONSTRAINT "audit_log_prev_hash_check" CHECK (octet_length("audit_log"."prev_hash") = 32),
|
|
@@ -41,6 +41,12 @@ CREATE TABLE "audit_log" (
|
|
|
41
41
|
CONSTRAINT "audit_log_hash_check" CHECK (octet_length("audit_log"."hash") = 32)
|
|
42
42
|
);
|
|
43
43
|
--> statement-breakpoint
|
|
44
|
+
CREATE TABLE "consumed_tokens" (
|
|
45
|
+
"hash" "bytea" PRIMARY KEY NOT NULL,
|
|
46
|
+
"consumed_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
47
|
+
CONSTRAINT "consumed_tokens_hash_check" CHECK (octet_length("consumed_tokens"."hash") = 32)
|
|
48
|
+
);
|
|
49
|
+
--> statement-breakpoint
|
|
44
50
|
CREATE TABLE "credentials" (
|
|
45
51
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
46
52
|
"kind" text NOT NULL,
|
|
@@ -91,6 +97,17 @@ CREATE TABLE "device_authorizations" (
|
|
|
91
97
|
)))
|
|
92
98
|
);
|
|
93
99
|
--> statement-breakpoint
|
|
100
|
+
CREATE TABLE "dismissed_keys" (
|
|
101
|
+
"environment_id" uuid NOT NULL,
|
|
102
|
+
"key" text NOT NULL,
|
|
103
|
+
"dismissed_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
104
|
+
"dismissed_by" text NOT NULL,
|
|
105
|
+
"restored_at" timestamp with time zone,
|
|
106
|
+
"restored_by" text,
|
|
107
|
+
CONSTRAINT "dismissed_keys_pkey" PRIMARY KEY("environment_id","key"),
|
|
108
|
+
CONSTRAINT "dismissed_keys_key_check" CHECK ("dismissed_keys"."key" ~ '^[A-Za-z_][A-Za-z0-9_]{0,127}$')
|
|
109
|
+
);
|
|
110
|
+
--> statement-breakpoint
|
|
94
111
|
CREATE TABLE "environments" (
|
|
95
112
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
96
113
|
"project_id" uuid NOT NULL,
|
|
@@ -100,7 +117,7 @@ CREATE TABLE "environments" (
|
|
|
100
117
|
"archived_at" timestamp with time zone,
|
|
101
118
|
CONSTRAINT "environments_project_id_slug_key" UNIQUE("project_id","slug"),
|
|
102
119
|
CONSTRAINT "environments_project_scoped" UNIQUE("id","project_id"),
|
|
103
|
-
CONSTRAINT "environments_slug_check" CHECK ("environments"."slug" ~ '^[a-z0-9][a-z0-9-]{0,62}
|
|
120
|
+
CONSTRAINT "environments_slug_check" CHECK ("environments"."slug" ~ '^[a-z0-9][a-z0-9-]{0,62}(~[a-z0-9-]{1,40})?$')
|
|
104
121
|
);
|
|
105
122
|
--> statement-breakpoint
|
|
106
123
|
CREATE TABLE "identities" (
|
|
@@ -124,14 +141,73 @@ CREATE TABLE "identities" (
|
|
|
124
141
|
CONSTRAINT "identities_auth_mac_check" CHECK (octet_length("identities"."auth_mac") = 32)
|
|
125
142
|
);
|
|
126
143
|
--> statement-breakpoint
|
|
144
|
+
CREATE TABLE "mcp_connections" (
|
|
145
|
+
"id" uuid PRIMARY KEY NOT NULL,
|
|
146
|
+
"auth_mac" "bytea" NOT NULL,
|
|
147
|
+
"principal" text NOT NULL,
|
|
148
|
+
"generation" integer NOT NULL,
|
|
149
|
+
"client_id" text NOT NULL,
|
|
150
|
+
"client_name" text NOT NULL,
|
|
151
|
+
"client_host" text,
|
|
152
|
+
"registration" text NOT NULL,
|
|
153
|
+
"scopes" text NOT NULL,
|
|
154
|
+
"redirect_uri" text NOT NULL,
|
|
155
|
+
"code_hash" "bytea",
|
|
156
|
+
"code_challenge" text,
|
|
157
|
+
"code_expires_at" timestamp with time zone,
|
|
158
|
+
"refresh_hash" "bytea",
|
|
159
|
+
"refresh_previous_hash" "bytea",
|
|
160
|
+
"expires_at" timestamp with time zone NOT NULL,
|
|
161
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
162
|
+
"last_used_at" timestamp with time zone,
|
|
163
|
+
"last_used_ip" text,
|
|
164
|
+
"revoked_at" timestamp with time zone,
|
|
165
|
+
"revoked_by" text,
|
|
166
|
+
CONSTRAINT "mcp_connections_code_hash_key" UNIQUE("code_hash"),
|
|
167
|
+
CONSTRAINT "mcp_connections_refresh_hash_key" UNIQUE("refresh_hash"),
|
|
168
|
+
CONSTRAINT "mcp_connections_principal_check" CHECK ("mcp_connections"."principal" LIKE 'user:%'),
|
|
169
|
+
CONSTRAINT "mcp_connections_registration_check" CHECK ("mcp_connections"."registration" IN ('cimd', 'dcr')),
|
|
170
|
+
CONSTRAINT "mcp_connections_auth_mac_check" CHECK (octet_length("mcp_connections"."auth_mac") = 32),
|
|
171
|
+
CONSTRAINT "mcp_connections_code_hash_check" CHECK ("mcp_connections"."code_hash" IS NULL OR octet_length("mcp_connections"."code_hash") = 32),
|
|
172
|
+
CONSTRAINT "mcp_connections_refresh_hash_check" CHECK ("mcp_connections"."refresh_hash" IS NULL OR octet_length("mcp_connections"."refresh_hash") = 32)
|
|
173
|
+
);
|
|
174
|
+
--> statement-breakpoint
|
|
175
|
+
CREATE TABLE "oauth_clients" (
|
|
176
|
+
"id" uuid PRIMARY KEY NOT NULL,
|
|
177
|
+
"auth_mac" "bytea" NOT NULL,
|
|
178
|
+
"name" text NOT NULL,
|
|
179
|
+
"redirect_uris" text NOT NULL,
|
|
180
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
181
|
+
"created_ip" text,
|
|
182
|
+
"revoked_at" timestamp with time zone,
|
|
183
|
+
CONSTRAINT "oauth_clients_auth_mac_check" CHECK (octet_length("oauth_clients"."auth_mac") = 32),
|
|
184
|
+
CONSTRAINT "oauth_clients_redirect_uris_check" CHECK ("oauth_clients"."redirect_uris"::jsonb IS NOT NULL)
|
|
185
|
+
);
|
|
186
|
+
--> statement-breakpoint
|
|
127
187
|
CREATE TABLE "projects" (
|
|
128
188
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
129
189
|
"slug" text NOT NULL,
|
|
130
190
|
"name" text NOT NULL,
|
|
131
191
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
132
192
|
"archived_at" timestamp with time zone,
|
|
193
|
+
"folder" text,
|
|
133
194
|
CONSTRAINT "projects_slug_key" UNIQUE("slug"),
|
|
134
|
-
CONSTRAINT "projects_slug_check" CHECK ("projects"."slug" ~ '^[a-z0-9][a-z0-9-]{0,62}
|
|
195
|
+
CONSTRAINT "projects_slug_check" CHECK ("projects"."slug" ~ '^[a-z0-9][a-z0-9-]{0,62}(~[a-z0-9-]{1,40})?$'),
|
|
196
|
+
CONSTRAINT "projects_folder_check" CHECK ("projects"."folder" IS NULL OR (char_length("projects"."folder") BETWEEN 1 AND 64 AND "projects"."folder" !~ '[/[:cntrl:]]' AND "projects"."folder" = btrim("projects"."folder")))
|
|
197
|
+
);
|
|
198
|
+
--> statement-breakpoint
|
|
199
|
+
CREATE TABLE "secret_references" (
|
|
200
|
+
"id" uuid PRIMARY KEY NOT NULL,
|
|
201
|
+
"project_id" uuid NOT NULL,
|
|
202
|
+
"environment_id" uuid NOT NULL,
|
|
203
|
+
"secret_id" uuid NOT NULL,
|
|
204
|
+
"source_project_id" uuid NOT NULL,
|
|
205
|
+
"source_environment_id" uuid NOT NULL,
|
|
206
|
+
"source_secret_id" uuid NOT NULL,
|
|
207
|
+
"created_seq" bigint NOT NULL,
|
|
208
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
209
|
+
"created_by" text NOT NULL,
|
|
210
|
+
CONSTRAINT "secret_references_created_seq_key" UNIQUE("created_seq")
|
|
135
211
|
);
|
|
136
212
|
--> statement-breakpoint
|
|
137
213
|
CREATE TABLE "secret_versions" (
|
|
@@ -164,51 +240,48 @@ CREATE TABLE "secrets" (
|
|
|
164
240
|
"current_version_id" uuid,
|
|
165
241
|
"current_version" integer DEFAULT 0 NOT NULL,
|
|
166
242
|
"archived_at" timestamp with time zone,
|
|
243
|
+
"folder" text,
|
|
167
244
|
CONSTRAINT "secrets_project_id_environment_id_key_key" UNIQUE("project_id","environment_id","key"),
|
|
168
|
-
CONSTRAINT "secrets_key_check" CHECK ("secrets"."key" ~ '^[A-Za-z_][A-Za-z0-9_]{0,127}$')
|
|
245
|
+
CONSTRAINT "secrets_key_check" CHECK ("secrets"."key" ~ '^[A-Za-z_][A-Za-z0-9_]{0,127}$'),
|
|
246
|
+
CONSTRAINT "secrets_folder_check" CHECK ("secrets"."folder" IS NULL OR (char_length("secrets"."folder") BETWEEN 1 AND 64 AND "secrets"."folder" !~ '[/[:cntrl:]]' AND "secrets"."folder" = btrim("secrets"."folder")))
|
|
169
247
|
);
|
|
170
248
|
--> statement-breakpoint
|
|
171
|
-
CREATE TABLE "
|
|
172
|
-
"
|
|
173
|
-
"
|
|
174
|
-
"
|
|
175
|
-
"
|
|
176
|
-
"
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
182
|
-
"project_id" uuid NOT NULL,
|
|
183
|
-
"environment_id" uuid NOT NULL,
|
|
184
|
-
"provider" text NOT NULL,
|
|
185
|
-
"config" text NOT NULL,
|
|
186
|
-
"credential_secret_id" uuid NOT NULL,
|
|
249
|
+
CREATE TABLE "service_bindings" (
|
|
250
|
+
"id" uuid PRIMARY KEY NOT NULL,
|
|
251
|
+
"auth_mac" "bytea" NOT NULL,
|
|
252
|
+
"principal" text NOT NULL,
|
|
253
|
+
"generation" integer NOT NULL,
|
|
254
|
+
"profile" text NOT NULL,
|
|
255
|
+
"issuer" text NOT NULL,
|
|
256
|
+
"jwks_uri" text NOT NULL,
|
|
257
|
+
"claims" text NOT NULL,
|
|
258
|
+
"label" text,
|
|
187
259
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
188
260
|
"created_by" text NOT NULL,
|
|
189
|
-
"
|
|
190
|
-
"
|
|
191
|
-
"
|
|
192
|
-
"
|
|
193
|
-
"
|
|
194
|
-
"
|
|
195
|
-
CONSTRAINT "syncs_config_check" CHECK ("syncs"."config"::jsonb IS NOT NULL),
|
|
196
|
-
CONSTRAINT "syncs_last_status_check" CHECK ("syncs"."last_status" IS NULL OR "syncs"."last_status" IN ('ok', 'partial', 'failed'))
|
|
261
|
+
"last_used_at" timestamp with time zone,
|
|
262
|
+
"revoked_at" timestamp with time zone,
|
|
263
|
+
"revoked_by" text,
|
|
264
|
+
CONSTRAINT "service_bindings_principal_check" CHECK ("service_bindings"."principal" LIKE 'token:%'),
|
|
265
|
+
CONSTRAINT "service_bindings_auth_mac_check" CHECK (octet_length("service_bindings"."auth_mac") = 32),
|
|
266
|
+
CONSTRAINT "service_bindings_claims_check" CHECK ("service_bindings"."claims"::jsonb IS NOT NULL)
|
|
197
267
|
);
|
|
198
268
|
--> statement-breakpoint
|
|
199
269
|
CREATE TABLE "vault_grants" (
|
|
200
270
|
"principal" text NOT NULL,
|
|
201
271
|
"project_id" uuid,
|
|
202
272
|
"environment_id" uuid,
|
|
273
|
+
"environment_slug" text,
|
|
203
274
|
"role" text NOT NULL,
|
|
204
275
|
"expires_at" bigint,
|
|
205
276
|
"granted_at" bigint NOT NULL,
|
|
206
277
|
"granted_by" text NOT NULL,
|
|
207
278
|
CONSTRAINT "vault_grants_on_project" UNIQUE("principal","project_id"),
|
|
208
279
|
CONSTRAINT "vault_grants_on_environment" UNIQUE("principal","environment_id"),
|
|
209
|
-
CONSTRAINT "
|
|
280
|
+
CONSTRAINT "vault_grants_on_environment_slug" UNIQUE("principal","environment_slug"),
|
|
281
|
+
CONSTRAINT "vault_grants_one_place" CHECK ((("vault_grants"."project_id" IS NULL) <> ("vault_grants"."environment_id" IS NULL) AND "vault_grants"."environment_slug" IS NULL) OR ("vault_grants"."project_id" IS NULL AND "vault_grants"."environment_id" IS NULL)),
|
|
282
|
+
CONSTRAINT "vault_grants_environment_slug_check" CHECK ("vault_grants"."environment_slug" IS NULL OR "vault_grants"."environment_slug" ~ '^[a-z0-9][a-z0-9-]{0,62}$'),
|
|
210
283
|
CONSTRAINT "vault_grants_role_check" CHECK ("vault_grants"."role" IN ('viewer', 'developer', 'maintainer', 'access-manager', 'auditor', 'owner')),
|
|
211
|
-
CONSTRAINT "vault_grants_environment_role_check" CHECK ("vault_grants"."environment_id" IS NULL OR "vault_grants"."role" IN ('viewer', 'developer', 'auditor'))
|
|
284
|
+
CONSTRAINT "vault_grants_environment_role_check" CHECK (("vault_grants"."environment_id" IS NULL AND "vault_grants"."environment_slug" IS NULL) OR "vault_grants"."role" IN ('viewer', 'developer', 'auditor'))
|
|
212
285
|
);
|
|
213
286
|
--> statement-breakpoint
|
|
214
287
|
CREATE TABLE "vault_members" (
|
|
@@ -223,7 +296,7 @@ CREATE TABLE "vault_members" (
|
|
|
223
296
|
"access_seq" bigint NOT NULL,
|
|
224
297
|
"mac" "bytea" NOT NULL,
|
|
225
298
|
CONSTRAINT "vault_members_mac_check" CHECK (octet_length("vault_members"."mac") = 32),
|
|
226
|
-
CONSTRAINT "vault_members_principal_check" CHECK ("vault_members"."principal" ~ '^(user|token
|
|
299
|
+
CONSTRAINT "vault_members_principal_check" CHECK ("vault_members"."principal" ~ '^(user|token):[^[:space:]:][^[:space:]]*$'),
|
|
227
300
|
CONSTRAINT "vault_members_user_lowercase" CHECK ("vault_members"."principal" NOT LIKE 'user:%' OR "vault_members"."principal" = lower("vault_members"."principal")),
|
|
228
301
|
CONSTRAINT "vault_members_status_check" CHECK ("vault_members"."status" IN ('active', 'removed')),
|
|
229
302
|
CONSTRAINT "vault_members_owner_check" CHECK (NOT "vault_members"."owner" OR ("vault_members"."status" = 'active' AND "vault_members"."principal" LIKE 'user:%')),
|
|
@@ -238,17 +311,19 @@ ALTER TABLE "audit_log" ADD CONSTRAINT "audit_log_related_seq_fkey" FOREIGN KEY
|
|
|
238
311
|
ALTER TABLE "credentials" ADD CONSTRAINT "credentials_principal_fkey" FOREIGN KEY ("principal") REFERENCES "public"."vault_members"("principal") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
|
|
239
312
|
ALTER TABLE "credentials" ADD CONSTRAINT "credentials_identity_id_fkey" FOREIGN KEY ("identity_id","principal","generation") REFERENCES "public"."identities"("id","principal","generation") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
|
|
240
313
|
ALTER TABLE "device_authorizations" ADD CONSTRAINT "device_authorizations_principal_fkey" FOREIGN KEY ("principal") REFERENCES "public"."vault_members"("principal") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
|
|
314
|
+
ALTER TABLE "dismissed_keys" ADD CONSTRAINT "dismissed_keys_environment_id_fkey" FOREIGN KEY ("environment_id") REFERENCES "public"."environments"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
|
|
241
315
|
ALTER TABLE "environments" ADD CONSTRAINT "environments_project_id_fkey" FOREIGN KEY ("project_id") REFERENCES "public"."projects"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
|
|
242
316
|
ALTER TABLE "identities" ADD CONSTRAINT "identities_principal_fkey" FOREIGN KEY ("principal") REFERENCES "public"."vault_members"("principal") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
|
|
317
|
+
ALTER TABLE "mcp_connections" ADD CONSTRAINT "mcp_connections_principal_fkey" FOREIGN KEY ("principal") REFERENCES "public"."vault_members"("principal") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
|
|
318
|
+
ALTER TABLE "secret_references" ADD CONSTRAINT "secret_references_secret_id_fkey" FOREIGN KEY ("secret_id") REFERENCES "public"."secrets"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
|
|
319
|
+
ALTER TABLE "secret_references" ADD CONSTRAINT "secret_references_source_secret_id_fkey" FOREIGN KEY ("source_secret_id") REFERENCES "public"."secrets"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
|
|
320
|
+
ALTER TABLE "secret_references" ADD CONSTRAINT "secret_references_created_seq_fkey" FOREIGN KEY ("created_seq") REFERENCES "public"."audit_log"("seq") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
|
|
243
321
|
ALTER TABLE "secret_versions" ADD CONSTRAINT "secret_versions_secret_id_fkey" FOREIGN KEY ("secret_id") REFERENCES "public"."secrets"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
|
|
244
322
|
ALTER TABLE "secrets" ADD CONSTRAINT "secrets_current_version_id_secret_versions_id_fk" FOREIGN KEY ("current_version_id") REFERENCES "public"."secret_versions"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
|
245
323
|
ALTER TABLE "secrets" ADD CONSTRAINT "secrets_project_id_fkey" FOREIGN KEY ("project_id") REFERENCES "public"."projects"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
|
|
246
324
|
ALTER TABLE "secrets" ADD CONSTRAINT "secrets_environment_id_fkey" FOREIGN KEY ("environment_id") REFERENCES "public"."environments"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
|
|
247
325
|
ALTER TABLE "secrets" ADD CONSTRAINT "secrets_environment_in_project" FOREIGN KEY ("environment_id","project_id") REFERENCES "public"."environments"("id","project_id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
|
248
|
-
ALTER TABLE "
|
|
249
|
-
ALTER TABLE "sync_keys" ADD CONSTRAINT "sync_keys_secret_version_id_fkey" FOREIGN KEY ("secret_version_id") REFERENCES "public"."secret_versions"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
|
|
250
|
-
ALTER TABLE "syncs" ADD CONSTRAINT "syncs_environment_in_project" FOREIGN KEY ("environment_id","project_id") REFERENCES "public"."environments"("id","project_id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
|
|
251
|
-
ALTER TABLE "syncs" ADD CONSTRAINT "syncs_credential_secret_id_fkey" FOREIGN KEY ("credential_secret_id") REFERENCES "public"."secrets"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
|
|
326
|
+
ALTER TABLE "service_bindings" ADD CONSTRAINT "service_bindings_principal_fkey" FOREIGN KEY ("principal") REFERENCES "public"."vault_members"("principal") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
|
|
252
327
|
ALTER TABLE "vault_grants" ADD CONSTRAINT "vault_grants_principal_fkey" FOREIGN KEY ("principal") REFERENCES "public"."vault_members"("principal") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
|
|
253
328
|
ALTER TABLE "vault_grants" ADD CONSTRAINT "vault_grants_project_id_fkey" FOREIGN KEY ("project_id") REFERENCES "public"."projects"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
|
|
254
329
|
ALTER TABLE "vault_grants" ADD CONSTRAINT "vault_grants_environment_id_fkey" FOREIGN KEY ("environment_id") REFERENCES "public"."environments"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
|
|
@@ -260,12 +335,29 @@ CREATE INDEX "audit_log_operation_idx" ON "audit_log" USING btree ("operation_id
|
|
|
260
335
|
CREATE INDEX "audit_log_action_idx" ON "audit_log" USING btree ("author","action","seq");--> statement-breakpoint
|
|
261
336
|
CREATE INDEX "audit_log_releases_idx" ON "audit_log" USING btree ("author","actor","action","decision","occurred_at");--> statement-breakpoint
|
|
262
337
|
CREATE INDEX "audit_log_subject_idx" ON "audit_log" USING btree ("author","subject_principal","seq");--> statement-breakpoint
|
|
338
|
+
CREATE INDEX "audit_log_unbind_idx" ON "audit_log" USING btree ((("metadata")::jsonb ->> 'bindingId')) WHERE "audit_log"."author" = 'app' AND "audit_log"."action" = 'token.unbind' AND "audit_log"."decision" = 'allow';--> statement-breakpoint
|
|
339
|
+
CREATE INDEX "audit_log_exchange_idx" ON "audit_log" USING btree ((("metadata")::jsonb ->> 'credentialId')) WHERE "audit_log"."author" = 'app' AND "audit_log"."action" = 'token.exchange' AND "audit_log"."decision" = 'allow';--> statement-breakpoint
|
|
340
|
+
CREATE INDEX "audit_log_reference_end_idx" ON "audit_log" USING btree ("related_seq") WHERE "audit_log"."author" = 'vault' AND "audit_log"."action" = 'reference.end' AND "audit_log"."decision" = 'allow';--> statement-breakpoint
|
|
341
|
+
CREATE INDEX "audit_log_also_project_idx" ON "audit_log" USING btree (((("metadata")::jsonb -> 'also') ->> 'projectId'),"seq") WHERE (("audit_log"."metadata")::jsonb -> 'also') IS NOT NULL;--> statement-breakpoint
|
|
342
|
+
CREATE INDEX "audit_log_also_environment_idx" ON "audit_log" USING btree (((("metadata")::jsonb -> 'also') ->> 'environmentId'),"seq") WHERE (("audit_log"."metadata")::jsonb -> 'also') IS NOT NULL;--> statement-breakpoint
|
|
343
|
+
CREATE INDEX "audit_log_also_secret_idx" ON "audit_log" USING btree (((("metadata")::jsonb -> 'also') ->> 'secretId'),"seq") WHERE (("audit_log"."metadata")::jsonb -> 'also') IS NOT NULL;--> statement-breakpoint
|
|
263
344
|
CREATE INDEX "credentials_principal_idx" ON "credentials" USING btree ("principal","generation");--> statement-breakpoint
|
|
345
|
+
CREATE INDEX "credentials_live_idx" ON "credentials" USING btree ("principal","expires_at") WHERE "credentials"."revoked_at" IS NULL;--> statement-breakpoint
|
|
346
|
+
CREATE INDEX "credentials_issued_by_idx" ON "credentials" USING btree ("principal","created_by","created_at");--> statement-breakpoint
|
|
264
347
|
CREATE UNIQUE INDEX "identities_active_subject" ON "identities" USING btree ("provider","issuer_hash","active_subject");--> statement-breakpoint
|
|
265
348
|
CREATE INDEX "identities_principal_idx" ON "identities" USING btree ("principal","generation");--> statement-breakpoint
|
|
349
|
+
CREATE INDEX "mcp_connections_refresh_previous_idx" ON "mcp_connections" USING btree ("refresh_previous_hash");--> statement-breakpoint
|
|
350
|
+
CREATE INDEX "mcp_connections_live_idx" ON "mcp_connections" USING btree ("principal","expires_at") WHERE "mcp_connections"."revoked_at" IS NULL;--> statement-breakpoint
|
|
351
|
+
CREATE INDEX "secret_references_holder_idx" ON "secret_references" USING btree ("secret_id","created_seq");--> statement-breakpoint
|
|
352
|
+
CREATE INDEX "secret_references_source_idx" ON "secret_references" USING btree ("source_secret_id");--> statement-breakpoint
|
|
353
|
+
CREATE INDEX "secret_references_project_idx" ON "secret_references" USING btree ("project_id");--> statement-breakpoint
|
|
354
|
+
CREATE INDEX "secret_references_source_project_idx" ON "secret_references" USING btree ("source_project_id");--> statement-breakpoint
|
|
355
|
+
CREATE INDEX "secret_references_created_by_idx" ON "secret_references" USING btree ("created_by");--> statement-breakpoint
|
|
266
356
|
CREATE INDEX "secret_versions_secret_idx" ON "secret_versions" USING btree ("secret_id","version" DESC NULLS LAST);--> statement-breakpoint
|
|
267
357
|
CREATE INDEX "secrets_lookup_idx" ON "secrets" USING btree ("project_id","environment_id","key");--> statement-breakpoint
|
|
268
|
-
CREATE INDEX "
|
|
358
|
+
CREATE INDEX "service_bindings_principal_idx" ON "service_bindings" USING btree ("principal","issuer");--> statement-breakpoint
|
|
359
|
+
CREATE INDEX "service_bindings_live_idx" ON "service_bindings" USING btree ("principal","issuer","generation","created_at","id") WHERE "service_bindings"."revoked_at" IS NULL;--> statement-breakpoint
|
|
360
|
+
CREATE UNIQUE INDEX "vault_grants_on_every_project" ON "vault_grants" USING btree ("principal") WHERE "vault_grants"."project_id" IS NULL AND "vault_grants"."environment_id" IS NULL AND "vault_grants"."environment_slug" IS NULL;--> statement-breakpoint
|
|
269
361
|
|
|
270
362
|
-- The chain starts at sequence 0 from 32 zero bytes.
|
|
271
363
|
INSERT INTO audit_chain_head (only_row, next_seq, head_hash)
|
|
@@ -290,13 +382,35 @@ CREATE TRIGGER audit_log_no_truncate BEFORE TRUNCATE ON audit_log
|
|
|
290
382
|
FOR EACH STATEMENT EXECUTE FUNCTION audit_log_append_only();
|
|
291
383
|
--> statement-breakpoint
|
|
292
384
|
|
|
385
|
+
-- A secret version is never rewritten in place, only erased: a deleted
|
|
386
|
+
-- project or environment stays as a tombstone the log's entries name, and
|
|
387
|
+
-- its versions with it, their ciphertext and wrapped data key emptied. That
|
|
388
|
+
-- is the one change a version takes, for every login.
|
|
389
|
+
CREATE FUNCTION secret_versions_erase_only() RETURNS trigger LANGUAGE plpgsql AS $$
|
|
390
|
+
BEGIN
|
|
391
|
+
IF octet_length(NEW.ciphertext) <> 0 OR octet_length(NEW.wrapped_dek) <> 0
|
|
392
|
+
OR (NEW.id, NEW.secret_id, NEW.version, NEW.envelope_version, NEW.iv, NEW.auth_tag,
|
|
393
|
+
NEW.kek_provider, NEW.kek_id, NEW.kek_version, NEW.created_at, NEW.created_by)
|
|
394
|
+
IS DISTINCT FROM
|
|
395
|
+
(OLD.id, OLD.secret_id, OLD.version, OLD.envelope_version, OLD.iv, OLD.auth_tag,
|
|
396
|
+
OLD.kek_provider, OLD.kek_id, OLD.kek_version, OLD.created_at, OLD.created_by) THEN
|
|
397
|
+
RAISE EXCEPTION 'a secret version is only ever erased' USING ERRCODE = 'insufficient_privilege';
|
|
398
|
+
END IF;
|
|
399
|
+
RETURN NEW;
|
|
400
|
+
END
|
|
401
|
+
$$;
|
|
402
|
+
--> statement-breakpoint
|
|
403
|
+
CREATE TRIGGER secret_versions_erase_only BEFORE UPDATE ON secret_versions
|
|
404
|
+
FOR EACH ROW EXECUTE FUNCTION secret_versions_erase_only();
|
|
405
|
+
--> statement-breakpoint
|
|
406
|
+
|
|
293
407
|
-- Two logins, provisioned outside coffre (their passwords are never ours),
|
|
294
408
|
-- each with only the rights of its group:
|
|
295
409
|
--
|
|
296
410
|
-- coffre_runtime the server, through coffre_app: read and insert,
|
|
297
411
|
-- UPDATE on named columns only, and never DELETE. A
|
|
298
|
-
-- revoked session, a used device code and a
|
|
299
|
-
--
|
|
412
|
+
-- revoked session, a used device code and a spent
|
|
413
|
+
-- token are rows that say so, not gaps.
|
|
300
414
|
-- coffre_vault_runtime the vault, through coffre_vault: its members and
|
|
301
415
|
-- grants, and reading what it decides on.
|
|
302
416
|
--
|
|
@@ -378,6 +492,10 @@ GRANT USAGE ON SCHEMA drizzle TO coffre_app, coffre_vault;
|
|
|
378
492
|
GRANT SELECT ON drizzle.__drizzle_migrations TO coffre_app, coffre_vault;
|
|
379
493
|
--> statement-breakpoint
|
|
380
494
|
|
|
495
|
+
-- The app reads and adds; it never deletes. A binding, a registered client
|
|
496
|
+
-- and a connection change only in what their MAC allows to change in place;
|
|
497
|
+
-- a spent token and a reference never change at all, and the vault's log
|
|
498
|
+
-- says which references have ended.
|
|
381
499
|
GRANT SELECT, INSERT ON
|
|
382
500
|
projects,
|
|
383
501
|
environments,
|
|
@@ -387,8 +505,12 @@ GRANT SELECT, INSERT ON
|
|
|
387
505
|
identities,
|
|
388
506
|
credentials,
|
|
389
507
|
device_authorizations,
|
|
390
|
-
|
|
391
|
-
|
|
508
|
+
service_bindings,
|
|
509
|
+
consumed_tokens,
|
|
510
|
+
secret_references,
|
|
511
|
+
dismissed_keys,
|
|
512
|
+
oauth_clients,
|
|
513
|
+
mcp_connections
|
|
392
514
|
TO coffre_app;
|
|
393
515
|
--> statement-breakpoint
|
|
394
516
|
|
|
@@ -399,11 +521,11 @@ GRANT SELECT ON
|
|
|
399
521
|
TO coffre_app;
|
|
400
522
|
--> statement-breakpoint
|
|
401
523
|
|
|
402
|
-
GRANT UPDATE (slug, name, archived_at) ON projects TO coffre_app;
|
|
524
|
+
GRANT UPDATE (slug, name, archived_at, folder) ON projects TO coffre_app;
|
|
403
525
|
--> statement-breakpoint
|
|
404
526
|
GRANT UPDATE (slug, name, archived_at) ON environments TO coffre_app;
|
|
405
527
|
--> statement-breakpoint
|
|
406
|
-
GRANT UPDATE (key, current_version_id, current_version, updated_at, archived_at) ON secrets TO coffre_app;
|
|
528
|
+
GRANT UPDATE (key, current_version_id, current_version, updated_at, archived_at, folder) ON secrets TO coffre_app;
|
|
407
529
|
--> statement-breakpoint
|
|
408
530
|
GRANT UPDATE (next_seq, head_hash) ON audit_chain_head TO coffre_app;
|
|
409
531
|
--> statement-breakpoint
|
|
@@ -414,11 +536,14 @@ GRANT UPDATE (last_used_at, last_used_ip, revoked_at, revoked_by, auth_mac) ON c
|
|
|
414
536
|
GRANT UPDATE (decided_at, decision, generation, principal, consumed_at, auth_mac)
|
|
415
537
|
ON device_authorizations TO coffre_app;
|
|
416
538
|
--> statement-breakpoint
|
|
417
|
-
GRANT UPDATE (
|
|
418
|
-
last_run_at, last_status, last_error)
|
|
419
|
-
ON syncs TO coffre_app;
|
|
539
|
+
GRANT UPDATE (label, last_used_at, revoked_at, revoked_by, auth_mac) ON service_bindings TO coffre_app;
|
|
420
540
|
--> statement-breakpoint
|
|
421
|
-
GRANT UPDATE (
|
|
541
|
+
GRANT UPDATE (dismissed_at, dismissed_by, restored_at, restored_by) ON dismissed_keys TO coffre_app;
|
|
542
|
+
--> statement-breakpoint
|
|
543
|
+
GRANT UPDATE (revoked_at, auth_mac) ON oauth_clients TO coffre_app;
|
|
544
|
+
--> statement-breakpoint
|
|
545
|
+
GRANT UPDATE (code_challenge, code_expires_at, refresh_hash, refresh_previous_hash, last_used_at, last_used_ip, revoked_at, revoked_by, auth_mac)
|
|
546
|
+
ON mcp_connections TO coffre_app;
|
|
422
547
|
--> statement-breakpoint
|
|
423
548
|
|
|
424
549
|
-- The vault reads what it decides on and the log it chains to, and writes
|
|
@@ -447,6 +572,9 @@ REVOKE TRUNCATE ON ALL TABLES IN SCHEMA public FROM coffre_vault;
|
|
|
447
572
|
--> statement-breakpoint
|
|
448
573
|
REVOKE UPDATE ON audit_log, secret_versions FROM coffre_app, coffre_vault;
|
|
449
574
|
--> statement-breakpoint
|
|
575
|
+
-- What erasing a version empties, and nothing else: the trigger above holds every login to it.
|
|
576
|
+
GRANT UPDATE (ciphertext, wrapped_dek) ON secret_versions TO coffre_app;
|
|
577
|
+
--> statement-breakpoint
|
|
450
578
|
REVOKE CREATE ON SCHEMA public FROM PUBLIC, coffre_app, coffre_runtime, coffre_vault, coffre_vault_runtime;
|
|
451
579
|
--> statement-breakpoint
|
|
452
580
|
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
CREATE TABLE "mcp_approvals" (
|
|
2
|
+
"id" uuid PRIMARY KEY NOT NULL,
|
|
3
|
+
"connection_id" uuid NOT NULL,
|
|
4
|
+
"tool" text NOT NULL,
|
|
5
|
+
"arguments" text NOT NULL,
|
|
6
|
+
"digest" "bytea" NOT NULL,
|
|
7
|
+
"status" text DEFAULT 'pending' NOT NULL,
|
|
8
|
+
"outcome" text,
|
|
9
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
10
|
+
"expires_at" timestamp with time zone NOT NULL,
|
|
11
|
+
"decided_at" timestamp with time zone,
|
|
12
|
+
"reported_at" timestamp with time zone,
|
|
13
|
+
CONSTRAINT "mcp_approvals_status_check" CHECK ("mcp_approvals"."status" IN ('pending', 'approved', 'denied', 'cancelled', 'failed')),
|
|
14
|
+
CONSTRAINT "mcp_approvals_digest_check" CHECK (octet_length("mcp_approvals"."digest") = 32),
|
|
15
|
+
CONSTRAINT "mcp_approvals_arguments_check" CHECK ("mcp_approvals"."arguments"::jsonb IS NOT NULL)
|
|
16
|
+
);
|
|
17
|
+
--> statement-breakpoint
|
|
18
|
+
ALTER TABLE "mcp_approvals" ADD CONSTRAINT "mcp_approvals_connection_fkey" FOREIGN KEY ("connection_id") REFERENCES "public"."mcp_connections"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
|
|
19
|
+
CREATE INDEX "mcp_approvals_open_idx" ON "mcp_approvals" USING btree ("connection_id","digest") WHERE "mcp_approvals"."reported_at" IS NULL;--> statement-breakpoint
|
|
20
|
+
-- The app asks for approvals and records what became of them: the tool,
|
|
21
|
+
-- its arguments, their digest, the connection and the expiry are what the
|
|
22
|
+
-- person is shown, and never change. Nothing is deleted.
|
|
23
|
+
GRANT SELECT, INSERT ON mcp_approvals TO coffre_app;--> statement-breakpoint
|
|
24
|
+
GRANT UPDATE (status, outcome, decided_at, reported_at) ON mcp_approvals TO coffre_app;
|