@kici-dev/orchestrator 0.1.3 → 0.1.6
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 +26 -0
- package/dist/agent/ownership-tracker.d.ts +45 -3
- package/dist/app.d.ts +9 -3
- package/dist/audit/access-log.d.ts +7 -0
- package/dist/cli/api-client.d.ts +14 -0
- package/dist/cli/commands/cluster-name.d.ts +18 -0
- package/dist/cli/commands/db.d.ts +9 -6
- package/dist/cli/commands/org-settings.d.ts +2 -1
- package/dist/cli/commands/shared/secret-input.d.ts +46 -0
- package/dist/cli/commands/variable.d.ts +18 -0
- package/dist/cli/service/index.d.ts +1 -0
- package/dist/cli/service/launchd.d.ts +19 -0
- package/dist/cli/service/privilege.d.ts +21 -0
- package/dist/cli/wizard/orchestrator-wizard.d.ts +4 -2
- package/dist/cli.js +1074 -225
- package/dist/cluster/coordinator.d.ts +3 -3
- package/dist/cluster/join-token.d.ts +21 -13
- package/dist/cluster/peer-client.d.ts +9 -0
- package/dist/config/cluster-id.d.ts +23 -0
- package/dist/config/cluster-name.d.ts +39 -0
- package/dist/config.d.ts +8 -0
- package/dist/dashboard/handler.d.ts +54 -2
- package/dist/db/migrations/019_generic_sources_change_notify.d.ts +25 -0
- package/dist/db/migrations/020_org_settings_dashboard_write_policy.d.ts +17 -0
- package/dist/db/migrations/021_check_run_tracking.d.ts +26 -0
- package/dist/db/migrations/022_scaler_manager_state.d.ts +29 -0
- package/dist/db/migrations/023_dispatch_queue_recovery_deadline.d.ts +26 -0
- package/dist/db/types.d.ts +137 -0
- package/dist/events/event-store.d.ts +9 -2
- package/dist/events/trust-store.d.ts +7 -0
- package/dist/events/types.d.ts +33 -0
- package/dist/metrics/scheduled-jobs.d.ts +26 -5
- package/dist/orchestrator-core.d.ts +16 -2
- package/dist/pipeline/processor.d.ts +2 -2
- package/dist/pipeline/rerun.d.ts +2 -2
- package/dist/pipeline/test-pipeline.d.ts +2 -2
- package/dist/policy/dashboard-write-policy.d.ts +115 -0
- package/dist/queue/job-queue.d.ts +54 -1
- package/dist/reporting/{commit-status.d.ts → check-run-reporter.d.ts} +94 -16
- package/dist/reporting/check-run-tracking-store.d.ts +133 -0
- package/dist/routes/admin-access-log.d.ts +1 -0
- package/dist/routes/admin-backends.d.ts +9 -1
- package/dist/routes/admin-cluster-name.d.ts +50 -0
- package/dist/routes/admin-db.d.ts +9 -1
- package/dist/routes/admin-environments.d.ts +10 -6
- package/dist/routes/admin-event-dlq.d.ts +1 -0
- package/dist/routes/admin-event-log.d.ts +1 -0
- package/dist/routes/admin-events.d.ts +19 -0
- package/dist/routes/admin-maintenance.d.ts +9 -1
- package/dist/routes/admin-org-settings.d.ts +10 -1
- package/dist/routes/admin-queue-execution.d.ts +1 -0
- package/dist/routes/admin-registrations.d.ts +1 -0
- package/dist/routes/admin-runs.d.ts +1 -0
- package/dist/routes/admin-scheduled-jobs.d.ts +1 -0
- package/dist/routes/admin-sources.d.ts +24 -1
- package/dist/routes/admin.d.ts +22 -0
- package/dist/scaler/manager.d.ts +38 -0
- package/dist/scaler/scaler-state-store.d.ts +102 -0
- package/dist/secrets/routing-key-scope.d.ts +43 -0
- package/dist/server.js +10098 -6961
- package/dist/sources/build-platform-sources.d.ts +26 -0
- package/dist/sources/source-manager.d.ts +14 -0
- package/dist/stale-detector/stale-run-detector.d.ts +17 -5
- package/dist/standalone.js +7525 -5172
- package/dist/webhook/generic-sources-listener.d.ts +89 -0
- package/dist/webhook/register-source-bundle.d.ts +57 -0
- package/dist/ws/dashboard-backends-handler.d.ts +14 -0
- package/dist/ws/dashboard-env-handler.d.ts +7 -0
- package/dist/ws/dashboard-global-workflows-handler.d.ts +6 -0
- package/dist/ws/dashboard-registrations-handler.d.ts +7 -0
- package/dist/ws/platform-client.d.ts +57 -2
- package/package.json +3 -3
- package/sbom.spdx.json +40 -35
package/dist/events/types.d.ts
CHANGED
|
@@ -23,6 +23,20 @@ export interface EventRouterConfig {
|
|
|
23
23
|
retryMaxBackoffMs: number;
|
|
24
24
|
/** Interval at which the leader-only retry scanner ticks (default: 10_000) */
|
|
25
25
|
retryScanIntervalMs: number;
|
|
26
|
+
/**
|
|
27
|
+
* **Test-only.** Per-event-name fault injection: when `attempts <= N`,
|
|
28
|
+
* the EventRouter throws a synthetic dispatch error to drive the retry /
|
|
29
|
+
* DLQ path. Used by the fault-injection E2E to prove the lease + retry
|
|
30
|
+
* loop dispatches a real run when the inner dispatch eventually
|
|
31
|
+
* succeeds, and lands the row in the DLQ when N exceeds
|
|
32
|
+
* `maxDispatchAttempts`.
|
|
33
|
+
*
|
|
34
|
+
* Only honoured when `KICI_TEST_MODE=1` is set at config-load time —
|
|
35
|
+
* production deployments never see this knob even if the env var is
|
|
36
|
+
* planted by accident. Source the value from
|
|
37
|
+
* `KICI_TEST_EVENT_FAIL_FIRST_N` (a JSON object literal).
|
|
38
|
+
*/
|
|
39
|
+
debugFailFirstNAttemptsByEvent?: Record<string, number>;
|
|
26
40
|
}
|
|
27
41
|
/**
|
|
28
42
|
* Reason an event landed in the DLQ.
|
|
@@ -54,6 +68,25 @@ export interface StoredEvent {
|
|
|
54
68
|
dlqAt: Date | null;
|
|
55
69
|
dlqReason: DlqReason | null;
|
|
56
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* Parse the `KICI_TEST_EVENT_FAIL_FIRST_N` JSON payload, gated by
|
|
73
|
+
* `KICI_TEST_MODE`. Returns the parsed map or `undefined` when:
|
|
74
|
+
*
|
|
75
|
+
* - `testMode` is false (the master switch). The JSON value is ignored
|
|
76
|
+
* entirely; production deployments never see fault-injection even if
|
|
77
|
+
* the per-event env var is accidentally planted.
|
|
78
|
+
* - the JSON value is absent / empty.
|
|
79
|
+
* - the JSON value is malformed or carries a wrong-shape entry. We
|
|
80
|
+
* refuse to fall back to a partial map: a typo on one line silently
|
|
81
|
+
* skipping that test would be confusing in CI logs.
|
|
82
|
+
*
|
|
83
|
+
* The accepted shape is `{ "<eventName>": <number> }`; non-string keys
|
|
84
|
+
* and non-number values are rejected. The numeric value is the inclusive
|
|
85
|
+
* upper bound of attempts to fail (so `1` fails the first attempt and
|
|
86
|
+
* succeeds on retry; `99` exceeds `maxDispatchAttempts` and lands the
|
|
87
|
+
* row in the DLQ).
|
|
88
|
+
*/
|
|
89
|
+
export declare function parseFaultInjectionMap(testMode: boolean, raw: string | undefined): Record<string, number> | undefined;
|
|
57
90
|
/**
|
|
58
91
|
* Default event router configuration.
|
|
59
92
|
*/
|
|
@@ -1,18 +1,39 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* Success/failure counter for each tick of each scheduled job.
|
|
3
|
+
* Labels:
|
|
4
|
+
* - job: scheduled-job name (one of `OrchestratorScheduledJobName`)
|
|
5
|
+
* - result: success | failure
|
|
6
|
+
*/
|
|
2
7
|
export declare const jobRunsTotal: import("@opentelemetry/api").Counter<import("@opentelemetry/api").Attributes>;
|
|
3
|
-
/**
|
|
8
|
+
/**
|
|
9
|
+
* Histogram of per-tick duration, seconds.
|
|
10
|
+
* Labels:
|
|
11
|
+
* - job: scheduled-job name (one of `OrchestratorScheduledJobName`)
|
|
12
|
+
*/
|
|
4
13
|
export declare const jobDurationSeconds: import("@opentelemetry/api").Histogram<import("@opentelemetry/api").Attributes>;
|
|
5
|
-
/**
|
|
14
|
+
/**
|
|
15
|
+
* Unix timestamp (seconds) of the most recent successful tick.
|
|
16
|
+
* Labels:
|
|
17
|
+
* - job: scheduled-job name (one of `OrchestratorScheduledJobName`)
|
|
18
|
+
*/
|
|
6
19
|
export declare const jobLastSuccessTimestamp: {
|
|
7
20
|
set(labels: Record<string, string>, value: number): void;
|
|
8
21
|
reset(): void;
|
|
9
22
|
};
|
|
10
|
-
/**
|
|
23
|
+
/**
|
|
24
|
+
* Unix timestamp (seconds) of the most recent failed tick.
|
|
25
|
+
* Labels:
|
|
26
|
+
* - job: scheduled-job name (one of `OrchestratorScheduledJobName`)
|
|
27
|
+
*/
|
|
11
28
|
export declare const jobLastFailureTimestamp: {
|
|
12
29
|
set(labels: Record<string, string>, value: number): void;
|
|
13
30
|
reset(): void;
|
|
14
31
|
};
|
|
15
|
-
/**
|
|
32
|
+
/**
|
|
33
|
+
* Count of consecutive failures since last success. Resets to 0 on success.
|
|
34
|
+
* Labels:
|
|
35
|
+
* - job: scheduled-job name (one of `OrchestratorScheduledJobName`)
|
|
36
|
+
*/
|
|
16
37
|
export declare const jobConsecutiveFailures: {
|
|
17
38
|
set(labels: Record<string, string>, value: number): void;
|
|
18
39
|
reset(): void;
|
|
@@ -27,7 +27,7 @@ import { ScalerManager } from './scaler/index.js';
|
|
|
27
27
|
import type { ScalerConfig } from './scaler/index.js';
|
|
28
28
|
import type { CacheStorage } from './storage/index.js';
|
|
29
29
|
import { SourceCache, BuildCoordinator, DepCache, PendingBuildTracker, PendingInitTracker, PendingDynamicTracker } from './cache/index.js';
|
|
30
|
-
import {
|
|
30
|
+
import { CheckRunReporter } from './reporting/check-run-reporter.js';
|
|
31
31
|
import { StepLogBuffer } from './reporting/step-log-buffer.js';
|
|
32
32
|
import { type LogStorage } from './reporting/log-storage.js';
|
|
33
33
|
import { ExecutionTracker, type ExecutionTrackerDeps } from './reporting/execution-tracker.js';
|
|
@@ -39,10 +39,12 @@ import type { SecretStore } from '@kici-dev/engine';
|
|
|
39
39
|
import type { AdminRouteDeps } from './routes/admin.js';
|
|
40
40
|
import { AgentTokenStore } from './agent/token-store.js';
|
|
41
41
|
import { OwnershipTracker } from './agent/ownership-tracker.js';
|
|
42
|
+
import { EventStore } from './events/event-store.js';
|
|
42
43
|
import { EventRouter } from './events/event-router.js';
|
|
43
44
|
import { EventEmitter } from './events/event-emitter.js';
|
|
44
45
|
import { TrustStore } from './events/trust-store.js';
|
|
45
46
|
import { GenericSourceManager } from './webhook/generic-sources.js';
|
|
47
|
+
import { GenericSourcesChangeListener } from './webhook/generic-sources-listener.js';
|
|
46
48
|
import { RegistrationStore } from './registration/registration-store.js';
|
|
47
49
|
import { RegistrationIndex } from './registration/registration-index.js';
|
|
48
50
|
import { CronScheduler } from './cron/cron-scheduler.js';
|
|
@@ -72,7 +74,7 @@ export interface OrchestratorSubsystems {
|
|
|
72
74
|
pendingBuilds: PendingBuildTracker | undefined;
|
|
73
75
|
pendingInits: PendingInitTracker;
|
|
74
76
|
pendingDynamics: PendingDynamicTracker;
|
|
75
|
-
|
|
77
|
+
checkRunReporter: CheckRunReporter;
|
|
76
78
|
stepLogBuffer: StepLogBuffer;
|
|
77
79
|
sourceLocationStore: SourceLocationStore;
|
|
78
80
|
logStorage: LogStorage;
|
|
@@ -87,6 +89,12 @@ export interface OrchestratorSubsystems {
|
|
|
87
89
|
lockFileCache: LockFileCache;
|
|
88
90
|
dedup: DedupCache;
|
|
89
91
|
eventRouter: EventRouter;
|
|
92
|
+
/**
|
|
93
|
+
* Event store for custom internal events (system + custom). Exposed
|
|
94
|
+
* here so the dashboard handler can serve the per-org DLQ surface
|
|
95
|
+
* (list / count / retry / discard) over the WS relay.
|
|
96
|
+
*/
|
|
97
|
+
eventStore: EventStore;
|
|
90
98
|
eventEmitter: EventEmitter;
|
|
91
99
|
genericSourceManager: GenericSourceManager;
|
|
92
100
|
trustStore: TrustStore;
|
|
@@ -107,6 +115,12 @@ export interface OrchestratorSubsystems {
|
|
|
107
115
|
localConfigVersion: number;
|
|
108
116
|
sourceStore: SourceStore;
|
|
109
117
|
sourceManager: SourceManager;
|
|
118
|
+
/**
|
|
119
|
+
* Generic-webhook-source hot-reload listener. Exposed so the platform-mode
|
|
120
|
+
* boot can wire its `onChange` to re-push the full source list to the
|
|
121
|
+
* Platform when a generic source is added/removed at runtime.
|
|
122
|
+
*/
|
|
123
|
+
genericSourcesChangeListener: GenericSourcesChangeListener;
|
|
110
124
|
/** Inbound webhook delivery log writer (event_log table + object-storage payloads). */
|
|
111
125
|
eventLogWriter: EventLogWriter;
|
|
112
126
|
/** Access log writer (read + mutation attribution for dashboard + admin). */
|
|
@@ -26,7 +26,7 @@ import type { DepCache } from '../cache/index.js';
|
|
|
26
26
|
import type { PendingBuildTracker } from '../cache/index.js';
|
|
27
27
|
import type { PendingInitTracker } from '../cache/pending-inits.js';
|
|
28
28
|
import type { PendingDynamicTracker } from '../cache/pending-dynamics.js';
|
|
29
|
-
import type {
|
|
29
|
+
import type { CheckRunReporter } from '../reporting/check-run-reporter.js';
|
|
30
30
|
import type { ExecutionTracker } from '../reporting/execution-tracker.js';
|
|
31
31
|
import type { AgentRegistry } from '../agent/registry.js';
|
|
32
32
|
import type { RunCoordinator } from '../cluster/coordinator.js';
|
|
@@ -237,7 +237,7 @@ export interface ProcessingDeps {
|
|
|
237
237
|
/** Pending dynamic tracker -- waits for agents to evaluate DynamicJobFn and return generated LockJob[]. */
|
|
238
238
|
pendingDynamics?: PendingDynamicTracker;
|
|
239
239
|
/** Commit status reporter for setting pending/success/failure/error on commits. Optional. */
|
|
240
|
-
|
|
240
|
+
checkRunReporter?: CheckRunReporter;
|
|
241
241
|
/** Execution tracker for DB persistence. Optional -- if not set, execution tracking is skipped. */
|
|
242
242
|
executionTracker?: ExecutionTracker;
|
|
243
243
|
/** Agent registry for determining execution target platform/arch. Optional -- if not set, defaults to linux/x64. */
|
package/dist/pipeline/rerun.d.ts
CHANGED
|
@@ -18,7 +18,7 @@ import type { Dispatcher } from '../agent/dispatcher.js';
|
|
|
18
18
|
import type { ExecutionTracker } from '../reporting/execution-tracker.js';
|
|
19
19
|
import type { JobQueue } from '../queue/job-queue.js';
|
|
20
20
|
import type { PlatformClient } from '../ws/platform-client.js';
|
|
21
|
-
import type {
|
|
21
|
+
import type { CheckRunReporter } from '../reporting/check-run-reporter.js';
|
|
22
22
|
import type { RunCoordinator } from '../cluster/coordinator.js';
|
|
23
23
|
import type { SecretResolver } from '../secrets/secret-resolver.js';
|
|
24
24
|
import type { EventRouter } from '../events/event-router.js';
|
|
@@ -50,7 +50,7 @@ export interface RerunDeps {
|
|
|
50
50
|
dispatcher: Dispatcher;
|
|
51
51
|
jobQueue: JobQueue;
|
|
52
52
|
platformClient: PlatformClient | null;
|
|
53
|
-
|
|
53
|
+
checkRunReporter: CheckRunReporter | null;
|
|
54
54
|
coordinator: RunCoordinator | null;
|
|
55
55
|
secretResolver: SecretResolver | null;
|
|
56
56
|
eventRouter: EventRouter | null;
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
*/
|
|
17
17
|
import type { LockFileCache } from '../lockfile-cache.js';
|
|
18
18
|
import type { Dispatcher } from '../agent/dispatcher.js';
|
|
19
|
-
import type {
|
|
19
|
+
import type { CheckRunReporter } from '../reporting/check-run-reporter.js';
|
|
20
20
|
import type { ExecutionTracker } from '../reporting/execution-tracker.js';
|
|
21
21
|
import type { AgentRegistry } from '../agent/registry.js';
|
|
22
22
|
import type { ProviderRegistry } from '../provider-registry.js';
|
|
@@ -85,7 +85,7 @@ export interface TestPipelineDeps {
|
|
|
85
85
|
lockFileCache: LockFileCache;
|
|
86
86
|
dispatcher: Dispatcher;
|
|
87
87
|
executionTracker?: ExecutionTracker;
|
|
88
|
-
|
|
88
|
+
checkRunReporter?: CheckRunReporter;
|
|
89
89
|
sourceCache?: SourceCache;
|
|
90
90
|
buildCoordinator?: BuildCoordinator;
|
|
91
91
|
depCache?: DepCache;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-orchestrator policy controlling which dashboard.* write operations
|
|
3
|
+
* the orch accepts from Platform.
|
|
4
|
+
*
|
|
5
|
+
* Storage: a JSONB column on the existing `org_settings` table, keyed by
|
|
6
|
+
* `customer_id`. Empty object means every operation is enabled
|
|
7
|
+
* (permissive default at first-boot). Operators flip individual
|
|
8
|
+
* operations off via `kici-admin org-settings dashboard-writes set`.
|
|
9
|
+
*
|
|
10
|
+
* Three callers:
|
|
11
|
+
* - The kici-admin CLI mutates via `setDashboardWritePolicy`.
|
|
12
|
+
* - Mutating dashboard.* handlers check via `assertDashboardWriteAllowed`.
|
|
13
|
+
* - The Platform-bound WS publisher reads the full map via
|
|
14
|
+
* `getDashboardWritePolicy` to broadcast `orch.capabilities`.
|
|
15
|
+
*
|
|
16
|
+
* Reads are cached in-process (30 s TTL) — the policy changes
|
|
17
|
+
* infrequently and reading on every dashboard.* request is wasted IO.
|
|
18
|
+
* Writes invalidate the cache and emit a change event so the WS
|
|
19
|
+
* broadcaster can republish.
|
|
20
|
+
*/
|
|
21
|
+
import { EventEmitter } from 'node:events';
|
|
22
|
+
import { type Kysely } from 'kysely';
|
|
23
|
+
import { DashboardWriteOperation, type DashboardWritePolicyMap } from '@kici-dev/engine/protocol/dashboard-write-operations';
|
|
24
|
+
import type { Database } from '../db/types.js';
|
|
25
|
+
import type { ActorPrincipal } from '@kici-dev/engine';
|
|
26
|
+
/**
|
|
27
|
+
* Event bus for policy-change notifications. The WS publisher subscribes
|
|
28
|
+
* to `'changed'` so it can broadcast a fresh `orch.capabilities` to
|
|
29
|
+
* Platform whenever the operator flips a switch.
|
|
30
|
+
*/
|
|
31
|
+
export declare const dashboardWritePolicyEvents: EventEmitter<[never]>;
|
|
32
|
+
/**
|
|
33
|
+
* Error thrown by `assertDashboardWriteAllowed` when an operation is
|
|
34
|
+
* disabled. Carries the operation name + the descriptor's CLI hint so
|
|
35
|
+
* callers can surface a structured error to Platform / dashboard.
|
|
36
|
+
*/
|
|
37
|
+
export declare class DashboardWritePolicyDisabledError extends Error {
|
|
38
|
+
readonly operation: DashboardWriteOperation;
|
|
39
|
+
readonly cliEquivalent: string;
|
|
40
|
+
readonly code: "operation_disabled";
|
|
41
|
+
constructor(operation: DashboardWriteOperation, cliEquivalent: string);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Structured response envelope sent back to Platform when a mutating
|
|
45
|
+
* dashboard.* handler is rejected by the policy gate. Mirrors the
|
|
46
|
+
* Platform-side 403 body so the dashboard renders one consistent
|
|
47
|
+
* "operation disabled" affordance no matter which layer fires first.
|
|
48
|
+
*/
|
|
49
|
+
export declare function buildPolicyDeniedResponse(op: DashboardWriteOperation, responseType: string, requestId: string): Record<string, unknown>;
|
|
50
|
+
/**
|
|
51
|
+
* Clear the cache. Public for tests and for the rare case where an
|
|
52
|
+
* operator wants to force a fresh read after manual DB surgery.
|
|
53
|
+
*/
|
|
54
|
+
export declare function invalidateDashboardWritePolicyCache(customerId?: string): void;
|
|
55
|
+
/**
|
|
56
|
+
* Read the full policy map for a customer. Hits the in-process cache
|
|
57
|
+
* for 30 s after the first read; falls back to the DB on cache miss.
|
|
58
|
+
* Returns an empty map (everything enabled) when no `org_settings` row
|
|
59
|
+
* exists for the customer.
|
|
60
|
+
*/
|
|
61
|
+
export declare function getDashboardWritePolicy(db: Kysely<Database>, customerId: string): Promise<DashboardWritePolicyMap>;
|
|
62
|
+
/**
|
|
63
|
+
* Single-operation check. Convenience wrapper around
|
|
64
|
+
* `getDashboardWritePolicy` + the engine-side resolver.
|
|
65
|
+
*/
|
|
66
|
+
export declare function isDashboardWriteEnabled(db: Kysely<Database>, customerId: string, op: DashboardWriteOperation): Promise<boolean>;
|
|
67
|
+
/**
|
|
68
|
+
* Defense-in-depth gate for orch-side dashboard.* handlers. Throws
|
|
69
|
+
* `DashboardWritePolicyDisabledError` when the operation is disabled.
|
|
70
|
+
* Callers translate the error into the structured error envelope they
|
|
71
|
+
* send back to Platform.
|
|
72
|
+
*/
|
|
73
|
+
export declare function assertDashboardWriteAllowed(db: Kysely<Database>, customerId: string, op: DashboardWriteOperation): Promise<void>;
|
|
74
|
+
/**
|
|
75
|
+
* Merge `updates` into the persisted policy and persist the result.
|
|
76
|
+
* Unknown keys in `updates` are rejected at the Zod schema layer
|
|
77
|
+
* before this function runs (kici-admin already validates). Any
|
|
78
|
+
* operation explicitly set to `true` is normalized away — the
|
|
79
|
+
* permissive default lives in the absence of the key, keeping the
|
|
80
|
+
* JSONB shape minimal.
|
|
81
|
+
*
|
|
82
|
+
* Each changed operation invokes the optional `onChange` callback
|
|
83
|
+
* once — the caller decides what to do with it (typically: write
|
|
84
|
+
* one `access_log` row per change).
|
|
85
|
+
*
|
|
86
|
+
* Emits `'changed'` on `dashboardWritePolicyEvents` with the new map
|
|
87
|
+
* so the WS publisher can rebroadcast capabilities.
|
|
88
|
+
*/
|
|
89
|
+
export declare function setDashboardWritePolicy(db: Kysely<Database>, customerId: string, updates: DashboardWritePolicyMap, options: {
|
|
90
|
+
actor: ActorPrincipal;
|
|
91
|
+
onChange?: (event: PolicyChangeEvent) => Promise<void>;
|
|
92
|
+
}): Promise<DashboardWritePolicyMap>;
|
|
93
|
+
/**
|
|
94
|
+
* Per-operation change event fired by `setDashboardWritePolicy` for
|
|
95
|
+
* each switch that actually flipped. The caller (admin HTTP route,
|
|
96
|
+
* test, future automation) decides what to do — typically writes one
|
|
97
|
+
* `access_log` row carrying `op`, `prior`, and `next` in `meta`.
|
|
98
|
+
*/
|
|
99
|
+
export interface PolicyChangeEvent {
|
|
100
|
+
actor: ActorPrincipal;
|
|
101
|
+
customerId: string;
|
|
102
|
+
op: DashboardWriteOperation;
|
|
103
|
+
prior: boolean;
|
|
104
|
+
next: boolean;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Reset to the permissive defaults (everything enabled). Useful for
|
|
108
|
+
* the `kici-admin org-settings dashboard-writes reset` subcommand.
|
|
109
|
+
*/
|
|
110
|
+
export declare function resetDashboardWritePolicy(db: Kysely<Database>, customerId: string, options: {
|
|
111
|
+
actor: ActorPrincipal;
|
|
112
|
+
onChange?: (event: PolicyChangeEvent) => Promise<void>;
|
|
113
|
+
}): Promise<DashboardWritePolicyMap>;
|
|
114
|
+
export { resolveFullPolicyView } from '@kici-dev/engine/protocol/dashboard-write-operations';
|
|
115
|
+
//# sourceMappingURL=dashboard-write-policy.d.ts.map
|
|
@@ -298,8 +298,43 @@ export declare class JobQueue {
|
|
|
298
298
|
/**
|
|
299
299
|
* Mark a job as recovering (agent disconnected, within grace period).
|
|
300
300
|
* Only transitions from 'dispatched' state for safety.
|
|
301
|
+
*
|
|
302
|
+
* When `deadline` and `agentId` are provided, persists them so a
|
|
303
|
+
* replacement coord on Raft leader switch can recreate the recovery
|
|
304
|
+
* timer (via `getRecoveringJobs()` on boot) or expire the row in
|
|
305
|
+
* the leader-gated sweep (`sweepExpiredRecoveries()`).
|
|
301
306
|
*/
|
|
302
|
-
markRecovering(jobId: string): Promise<void>;
|
|
307
|
+
markRecovering(jobId: string, deadline?: Date, agentId?: string): Promise<void>;
|
|
308
|
+
/**
|
|
309
|
+
* List every job currently in `recovering` state with its persisted
|
|
310
|
+
* recovery deadline. Used at coord boot (`Dispatcher.recoverState()`)
|
|
311
|
+
* to recreate the in-memory `recoveringJobs` Map with fresh timers.
|
|
312
|
+
*
|
|
313
|
+
* Returns rows whose `recovery_deadline` is non-null (the populated
|
|
314
|
+
* subset). Recovering rows from before the migration carry NULL and
|
|
315
|
+
* are handled by the leader-gated sweep on its next pass.
|
|
316
|
+
*/
|
|
317
|
+
getRecoveringJobs(): Promise<Array<{
|
|
318
|
+
id: string;
|
|
319
|
+
runId: string;
|
|
320
|
+
agentId: string | null;
|
|
321
|
+
deadline: Date | null;
|
|
322
|
+
}>>;
|
|
323
|
+
/**
|
|
324
|
+
* Sweep every `recovering` row whose `recovery_deadline` is in the
|
|
325
|
+
* past, marking them `failed`. Returns the rows that flipped so the
|
|
326
|
+
* caller can fire the per-job `onRecoveryTimeout` hook in process.
|
|
327
|
+
*
|
|
328
|
+
* Intended for the leader-gated `Dispatcher.sweepExpiredRecoveries`
|
|
329
|
+
* tick — running on N coords would still be correct (the WHERE
|
|
330
|
+
* `status='recovering'` clause prevents double-failure) but only one
|
|
331
|
+
* needs to do the work.
|
|
332
|
+
*/
|
|
333
|
+
sweepExpiredRecoveries(now: Date): Promise<Array<{
|
|
334
|
+
id: string;
|
|
335
|
+
runId: string;
|
|
336
|
+
agentId: string | null;
|
|
337
|
+
}>>;
|
|
303
338
|
/**
|
|
304
339
|
* Mark a job as failed only if it is still in 'recovering' state.
|
|
305
340
|
* Uses optimistic concurrency to avoid failing jobs that were reclaimed.
|
|
@@ -321,6 +356,24 @@ export declare class JobQueue {
|
|
|
321
356
|
runId: string;
|
|
322
357
|
status: DispatchQueueStatus;
|
|
323
358
|
} | null>;
|
|
359
|
+
/**
|
|
360
|
+
* HA-safe ownership check. Returns true if the DB shows that
|
|
361
|
+
* `agentId` previously held `jobId` according to any of:
|
|
362
|
+
*
|
|
363
|
+
* - `status='dispatched'` AND the registry-managed bookkeeping
|
|
364
|
+
* records the agent assignment (caller-side `agentJobs` map),
|
|
365
|
+
* - `status='recovering'` AND `recovery_agent_id = <agent>` (so a
|
|
366
|
+
* replacement coord still recognises in-flight chunks), OR
|
|
367
|
+
* - the row is already terminal (`completed` / `failed` /
|
|
368
|
+
* `expired`) — late `log.chunk` chunks from the agent's drain
|
|
369
|
+
* window are accepted as benign duplicates rather than
|
|
370
|
+
* rejected.
|
|
371
|
+
*
|
|
372
|
+
* Used by `OwnershipTracker.validateAsync` so a Raft leader switch
|
|
373
|
+
* doesn't turn the next 30s of legitimate per-job chunks into a
|
|
374
|
+
* stream of ownership violations.
|
|
375
|
+
*/
|
|
376
|
+
hasAgentOwnedJob(agentId: string, jobId: string): Promise<boolean>;
|
|
324
377
|
/**
|
|
325
378
|
* Get all jobs matching a given status.
|
|
326
379
|
* Used on startup to find 'dispatched' jobs from a previous instance for recovery.
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* Check run IDs are tracked in-memory after creation so that subsequent
|
|
13
13
|
* updates (job complete, workflow complete) can reference them via checks.update().
|
|
14
14
|
*
|
|
15
|
-
* Enriched output
|
|
15
|
+
* Enriched output:
|
|
16
16
|
* - Live step progress with checklist-style updates (debounced at 5s)
|
|
17
17
|
* - Failed check runs include step names, error messages, exit codes, and log context
|
|
18
18
|
* - Check run annotations link failures to step source locations in workflow files (.kici/workflows/*.ts)
|
|
@@ -22,18 +22,19 @@
|
|
|
22
22
|
* Note: The engine-level CheckStatusPoster interface (packages/engine/src/provider/check-status-poster.ts)
|
|
23
23
|
* provides a provider-agnostic API for posting security-related check statuses (holds, approvals,
|
|
24
24
|
* workflow modifications). The GitHub implementation is at packages/orchestrator/src/providers/github/check-status-poster.ts.
|
|
25
|
-
* This
|
|
25
|
+
* This CheckRunReporter handles execution lifecycle checks (queued, in_progress, completed per job/workflow).
|
|
26
26
|
* Future cleanup may unify both under CheckStatusPoster, but they serve different purposes today.
|
|
27
27
|
*/
|
|
28
28
|
import { type GitHubAppConfig } from '../providers/github/auth.js';
|
|
29
29
|
import type { ProviderRegistry } from '../provider-registry.js';
|
|
30
30
|
import type { StepLogBuffer } from './step-log-buffer.js';
|
|
31
31
|
import { type SourceLocationData } from './check-run-summary.js';
|
|
32
|
+
import type { CheckRunTrackingStore } from './check-run-tracking-store.js';
|
|
32
33
|
import { ExecutionJobStatus } from '@kici-dev/engine';
|
|
33
34
|
/**
|
|
34
|
-
* Dependencies for the
|
|
35
|
+
* Dependencies for the CheckRunReporter.
|
|
35
36
|
*/
|
|
36
|
-
interface
|
|
37
|
+
interface CheckRunReporterDeps {
|
|
37
38
|
/**
|
|
38
39
|
* Provider registry for per-routing-key credential lookup.
|
|
39
40
|
* When provided, the reporter resolves GitHub App credentials by routing key
|
|
@@ -48,6 +49,15 @@ interface CommitStatusReporterDeps {
|
|
|
48
49
|
githubConfig?: GitHubAppConfig;
|
|
49
50
|
/** Step log buffer for enriched failure summaries. */
|
|
50
51
|
stepLogBuffer?: StepLogBuffer;
|
|
52
|
+
/**
|
|
53
|
+
* DB-backed tracking store. When provided, every per-key state mutation
|
|
54
|
+
* (check-run ID, step-progress array, build creation marker,
|
|
55
|
+
* in-progress-sent flag) is written through to the store so a replacement
|
|
56
|
+
* coord on Raft leader switch can recover the state. When omitted (the
|
|
57
|
+
* back-compat path used by unit tests that don't need HA correctness),
|
|
58
|
+
* the reporter operates entirely from in-memory `Map`s.
|
|
59
|
+
*/
|
|
60
|
+
trackingStore?: CheckRunTrackingStore;
|
|
51
61
|
/** Resolver for step source locations from the lock file (for annotations). */
|
|
52
62
|
getStepSourceLocations?: (workflowName: string, jobName: string) => SourceLocationData[] | undefined;
|
|
53
63
|
/**
|
|
@@ -196,19 +206,45 @@ interface UpdateStepProgressOptions {
|
|
|
196
206
|
* All public methods are fire-and-forget: they return void immediately
|
|
197
207
|
* and log errors internally without propagating them.
|
|
198
208
|
*/
|
|
199
|
-
export declare class
|
|
209
|
+
export declare class CheckRunReporter {
|
|
200
210
|
private deps;
|
|
201
|
-
/**
|
|
211
|
+
/**
|
|
212
|
+
* L1 cache: composite key → check run ID.
|
|
213
|
+
*
|
|
214
|
+
* Backed by `check_run_tracking.check_run_id` when `deps.trackingStore`
|
|
215
|
+
* is wired. On a miss the cache falls through to the store; on a store
|
|
216
|
+
* miss the lookup returns undefined and the caller logs + skips.
|
|
217
|
+
*
|
|
218
|
+
* Without the store this Map IS the source of truth (single-coord
|
|
219
|
+
* deployments, unit tests).
|
|
220
|
+
*/
|
|
202
221
|
private readonly checkRunIds;
|
|
203
|
-
/**
|
|
222
|
+
/**
|
|
223
|
+
* L1 cache: in-flight build-creation promises. The DB-backed counterpart
|
|
224
|
+
* lives in `check_run_tracking.build_creation_state`; this Map is needed
|
|
225
|
+
* locally so a same-process `setBuildComplete` can await the
|
|
226
|
+
* in-progress `setBuildPending` promise (the DB column is a state
|
|
227
|
+
* marker, not an awaitable).
|
|
228
|
+
*/
|
|
204
229
|
private readonly pendingBuildCreations;
|
|
205
|
-
/**
|
|
230
|
+
/** L1 cache: step-progress entries (synced to `check_run_tracking.step_progress_json`). */
|
|
206
231
|
private readonly stepProgress;
|
|
207
|
-
/**
|
|
232
|
+
/**
|
|
233
|
+
* L1 cache: per-key debounce timers. NOT persisted — on coord failover
|
|
234
|
+
* the next update either flushes immediately (because the DB row's
|
|
235
|
+
* `updated_at` is older than the debounce window) or starts a fresh
|
|
236
|
+
* timer.
|
|
237
|
+
*/
|
|
208
238
|
private readonly progressTimers;
|
|
209
|
-
/**
|
|
239
|
+
/** L1 cache: first in-progress sent flag (synced to `check_run_tracking.in_progress_sent_at`). */
|
|
210
240
|
private readonly inProgressSent;
|
|
211
|
-
|
|
241
|
+
/**
|
|
242
|
+
* L1 cache: runId → set of check-run composite keys. Synced to the
|
|
243
|
+
* indexed `check_run_tracking.run_id` column so a replacement coord can
|
|
244
|
+
* still find every key for a runId at cleanup time.
|
|
245
|
+
*/
|
|
246
|
+
private readonly runIdToKeys;
|
|
247
|
+
constructor(deps: CheckRunReporterDeps);
|
|
212
248
|
/**
|
|
213
249
|
* Update the provider registry used for per-routing-key credential lookup.
|
|
214
250
|
* Called after config reload when the provider registry is rebuilt.
|
|
@@ -298,14 +334,56 @@ export declare class CommitStatusReporter {
|
|
|
298
334
|
*/
|
|
299
335
|
setBuildComplete(opts: SetBuildCompleteOptions): void;
|
|
300
336
|
/**
|
|
301
|
-
* Clean up step
|
|
302
|
-
* Called when execution tracker prunes
|
|
337
|
+
* Clean up step-progress entries, debounce timers, and DB rows for a
|
|
338
|
+
* completed run. Called when the execution tracker prunes the run.
|
|
339
|
+
*
|
|
340
|
+
* In-memory cleanup is synchronous; the DB cleanup is fire-and-forget
|
|
341
|
+
* because the caller (run-pruning hook) is on the response-shaping path
|
|
342
|
+
* and shouldn't block on a network round-trip. Failure logs but does
|
|
343
|
+
* not propagate.
|
|
303
344
|
*/
|
|
304
345
|
cleanupRun(runId: string): void;
|
|
305
|
-
/**
|
|
306
|
-
|
|
346
|
+
/**
|
|
347
|
+
* Hydrate the L1 caches from the DB after a leader switch (or any
|
|
348
|
+
* boot-time recovery). Called once on coord become-leader so the
|
|
349
|
+
* runIdToKeys reverse map is populated for any future cleanupRun calls
|
|
350
|
+
* without requiring a DB round-trip per cleanup. If no store is wired,
|
|
351
|
+
* this is a no-op.
|
|
352
|
+
*/
|
|
353
|
+
recoverState(): Promise<void>;
|
|
307
354
|
/** Track a check run key associated with a runId for later cleanup. */
|
|
308
355
|
private trackRunKey;
|
|
356
|
+
/**
|
|
357
|
+
* Parse a composite L1 cache key back into the (provider, owner, repo,
|
|
358
|
+
* sha, check_name) tuple used by the store. The key format is fixed by
|
|
359
|
+
* `checkRunKey()`; provider defaults to 'github' because today's
|
|
360
|
+
* reporter only writes check runs for GitHub.
|
|
361
|
+
*/
|
|
362
|
+
private parseKey;
|
|
363
|
+
/**
|
|
364
|
+
* Write-through helper: persist a check-run ID to L1 + the store.
|
|
365
|
+
* Used by `setPending` / `setBuildPending` after a successful
|
|
366
|
+
* `checks.create()`.
|
|
367
|
+
*/
|
|
368
|
+
private persistCheckRunId;
|
|
369
|
+
/**
|
|
370
|
+
* Read-through helper: look up a check-run ID. Checks L1 first, falls
|
|
371
|
+
* through to the store on miss, caches the result on hit. Returns
|
|
372
|
+
* undefined when neither layer has the ID — the caller logs + skips.
|
|
373
|
+
*/
|
|
374
|
+
private resolveCheckRunId;
|
|
375
|
+
/**
|
|
376
|
+
* Write-through helper: persist updated step-progress entries.
|
|
377
|
+
*/
|
|
378
|
+
private persistStepProgress;
|
|
379
|
+
/**
|
|
380
|
+
* Write-through helper: mark the first running-step transition as sent.
|
|
381
|
+
*/
|
|
382
|
+
private persistInProgressSent;
|
|
383
|
+
/**
|
|
384
|
+
* Write-through helper: stamp `build_creation_state = 'pending'`.
|
|
385
|
+
*/
|
|
386
|
+
private persistBuildCreationPending;
|
|
309
387
|
/**
|
|
310
388
|
* Resolve GitHub App credentials for a given routing key.
|
|
311
389
|
*
|
|
@@ -379,4 +457,4 @@ export declare class CommitStatusReporter {
|
|
|
379
457
|
*/
|
|
380
458
|
export declare function buildJobFailureDescription(data: Record<string, unknown>): string;
|
|
381
459
|
export {};
|
|
382
|
-
//# sourceMappingURL=
|
|
460
|
+
//# sourceMappingURL=check-run-reporter.d.ts.map
|