@kici-dev/shared 0.0.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +1 -6
  3. package/dist/chunk-gOLHoazu.js +4 -0
  4. package/dist/cold-store/bucket.d.ts +26 -0
  5. package/dist/cold-store/bucket.js +40 -0
  6. package/dist/cold-store/bucket.test.d.ts +2 -0
  7. package/dist/cold-store/chunk-encoder.d.ts +63 -0
  8. package/dist/cold-store/chunk-encoder.js +94 -0
  9. package/dist/cold-store/chunk-encoder.test.d.ts +2 -0
  10. package/dist/cold-store/chunk-id.d.ts +10 -0
  11. package/dist/cold-store/chunk-id.js +29 -0
  12. package/dist/cold-store/chunk-id.test.d.ts +2 -0
  13. package/dist/cold-store/cold-store.d.ts +345 -0
  14. package/dist/cold-store/cold-store.js +1078 -0
  15. package/dist/cold-store/cold-store.test.d.ts +2 -0
  16. package/dist/cold-store/config.d.ts +62 -0
  17. package/dist/cold-store/config.js +28 -0
  18. package/dist/cold-store/index.d.ts +20 -0
  19. package/dist/cold-store/index.js +11 -0
  20. package/dist/cold-store/key.d.ts +89 -0
  21. package/dist/cold-store/key.js +88 -0
  22. package/dist/cold-store/key.test.d.ts +2 -0
  23. package/dist/cold-store/lru.d.ts +33 -0
  24. package/dist/cold-store/lru.js +59 -0
  25. package/dist/cold-store/lru.test.d.ts +2 -0
  26. package/dist/cold-store/manifest.d.ts +11 -0
  27. package/dist/cold-store/manifest.js +57 -0
  28. package/dist/cold-store/manifest.test.d.ts +2 -0
  29. package/dist/cold-store/metrics.d.ts +103 -0
  30. package/dist/cold-store/metrics.js +179 -0
  31. package/dist/cold-store/table-adapter.d.ts +229 -0
  32. package/dist/cold-store/table-adapter.js +2 -0
  33. package/dist/cold-store/types.d.ts +111 -0
  34. package/dist/cold-store/types.js +2 -0
  35. package/dist/crypto.d.ts +33 -0
  36. package/dist/crypto.js +67 -0
  37. package/dist/db-admin.d.ts +1422 -0
  38. package/dist/db-admin.js +2525 -0
  39. package/dist/db-admin.test.d.ts +2 -0
  40. package/dist/db.d.ts +14 -0
  41. package/dist/db.js +23 -0
  42. package/dist/env/allowlist.d.ts +79 -0
  43. package/dist/env/allowlist.js +86 -0
  44. package/dist/env/define-env.d.ts +172 -0
  45. package/dist/env/define-env.js +295 -0
  46. package/dist/env/define-env.test.d.ts +2 -0
  47. package/dist/env/env-rule-allowlist.test.d.ts +2 -0
  48. package/dist/env/index.d.ts +11 -0
  49. package/dist/env/index.js +4 -0
  50. package/dist/env/logger-env.d.ts +30 -0
  51. package/dist/env/logger-env.js +95 -0
  52. package/dist/error.d.ts +16 -0
  53. package/dist/error.js +58 -0
  54. package/dist/error.test.d.ts +2 -0
  55. package/dist/format-bytes.d.ts +5 -0
  56. package/dist/format-bytes.js +15 -0
  57. package/dist/format-bytes.test.d.ts +2 -0
  58. package/dist/format-duration.d.ts +11 -0
  59. package/dist/format-duration.js +32 -0
  60. package/dist/format-duration.test.d.ts +2 -0
  61. package/dist/graceful-shutdown.d.ts +58 -0
  62. package/dist/graceful-shutdown.js +71 -0
  63. package/dist/graceful-shutdown.test.d.ts +2 -0
  64. package/dist/idempotency-files.d.ts +113 -0
  65. package/dist/idempotency-files.js +190 -0
  66. package/dist/idempotency-files.test.d.ts +2 -0
  67. package/dist/idempotency.d.ts +68 -0
  68. package/dist/idempotency.js +49 -0
  69. package/dist/idempotency.test.d.ts +2 -0
  70. package/dist/index.d.ts +19 -0
  71. package/dist/index.js +31 -0
  72. package/dist/logger.d.ts +57 -0
  73. package/dist/logger.js +175 -0
  74. package/dist/logger.test.d.ts +2 -0
  75. package/dist/reconnect-delay.d.ts +11 -0
  76. package/dist/reconnect-delay.js +22 -0
  77. package/dist/request-context.d.ts +42 -0
  78. package/dist/request-context.js +37 -0
  79. package/dist/ring-buffer.d.ts +35 -0
  80. package/dist/ring-buffer.js +62 -0
  81. package/dist/ring-buffer.test.d.ts +2 -0
  82. package/dist/routes/health.d.ts +26 -0
  83. package/dist/routes/health.js +45 -0
  84. package/dist/routes/health.test.d.ts +2 -0
  85. package/dist/routes/metrics.d.ts +20 -0
  86. package/dist/routes/metrics.js +38 -0
  87. package/dist/s3-client.d.ts +42 -0
  88. package/dist/s3-client.js +25 -0
  89. package/dist/telemetry/index.d.ts +3 -0
  90. package/dist/telemetry/index.js +4 -0
  91. package/dist/telemetry/init.d.ts +20 -0
  92. package/dist/telemetry/init.js +42 -0
  93. package/dist/telemetry/init.test.d.ts +2 -0
  94. package/dist/telemetry/metrics.d.ts +8 -0
  95. package/dist/telemetry/metrics.js +16 -0
  96. package/dist/tool-check.d.ts +33 -0
  97. package/dist/tool-check.js +60 -0
  98. package/dist/tool-check.test.d.ts +2 -0
  99. package/dist/ts-loader-hook.d.ts +26 -0
  100. package/dist/ts-loader-hook.js +48 -0
  101. package/dist/zx.d.ts +8 -0
  102. package/dist/zx.js +78 -0
  103. package/package.json +69 -5
  104. package/sbom.spdx.json +8775 -0
  105. package/index.js +0 -3
