@kici-dev/agent 0.1.22 → 0.1.23
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/bootstrap/api-intercept.d.ts +20 -0
- package/dist/bootstrap/ensure-init-runner.d.ts +39 -0
- package/dist/bootstrap/pre-boot-send.d.ts +25 -0
- package/dist/bootstrap/reach.d.ts +17 -0
- package/dist/bootstrap/ssh-exec.d.ts +58 -0
- package/dist/execution/job-runner.d.ts +12 -0
- package/dist/execution/rule-evaluator.d.ts +4 -2
- package/dist/execution/sandbox/ipc-protocol.d.ts +14 -0
- package/dist/execution/sandbox/step-loop.d.ts +5 -1
- package/dist/execution/sandbox/workflow-runner.d.ts +7 -1
- package/dist/server.js +349 -19
- package/dist/workflow-runner.js +68 -9
- package/package.json +5 -5
- package/sbom.spdx.json +62 -62
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent-process interception of the bootstrap bring-up API methods.
|
|
3
|
+
*
|
|
4
|
+
* `ctx.kici.bootstrap.ensureInitRunner` / `preBootSend` are relayed from the
|
|
5
|
+
* workflow sandbox as `agent.api.request` IPC. The agent process intercepts
|
|
6
|
+
* those two methods HERE (rather than relaying them straight to the
|
|
7
|
+
* orchestrator) so the SSH transport — and the bring-up key / bootstrap token
|
|
8
|
+
* the orchestrator hands back — stay in the agent process, never reaching user
|
|
9
|
+
* workflow code. Every other method falls through to the orchestrator relay
|
|
10
|
+
* unchanged.
|
|
11
|
+
*/
|
|
12
|
+
import { type ApiTransport, type EnsureInitRunnerDeps } from './ensure-init-runner.js';
|
|
13
|
+
/**
|
|
14
|
+
* Wrap the orchestrator API transport so the two bootstrap methods are handled
|
|
15
|
+
* in-process (SSH transport here; privileged resolve relayed to the
|
|
16
|
+
* orchestrator). `relay` is the raw orchestrator transport (the WS
|
|
17
|
+
* `sendApiRequest`).
|
|
18
|
+
*/
|
|
19
|
+
export declare function withBootstrapInterception(relay: ApiTransport, deps?: EnsureInitRunnerDeps): (method: string, params?: Record<string, unknown>) => Promise<unknown>;
|
|
20
|
+
//# sourceMappingURL=api-intercept.d.ts.map
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent-side init-runner bring-up.
|
|
3
|
+
*
|
|
4
|
+
* Runs in the AGENT process (never the workflow sandbox), so the bring-up SSH
|
|
5
|
+
* key and bootstrap token the orchestrator hands back never reach user
|
|
6
|
+
* workflow code. The flow:
|
|
7
|
+
*
|
|
8
|
+
* 1. Call the orchestrator's privileged `kici.ensureInitRunner` handler — it
|
|
9
|
+
* gates on this agent's `kici:capability:ssh-transport` capability,
|
|
10
|
+
* resolves the target's reach + SSH key, mints a single-use bootstrap
|
|
11
|
+
* token, audits, and returns the material (or `{ broughtUp: false }` when
|
|
12
|
+
* the target already has a live agent).
|
|
13
|
+
* 2. Over SSH (ephemeral key, never on disk): drop a launcher onto the target
|
|
14
|
+
* that starts `kici-agent` with the bootstrap env (token + agent id +
|
|
15
|
+
* orchestrator URL + labels), and start it detached.
|
|
16
|
+
*
|
|
17
|
+
* The init-runner then connects → `auth.request` (bootstrap token) →
|
|
18
|
+
* `agent.register` auto-enroll as a temporary `kici:init` agent.
|
|
19
|
+
*/
|
|
20
|
+
import { type SshDeps } from './ssh-exec.js';
|
|
21
|
+
/** Transport that relays an API request to the orchestrator and awaits the result. */
|
|
22
|
+
export type ApiTransport = (method: string, params: Record<string, unknown>) => Promise<unknown>;
|
|
23
|
+
export interface EnsureInitRunnerDeps extends SshDeps {
|
|
24
|
+
/**
|
|
25
|
+
* The command used to start the init-runner on the target. Defaults to
|
|
26
|
+
* `kici-agent` (resolved on the target's PATH). Override for a rescue env
|
|
27
|
+
* that stages the binary at a fixed path.
|
|
28
|
+
*/
|
|
29
|
+
agentCommand?: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Bring up a temporary init-runner on `targetAgentId`. Returns `{ broughtUp }`:
|
|
33
|
+
* false when the target already had a live agent (the orchestrator no-op'd),
|
|
34
|
+
* true when this call dropped + started the init-runner.
|
|
35
|
+
*/
|
|
36
|
+
export declare function ensureInitRunner(transport: ApiTransport, targetAgentId: string, deps?: EnsureInitRunnerDeps): Promise<{
|
|
37
|
+
broughtUp: boolean;
|
|
38
|
+
}>;
|
|
39
|
+
//# sourceMappingURL=ensure-init-runner.d.ts.map
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent-side pre-boot input send (dropbear / initramfs unlock).
|
|
3
|
+
*
|
|
4
|
+
* Runs in the AGENT process. Asks the orchestrator's privileged
|
|
5
|
+
* `kici.preBootSend` handler to gate on the `kici:capability:ssh-transport`
|
|
6
|
+
* capability, resolve the input secret (e.g. a LUKS passphrase), and audit;
|
|
7
|
+
* then pipes the resolved input to the target's pre-boot SSH endpoint
|
|
8
|
+
* (default dropbear port 2222, forced `cryptroot-unlock`). The unlock drops
|
|
9
|
+
* the session as the box boots — success is the send completing, not the SSH
|
|
10
|
+
* exit code; the caller composes a host-alive wait to confirm boot.
|
|
11
|
+
*/
|
|
12
|
+
import { type SshDeps } from './ssh-exec.js';
|
|
13
|
+
import type { ApiTransport } from './ensure-init-runner.js';
|
|
14
|
+
export interface PreBootSendOpts {
|
|
15
|
+
inputSecret: string;
|
|
16
|
+
port?: number;
|
|
17
|
+
command?: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Ship a pre-boot input to the target's dropbear/initramfs SSH channel. The
|
|
21
|
+
* input plaintext is resolved server-side and never logged. Resolves once the
|
|
22
|
+
* send completes (the SSH session legitimately drops as the box boots).
|
|
23
|
+
*/
|
|
24
|
+
export declare function preBootSend(transport: ApiTransport, targetAgentId: string, opts: PreBootSendOpts, deps?: SshDeps): Promise<void>;
|
|
25
|
+
//# sourceMappingURL=pre-boot-send.d.ts.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent-facing host reach metadata: how to SSH to a target for bootstrap.
|
|
3
|
+
*
|
|
4
|
+
* This is the subset the agent's SSH helper needs — the connection
|
|
5
|
+
* coordinates only. It deliberately does NOT carry the `sshKeySecret` ref:
|
|
6
|
+
* the orchestrator resolves the scoped secret server-side and hands the agent
|
|
7
|
+
* the already-resolved private key separately, so the secret ref never reaches
|
|
8
|
+
* the agent. `sshPort` is the OS-sshd port for bring-up; a pre-boot dropbear
|
|
9
|
+
* port is supplied per-call via `SshExecOpts.port`.
|
|
10
|
+
*/
|
|
11
|
+
export interface HostReach {
|
|
12
|
+
agentId: string;
|
|
13
|
+
address: string | null;
|
|
14
|
+
sshUser: string | null;
|
|
15
|
+
sshPort: number | null;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=reach.d.ts.map
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { HostReach } from './reach.js';
|
|
2
|
+
/** Host-key verification mode for the SSH connection. */
|
|
3
|
+
export type SshHostKeyMode = 'accept-new' | 'strict';
|
|
4
|
+
/** Result of an SSH invocation: exit code is reported, never thrown away. */
|
|
5
|
+
export interface SshResult {
|
|
6
|
+
exitCode: number;
|
|
7
|
+
stdout: string;
|
|
8
|
+
stderr: string;
|
|
9
|
+
}
|
|
10
|
+
export interface SshExecOpts {
|
|
11
|
+
/** Piped to the remote command's stdin (e.g. a LUKS passphrase to cryptroot-unlock). */
|
|
12
|
+
stdin?: string;
|
|
13
|
+
/** Override the default SSH port (22). E.g. 2222 for a dropbear initramfs prompt. */
|
|
14
|
+
port?: number;
|
|
15
|
+
/**
|
|
16
|
+
* Host-key verification. Defaults to `accept-new` — the dropbear initramfs
|
|
17
|
+
* host key differs from the OS sshd key, so a pinned OS entry must not be
|
|
18
|
+
* reused. `strict` enforces a known_hosts match.
|
|
19
|
+
*/
|
|
20
|
+
hostKeyMode?: SshHostKeyMode;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Low-level process spawn boundary, injectable so unit tests can assert the
|
|
24
|
+
* exact argv / env / stdin without running a real `ssh`. Mirrors the relevant
|
|
25
|
+
* subset of `child_process.spawn`'s contract.
|
|
26
|
+
*/
|
|
27
|
+
export interface SpawnFn {
|
|
28
|
+
(command: string, args: string[], opts: {
|
|
29
|
+
env: NodeJS.ProcessEnv;
|
|
30
|
+
stdin?: string;
|
|
31
|
+
}): Promise<SshResult>;
|
|
32
|
+
}
|
|
33
|
+
/** Default spawn boundary backed by `node:child_process.spawn`. */
|
|
34
|
+
export declare const defaultSpawn: SpawnFn;
|
|
35
|
+
/** Deps for the SSH helper — the spawn boundary is injectable for tests. */
|
|
36
|
+
export interface SshDeps {
|
|
37
|
+
spawnFn?: SpawnFn;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Run a command on the target over SSH using an ephemeral, in-memory key.
|
|
41
|
+
*
|
|
42
|
+
* The key is loaded into a per-call ssh-agent (never written to disk) and the
|
|
43
|
+
* agent is killed in `finally`. The remote command's exit code / stdout /
|
|
44
|
+
* stderr are returned verbatim — a non-zero exit is reported, not swallowed
|
|
45
|
+
* (a pre-boot unlock legitimately drops the session, so the caller decides
|
|
46
|
+
* what a "success" looks like).
|
|
47
|
+
*/
|
|
48
|
+
export declare function sshExec(reach: HostReach, privateKey: string, command: string, opts?: SshExecOpts, deps?: SshDeps): Promise<SshResult>;
|
|
49
|
+
/**
|
|
50
|
+
* Ship local bytes to a remote path over SSH (`ssh 'cat > path'`), using the
|
|
51
|
+
* same ephemeral-key discipline. Throws on a non-zero exit (a push must
|
|
52
|
+
* succeed end-to-end, unlike a pre-boot unlock).
|
|
53
|
+
*/
|
|
54
|
+
export declare function sshPush(reach: HostReach, privateKey: string, localBytes: string, remotePath: string, opts?: {
|
|
55
|
+
port?: number;
|
|
56
|
+
hostKeyMode?: SshHostKeyMode;
|
|
57
|
+
}, deps?: SshDeps): Promise<void>;
|
|
58
|
+
//# sourceMappingURL=ssh-exec.d.ts.map
|
|
@@ -215,6 +215,18 @@ export declare class JobRunner {
|
|
|
215
215
|
* failure diagnostics, and send the terminal `job.status` message.
|
|
216
216
|
*/
|
|
217
217
|
private reportExecutionResult;
|
|
218
|
+
/**
|
|
219
|
+
* Handle a bring-up job: bring up a temporary init-runner on a declared-but-
|
|
220
|
+
* un-agented host over SSH (fresh-box bootstrap convergence). The orchestrator
|
|
221
|
+
* dispatches this synthetic `__bringup__` job to an agent holding the
|
|
222
|
+
* `kici:capability:ssh-transport` capability; here we run the agent-side
|
|
223
|
+
* `ensureInitRunner` helper (the privileged resolve is relayed to the
|
|
224
|
+
* orchestrator, the SSH transport happens in this agent process — never
|
|
225
|
+
* reaching workflow code). No clone, no sandbox — the init-runner then
|
|
226
|
+
* connects under the target's agent id and the orchestrator's pinned-hold
|
|
227
|
+
* drains the target's bootstrap steps onto it.
|
|
228
|
+
*/
|
|
229
|
+
private handleBringupJob;
|
|
218
230
|
/**
|
|
219
231
|
* Handle a build-only job.
|
|
220
232
|
*
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import type { RuleContext } from '@kici-dev/sdk';
|
|
1
|
+
import type { RuleContext, FanoutPosition } from '@kici-dev/sdk';
|
|
2
2
|
/**
|
|
3
3
|
* Create RuleContext for agent-side rule evaluation.
|
|
4
4
|
*
|
|
5
5
|
* @param event - Event payload from the dispatch message
|
|
6
6
|
* @param changedFiles - List of files changed in this event
|
|
7
7
|
* @param env - Merged environment variables
|
|
8
|
+
* @param dispatchInputs - Operator dispatch inputs (`ctx.dispatchInputs`)
|
|
9
|
+
* @param fanout - Fan-out position (`ctx.fanout`); undefined on a non-fan-out job
|
|
8
10
|
*/
|
|
9
|
-
export declare function createRuleContext(event: Record<string, unknown>, changedFiles?: string[], env?: Record<string, string | undefined
|
|
11
|
+
export declare function createRuleContext(event: Record<string, unknown>, changedFiles?: string[], env?: Record<string, string | undefined>, dispatchInputs?: Readonly<Record<string, string | number | boolean | null>>, fanout?: FanoutPosition): RuleContext;
|
|
10
12
|
export { evaluateRules, type RuleEvaluationResult } from '@kici-dev/sdk';
|
|
11
13
|
//# sourceMappingURL=rule-evaluator.d.ts.map
|
|
@@ -410,6 +410,20 @@ export interface JobExecutionRequest {
|
|
|
410
410
|
platform?: string;
|
|
411
411
|
arch?: string;
|
|
412
412
|
};
|
|
413
|
+
/**
|
|
414
|
+
* Operator-supplied, validated + coerced + defaulted workflow-dispatch inputs
|
|
415
|
+
* (from `kici run --input`), exposed to steps + rules as `ctx.dispatchInputs`.
|
|
416
|
+
* Absent for webhook runs.
|
|
417
|
+
*/
|
|
418
|
+
dispatchInputs?: Record<string, unknown>;
|
|
419
|
+
/**
|
|
420
|
+
* For a fan-out child (`runsOnAll` host or matrix combination): the 0-based
|
|
421
|
+
* deterministic position in the fan-out, assembled into `ctx.fanout`. Absent
|
|
422
|
+
* for non-fan-out jobs.
|
|
423
|
+
*/
|
|
424
|
+
fanoutIndex?: number;
|
|
425
|
+
/** For a fan-out child: the number of children in this fan-out. */
|
|
426
|
+
fanoutTotal?: number;
|
|
413
427
|
/** Secrets to merge into step environment (highest precedence). */
|
|
414
428
|
secrets?: Record<string, string>;
|
|
415
429
|
/** Namespaced secrets by context name for ctx.secrets['context-name'].KEY access. */
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Extracted for testability: the workflow-runner's main() handles IPC, clone, deps,
|
|
6
6
|
* module loading, and calls this loop for step execution with hooks.
|
|
7
7
|
*/
|
|
8
|
-
import type { Step, StepContext, HookInput, OutputsMap, StepSecretMountRecord } from '@kici-dev/sdk';
|
|
8
|
+
import type { Step, StepContext, HookInput, OutputsMap, StepSecretMountRecord, FanoutPosition } from '@kici-dev/sdk';
|
|
9
9
|
import { CheckMode } from '@kici-dev/engine';
|
|
10
10
|
import type { RunnerToAgentMessage } from './ipc-protocol.js';
|
|
11
11
|
import type { SandboxStepResult } from './types.js';
|
|
@@ -36,6 +36,10 @@ export interface StepLoopOptions {
|
|
|
36
36
|
event: Record<string, unknown>;
|
|
37
37
|
/** Environment variables for rule context. */
|
|
38
38
|
env: Record<string, string | undefined>;
|
|
39
|
+
/** Operator dispatch inputs for the rule context (`ctx.dispatchInputs`). */
|
|
40
|
+
dispatchInputs?: Readonly<Record<string, string | number | boolean | null>>;
|
|
41
|
+
/** Fan-out position for the rule context (`ctx.fanout`); undefined on a non-fan-out job. */
|
|
42
|
+
fanout?: FanoutPosition;
|
|
39
43
|
/** Job-level hooks. */
|
|
40
44
|
jobHooks?: JobHooks;
|
|
41
45
|
/**
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import { ExecutionJobStatus } from '@kici-dev/engine';
|
|
17
17
|
import type { StepContext } from '@kici-dev/sdk';
|
|
18
|
-
import type { NeedsContext } from '@kici-dev/sdk';
|
|
18
|
+
import type { NeedsContext, FanoutPosition } from '@kici-dev/sdk';
|
|
19
19
|
import type { OutputsMap, StepRefMap, TrackedStepSecrets } from '@kici-dev/sdk';
|
|
20
20
|
import type { RunnerToAgentMessage, JobExecutionRequest } from './ipc-protocol.js';
|
|
21
21
|
import { LogMasker } from './log-masker.js';
|
|
@@ -36,6 +36,12 @@ export declare function buildStepNeedsContext(declaredNeeds: readonly unknown[]
|
|
|
36
36
|
* inside this process with full shell access.
|
|
37
37
|
*/
|
|
38
38
|
export declare function createSandboxStepContext(workDir: string, stepIndex: number, stepName: string, request: JobExecutionRequest, maskedSendFn: (msg: RunnerToAgentMessage) => void, outputsMap: OutputsMap, refMap: StepRefMap, operatorSecretKeys: Set<string>, secretOutputs: Map<string, string>, jobOutputsMap: OutputsMap, secrets: TrackedStepSecrets, masker: LogMasker): StepContext;
|
|
39
|
+
/**
|
|
40
|
+
* Derive the fan-out position (`ctx.fanout`) from a dispatch request. Returns
|
|
41
|
+
* `undefined` for a non-fan-out job (no `fanoutTotal`), so `ctx.fanout` is only
|
|
42
|
+
* set for `runsOnAll` host children and matrix combinations.
|
|
43
|
+
*/
|
|
44
|
+
export declare function deriveFanout(request: JobExecutionRequest): FanoutPosition | undefined;
|
|
39
45
|
/** Raw provider webhook body for ctx.rawPayload — nested in the envelope. */
|
|
40
46
|
export declare function rawPayloadFromEvent(event: Record<string, unknown> | undefined): Record<string, unknown> | undefined;
|
|
41
47
|
//# sourceMappingURL=workflow-runner.d.ts.map
|
package/dist/server.js
CHANGED
|
@@ -1310,14 +1310,14 @@ var init_console_capture = __esmMin((() => {
|
|
|
1310
1310
|
init_console_capture();
|
|
1311
1311
|
function safe(name, fallback = "unknown") {
|
|
1312
1312
|
switch (name) {
|
|
1313
|
-
case "version": return "0.1.
|
|
1314
|
-
case "buildCommit": return "
|
|
1315
|
-
case "sdkVersion": return "0.1.
|
|
1316
|
-
case "sdkBundleHash": return "
|
|
1317
|
-
case "sharedVersion": return "0.1.
|
|
1313
|
+
case "version": return "0.1.23";
|
|
1314
|
+
case "buildCommit": return "4465935bb";
|
|
1315
|
+
case "sdkVersion": return "0.1.23";
|
|
1316
|
+
case "sdkBundleHash": return "3a83610d2d122b9f9b0f924b225a47050d0b35f00a8f3256a3e15f3ff3bf7ddc";
|
|
1317
|
+
case "sharedVersion": return "0.1.23";
|
|
1318
1318
|
case "sharedBundleHash": return "991385c024392c395d3eb8a68946ef8ed3fcba96f2652f21c3164a54eafa1b1b";
|
|
1319
|
-
case "engineVersion": return "0.1.
|
|
1320
|
-
case "engineBundleHash": return "
|
|
1319
|
+
case "engineVersion": return "0.1.23";
|
|
1320
|
+
case "engineBundleHash": return "4a0566c709180a6a8744ff3281640e596b8e661ddceb81327cd37d232d9768d5";
|
|
1321
1321
|
default: return fallback;
|
|
1322
1322
|
}
|
|
1323
1323
|
}
|
|
@@ -2080,8 +2080,8 @@ async function extractStepsFromDynamicJob(workflow, dynamicIndex, jobName, event
|
|
|
2080
2080
|
}
|
|
2081
2081
|
var AGENT_SDK_VERSION, AGENT_SDK_BUNDLE_HASH, hookRegistered;
|
|
2082
2082
|
var init_workflow_loader = __esmMin((() => {
|
|
2083
|
-
AGENT_SDK_VERSION = "0.1.
|
|
2084
|
-
AGENT_SDK_BUNDLE_HASH = "
|
|
2083
|
+
AGENT_SDK_VERSION = "0.1.23";
|
|
2084
|
+
AGENT_SDK_BUNDLE_HASH = "3a83610d2d122b9f9b0f924b225a47050d0b35f00a8f3256a3e15f3ff3bf7ddc";
|
|
2085
2085
|
hookRegistered = false;
|
|
2086
2086
|
}));
|
|
2087
2087
|
//#endregion
|
|
@@ -2566,6 +2566,274 @@ var init_init_runner = __esmMin((() => {
|
|
|
2566
2566
|
init_timeout_util();
|
|
2567
2567
|
}));
|
|
2568
2568
|
//#endregion
|
|
2569
|
+
//#region src/bootstrap/ssh-exec.ts
|
|
2570
|
+
/**
|
|
2571
|
+
* Agent-side SSH helper for bootstrap bring-up.
|
|
2572
|
+
*
|
|
2573
|
+
* Lifts the discipline from `infra/prod/hw/ssh.sh` + the deploy-prod
|
|
2574
|
+
* `runOnBox` helper into the agent: the bring-up private key is piped into an
|
|
2575
|
+
* **ephemeral ssh-agent** (`ssh-add -` reads it from stdin) and the agent is
|
|
2576
|
+
* torn down in a `finally`, so the key never lands on disk and never enters a
|
|
2577
|
+
* long-lived process environment. The agent only holds the key for the
|
|
2578
|
+
* lifetime of the one `ssh` / `scp` invocation.
|
|
2579
|
+
*
|
|
2580
|
+
* `sshExec` runs a remote command; `sshPush` ships local bytes to a remote
|
|
2581
|
+
* path (`ssh 'cat > path'`). Both accept a resolved private key string
|
|
2582
|
+
* (supplied by the caller — the orchestrator resolves the scoped secret and
|
|
2583
|
+
* hands the key down). `sshExec` supports `{ stdin, port, hostKeyMode }` so it
|
|
2584
|
+
* can also drive a pre-boot dropbear / initramfs prompt (a forced-command
|
|
2585
|
+
* endpoint such as `cryptroot-unlock` on port 2222, which accepts the unlock
|
|
2586
|
+
* input on stdin and uses a transient host key distinct from the OS sshd key).
|
|
2587
|
+
*/
|
|
2588
|
+
/** Common `-o` flags every bootstrap SSH connection carries. */
|
|
2589
|
+
function baseSshOptions(hostKeyMode) {
|
|
2590
|
+
return [
|
|
2591
|
+
"-o",
|
|
2592
|
+
`StrictHostKeyChecking=${HOST_KEY_FLAG[hostKeyMode]}`,
|
|
2593
|
+
"-o",
|
|
2594
|
+
"ConnectTimeout=10",
|
|
2595
|
+
"-o",
|
|
2596
|
+
"BatchMode=yes"
|
|
2597
|
+
];
|
|
2598
|
+
}
|
|
2599
|
+
/** Resolve the `user@address` target + port from reach metadata. */
|
|
2600
|
+
function resolveTarget(reach, portOverride) {
|
|
2601
|
+
if (!reach.address) throw new Error(`host ${reach.agentId} has no SSH reach address declared`);
|
|
2602
|
+
const user = reach.sshUser ?? SSH_USER_DEFAULT;
|
|
2603
|
+
const port = portOverride ?? reach.sshPort ?? SSH_PORT_DEFAULT;
|
|
2604
|
+
return {
|
|
2605
|
+
dest: `${user}@${reach.address}`,
|
|
2606
|
+
port
|
|
2607
|
+
};
|
|
2608
|
+
}
|
|
2609
|
+
/**
|
|
2610
|
+
* Run a command on the target over SSH using an ephemeral, in-memory key.
|
|
2611
|
+
*
|
|
2612
|
+
* The key is loaded into a per-call ssh-agent (never written to disk) and the
|
|
2613
|
+
* agent is killed in `finally`. The remote command's exit code / stdout /
|
|
2614
|
+
* stderr are returned verbatim — a non-zero exit is reported, not swallowed
|
|
2615
|
+
* (a pre-boot unlock legitimately drops the session, so the caller decides
|
|
2616
|
+
* what a "success" looks like).
|
|
2617
|
+
*/
|
|
2618
|
+
async function sshExec(reach, privateKey, command, opts = {}, deps = {}) {
|
|
2619
|
+
const spawnFn = deps.spawnFn ?? defaultSpawn;
|
|
2620
|
+
const hostKeyMode = opts.hostKeyMode ?? "accept-new";
|
|
2621
|
+
const { dest, port } = resolveTarget(reach, opts.port);
|
|
2622
|
+
return withEphemeralAgent(privateKey, spawnFn, async (env) => {
|
|
2623
|
+
return spawnFn("ssh", [
|
|
2624
|
+
...baseSshOptions(hostKeyMode),
|
|
2625
|
+
"-p",
|
|
2626
|
+
String(port),
|
|
2627
|
+
dest,
|
|
2628
|
+
command
|
|
2629
|
+
], {
|
|
2630
|
+
env,
|
|
2631
|
+
stdin: opts.stdin
|
|
2632
|
+
});
|
|
2633
|
+
});
|
|
2634
|
+
}
|
|
2635
|
+
/**
|
|
2636
|
+
* Ship local bytes to a remote path over SSH (`ssh 'cat > path'`), using the
|
|
2637
|
+
* same ephemeral-key discipline. Throws on a non-zero exit (a push must
|
|
2638
|
+
* succeed end-to-end, unlike a pre-boot unlock).
|
|
2639
|
+
*/
|
|
2640
|
+
async function sshPush(reach, privateKey, localBytes, remotePath, opts = {}, deps = {}) {
|
|
2641
|
+
const spawnFn = deps.spawnFn ?? defaultSpawn;
|
|
2642
|
+
const hostKeyMode = opts.hostKeyMode ?? "accept-new";
|
|
2643
|
+
const { dest, port } = resolveTarget(reach, opts.port);
|
|
2644
|
+
const result = await withEphemeralAgent(privateKey, spawnFn, async (env) => {
|
|
2645
|
+
return spawnFn("ssh", [
|
|
2646
|
+
...baseSshOptions(hostKeyMode),
|
|
2647
|
+
"-p",
|
|
2648
|
+
String(port),
|
|
2649
|
+
dest,
|
|
2650
|
+
`cat > '${remotePath.replace(/'/g, `'\\''`)}'`
|
|
2651
|
+
], {
|
|
2652
|
+
env,
|
|
2653
|
+
stdin: localBytes
|
|
2654
|
+
});
|
|
2655
|
+
});
|
|
2656
|
+
if (result.exitCode !== 0) throw new Error(`sshPush(${reach.agentId}:${remotePath}): exit ${result.exitCode}${result.stderr ? `\n${result.stderr}` : ""}`);
|
|
2657
|
+
}
|
|
2658
|
+
/**
|
|
2659
|
+
* Start a per-call ephemeral ssh-agent, load the key via stdin (never a file),
|
|
2660
|
+
* run `body` with `SSH_AUTH_SOCK` in env, and kill the agent in `finally`.
|
|
2661
|
+
*/
|
|
2662
|
+
async function withEphemeralAgent(privateKey, spawnFn, body) {
|
|
2663
|
+
const baseEnv = { ...process.env };
|
|
2664
|
+
const start = await spawnFn("ssh-agent", ["-s"], { env: baseEnv });
|
|
2665
|
+
if (start.exitCode !== 0) throw new Error(`ssh-agent start failed: exit ${start.exitCode}\n${start.stderr}`);
|
|
2666
|
+
const sock = parseAgentSocket(start.stdout);
|
|
2667
|
+
const pid = parseAgentPid(start.stdout);
|
|
2668
|
+
const agentEnv = {
|
|
2669
|
+
...baseEnv,
|
|
2670
|
+
SSH_AUTH_SOCK: sock,
|
|
2671
|
+
...pid ? { SSH_AGENT_PID: pid } : {},
|
|
2672
|
+
SSH_ASKPASS: "/bin/false",
|
|
2673
|
+
DISPLAY: ""
|
|
2674
|
+
};
|
|
2675
|
+
try {
|
|
2676
|
+
const add = await spawnFn("ssh-add", ["-"], {
|
|
2677
|
+
env: agentEnv,
|
|
2678
|
+
stdin: privateKey.endsWith("\n") ? privateKey : `${privateKey}\n`
|
|
2679
|
+
});
|
|
2680
|
+
if (add.exitCode !== 0) throw new Error(`ssh-add failed: exit ${add.exitCode}\n${add.stderr}`);
|
|
2681
|
+
return await body(agentEnv);
|
|
2682
|
+
} finally {
|
|
2683
|
+
await spawnFn("ssh-agent", ["-k"], { env: agentEnv }).catch(() => {});
|
|
2684
|
+
}
|
|
2685
|
+
}
|
|
2686
|
+
/** Extract `SSH_AUTH_SOCK=<path>;` from `ssh-agent -s` output. */
|
|
2687
|
+
function parseAgentSocket(out) {
|
|
2688
|
+
const m = out.match(/SSH_AUTH_SOCK=([^;\n]+)/);
|
|
2689
|
+
if (!m) throw new Error("ssh-agent -s did not emit SSH_AUTH_SOCK");
|
|
2690
|
+
return m[1];
|
|
2691
|
+
}
|
|
2692
|
+
/** Extract `SSH_AGENT_PID=<n>;` from `ssh-agent -s` output (best-effort). */
|
|
2693
|
+
function parseAgentPid(out) {
|
|
2694
|
+
return out.match(/SSH_AGENT_PID=([^;\n]+)/)?.[1];
|
|
2695
|
+
}
|
|
2696
|
+
var defaultSpawn, SSH_USER_DEFAULT, SSH_PORT_DEFAULT, HOST_KEY_FLAG;
|
|
2697
|
+
var init_ssh_exec = __esmMin((() => {
|
|
2698
|
+
defaultSpawn = (command, args, opts) => new Promise((resolve, reject) => {
|
|
2699
|
+
const child = spawn(command, args, {
|
|
2700
|
+
env: opts.env,
|
|
2701
|
+
stdio: [
|
|
2702
|
+
opts.stdin !== void 0 ? "pipe" : "ignore",
|
|
2703
|
+
"pipe",
|
|
2704
|
+
"pipe"
|
|
2705
|
+
]
|
|
2706
|
+
});
|
|
2707
|
+
let stdout = "";
|
|
2708
|
+
let stderr = "";
|
|
2709
|
+
child.stdout?.on("data", (b) => {
|
|
2710
|
+
stdout += b.toString();
|
|
2711
|
+
});
|
|
2712
|
+
child.stderr?.on("data", (b) => {
|
|
2713
|
+
stderr += b.toString();
|
|
2714
|
+
});
|
|
2715
|
+
child.on("error", reject);
|
|
2716
|
+
child.on("close", (code) => resolve({
|
|
2717
|
+
exitCode: code ?? -1,
|
|
2718
|
+
stdout,
|
|
2719
|
+
stderr
|
|
2720
|
+
}));
|
|
2721
|
+
if (opts.stdin !== void 0) child.stdin?.end(opts.stdin);
|
|
2722
|
+
});
|
|
2723
|
+
SSH_USER_DEFAULT = "root";
|
|
2724
|
+
SSH_PORT_DEFAULT = 22;
|
|
2725
|
+
HOST_KEY_FLAG = {
|
|
2726
|
+
"accept-new": "accept-new",
|
|
2727
|
+
strict: "yes"
|
|
2728
|
+
};
|
|
2729
|
+
}));
|
|
2730
|
+
//#endregion
|
|
2731
|
+
//#region src/bootstrap/ensure-init-runner.ts
|
|
2732
|
+
/**
|
|
2733
|
+
* Build the launcher script that starts the init-runner on the target with its
|
|
2734
|
+
* bootstrap env. Detached (`setsid … &`) so the SSH session can return while
|
|
2735
|
+
* the agent keeps running and dials the orchestrator.
|
|
2736
|
+
*/
|
|
2737
|
+
function buildLauncher(material, agentCommand) {
|
|
2738
|
+
return [
|
|
2739
|
+
"#!/usr/bin/env bash",
|
|
2740
|
+
"set -euo pipefail",
|
|
2741
|
+
`setsid env ${[
|
|
2742
|
+
`KICI_AGENT_TOKEN=${shQuote(material.bootstrapToken)}`,
|
|
2743
|
+
`KICI_AGENT_ID=${shQuote(material.targetAgentId)}`,
|
|
2744
|
+
`KICI_ORCHESTRATOR_URL=${shQuote(material.orchestratorUrl)}`,
|
|
2745
|
+
`KICI_LABELS=${shQuote(material.labels.join(","))}`,
|
|
2746
|
+
"KICI_EXECUTION_MODE=bare-metal",
|
|
2747
|
+
"KICI_PORT=0"
|
|
2748
|
+
].join(" \\\n ")} \\`,
|
|
2749
|
+
` ${agentCommand} >/tmp/kici-init-runner.log 2>&1 &`,
|
|
2750
|
+
"echo \"init-runner started pid=$!\""
|
|
2751
|
+
].join("\n");
|
|
2752
|
+
}
|
|
2753
|
+
/** Single-quote a value for safe embedding in the launcher's env assignment. */
|
|
2754
|
+
function shQuote(v) {
|
|
2755
|
+
return `'${v.replace(/'/g, `'\\''`)}'`;
|
|
2756
|
+
}
|
|
2757
|
+
/**
|
|
2758
|
+
* Bring up a temporary init-runner on `targetAgentId`. Returns `{ broughtUp }`:
|
|
2759
|
+
* false when the target already had a live agent (the orchestrator no-op'd),
|
|
2760
|
+
* true when this call dropped + started the init-runner.
|
|
2761
|
+
*/
|
|
2762
|
+
async function ensureInitRunner(transport, targetAgentId, deps = {}) {
|
|
2763
|
+
const material = await transport("kici.ensureInitRunner", { targetAgentId });
|
|
2764
|
+
if (!material.broughtUp) return { broughtUp: false };
|
|
2765
|
+
const { reach, privateKey, bootstrapToken, orchestratorUrl, labels } = material;
|
|
2766
|
+
if (!reach || !privateKey || !bootstrapToken || !orchestratorUrl || !labels) throw new Error(`orchestrator returned incomplete bring-up material for ${targetAgentId}`);
|
|
2767
|
+
const agentCommand = deps.agentCommand ?? DEFAULT_AGENT_COMMAND;
|
|
2768
|
+
await sshPush(reach, privateKey, buildLauncher({
|
|
2769
|
+
bootstrapToken,
|
|
2770
|
+
targetAgentId,
|
|
2771
|
+
orchestratorUrl,
|
|
2772
|
+
labels
|
|
2773
|
+
}, agentCommand), LAUNCHER_REMOTE_PATH, {}, deps);
|
|
2774
|
+
const run = await sshExec(reach, privateKey, `chmod 0700 ${LAUNCHER_REMOTE_PATH} && ${LAUNCHER_REMOTE_PATH}`, {}, deps);
|
|
2775
|
+
if (run.exitCode !== 0) throw new Error(`init-runner launch on ${targetAgentId} failed: exit ${run.exitCode}${run.stderr ? `\n${run.stderr}` : ""}`);
|
|
2776
|
+
return { broughtUp: true };
|
|
2777
|
+
}
|
|
2778
|
+
var DEFAULT_AGENT_COMMAND, LAUNCHER_REMOTE_PATH;
|
|
2779
|
+
var init_ensure_init_runner = __esmMin((() => {
|
|
2780
|
+
init_ssh_exec();
|
|
2781
|
+
DEFAULT_AGENT_COMMAND = "kici-agent";
|
|
2782
|
+
LAUNCHER_REMOTE_PATH = "/tmp/kici-init-runner.sh";
|
|
2783
|
+
}));
|
|
2784
|
+
//#endregion
|
|
2785
|
+
//#region src/bootstrap/pre-boot-send.ts
|
|
2786
|
+
/**
|
|
2787
|
+
* Ship a pre-boot input to the target's dropbear/initramfs SSH channel. The
|
|
2788
|
+
* input plaintext is resolved server-side and never logged. Resolves once the
|
|
2789
|
+
* send completes (the SSH session legitimately drops as the box boots).
|
|
2790
|
+
*/
|
|
2791
|
+
async function preBootSend(transport, targetAgentId, opts, deps = {}) {
|
|
2792
|
+
const material = await transport("kici.preBootSend", {
|
|
2793
|
+
targetAgentId,
|
|
2794
|
+
inputSecret: opts.inputSecret,
|
|
2795
|
+
...opts.port !== void 0 ? { port: opts.port } : {},
|
|
2796
|
+
...opts.command !== void 0 ? { command: opts.command } : {}
|
|
2797
|
+
});
|
|
2798
|
+
await sshExec(material.reach, material.privateKey, material.command, {
|
|
2799
|
+
stdin: material.input,
|
|
2800
|
+
port: material.port,
|
|
2801
|
+
hostKeyMode: "accept-new"
|
|
2802
|
+
}, deps);
|
|
2803
|
+
}
|
|
2804
|
+
var init_pre_boot_send = __esmMin((() => {
|
|
2805
|
+
init_ssh_exec();
|
|
2806
|
+
}));
|
|
2807
|
+
//#endregion
|
|
2808
|
+
//#region src/bootstrap/api-intercept.ts
|
|
2809
|
+
/**
|
|
2810
|
+
* Wrap the orchestrator API transport so the two bootstrap methods are handled
|
|
2811
|
+
* in-process (SSH transport here; privileged resolve relayed to the
|
|
2812
|
+
* orchestrator). `relay` is the raw orchestrator transport (the WS
|
|
2813
|
+
* `sendApiRequest`).
|
|
2814
|
+
*/
|
|
2815
|
+
function withBootstrapInterception(relay, deps = {}) {
|
|
2816
|
+
return async (method, params = {}) => {
|
|
2817
|
+
if (method === ENSURE_INIT_RUNNER) return ensureInitRunner(relay, String(params.targetAgentId ?? ""), deps);
|
|
2818
|
+
if (method === PRE_BOOT_SEND) {
|
|
2819
|
+
await preBootSend(relay, String(params.targetAgentId ?? ""), {
|
|
2820
|
+
inputSecret: String(params.inputSecret ?? ""),
|
|
2821
|
+
...typeof params.port === "number" ? { port: params.port } : {},
|
|
2822
|
+
...typeof params.command === "string" ? { command: params.command } : {}
|
|
2823
|
+
}, deps);
|
|
2824
|
+
return;
|
|
2825
|
+
}
|
|
2826
|
+
return relay(method, params);
|
|
2827
|
+
};
|
|
2828
|
+
}
|
|
2829
|
+
var ENSURE_INIT_RUNNER, PRE_BOOT_SEND;
|
|
2830
|
+
var init_api_intercept = __esmMin((() => {
|
|
2831
|
+
init_ensure_init_runner();
|
|
2832
|
+
init_pre_boot_send();
|
|
2833
|
+
ENSURE_INIT_RUNNER = "kici.ensureInitRunner";
|
|
2834
|
+
PRE_BOOT_SEND = "kici.preBootSend";
|
|
2835
|
+
}));
|
|
2836
|
+
//#endregion
|
|
2569
2837
|
//#region src/execution/dynamic-job-serializer.ts
|
|
2570
2838
|
/**
|
|
2571
2839
|
* Convert an array of SDK Job objects into LockJob format for the orchestrator.
|
|
@@ -2687,7 +2955,13 @@ function serializeSteps(steps) {
|
|
|
2687
2955
|
name: step.name || `step-${index}`,
|
|
2688
2956
|
hasOutputs: !!step.outputs,
|
|
2689
2957
|
...step.continueOnError ? { continueOnError: true } : {},
|
|
2690
|
-
...step.timeout ? { timeout: step.timeout } : {}
|
|
2958
|
+
...step.timeout ? { timeout: step.timeout } : {},
|
|
2959
|
+
...step.retry ? { retry: {
|
|
2960
|
+
maxAttempts: step.retry.maxAttempts,
|
|
2961
|
+
delayMs: step.retry.delayMs,
|
|
2962
|
+
backoff: step.retry.backoff,
|
|
2963
|
+
maxDelayMs: step.retry.maxDelayMs
|
|
2964
|
+
} } : {}
|
|
2691
2965
|
};
|
|
2692
2966
|
});
|
|
2693
2967
|
}
|
|
@@ -4263,6 +4537,9 @@ function buildRequest(dispatch, workDir) {
|
|
|
4263
4537
|
matrixValues: jobConfig.matrixValues,
|
|
4264
4538
|
host: jobConfig.host,
|
|
4265
4539
|
agent: jobConfig.agent,
|
|
4540
|
+
dispatchInputs: jobConfig.dispatchInputs,
|
|
4541
|
+
fanoutIndex: jobConfig.fanoutIndex,
|
|
4542
|
+
fanoutTotal: jobConfig.fanoutTotal,
|
|
4266
4543
|
secrets: dispatch.secrets,
|
|
4267
4544
|
namespacedSecrets: dispatch.namespacedSecrets,
|
|
4268
4545
|
sourceFile: jobConfig.source?.file,
|
|
@@ -5543,6 +5820,8 @@ var init_job_runner = __esmMin((() => {
|
|
|
5543
5820
|
init_source_packer();
|
|
5544
5821
|
init_source_restore();
|
|
5545
5822
|
init_init_runner();
|
|
5823
|
+
init_api_intercept();
|
|
5824
|
+
init_ensure_init_runner();
|
|
5546
5825
|
init_timeout_util();
|
|
5547
5826
|
init_dynamic_job_serializer();
|
|
5548
5827
|
init_log_streamer();
|
|
@@ -5655,6 +5934,10 @@ var init_job_runner = __esmMin((() => {
|
|
|
5655
5934
|
await this.handleDynamicJobFn(dispatch, workDir, abortController);
|
|
5656
5935
|
return true;
|
|
5657
5936
|
}
|
|
5937
|
+
if (jobConfig.bringupOnly === true) {
|
|
5938
|
+
await this.handleBringupJob(dispatch);
|
|
5939
|
+
return true;
|
|
5940
|
+
}
|
|
5658
5941
|
if (jobConfig.buildOnly === true) {
|
|
5659
5942
|
if (jobConfig.fullRepo) {
|
|
5660
5943
|
logger$2.warn("Build job received for fullRepo run -- skipping (should not happen)", {
|
|
@@ -5827,7 +6110,7 @@ var init_job_runner = __esmMin((() => {
|
|
|
5827
6110
|
reason: ack.reason
|
|
5828
6111
|
};
|
|
5829
6112
|
},
|
|
5830
|
-
onApiRequest: this._sendApiRequest ? async (method, params) => this._sendApiRequest(method, params) : void 0,
|
|
6113
|
+
onApiRequest: this._sendApiRequest ? withBootstrapInterception(async (method, params) => this._sendApiRequest(method, params)) : void 0,
|
|
5831
6114
|
onCacheRequest: this._requestUserCache ? async (request) => this._requestUserCache(jobId, request) : void 0,
|
|
5832
6115
|
onProvenanceRequest: this._relayProvenance ? async (request) => this._relayProvenance(jobId, request) : void 0,
|
|
5833
6116
|
onApprovalRequest: this._sendStepApproval ? async (request) => this._sendStepApproval(dispatch.runId, dispatch.jobId, request) : void 0,
|
|
@@ -5889,6 +6172,53 @@ var init_job_runner = __esmMin((() => {
|
|
|
5889
6172
|
}, result.secretOutputs);
|
|
5890
6173
|
}
|
|
5891
6174
|
/**
|
|
6175
|
+
* Handle a bring-up job: bring up a temporary init-runner on a declared-but-
|
|
6176
|
+
* un-agented host over SSH (fresh-box bootstrap convergence). The orchestrator
|
|
6177
|
+
* dispatches this synthetic `__bringup__` job to an agent holding the
|
|
6178
|
+
* `kici:capability:ssh-transport` capability; here we run the agent-side
|
|
6179
|
+
* `ensureInitRunner` helper (the privileged resolve is relayed to the
|
|
6180
|
+
* orchestrator, the SSH transport happens in this agent process — never
|
|
6181
|
+
* reaching workflow code). No clone, no sandbox — the init-runner then
|
|
6182
|
+
* connects under the target's agent id and the orchestrator's pinned-hold
|
|
6183
|
+
* drains the target's bootstrap steps onto it.
|
|
6184
|
+
*/
|
|
6185
|
+
async handleBringupJob(dispatch) {
|
|
6186
|
+
const { runId, jobId, jobConfig } = dispatch;
|
|
6187
|
+
const targetAgentId = String(jobConfig.bringupTarget ?? "");
|
|
6188
|
+
logger$2.info("Starting bring-up job", {
|
|
6189
|
+
jobId,
|
|
6190
|
+
runId,
|
|
6191
|
+
targetAgentId
|
|
6192
|
+
});
|
|
6193
|
+
this.sendJobStatus(dispatch, ExecutionJobStatus.enum.running);
|
|
6194
|
+
const streamer = this.createStepStreamer(dispatch, 0);
|
|
6195
|
+
this.sendStepStatus(dispatch, 0, "bring-up", ExecutionStepStatus.enum.running);
|
|
6196
|
+
try {
|
|
6197
|
+
if (!targetAgentId) throw new Error("bring-up job missing bringupTarget");
|
|
6198
|
+
if (!this._sendApiRequest) throw new Error("bring-up job requires an orchestrator API transport");
|
|
6199
|
+
streamer.addLine(`Bringing up init-runner on ${targetAgentId}…`);
|
|
6200
|
+
const result = await ensureInitRunner(async (method, params) => this._sendApiRequest(method, params), targetAgentId);
|
|
6201
|
+
streamer.addLine(result.broughtUp ? `Init-runner brought up on ${targetAgentId}.` : `${targetAgentId} already has a live agent — no bring-up needed.`);
|
|
6202
|
+
await streamer.flush();
|
|
6203
|
+
this.sendStepStatus(dispatch, 0, "bring-up", ExecutionStepStatus.enum.success, void 0, streamer.getTotalBytes());
|
|
6204
|
+
streamer.destroy();
|
|
6205
|
+
this.sendJobStatus(dispatch, ExecutionJobStatus.enum.success);
|
|
6206
|
+
} catch (err) {
|
|
6207
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
6208
|
+
streamer.addLine(`Bring-up failed: ${message}`);
|
|
6209
|
+
await streamer.flush();
|
|
6210
|
+
this.sendStepStatus(dispatch, 0, "bring-up", ExecutionStepStatus.enum.failed, void 0, streamer.getTotalBytes());
|
|
6211
|
+
streamer.destroy();
|
|
6212
|
+
this.sendJobStatus(dispatch, ExecutionJobStatus.enum.failed, { error: message });
|
|
6213
|
+
logger$2.warn("Bring-up job failed", {
|
|
6214
|
+
jobId,
|
|
6215
|
+
runId,
|
|
6216
|
+
targetAgentId,
|
|
6217
|
+
error: message
|
|
6218
|
+
});
|
|
6219
|
+
}
|
|
6220
|
+
}
|
|
6221
|
+
/**
|
|
5892
6222
|
* Handle a build-only job.
|
|
5893
6223
|
*
|
|
5894
6224
|
* Build jobs install dependencies, pack them into a tarball,
|
|
@@ -6281,7 +6611,7 @@ var init_job_runner = __esmMin((() => {
|
|
|
6281
6611
|
error: (msg, ..._args) => evalLog(`ERROR: ${msg}`),
|
|
6282
6612
|
debug: (msg, ..._args) => evalLog(`DEBUG: ${msg}`)
|
|
6283
6613
|
};
|
|
6284
|
-
const kici = buildKiciApi(this._sendApiRequest ? (method, params) => this._sendApiRequest(method, params ?? {}) : () => Promise.reject(/* @__PURE__ */ new Error("Agent API not available")));
|
|
6614
|
+
const kici = buildKiciApi(this._sendApiRequest ? withBootstrapInterception((method, params) => this._sendApiRequest(method, params ?? {})) : () => Promise.reject(/* @__PURE__ */ new Error("Agent API not available")));
|
|
6285
6615
|
const lockJobs = await runCaptured(evalSink, async () => {
|
|
6286
6616
|
const { module } = await loadWorkflowSource(workDir, config.source.file, config.contentHash, config.resolvedHashFiles);
|
|
6287
6617
|
evalLog("Workflow loaded");
|
|
@@ -6511,14 +6841,14 @@ var init_job_runner = __esmMin((() => {
|
|
|
6511
6841
|
*/
|
|
6512
6842
|
init_console_capture();
|
|
6513
6843
|
init_npm_resolver();
|
|
6514
|
-
const AGENT_VERSION = "0.1.
|
|
6515
|
-
const BUILD_COMMIT = "
|
|
6516
|
-
const SDK_VERSION = "0.1.
|
|
6517
|
-
const SDK_BUNDLE_HASH = "
|
|
6518
|
-
const SHARED_VERSION = "0.1.
|
|
6844
|
+
const AGENT_VERSION = "0.1.23";
|
|
6845
|
+
const BUILD_COMMIT = "4465935bb";
|
|
6846
|
+
const SDK_VERSION = "0.1.23";
|
|
6847
|
+
const SDK_BUNDLE_HASH = "3a83610d2d122b9f9b0f924b225a47050d0b35f00a8f3256a3e15f3ff3bf7ddc";
|
|
6848
|
+
const SHARED_VERSION = "0.1.23";
|
|
6519
6849
|
const SHARED_BUNDLE_HASH = "991385c024392c395d3eb8a68946ef8ed3fcba96f2652f21c3164a54eafa1b1b";
|
|
6520
|
-
const ENGINE_VERSION = "0.1.
|
|
6521
|
-
const ENGINE_BUNDLE_HASH = "
|
|
6850
|
+
const ENGINE_VERSION = "0.1.23";
|
|
6851
|
+
const ENGINE_BUNDLE_HASH = "4a0566c709180a6a8744ff3281640e596b8e661ddceb81327cd37d232d9768d5";
|
|
6522
6852
|
initTelemetry({
|
|
6523
6853
|
serviceName: "kici-agent",
|
|
6524
6854
|
otlpEndpoint: process.env.OTEL_EXPORTER_OTLP_ENDPOINT
|
package/dist/workflow-runner.js
CHANGED
|
@@ -10,7 +10,7 @@ import { createLogger, deriveSharedSecret, initZx, normalizeLineEndings, sha256,
|
|
|
10
10
|
import { CacheOutcome, CacheStepType, CheckMode, CheckStepOutcome, ExecutionJobStatus, ExecutionStepStatus, TimeoutReason } from "@kici-dev/engine";
|
|
11
11
|
import { buildKiciApi, buildNeedsContext, createStepSecrets, evaluateRules, isDynamicJobFn, normalizeApproval, normalizeCacheSpecs, provenanceSubjectIsPath, resolveJobOutputs, resolveStepOutputs, setJobOutputsMap, setStepOutputsMap, setStepRefMap } from "@kici-dev/sdk";
|
|
12
12
|
import { OIDC_TOKEN_REQUEST_METHOD } from "@kici-dev/engine/protocol/messages/oidc-token-relay";
|
|
13
|
-
import { sha256File as sha256File$1 } from "@kici-dev/core";
|
|
13
|
+
import { computeBackoffDelay, sha256File as sha256File$1 } from "@kici-dev/core";
|
|
14
14
|
import { calculateJwkThumbprint, decodeJwt, exportJWK, generateKeyPair } from "jose";
|
|
15
15
|
import { IN_TOTO_PAYLOAD_TYPE, KICI_PROVENANCE_AUDIENCE, KICI_PROVENANCE_BUNDLE_MEDIA_TYPE } from "@kici-dev/engine/provenance/bundle";
|
|
16
16
|
import { IN_TOTO_STATEMENT_TYPE, KICI_WORKFLOW_BUILD_TYPE, SLSA_PROVENANCE_PREDICATE_TYPE } from "@kici-dev/engine/provenance/schema";
|
|
@@ -1106,12 +1106,16 @@ initZx();
|
|
|
1106
1106
|
* @param event - Event payload from the dispatch message
|
|
1107
1107
|
* @param changedFiles - List of files changed in this event
|
|
1108
1108
|
* @param env - Merged environment variables
|
|
1109
|
+
* @param dispatchInputs - Operator dispatch inputs (`ctx.dispatchInputs`)
|
|
1110
|
+
* @param fanout - Fan-out position (`ctx.fanout`); undefined on a non-fan-out job
|
|
1109
1111
|
*/
|
|
1110
|
-
function createRuleContext(event, changedFiles = [], env = {}) {
|
|
1112
|
+
function createRuleContext(event, changedFiles = [], env = {}, dispatchInputs = {}, fanout) {
|
|
1111
1113
|
return {
|
|
1112
1114
|
event,
|
|
1113
1115
|
changedFiles,
|
|
1114
1116
|
env,
|
|
1117
|
+
dispatchInputs,
|
|
1118
|
+
...fanout && { fanout },
|
|
1115
1119
|
$
|
|
1116
1120
|
};
|
|
1117
1121
|
}
|
|
@@ -1316,7 +1320,7 @@ function extractSignal(error) {
|
|
|
1316
1320
|
*/
|
|
1317
1321
|
async function evaluateStepRulesAndMaybeSkip(step, stepIndex, opts) {
|
|
1318
1322
|
if (!step.rules || step.rules.length === 0) return null;
|
|
1319
|
-
const ruleCtx = createRuleContext(opts.event, [], opts.env);
|
|
1323
|
+
const ruleCtx = createRuleContext(opts.event, [], opts.env, opts.dispatchInputs ?? {}, opts.fanout);
|
|
1320
1324
|
const ruleResult = await evaluateRules(step.rules, ruleCtx, step.name);
|
|
1321
1325
|
if (ruleResult.allPassed) return null;
|
|
1322
1326
|
opts.sendIpc({
|
|
@@ -1442,6 +1446,39 @@ async function runObserverHook(args) {
|
|
|
1442
1446
|
* `ctx.secrets.mountFile` tmpdir, any env vars set via `exposeFile`) is
|
|
1443
1447
|
* removed even when the step throws, times out, or rule-skips.
|
|
1444
1448
|
*/
|
|
1449
|
+
/**
|
|
1450
|
+
* Run a step through its retry policy. Each call to `executeStepInLoop` is one
|
|
1451
|
+
* attempt: it sets up its own per-attempt timeout from `step.timeout` and returns
|
|
1452
|
+
* a `SandboxStepResult` (it never throws — a failed attempt is reported as a
|
|
1453
|
+
* `failed` status with an `error`). A failed attempt is retried while attempts
|
|
1454
|
+
* remain AND `retryIf(reconstructedError)` is true; backoff sleeps between
|
|
1455
|
+
* attempts. The retry loop runs to completion BEFORE the caller applies
|
|
1456
|
+
* `continueOnError` to the final outcome.
|
|
1457
|
+
*/
|
|
1458
|
+
async function runStepWithRetry(step, stepIndex, ctx, timeoutMs, opts) {
|
|
1459
|
+
const retry = step.retry;
|
|
1460
|
+
const max = retry?.maxAttempts ?? 1;
|
|
1461
|
+
let result;
|
|
1462
|
+
for (let n = 1; n <= max; n++) {
|
|
1463
|
+
result = await executeStepInLoop(step, stepIndex, ctx, timeoutMs, opts.sendIpc, opts.outputsMap, opts.getSecretsAccessLog, opts.getSecretMountRecords, opts.jobDeadlineSignal, opts.checkMode ?? CheckMode.enum.apply, opts);
|
|
1464
|
+
if (result.status !== ExecutionStepStatus.enum.failed) return result;
|
|
1465
|
+
const err = new Error(result.error?.message ?? `Step '${step.name}' failed`);
|
|
1466
|
+
if (!(n < max && (retry?.retryIf?.(err) ?? true))) break;
|
|
1467
|
+
const delay = computeBackoffDelay(n, {
|
|
1468
|
+
maxAttempts: max,
|
|
1469
|
+
delayMs: retry.delayMs,
|
|
1470
|
+
backoff: retry.backoff,
|
|
1471
|
+
maxDelayMs: retry.maxDelayMs
|
|
1472
|
+
});
|
|
1473
|
+
opts.sendIpc({
|
|
1474
|
+
type: "log.line",
|
|
1475
|
+
stepIndex,
|
|
1476
|
+
line: `[kici] Step '${step.name}' attempt ${n}/${max} failed: ${err.message}; retrying in ${delay}ms`
|
|
1477
|
+
});
|
|
1478
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
1479
|
+
}
|
|
1480
|
+
return result;
|
|
1481
|
+
}
|
|
1445
1482
|
async function runStepIteration(step, stepIndex, opts) {
|
|
1446
1483
|
const skippedResult = await evaluateStepRulesAndMaybeSkip(step, stepIndex, opts);
|
|
1447
1484
|
if (skippedResult) {
|
|
@@ -1469,7 +1506,7 @@ async function runStepIteration(step, stepIndex, opts) {
|
|
|
1469
1506
|
const timeoutMs = step.timeout ?? opts.defaultTimeoutMs;
|
|
1470
1507
|
let result;
|
|
1471
1508
|
try {
|
|
1472
|
-
result = await
|
|
1509
|
+
result = await runStepWithRetry(step, stepIndex, ctx, timeoutMs, opts);
|
|
1473
1510
|
} finally {
|
|
1474
1511
|
await opts.afterStepApplyEnvFiles?.();
|
|
1475
1512
|
}
|
|
@@ -3111,8 +3148,8 @@ function logSubprocessStreams(e, tokens) {
|
|
|
3111
3148
|
* no Rolldown step at runtime. `@kici-dev/sdk` and host-repo deps resolve via
|
|
3112
3149
|
* Node's normal ESM lookup against `.kici/node_modules/`.
|
|
3113
3150
|
*/
|
|
3114
|
-
const AGENT_SDK_VERSION = "0.1.
|
|
3115
|
-
const AGENT_SDK_BUNDLE_HASH = "
|
|
3151
|
+
const AGENT_SDK_VERSION = "0.1.23";
|
|
3152
|
+
const AGENT_SDK_BUNDLE_HASH = "3a83610d2d122b9f9b0f924b225a47050d0b35f00a8f3256a3e15f3ff3bf7ddc";
|
|
3116
3153
|
/**
|
|
3117
3154
|
* Register the `@kici-dev/core/ts-loader-hook` oxc-transform ESM loader hook so
|
|
3118
3155
|
* subsequent dynamic `import()` calls for `.ts` / `.tsx` files transform on the
|
|
@@ -3474,7 +3511,7 @@ async function applyOverlay(config) {
|
|
|
3474
3511
|
*/
|
|
3475
3512
|
init_download();
|
|
3476
3513
|
init_dep_restore();
|
|
3477
|
-
const AGENT_VERSION = "0.1.
|
|
3514
|
+
const AGENT_VERSION = "0.1.23";
|
|
3478
3515
|
process.on("uncaughtException", (err) => {
|
|
3479
3516
|
process.stderr.write(`[workflow-runner] UNCAUGHT EXCEPTION: ${err.message}\n`);
|
|
3480
3517
|
if (err.stack) process.stderr.write(`[workflow-runner] Stack: ${err.stack}\n`);
|
|
@@ -4407,12 +4444,32 @@ function createSandboxStepContext(workDir, stepIndex, stepName, request, maskedS
|
|
|
4407
4444
|
...request.matrixValues && { matrix: request.matrixValues },
|
|
4408
4445
|
...request.host && { host: request.host },
|
|
4409
4446
|
...request.agent && { agent: request.agent },
|
|
4447
|
+
...(() => {
|
|
4448
|
+
const fanout = deriveFanout(request);
|
|
4449
|
+
return fanout ? { fanout } : {};
|
|
4450
|
+
})(),
|
|
4451
|
+
dispatchInputs: request.dispatchInputs ?? {},
|
|
4410
4452
|
...(() => {
|
|
4411
4453
|
const needs = buildStepNeedsContext(request.jobNeeds, request.upstreamJobOutputs, request.upstreamJobStatuses);
|
|
4412
4454
|
return needs ? { needs } : {};
|
|
4413
4455
|
})()
|
|
4414
4456
|
};
|
|
4415
4457
|
}
|
|
4458
|
+
/**
|
|
4459
|
+
* Derive the fan-out position (`ctx.fanout`) from a dispatch request. Returns
|
|
4460
|
+
* `undefined` for a non-fan-out job (no `fanoutTotal`), so `ctx.fanout` is only
|
|
4461
|
+
* set for `runsOnAll` host children and matrix combinations.
|
|
4462
|
+
*/
|
|
4463
|
+
function deriveFanout(request) {
|
|
4464
|
+
if (request.fanoutTotal === void 0) return void 0;
|
|
4465
|
+
const index = request.fanoutIndex ?? 0;
|
|
4466
|
+
return {
|
|
4467
|
+
index,
|
|
4468
|
+
total: request.fanoutTotal,
|
|
4469
|
+
first: index === 0,
|
|
4470
|
+
last: index === request.fanoutTotal - 1
|
|
4471
|
+
};
|
|
4472
|
+
}
|
|
4416
4473
|
/** Raw provider webhook body for ctx.rawPayload — nested in the envelope. */
|
|
4417
4474
|
function rawPayloadFromEvent(event) {
|
|
4418
4475
|
if (!event) return void 0;
|
|
@@ -5026,7 +5083,7 @@ function buildOutputInfrastructure(request, refMap) {
|
|
|
5026
5083
|
*/
|
|
5027
5084
|
async function maybeSkipJobOnRules(job, request, normalizedSteps) {
|
|
5028
5085
|
if (!job?.rules || job.rules.length === 0) return false;
|
|
5029
|
-
const ruleCtx = createRuleContext(request.event ?? {}, [], process.env);
|
|
5086
|
+
const ruleCtx = createRuleContext(request.event ?? {}, [], process.env, request.dispatchInputs ?? {}, deriveFanout(request));
|
|
5030
5087
|
if ((await evaluateRules(job.rules, ruleCtx, request.jobName)).allPassed) return false;
|
|
5031
5088
|
const skippedResults = normalizedSteps.map((s, i) => ({
|
|
5032
5089
|
name: s.name,
|
|
@@ -5281,6 +5338,8 @@ async function main() {
|
|
|
5281
5338
|
outputsMap,
|
|
5282
5339
|
event: request.event ?? {},
|
|
5283
5340
|
env: process.env,
|
|
5341
|
+
dispatchInputs: request.dispatchInputs ?? {},
|
|
5342
|
+
fanout: deriveFanout(request),
|
|
5284
5343
|
jobHooks,
|
|
5285
5344
|
cachePhaseDeps,
|
|
5286
5345
|
isAborted: () => aborted,
|
|
@@ -5389,6 +5448,6 @@ main().catch((error) => {
|
|
|
5389
5448
|
setTimeout(() => process.exit(1), 100);
|
|
5390
5449
|
});
|
|
5391
5450
|
//#endregion
|
|
5392
|
-
export { buildStepNeedsContext, createSandboxStepContext, rawPayloadFromEvent };
|
|
5451
|
+
export { buildStepNeedsContext, createSandboxStepContext, deriveFanout, rawPayloadFromEvent };
|
|
5393
5452
|
|
|
5394
5453
|
//# sourceMappingURL=workflow-runner.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kici-dev/agent",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.23",
|
|
4
4
|
"description": "Customer-deployable agent for the KiCI CI/CD stack. Connects to an orchestrator, clones the workflow repo, executes steps, and streams logs back.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ci",
|
|
@@ -64,10 +64,10 @@
|
|
|
64
64
|
"yaml": "^2.9.0",
|
|
65
65
|
"zod": "^4.4.3",
|
|
66
66
|
"zx": "^8.8.5",
|
|
67
|
-
"@kici-dev/core": "0.1.
|
|
68
|
-
"@kici-dev/engine": "0.1.
|
|
69
|
-
"@kici-dev/sdk": "0.1.
|
|
70
|
-
"@kici-dev/shared": "0.1.
|
|
67
|
+
"@kici-dev/core": "0.1.23",
|
|
68
|
+
"@kici-dev/engine": "0.1.23",
|
|
69
|
+
"@kici-dev/sdk": "0.1.23",
|
|
70
|
+
"@kici-dev/shared": "0.1.23"
|
|
71
71
|
},
|
|
72
72
|
"kici": {
|
|
73
73
|
"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/agent@0.1.
|
|
6
|
-
"documentNamespace": "https://kici.dev/sbom/%40kici-dev%2Fagent/0.1.
|
|
5
|
+
"name": "@kici-dev/agent@0.1.23",
|
|
6
|
+
"documentNamespace": "https://kici.dev/sbom/%40kici-dev%2Fagent/0.1.23/55c6fdcb-9b29-45b7-b421-94309c584037",
|
|
7
7
|
"creationInfo": {
|
|
8
|
-
"created": "2026-06-
|
|
8
|
+
"created": "2026-06-25T11:13:08Z",
|
|
9
9
|
"creators": [
|
|
10
10
|
"Tool: kici-sbom-generator"
|
|
11
11
|
]
|
|
@@ -816,7 +816,7 @@
|
|
|
816
816
|
{
|
|
817
817
|
"SPDXID": "SPDXRef-RootPackage",
|
|
818
818
|
"name": "@kici-dev/agent",
|
|
819
|
-
"versionInfo": "0.1.
|
|
819
|
+
"versionInfo": "0.1.23",
|
|
820
820
|
"downloadLocation": "NOASSERTION",
|
|
821
821
|
"filesAnalyzed": false,
|
|
822
822
|
"licenseConcluded": "NOASSERTION",
|
|
@@ -827,16 +827,16 @@
|
|
|
827
827
|
{
|
|
828
828
|
"referenceCategory": "PACKAGE-MANAGER",
|
|
829
829
|
"referenceType": "purl",
|
|
830
|
-
"referenceLocator": "pkg:npm/%40kici-dev/agent@0.1.
|
|
830
|
+
"referenceLocator": "pkg:npm/%40kici-dev/agent@0.1.23"
|
|
831
831
|
}
|
|
832
832
|
],
|
|
833
833
|
"description": "Customer-deployable agent for the KiCI CI/CD stack. Connects to an orchestrator, clones the workflow repo, executes steps, and streams logs back.",
|
|
834
834
|
"homepage": "https://kici.dev"
|
|
835
835
|
},
|
|
836
836
|
{
|
|
837
|
-
"SPDXID": "SPDXRef-Package--kici-dev-core-0.1.
|
|
837
|
+
"SPDXID": "SPDXRef-Package--kici-dev-core-0.1.23",
|
|
838
838
|
"name": "@kici-dev/core",
|
|
839
|
-
"versionInfo": "0.1.
|
|
839
|
+
"versionInfo": "0.1.23",
|
|
840
840
|
"downloadLocation": "NOASSERTION",
|
|
841
841
|
"filesAnalyzed": false,
|
|
842
842
|
"licenseConcluded": "NOASSERTION",
|
|
@@ -847,16 +847,16 @@
|
|
|
847
847
|
{
|
|
848
848
|
"referenceCategory": "PACKAGE-MANAGER",
|
|
849
849
|
"referenceType": "purl",
|
|
850
|
-
"referenceLocator": "pkg:npm/%40kici-dev/core@0.1.
|
|
850
|
+
"referenceLocator": "pkg:npm/%40kici-dev/core@0.1.23"
|
|
851
851
|
}
|
|
852
852
|
],
|
|
853
853
|
"description": "Light shared utilities for the KiCI stack (logging, errors, formatting, crypto, zx init, the TypeScript ESM loader hook). No server-side dependencies.",
|
|
854
854
|
"homepage": "https://kici.dev"
|
|
855
855
|
},
|
|
856
856
|
{
|
|
857
|
-
"SPDXID": "SPDXRef-Package--kici-dev-engine-0.1.
|
|
857
|
+
"SPDXID": "SPDXRef-Package--kici-dev-engine-0.1.23",
|
|
858
858
|
"name": "@kici-dev/engine",
|
|
859
|
-
"versionInfo": "0.1.
|
|
859
|
+
"versionInfo": "0.1.23",
|
|
860
860
|
"downloadLocation": "NOASSERTION",
|
|
861
861
|
"filesAnalyzed": false,
|
|
862
862
|
"licenseConcluded": "NOASSERTION",
|
|
@@ -867,16 +867,16 @@
|
|
|
867
867
|
{
|
|
868
868
|
"referenceCategory": "PACKAGE-MANAGER",
|
|
869
869
|
"referenceType": "purl",
|
|
870
|
-
"referenceLocator": "pkg:npm/%40kici-dev/engine@0.1.
|
|
870
|
+
"referenceLocator": "pkg:npm/%40kici-dev/engine@0.1.23"
|
|
871
871
|
}
|
|
872
872
|
],
|
|
873
873
|
"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.",
|
|
874
874
|
"homepage": "https://kici.dev"
|
|
875
875
|
},
|
|
876
876
|
{
|
|
877
|
-
"SPDXID": "SPDXRef-Package--kici-dev-sdk-0.1.
|
|
877
|
+
"SPDXID": "SPDXRef-Package--kici-dev-sdk-0.1.23",
|
|
878
878
|
"name": "@kici-dev/sdk",
|
|
879
|
-
"versionInfo": "0.1.
|
|
879
|
+
"versionInfo": "0.1.23",
|
|
880
880
|
"downloadLocation": "NOASSERTION",
|
|
881
881
|
"filesAnalyzed": false,
|
|
882
882
|
"licenseConcluded": "NOASSERTION",
|
|
@@ -887,16 +887,16 @@
|
|
|
887
887
|
{
|
|
888
888
|
"referenceCategory": "PACKAGE-MANAGER",
|
|
889
889
|
"referenceType": "purl",
|
|
890
|
-
"referenceLocator": "pkg:npm/%40kici-dev/sdk@0.1.
|
|
890
|
+
"referenceLocator": "pkg:npm/%40kici-dev/sdk@0.1.23"
|
|
891
891
|
}
|
|
892
892
|
],
|
|
893
893
|
"description": "TypeScript SDK for defining KiCI workflows. Import into `.kici/workflows/*.ts` to declare workflows, jobs, steps, triggers, rules, and matrix configurations.",
|
|
894
894
|
"homepage": "https://kici.dev"
|
|
895
895
|
},
|
|
896
896
|
{
|
|
897
|
-
"SPDXID": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
897
|
+
"SPDXID": "SPDXRef-Package--kici-dev-shared-0.1.23",
|
|
898
898
|
"name": "@kici-dev/shared",
|
|
899
|
-
"versionInfo": "0.1.
|
|
899
|
+
"versionInfo": "0.1.23",
|
|
900
900
|
"downloadLocation": "NOASSERTION",
|
|
901
901
|
"filesAnalyzed": false,
|
|
902
902
|
"licenseConcluded": "NOASSERTION",
|
|
@@ -907,7 +907,7 @@
|
|
|
907
907
|
{
|
|
908
908
|
"referenceCategory": "PACKAGE-MANAGER",
|
|
909
909
|
"referenceType": "purl",
|
|
910
|
-
"referenceLocator": "pkg:npm/%40kici-dev/shared@0.1.
|
|
910
|
+
"referenceLocator": "pkg:npm/%40kici-dev/shared@0.1.23"
|
|
911
911
|
}
|
|
912
912
|
],
|
|
913
913
|
"description": "Shared utilities for the KiCI CI/CD stack — logging, zx setup, crypto, telemetry, health and metrics routes. No business logic.",
|
|
@@ -6209,22 +6209,22 @@
|
|
|
6209
6209
|
},
|
|
6210
6210
|
{
|
|
6211
6211
|
"spdxElementId": "SPDXRef-RootPackage",
|
|
6212
|
-
"relatedSpdxElement": "SPDXRef-Package--kici-dev-core-0.1.
|
|
6212
|
+
"relatedSpdxElement": "SPDXRef-Package--kici-dev-core-0.1.23",
|
|
6213
6213
|
"relationshipType": "DEPENDS_ON"
|
|
6214
6214
|
},
|
|
6215
6215
|
{
|
|
6216
6216
|
"spdxElementId": "SPDXRef-RootPackage",
|
|
6217
|
-
"relatedSpdxElement": "SPDXRef-Package--kici-dev-engine-0.1.
|
|
6217
|
+
"relatedSpdxElement": "SPDXRef-Package--kici-dev-engine-0.1.23",
|
|
6218
6218
|
"relationshipType": "DEPENDS_ON"
|
|
6219
6219
|
},
|
|
6220
6220
|
{
|
|
6221
6221
|
"spdxElementId": "SPDXRef-RootPackage",
|
|
6222
|
-
"relatedSpdxElement": "SPDXRef-Package--kici-dev-sdk-0.1.
|
|
6222
|
+
"relatedSpdxElement": "SPDXRef-Package--kici-dev-sdk-0.1.23",
|
|
6223
6223
|
"relationshipType": "DEPENDS_ON"
|
|
6224
6224
|
},
|
|
6225
6225
|
{
|
|
6226
6226
|
"spdxElementId": "SPDXRef-RootPackage",
|
|
6227
|
-
"relatedSpdxElement": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
6227
|
+
"relatedSpdxElement": "SPDXRef-Package--kici-dev-shared-0.1.23",
|
|
6228
6228
|
"relationshipType": "DEPENDS_ON"
|
|
6229
6229
|
},
|
|
6230
6230
|
{
|
|
@@ -6278,192 +6278,192 @@
|
|
|
6278
6278
|
"relationshipType": "DEPENDS_ON"
|
|
6279
6279
|
},
|
|
6280
6280
|
{
|
|
6281
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.
|
|
6281
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.23",
|
|
6282
6282
|
"relatedSpdxElement": "SPDXRef-Package-oxc-transform-0.135.0",
|
|
6283
6283
|
"relationshipType": "DEPENDS_ON"
|
|
6284
6284
|
},
|
|
6285
6285
|
{
|
|
6286
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.
|
|
6286
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.23",
|
|
6287
6287
|
"relatedSpdxElement": "SPDXRef-Package-picocolors-1.1.1",
|
|
6288
6288
|
"relationshipType": "DEPENDS_ON"
|
|
6289
6289
|
},
|
|
6290
6290
|
{
|
|
6291
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.
|
|
6291
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.23",
|
|
6292
6292
|
"relatedSpdxElement": "SPDXRef-Package-winston-daily-rotate-file-5.0.0",
|
|
6293
6293
|
"relationshipType": "DEPENDS_ON"
|
|
6294
6294
|
},
|
|
6295
6295
|
{
|
|
6296
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.
|
|
6296
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.23",
|
|
6297
6297
|
"relatedSpdxElement": "SPDXRef-Package-winston-3.19.0",
|
|
6298
6298
|
"relationshipType": "DEPENDS_ON"
|
|
6299
6299
|
},
|
|
6300
6300
|
{
|
|
6301
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.
|
|
6301
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.23",
|
|
6302
6302
|
"relatedSpdxElement": "SPDXRef-Package-zod-4.4.3",
|
|
6303
6303
|
"relationshipType": "DEPENDS_ON"
|
|
6304
6304
|
},
|
|
6305
6305
|
{
|
|
6306
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.
|
|
6306
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.23",
|
|
6307
6307
|
"relatedSpdxElement": "SPDXRef-Package-zx-8.8.5",
|
|
6308
6308
|
"relationshipType": "DEPENDS_ON"
|
|
6309
6309
|
},
|
|
6310
6310
|
{
|
|
6311
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.
|
|
6311
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.23",
|
|
6312
6312
|
"relatedSpdxElement": "SPDXRef-Package-jose-6.2.3",
|
|
6313
6313
|
"relationshipType": "DEPENDS_ON"
|
|
6314
6314
|
},
|
|
6315
6315
|
{
|
|
6316
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.
|
|
6316
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.23",
|
|
6317
6317
|
"relatedSpdxElement": "SPDXRef-Package-jsonpath-plus-10.4.0",
|
|
6318
6318
|
"relationshipType": "DEPENDS_ON"
|
|
6319
6319
|
},
|
|
6320
6320
|
{
|
|
6321
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.
|
|
6321
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.23",
|
|
6322
6322
|
"relatedSpdxElement": "SPDXRef-Package-picomatch-4.0.4",
|
|
6323
6323
|
"relationshipType": "DEPENDS_ON"
|
|
6324
6324
|
},
|
|
6325
6325
|
{
|
|
6326
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.
|
|
6326
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.23",
|
|
6327
6327
|
"relatedSpdxElement": "SPDXRef-Package-safe-regex-2.1.1",
|
|
6328
6328
|
"relationshipType": "DEPENDS_ON"
|
|
6329
6329
|
},
|
|
6330
6330
|
{
|
|
6331
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.
|
|
6331
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.23",
|
|
6332
6332
|
"relatedSpdxElement": "SPDXRef-Package-zod-4.4.3",
|
|
6333
6333
|
"relationshipType": "DEPENDS_ON"
|
|
6334
6334
|
},
|
|
6335
6335
|
{
|
|
6336
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-sdk-0.1.
|
|
6337
|
-
"relatedSpdxElement": "SPDXRef-Package--kici-dev-core-0.1.
|
|
6336
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-sdk-0.1.23",
|
|
6337
|
+
"relatedSpdxElement": "SPDXRef-Package--kici-dev-core-0.1.23",
|
|
6338
6338
|
"relationshipType": "DEPENDS_ON"
|
|
6339
6339
|
},
|
|
6340
6340
|
{
|
|
6341
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-sdk-0.1.
|
|
6342
|
-
"relatedSpdxElement": "SPDXRef-Package--kici-dev-engine-0.1.
|
|
6341
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-sdk-0.1.23",
|
|
6342
|
+
"relatedSpdxElement": "SPDXRef-Package--kici-dev-engine-0.1.23",
|
|
6343
6343
|
"relationshipType": "DEPENDS_ON"
|
|
6344
6344
|
},
|
|
6345
6345
|
{
|
|
6346
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-sdk-0.1.
|
|
6346
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-sdk-0.1.23",
|
|
6347
6347
|
"relatedSpdxElement": "SPDXRef-Package-micromatch-4.0.8",
|
|
6348
6348
|
"relationshipType": "DEPENDS_ON"
|
|
6349
6349
|
},
|
|
6350
6350
|
{
|
|
6351
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-sdk-0.1.
|
|
6351
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-sdk-0.1.23",
|
|
6352
6352
|
"relatedSpdxElement": "SPDXRef-Package-zod-4.4.3",
|
|
6353
6353
|
"relationshipType": "DEPENDS_ON"
|
|
6354
6354
|
},
|
|
6355
6355
|
{
|
|
6356
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-sdk-0.1.
|
|
6356
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-sdk-0.1.23",
|
|
6357
6357
|
"relatedSpdxElement": "SPDXRef-Package-zx-8.8.5",
|
|
6358
6358
|
"relationshipType": "DEPENDS_ON"
|
|
6359
6359
|
},
|
|
6360
6360
|
{
|
|
6361
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
6361
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.23",
|
|
6362
6362
|
"relatedSpdxElement": "SPDXRef-Package--aws-sdk-client-s3-3.1064.0",
|
|
6363
6363
|
"relationshipType": "DEPENDS_ON"
|
|
6364
6364
|
},
|
|
6365
6365
|
{
|
|
6366
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
6367
|
-
"relatedSpdxElement": "SPDXRef-Package--kici-dev-core-0.1.
|
|
6366
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.23",
|
|
6367
|
+
"relatedSpdxElement": "SPDXRef-Package--kici-dev-core-0.1.23",
|
|
6368
6368
|
"relationshipType": "DEPENDS_ON"
|
|
6369
6369
|
},
|
|
6370
6370
|
{
|
|
6371
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
6371
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.23",
|
|
6372
6372
|
"relatedSpdxElement": "SPDXRef-Package--opentelemetry-api-1.9.1",
|
|
6373
6373
|
"relationshipType": "DEPENDS_ON"
|
|
6374
6374
|
},
|
|
6375
6375
|
{
|
|
6376
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
6376
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.23",
|
|
6377
6377
|
"relatedSpdxElement": "SPDXRef-Package--opentelemetry-exporter-metrics-otlp-http-0.218.0",
|
|
6378
6378
|
"relationshipType": "DEPENDS_ON"
|
|
6379
6379
|
},
|
|
6380
6380
|
{
|
|
6381
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
6381
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.23",
|
|
6382
6382
|
"relatedSpdxElement": "SPDXRef-Package--opentelemetry-exporter-prometheus-0.218.0",
|
|
6383
6383
|
"relationshipType": "DEPENDS_ON"
|
|
6384
6384
|
},
|
|
6385
6385
|
{
|
|
6386
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
6386
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.23",
|
|
6387
6387
|
"relatedSpdxElement": "SPDXRef-Package--opentelemetry-exporter-trace-otlp-http-0.218.0",
|
|
6388
6388
|
"relationshipType": "DEPENDS_ON"
|
|
6389
6389
|
},
|
|
6390
6390
|
{
|
|
6391
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
6391
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.23",
|
|
6392
6392
|
"relatedSpdxElement": "SPDXRef-Package--opentelemetry-instrumentation-runtime-node-0.31.0",
|
|
6393
6393
|
"relationshipType": "DEPENDS_ON"
|
|
6394
6394
|
},
|
|
6395
6395
|
{
|
|
6396
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
6396
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.23",
|
|
6397
6397
|
"relatedSpdxElement": "SPDXRef-Package--opentelemetry-resources-2.7.1",
|
|
6398
6398
|
"relationshipType": "DEPENDS_ON"
|
|
6399
6399
|
},
|
|
6400
6400
|
{
|
|
6401
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
6401
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.23",
|
|
6402
6402
|
"relatedSpdxElement": "SPDXRef-Package--opentelemetry-sdk-node-0.218.0",
|
|
6403
6403
|
"relationshipType": "DEPENDS_ON"
|
|
6404
6404
|
},
|
|
6405
6405
|
{
|
|
6406
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
6406
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.23",
|
|
6407
6407
|
"relatedSpdxElement": "SPDXRef-Package--opentelemetry-semantic-conventions-1.41.1",
|
|
6408
6408
|
"relationshipType": "DEPENDS_ON"
|
|
6409
6409
|
},
|
|
6410
6410
|
{
|
|
6411
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
6411
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.23",
|
|
6412
6412
|
"relatedSpdxElement": "SPDXRef-Package-archiver-8.0.0",
|
|
6413
6413
|
"relationshipType": "DEPENDS_ON"
|
|
6414
6414
|
},
|
|
6415
6415
|
{
|
|
6416
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
6416
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.23",
|
|
6417
6417
|
"relatedSpdxElement": "SPDXRef-Package-diff-9.0.0",
|
|
6418
6418
|
"relationshipType": "DEPENDS_ON"
|
|
6419
6419
|
},
|
|
6420
6420
|
{
|
|
6421
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
6421
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.23",
|
|
6422
6422
|
"relatedSpdxElement": "SPDXRef-Package-hono-4.12.25",
|
|
6423
6423
|
"relationshipType": "DEPENDS_ON"
|
|
6424
6424
|
},
|
|
6425
6425
|
{
|
|
6426
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
6426
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.23",
|
|
6427
6427
|
"relatedSpdxElement": "SPDXRef-Package-kysely-0.29.2",
|
|
6428
6428
|
"relationshipType": "DEPENDS_ON"
|
|
6429
6429
|
},
|
|
6430
6430
|
{
|
|
6431
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
6431
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.23",
|
|
6432
6432
|
"relatedSpdxElement": "SPDXRef-Package-oxc-transform-0.135.0",
|
|
6433
6433
|
"relationshipType": "DEPENDS_ON"
|
|
6434
6434
|
},
|
|
6435
6435
|
{
|
|
6436
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
6436
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.23",
|
|
6437
6437
|
"relatedSpdxElement": "SPDXRef-Package-pg-8.21.0",
|
|
6438
6438
|
"relationshipType": "DEPENDS_ON"
|
|
6439
6439
|
},
|
|
6440
6440
|
{
|
|
6441
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
6441
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.23",
|
|
6442
6442
|
"relatedSpdxElement": "SPDXRef-Package-picocolors-1.1.1",
|
|
6443
6443
|
"relationshipType": "DEPENDS_ON"
|
|
6444
6444
|
},
|
|
6445
6445
|
{
|
|
6446
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
6446
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.23",
|
|
6447
6447
|
"relatedSpdxElement": "SPDXRef-Package-winston-daily-rotate-file-5.0.0",
|
|
6448
6448
|
"relationshipType": "DEPENDS_ON"
|
|
6449
6449
|
},
|
|
6450
6450
|
{
|
|
6451
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
6451
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.23",
|
|
6452
6452
|
"relatedSpdxElement": "SPDXRef-Package-winston-3.19.0",
|
|
6453
6453
|
"relationshipType": "DEPENDS_ON"
|
|
6454
6454
|
},
|
|
6455
6455
|
{
|
|
6456
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
6456
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.23",
|
|
6457
6457
|
"relatedSpdxElement": "SPDXRef-Package-yaml-2.9.0",
|
|
6458
6458
|
"relationshipType": "DEPENDS_ON"
|
|
6459
6459
|
},
|
|
6460
6460
|
{
|
|
6461
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
6461
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.23",
|
|
6462
6462
|
"relatedSpdxElement": "SPDXRef-Package-zod-4.4.3",
|
|
6463
6463
|
"relationshipType": "DEPENDS_ON"
|
|
6464
6464
|
},
|
|
6465
6465
|
{
|
|
6466
|
-
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.
|
|
6466
|
+
"spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.23",
|
|
6467
6467
|
"relatedSpdxElement": "SPDXRef-Package-zx-8.8.5",
|
|
6468
6468
|
"relationshipType": "DEPENDS_ON"
|
|
6469
6469
|
},
|