@kici-dev/orchestrator 0.6.0 → 0.7.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/agent/dispatcher.d.ts +10 -1
- package/dist/agent/host-roster.d.ts +8 -3
- package/dist/agent/registry.d.ts +60 -5
- package/dist/app.d.ts +10 -5
- package/dist/cache/dep-cache.d.ts +14 -6
- package/dist/cache/global-eval-round-cache.d.ts +1 -1
- package/dist/cache/index.d.ts +1 -1
- package/dist/cache/source-cache.d.ts +92 -15
- package/dist/cancel/cancel-run.d.ts +20 -2
- package/dist/cancel/sweep-stuck-cancelling.d.ts +30 -0
- package/dist/cli/api-client.d.ts +10 -0
- package/dist/cli/commands/agent-service/logs.d.ts +1 -1
- package/dist/cli/commands/agent-service/restart.d.ts +1 -1
- package/dist/cli/commands/agent-service/start.d.ts +1 -1
- package/dist/cli/commands/agent-service/status.d.ts +1 -1
- package/dist/cli/commands/agent-service/stop.d.ts +1 -1
- package/dist/cli/commands/agent-service/uninstall.d.ts +1 -1
- package/dist/cli/commands/agent.d.ts +25 -0
- package/dist/cli/commands/config.d.ts +16 -0
- package/dist/cli/commands/db-backup.d.ts +46 -0
- package/dist/cli/commands/held-run.d.ts +9 -0
- package/dist/cli/commands/orchestrator-service/drain.d.ts +2 -19
- package/dist/cli/commands/orchestrator-service/index.d.ts +9 -1
- package/dist/cli/commands/orchestrator-service/install-env.d.ts +43 -2
- package/dist/cli/commands/orchestrator-service/logs.d.ts +1 -1
- package/dist/cli/commands/orchestrator-service/restart.d.ts +1 -1
- package/dist/cli/commands/orchestrator-service/start.d.ts +1 -1
- package/dist/cli/commands/orchestrator-service/status.d.ts +17 -1
- package/dist/cli/commands/orchestrator-service/stop.d.ts +1 -1
- package/dist/cli/commands/orchestrator-service/uninstall.d.ts +1 -1
- package/dist/cli/commands/orchestrator-service/upgrade.d.ts +2 -1
- package/dist/cli/commands/rotate.d.ts +1 -1
- package/dist/cli/commands/shared/env-file-mode.d.ts +16 -0
- package/dist/cli/commands/shared/upgrade-hooks.d.ts +32 -0
- package/dist/cli/commands/shared/upgrade-safety.d.ts +81 -0
- package/dist/cli/commands/shared/versioned-upgrade.d.ts +67 -12
- package/dist/cli/commands/source.d.ts +1 -0
- package/dist/cli/commands/token.d.ts +4 -0
- package/dist/cli/commands/trust-policy.d.ts +57 -1
- package/dist/cli/join.d.ts +1 -1
- package/dist/cli/service/backup-timer.d.ts +108 -0
- package/dist/cli/service/compose-path.d.ts +11 -0
- package/dist/cli/service/compose.d.ts +22 -0
- package/dist/cli/service/deploy-env.d.ts +10 -11
- package/dist/cli/service/env-assignment.d.ts +24 -0
- package/dist/cli/service/index.d.ts +2 -2
- package/dist/cli/service/instance/resolve.d.ts +71 -7
- package/dist/cli/service/instance/types.d.ts +15 -0
- package/dist/cli/service/launchd.d.ts +7 -0
- package/dist/cli/service/systemd.d.ts +1 -0
- package/dist/cli/service/types.d.ts +36 -0
- package/dist/cli/service/windows.d.ts +16 -0
- package/dist/cli/wizard/orchestrator-wizard.d.ts +12 -3
- package/dist/cli/wizard/prompts.d.ts +7 -0
- package/dist/cli.js +12525 -9298
- package/dist/cluster/cluster-settings-reader.d.ts +2 -2
- package/dist/cluster/coordinator.d.ts +11 -0
- package/dist/cluster/instance-heartbeat.d.ts +96 -0
- package/dist/cluster/join-client.d.ts +55 -5
- package/dist/cluster/join-handler.d.ts +1 -0
- package/dist/cluster/orphan-recovery.d.ts +16 -0
- package/dist/cluster/peer-registry.d.ts +10 -0
- package/dist/concurrency/dispatch-next-queued.d.ts +1 -13
- package/dist/concurrency/index.d.ts +1 -2
- package/dist/concurrency/queue-manager.d.ts +63 -18
- package/dist/config/env-overlay.d.ts +3 -2
- package/dist/config.d.ts +24 -0
- package/dist/contexts/release-queued-holds.d.ts +23 -1
- package/dist/dashboard/attestation-filters.d.ts +2 -0
- package/dist/dashboard/handler.d.ts +22 -2
- package/dist/db/deferred-indexes.d.ts +72 -0
- package/dist/db/migration-test-harness.d.ts +22 -0
- package/dist/db/migrations/131_execution_jobs_git_credentials.d.ts +30 -0
- package/dist/db/migrations/132_execution_runs_trigger_event.d.ts +23 -0
- package/dist/db/migrations/133_dispatch_queue_source_tar_digest.d.ts +23 -0
- package/dist/db/migrations/134_dispatch_queue_ownership.d.ts +4 -0
- package/dist/db/migrations/135_cluster_settings_retention_days.d.ts +4 -0
- package/dist/db/migrations/136_master_key_wrapped_tables_key_version.d.ts +4 -0
- package/dist/db/migrations/137_execution_runs_pr_head_context.d.ts +4 -0
- package/dist/db/migrations/138_execution_runs_subject_trigger_event.d.ts +4 -0
- package/dist/db/migrations/139_admin_token_subject.d.ts +4 -0
- package/dist/db/migrations/140_dispatch_queue_canonical_labels.d.ts +54 -0
- package/dist/db/migrations/141_event_log_shed.d.ts +15 -0
- package/dist/db/migrator.d.ts +47 -0
- package/dist/db/notify-listener.d.ts +60 -0
- package/dist/db/synthetic-job-ids.d.ts +24 -0
- package/dist/db/types.d.ts +169 -4
- package/dist/deployment/deployment-identity.d.ts +31 -1
- package/dist/diagnostics/checks/index.d.ts +2 -1
- package/dist/diagnostics/checks/retention.d.ts +24 -0
- package/dist/diagnostics/types.d.ts +7 -0
- package/dist/events/event-router.d.ts +1 -1
- package/dist/fault-injection-types.d.ts +53 -0
- package/dist/firecracker/host-network.d.ts +63 -8
- package/dist/git/credential-broker.d.ts +35 -2
- package/dist/git/inherited-secret.d.ts +7 -2
- package/dist/git/job-context.d.ts +7 -4
- package/dist/helpers/secure-write.d.ts +35 -0
- package/dist/index.js +196 -67
- package/dist/metrics/prometheus.d.ts +116 -1
- package/dist/oidc/db-signer.d.ts +27 -5
- package/dist/oidc/id-token-claims.d.ts +33 -2
- package/dist/oidc/oidc-mint-registration.d.ts +6 -0
- package/dist/oidc/orchestrator-mint.d.ts +8 -0
- package/dist/oidc/reconcile-signing-key.d.ts +37 -0
- package/dist/orchestrator-core.d.ts +9 -3
- package/dist/pipeline/decorating-secret-resolver.d.ts +1 -1
- package/dist/pipeline/dispatch-matched-workflow.d.ts +65 -14
- package/dist/pipeline/manual-schedule.d.ts +1 -0
- package/dist/pipeline/process-webhook.d.ts +20 -2
- package/dist/pipeline/route-or-dispatch-jobs.d.ts +7 -0
- package/dist/pipeline/run-event-context.d.ts +39 -0
- package/dist/policy/dashboard-write-policy-listener.d.ts +1 -1
- package/dist/policy/dashboard-write-policy.d.ts +47 -1
- package/dist/provenance/dispatch-context.d.ts +46 -0
- package/dist/provenance/verify-deferred-capture.d.ts +39 -0
- package/dist/providers/github/auth.d.ts +9 -0
- package/dist/providers/github/deliveries.d.ts +118 -0
- package/dist/providers/universal-git/config.d.ts +1 -1
- package/dist/queue/cleanup.d.ts +13 -0
- package/dist/queue/job-queue.d.ts +162 -14
- package/dist/queue/retention.d.ts +105 -0
- package/dist/reporting/execution-tracker.d.ts +87 -36
- package/dist/routes/admin-db.d.ts +5 -0
- package/dist/routes/admin-events.d.ts +13 -0
- package/dist/routes/admin-held-runs.d.ts +11 -1
- package/dist/routes/admin-org-settings.d.ts +9 -0
- package/dist/routes/admin-runs.d.ts +7 -4
- package/dist/routes/admin-sources.d.ts +15 -0
- package/dist/routes/admin-trust-policy.d.ts +11 -0
- package/dist/routes/admin.d.ts +25 -0
- package/dist/scaler/backend-factory.d.ts +16 -0
- package/dist/scaler/bare-metal-backend.d.ts +22 -4
- package/dist/scaler/config.d.ts +6 -3
- package/dist/scaler/container-backend.d.ts +102 -3
- package/dist/scaler/container-hostconfig.d.ts +60 -0
- package/dist/scaler/file-tail.d.ts +25 -2
- package/dist/scaler/firecracker-api.d.ts +9 -1
- package/dist/scaler/firecracker-backend.d.ts +135 -2
- package/dist/scaler/host-access.d.ts +59 -0
- package/dist/scaler/index.d.ts +1 -0
- package/dist/scaler/manager.d.ts +33 -0
- package/dist/scaler/scaler-state-store.d.ts +6 -0
- package/dist/scaler/types.d.ts +5 -7
- package/dist/secrets/config.d.ts +48 -0
- package/dist/secrets/dashboard-encryption-key.d.ts +19 -0
- package/dist/secrets/ephemeral-keys.d.ts +9 -3
- package/dist/secrets/index.d.ts +3 -1
- package/dist/secrets/job-secret-gate.d.ts +76 -0
- package/dist/secrets/master-key-rotation.d.ts +65 -0
- package/dist/secrets/secret-output-crypto.d.ts +17 -0
- package/dist/secrets/secret-resolver.d.ts +23 -6
- package/dist/secrets/source-credentials.d.ts +1 -1
- package/dist/secrets/token-manager.d.ts +4 -1
- package/dist/security/reduced-privilege-note.d.ts +5 -0
- package/dist/security/trust-policy-gate.d.ts +70 -6
- package/dist/security/trust-tier.d.ts +31 -0
- package/dist/server.d.ts +1 -1
- package/dist/server.js +10674 -5283
- package/dist/sources/source-manager.d.ts +1 -1
- package/dist/stale-detector/stale-dispatch-candidates.d.ts +43 -0
- package/dist/standalone.js +9258 -4122
- package/dist/storage/loopback-guard.d.ts +53 -6
- package/dist/webhook/event-log.d.ts +14 -1
- package/dist/webhook/generic-sources-listener.d.ts +1 -1
- package/dist/webhook/ingest-admission.d.ts +24 -0
- package/dist/webhook/ingest-overflow-replayer.d.ts +78 -14
- package/dist/webhook/ingest-overflow-types.d.ts +13 -1
- package/dist/webhook/register-source-bundle.d.ts +23 -0
- package/dist/webhook/relay-reinject.d.ts +11 -12
- package/dist/webhook/shed-breadcrumb.d.ts +15 -0
- package/dist/ws/git-credential-relay.d.ts +41 -12
- package/dist/ws/platform-client.d.ts +28 -5
- package/installer-image-digests.json +3 -3
- package/package.json +4 -4
- package/sbom.spdx.json +53 -53
- package/dist/concurrency/group-tracker.d.ts +0 -51
- package/dist/scaler/nftables.d.ts +0 -111
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type Kysely } from 'kysely';
|
|
2
2
|
import { type ColdStore } from '@kici-dev/shared';
|
|
3
|
-
import type { DashboardRunDetailRequest, DashboardRunsListRequest, DashboardRunsListResponse, DashboardRunsFiltersRequest, DashboardRunsFiltersResponse, DashboardSourcesListRequest, DashboardSourcesListResponse, DashboardStepLogsRequest, DashboardAttestationsListRequest, DashboardAttestationsListAllRequest, DashboardAttestationGetRequest, DashboardAttestationRetryRequest, DashboardPayloadRequest, DashboardOrchLogsRequest, DashboardEventLogListRequest, DashboardEventLogActivityRequest, DashboardEventLogDetailRequest, DashboardEventLogPayloadStreamRequest, DashboardAccessLogListRequest, DashboardEventDlqListRequest, DashboardEventDlqCountRequest, DashboardEventDlqRetryRequest, DashboardEventDlqDiscardRequest, RunRerunRequest, RunCancelRequest, ManualScheduleRequest, DashboardRunStructuredRequest, DashboardArtifactsListRequest } from '@kici-dev/engine';
|
|
3
|
+
import type { DashboardRunDetailRequest, DashboardRunsListRequest, DashboardRunsListResponse, DashboardRunsFiltersRequest, DashboardRunsFiltersResponse, DashboardSourcesListRequest, DashboardSourcesListResponse, DashboardAdminTokensListRequest, DashboardAdminTokensListResponse, DashboardStepLogsRequest, DashboardAttestationsListRequest, DashboardAttestationsListAllRequest, DashboardAttestationGetRequest, DashboardAttestationRetryRequest, DashboardPayloadRequest, DashboardOrchLogsRequest, DashboardEventLogListRequest, DashboardEventLogActivityRequest, DashboardEventLogDetailRequest, DashboardEventLogPayloadStreamRequest, DashboardAccessLogListRequest, DashboardEventDlqListRequest, DashboardEventDlqCountRequest, DashboardEventDlqRetryRequest, DashboardEventDlqDiscardRequest, RunRerunRequest, RunCancelRequest, ManualScheduleRequest, DashboardRunStructuredRequest, DashboardArtifactsListRequest } from '@kici-dev/engine';
|
|
4
4
|
import type { Database } from '../db/types.js';
|
|
5
5
|
import type { LogStorage } from '../reporting/log-storage.js';
|
|
6
6
|
import type { CacheStorage } from '../storage/types.js';
|
|
@@ -233,7 +233,7 @@ export declare class DashboardHandler {
|
|
|
233
233
|
* unioning both source tables. Uses the identical name/subtype/provider
|
|
234
234
|
* derivation as `handleSourcesList` so a run summary's `source` block
|
|
235
235
|
* matches what the sources page shows for the same routing key. Routing
|
|
236
|
-
* keys with no live source row are
|
|
236
|
+
* keys with no live source row are absent from the map (the caller
|
|
237
237
|
* falls back to the run's own provider).
|
|
238
238
|
*/
|
|
239
239
|
private resolveSourceIdentities;
|
|
@@ -303,6 +303,26 @@ export declare class DashboardHandler {
|
|
|
303
303
|
* carries the wire actor so the customer can audit any operator read.
|
|
304
304
|
*/
|
|
305
305
|
handleSourcesList(msg: DashboardSourcesListRequest): Promise<DashboardSourcesListResponse>;
|
|
306
|
+
/**
|
|
307
|
+
* Handle a dashboard.admin-tokens.list request.
|
|
308
|
+
*
|
|
309
|
+
* Returns the orchestrator's live admin-token inventory for the Platform's
|
|
310
|
+
* RBAC drift report. `admin_tokens` is orchestrator-wide — an orchestrator
|
|
311
|
+
* serves exactly one org — so the projection is not filtered by `orgId`; the
|
|
312
|
+
* handler-bound `orgId` / `routingKey` attribute the access_log row, the same
|
|
313
|
+
* inline-ctx pattern `handleSourcesList` uses.
|
|
314
|
+
*
|
|
315
|
+
* Only live tokens are returned: a revoked or already-expired token is not a
|
|
316
|
+
* finding, so reporting one would be noise the operator learns to ignore.
|
|
317
|
+
*
|
|
318
|
+
* `token_hash` is never selected. The report has no use for it, and a hash is
|
|
319
|
+
* a credential verifier — relaying one would put an offline-crackable value
|
|
320
|
+
* on the dashboard plane.
|
|
321
|
+
*
|
|
322
|
+
* Reading who holds admin tokens is itself privileged, so every read writes
|
|
323
|
+
* an access_log row carrying the wire actor.
|
|
324
|
+
*/
|
|
325
|
+
handleAdminTokensList(msg: DashboardAdminTokensListRequest): Promise<DashboardAdminTokensListResponse>;
|
|
306
326
|
/**
|
|
307
327
|
* Handle a dashboard.step.logs request.
|
|
308
328
|
* Looks up the step's log_path and reads content from LogStorage.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Indexes built after boot, outside the migration set.
|
|
3
|
+
*
|
|
4
|
+
* A migration cannot build an index without locking the table it indexes.
|
|
5
|
+
* Kysely runs the whole pending batch inside one transaction and offers no
|
|
6
|
+
* per-migration opt-out, and PostgreSQL rejects `CREATE INDEX CONCURRENTLY`
|
|
7
|
+
* inside a transaction block outright — so a migration's only option is a
|
|
8
|
+
* plain `CREATE INDEX`, which holds an exclusive lock for the whole build. On
|
|
9
|
+
* a table holding millions of rows that is a multi-minute outage bolted onto
|
|
10
|
+
* an upgrade.
|
|
11
|
+
*
|
|
12
|
+
* So an index on a table that scales with run volume goes here instead. Each
|
|
13
|
+
* entry is built `CONCURRENTLY` on its own connection with no statement
|
|
14
|
+
* timeout, under an advisory lock distinct from the migration lock, after the
|
|
15
|
+
* server is already serving. `IF NOT EXISTS` makes every build idempotent, and
|
|
16
|
+
* a failed build retries on the next boot.
|
|
17
|
+
*
|
|
18
|
+
* `hack/check-migration-safety.ts` enforces that new indexes on those tables
|
|
19
|
+
* land here rather than in a migration.
|
|
20
|
+
*/
|
|
21
|
+
import type pg from 'pg';
|
|
22
|
+
import { type Logger } from '@kici-dev/shared';
|
|
23
|
+
/**
|
|
24
|
+
* Distinct from the migrator's `543210001`: an index build must not block, or
|
|
25
|
+
* be blocked by, a peer applying migrations.
|
|
26
|
+
*/
|
|
27
|
+
export declare const DEFERRED_INDEX_LOCK_KEY = 543210002;
|
|
28
|
+
export interface DeferredIndex {
|
|
29
|
+
/** Index name, matching the one the SQL creates. */
|
|
30
|
+
name: string;
|
|
31
|
+
/** A single `CREATE INDEX CONCURRENTLY IF NOT EXISTS` statement. */
|
|
32
|
+
sql: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Every index the retention sweep and the age-based readers depend on.
|
|
36
|
+
*
|
|
37
|
+
* Each one supports a `... < cutoff` scan that would otherwise walk the whole
|
|
38
|
+
* table on every cleanup tick. The tables already carry indexes for their
|
|
39
|
+
* serving-path queries; these cover the aging path, whose predicate is not
|
|
40
|
+
* prefixed by an organization or routing key.
|
|
41
|
+
*/
|
|
42
|
+
export declare const DEFERRED_INDEXES: ReadonlyArray<DeferredIndex>;
|
|
43
|
+
/**
|
|
44
|
+
* Drop a leftover invalid index before rebuilding it.
|
|
45
|
+
*
|
|
46
|
+
* An interrupted `CREATE INDEX CONCURRENTLY` leaves the index in place marked
|
|
47
|
+
* invalid: it is not used by the planner, and `IF NOT EXISTS` sees it and
|
|
48
|
+
* skips. Without this, the very first failed build would make the retry a
|
|
49
|
+
* permanent no-op — the opposite of the "retries on the next boot" contract.
|
|
50
|
+
*/
|
|
51
|
+
export declare function dropIfInvalid(client: Pick<pg.Client, 'query'>, name: string, logger: Logger): Promise<void>;
|
|
52
|
+
export interface BuildDeferredIndexesResult {
|
|
53
|
+
built: string[];
|
|
54
|
+
failed: string[];
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Build every deferred index on one dedicated connection.
|
|
58
|
+
*
|
|
59
|
+
* The connection is taken straight from `pg` rather than from the serving
|
|
60
|
+
* pool: `CREATE INDEX CONCURRENTLY` must run outside a transaction and must
|
|
61
|
+
* not inherit a statement timeout, and a concurrent build on a large table
|
|
62
|
+
* would otherwise hold a serving connection for its whole duration.
|
|
63
|
+
*
|
|
64
|
+
* The advisory lock is `pg_try_advisory_lock`, not the blocking form: when a
|
|
65
|
+
* peer is already building, this instance has nothing to wait for.
|
|
66
|
+
*/
|
|
67
|
+
export declare function buildDeferredIndexes(databaseUrl: string, opts?: {
|
|
68
|
+
logger?: Logger;
|
|
69
|
+
indexes?: ReadonlyArray<DeferredIndex>;
|
|
70
|
+
pg?: typeof import('pg');
|
|
71
|
+
}): Promise<BuildDeferredIndexesResult>;
|
|
72
|
+
//# sourceMappingURL=deferred-indexes.d.ts.map
|
|
@@ -13,6 +13,11 @@
|
|
|
13
13
|
* test can neither name the wrong migration nor drift when a file is renamed.
|
|
14
14
|
* It has no fallback to the whole set: an unknown or no-op target throws.
|
|
15
15
|
*
|
|
16
|
+
* A DATA migration needs the state one step earlier as well, so it can insert
|
|
17
|
+
* the rows it is supposed to rewrite: `migrateToPreviousMigration()` provides
|
|
18
|
+
* it, deriving that target from the migration list rather than from a name the
|
|
19
|
+
* test spells out.
|
|
20
|
+
*
|
|
16
21
|
* Repo/store tests outside `migrations/` (host roster, artifact store, the repo
|
|
17
22
|
* suites) legitimately want head-of-list schema and use `migrateToLatest()`
|
|
18
23
|
* directly instead.
|
|
@@ -38,4 +43,21 @@ export declare function migrationNameFromTestUrl(testUrl: string): string;
|
|
|
38
43
|
* "the whole migration set ran".
|
|
39
44
|
*/
|
|
40
45
|
export declare function migrateToOwnMigration<DB>(db: Kysely<DB>, testUrl: string): Promise<MigrationResultSet>;
|
|
46
|
+
/**
|
|
47
|
+
* Apply migrations `001..NNN-1` — everything up to, but NOT including, the
|
|
48
|
+
* migration the calling test file is named after. Pass `import.meta.url`.
|
|
49
|
+
*
|
|
50
|
+
* This is the pre-migration state a DATA migration has to be tested from. A
|
|
51
|
+
* data migration rewrites rows that already exist, so its test has to straddle
|
|
52
|
+
* it: migrate here, insert the rows an upgraded database actually holds, then
|
|
53
|
+
* call {@link migrateToOwnMigration} and assert what moved. Going straight to
|
|
54
|
+
* `migrateToOwnMigration` leaves no window to insert anything, so the
|
|
55
|
+
* assertions would run against rows the migration never saw — a check that
|
|
56
|
+
* passes identically with the migration body deleted.
|
|
57
|
+
*
|
|
58
|
+
* The target is derived from the migration list, so the caller never names the
|
|
59
|
+
* previous migration and cannot drift when one is inserted before it. A test
|
|
60
|
+
* for the very first migration throws, since there is no earlier state.
|
|
61
|
+
*/
|
|
62
|
+
export declare function migrateToPreviousMigration<DB>(db: Kysely<DB>, testUrl: string): Promise<MigrationResultSet>;
|
|
41
63
|
//# sourceMappingURL=migration-test-harness.d.ts.map
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type Kysely } from 'kysely';
|
|
2
|
+
/**
|
|
3
|
+
* Add `execution_jobs.git_credentials JSONB NULL` — the `gitCredentials` map the
|
|
4
|
+
* job's lock entry declared, as server truth the credential relay can read on
|
|
5
|
+
* the hot path.
|
|
6
|
+
*
|
|
7
|
+
* The relay is called on every git network operation, so it must not re-fetch
|
|
8
|
+
* or re-parse a lock file to learn what a job is allowed to ask for. The
|
|
9
|
+
* orchestrator persists no per-job lock entry (`execution_jobs` carries no
|
|
10
|
+
* config column), so the declaration is written at dispatch and read back here.
|
|
11
|
+
*
|
|
12
|
+
* Values follow `LockJob.gitCredentials`: a `<name>Secret` field is a secret
|
|
13
|
+
* NAME in qualified `<context>:<key>` form, while its `<name>Value` sibling
|
|
14
|
+
* carries material for a credential with no store entry to name. The column
|
|
15
|
+
* stores whichever the lock declared, verbatim — it is the declaration the
|
|
16
|
+
* relay compares a request against, not a secret store of its own.
|
|
17
|
+
*
|
|
18
|
+
* Nullable, with no default: NULL means "this job declared no git credentials",
|
|
19
|
+
* which is true of nearly every job and of every row written before this column
|
|
20
|
+
* existed. A default would have to name a declaration nobody made. The row is
|
|
21
|
+
* written after the dispatch loop, so NULL also covers "not written yet" — the
|
|
22
|
+
* relay resolves that ambiguity against the job's dispatch record rather than
|
|
23
|
+
* reading it as a declaration (`git/job-context.ts`).
|
|
24
|
+
*
|
|
25
|
+
* Idempotent: the add is guarded on existence and the drop uses IF EXISTS, so a
|
|
26
|
+
* re-run is a no-op.
|
|
27
|
+
*/
|
|
28
|
+
export declare function up(db: Kysely<unknown>): Promise<void>;
|
|
29
|
+
export declare function down(db: Kysely<unknown>): Promise<void>;
|
|
30
|
+
//# sourceMappingURL=131_execution_jobs_git_credentials.d.ts.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type Kysely } from 'kysely';
|
|
2
|
+
/**
|
|
3
|
+
* Add `execution_runs.trigger_event TEXT NULL` — the event type that started
|
|
4
|
+
* the run (`push`, `pr:open`, `schedule`, …).
|
|
5
|
+
*
|
|
6
|
+
* The tracker has always carried this value in memory and relayed it to the
|
|
7
|
+
* dashboard, but never persisted it. The git credential relay needs it: it
|
|
8
|
+
* evaluates a named context's protection rules against the run, and a context
|
|
9
|
+
* may restrict which trigger types may use it (`triggerTypeFilters`). Without
|
|
10
|
+
* the recorded value that rule cannot be evaluated at all.
|
|
11
|
+
*
|
|
12
|
+
* Nullable, with no default: a row written before this column existed has no
|
|
13
|
+
* recorded trigger, and no cluster-wide value could stand in for one. A run
|
|
14
|
+
* whose trigger is unknown fails a `triggerTypeFilters` rule closed, which is
|
|
15
|
+
* the correct direction — a credential is withheld rather than granted on a
|
|
16
|
+
* rule nobody could check.
|
|
17
|
+
*
|
|
18
|
+
* Idempotent: the add is guarded on existence and the drop uses IF EXISTS, so a
|
|
19
|
+
* re-run is a no-op.
|
|
20
|
+
*/
|
|
21
|
+
export declare function up(db: Kysely<unknown>): Promise<void>;
|
|
22
|
+
export declare function down(db: Kysely<unknown>): Promise<void>;
|
|
23
|
+
//# sourceMappingURL=132_execution_runs_trigger_event.d.ts.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type Kysely } from 'kysely';
|
|
2
|
+
/**
|
|
3
|
+
* Add `dispatch_queue.source_tar_digest TEXT NULL` — the SHA-256 of the source
|
|
4
|
+
* tarball's own bytes, so the agent can verify what it downloaded before
|
|
5
|
+
* extracting it.
|
|
6
|
+
*
|
|
7
|
+
* The neighbouring `source_tar_hash` column carries the workflow `contentHash`
|
|
8
|
+
* despite its name, which is why the agent's restore path verified nothing: it
|
|
9
|
+
* had no value to compare the bytes against. `deps_hash` next door has always
|
|
10
|
+
* held its tarball's real digest, and this column is its source-side sibling.
|
|
11
|
+
*
|
|
12
|
+
* Nullable, with no default: NULL means "no digest known for this row", which
|
|
13
|
+
* is true of every row written before the column existed and of any dispatch
|
|
14
|
+
* whose source came from somewhere other than the content-addressed cache. The
|
|
15
|
+
* agent treats NULL as "nothing to verify against" and restores unverified,
|
|
16
|
+
* exactly as it did before — so an in-flight queue survives the upgrade.
|
|
17
|
+
*
|
|
18
|
+
* Idempotent: the add is guarded on existence and the drop uses IF EXISTS, so a
|
|
19
|
+
* re-run is a no-op.
|
|
20
|
+
*/
|
|
21
|
+
export declare function up(db: Kysely<unknown>): Promise<void>;
|
|
22
|
+
export declare function down(db: Kysely<unknown>): Promise<void>;
|
|
23
|
+
//# sourceMappingURL=133_dispatch_queue_source_tar_digest.d.ts.map
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { type Kysely } from 'kysely';
|
|
2
|
+
/**
|
|
3
|
+
* Fold `dispatch_queue` label arrays to their canonical (trimmed, lowercase)
|
|
4
|
+
* form.
|
|
5
|
+
*
|
|
6
|
+
* Label matching folds case, and every other label store folds on read.
|
|
7
|
+
* `dispatch_queue` cannot: its comparison happens in SQL — the `@>` containment
|
|
8
|
+
* prefilter and the `jsonb_array_elements_text` exclude check — so the SQL
|
|
9
|
+
* filters rows before any JavaScript sees them. A row enqueued before labels
|
|
10
|
+
* became case-insensitive carries whatever case the workflow author wrote, so
|
|
11
|
+
* it would never again match a folded agent label set, and no read-side fold
|
|
12
|
+
* could rescue it because the row is never selected in the first place. This
|
|
13
|
+
* migration is what makes those rows reachable.
|
|
14
|
+
*
|
|
15
|
+
* The fold mirrors `canonicalizeLabel` in `@kici-dev/engine` —
|
|
16
|
+
* `btrim(lower(...))` against `raw.trim().toLowerCase()` — so a row this
|
|
17
|
+
* migration rewrites holds the same bytes as the same labels enqueued today.
|
|
18
|
+
* Lowercasing alone would strand a padded legacy label the same way a
|
|
19
|
+
* mixed-case one is stranded, because the agent side trims.
|
|
20
|
+
*
|
|
21
|
+
* `runs_on_patterns` / `exclude_patterns` are deliberately untouched: they hold
|
|
22
|
+
* regex SOURCES, which cannot be lowercased without corrupting the pattern.
|
|
23
|
+
* Those fold via the forced `i` flag applied when they are read.
|
|
24
|
+
*
|
|
25
|
+
* The GIN index `idx_dispatch_queue_labels_gin` needs no change — the query
|
|
26
|
+
* shape is identical, only the values move.
|
|
27
|
+
*
|
|
28
|
+
* `COALESCE(jsonb_agg(...), '[]'::jsonb)` is defence in depth against the
|
|
29
|
+
* `EXISTS` guard below being loosened, and is unreachable as the statement
|
|
30
|
+
* stands. `jsonb_agg` over zero rows does return NULL, and a NULL would violate
|
|
31
|
+
* `runs_on_labels NOT NULL` and leave the drain's `jsonb_array_elements_text`
|
|
32
|
+
* with nothing to walk on `exclude_labels` — but zero rows requires an empty
|
|
33
|
+
* array, and an empty array can never satisfy a guard that demands an element
|
|
34
|
+
* differing from its own folded form. Removing the guard, or replacing it with
|
|
35
|
+
* one that admits an empty array, makes the COALESCE load-bearing immediately,
|
|
36
|
+
* so it stays.
|
|
37
|
+
*
|
|
38
|
+
* Idempotent: each `UPDATE` selects only rows holding an element that is not
|
|
39
|
+
* already its own canonical form, so a re-run touches nothing.
|
|
40
|
+
*/
|
|
41
|
+
export declare function up(db: Kysely<unknown>): Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* Irreversible by design: the original case is destroyed, so there is nothing
|
|
44
|
+
* to restore. This is a data migration, not a schema change, so `down` leaves
|
|
45
|
+
* the schema exactly as `up` found it and the no-op is the honest outcome
|
|
46
|
+
* rather than a missing implementation.
|
|
47
|
+
*
|
|
48
|
+
* Rolling the orchestrator back is briefly worse than never having migrated:
|
|
49
|
+
* an old orchestrator compares an agent's labels verbatim against rows this
|
|
50
|
+
* migration canonicalized, so a fleet whose configured labels are not already
|
|
51
|
+
* lowercase strands those rows until they expire, drain, or are re-enqueued.
|
|
52
|
+
*/
|
|
53
|
+
export declare function down(): Promise<void>;
|
|
54
|
+
//# sourceMappingURL=140_dispatch_queue_canonical_labels.d.ts.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type Kysely } from 'kysely';
|
|
2
|
+
/**
|
|
3
|
+
* Extend the event_log.status CHECK constraint with 'shed' so the orchestrator
|
|
4
|
+
* can record a breadcrumb for a delivery the ingest admission controller
|
|
5
|
+
* refused under load. Without the row a shed delivery is indistinguishable
|
|
6
|
+
* from one that never arrived, because the shed happens before the pipeline
|
|
7
|
+
* that writes every other status.
|
|
8
|
+
*
|
|
9
|
+
* Orchestrator-only: the Platform event_log uses a separate, narrower status set.
|
|
10
|
+
*
|
|
11
|
+
* Idempotent: the DROP ... IF EXISTS / re-ADD pair re-runs cleanly.
|
|
12
|
+
*/
|
|
13
|
+
export declare function up(db: Kysely<unknown>): Promise<void>;
|
|
14
|
+
export declare function down(db: Kysely<unknown>): Promise<void>;
|
|
15
|
+
//# sourceMappingURL=141_event_log_shed.d.ts.map
|
package/dist/db/migrator.d.ts
CHANGED
|
@@ -11,6 +11,31 @@ interface MigrateOptions {
|
|
|
11
11
|
db: Kysely<any>;
|
|
12
12
|
pool: pg.Pool;
|
|
13
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* Build a pool reserved for schema work.
|
|
16
|
+
*
|
|
17
|
+
* Migrations run DDL and backfills that legitimately take minutes on a
|
|
18
|
+
* database holding real history, so they must not inherit the hot path's
|
|
19
|
+
* `statement_timeout`. pg treats `0` as "no limit". Kysely's `Migrator`
|
|
20
|
+
* acquires its own connections from whatever pool backs the `Kysely` instance
|
|
21
|
+
* it is given, so the exemption has to be set on the pool — a `SET` issued on
|
|
22
|
+
* one client would not reach the connections that run the migrations.
|
|
23
|
+
*
|
|
24
|
+
* `max: 2` covers the advisory-lock client plus the one Kysely checks out.
|
|
25
|
+
*/
|
|
26
|
+
export declare function createMigrationPool(databaseUrl: string): pg.Pool;
|
|
27
|
+
/**
|
|
28
|
+
* Run `fn` against a short-lived timeout-free migration pool, then close it.
|
|
29
|
+
*/
|
|
30
|
+
export declare function withMigrationPool<T>(databaseUrl: string, fn: (opts: MigrateOptions) => Promise<T>): Promise<T>;
|
|
31
|
+
/** True when a driver error is a cancelled statement rather than bad SQL. */
|
|
32
|
+
export declare function isStatementTimeoutError(message: string): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Restate a migration failure so the log names the migration that failed and,
|
|
35
|
+
* on a cancelled statement, the way out. The bare driver message names
|
|
36
|
+
* neither, which is what left an operator with a boot loop and no next step.
|
|
37
|
+
*/
|
|
38
|
+
export declare function describeMigrationFailure(message: string, migrationName?: string): string;
|
|
14
39
|
interface MigrationStatusEntry {
|
|
15
40
|
name: string;
|
|
16
41
|
status: 'applied' | 'pending';
|
|
@@ -28,5 +53,27 @@ export declare function runMigrations(opts: MigrateOptions): Promise<MigrationRe
|
|
|
28
53
|
* Get migration status (applied/pending) without running anything.
|
|
29
54
|
*/
|
|
30
55
|
export declare function getMigrationStatus(opts: MigrateOptions): Promise<MigrationStatusEntry[]>;
|
|
56
|
+
/** What a `migrateTo` run did. */
|
|
57
|
+
export interface MigrateToResult {
|
|
58
|
+
/** The migration the ledger now sits at. */
|
|
59
|
+
target: string;
|
|
60
|
+
/** Migrations applied to reach it (empty when moving backwards). */
|
|
61
|
+
applied: string[];
|
|
62
|
+
/** Migrations reverted to reach it (empty when moving forwards). */
|
|
63
|
+
reverted: string[];
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Migrate the ledger to a named migration, in either direction.
|
|
67
|
+
*
|
|
68
|
+
* The point of this is rollback: a previous release's static provider does not
|
|
69
|
+
* carry the newer migrations' names, so Kysely refuses to start against a
|
|
70
|
+
* ledger that records them (`corrupted migrations: previously executed
|
|
71
|
+
* migration <name> is missing`). Reverting to the head that release was
|
|
72
|
+
* running at is what makes the old binary bootable again.
|
|
73
|
+
*
|
|
74
|
+
* It runs under the same advisory lock as {@link runMigrations}, so a peer
|
|
75
|
+
* cannot be applying migrations while this reverts them.
|
|
76
|
+
*/
|
|
77
|
+
export declare function migrateTo(opts: MigrateOptions, name: string): Promise<MigrateToResult>;
|
|
31
78
|
export {};
|
|
32
79
|
//# sourceMappingURL=migrator.d.ts.map
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A LISTEN subscription that survives losing its connection.
|
|
3
|
+
*
|
|
4
|
+
* A `LISTEN` session is a single checked-out client sitting idle. A Postgres
|
|
5
|
+
* failover, a restart, or an idle-backend sweep terminates it, and the pool's
|
|
6
|
+
* own error handler discards the broken connection without re-acquiring — so
|
|
7
|
+
* the subscription is silently gone while `/health` and `/ready` stay 200. The
|
|
8
|
+
* process keeps running and never hears another NOTIFY on that channel.
|
|
9
|
+
*
|
|
10
|
+
* This wraps the pattern once: acquire, subscribe, `LISTEN`, and on `error` or
|
|
11
|
+
* `end` release the dead client and reconnect with jittered exponential
|
|
12
|
+
* backoff until `stop()`. NOTIFY has no durable log, so nothing can be
|
|
13
|
+
* replayed — instead, after a successful re-`LISTEN` the consumer's
|
|
14
|
+
* `onReconnect` re-derives whatever it missed from the database, which is
|
|
15
|
+
* exactly what that consumer already does at cold boot.
|
|
16
|
+
*/
|
|
17
|
+
import type pg from 'pg';
|
|
18
|
+
import { type Logger } from '@kici-dev/shared';
|
|
19
|
+
export interface NotifyListenerOptions {
|
|
20
|
+
pool: pg.Pool;
|
|
21
|
+
/** Channel name. Interpolated into `LISTEN`, so it must be an identifier. */
|
|
22
|
+
channel: string;
|
|
23
|
+
onNotification: (msg: pg.Notification) => void;
|
|
24
|
+
/**
|
|
25
|
+
* Re-derive what the subscription missed while it was disconnected. Awaited
|
|
26
|
+
* after a successful re-`LISTEN`, never on the first connect — a cold start
|
|
27
|
+
* has its own load path.
|
|
28
|
+
*/
|
|
29
|
+
onReconnect?: () => Promise<void> | void;
|
|
30
|
+
logger?: Logger;
|
|
31
|
+
/** First backoff step. Doubles up to {@link MAX_BACKOFF_MS}. */
|
|
32
|
+
baseBackoffMs?: number;
|
|
33
|
+
}
|
|
34
|
+
export declare const MAX_BACKOFF_MS = 30000;
|
|
35
|
+
export declare class NotifyListener {
|
|
36
|
+
private readonly opts;
|
|
37
|
+
private client;
|
|
38
|
+
private stopped;
|
|
39
|
+
private reconnecting;
|
|
40
|
+
private timer;
|
|
41
|
+
private attempt;
|
|
42
|
+
private readonly logger;
|
|
43
|
+
private readonly baseBackoffMs;
|
|
44
|
+
constructor(opts: NotifyListenerOptions);
|
|
45
|
+
/** Acquire a client and subscribe. Throws if the first connect fails. */
|
|
46
|
+
start(): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Best-effort `UNLISTEN`, then release. Cancels any pending reconnect, so a
|
|
49
|
+
* shutdown mid-backoff does not resurrect the subscription.
|
|
50
|
+
*/
|
|
51
|
+
stop(): Promise<void>;
|
|
52
|
+
/** True while a live client holds the subscription. */
|
|
53
|
+
get connected(): boolean;
|
|
54
|
+
private connect;
|
|
55
|
+
private scheduleReconnect;
|
|
56
|
+
/** Exponential backoff with full jitter, capped at {@link MAX_BACKOFF_MS}. */
|
|
57
|
+
private backoffMs;
|
|
58
|
+
private reconnect;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=notify-listener.d.ts.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `execution_jobs.job_id` prefix that marks a PLACEHOLDER row.
|
|
3
|
+
*
|
|
4
|
+
* A placeholder stands for a job the dispatch pass registered but did not hand
|
|
5
|
+
* to the dispatcher — one waiting on a `needs` edge, on a rolling-wave slot, on
|
|
6
|
+
* an invoke-gate summon, or on a protection-rule hold. It exists so the run is
|
|
7
|
+
* not considered complete without it (`isRunComplete` iterates only registered
|
|
8
|
+
* jobs), and it is swapped for the real job id the moment the job actually
|
|
9
|
+
* dispatches (`dispatchReadyJob` → `findSyntheticJobId` → `addJobsToRun`).
|
|
10
|
+
*
|
|
11
|
+
* Lives here, beside the table it describes, because both the writers
|
|
12
|
+
* (`pipeline/`) and the readers that must exclude these rows from an occupancy
|
|
13
|
+
* count (`contexts/`) key on it, and neither layer imports the other.
|
|
14
|
+
*/
|
|
15
|
+
export declare const NEEDS_PENDING_JOB_ID_PREFIX = "needs-pending-";
|
|
16
|
+
/**
|
|
17
|
+
* SQL `LIKE` pattern matching every placeholder `job_id`.
|
|
18
|
+
*
|
|
19
|
+
* `_` is a single-character wildcard in `LIKE`, so the literal underscore-free
|
|
20
|
+
* prefix above needs no escaping — kept as one constant anyway so a caller can
|
|
21
|
+
* never spell the pattern and the prefix differently.
|
|
22
|
+
*/
|
|
23
|
+
export declare const NEEDS_PENDING_JOB_ID_LIKE = "needs-pending-%";
|
|
24
|
+
//# sourceMappingURL=synthetic-job-ids.d.ts.map
|