@kici-dev/orchestrator 0.1.9 → 0.1.10
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/scaler/manager.d.ts +13 -0
- package/dist/server.js +74 -53
- package/dist/standalone.js +74 -53
- package/dist/ws/agent-handler.d.ts +33 -0
- package/package.json +3 -3
- package/sbom.spdx.json +36 -36
package/dist/scaler/manager.d.ts
CHANGED
|
@@ -15,6 +15,19 @@ import type { ScalerStateStore, ScalerStateRecovery } from './scaler-state-store
|
|
|
15
15
|
* combined with the scaler's `defaults.resources`, applying the request<->limit
|
|
16
16
|
* mirroring rule. Caps aggregate `requests`; backends use `limits`.
|
|
17
17
|
*/
|
|
18
|
+
/**
|
|
19
|
+
* Resolve the orchestrator WebSocket URL a scaler-spawned agent should dial.
|
|
20
|
+
*
|
|
21
|
+
* 1. Per-scaler `orchestratorUrl` (scalers.yaml) wins — required for container
|
|
22
|
+
* agents (host.docker.internal / LAN IP) and Firecracker VMs (bridge gateway
|
|
23
|
+
* IP), which cannot reach the orchestrator over the host's loopback.
|
|
24
|
+
* 2. `KICI_ORCHESTRATOR_URL` env override.
|
|
25
|
+
* 3. Default `ws://127.0.0.1:<orchestrator-port>/ws` — for local (bare-metal)
|
|
26
|
+
* agents that share the host. The port is the orchestrator's own bind port
|
|
27
|
+
* (`KICI_PORT`, default 4000), NOT the agent's 8080 default; pointing local
|
|
28
|
+
* agents at 8080 leaves them unable to reach the orchestrator.
|
|
29
|
+
*/
|
|
30
|
+
export declare function resolveScalerOrchestratorUrl(configUrl: string | undefined, envUrl: string | undefined, port: string | number | undefined): string;
|
|
18
31
|
export interface ResolvedResources {
|
|
19
32
|
requests: {
|
|
20
33
|
cpus: number;
|
package/dist/server.js
CHANGED
|
@@ -3,7 +3,7 @@ import { dirname as __cjs_dirname } from "node:path";
|
|
|
3
3
|
__cjs_dirname(__cjs_fileURLToPath(import.meta.url));
|
|
4
4
|
import "node:module";
|
|
5
5
|
import { BaseColdStore, RingBuffer, createDb, createHealthRoutes, createLogger, createMeter, createMetricsRoutes, createPool, createS3Client, encodeKeySegment, enrichRequestContext, formatDuration, getPrometheusExporter, getReconnectDelay, getRequestContext, guardStartup, initTelemetry, requestContext, serializeError, setServiceName, setupGracefulShutdown, sha256, toErrorMessage, validateRequiredTools } from "@kici-dev/shared";
|
|
6
|
-
import { ALLOWED_SYSTEM_VARS, AccessLogAction, AccessLogOutcome, AccessLogSource, AccessLogTargetType, ActorType, CheckRunConclusion, EVENT_LOG_PAYLOAD_CHUNK_BYTES, EventLogPayloadStreamError, EventLogSource, EventLogStatus, ExecutionJobStatus, ExecutionRunStatus, ExecutionStepStatus, KICI_AGENT_ENV_PREFIX, KNOWN_ROLES, MIN_PROTOCOL_VERSION, ORCH_CAPABILITIES, OrchRole, PROTOCOL_VERSION, PayloadOmittedReason, RegisterableTriggerType, SCHEMA_VERSION, ScalerBackendType, SourceSubtype, TERMINAL_JOB_STATES, TERMINAL_RUN_STATES, WEBHOOK_RELAY_MAX_BODY_BYTES, WS_CLOSE_AGENT_AUTH_FAILED, WS_CLOSE_AUTH_TIMEOUT, WS_CLOSE_GOING_AWAY, WS_CLOSE_HEARTBEAT_TIMEOUT, WS_CLOSE_INVALID_MESSAGE, WS_CLOSE_PROTOCOL_ERROR, WS_CLOSE_RUN_NOT_FOUND, WS_CLOSE_UNAUTHORIZED, WS_MAX_PAYLOAD_BYTES, WsRateLimiter, accessLogWarmSqlCase, agentAuthRequestSchema, agentToOrchestratorMessageSchema, agentTypeLabel, createWorkflowDecision, dashboardRunDetailApiResponseSchema, dashboardStepLogsApiResponseSchema, deriveOsArchLabels, flattenActor, getAccessLogColdDays, getSecretAuditLogColdDays, isLockDynamicJobFn, isLockInlineValue, isLockStaticJob, joinRequestSchema, logPullPlatformToOrchSchema, matchAllWorkflows, matchScopePattern, minAccessLogWarmDays, minSecretAuditLogWarmDays, observeSubscribeSchema, peerAuthRequestSchema, peerFromPeerMessageSchema, peerHelloResponseSchema, peerHelloSchema, platformToOrchestratorMessageSchema, resolveRoleLabels, resolveSecretsForEnvironment, scalerLabel, secretAuditLogWarmSqlCase, shouldRecordAccess, shouldRecordSecretResolve, stringifyActor, stripScopePrefix, testEventSchema } from "@kici-dev/engine";
|
|
6
|
+
import { ALLOWED_SYSTEM_VARS, AccessLogAction, AccessLogOutcome, AccessLogSource, AccessLogTargetType, ActorType, CheckRunConclusion, EVENT_LOG_PAYLOAD_CHUNK_BYTES, EventLogPayloadStreamError, EventLogSource, EventLogStatus, ExecutionJobStatus, ExecutionRunStatus, ExecutionStepStatus, KICI_AGENT_ENV_PREFIX, KNOWN_ROLES, MIN_PROTOCOL_VERSION, ORCH_CAPABILITIES, OrchRole, PROTOCOL_VERSION, PayloadOmittedReason, RegisterableTriggerType, SCHEMA_VERSION, ScalerBackendType, SourceSubtype, TERMINAL_JOB_STATES, TERMINAL_RUN_STATES, WEBHOOK_RELAY_MAX_BODY_BYTES, WS_CLOSE_AGENT_AUTH_FAILED, WS_CLOSE_AUTH_TIMEOUT, WS_CLOSE_GOING_AWAY, WS_CLOSE_HEARTBEAT_TIMEOUT, WS_CLOSE_INVALID_MESSAGE, WS_CLOSE_PROTOCOL_ERROR, WS_CLOSE_RUN_NOT_FOUND, WS_CLOSE_UNAUTHORIZED, WS_MAX_PAYLOAD_BYTES, WsRateLimiter, accessLogWarmSqlCase, agentAuthRequestSchema, agentToOrchestratorMessageSchema, agentTypeLabel, createWorkflowDecision, dashboardRunDetailApiResponseSchema, dashboardStepLogsApiResponseSchema, deriveOsArchLabels, flattenActor, getAccessLogColdDays, getSecretAuditLogColdDays, isLockDynamicJobFn, isLockInlineValue, isLockStaticJob, isSelfReportedLabel, joinRequestSchema, logPullPlatformToOrchSchema, matchAllWorkflows, matchScopePattern, minAccessLogWarmDays, minSecretAuditLogWarmDays, observeSubscribeSchema, peerAuthRequestSchema, peerFromPeerMessageSchema, peerHelloResponseSchema, peerHelloSchema, platformToOrchestratorMessageSchema, resolveRoleLabels, resolveSecretsForEnvironment, scalerAgentLabels, scalerLabel, secretAuditLogWarmSqlCase, shouldRecordAccess, shouldRecordSecretResolve, stringifyActor, stripScopePrefix, testEventSchema } from "@kici-dev/engine";
|
|
7
7
|
import { verifySignature } from "@kici-dev/engine/webhook/signature";
|
|
8
8
|
import { X509Certificate, createCipheriv, createDecipheriv, createHmac, createPrivateKey, createPublicKey, diffieHellman, generateKeyPairSync, hkdfSync, randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
|
|
9
9
|
import os, { cpus, freemem, homedir, hostname, release, tmpdir, totalmem, uptime, userInfo, version } from "node:os";
|
|
@@ -15151,7 +15151,7 @@ var init_peer_client = __esmMin((() => {
|
|
|
15151
15151
|
init_peer_crypto();
|
|
15152
15152
|
init_peer_credentials();
|
|
15153
15153
|
logger$73 = createLogger({ prefix: "peer-client" });
|
|
15154
|
-
SOFTWARE_VERSION$1 = "0.1.
|
|
15154
|
+
SOFTWARE_VERSION$1 = "0.1.10";
|
|
15155
15155
|
PeerClient$1 = class {
|
|
15156
15156
|
ws = null;
|
|
15157
15157
|
_state = "disconnected";
|
|
@@ -16614,7 +16614,7 @@ var init_peer_handler = __esmMin((() => {
|
|
|
16614
16614
|
init_peer_crypto();
|
|
16615
16615
|
init_join_token();
|
|
16616
16616
|
logger$72 = createLogger({ prefix: "peer-handler" });
|
|
16617
|
-
SOFTWARE_VERSION = "0.1.
|
|
16617
|
+
SOFTWARE_VERSION = "0.1.10";
|
|
16618
16618
|
RATE_LIMIT_MAX = 5;
|
|
16619
16619
|
RATE_LIMIT_WINDOW_MS = 6e4;
|
|
16620
16620
|
}));
|
|
@@ -24774,13 +24774,25 @@ var init_check_run_reporter = __esmMin((() => {
|
|
|
24774
24774
|
* returns `false` after closing the WS on the first violation, in which
|
|
24775
24775
|
* case the caller MUST stop processing.
|
|
24776
24776
|
*/
|
|
24777
|
+
/**
|
|
24778
|
+
* WebSocket close reasons are capped at 123 UTF-8 bytes (RFC 6455 §5.5.1).
|
|
24779
|
+
* A reason longer than that makes `ws.close()` throw a RangeError, which —
|
|
24780
|
+
* thrown from an async message handler — surfaces as an unhandled rejection
|
|
24781
|
+
* and skips the close entirely. Truncate on a byte boundary and drop any
|
|
24782
|
+
* trailing partial multi-byte char.
|
|
24783
|
+
*/
|
|
24784
|
+
function truncateCloseReason(reason) {
|
|
24785
|
+
const bytes = Buffer.from(reason, "utf-8");
|
|
24786
|
+
if (bytes.length <= 123) return reason;
|
|
24787
|
+
return bytes.subarray(0, 123).toString("utf-8").replace(/�+$/, "");
|
|
24788
|
+
}
|
|
24777
24789
|
function enforceRegisterAuthGates(authState, payload, ws, agentIdToTokenId) {
|
|
24778
24790
|
if (authState === void 0) return true;
|
|
24779
24791
|
const { tokenId, tokenLabels, tokenAgentType, tokenCreatedBy } = authState;
|
|
24780
24792
|
const { agentId, labels } = payload;
|
|
24781
24793
|
if (tokenLabels !== void 0 && tokenLabels !== null) {
|
|
24782
24794
|
const allowedSet = new Set(tokenLabels);
|
|
24783
|
-
const elevated = labels.filter((l) => !allowedSet.has(l));
|
|
24795
|
+
const elevated = labels.filter((l) => !allowedSet.has(l) && !isSelfReportedLabel(l));
|
|
24784
24796
|
if (elevated.length > 0) {
|
|
24785
24797
|
logger$59.warn("Agent register-time label-scope violation: wire labels exceed token-bound set", {
|
|
24786
24798
|
agentId,
|
|
@@ -24788,7 +24800,7 @@ function enforceRegisterAuthGates(authState, payload, ws, agentIdToTokenId) {
|
|
|
24788
24800
|
wireLabels: labels,
|
|
24789
24801
|
elevated
|
|
24790
24802
|
});
|
|
24791
|
-
ws.close(WS_CLOSE_AGENT_AUTH_FAILED, `Agent labels exceed token-bound scope: ${elevated.join(",")}`);
|
|
24803
|
+
ws.close(WS_CLOSE_AGENT_AUTH_FAILED, truncateCloseReason(`Agent labels exceed token-bound scope: ${elevated.join(",")}`));
|
|
24792
24804
|
return false;
|
|
24793
24805
|
}
|
|
24794
24806
|
}
|
|
@@ -24798,7 +24810,7 @@ function enforceRegisterAuthGates(authState, payload, ws, agentIdToTokenId) {
|
|
|
24798
24810
|
tokenCreatedBy,
|
|
24799
24811
|
tokenId
|
|
24800
24812
|
});
|
|
24801
|
-
ws.close(WS_CLOSE_AGENT_AUTH_FAILED, `Ephemeral token bound to a different agentId: expected ${tokenCreatedBy}, got ${agentId}`);
|
|
24813
|
+
ws.close(WS_CLOSE_AGENT_AUTH_FAILED, truncateCloseReason(`Ephemeral token bound to a different agentId: expected ${tokenCreatedBy}, got ${agentId}`));
|
|
24802
24814
|
return false;
|
|
24803
24815
|
}
|
|
24804
24816
|
if (tokenId !== void 0) {
|
|
@@ -34104,15 +34116,15 @@ var init_admin_config = __esmMin((() => {
|
|
|
34104
34116
|
function createHealthRoutes$1(deps = {}) {
|
|
34105
34117
|
return createHealthRoutes({
|
|
34106
34118
|
livenessInfo: () => ({
|
|
34107
|
-
version: "0.1.
|
|
34108
|
-
buildDate: "2026-05-
|
|
34109
|
-
buildCommit: "
|
|
34110
|
-
sdkVersion: "0.1.
|
|
34111
|
-
sdkBundleHash: "
|
|
34112
|
-
sharedVersion: "0.1.
|
|
34119
|
+
version: "0.1.10",
|
|
34120
|
+
buildDate: "2026-05-26T17:19:08.888Z",
|
|
34121
|
+
buildCommit: "6bf528b56",
|
|
34122
|
+
sdkVersion: "0.1.10",
|
|
34123
|
+
sdkBundleHash: "unknown",
|
|
34124
|
+
sharedVersion: "0.1.10",
|
|
34113
34125
|
sharedBundleHash: "36a23a454fd75ec35f258d39f254543ec0451c6b543fe3618ce427e6e6369aae",
|
|
34114
|
-
engineVersion: "0.1.
|
|
34115
|
-
engineBundleHash: "
|
|
34126
|
+
engineVersion: "0.1.10",
|
|
34127
|
+
engineBundleHash: "dff25bbd7602e853cec6e6e985c6c956ad773e245830273cd52950fff958d4bb"
|
|
34116
34128
|
}),
|
|
34117
34129
|
readinessCheck: deps.db ? async () => {
|
|
34118
34130
|
const checks = {};
|
|
@@ -34146,7 +34158,7 @@ function createCapabilitiesRoutes() {
|
|
|
34146
34158
|
const app = new Hono();
|
|
34147
34159
|
app.get("/api/v1/capabilities", (c) => {
|
|
34148
34160
|
const manifest = {
|
|
34149
|
-
orchestratorVersion: "0.1.
|
|
34161
|
+
orchestratorVersion: "0.1.10",
|
|
34150
34162
|
protocolVersion: PROTOCOL_VERSION,
|
|
34151
34163
|
minProtocolVersion: MIN_PROTOCOL_VERSION
|
|
34152
34164
|
};
|
|
@@ -36583,17 +36595,13 @@ var init_container_backend = __esmMin((() => {
|
|
|
36583
36595
|
const stripped = key.slice(KICI_AGENT_ENV_PREFIX.length);
|
|
36584
36596
|
if (stripped.length > 0) agentEnvForwarded.push(`${stripped}=${value}`);
|
|
36585
36597
|
}
|
|
36598
|
+
const fullLabels = scalerAgentLabels(labelSet, this.type, this.name, this.roles);
|
|
36586
36599
|
let agentToken;
|
|
36587
|
-
if (this.tokenStore) agentToken = await this.tokenStore.createEphemeral(agentId,
|
|
36600
|
+
if (this.tokenStore) agentToken = await this.tokenStore.createEphemeral(agentId, fullLabels, this.tokenTtlMs);
|
|
36588
36601
|
const env = [
|
|
36589
36602
|
`KICI_ORCHESTRATOR_URL=${orchestratorUrl}`,
|
|
36590
36603
|
`KICI_AGENT_ID=${agentId}`,
|
|
36591
|
-
`KICI_LABELS=${
|
|
36592
|
-
...labelSet,
|
|
36593
|
-
`kici:agent:${this.type}`,
|
|
36594
|
-
`kici:scaler:${this.name}`,
|
|
36595
|
-
...resolveRoleLabels(this.roles)
|
|
36596
|
-
].join(",")}`,
|
|
36604
|
+
`KICI_LABELS=${fullLabels.join(",")}`,
|
|
36597
36605
|
`KICI_SCALER_MANAGED=1`,
|
|
36598
36606
|
`KICI_EXECUTION_MODE=bare-metal`,
|
|
36599
36607
|
...agentToken ? [`KICI_AGENT_TOKEN=${agentToken}`] : [],
|
|
@@ -36889,15 +36897,11 @@ var init_bare_metal_backend = __esmMin((() => {
|
|
|
36889
36897
|
const strippedKey = key.slice(KICI_AGENT_ENV_PREFIX.length);
|
|
36890
36898
|
if (strippedKey.length > 0) env[strippedKey] = value;
|
|
36891
36899
|
}
|
|
36892
|
-
|
|
36900
|
+
const fullLabels = scalerAgentLabels(labelSet, this.type, this.name, this.roles);
|
|
36901
|
+
if (this.tokenStore) env.KICI_AGENT_TOKEN = await this.tokenStore.createEphemeral(agentId, fullLabels, this.tokenTtlMs);
|
|
36893
36902
|
env.KICI_ORCHESTRATOR_URL = orchestratorUrl;
|
|
36894
36903
|
env.KICI_AGENT_ID = agentId;
|
|
36895
|
-
env.KICI_LABELS =
|
|
36896
|
-
...labelSet,
|
|
36897
|
-
`kici:agent:${this.type}`,
|
|
36898
|
-
`kici:scaler:${this.name}`,
|
|
36899
|
-
...resolveRoleLabels(this.roles)
|
|
36900
|
-
].join(",");
|
|
36904
|
+
env.KICI_LABELS = fullLabels.join(",");
|
|
36901
36905
|
env.KICI_SCALER_MANAGED = "1";
|
|
36902
36906
|
env.KICI_EXECUTION_MODE = "bare-metal";
|
|
36903
36907
|
env.KICI_PORT = "0";
|
|
@@ -37647,18 +37651,14 @@ var init_firecracker_backend = __esmMin((() => {
|
|
|
37647
37651
|
if (chmodLoosenInterval) clearInterval(chmodLoosenInterval);
|
|
37648
37652
|
}
|
|
37649
37653
|
if (!ready) throw new Error(`Firecracker API socket not ready within 5s for agent ${agentId}`);
|
|
37654
|
+
const fullLabels = scalerAgentLabels(labelSet, this.type, this.name, this.roles);
|
|
37650
37655
|
let agentToken;
|
|
37651
|
-
if (this.tokenStore) agentToken = await this.tokenStore.createEphemeral(agentId,
|
|
37656
|
+
if (this.tokenStore) agentToken = await this.tokenStore.createEphemeral(agentId, fullLabels, this.tokenTtlMs);
|
|
37652
37657
|
const acceptedEnv = this.buildForwardedEnv(matchedLabelSet, agentId);
|
|
37653
37658
|
await api.putMmds({ latest: { "meta-data": {
|
|
37654
37659
|
"kici-orchestrator-url": orchestratorUrl,
|
|
37655
37660
|
"kici-agent-id": agentId,
|
|
37656
|
-
"kici-labels":
|
|
37657
|
-
...labelSet,
|
|
37658
|
-
`kici:agent:${this.type}`,
|
|
37659
|
-
`kici:scaler:${this.name}`,
|
|
37660
|
-
...resolveRoleLabels(this.roles)
|
|
37661
|
-
].join(","),
|
|
37661
|
+
"kici-labels": fullLabels.join(","),
|
|
37662
37662
|
"kici-scaler-managed": "1",
|
|
37663
37663
|
"kici-gateway-ip": this.gateway,
|
|
37664
37664
|
...agentToken ? { "kici-agent-token": agentToken } : {},
|
|
@@ -38735,6 +38735,29 @@ var init_machine_ledger = __esmMin((() => {
|
|
|
38735
38735
|
* and manages the agent lifecycle from spawn to destroy.
|
|
38736
38736
|
*/
|
|
38737
38737
|
/**
|
|
38738
|
+
* Resolved per-job resource amounts (cpus + bytes) for both `requests` and
|
|
38739
|
+
* `limits`. The scaler manager produces this from the job's declared resources
|
|
38740
|
+
* combined with the scaler's `defaults.resources`, applying the request<->limit
|
|
38741
|
+
* mirroring rule. Caps aggregate `requests`; backends use `limits`.
|
|
38742
|
+
*/
|
|
38743
|
+
/**
|
|
38744
|
+
* Resolve the orchestrator WebSocket URL a scaler-spawned agent should dial.
|
|
38745
|
+
*
|
|
38746
|
+
* 1. Per-scaler `orchestratorUrl` (scalers.yaml) wins — required for container
|
|
38747
|
+
* agents (host.docker.internal / LAN IP) and Firecracker VMs (bridge gateway
|
|
38748
|
+
* IP), which cannot reach the orchestrator over the host's loopback.
|
|
38749
|
+
* 2. `KICI_ORCHESTRATOR_URL` env override.
|
|
38750
|
+
* 3. Default `ws://127.0.0.1:<orchestrator-port>/ws` — for local (bare-metal)
|
|
38751
|
+
* agents that share the host. The port is the orchestrator's own bind port
|
|
38752
|
+
* (`KICI_PORT`, default 4000), NOT the agent's 8080 default; pointing local
|
|
38753
|
+
* agents at 8080 leaves them unable to reach the orchestrator.
|
|
38754
|
+
*/
|
|
38755
|
+
function resolveScalerOrchestratorUrl(configUrl, envUrl, port) {
|
|
38756
|
+
if (configUrl) return configUrl;
|
|
38757
|
+
if (envUrl) return envUrl;
|
|
38758
|
+
return `ws://127.0.0.1:${port ?? "4000"}/ws`;
|
|
38759
|
+
}
|
|
38760
|
+
/**
|
|
38738
38761
|
* Apply the request<->limit mirroring rule: if only one side is set, copy it
|
|
38739
38762
|
* to the other; if neither is set, return undefined; if both are set, leave them.
|
|
38740
38763
|
*
|
|
@@ -39646,9 +39669,7 @@ var init_manager = __esmMin((() => {
|
|
|
39646
39669
|
});
|
|
39647
39670
|
}
|
|
39648
39671
|
getOrchestratorUrl(backendName) {
|
|
39649
|
-
|
|
39650
|
-
if (configUrl) return configUrl;
|
|
39651
|
-
return process.env.KICI_ORCHESTRATOR_URL ?? "ws://localhost:8080/ws";
|
|
39672
|
+
return resolveScalerOrchestratorUrl(this.scalerUrls.get(backendName), process.env.KICI_ORCHESTRATOR_URL, process.env.KICI_PORT);
|
|
39652
39673
|
}
|
|
39653
39674
|
/**
|
|
39654
39675
|
* Create a per-agent event emitter closure to pass to backend.spawn().
|
|
@@ -50298,14 +50319,14 @@ var init_worker_core = __esmMin((() => {
|
|
|
50298
50319
|
init_agent_handler();
|
|
50299
50320
|
init_worker_status();
|
|
50300
50321
|
init_agent_heartbeat();
|
|
50301
|
-
ORCHESTRATOR_VERSION$1 = "0.1.
|
|
50302
|
-
WORKER_BUILD_COMMIT = "
|
|
50303
|
-
WORKER_SDK_VERSION = "0.1.
|
|
50304
|
-
WORKER_SDK_BUNDLE_HASH = "
|
|
50305
|
-
WORKER_SHARED_VERSION = "0.1.
|
|
50322
|
+
ORCHESTRATOR_VERSION$1 = "0.1.10";
|
|
50323
|
+
WORKER_BUILD_COMMIT = "6bf528b56";
|
|
50324
|
+
WORKER_SDK_VERSION = "0.1.10";
|
|
50325
|
+
WORKER_SDK_BUNDLE_HASH = "unknown";
|
|
50326
|
+
WORKER_SHARED_VERSION = "0.1.10";
|
|
50306
50327
|
WORKER_SHARED_BUNDLE_HASH = "36a23a454fd75ec35f258d39f254543ec0451c6b543fe3618ce427e6e6369aae";
|
|
50307
|
-
WORKER_ENGINE_VERSION = "0.1.
|
|
50308
|
-
WORKER_ENGINE_BUNDLE_HASH = "
|
|
50328
|
+
WORKER_ENGINE_VERSION = "0.1.10";
|
|
50329
|
+
WORKER_ENGINE_BUNDLE_HASH = "dff25bbd7602e853cec6e6e985c6c956ad773e245830273cd52950fff958d4bb";
|
|
50309
50330
|
logger$1 = createLogger({ prefix: "worker" });
|
|
50310
50331
|
DRAIN_TIMEOUT_MS = 3e5;
|
|
50311
50332
|
}));
|
|
@@ -50326,14 +50347,14 @@ var init_worker_core = __esmMin((() => {
|
|
|
50326
50347
|
* Graceful shutdown in reverse order:
|
|
50327
50348
|
* Platform client -> agent WS -> heartbeat -> HTTP -> DB
|
|
50328
50349
|
*/
|
|
50329
|
-
const ORCHESTRATOR_VERSION = "0.1.
|
|
50330
|
-
const BUILD_COMMIT = "
|
|
50331
|
-
const SDK_VERSION = "0.1.
|
|
50332
|
-
const SDK_BUNDLE_HASH = "
|
|
50333
|
-
const SHARED_VERSION = "0.1.
|
|
50350
|
+
const ORCHESTRATOR_VERSION = "0.1.10";
|
|
50351
|
+
const BUILD_COMMIT = "6bf528b56";
|
|
50352
|
+
const SDK_VERSION = "0.1.10";
|
|
50353
|
+
const SDK_BUNDLE_HASH = "unknown";
|
|
50354
|
+
const SHARED_VERSION = "0.1.10";
|
|
50334
50355
|
const SHARED_BUNDLE_HASH = "36a23a454fd75ec35f258d39f254543ec0451c6b543fe3618ce427e6e6369aae";
|
|
50335
|
-
const ENGINE_VERSION = "0.1.
|
|
50336
|
-
const ENGINE_BUNDLE_HASH = "
|
|
50356
|
+
const ENGINE_VERSION = "0.1.10";
|
|
50357
|
+
const ENGINE_BUNDLE_HASH = "dff25bbd7602e853cec6e6e985c6c956ad773e245830273cd52950fff958d4bb";
|
|
50337
50358
|
const otelSdk = initTelemetry({
|
|
50338
50359
|
serviceName: "kici-orchestrator",
|
|
50339
50360
|
otlpEndpoint: process.env.OTEL_EXPORTER_OTLP_ENDPOINT
|
package/dist/standalone.js
CHANGED
|
@@ -9,7 +9,7 @@ import { z } from "zod";
|
|
|
9
9
|
import { LOGGER_ENV_VARS, defineEnv, validateUnknownKiciVars } from "@kici-dev/shared/env";
|
|
10
10
|
import WebSocket from "ws";
|
|
11
11
|
import { chmodSync, closeSync, createReadStream, createWriteStream, mkdirSync, mkdtempSync, openSync, promises, readFileSync, rmSync, statSync, unlinkSync, unwatchFile, watchFile, writeFileSync } from "node:fs";
|
|
12
|
-
import { ALLOWED_SYSTEM_VARS, AccessLogAction, AccessLogOutcome, AccessLogSource, AccessLogTargetType, ActorType, CheckRunConclusion, EventLogSource, EventLogStatus, ExecutionJobStatus, ExecutionRunStatus, ExecutionStepStatus, KICI_AGENT_ENV_PREFIX, KNOWN_ROLES, MIN_PROTOCOL_VERSION, PROTOCOL_VERSION, PayloadOmittedReason, RegisterableTriggerType, SCHEMA_VERSION, ScalerBackendType, SourceSubtype, TERMINAL_JOB_STATES, TERMINAL_RUN_STATES, WS_CLOSE_AGENT_AUTH_FAILED, WS_CLOSE_AUTH_TIMEOUT, WS_CLOSE_GOING_AWAY, WS_CLOSE_HEARTBEAT_TIMEOUT, WS_CLOSE_INVALID_MESSAGE, WS_CLOSE_PROTOCOL_ERROR, WS_CLOSE_RUN_NOT_FOUND, WS_CLOSE_UNAUTHORIZED, WS_MAX_PAYLOAD_BYTES, WsRateLimiter, accessLogWarmSqlCase, agentAuthRequestSchema, agentToOrchestratorMessageSchema, agentTypeLabel, createWorkflowDecision, deriveOsArchLabels, flattenActor, getAccessLogColdDays, getSecretAuditLogColdDays, isLockDynamicJobFn, isLockInlineValue, isLockStaticJob, matchAllWorkflows, minAccessLogWarmDays, minSecretAuditLogWarmDays, observeSubscribeSchema, peerAuthRequestSchema, peerFromPeerMessageSchema, peerHelloResponseSchema, peerHelloSchema, resolveRoleLabels, scalerLabel, secretAuditLogWarmSqlCase, shouldRecordAccess, shouldRecordSecretResolve, testEventSchema } from "@kici-dev/engine";
|
|
12
|
+
import { ALLOWED_SYSTEM_VARS, AccessLogAction, AccessLogOutcome, AccessLogSource, AccessLogTargetType, ActorType, CheckRunConclusion, EventLogSource, EventLogStatus, ExecutionJobStatus, ExecutionRunStatus, ExecutionStepStatus, KICI_AGENT_ENV_PREFIX, KNOWN_ROLES, MIN_PROTOCOL_VERSION, PROTOCOL_VERSION, PayloadOmittedReason, RegisterableTriggerType, SCHEMA_VERSION, ScalerBackendType, SourceSubtype, TERMINAL_JOB_STATES, TERMINAL_RUN_STATES, WS_CLOSE_AGENT_AUTH_FAILED, WS_CLOSE_AUTH_TIMEOUT, WS_CLOSE_GOING_AWAY, WS_CLOSE_HEARTBEAT_TIMEOUT, WS_CLOSE_INVALID_MESSAGE, WS_CLOSE_PROTOCOL_ERROR, WS_CLOSE_RUN_NOT_FOUND, WS_CLOSE_UNAUTHORIZED, WS_MAX_PAYLOAD_BYTES, WsRateLimiter, accessLogWarmSqlCase, agentAuthRequestSchema, agentToOrchestratorMessageSchema, agentTypeLabel, createWorkflowDecision, deriveOsArchLabels, flattenActor, getAccessLogColdDays, getSecretAuditLogColdDays, isLockDynamicJobFn, isLockInlineValue, isLockStaticJob, isSelfReportedLabel, matchAllWorkflows, minAccessLogWarmDays, minSecretAuditLogWarmDays, observeSubscribeSchema, peerAuthRequestSchema, peerFromPeerMessageSchema, peerHelloResponseSchema, peerHelloSchema, resolveRoleLabels, scalerAgentLabels, scalerLabel, secretAuditLogWarmSqlCase, shouldRecordAccess, shouldRecordSecretResolve, testEventSchema } from "@kici-dev/engine";
|
|
13
13
|
import { access, appendFile, chmod, constants, copyFile, link, mkdir, mkdtemp, open, readFile, readdir, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
14
14
|
import { dirname, join, relative, resolve } from "node:path";
|
|
15
15
|
import { sql } from "kysely";
|
|
@@ -1040,7 +1040,7 @@ var init_peer_client = __esmMin((() => {
|
|
|
1040
1040
|
init_peer_crypto();
|
|
1041
1041
|
init_peer_credentials();
|
|
1042
1042
|
logger$85 = createLogger({ prefix: "peer-client" });
|
|
1043
|
-
SOFTWARE_VERSION$1 = "0.1.
|
|
1043
|
+
SOFTWARE_VERSION$1 = "0.1.10";
|
|
1044
1044
|
PeerClient$1 = class {
|
|
1045
1045
|
ws = null;
|
|
1046
1046
|
_state = "disconnected";
|
|
@@ -2503,7 +2503,7 @@ var init_peer_handler = __esmMin((() => {
|
|
|
2503
2503
|
init_peer_crypto();
|
|
2504
2504
|
init_join_token();
|
|
2505
2505
|
logger$84 = createLogger({ prefix: "peer-handler" });
|
|
2506
|
-
SOFTWARE_VERSION = "0.1.
|
|
2506
|
+
SOFTWARE_VERSION = "0.1.10";
|
|
2507
2507
|
RATE_LIMIT_MAX = 5;
|
|
2508
2508
|
RATE_LIMIT_WINDOW_MS = 6e4;
|
|
2509
2509
|
}));
|
|
@@ -10900,13 +10900,25 @@ var init_check_run_reporter = __esmMin((() => {
|
|
|
10900
10900
|
* returns `false` after closing the WS on the first violation, in which
|
|
10901
10901
|
* case the caller MUST stop processing.
|
|
10902
10902
|
*/
|
|
10903
|
+
/**
|
|
10904
|
+
* WebSocket close reasons are capped at 123 UTF-8 bytes (RFC 6455 §5.5.1).
|
|
10905
|
+
* A reason longer than that makes `ws.close()` throw a RangeError, which —
|
|
10906
|
+
* thrown from an async message handler — surfaces as an unhandled rejection
|
|
10907
|
+
* and skips the close entirely. Truncate on a byte boundary and drop any
|
|
10908
|
+
* trailing partial multi-byte char.
|
|
10909
|
+
*/
|
|
10910
|
+
function truncateCloseReason(reason) {
|
|
10911
|
+
const bytes = Buffer.from(reason, "utf-8");
|
|
10912
|
+
if (bytes.length <= 123) return reason;
|
|
10913
|
+
return bytes.subarray(0, 123).toString("utf-8").replace(/�+$/, "");
|
|
10914
|
+
}
|
|
10903
10915
|
function enforceRegisterAuthGates(authState, payload, ws, agentIdToTokenId) {
|
|
10904
10916
|
if (authState === void 0) return true;
|
|
10905
10917
|
const { tokenId, tokenLabels, tokenAgentType, tokenCreatedBy } = authState;
|
|
10906
10918
|
const { agentId, labels } = payload;
|
|
10907
10919
|
if (tokenLabels !== void 0 && tokenLabels !== null) {
|
|
10908
10920
|
const allowedSet = new Set(tokenLabels);
|
|
10909
|
-
const elevated = labels.filter((l) => !allowedSet.has(l));
|
|
10921
|
+
const elevated = labels.filter((l) => !allowedSet.has(l) && !isSelfReportedLabel(l));
|
|
10910
10922
|
if (elevated.length > 0) {
|
|
10911
10923
|
logger$69.warn("Agent register-time label-scope violation: wire labels exceed token-bound set", {
|
|
10912
10924
|
agentId,
|
|
@@ -10914,7 +10926,7 @@ function enforceRegisterAuthGates(authState, payload, ws, agentIdToTokenId) {
|
|
|
10914
10926
|
wireLabels: labels,
|
|
10915
10927
|
elevated
|
|
10916
10928
|
});
|
|
10917
|
-
ws.close(WS_CLOSE_AGENT_AUTH_FAILED, `Agent labels exceed token-bound scope: ${elevated.join(",")}`);
|
|
10929
|
+
ws.close(WS_CLOSE_AGENT_AUTH_FAILED, truncateCloseReason(`Agent labels exceed token-bound scope: ${elevated.join(",")}`));
|
|
10918
10930
|
return false;
|
|
10919
10931
|
}
|
|
10920
10932
|
}
|
|
@@ -10924,7 +10936,7 @@ function enforceRegisterAuthGates(authState, payload, ws, agentIdToTokenId) {
|
|
|
10924
10936
|
tokenCreatedBy,
|
|
10925
10937
|
tokenId
|
|
10926
10938
|
});
|
|
10927
|
-
ws.close(WS_CLOSE_AGENT_AUTH_FAILED, `Ephemeral token bound to a different agentId: expected ${tokenCreatedBy}, got ${agentId}`);
|
|
10939
|
+
ws.close(WS_CLOSE_AGENT_AUTH_FAILED, truncateCloseReason(`Ephemeral token bound to a different agentId: expected ${tokenCreatedBy}, got ${agentId}`));
|
|
10928
10940
|
return false;
|
|
10929
10941
|
}
|
|
10930
10942
|
if (tokenId !== void 0) {
|
|
@@ -21591,15 +21603,15 @@ var init_admin_config = __esmMin((() => {
|
|
|
21591
21603
|
function createHealthRoutes$1(deps = {}) {
|
|
21592
21604
|
return createHealthRoutes({
|
|
21593
21605
|
livenessInfo: () => ({
|
|
21594
|
-
version: "0.1.
|
|
21595
|
-
buildDate: "2026-05-
|
|
21596
|
-
buildCommit: "
|
|
21597
|
-
sdkVersion: "0.1.
|
|
21598
|
-
sdkBundleHash: "
|
|
21599
|
-
sharedVersion: "0.1.
|
|
21606
|
+
version: "0.1.10",
|
|
21607
|
+
buildDate: "2026-05-26T17:19:08.888Z",
|
|
21608
|
+
buildCommit: "6bf528b56",
|
|
21609
|
+
sdkVersion: "0.1.10",
|
|
21610
|
+
sdkBundleHash: "unknown",
|
|
21611
|
+
sharedVersion: "0.1.10",
|
|
21600
21612
|
sharedBundleHash: "36a23a454fd75ec35f258d39f254543ec0451c6b543fe3618ce427e6e6369aae",
|
|
21601
|
-
engineVersion: "0.1.
|
|
21602
|
-
engineBundleHash: "
|
|
21613
|
+
engineVersion: "0.1.10",
|
|
21614
|
+
engineBundleHash: "dff25bbd7602e853cec6e6e985c6c956ad773e245830273cd52950fff958d4bb"
|
|
21603
21615
|
}),
|
|
21604
21616
|
readinessCheck: deps.db ? async () => {
|
|
21605
21617
|
const checks = {};
|
|
@@ -21633,7 +21645,7 @@ function createCapabilitiesRoutes() {
|
|
|
21633
21645
|
const app = new Hono();
|
|
21634
21646
|
app.get("/api/v1/capabilities", (c) => {
|
|
21635
21647
|
const manifest = {
|
|
21636
|
-
orchestratorVersion: "0.1.
|
|
21648
|
+
orchestratorVersion: "0.1.10",
|
|
21637
21649
|
protocolVersion: PROTOCOL_VERSION,
|
|
21638
21650
|
minProtocolVersion: MIN_PROTOCOL_VERSION
|
|
21639
21651
|
};
|
|
@@ -28926,17 +28938,13 @@ var init_container_backend = __esmMin((() => {
|
|
|
28926
28938
|
const stripped = key.slice(KICI_AGENT_ENV_PREFIX.length);
|
|
28927
28939
|
if (stripped.length > 0) agentEnvForwarded.push(`${stripped}=${value}`);
|
|
28928
28940
|
}
|
|
28941
|
+
const fullLabels = scalerAgentLabels(labelSet, this.type, this.name, this.roles);
|
|
28929
28942
|
let agentToken;
|
|
28930
|
-
if (this.tokenStore) agentToken = await this.tokenStore.createEphemeral(agentId,
|
|
28943
|
+
if (this.tokenStore) agentToken = await this.tokenStore.createEphemeral(agentId, fullLabels, this.tokenTtlMs);
|
|
28931
28944
|
const env = [
|
|
28932
28945
|
`KICI_ORCHESTRATOR_URL=${orchestratorUrl}`,
|
|
28933
28946
|
`KICI_AGENT_ID=${agentId}`,
|
|
28934
|
-
`KICI_LABELS=${
|
|
28935
|
-
...labelSet,
|
|
28936
|
-
`kici:agent:${this.type}`,
|
|
28937
|
-
`kici:scaler:${this.name}`,
|
|
28938
|
-
...resolveRoleLabels(this.roles)
|
|
28939
|
-
].join(",")}`,
|
|
28947
|
+
`KICI_LABELS=${fullLabels.join(",")}`,
|
|
28940
28948
|
`KICI_SCALER_MANAGED=1`,
|
|
28941
28949
|
`KICI_EXECUTION_MODE=bare-metal`,
|
|
28942
28950
|
...agentToken ? [`KICI_AGENT_TOKEN=${agentToken}`] : [],
|
|
@@ -29232,15 +29240,11 @@ var init_bare_metal_backend = __esmMin((() => {
|
|
|
29232
29240
|
const strippedKey = key.slice(KICI_AGENT_ENV_PREFIX.length);
|
|
29233
29241
|
if (strippedKey.length > 0) env[strippedKey] = value;
|
|
29234
29242
|
}
|
|
29235
|
-
|
|
29243
|
+
const fullLabels = scalerAgentLabels(labelSet, this.type, this.name, this.roles);
|
|
29244
|
+
if (this.tokenStore) env.KICI_AGENT_TOKEN = await this.tokenStore.createEphemeral(agentId, fullLabels, this.tokenTtlMs);
|
|
29236
29245
|
env.KICI_ORCHESTRATOR_URL = orchestratorUrl;
|
|
29237
29246
|
env.KICI_AGENT_ID = agentId;
|
|
29238
|
-
env.KICI_LABELS =
|
|
29239
|
-
...labelSet,
|
|
29240
|
-
`kici:agent:${this.type}`,
|
|
29241
|
-
`kici:scaler:${this.name}`,
|
|
29242
|
-
...resolveRoleLabels(this.roles)
|
|
29243
|
-
].join(",");
|
|
29247
|
+
env.KICI_LABELS = fullLabels.join(",");
|
|
29244
29248
|
env.KICI_SCALER_MANAGED = "1";
|
|
29245
29249
|
env.KICI_EXECUTION_MODE = "bare-metal";
|
|
29246
29250
|
env.KICI_PORT = "0";
|
|
@@ -29990,18 +29994,14 @@ var init_firecracker_backend = __esmMin((() => {
|
|
|
29990
29994
|
if (chmodLoosenInterval) clearInterval(chmodLoosenInterval);
|
|
29991
29995
|
}
|
|
29992
29996
|
if (!ready) throw new Error(`Firecracker API socket not ready within 5s for agent ${agentId}`);
|
|
29997
|
+
const fullLabels = scalerAgentLabels(labelSet, this.type, this.name, this.roles);
|
|
29993
29998
|
let agentToken;
|
|
29994
|
-
if (this.tokenStore) agentToken = await this.tokenStore.createEphemeral(agentId,
|
|
29999
|
+
if (this.tokenStore) agentToken = await this.tokenStore.createEphemeral(agentId, fullLabels, this.tokenTtlMs);
|
|
29995
30000
|
const acceptedEnv = this.buildForwardedEnv(matchedLabelSet, agentId);
|
|
29996
30001
|
await api.putMmds({ latest: { "meta-data": {
|
|
29997
30002
|
"kici-orchestrator-url": orchestratorUrl,
|
|
29998
30003
|
"kici-agent-id": agentId,
|
|
29999
|
-
"kici-labels":
|
|
30000
|
-
...labelSet,
|
|
30001
|
-
`kici:agent:${this.type}`,
|
|
30002
|
-
`kici:scaler:${this.name}`,
|
|
30003
|
-
...resolveRoleLabels(this.roles)
|
|
30004
|
-
].join(","),
|
|
30004
|
+
"kici-labels": fullLabels.join(","),
|
|
30005
30005
|
"kici-scaler-managed": "1",
|
|
30006
30006
|
"kici-gateway-ip": this.gateway,
|
|
30007
30007
|
...agentToken ? { "kici-agent-token": agentToken } : {},
|
|
@@ -31078,6 +31078,29 @@ var init_machine_ledger = __esmMin((() => {
|
|
|
31078
31078
|
* and manages the agent lifecycle from spawn to destroy.
|
|
31079
31079
|
*/
|
|
31080
31080
|
/**
|
|
31081
|
+
* Resolved per-job resource amounts (cpus + bytes) for both `requests` and
|
|
31082
|
+
* `limits`. The scaler manager produces this from the job's declared resources
|
|
31083
|
+
* combined with the scaler's `defaults.resources`, applying the request<->limit
|
|
31084
|
+
* mirroring rule. Caps aggregate `requests`; backends use `limits`.
|
|
31085
|
+
*/
|
|
31086
|
+
/**
|
|
31087
|
+
* Resolve the orchestrator WebSocket URL a scaler-spawned agent should dial.
|
|
31088
|
+
*
|
|
31089
|
+
* 1. Per-scaler `orchestratorUrl` (scalers.yaml) wins — required for container
|
|
31090
|
+
* agents (host.docker.internal / LAN IP) and Firecracker VMs (bridge gateway
|
|
31091
|
+
* IP), which cannot reach the orchestrator over the host's loopback.
|
|
31092
|
+
* 2. `KICI_ORCHESTRATOR_URL` env override.
|
|
31093
|
+
* 3. Default `ws://127.0.0.1:<orchestrator-port>/ws` — for local (bare-metal)
|
|
31094
|
+
* agents that share the host. The port is the orchestrator's own bind port
|
|
31095
|
+
* (`KICI_PORT`, default 4000), NOT the agent's 8080 default; pointing local
|
|
31096
|
+
* agents at 8080 leaves them unable to reach the orchestrator.
|
|
31097
|
+
*/
|
|
31098
|
+
function resolveScalerOrchestratorUrl(configUrl, envUrl, port) {
|
|
31099
|
+
if (configUrl) return configUrl;
|
|
31100
|
+
if (envUrl) return envUrl;
|
|
31101
|
+
return `ws://127.0.0.1:${port ?? "4000"}/ws`;
|
|
31102
|
+
}
|
|
31103
|
+
/**
|
|
31081
31104
|
* Apply the request<->limit mirroring rule: if only one side is set, copy it
|
|
31082
31105
|
* to the other; if neither is set, return undefined; if both are set, leave them.
|
|
31083
31106
|
*
|
|
@@ -31989,9 +32012,7 @@ var init_manager = __esmMin((() => {
|
|
|
31989
32012
|
});
|
|
31990
32013
|
}
|
|
31991
32014
|
getOrchestratorUrl(backendName) {
|
|
31992
|
-
|
|
31993
|
-
if (configUrl) return configUrl;
|
|
31994
|
-
return process.env.KICI_ORCHESTRATOR_URL ?? "ws://localhost:8080/ws";
|
|
32015
|
+
return resolveScalerOrchestratorUrl(this.scalerUrls.get(backendName), process.env.KICI_ORCHESTRATOR_URL, process.env.KICI_PORT);
|
|
31995
32016
|
}
|
|
31996
32017
|
/**
|
|
31997
32018
|
* Create a per-agent event emitter closure to pass to backend.spawn().
|
|
@@ -43777,14 +43798,14 @@ var init_worker_core = __esmMin((() => {
|
|
|
43777
43798
|
init_agent_handler();
|
|
43778
43799
|
init_worker_status();
|
|
43779
43800
|
init_agent_heartbeat();
|
|
43780
|
-
ORCHESTRATOR_VERSION$1 = "0.1.
|
|
43781
|
-
WORKER_BUILD_COMMIT = "
|
|
43782
|
-
WORKER_SDK_VERSION = "0.1.
|
|
43783
|
-
WORKER_SDK_BUNDLE_HASH = "
|
|
43784
|
-
WORKER_SHARED_VERSION = "0.1.
|
|
43801
|
+
ORCHESTRATOR_VERSION$1 = "0.1.10";
|
|
43802
|
+
WORKER_BUILD_COMMIT = "6bf528b56";
|
|
43803
|
+
WORKER_SDK_VERSION = "0.1.10";
|
|
43804
|
+
WORKER_SDK_BUNDLE_HASH = "unknown";
|
|
43805
|
+
WORKER_SHARED_VERSION = "0.1.10";
|
|
43785
43806
|
WORKER_SHARED_BUNDLE_HASH = "36a23a454fd75ec35f258d39f254543ec0451c6b543fe3618ce427e6e6369aae";
|
|
43786
|
-
WORKER_ENGINE_VERSION = "0.1.
|
|
43787
|
-
WORKER_ENGINE_BUNDLE_HASH = "
|
|
43807
|
+
WORKER_ENGINE_VERSION = "0.1.10";
|
|
43808
|
+
WORKER_ENGINE_BUNDLE_HASH = "dff25bbd7602e853cec6e6e985c6c956ad773e245830273cd52950fff958d4bb";
|
|
43788
43809
|
logger$1 = createLogger({ prefix: "worker" });
|
|
43789
43810
|
DRAIN_TIMEOUT_MS = 3e5;
|
|
43790
43811
|
}));
|
|
@@ -43808,14 +43829,14 @@ var init_worker_core = __esmMin((() => {
|
|
|
43808
43829
|
* Graceful shutdown:
|
|
43809
43830
|
* agent WS -> heartbeat -> HTTP -> DB
|
|
43810
43831
|
*/
|
|
43811
|
-
const ORCHESTRATOR_VERSION = "0.1.
|
|
43812
|
-
const BUILD_COMMIT = "
|
|
43813
|
-
const SDK_VERSION = "0.1.
|
|
43814
|
-
const SDK_BUNDLE_HASH = "
|
|
43815
|
-
const SHARED_VERSION = "0.1.
|
|
43832
|
+
const ORCHESTRATOR_VERSION = "0.1.10";
|
|
43833
|
+
const BUILD_COMMIT = "6bf528b56";
|
|
43834
|
+
const SDK_VERSION = "0.1.10";
|
|
43835
|
+
const SDK_BUNDLE_HASH = "unknown";
|
|
43836
|
+
const SHARED_VERSION = "0.1.10";
|
|
43816
43837
|
const SHARED_BUNDLE_HASH = "36a23a454fd75ec35f258d39f254543ec0451c6b543fe3618ce427e6e6369aae";
|
|
43817
|
-
const ENGINE_VERSION = "0.1.
|
|
43818
|
-
const ENGINE_BUNDLE_HASH = "
|
|
43838
|
+
const ENGINE_VERSION = "0.1.10";
|
|
43839
|
+
const ENGINE_BUNDLE_HASH = "dff25bbd7602e853cec6e6e985c6c956ad773e245830273cd52950fff958d4bb";
|
|
43819
43840
|
const otelSdk = initTelemetry({
|
|
43820
43841
|
serviceName: "kici-orchestrator",
|
|
43821
43842
|
otlpEndpoint: process.env.OTEL_EXPORTER_OTLP_ENDPOINT
|
|
@@ -29,6 +29,39 @@ import type { PendingDynamicTracker } from '../cache/pending-dynamics.js';
|
|
|
29
29
|
import type { CacheStorage } from '../storage/types.js';
|
|
30
30
|
import type { AgentMetricsAggregator } from '../metrics/agent-metrics-aggregator.js';
|
|
31
31
|
import type { AgentApiRegistry } from './agent-api-registry.js';
|
|
32
|
+
/**
|
|
33
|
+
* Run the three token-bound authorization gates against a wire-supplied
|
|
34
|
+
* `agent.register` payload. The gates are identical at first register
|
|
35
|
+
* (Phase 2 / `pendingRegistration`) and on every subsequent re-register
|
|
36
|
+
* arriving on the same registered WS — every code path that mutates the
|
|
37
|
+
* registry's `agentId → entry` mapping for an authenticated WS MUST run
|
|
38
|
+
* them, otherwise the §5.3 / §5.1 invariants only hold for the very first
|
|
39
|
+
* register and a re-register can silently overwrite the authority.
|
|
40
|
+
*
|
|
41
|
+
* Gates:
|
|
42
|
+
* 1. Token-scope subset — wire labels MUST be a subset of
|
|
43
|
+
* `agent_tokens.labels` when that set is non-null. Closes the WS with
|
|
44
|
+
* `WS_CLOSE_AGENT_AUTH_FAILED` listing the elevated labels.
|
|
45
|
+
* 2. Ephemeral identity-binding — for `agent_type === 'ephemeral'`,
|
|
46
|
+
* wire `agentId` MUST equal `tokenCreatedBy` (the scaler-spawned
|
|
47
|
+
* agentId the token was issued for). Closes the WS with
|
|
48
|
+
* `WS_CLOSE_AGENT_AUTH_FAILED`.
|
|
49
|
+
* 3. Static-token agentId-collision — a different `tokenId` must not
|
|
50
|
+
* already claim the wire `agentId`. Closes the WS with
|
|
51
|
+
* `WS_CLOSE_INVALID_MESSAGE`.
|
|
52
|
+
*
|
|
53
|
+
* Returns `true` when every gate passed and the caller may proceed;
|
|
54
|
+
* returns `false` after closing the WS on the first violation, in which
|
|
55
|
+
* case the caller MUST stop processing.
|
|
56
|
+
*/
|
|
57
|
+
/**
|
|
58
|
+
* WebSocket close reasons are capped at 123 UTF-8 bytes (RFC 6455 §5.5.1).
|
|
59
|
+
* A reason longer than that makes `ws.close()` throw a RangeError, which —
|
|
60
|
+
* thrown from an async message handler — surfaces as an unhandled rejection
|
|
61
|
+
* and skips the close entirely. Truncate on a byte boundary and drop any
|
|
62
|
+
* trailing partial multi-byte char.
|
|
63
|
+
*/
|
|
64
|
+
export declare function truncateCloseReason(reason: string): string;
|
|
32
65
|
export interface AgentWsHandlerDeps {
|
|
33
66
|
registry: AgentRegistry;
|
|
34
67
|
dispatcher: Dispatcher;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kici-dev/orchestrator",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.10",
|
|
4
4
|
"description": "Customer-deployable orchestrator for the KiCI CI/CD stack. Receives webhook events (direct or via Platform relay), matches triggers against the lock file, and dispatches jobs to connected agents.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"kici",
|
|
@@ -82,8 +82,8 @@
|
|
|
82
82
|
"ws": "^8.20.0",
|
|
83
83
|
"yaml": "^2.8.3",
|
|
84
84
|
"zod": "^4.3.6",
|
|
85
|
-
"@kici-dev/
|
|
86
|
-
"@kici-dev/
|
|
85
|
+
"@kici-dev/shared": "0.1.10",
|
|
86
|
+
"@kici-dev/engine": "0.1.10"
|
|
87
87
|
},
|
|
88
88
|
"kici": {
|
|
89
89
|
"metrics": {
|
package/sbom.spdx.json
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
"spdxVersion": "SPDX-2.3",
|
|
3
3
|
"dataLicense": "CC0-1.0",
|
|
4
4
|
"SPDXID": "SPDXRef-DOCUMENT",
|
|
5
|
-
"name": "@kici-dev/orchestrator@0.1.
|
|
6
|
-
"documentNamespace": "https://kici.dev/sbom/%40kici-dev%2Forchestrator/0.1.
|
|
5
|
+
"name": "@kici-dev/orchestrator@0.1.10",
|
|
6
|
+
"documentNamespace": "https://kici.dev/sbom/%40kici-dev%2Forchestrator/0.1.10/1e7943f5-2300-4aee-b905-0121c011771c",
|
|
7
7
|
"creationInfo": {
|
|
8
|
-
"created": "2026-05-
|
|
8
|
+
"created": "2026-05-26T17:26:36Z",
|
|
9
9
|
"creators": [
|
|
10
10
|
"Tool: kici-sbom-generator"
|
|
11
11
|
]
|
|
@@ -1477,9 +1477,9 @@
|
|
|
1477
1477
|
"homepage": "https://ericsmekens.github.io/jsep/tree/master/packages/regex#readme"
|
|
1478
1478
|
},
|
|
1479
1479
|
{
|
|
1480
|
-
"SPDXID": "SPDXRef-Package--kici-dev-engine-0.1.
|
|
1480
|
+
"SPDXID": "SPDXRef-Package--kici-dev-engine-0.1.10",
|
|
1481
1481
|
"name": "@kici-dev/engine",
|
|
1482
|
-
"versionInfo": "0.1.
|
|
1482
|
+
"versionInfo": "0.1.10",
|
|
1483
1483
|
"downloadLocation": "NOASSERTION",
|
|
1484
1484
|
"filesAnalyzed": false,
|
|
1485
1485
|
"licenseConcluded": "NOASSERTION",
|
|
@@ -1490,7 +1490,7 @@
|
|
|
1490
1490
|
{
|
|
1491
1491
|
"referenceCategory": "PACKAGE-MANAGER",
|
|
1492
1492
|
"referenceType": "purl",
|
|
1493
|
-
"referenceLocator": "pkg:npm/%40kici-dev/engine@0.1.
|
|
1493
|
+
"referenceLocator": "pkg:npm/%40kici-dev/engine@0.1.10"
|
|
1494
1494
|
}
|
|
1495
1495
|
],
|
|
1496
1496
|
"description": "Shared business logic for the KiCI CI/CD stack: protocol, triggers, state machine, and provider interfaces used by the Platform relay, orchestrator, and compiler.",
|
|
@@ -1499,7 +1499,7 @@
|
|
|
1499
1499
|
{
|
|
1500
1500
|
"SPDXID": "SPDXRef-RootPackage",
|
|
1501
1501
|
"name": "@kici-dev/orchestrator",
|
|
1502
|
-
"versionInfo": "0.1.
|
|
1502
|
+
"versionInfo": "0.1.10",
|
|
1503
1503
|
"downloadLocation": "NOASSERTION",
|
|
1504
1504
|
"filesAnalyzed": false,
|
|
1505
1505
|
"licenseConcluded": "NOASSERTION",
|
|
@@ -1510,16 +1510,16 @@
|
|
|
1510
1510
|
{
|
|
1511
1511
|
"referenceCategory": "PACKAGE-MANAGER",
|
|
1512
1512
|
"referenceType": "purl",
|
|
1513
|
-
"referenceLocator": "pkg:npm/%40kici-dev/orchestrator@0.1.
|
|
1513
|
+
"referenceLocator": "pkg:npm/%40kici-dev/orchestrator@0.1.10"
|
|
1514
1514
|
}
|
|
1515
1515
|
],
|
|
1516
1516
|
"description": "Customer-deployable orchestrator for the KiCI CI/CD stack. Receives webhook events (direct or via Platform relay), matches triggers against the lock file, and dispatches jobs to connected agents.",
|
|
1517
1517
|
"homepage": "https://kici.dev"
|
|
1518
1518
|
},
|
|
1519
1519
|
{
|
|
1520
|
-
"SPDXID": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
1520
|
+
"SPDXID": "SPDXRef-Package--kici-dev-shared-0.1.10",
|
|
1521
1521
|
"name": "@kici-dev/shared",
|
|
1522
|
-
"versionInfo": "0.1.
|
|
1522
|
+
"versionInfo": "0.1.10",
|
|
1523
1523
|
"downloadLocation": "NOASSERTION",
|
|
1524
1524
|
"filesAnalyzed": false,
|
|
1525
1525
|
"licenseConcluded": "NOASSERTION",
|
|
@@ -1530,7 +1530,7 @@
|
|
|
1530
1530
|
{
|
|
1531
1531
|
"referenceCategory": "PACKAGE-MANAGER",
|
|
1532
1532
|
"referenceType": "purl",
|
|
1533
|
-
"referenceLocator": "pkg:npm/%40kici-dev/shared@0.1.
|
|
1533
|
+
"referenceLocator": "pkg:npm/%40kici-dev/shared@0.1.10"
|
|
1534
1534
|
}
|
|
1535
1535
|
],
|
|
1536
1536
|
"description": "Shared utilities for the KiCI CI/CD stack — logging, zx setup, crypto, telemetry, health and metrics routes. No business logic.",
|
|
@@ -10682,17 +10682,17 @@
|
|
|
10682
10682
|
"relationshipType": "DEPENDS_ON"
|
|
10683
10683
|
},
|
|
10684
10684
|
{
|
|
10685
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.
|
|
10685
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.10",
|
|
10686
10686
|
"relatedSpdxElement": "SPDXRef-Package-jsonpath-plus-10.4.0",
|
|
10687
10687
|
"relationshipType": "DEPENDS_ON"
|
|
10688
10688
|
},
|
|
10689
10689
|
{
|
|
10690
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.
|
|
10690
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.10",
|
|
10691
10691
|
"relatedSpdxElement": "SPDXRef-Package-picomatch-4.0.4",
|
|
10692
10692
|
"relationshipType": "DEPENDS_ON"
|
|
10693
10693
|
},
|
|
10694
10694
|
{
|
|
10695
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.
|
|
10695
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.10",
|
|
10696
10696
|
"relatedSpdxElement": "SPDXRef-Package-zod-4.3.6",
|
|
10697
10697
|
"relationshipType": "DEPENDS_ON"
|
|
10698
10698
|
},
|
|
@@ -10728,12 +10728,12 @@
|
|
|
10728
10728
|
},
|
|
10729
10729
|
{
|
|
10730
10730
|
"spdxElementId": "SPDXRef-RootPackage",
|
|
10731
|
-
"relatedSpdxElement": "SPDXRef-Package--kici-dev-engine-0.1.
|
|
10731
|
+
"relatedSpdxElement": "SPDXRef-Package--kici-dev-engine-0.1.10",
|
|
10732
10732
|
"relationshipType": "DEPENDS_ON"
|
|
10733
10733
|
},
|
|
10734
10734
|
{
|
|
10735
10735
|
"spdxElementId": "SPDXRef-RootPackage",
|
|
10736
|
-
"relatedSpdxElement": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
10736
|
+
"relatedSpdxElement": "SPDXRef-Package--kici-dev-shared-0.1.10",
|
|
10737
10737
|
"relationshipType": "DEPENDS_ON"
|
|
10738
10738
|
},
|
|
10739
10739
|
{
|
|
@@ -10837,102 +10837,102 @@
|
|
|
10837
10837
|
"relationshipType": "DEPENDS_ON"
|
|
10838
10838
|
},
|
|
10839
10839
|
{
|
|
10840
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
10840
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.10",
|
|
10841
10841
|
"relatedSpdxElement": "SPDXRef-Package--aws-sdk-client-s3-3.1038.0",
|
|
10842
10842
|
"relationshipType": "DEPENDS_ON"
|
|
10843
10843
|
},
|
|
10844
10844
|
{
|
|
10845
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
10845
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.10",
|
|
10846
10846
|
"relatedSpdxElement": "SPDXRef-Package--opentelemetry-api-1.9.1",
|
|
10847
10847
|
"relationshipType": "DEPENDS_ON"
|
|
10848
10848
|
},
|
|
10849
10849
|
{
|
|
10850
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
10850
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.10",
|
|
10851
10851
|
"relatedSpdxElement": "SPDXRef-Package--opentelemetry-exporter-metrics-otlp-http-0.217.0",
|
|
10852
10852
|
"relationshipType": "DEPENDS_ON"
|
|
10853
10853
|
},
|
|
10854
10854
|
{
|
|
10855
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
10855
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.10",
|
|
10856
10856
|
"relatedSpdxElement": "SPDXRef-Package--opentelemetry-exporter-prometheus-0.217.0",
|
|
10857
10857
|
"relationshipType": "DEPENDS_ON"
|
|
10858
10858
|
},
|
|
10859
10859
|
{
|
|
10860
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
10860
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.10",
|
|
10861
10861
|
"relatedSpdxElement": "SPDXRef-Package--opentelemetry-exporter-trace-otlp-http-0.217.0",
|
|
10862
10862
|
"relationshipType": "DEPENDS_ON"
|
|
10863
10863
|
},
|
|
10864
10864
|
{
|
|
10865
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
10865
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.10",
|
|
10866
10866
|
"relatedSpdxElement": "SPDXRef-Package--opentelemetry-instrumentation-runtime-node-0.28.0",
|
|
10867
10867
|
"relationshipType": "DEPENDS_ON"
|
|
10868
10868
|
},
|
|
10869
10869
|
{
|
|
10870
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
10870
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.10",
|
|
10871
10871
|
"relatedSpdxElement": "SPDXRef-Package--opentelemetry-resources-2.7.0",
|
|
10872
10872
|
"relationshipType": "DEPENDS_ON"
|
|
10873
10873
|
},
|
|
10874
10874
|
{
|
|
10875
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
10875
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.10",
|
|
10876
10876
|
"relatedSpdxElement": "SPDXRef-Package--opentelemetry-sdk-node-0.217.0",
|
|
10877
10877
|
"relationshipType": "DEPENDS_ON"
|
|
10878
10878
|
},
|
|
10879
10879
|
{
|
|
10880
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
10880
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.10",
|
|
10881
10881
|
"relatedSpdxElement": "SPDXRef-Package--opentelemetry-semantic-conventions-1.40.0",
|
|
10882
10882
|
"relationshipType": "DEPENDS_ON"
|
|
10883
10883
|
},
|
|
10884
10884
|
{
|
|
10885
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
10885
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.10",
|
|
10886
10886
|
"relatedSpdxElement": "SPDXRef-Package-diff-7.0.0",
|
|
10887
10887
|
"relationshipType": "DEPENDS_ON"
|
|
10888
10888
|
},
|
|
10889
10889
|
{
|
|
10890
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
10890
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.10",
|
|
10891
10891
|
"relatedSpdxElement": "SPDXRef-Package-hono-4.12.18",
|
|
10892
10892
|
"relationshipType": "DEPENDS_ON"
|
|
10893
10893
|
},
|
|
10894
10894
|
{
|
|
10895
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
10895
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.10",
|
|
10896
10896
|
"relatedSpdxElement": "SPDXRef-Package-kysely-0.29.0",
|
|
10897
10897
|
"relationshipType": "DEPENDS_ON"
|
|
10898
10898
|
},
|
|
10899
10899
|
{
|
|
10900
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
10900
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.10",
|
|
10901
10901
|
"relatedSpdxElement": "SPDXRef-Package-oxc-transform-0.128.0",
|
|
10902
10902
|
"relationshipType": "DEPENDS_ON"
|
|
10903
10903
|
},
|
|
10904
10904
|
{
|
|
10905
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
10905
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.10",
|
|
10906
10906
|
"relatedSpdxElement": "SPDXRef-Package-pg-8.20.0",
|
|
10907
10907
|
"relationshipType": "DEPENDS_ON"
|
|
10908
10908
|
},
|
|
10909
10909
|
{
|
|
10910
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
10910
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.10",
|
|
10911
10911
|
"relatedSpdxElement": "SPDXRef-Package-picocolors-1.1.1",
|
|
10912
10912
|
"relationshipType": "DEPENDS_ON"
|
|
10913
10913
|
},
|
|
10914
10914
|
{
|
|
10915
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
10915
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.10",
|
|
10916
10916
|
"relatedSpdxElement": "SPDXRef-Package-winston-daily-rotate-file-5.0.0",
|
|
10917
10917
|
"relationshipType": "DEPENDS_ON"
|
|
10918
10918
|
},
|
|
10919
10919
|
{
|
|
10920
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
10920
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.10",
|
|
10921
10921
|
"relatedSpdxElement": "SPDXRef-Package-winston-3.19.0",
|
|
10922
10922
|
"relationshipType": "DEPENDS_ON"
|
|
10923
10923
|
},
|
|
10924
10924
|
{
|
|
10925
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
10925
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.10",
|
|
10926
10926
|
"relatedSpdxElement": "SPDXRef-Package-yaml-2.8.3",
|
|
10927
10927
|
"relationshipType": "DEPENDS_ON"
|
|
10928
10928
|
},
|
|
10929
10929
|
{
|
|
10930
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
10930
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.10",
|
|
10931
10931
|
"relatedSpdxElement": "SPDXRef-Package-zod-4.3.6",
|
|
10932
10932
|
"relationshipType": "DEPENDS_ON"
|
|
10933
10933
|
},
|
|
10934
10934
|
{
|
|
10935
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
10935
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.10",
|
|
10936
10936
|
"relatedSpdxElement": "SPDXRef-Package-zx-8.8.5",
|
|
10937
10937
|
"relationshipType": "DEPENDS_ON"
|
|
10938
10938
|
},
|