@@ -0,0 +1,1422 @@
1
+ import pg from 'pg';
2
+ import type { MigrationProvider } from 'kysely/migration';
3
+ /**
4
+ * Admin/DB-operations helpers shared between `kici-admin` (orchestrator DB)
5
+ * and `kici-platform-admin` (Platform DB). Each CLI wraps these with its own
6
+ * bundled migration provider and audit-log pattern.
7
+ *
8
+ * All destructive ops require the caller to pass a fully-formed database URL
9
+ * — no parsing of environment variables here. The CLI layer handles that.
10
+ */
11
+ export declare const MIGRATION_HASH_TABLE = "_migration_content_hash";
12
+ interface ParsedDatabaseUrl {
13
+ adminUrl: string;
14
+ dbName: string;
15
+ dbOwner: string;
16
+ }
17
+ /**
18
+ * Parse a libpq-style URL into (adminUrl, dbName, dbOwner).
19
+ *
20
+ * `adminUrl` connects to the `postgres` maintenance DB so callers can run
21
+ * `CREATE DATABASE` / `DROP DATABASE` on `dbName`. `dbOwner` is the URL's
22
+ * username, which becomes the new DB owner when we create it.
23
+ */
24
+ export declare function parseDatabaseUrl(databaseUrl: string): ParsedDatabaseUrl;
25
+ /**
26
+ * Redact the password from a libpq URL for safe logging.
27
+ */
28
+ export declare function maskDatabaseUrl(databaseUrl: string): string;
29
+ /**
30
+ * DROP `dbName` (if it exists). Terminates existing backend connections
31
+ * so the DROP doesn't block. Idempotent — drops are IF EXISTS.
32
+ *
33
+ * Used by e2e cleanup after a full-lifecycle service-deploy test tears
34
+ * down its isolated database. Shares the same admin-URL + identifier-
35
+ * validation + backend-termination scaffolding as dropAndCreateDatabase
36
+ * so the two helpers cannot drift.
37
+ */
38
+ export declare function dropDatabaseDirect(databaseUrl: string): Promise<void>;
39
+ /**
40
+ * Drop `dbName` (if it exists), then recreate it owned by `owner`. Terminates
41
+ * existing backend connections so the DROP doesn't block.
42
+ */
43
+ export declare function dropAndCreateDatabase(databaseUrl: string): Promise<void>;
44
+ /**
45
+ * CREATE DATABASE IF NOT EXISTS (idempotent). Uses the URL's username as owner.
46
+ */
47
+ export declare function ensureDatabase(databaseUrl: string): Promise<'created' | 'exists'>;
48
+ /**
49
+ * CREATE ROLE ... LOGIN [CREATEDB] (idempotent — updates password if role
50
+ * already exists).
51
+ */
52
+ export declare function createDbRole(adminUrl: string, opts: {
53
+ username: string;
54
+ password: string;
55
+ createDb?: boolean;
56
+ }): Promise<'created' | 'updated'>;
57
+ /**
58
+ * Create a read-only role and grant SELECT on all tables in the public schema
59
+ * (plus default privileges for tables created later).
60
+ *
61
+ * `databaseUrl` must connect as the DB owner (or superuser) since we need to
62
+ * ALTER DEFAULT PRIVILEGES.
63
+ */
64
+ export declare function createReadOnlyDbUser(databaseUrl: string, opts: {
65
+ username: string;
66
+ password: string;
67
+ }): Promise<'created' | 'updated'>;
68
+ /**
69
+ * Compute a stable content hash over all migrations the provider exposes.
70
+ * Uses migration name + the string representation of `up`/`down` (via
71
+ * `Function.toString()`), so brute-force rewrites of a migration body invalidate
72
+ * the hash even when the filename stays the same.
73
+ *
74
+ * Works with any `MigrationProvider` — file-based or the orchestrator /
75
+ * Platform bundled ones.
76
+ */
77
+ export declare function computeMigrationsHash(provider: MigrationProvider): Promise<string>;
78
+ /**
79
+ * Marker row key used by the bundled-provider hash (`computeMigrationsHash`).
80
+ *
81
+ * Kept distinct from the legacy e2e file-based hash (which still writes to
82
+ * the row keyed `'kysely_migration'`) so the two algorithms can coexist in
83
+ * the same `_migration_content_hash` table without clobbering each other.
84
+ * `kici-admin db check-schema` / `kici-platform-admin db check-schema` read
85
+ * this row; the e2e `isSchemaCurrent` helper reads the other.
86
+ */
87
+ export declare const PROVIDER_HASH_KEY = "kysely_migration_provider";
88
+ /**
89
+ * Ensure the content-hash marker table exists, then upsert `hash` keyed by
90
+ * `PROVIDER_HASH_KEY`. Paired with `readStoredMigrationContentHash` +
91
+ * `isSchemaCurrent`.
92
+ */
93
+ export declare function storeMigrationContentHash(pool: pg.Pool, hash: string): Promise<void>;
94
+ /**
95
+ * Read the provider-based content hash, or `null` if the marker table / row
96
+ * doesn't exist.
97
+ */
98
+ export declare function readStoredMigrationContentHash(pool: pg.Pool): Promise<string | null>;
99
+ export interface PurgeStaleExecutionResult {
100
+ runsDeleted: number;
101
+ jobsDeleted: number;
102
+ concurrencyGroupsDeleted: number;
103
+ }
104
+ /**
105
+ * TRUNCATE dispatch_queue on the orchestrator DB (direct SQL). Used by the
106
+ * `kici-admin queue clear --database-url ...` direct-DB fallback when the
107
+ * orchestrator isn't reachable over HTTP (e.g. warm-start cleanup before the
108
+ * service restarts).
109
+ */
110
+ export declare function clearDispatchQueueDirect(databaseUrl: string): Promise<void>;
111
+ /**
112
+ * DELETE orphan execution_runs + execution_jobs for routing keys other than
113
+ * `routingKey` (and rows with NULL routing_key). Returns row counts.
114
+ */
115
+ export declare function purgeStaleExecutionDirect(databaseUrl: string, routingKey: string): Promise<PurgeStaleExecutionResult>;
116
+ export interface PurgeStaleSourcesResult {
117
+ dryRun: boolean;
118
+ secretsDeleted?: number;
119
+ sourcesDeleted?: number;
120
+ genericDeleted?: number;
121
+ registrationsDeleted?: number;
122
+ staleSecrets?: number;
123
+ staleSources?: number;
124
+ genericSources?: number;
125
+ orphanRegistrations?: number;
126
+ }
127
+ /**
128
+ * DELETE orphan sources + their `__system__`-scoped webhook/private-key
129
+ * secrets, all `generic_webhook_sources` (the table is single-tenant per
130
+ * deployment), and any `workflow_registrations` rows whose routing_key no
131
+ * longer points at an existing source. When `dryRun` is true, only count
132
+ * the rows that would be deleted.
133
+ *
134
+ * Orphan registration cleanup is critical: generic_webhook_sources is wiped
135
+ * wholesale, but workflow_registrations rows previously persisted under those
136
+ * routing keys would otherwise survive and pollute the cross-source dispatch
137
+ * fan-out on the next test run (causing clone attempts against long-dead
138
+ * repo identifiers from earlier tests).
139
+ */
140
+ export declare function purgeStaleSourcesDirect(databaseUrl: string, routingKey: string, dryRun: boolean): Promise<PurgeStaleSourcesResult>;
141
+ /**
142
+ * Bulk-delete scoped_secrets. Scoped to one org when `orgId` is provided,
143
+ * else all orgs. Returns the number of rows deleted.
144
+ */
145
+ export declare function purgeScopedSecretsDirect(databaseUrl: string, orgId?: string): Promise<{
146
+ deleted: number;
147
+ }>;
148
+ export interface SeedEnvironmentOpts {
149
+ orgId: string;
150
+ name: string;
151
+ type?: string;
152
+ enabled?: boolean;
153
+ branchRestrictions?: unknown;
154
+ requiredReviewers?: unknown;
155
+ waitTimerSeconds?: number | null;
156
+ holdExpirySeconds?: number | null;
157
+ minimumTrust?: string | null;
158
+ }
159
+ export interface SeedEnvironmentResult {
160
+ envId: string;
161
+ created: boolean;
162
+ }
163
+ /**
164
+ * Upsert an environment row keyed by (org_id, name). Returns the env id and
165
+ * whether the row was newly inserted. `branchRestrictions` / `requiredReviewers`
166
+ * are JSON-serialised server-side; pass them as plain arrays or objects.
167
+ */
168
+ export declare function seedEnvironmentDirect(databaseUrl: string, opts: SeedEnvironmentOpts): Promise<SeedEnvironmentResult>;
169
+ export interface SeedEnvironmentBindingOpts {
170
+ orgId: string;
171
+ envName: string;
172
+ scopePattern: string;
173
+ }
174
+ /**
175
+ * Upsert an `environment_bindings` row connecting `envName` to `scopePattern`.
176
+ * Throws if the environment does not exist.
177
+ */
178
+ export declare function seedEnvironmentBindingDirect(databaseUrl: string, opts: SeedEnvironmentBindingOpts): Promise<{
179
+ created: boolean;
180
+ }>;
181
+ export interface SetEnvironmentPolicyOpts {
182
+ orgId: string;
183
+ envName: string;
184
+ branchRestrictions?: unknown;
185
+ requiredReviewers?: unknown;
186
+ waitTimerSeconds?: number | null;
187
+ holdExpirySeconds?: number | null;
188
+ minimumTrust?: string | null;
189
+ enabled?: boolean;
190
+ }
191
+ /**
192
+ * UPDATE only the policy fields that were explicitly provided. Columns that
193
+ * were NOT in `opts` are left untouched. Throws if the environment is missing.
194
+ */
195
+ export declare function setEnvironmentPolicyDirect(databaseUrl: string, opts: SetEnvironmentPolicyOpts): Promise<void>;
196
+ export interface EnvironmentRow {
197
+ id: string;
198
+ org_id: string;
199
+ name: string;
200
+ type: string;
201
+ enabled: boolean;
202
+ branch_restrictions: unknown;
203
+ required_reviewers: unknown;
204
+ wait_timer_seconds: number | null;
205
+ hold_expiry_seconds: number | null;
206
+ minimum_trust: string | null;
207
+ created_at: string;
208
+ updated_at: string;
209
+ }
210
+ /**
211
+ * SELECT * FROM environments WHERE org_id = $1, ordered by name.
212
+ */
213
+ export declare function listEnvironmentsDirect(databaseUrl: string, opts: {
214
+ orgId: string;
215
+ }): Promise<{
216
+ environments: EnvironmentRow[];
217
+ }>;
218
+ export interface EnvironmentVariableRow {
219
+ key: string;
220
+ value: string;
221
+ locked: boolean;
222
+ updated_at: string;
223
+ }
224
+ export interface EnvironmentBindingRow {
225
+ scope_pattern: string;
226
+ created_at: string;
227
+ }
228
+ export interface ShowEnvironmentResult {
229
+ environment: EnvironmentRow;
230
+ variables: EnvironmentVariableRow[];
231
+ bindings: EnvironmentBindingRow[];
232
+ }
233
+ /**
234
+ * Fetch a single environment row joined with its variables and bindings.
235
+ * Throws if the environment does not exist.
236
+ */
237
+ export declare function showEnvironmentDirect(databaseUrl: string, opts: {
238
+ orgId: string;
239
+ name: string;
240
+ }): Promise<ShowEnvironmentResult>;
241
+ export interface CreateEnvironmentTemplateOpts {
242
+ orgId: string;
243
+ templateName: string;
244
+ type?: string;
245
+ branchRestrictions?: unknown;
246
+ requiredReviewers?: unknown;
247
+ waitTimerSeconds?: number | null;
248
+ holdExpirySeconds?: number | null;
249
+ minimumTrust?: string | null;
250
+ variables?: Record<string, string>;
251
+ }
252
+ /**
253
+ * Create (or update) an environment template + its seed variables in one
254
+ * transaction. Templates are represented as environments with `type='template'`
255
+ * by convention. Returns `{ envId, variablesSet }`.
256
+ */
257
+ export declare function createEnvironmentTemplateDirect(databaseUrl: string, opts: CreateEnvironmentTemplateOpts): Promise<{
258
+ envId: string;
259
+ created: boolean;
260
+ variablesSet: number;
261
+ }>;
262
+ export interface SetEnvironmentSecretOpts {
263
+ orgId: string;
264
+ environment: string;
265
+ key: string;
266
+ encryptedValue: string;
267
+ }
268
+ /**
269
+ * UPSERT a scoped_secrets row keyed by (org_id, scope=environment, key).
270
+ * Writes the value verbatim — the caller is responsible for encryption
271
+ * (matches the stage-4 deferral noted in the plan).
272
+ */
273
+ export declare function setEnvironmentSecretDirect(databaseUrl: string, opts: SetEnvironmentSecretOpts): Promise<{
274
+ inserted: boolean;
275
+ }>;
276
+ export interface DispatchQueueRow {
277
+ id: string;
278
+ run_id: string;
279
+ workflow_name: string;
280
+ job_name: string;
281
+ status: string;
282
+ routing_key: string;
283
+ provider: string;
284
+ created_at: string;
285
+ expires_at: string | null;
286
+ delivery_id: string;
287
+ source_tar_url: string | null;
288
+ deps_url: string | null;
289
+ job_config: string | null;
290
+ }
291
+ export interface ListQueueOpts {
292
+ status?: string;
293
+ /** Status NOT IN list (e.g., to find non-terminal rows). */
294
+ statusNotIn?: readonly string[];
295
+ jobNamePrefix?: string;
296
+ /** Exact job_name match (e.g., `__build__e2e-test`). */
297
+ jobName?: string;
298
+ /** job_name NOT LIKE (e.g., `__build__%` to exclude build jobs). */
299
+ jobNameNotLike?: string;
300
+ workflowName?: string;
301
+ /** ISO timestamp or Date; matches rows with created_at > this. */
302
+ createdAfter?: string | Date;
303
+ limit?: number;
304
+ }
305
+ /**
306
+ * READ-ONLY: SELECT from `dispatch_queue` with optional status + job-name
307
+ * filters and a bounded limit (defaults to 100). Includes source_tar_url,
308
+ * deps_url, and job_config so E2E tests can assert on cache metadata
309
+ * without a second round-trip.
310
+ */
311
+ export declare function listQueueDirect(databaseUrl: string, opts?: ListQueueOpts): Promise<{
312
+ entries: DispatchQueueRow[];
313
+ }>;
314
+ /**
315
+ * READ-ONLY: SELECT a single dispatch_queue row by id. Throws with a
316
+ * clear message when no row matches.
317
+ */
318
+ export declare function showQueueEntryDirect(databaseUrl: string, opts: {
319
+ id: string;
320
+ }): Promise<DispatchQueueRow>;
321
+ export interface ExecutionRunRow {
322
+ id: string;
323
+ run_id: string;
324
+ workflow_name: string;
325
+ status: string;
326
+ provider: string;
327
+ repo_identifier: string;
328
+ ref: string;
329
+ sha: string;
330
+ routing_key: string | null;
331
+ environment: string | null;
332
+ trust_tier: string | null;
333
+ created_at: string;
334
+ started_at: string;
335
+ completed_at: string | null;
336
+ duration_ms: number | null;
337
+ }
338
+ export interface ExecutionJobRow {
339
+ id: string;
340
+ run_id: string;
341
+ job_id: string;
342
+ job_name: string;
343
+ status: string;
344
+ agent_id: string | null;
345
+ started_at: string | null;
346
+ completed_at: string | null;
347
+ duration_ms: number | null;
348
+ created_at: string;
349
+ error_message: string | null;
350
+ }
351
+ export interface ListExecutionRunsOpts {
352
+ routingKey?: string;
353
+ status?: string;
354
+ workflowName?: string;
355
+ limit?: number;
356
+ }
357
+ /**
358
+ * READ-ONLY: SELECT execution_runs with optional filters. Ordered by
359
+ * created_at DESC, capped at a sensible limit.
360
+ */
361
+ export declare function listExecutionRunsDirect(databaseUrl: string, opts?: ListExecutionRunsOpts): Promise<{
362
+ runs: ExecutionRunRow[];
363
+ }>;
364
+ /**
365
+ * READ-ONLY: fetch a single run by run_id AND its jobs. Throws if no run
366
+ * matches the run_id. Jobs list may be empty for pending runs.
367
+ */
368
+ export declare function showExecutionRunDirect(databaseUrl: string, opts: {
369
+ runId: string;
370
+ }): Promise<{
371
+ run: ExecutionRunRow;
372
+ jobs: ExecutionJobRow[];
373
+ }>;
374
+ /**
375
+ * READ-ONLY: list execution_jobs for a given execution_runs.id. Ordered by
376
+ * created_at ASC so downstream diffs show timeline order.
377
+ */
378
+ export declare function listExecutionJobsDirect(databaseUrl: string, opts: {
379
+ runId: string;
380
+ }): Promise<{
381
+ jobs: ExecutionJobRow[];
382
+ }>;
383
+ export interface WorkflowRegistrationRow {
384
+ id: string;
385
+ repo_identifier: string;
386
+ workflow_name: string;
387
+ routing_key: string;
388
+ customer_id: string;
389
+ trigger_types: string[];
390
+ disabled: boolean;
391
+ is_global: boolean;
392
+ commit_sha: string | null;
393
+ source_file: string | null;
394
+ created_at: string;
395
+ updated_at: string;
396
+ }
397
+ export interface ListRegistrationsOpts {
398
+ customerId?: string;
399
+ routingKey?: string;
400
+ repoIdentifier?: string;
401
+ /** Include rows where this trigger type is in trigger_types[]. */
402
+ triggerType?: string;
403
+ limit?: number;
404
+ }
405
+ export interface ListRegistrationsResult {
406
+ registrations: WorkflowRegistrationRow[];
407
+ /** Latest `registry_versions.version`, or null if the table has no row. */
408
+ registryVersion: number | null;
409
+ }
410
+ /**
411
+ * READ-ONLY: list workflow_registrations with optional filters. Also returns
412
+ * the latest registry_versions.version so callers can assert registry bumps
413
+ * without a second round trip.
414
+ */
415
+ export declare function listRegistrationsDirect(databaseUrl: string, opts?: ListRegistrationsOpts): Promise<ListRegistrationsResult>;
416
+ export interface ShowRegistrationResult {
417
+ registration: WorkflowRegistrationRow & {
418
+ lock_entry: unknown;
419
+ provider_context: unknown;
420
+ };
421
+ registryVersion: number | null;
422
+ }
423
+ /**
424
+ * READ-ONLY: show one workflow_registrations row by id, plus the latest
425
+ * registry_versions row (the monotonic version bumped on every registration
426
+ * insert/delete). Throws if the registration id is unknown.
427
+ */
428
+ export declare function showRegistrationDirect(databaseUrl: string, opts: {
429
+ id: string;
430
+ }): Promise<ShowRegistrationResult>;
431
+ /**
432
+ * Registerable trigger types. Kept in sync with
433
+ * packages/orchestrator/src/registration/extractor.ts — any trigger whose type
434
+ * is in this set (or which pins `repos: [...]` patterns) produces a
435
+ * workflow_registrations row on default-branch push extraction.
436
+ *
437
+ * Duplicated here intentionally so the helper has no runtime dependency on
438
+ * the engine package.
439
+ */
440
+ export declare const REGISTERABLE_TRIGGER_TYPES: ReadonlySet<string>;
441
+ interface MinimalLockEntry {
442
+ name: string;
443
+ triggers: ReadonlyArray<{
444
+ _type: string;
445
+ repos?: unknown[];
446
+ [k: string]: unknown;
447
+ }>;
448
+ [k: string]: unknown;
449
+ }
450
+ interface MinimalLockFileShape {
451
+ workflows: readonly MinimalLockEntry[];
452
+ }
453
+ export interface RegisterWorkflowManualOpts {
454
+ /** Either `lockFileContents` (raw JSON string) OR `lockFile` (parsed object). */
455
+ lockFileContents?: string;
456
+ lockFile?: MinimalLockFileShape;
457
+ repoIdentifier: string;
458
+ routingKey: string;
459
+ customerId: string;
460
+ providerContext: Record<string, unknown>;
461
+ commitSha?: string;
462
+ }
463
+ export interface RegisterWorkflowManualResult {
464
+ workflowCount: number;
465
+ registryVersion: number;
466
+ }
467
+ /**
468
+ * Transactionally upsert `workflow_registrations` rows from a lock file and
469
+ * bump `registry_versions.version`. Mirrors the orchestrator's
470
+ * RegistrationStore.replaceAll() path but runs offline — the E2E test helpers
471
+ * `seedWorkflowRegistrationsFromLockFile` called this pattern via raw pg.Pool
472
+ * before this helper existed.
473
+ *
474
+ * Writes one row per registerable workflow (UPSERT by
475
+ * (routing_key, repo_identifier, workflow_name)), then bumps
476
+ * `registry_versions` in the same transaction so orchestrator processes
477
+ * watching that row refresh their in-memory index.
478
+ */
479
+ export declare function registerWorkflowManualDirect(databaseUrl: string, opts: RegisterWorkflowManualOpts): Promise<RegisterWorkflowManualResult>;
480
+ /**
481
+ * DELETE all rows from `raft_state` so a freshly-started orchestrator
482
+ * self-elects with a clean term. Used after swapping the running
483
+ * orchestrator process (warm-mode deploys) — without this, the new
484
+ * process loads a high term and takes 60+ seconds cycling through
485
+ * failed election rounds. Returns the number of rows deleted.
486
+ *
487
+ * Safe for repeated calls — if the table is empty, returns 0.
488
+ */
489
+ export declare function resetRaftStateDirect(databaseUrl: string): Promise<{
490
+ rowsDeleted: number;
491
+ }>;
492
+ export interface EmitKiciEventOpts {
493
+ eventName: string;
494
+ payload: Record<string, unknown>;
495
+ sourceRoutingKey?: string;
496
+ sourceRepo?: string;
497
+ }
498
+ /**
499
+ * INSERT a row into `kici_events` and fire `pg_notify('kici_event_channel', <id>)`
500
+ * so the orchestrator EventRouter picks it up immediately. Used by Bucket B/C
501
+ * e2e helpers to simulate what `agent ctx.emit()` does from inside a step
502
+ * execution — but without needing an actual running step. Returns the event id.
503
+ *
504
+ * Fixed `chain_depth=0` and `expires_at=NOW() + 1h` match emitInternalEvent()
505
+ * in e2e/helpers/internal-webhook.ts, which this helper supersedes.
506
+ */
507
+ export declare function emitKiciEventDirect(databaseUrl: string, opts: EmitKiciEventOpts): Promise<{
508
+ eventId: string;
509
+ }>;
510
+ export interface SeedGenericWebhookSourceOpts {
511
+ orgId: string;
512
+ name: string;
513
+ /** Pre-computed deterministic UUID (caller derives via sha256(orgId:name)) */
514
+ sourceId: string;
515
+ /** Pre-computed routing key (caller uses `generic:${orgId}:${name}`) */
516
+ routingKey: string;
517
+ verificationMethod?: string;
518
+ /** 'generic' (Stripe-shaped) or 'internal' (github-shaped via InternalWebhookNormalizer) */
519
+ providerType?: 'generic' | 'internal';
520
+ }
521
+ /**
522
+ * Upsert a row into `generic_webhook_sources` for internal E2E tests. Uses
523
+ * `ON CONFLICT (routing_key) DO UPDATE` so warm-start mode (where the source
524
+ * may already exist from a prior run) is idempotent.
525
+ *
526
+ * IMPORTANT: callers must invoke this BEFORE the orchestrator starts, because
527
+ * GenericSourceManager caches sources at boot and does not reload them later.
528
+ * This helper supersedes seedGenericWebhookSource() in
529
+ * e2e/helpers/internal-webhook.ts.
530
+ */
531
+ export declare function seedGenericWebhookSourceDirect(databaseUrl: string, opts: SeedGenericWebhookSourceOpts): Promise<void>;
532
+ /**
533
+ * Return `{ current: true }` if the applied migration count matches the
534
+ * provider's migration count AND the content hash in `_migration_content_hash`
535
+ * matches the provider's current hash. Otherwise return `{ current: false,
536
+ * reason }` with a human-readable reason.
537
+ *
538
+ * Callers use this as a warm-start freshness gate — if not current, do a cold
539
+ * start (`db fresh`).
540
+ */
541
+ export declare function isSchemaCurrent(pool: pg.Pool, provider: MigrationProvider): Promise<{
542
+ current: boolean;
543
+ reason?: string;
544
+ }>;
545
+ /**
546
+ * Purge backends whose encrypted `config` column can no longer be decrypted
547
+ * (e.g. warm-start E2E where KICI_SECRET_KEY rotated between categories).
548
+ *
549
+ * Only rows with a non-empty `config_encrypted` are affected — the default
550
+ * `pg` backend is seeded by the initial migration with `config_encrypted = ''`
551
+ * as a sentinel (loadAllStores() skips decryption for it), so it is never the
552
+ * source of the decryption failure and must be preserved. Deleting it breaks
553
+ * downstream tests that rely on the default backend being registered.
554
+ */
555
+ export declare function purgeSecretBackendsDirect(databaseUrl: string): Promise<{
556
+ deleted: number;
557
+ }>;
558
+ /**
559
+ * Check if an API key exists in the Platform DB (api_keys table — orchestrator-
560
+ * managed, NOT user_api_keys). Returns true when a row matches the hashed key.
561
+ */
562
+ export declare function apiKeyExistsDirect(databaseUrl: string, apiKey: string): Promise<boolean>;
563
+ /**
564
+ * Insert an api_keys row (Platform-side orchestrator credential). Used by
565
+ * e2e setup to seed an orchestrator authentication token. Returns the id.
566
+ */
567
+ export declare function seedApiKeyInlineDirect(databaseUrl: string, opts: {
568
+ keyName: string;
569
+ orgId: string;
570
+ fullKey: string;
571
+ }): Promise<{
572
+ keyId: string;
573
+ }>;
574
+ /**
575
+ * Lookup a `platform_connections` row by connection_id. Returns true when
576
+ * present. Used by the orphan-sweeper e2e test.
577
+ */
578
+ export declare function platformConnectionExistsDirect(databaseUrl: string, connectionId: string): Promise<boolean>;
579
+ /**
580
+ * Count `webhook_sources` rows for a given orchestrator_connection_id.
581
+ * Used by the orphan-sweeper e2e test to assert the FK CASCADE introduced
582
+ * by Platform migration 017 actually fires when the parent
583
+ * `platform_connections` row is deleted.
584
+ */
585
+ export declare function countWebhookSourcesByConnectionIdDirect(databaseUrl: string, connectionId: string): Promise<number>;
586
+ /**
587
+ * Find a `user_api_keys.id` preferring rows scoped to `preferredOrgId`, else
588
+ * any row in the table. Used by orphan-sweeper test to get a realistic
589
+ * `key_id` for platform_connections seeding.
590
+ */
591
+ export declare function findAnyUserApiKeyIdDirect(databaseUrl: string, preferredOrgId: string): Promise<string | null>;
592
+ /**
593
+ * Seed or refresh a synthetic GitHub webhook source on the Platform DB.
594
+ * Used by HMAC E2E tests that post to `/webhook/:orgId/github`.
595
+ * Idempotent — refreshes the secret/org_id via ON CONFLICT DO UPDATE,
596
+ * and clears stale rows with a different routing_key under the same
597
+ * (org_id, provider, connection_id) triple.
598
+ */
599
+ export declare function seedSyntheticGithubSourceDirect(databaseUrl: string, opts: {
600
+ routingKey: string;
601
+ orgId: string;
602
+ }): Promise<void>;
603
+ /**
604
+ * Seed a webhook secret into the orchestrator's `scoped_secrets` table,
605
+ * encrypted with the caller-supplied key. Ensures a `sources` row exists
606
+ * for the routing_key. Used by e2e setup on the orchestrator DB side.
607
+ *
608
+ * encryptFn takes plaintext + AAD and returns ciphertext bytes. The
609
+ * caller owns the crypto primitive so this helper stays decoupled from
610
+ * the orchestrator's PgSecretStore crypto module.
611
+ */
612
+ export declare function seedWebhookSecretDirect(databaseUrl: string, opts: {
613
+ routingKey: string;
614
+ webhookSecret: string;
615
+ encryptFn: (plaintext: string, aad: string) => string | Buffer;
616
+ }): Promise<{
617
+ sourceId: string;
618
+ }>;
619
+ /**
620
+ * Seed a source private key into the orchestrator's `scoped_secrets` table.
621
+ * encryptFn signature matches seedWebhookSecretDirect. Returns null if the
622
+ * sources row is missing (matches legacy warning-and-skip behaviour).
623
+ */
624
+ export declare function seedSourcePrivateKeyDirect(databaseUrl: string, opts: {
625
+ routingKey: string;
626
+ privateKey: string;
627
+ encryptFn: (plaintext: string, aad: string) => string | Buffer;
628
+ }): Promise<{
629
+ sourceId: string;
630
+ } | null>;
631
+ /**
632
+ * Bump `registry_versions.version` for the default registry and return the
633
+ * new value. Used by cron-scheduler e2e to retrigger index after a manual
634
+ * workflow change.
635
+ */
636
+ export declare function bumpRegistryVersionDirect(databaseUrl: string): Promise<number>;
637
+ /**
638
+ * Poll `kici_events` for an event matching `eventName` created after `since`.
639
+ * Returns the newest match, or throws on timeout. Used by e2e event-routing tests.
640
+ */
641
+ export declare function pollKiciEventsDirect(databaseUrl: string, opts: {
642
+ eventName: string;
643
+ since: Date;
644
+ timeoutMs?: number;
645
+ pollIntervalMs?: number;
646
+ payloadFilter?: {
647
+ key: string;
648
+ value: string;
649
+ };
650
+ }): Promise<Record<string, unknown>>;
651
+ /**
652
+ * Ping a PostgreSQL database; retries until `SELECT 1` succeeds or the
653
+ * timeout expires. Used by e2e startup to wait for Postgres readiness.
654
+ */
655
+ export declare function waitForPostgresDirect(databaseUrl: string, opts?: {
656
+ timeoutMs?: number;
657
+ intervalMs?: number;
658
+ }): Promise<void>;
659
+ /**
660
+ * Wait for a specific execution_runs row to reach a terminal status.
661
+ * Used by test-pipeline e2e to gate on run completion. Terminal statuses
662
+ * are success / failed / cancelled / timed_out_stale.
663
+ */
664
+ export declare function waitForRunCompletionDirect(databaseUrl: string, runId: string, opts?: {
665
+ timeoutMs?: number;
666
+ intervalMs?: number;
667
+ }): Promise<{
668
+ status: string;
669
+ }>;
670
+ /**
671
+ * DELETE from execution_jobs + execution_runs where started_at > since.
672
+ * Used by e2e cleanup for tests that want explicit post-test row cleanup.
673
+ */
674
+ export declare function cleanupExecutionRowsDirect(databaseUrl: string, since: Date): Promise<{
675
+ runs: number;
676
+ jobs: number;
677
+ }>;
678
+ /**
679
+ * Check whether the schema is "current" by comparing applied migration count
680
+ * and content hash against a caller-supplied set of migration files.
681
+ * Returns false if the migration table is missing, counts mismatch, or the
682
+ * stored hash differs from the caller-supplied hash. Used by e2e warm-start.
683
+ */
684
+ export declare function isSchemaCurrentFromFilesDirect(databaseUrl: string, opts: {
685
+ tableName?: string;
686
+ expectedCount: number;
687
+ expectedContentHash: string;
688
+ }): Promise<boolean>;
689
+ /**
690
+ * Store a migration content hash in the `_migration_content_hash` marker
691
+ * table. Creates the table if missing. Used by e2e freshDatabase() after
692
+ * migrations run so warm-start detection can compare on next run.
693
+ */
694
+ export declare function storeMigrationContentHashInTableDirect(databaseUrl: string, opts: {
695
+ tableName?: string;
696
+ contentHash: string;
697
+ }): Promise<void>;
698
+ /**
699
+ * Insert a join_tokens row (orchestrator DB) for cluster peer auth.
700
+ * Used by cluster e2e helpers to provision a shared secret the second
701
+ * orchestrator will use when joining the cluster.
702
+ */
703
+ export declare function createJoinTokenDirect(databaseUrl: string, opts: {
704
+ id: string;
705
+ tokenHash: string;
706
+ routingInfo: Record<string, unknown>;
707
+ role: string;
708
+ createdBy: string;
709
+ expiresAt: Date;
710
+ }): Promise<void>;
711
+ /**
712
+ * Update the routing_key on `sources` rows for a given provider. Used by
713
+ * cluster e2e to swap the staging routing key for an isolated test key
714
+ * (and to restore it on teardown).
715
+ *
716
+ * `whereRoutingKey`: optional filter on the current routing_key. When
717
+ * present only rows matching it are updated; when absent the provider
718
+ * filter alone is used (with an implicit `!= newRoutingKey` guard so the
719
+ * update is idempotent).
720
+ */
721
+ export declare function updateSourceRoutingKeyDirect(databaseUrl: string, opts: {
722
+ provider: string;
723
+ newRoutingKey: string;
724
+ whereRoutingKey?: string;
725
+ }): Promise<{
726
+ updated: number;
727
+ }>;
728
+ /**
729
+ * Delete peer_credentials rows whose instance_id does NOT match a pattern.
730
+ * Used by cluster e2e to wipe stale staging peer credentials while leaving
731
+ * e2e-* peers intact.
732
+ */
733
+ export declare function prunePeerCredentialsDirect(databaseUrl: string, opts: {
734
+ keepInstanceIdPattern: string;
735
+ }): Promise<{
736
+ deleted: number;
737
+ }>;
738
+ /**
739
+ * Poll Platform until at least `minRegistrations` distinct orchestrator
740
+ * connections are BOTH registered for the routing key (row in webhook_sources)
741
+ * AND live (row in platform_connections with status='connected'). The live-
742
+ * connection join is critical — Platform's webhook_sources rows persist after
743
+ * a connection disconnects (the orphan sweeper eventually reaps them), so a
744
+ * naive COUNT(DISTINCT) on webhook_sources alone would inflate the number
745
+ * and mask a missing coordinator registration.
746
+ */
747
+ export declare function waitForPlatformRegistrationsDirect(platformDbUrl: string, routingKey: string, opts?: {
748
+ minRegistrations?: number;
749
+ timeoutMs?: number;
750
+ intervalMs?: number;
751
+ }): Promise<void>;
752
+ /**
753
+ * Seed a generic_webhook_sources row with a custom `event_type_header` and
754
+ * `git_config` payload. Used by universal-git e2e (Forgejo) to register
755
+ * an ingest endpoint that extracts the event type from Gitea-style headers.
756
+ */
757
+ export interface SeedUniversalGitSourceOpts {
758
+ orgId: string;
759
+ sourceId: string;
760
+ sourceName: string;
761
+ routingKey: string;
762
+ gitConfig: Record<string, unknown>;
763
+ eventTypeHeader?: string;
764
+ }
765
+ export declare function seedUniversalGitSourceDirect(databaseUrl: string, opts: SeedUniversalGitSourceOpts): Promise<void>;
766
+ /**
767
+ * Seed the ci-security orchestrator fixtures expected by the security
768
+ * pipeline e2e: sources row for dashboard orgId resolution, environment,
769
+ * two execution_runs (unknown + trusted), two execution_jobs, and a
770
+ * security held_run for the unknown contributor.
771
+ *
772
+ * Returns the ids so the caller can assert downstream.
773
+ */
774
+ export interface SeedCiSecurityFixturesOpts {
775
+ orgId: string;
776
+ envName?: string;
777
+ sourceName?: string;
778
+ sourceRoutingKey?: string;
779
+ runsRoutingKey: string;
780
+ unknownRunId: string;
781
+ unknownDeliveryId: string;
782
+ unknownJobId: string;
783
+ trustedRunId: string;
784
+ trustedDeliveryId: string;
785
+ trustedJobId: string;
786
+ }
787
+ export interface SeedCiSecurityFixturesResult {
788
+ envId: string;
789
+ heldRunId: string;
790
+ }
791
+ export declare function seedCiSecurityFixturesDirect(databaseUrl: string, opts: SeedCiSecurityFixturesOpts): Promise<SeedCiSecurityFixturesResult>;
792
+ /**
793
+ * Poll `execution_runs` for at least one row matching `status` whose
794
+ * `started_at > since`. Used by cluster/job-reroute tests to gate on
795
+ * a workflow reaching the terminal state after a webhook trigger.
796
+ */
797
+ export declare function waitForExecutionRunStatusSinceDirect(databaseUrl: string, opts: {
798
+ status: string;
799
+ since: Date;
800
+ timeoutMs?: number;
801
+ intervalMs?: number;
802
+ }): Promise<{
803
+ found: boolean;
804
+ }>;
805
+ /**
806
+ * Fetch the most recent `execution_runs` row matching `status`, plus its
807
+ * `execution_jobs`. Used by cluster reroute tests to confirm the run +
808
+ * its jobs completed successfully.
809
+ */
810
+ export interface LatestExecutionRunResult {
811
+ run: {
812
+ run_id: string;
813
+ workflow_name: string;
814
+ status: string;
815
+ };
816
+ jobs: Array<{
817
+ job_id: string;
818
+ job_name: string;
819
+ status: string;
820
+ }>;
821
+ }
822
+ export declare function latestExecutionRunByStatusDirect(databaseUrl: string, opts: {
823
+ status: string;
824
+ }): Promise<LatestExecutionRunResult | null>;
825
+ /**
826
+ * Wait for a `execution_jobs` row joined against the most recent
827
+ * `execution_runs` for a given workflow name with started_at >= since,
828
+ * returning the job's status + error + run_id. Used by secrets-pipeline
829
+ * to gate on terminal job status.
830
+ */
831
+ export interface WaitForLatestJobResult {
832
+ status: string | null;
833
+ errorMessage: string | null;
834
+ runId: string | null;
835
+ }
836
+ export declare function waitForLatestExecutionJobStatusDirect(databaseUrl: string, opts: {
837
+ workflowName: string;
838
+ since: Date;
839
+ terminalStatuses?: readonly string[];
840
+ timeoutMs?: number;
841
+ intervalMs?: number;
842
+ }): Promise<WaitForLatestJobResult>;
843
+ /**
844
+ * READ-ONLY: return information_schema column names for `tableName`,
845
+ * ordered by ordinal_position. Used by e2e tests to verify migrations
846
+ * produced expected schema shape. Returns empty array if the table
847
+ * doesn't exist.
848
+ */
849
+ export interface ColumnInfo {
850
+ name: string;
851
+ dataType: string;
852
+ }
853
+ export declare function describeTableColumnsDirect(databaseUrl: string, opts: {
854
+ tableName: string;
855
+ }): Promise<ColumnInfo[]>;
856
+ /**
857
+ * READ-ONLY: return true if a table exists in the public schema.
858
+ */
859
+ export declare function tableExistsDirect(databaseUrl: string, opts: {
860
+ tableName: string;
861
+ schema?: string;
862
+ }): Promise<boolean>;
863
+ /**
864
+ * Raw INSERT into kici_events with custom chain_depth + expiry window.
865
+ * Used by event-routing e2e to test circuit-breaker + TTL behavior
866
+ * beyond what `emitKiciEventDirect` exposes (which hardcodes depth=0
867
+ * and 1h expiry). Returns the inserted id.
868
+ */
869
+ export interface InsertKiciEventRawOpts {
870
+ eventName: string;
871
+ payload: Record<string, unknown>;
872
+ sourceRoutingKey?: string;
873
+ chainDepth?: number;
874
+ /** ISO string or relative '1 hour' / '-1 hour'. Use negative for expired. */
875
+ expiresIn?: string;
876
+ }
877
+ export declare function insertKiciEventRawDirect(databaseUrl: string, opts: InsertKiciEventRawOpts): Promise<{
878
+ id: string;
879
+ }>;
880
+ /**
881
+ * READ-ONLY: return a kici_events row by id, or null. Callers decode
882
+ * `payload` as they need. Used by event-routing e2e after an INSERT.
883
+ */
884
+ export interface KiciEventRow {
885
+ id: string;
886
+ event_name: string;
887
+ payload: Record<string, unknown>;
888
+ chain_depth: number;
889
+ source_routing_key: string | null;
890
+ source_repo: string | null;
891
+ processed: boolean | null;
892
+ expires_at: string;
893
+ created_at: string;
894
+ }
895
+ export declare function showKiciEventDirect(databaseUrl: string, opts: {
896
+ id: string;
897
+ }): Promise<KiciEventRow | null>;
898
+ /**
899
+ * READ-ONLY: list kici_events with filter hooks used by e2e tests:
900
+ * by `event_name`, minimum `chain_depth`, expiry window. Returns the
901
+ * rows with chain_depth ordered ascending. Callers apply assertions.
902
+ */
903
+ export declare function listKiciEventsDirect(databaseUrl: string, opts?: {
904
+ eventName?: string;
905
+ minChainDepth?: number;
906
+ /** When true, return only rows past their expires_at. */
907
+ onlyExpired?: boolean;
908
+ /** When set, cap to this many rows. */
909
+ limit?: number;
910
+ }): Promise<KiciEventRow[]>;
911
+ /**
912
+ * DELETE kici_events by id or event_name. Returns the number of rows
913
+ * deleted. Used by event-routing teardown.
914
+ */
915
+ export declare function deleteKiciEventsDirect(databaseUrl: string, opts: {
916
+ id?: string;
917
+ eventName?: string;
918
+ }): Promise<{
919
+ deleted: number;
920
+ }>;
921
+ /**
922
+ * Simulate a NOTIFY on `kici_event_channel` and verify a LISTEN client
923
+ * receives it. Used by event-routing e2e to prove the infrastructure
924
+ * the EventRouter uses for real-time delivery is functional. Owns the
925
+ * pool for the full test to keep the listen/notify correlated.
926
+ */
927
+ export declare function verifyKiciEventNotifyDirect(databaseUrl: string, opts: {
928
+ payload: string;
929
+ waitMs?: number;
930
+ }): Promise<{
931
+ received: string[];
932
+ }>;
933
+ export interface CrossRepoTrustRow {
934
+ id: string;
935
+ source_repo: string;
936
+ source_routing_key: string;
937
+ target_repo: string;
938
+ target_routing_key: string;
939
+ allowed_events: string[] | null;
940
+ }
941
+ /**
942
+ * INSERT a cross_repo_trust row. Returns the new id and allowed_events
943
+ * array. Used by generic-webhook + event-routing e2e until a proper
944
+ * `kici-admin trust` CLI ships.
945
+ */
946
+ export declare function seedCrossRepoTrustDirect(databaseUrl: string, opts: {
947
+ sourceRepo: string;
948
+ sourceRoutingKey: string;
949
+ targetRepo: string;
950
+ targetRoutingKey: string;
951
+ allowedEvents?: string[];
952
+ }): Promise<{
953
+ id: string;
954
+ allowedEvents: string[] | null;
955
+ }>;
956
+ /**
957
+ * READ-ONLY: list cross_repo_trust rows by source_routing_key. Used by
958
+ * generic-webhook e2e to find a trust row it just inserted.
959
+ */
960
+ export declare function listCrossRepoTrustBySourceRoutingKeyDirect(databaseUrl: string, opts: {
961
+ sourceRoutingKey: string;
962
+ }): Promise<CrossRepoTrustRow[]>;
963
+ /**
964
+ * DELETE cross_repo_trust rows. Deletes by id, or asserts uniqueness
965
+ * check error on duplicate INSERT (handled by caller). Returns row count.
966
+ */
967
+ export declare function deleteCrossRepoTrustDirect(databaseUrl: string, opts: {
968
+ id: string;
969
+ }): Promise<{
970
+ deleted: number;
971
+ }>;
972
+ /**
973
+ * Direct INSERT with duplicate-key detection. Used by event-routing
974
+ * e2e to verify the unique constraint enforces. Throws on duplicate;
975
+ * caller asserts the error message matches /unique/i.
976
+ */
977
+ export declare function insertCrossRepoTrustStrictDirect(databaseUrl: string, opts: {
978
+ sourceRepo: string;
979
+ sourceRoutingKey: string;
980
+ targetRepo: string;
981
+ targetRoutingKey: string;
982
+ }): Promise<void>;
983
+ /**
984
+ * Cleanup helper for workflow_registrations. Accepts id, routingKey,
985
+ * or repoIdentifier filter (exactly one). Returns delete count.
986
+ */
987
+ export declare function deleteWorkflowRegistrationsDirect(databaseUrl: string, opts: {
988
+ id?: string;
989
+ routingKey?: string;
990
+ repoIdentifier?: string;
991
+ }): Promise<{
992
+ deleted: number;
993
+ }>;
994
+ /**
995
+ * READ-ONLY: workflow_registrations by id — returns null when missing.
996
+ * Pulls the full row so tests can assert lock_entry contents + trigger_types.
997
+ */
998
+ export interface WorkflowRegistrationFullRow extends WorkflowRegistrationRow {
999
+ lock_entry: unknown;
1000
+ }
1001
+ export declare function getWorkflowRegistrationByIdDirect(databaseUrl: string, opts: {
1002
+ id: string;
1003
+ }): Promise<WorkflowRegistrationFullRow | null>;
1004
+ /**
1005
+ * READ-ONLY: return the count + optional rows + latest updated_at for
1006
+ * workflow_registrations scoped to a routing key. Used by forgejo e2e
1007
+ * to wait for extraction + verify re-extraction bumped updated_at.
1008
+ */
1009
+ export interface RegistrationsScopedResult {
1010
+ count: number;
1011
+ latestUpdatedAt: Date | null;
1012
+ rows: Array<{
1013
+ workflow_name: string;
1014
+ is_global: boolean;
1015
+ }>;
1016
+ }
1017
+ export declare function listRegistrationsByRoutingKeyDirect(databaseUrl: string, opts: {
1018
+ routingKey: string;
1019
+ onlyGlobal?: boolean;
1020
+ }): Promise<RegistrationsScopedResult>;
1021
+ /**
1022
+ * Poll `workflow_registrations` for at least `minCount` rows for a
1023
+ * routing key. Returns the rows or throws on timeout (keeps parity with
1024
+ * the forgejo helper pattern it replaces).
1025
+ */
1026
+ export declare function waitForRegistrationsByRoutingKeyDirect(databaseUrl: string, opts: {
1027
+ routingKey: string;
1028
+ minCount?: number;
1029
+ onlyGlobal?: boolean;
1030
+ timeoutMs?: number;
1031
+ intervalMs?: number;
1032
+ }): Promise<Array<{
1033
+ workflow_name: string;
1034
+ is_global: boolean;
1035
+ }>>;
1036
+ /**
1037
+ * Wait for `workflow_registrations.updated_at` for a routing key to
1038
+ * exceed `baselineUpdatedAt`. Used by forgejo rotated-PAT e2e.
1039
+ */
1040
+ export declare function waitForRegistrationsUpdatedAtAdvanceDirect(databaseUrl: string, opts: {
1041
+ routingKey: string;
1042
+ baselineUpdatedAt: Date | null;
1043
+ timeoutMs?: number;
1044
+ intervalMs?: number;
1045
+ }): Promise<{
1046
+ advanced: boolean;
1047
+ latestUpdatedAt: Date | null;
1048
+ }>;
1049
+ /**
1050
+ * UPDATE a workflow_registrations row's commit_sha. Used by cron-scheduler
1051
+ * e2e where the manual-schedule handler rejects null commit SHAs.
1052
+ */
1053
+ export declare function updateWorkflowRegistrationCommitShaDirect(databaseUrl: string, opts: {
1054
+ id: string;
1055
+ commitSha: string;
1056
+ }): Promise<void>;
1057
+ /**
1058
+ * Lock-entry seeding for the admin-API e2e, which uses a custom
1059
+ * shape (cron schedule). Returns the inserted id.
1060
+ */
1061
+ export declare function insertWorkflowRegistrationRawDirect(databaseUrl: string, opts: {
1062
+ routingKey: string;
1063
+ repoIdentifier: string;
1064
+ workflowName: string;
1065
+ lockEntry: Record<string, unknown>;
1066
+ triggerTypes: string[];
1067
+ customerId: string;
1068
+ isGlobal?: boolean;
1069
+ disabled?: boolean;
1070
+ commitSha?: string;
1071
+ id?: string;
1072
+ }): Promise<{
1073
+ id: string;
1074
+ }>;
1075
+ /**
1076
+ * INSERT with a STRICT shape (no ON CONFLICT). Used by registration-schema
1077
+ * e2e to prove the unique constraint rejects duplicates. Throws the raw
1078
+ * DB error (caller matches /unique/i).
1079
+ */
1080
+ export declare function insertWorkflowRegistrationStrictDirect(databaseUrl: string, opts: {
1081
+ routingKey: string;
1082
+ repoIdentifier: string;
1083
+ workflowName: string;
1084
+ lockEntryJson?: string;
1085
+ triggerTypes: readonly string[];
1086
+ customerId: string;
1087
+ }): Promise<{
1088
+ id: string | null;
1089
+ }>;
1090
+ /**
1091
+ * READ-ONLY: latest registry_versions.version, or null if the default
1092
+ * row is missing. Used by registration-admin-api e2e to bracket a
1093
+ * refresh call.
1094
+ */
1095
+ export declare function getRegistryVersionDirect(databaseUrl: string, opts?: {
1096
+ id?: string;
1097
+ }): Promise<number | null>;
1098
+ /**
1099
+ * UPDATE `registry_versions.version = version + 1` WHERE id (default).
1100
+ * Simpler than `bumpRegistryVersionDirect` — used by global-workflow
1101
+ * e2e which wants the side-effect (force index refresh) without the
1102
+ * return value.
1103
+ */
1104
+ export declare function bumpRegistryVersionSimpleDirect(databaseUrl: string, opts?: {
1105
+ id?: string;
1106
+ }): Promise<void>;
1107
+ /**
1108
+ * Seed cron_last_fired for a registration with an `-INTERVAL` offset so
1109
+ * the scheduler fires on the next evaluation. Upsert via ON CONFLICT.
1110
+ */
1111
+ export declare function upsertCronLastFiredDirect(databaseUrl: string, opts: {
1112
+ registrationId: string;
1113
+ agoInterval: string;
1114
+ }): Promise<void>;
1115
+ /**
1116
+ * READ-ONLY: count cron_last_fired rows for a registration. Used by
1117
+ * registration-schema e2e to assert the FK cascade deletes the row.
1118
+ */
1119
+ export declare function countCronLastFiredDirect(databaseUrl: string, opts: {
1120
+ registrationId: string;
1121
+ }): Promise<number>;
1122
+ /**
1123
+ * INSERT a cron_last_fired row with an explicit timestamp. Used by
1124
+ * registration-schema e2e to set up the FK cascade test.
1125
+ */
1126
+ export declare function insertCronLastFiredNowDirect(databaseUrl: string, opts: {
1127
+ registrationId: string;
1128
+ }): Promise<void>;
1129
+ /**
1130
+ * DELETE cron_last_fired rows for a registration. Teardown helper.
1131
+ */
1132
+ export declare function deleteCronLastFiredDirect(databaseUrl: string, opts: {
1133
+ registrationId: string;
1134
+ }): Promise<void>;
1135
+ /**
1136
+ * DELETE execution_runs by workflow_name. Teardown helper for
1137
+ * manual-schedule e2e.
1138
+ */
1139
+ export declare function deleteExecutionRunsByWorkflowNameDirect(databaseUrl: string, opts: {
1140
+ workflowName: string;
1141
+ }): Promise<{
1142
+ deleted: number;
1143
+ }>;
1144
+ /**
1145
+ * READ-ONLY: SELECT generic_webhook_sources by routing_key.
1146
+ * Used by forgejo e2e to assert the source exists with correct git_config.
1147
+ */
1148
+ export declare function getGenericWebhookSourceByRoutingKeyDirect(databaseUrl: string, opts: {
1149
+ routingKey: string;
1150
+ }): Promise<{
1151
+ id: string;
1152
+ git_config: unknown;
1153
+ customer_id: string | null;
1154
+ } | null>;
1155
+ /**
1156
+ * READ-ONLY: list active (enabled=true) generic_webhook_sources.
1157
+ * Used by cluster-leader-failover e2e to prove the seeded source exists
1158
+ * before a leader crash.
1159
+ */
1160
+ export declare function listActiveGenericWebhookSourcesDirect(databaseUrl: string): Promise<Array<{
1161
+ id: string;
1162
+ customer_id: string | null;
1163
+ routing_key: string;
1164
+ }>>;
1165
+ /**
1166
+ * UPDATE generic_webhook_sources.verification_config for a source by
1167
+ * name + customer_id. Used by the generic-webhook-auth e2e which seeds
1168
+ * sources and then writes custom auth configs.
1169
+ */
1170
+ export declare function updateGenericWebhookVerificationConfigDirect(databaseUrl: string, opts: {
1171
+ name: string;
1172
+ customerId: string;
1173
+ verificationConfig: Record<string, unknown>;
1174
+ }): Promise<void>;
1175
+ /**
1176
+ * DELETE generic_webhook_sources by name list. Teardown for the auth
1177
+ * e2e, which seeded 3 sources by name.
1178
+ */
1179
+ export declare function deleteGenericWebhookSourcesByNameDirect(databaseUrl: string, opts: {
1180
+ names: readonly string[];
1181
+ }): Promise<{
1182
+ deleted: number;
1183
+ }>;
1184
+ /**
1185
+ * UPDATE generic_webhook_sources.deleted_at = NULL for a row by id.
1186
+ * Used by the generic-webhook e2e to restore a soft-deleted source
1187
+ * after the soft-delete test ran — there is no CLI-level undelete.
1188
+ */
1189
+ export declare function restoreSoftDeletedGenericWebhookSourceDirect(databaseUrl: string, opts: {
1190
+ id: string;
1191
+ }): Promise<void>;
1192
+ /**
1193
+ * One entry in any of the three repo-pattern lists stored on `org_settings`.
1194
+ * `routingKey` is the source-qualifier; when absent, the entry applies to
1195
+ * any source in the org.
1196
+ */
1197
+ export interface OrgSettingsRepoPatternEntry {
1198
+ routingKey?: string;
1199
+ pattern: string;
1200
+ }
1201
+ /**
1202
+ * UPSERT org_settings for a customer/org id. `globalWorkflowsEnabled` is
1203
+ * required; the three list fields are each optional. Each list is a jsonb
1204
+ * array of `{routingKey?, pattern}` entries. Pass `null` to clear a list.
1205
+ */
1206
+ export interface UpsertOrgSettingsOpts {
1207
+ customerId: string;
1208
+ globalWorkflowsEnabled: boolean;
1209
+ allowedRepos?: OrgSettingsRepoPatternEntry[] | null;
1210
+ deniedRepos?: OrgSettingsRepoPatternEntry[] | null;
1211
+ elevatedRepos?: OrgSettingsRepoPatternEntry[] | null;
1212
+ }
1213
+ export declare function upsertOrgSettingsGlobalWorkflowsDirect(databaseUrl: string, opts: UpsertOrgSettingsOpts): Promise<void>;
1214
+ /**
1215
+ * UPDATE org_settings.global_workflow_denied_repos for a customer/org id.
1216
+ * Assumes the row exists (upsertOrgSettingsGlobalWorkflowsDirect was
1217
+ * called earlier in the test).
1218
+ */
1219
+ export declare function updateOrgSettingsDeniedReposDirect(databaseUrl: string, opts: {
1220
+ customerId: string;
1221
+ deniedRepos: OrgSettingsRepoPatternEntry[] | null;
1222
+ }): Promise<void>;
1223
+ /**
1224
+ * DELETE org_settings by customer/org id. Teardown helper.
1225
+ */
1226
+ export declare function deleteOrgSettingsByCustomerIdDirect(databaseUrl: string, opts: {
1227
+ customerId: string;
1228
+ }): Promise<{
1229
+ deleted: number;
1230
+ }>;
1231
+ /**
1232
+ * READ-ONLY: fetch an execution_runs row by run_id, returning the
1233
+ * security-relevant columns the ci-security e2e asserts on. Throws
1234
+ * when the row is missing.
1235
+ */
1236
+ export interface ExecutionRunSecurityRow {
1237
+ run_id: string;
1238
+ trust_tier: string | null;
1239
+ lock_file_source: string | null;
1240
+ contributor_username: string | null;
1241
+ status: string;
1242
+ }
1243
+ export declare function getExecutionRunSecurityDirect(databaseUrl: string, opts: {
1244
+ runId: string;
1245
+ }): Promise<ExecutionRunSecurityRow>;
1246
+ /**
1247
+ * READ-ONLY: fetch a held_runs row by id (with the security columns).
1248
+ * Returns null if missing.
1249
+ */
1250
+ export interface HeldRunSecurityRow {
1251
+ id: string;
1252
+ run_id: string;
1253
+ hold_type: string;
1254
+ queue_type: string;
1255
+ status: string;
1256
+ reason: string | null;
1257
+ expires_at: string | null;
1258
+ approved_by: string | null;
1259
+ resolved_at: string | null;
1260
+ }
1261
+ export declare function getHeldRunByIdDirect(databaseUrl: string, opts: {
1262
+ id: string;
1263
+ }): Promise<HeldRunSecurityRow | null>;
1264
+ /**
1265
+ * READ-ONLY: count held_runs rows matching run_id + queue_type.
1266
+ * Used by ci-security e2e to prove no security hold exists for a
1267
+ * trusted contributor PR.
1268
+ */
1269
+ export declare function countHeldRunsByRunIdDirect(databaseUrl: string, opts: {
1270
+ runId: string;
1271
+ queueType?: string;
1272
+ }): Promise<number>;
1273
+ /**
1274
+ * Wait for Platform-side `execution_runs.status = <status>` where
1275
+ * `created_at > since`. Returns the final status + failure_reason or
1276
+ * null if the timeout elapsed. Used by webhook-pipeline (failed) and
1277
+ * orchestrator-never-reconnects (timed_out_stale).
1278
+ */
1279
+ export declare function waitForPlatformExecutionRunStatusDirect(databaseUrl: string, opts: {
1280
+ status: string;
1281
+ since: Date;
1282
+ timeoutMs?: number;
1283
+ intervalMs?: number;
1284
+ }): Promise<{
1285
+ status: string;
1286
+ failure_reason: string | null;
1287
+ } | null>;
1288
+ /**
1289
+ * Wait for Platform `event_log` to show at least `minDistinctRouted`
1290
+ * distinct `routed_to` values since a given timestamp. Used by
1291
+ * cluster-round-robin to prove at least 2 orchestrators received
1292
+ * deliveries. Returns the observed count (0 if timed out).
1293
+ */
1294
+ export declare function waitForPlatformEventLogDistinctRoutedDirect(databaseUrl: string, opts: {
1295
+ since: Date;
1296
+ minDistinctRouted: number;
1297
+ timeoutMs?: number;
1298
+ intervalMs?: number;
1299
+ }): Promise<{
1300
+ distinctRouted: number;
1301
+ }>;
1302
+ /**
1303
+ * Wait for an orchestrator `event_log` row keyed by `delivery_id`.
1304
+ * Returns the full row (the webhook-pipeline e2e asserts many
1305
+ * columns) or null on timeout.
1306
+ */
1307
+ export interface EventLogRow {
1308
+ org_id: string;
1309
+ delivery_id: string;
1310
+ status: string;
1311
+ source: string;
1312
+ event: string;
1313
+ provider: string;
1314
+ payload_hash: string;
1315
+ payload_omitted: boolean;
1316
+ payload_key: string | null;
1317
+ payload_size_bytes: number;
1318
+ matched_count: number;
1319
+ run_id: string | null;
1320
+ }
1321
+ export declare function waitForEventLogRowByDeliveryIdDirect(databaseUrl: string, opts: {
1322
+ deliveryId: string;
1323
+ timeoutMs?: number;
1324
+ intervalMs?: number;
1325
+ }): Promise<EventLogRow | null>;
1326
+ /**
1327
+ * Resolve a Platform `webhook_sources.routing_key` for an org.
1328
+ *
1329
+ * - With `routingKeyLikePrefix` only: returns the newest match. Note that
1330
+ * this picks whichever generic source was registered most recently — if
1331
+ * tests have created additional generic sources (e.g. universal-git-forgejo
1332
+ * creating `stg-universal-git-forgejo`), the newest may NOT be the
1333
+ * `stg-generic` default seeded by `pnpm deploy:stg`.
1334
+ * - With `orchDbUrl` + `nameInOrchDb`: looks up the source by name in the
1335
+ * orchestrator's `generic_webhook_sources` table, then verifies the
1336
+ * resulting routing key is registered in Platform's `webhook_sources`.
1337
+ * This is the disambiguating path Bucket-B tests should use when other
1338
+ * generic sources may exist alongside the default.
1339
+ */
1340
+ export declare function resolvePlatformWebhookSourceRoutingKeyDirect(platformDbUrl: string, opts: {
1341
+ orgId: string;
1342
+ routingKeyLikePrefix: string;
1343
+ orchDbUrl?: string;
1344
+ nameInOrchDb?: string;
1345
+ }): Promise<string | null>;
1346
+ /**
1347
+ * Idempotent seeding of an E2E regular user + org membership + owner
1348
+ * role on the Platform DB. Used by stg-ha-smoke before seeding a user
1349
+ * API key. Requires the org to already have an owner role.
1350
+ */
1351
+ export declare function ensureOrgOwnerMemberDirect(platformDbUrl: string, opts: {
1352
+ orgId: string;
1353
+ zitadelSub: string;
1354
+ email: string;
1355
+ displayName: string;
1356
+ }): Promise<{
1357
+ ownerRoleId: string;
1358
+ }>;
1359
+ /**
1360
+ * Cleanup peer_credentials by instance_id LIKE pattern. Used by the
1361
+ * cluster-peer-credentials e2e before/after each test to wipe its
1362
+ * own seeded rows without touching real cluster credentials.
1363
+ */
1364
+ export declare function deletePeerCredentialsByInstanceIdLikeDirect(databaseUrl: string, opts: {
1365
+ pattern: string;
1366
+ }): Promise<{
1367
+ deleted: number;
1368
+ }>;
1369
+ /**
1370
+ * Insert a peer_credentials row with an explicit expires_at. Used by
1371
+ * the "expired credential is not returned" e2e — the store's save()
1372
+ * always computes a future expiry, so tests that need a pre-expired
1373
+ * row must bypass it.
1374
+ */
1375
+ export declare function insertPeerCredentialExpiredDirect(databaseUrl: string, opts: {
1376
+ instanceId: string;
1377
+ credentialHash: string;
1378
+ role: string;
1379
+ routingKeys: readonly string[];
1380
+ expiresAt: Date;
1381
+ }): Promise<void>;
1382
+ /**
1383
+ * READ-ONLY: `revoked_at` for a peer_credentials row by hash. Used
1384
+ * by the "save revokes old credential" e2e to assert revocation.
1385
+ * Returns null when the row is missing entirely (distinct from
1386
+ * "present but not revoked").
1387
+ */
1388
+ export declare function getPeerCredentialRevokedAtDirect(databaseUrl: string, opts: {
1389
+ credentialHash: string;
1390
+ }): Promise<{
1391
+ present: boolean;
1392
+ revokedAt: Date | null;
1393
+ }>;
1394
+ /**
1395
+ * READ-ONLY: list active peer_credentials ids EXCLUDING a
1396
+ * `instance_id LIKE` pattern. Used by revokeAll e2e to snapshot
1397
+ * real cluster credentials it will restore later.
1398
+ */
1399
+ export declare function listActivePeerCredentialsExcludingDirect(databaseUrl: string, opts: {
1400
+ excludeInstanceIdPattern: string;
1401
+ }): Promise<{
1402
+ ids: string[];
1403
+ }>;
1404
+ /**
1405
+ * Clear revoked_at on a set of peer_credentials ids. Used by revokeAll
1406
+ * e2e to restore real cluster credentials after the destructive test.
1407
+ */
1408
+ export declare function clearPeerCredentialsRevokedAtByIdsDirect(databaseUrl: string, opts: {
1409
+ ids: readonly string[];
1410
+ }): Promise<{
1411
+ updated: number;
1412
+ }>;
1413
+ /**
1414
+ * READ-ONLY: count currently-active (non-revoked, non-expired)
1415
+ * peer_credentials rows for a given instance_id. Used by the
1416
+ * concurrent-save e2e to assert 1 <= count <= 2.
1417
+ */
1418
+ export declare function countActivePeerCredentialsByInstanceDirect(databaseUrl: string, opts: {
1419
+ instanceId: string;
1420
+ }): Promise<number>;
1421
+ export {};
1422
+ //# sourceMappingURL=db-admin.d.ts.map