@kici-dev/agent 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config.d.ts +38 -38
- package/dist/eval-runner.js +1866 -0
- package/dist/execution/dep-installer.d.ts +28 -7
- package/dist/execution/eval-context.d.ts +114 -0
- package/dist/execution/global-eval-types.d.ts +26 -0
- package/dist/execution/job-runner.d.ts +23 -75
- package/dist/execution/npm-registry-config.d.ts +6 -0
- package/dist/execution/rule-evaluator.d.ts +2 -1
- package/dist/execution/sandbox/bare-metal-sandbox.d.ts +6 -0
- package/dist/execution/sandbox/container-hardening.d.ts +8 -0
- package/dist/execution/sandbox/container-sandbox.d.ts +9 -0
- package/dist/execution/sandbox/eval-dispatch.d.ts +28 -0
- package/dist/execution/sandbox/eval-fork-runner.d.ts +43 -0
- package/dist/execution/sandbox/eval-runner.d.ts +21 -0
- package/dist/execution/sandbox/fork-runner.d.ts +23 -0
- package/dist/execution/sandbox/ipc-protocol.d.ts +82 -8
- package/dist/execution/sandbox/job-network.d.ts +91 -0
- package/dist/execution/sandbox/log-masker.d.ts +38 -0
- package/dist/execution/sandbox/types.d.ts +6 -0
- package/dist/execution/sandbox/workflow-runner.d.ts +1 -1
- package/dist/execution/source-packer.d.ts +4 -4
- package/dist/execution/source-restore.d.ts +28 -13
- package/dist/execution/workflow-loader.d.ts +16 -13
- package/dist/execution/yarnrc-berry-config.d.ts +6 -4
- package/dist/index.js +83 -40
- package/dist/provenance/statement-builder.d.ts +19 -8
- package/dist/server.js +1527 -1665
- package/dist/workflow-runner-bundle.js +1117 -185
- package/dist/workflow-runner.js +395 -149
- package/dist/ws/orchestrator-client.d.ts +4 -0
- package/package.json +6 -5
- package/sbom.spdx.json +66 -66
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CheckMode, CheckStepOutcome, LogStream } from '@kici-dev/engine';
|
|
1
|
+
import type { CheckMode, CheckStepOutcome, LogStream, ProvenanceContext } from '@kici-dev/engine';
|
|
2
2
|
import type { SandboxStepResult } from './types.js';
|
|
3
3
|
/**
|
|
4
4
|
* Structured clone auth. Wire-compatible with `gitAuthSchema` on the
|
|
@@ -500,6 +500,11 @@ export type AgentToRunnerMessage = ExecuteMessage | AbortMessage | EventEmitResp
|
|
|
500
500
|
* The runner uses this to clone, install deps, compile, and execute steps.
|
|
501
501
|
*/
|
|
502
502
|
export interface JobExecutionRequest {
|
|
503
|
+
/**
|
|
504
|
+
* Operator opt-out from `--ignore-scripts` on the `.kici/` dependency install
|
|
505
|
+
* (`KICI_ALLOW_INSTALL_SCRIPTS` on the agent). Absent means scripts stay off.
|
|
506
|
+
*/
|
|
507
|
+
allowInstallScripts?: boolean;
|
|
503
508
|
/**
|
|
504
509
|
* Run UUID. Threaded into the step context so the OIDC token relay can name
|
|
505
510
|
* the job/run a request is bound to. Correlation only — the orchestrator
|
|
@@ -550,6 +555,7 @@ export interface JobExecutionRequest {
|
|
|
550
555
|
credentialHelperPath?: string;
|
|
551
556
|
/** SHA-256 hash of the source tarball bytes for integrity verification. */
|
|
552
557
|
sourceTarHash?: string;
|
|
558
|
+
sourceTarDigest?: string;
|
|
553
559
|
/** URL to pre-built dependency tarball (skip install if present). */
|
|
554
560
|
depsUrl?: string;
|
|
555
561
|
/** SHA-256 hash of the dependency tarball for integrity verification. */
|
|
@@ -627,14 +633,16 @@ export interface JobExecutionRequest {
|
|
|
627
633
|
/** Git provider that originated the triggering event (e.g. 'github', 'forgejo'). */
|
|
628
634
|
provider?: string;
|
|
629
635
|
/**
|
|
630
|
-
*
|
|
631
|
-
*
|
|
632
|
-
*
|
|
633
|
-
*
|
|
634
|
-
*
|
|
635
|
-
*
|
|
636
|
+
* The orchestrator's own view of this build, from the job dispatch.
|
|
637
|
+
*
|
|
638
|
+
* Verification load-bearing. A deferred attestation's frozen statement is
|
|
639
|
+
* built from this so it is field-for-field what a live mint would have
|
|
640
|
+
* produced, and the orchestrator therefore cross-checks it against its own
|
|
641
|
+
* run row before storing it. Absent from an older orchestrator's dispatch, in
|
|
642
|
+
* which case the agent falls back to its local guess — a statement the
|
|
643
|
+
* capture check rejects, so the defer is dropped rather than stored unchecked.
|
|
636
644
|
*/
|
|
637
|
-
|
|
645
|
+
provenanceContext?: ProvenanceContext;
|
|
638
646
|
/** Whether to checkout the repo (default: true). */
|
|
639
647
|
checkout?: boolean;
|
|
640
648
|
/** Whether this job is part of a developer-initiated run triggered by `kici run`. */
|
|
@@ -739,5 +747,71 @@ export interface JobExecutionRequest {
|
|
|
739
747
|
declaredNeeds?: readonly unknown[];
|
|
740
748
|
};
|
|
741
749
|
}
|
|
750
|
+
/** Which evaluation the child should perform. */
|
|
751
|
+
export type EvalRequestKind = 'init' | 'dynamic-job' | 'build-verify' | 'global-eval';
|
|
752
|
+
/**
|
|
753
|
+
* One evaluation request. `config` is the dispatch's own `jobConfig` and
|
|
754
|
+
* `dispatch` the fields the evaluation reads, both passed through verbatim so
|
|
755
|
+
* the child builds the same contexts the agent used to build in-process.
|
|
756
|
+
*
|
|
757
|
+
* Carries no `secrets` and no `namespacedSecrets`: no evaluation surface
|
|
758
|
+
* consumes them, and adding them would put job secrets in the one process that
|
|
759
|
+
* runs customer module code.
|
|
760
|
+
*/
|
|
761
|
+
export interface EvalRequest {
|
|
762
|
+
kind: EvalRequestKind;
|
|
763
|
+
/** Absolute path of the already-materialized working directory. */
|
|
764
|
+
workDir: string;
|
|
765
|
+
/** The dispatch's `jobConfig`, verbatim. */
|
|
766
|
+
config: Record<string, unknown>;
|
|
767
|
+
/** The dispatch fields an evaluation reads (repo URL, ref, sha, auth, …). */
|
|
768
|
+
dispatch: Record<string, unknown>;
|
|
769
|
+
}
|
|
770
|
+
/** Instruct the eval child to run one evaluation. */
|
|
771
|
+
interface EvalExecuteMessage {
|
|
772
|
+
type: 'eval';
|
|
773
|
+
request: EvalRequest;
|
|
774
|
+
}
|
|
775
|
+
/** Response to an `eval.api.request` the child relayed. */
|
|
776
|
+
interface EvalApiResponseMessage {
|
|
777
|
+
type: 'eval.api.response';
|
|
778
|
+
id: string;
|
|
779
|
+
result?: unknown;
|
|
780
|
+
error?: string;
|
|
781
|
+
}
|
|
782
|
+
export type AgentToEvalMessage = EvalExecuteMessage | EvalApiResponseMessage;
|
|
783
|
+
/** The eval child is initialized and ready to receive a request. */
|
|
784
|
+
interface EvalReadyMessage {
|
|
785
|
+
type: 'ready';
|
|
786
|
+
}
|
|
787
|
+
/** One captured console / subprocess line, streamed onto the synthetic step-0 log. */
|
|
788
|
+
interface EvalLogLineMessage {
|
|
789
|
+
type: 'log.line';
|
|
790
|
+
line: string;
|
|
791
|
+
stream?: LogStream;
|
|
792
|
+
}
|
|
793
|
+
/**
|
|
794
|
+
* Relay for `ctx.kici`. The one privileged message on this union, and it is
|
|
795
|
+
* privilege preservation rather than expansion: a `DynamicJobFn` and a
|
|
796
|
+
* global-eval generator are already handed a `kici` API built on this exact
|
|
797
|
+
* transport, so withholding it would break a documented SDK surface.
|
|
798
|
+
*/
|
|
799
|
+
interface EvalApiRequestMessage {
|
|
800
|
+
type: 'eval.api.request';
|
|
801
|
+
id: string;
|
|
802
|
+
method: string;
|
|
803
|
+
params: Record<string, unknown>;
|
|
804
|
+
}
|
|
805
|
+
/** The evaluation finished. `result` is the kind's own serialized outcome. */
|
|
806
|
+
interface EvalResultMessage {
|
|
807
|
+
type: 'eval.result';
|
|
808
|
+
result: unknown;
|
|
809
|
+
}
|
|
810
|
+
/** The evaluation threw. */
|
|
811
|
+
interface EvalErrorMessage {
|
|
812
|
+
type: 'eval.error';
|
|
813
|
+
error: string;
|
|
814
|
+
}
|
|
815
|
+
export type EvalToAgentMessage = EvalReadyMessage | EvalLogLineMessage | EvalApiRequestMessage | EvalResultMessage | EvalErrorMessage;
|
|
742
816
|
export {};
|
|
743
817
|
//# sourceMappingURL=ipc-protocol.d.ts.map
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Egress filtering for nested job containers.
|
|
3
|
+
*
|
|
4
|
+
* A job container joins a dedicated `kici-jobs` bridge network, and the agent
|
|
5
|
+
* installs the same RFC1918 + cloud-metadata nftables drops the orchestrator's
|
|
6
|
+
* scaler installs for agent containers. Without them a job container keeps the
|
|
7
|
+
* runtime's default bridge, which reaches `169.254.169.254` and the host's whole
|
|
8
|
+
* private network — a step can take the instance role or sweep the customer's
|
|
9
|
+
* internal services.
|
|
10
|
+
*
|
|
11
|
+
* The rule builder is `@kici-dev/shared`'s, so the agent and the scaler apply
|
|
12
|
+
* one implementation rather than two copies that drift.
|
|
13
|
+
*
|
|
14
|
+
* `network: 'host'` (from `KICI_SANDBOX_NETWORK=host` or a per-job
|
|
15
|
+
* `sandbox: { network: 'host' }` grant) bypasses this by construction: asking
|
|
16
|
+
* for the host namespace is asking for the host's network.
|
|
17
|
+
*/
|
|
18
|
+
import type Docker from 'dockerode';
|
|
19
|
+
import { JOB_NETWORK_SUBNET, type NetworkPolicy } from '@kici-dev/shared/net';
|
|
20
|
+
/** Bridge network every filtered job container joins. */
|
|
21
|
+
export declare const JOB_NETWORK_NAME = "kici-jobs";
|
|
22
|
+
/**
|
|
23
|
+
* Subnet for {@link JOB_NETWORK_NAME}. Distinct from the scaler's agent network.
|
|
24
|
+
*
|
|
25
|
+
* Defined in `@kici-dev/shared/net` and re-exported here: the Firecracker host
|
|
26
|
+
* provisioner must recognise this subnet's rules to leave them alone, and it
|
|
27
|
+
* cannot import from the agent package.
|
|
28
|
+
*/
|
|
29
|
+
export { JOB_NETWORK_SUBNET };
|
|
30
|
+
/** Gateway for {@link JOB_NETWORK_NAME} — the one destination the rules allow. */
|
|
31
|
+
export declare const JOB_NETWORK_GATEWAY = "172.31.0.1";
|
|
32
|
+
/**
|
|
33
|
+
* Resolve what a job container may reach on the host.
|
|
34
|
+
*
|
|
35
|
+
* The default is DNS on the bridge gateway and nothing else. A job container
|
|
36
|
+
* talks to the agent through `docker exec` rather than over the network, and it
|
|
37
|
+
* holds none of the agent's credentials, so name resolution is the one host
|
|
38
|
+
* service it genuinely needs. That carve-out is not cosmetic: rootful podman
|
|
39
|
+
* runs its resolver on the gateway, a host address, so a container with no such
|
|
40
|
+
* rule cannot resolve any name at all. Docker answers inside the container's
|
|
41
|
+
* own netns and is unaffected either way.
|
|
42
|
+
*
|
|
43
|
+
* The set is derived HERE, from the agent's own configuration, and takes no
|
|
44
|
+
* argument that could widen it. A `NetworkPolicy` reaching
|
|
45
|
+
* {@link applyJobEgressRules} governs the FORWARD hook only — what the job
|
|
46
|
+
* reaches through the host — so its `hostAccess` is deliberately not consulted:
|
|
47
|
+
* a job that could name its own host reachability is the escape hatch this
|
|
48
|
+
* boundary exists to close, and a signature that cannot carry one is what makes
|
|
49
|
+
* that structural rather than a convention.
|
|
50
|
+
*/
|
|
51
|
+
export declare function resolveJobHostAccess(gateway?: string): string[];
|
|
52
|
+
/**
|
|
53
|
+
* Ensure the `kici-jobs` network exists, the nftables table is ready, and the
|
|
54
|
+
* subnet's default egress drops are installed.
|
|
55
|
+
*
|
|
56
|
+
* The drops land here — before any job container is created — and are keyed on
|
|
57
|
+
* the subnet rather than on a container address, so a customer image's own
|
|
58
|
+
* `ENTRYPOINT` never runs unfiltered.
|
|
59
|
+
*
|
|
60
|
+
* Returns whether egress filtering is actually in force. A host without `nft`
|
|
61
|
+
* or without `NET_ADMIN` — a rootless agent, most commonly — warns loudly and
|
|
62
|
+
* degrades to the network with no rules rather than refusing to run any job:
|
|
63
|
+
* `kici-admin agent install` is a compat-protected surface, and hard-requiring
|
|
64
|
+
* NET_ADMIN would break every existing rootless install with no additive path.
|
|
65
|
+
* The same trade-off the scaler already made for agent containers.
|
|
66
|
+
*/
|
|
67
|
+
export declare function ensureJobNetwork(docker: Docker): Promise<boolean>;
|
|
68
|
+
/**
|
|
69
|
+
* Apply the per-container egress rules once the container has an IP.
|
|
70
|
+
*
|
|
71
|
+
* This is the per-job layer, not the control: the subnet drop set
|
|
72
|
+
* {@link ensureJobNetwork} installs is already in the chain and already covers
|
|
73
|
+
* this container. What a per-container rule set adds is a place to key a future
|
|
74
|
+
* per-job policy — an allowlist or `denyAll` — on one address rather than on
|
|
75
|
+
* the whole bridge.
|
|
76
|
+
*
|
|
77
|
+
* Returns the container IP the rules are keyed on, so teardown can remove
|
|
78
|
+
* exactly those rules; `undefined` when no IP could be read, which is logged
|
|
79
|
+
* rather than thrown — a job whose rules could not be keyed still runs behind
|
|
80
|
+
* the subnet drops, and the operator sees why.
|
|
81
|
+
*/
|
|
82
|
+
export declare function applyJobEgressRules(docker: Docker, containerId: string, policy: NetworkPolicy | undefined): Promise<string | undefined>;
|
|
83
|
+
/**
|
|
84
|
+
* Remove the per-container rules at teardown.
|
|
85
|
+
*
|
|
86
|
+
* Never throws: a failed cleanup must not turn a finished job into a failed
|
|
87
|
+
* one. A leaked rule set is keyed on an IP the network will reuse, so it is
|
|
88
|
+
* reported at `warn` for the operator rather than swallowed.
|
|
89
|
+
*/
|
|
90
|
+
export declare function removeJobEgressRules(containerIp: string | undefined): Promise<void>;
|
|
91
|
+
//# sourceMappingURL=job-network.d.ts.map
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* Performance: Builds a single combined regex from all secret values, so each
|
|
8
8
|
* log line is scanned in a single pass (not O(secrets * lines)).
|
|
9
9
|
*/
|
|
10
|
+
import type { JobExecutionRequest, RunnerToAgentMessage } from './ipc-protocol.js';
|
|
10
11
|
/**
|
|
11
12
|
* Masks secret values in log lines.
|
|
12
13
|
*
|
|
@@ -29,6 +30,21 @@ export declare class LogMasker {
|
|
|
29
30
|
* Authorization: Basic headers, base64-encoded config values).
|
|
30
31
|
* Values are sorted by length descending so longer values are matched first
|
|
31
32
|
* (prevents partial masking when one secret is a substring of another).
|
|
33
|
+
*
|
|
34
|
+
* Multi-line values additionally register each of their individual lines.
|
|
35
|
+
* Log output is split into lines before it reaches the masker, so a value
|
|
36
|
+
* containing a newline can never match as a whole — a PEM private key or a
|
|
37
|
+
* kubeconfig would otherwise stream in clear text. Two consequences of the
|
|
38
|
+
* per-line registration are deliberate:
|
|
39
|
+
*
|
|
40
|
+
* - `MIN_MASK_LENGTH` is 3, so short structural lines of a structured secret
|
|
41
|
+
* are registered too. A `---` YAML separator or a bare `{` from a
|
|
42
|
+
* service-account JSON is masked wherever it appears in that job's logs.
|
|
43
|
+
* - PEM header and footer lines (`-----BEGIN OPENSSH PRIVATE KEY-----`) are
|
|
44
|
+
* not secret on their own and are masked as a side effect.
|
|
45
|
+
*
|
|
46
|
+
* Both are strictly safer than leaking the body, and no heuristic separates a
|
|
47
|
+
* structural line from a body line without risking the reverse mistake.
|
|
32
48
|
*/
|
|
33
49
|
registerSecrets(secrets: Record<string, string>): void;
|
|
34
50
|
/**
|
|
@@ -42,4 +58,26 @@ export declare class LogMasker {
|
|
|
42
58
|
*/
|
|
43
59
|
hasSecrets(): boolean;
|
|
44
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* Create a LogMasker initialized with all secret values from the request.
|
|
63
|
+
*
|
|
64
|
+
* Collects values from both flat secrets and all namespaced context secrets,
|
|
65
|
+
* deduplicating before registration.
|
|
66
|
+
*
|
|
67
|
+
* Both the runner child and the agent-side fork runner build a masker from the
|
|
68
|
+
* same request, so the crash tail the agent assembles from the child's stderr is
|
|
69
|
+
* masked with the same value set the child used for its own log lines.
|
|
70
|
+
*/
|
|
71
|
+
export declare function createSecretMasker(request: JobExecutionRequest): LogMasker;
|
|
72
|
+
/**
|
|
73
|
+
* Mask every operator-visible text field of an outbound runner message.
|
|
74
|
+
*
|
|
75
|
+
* Each message type carrying free text is named here, so a new text-bearing
|
|
76
|
+
* message type is a visible omission rather than a silent leak. `step.complete`
|
|
77
|
+
* error text and the `job.complete` failure reason are persisted on the step and
|
|
78
|
+
* run rows the dashboard renders, so they need the same masking `log.line` gets.
|
|
79
|
+
*
|
|
80
|
+
* Returns the message unchanged when no secrets are registered.
|
|
81
|
+
*/
|
|
82
|
+
export declare function maskMessageText(msg: RunnerToAgentMessage, masker: LogMasker): RunnerToAgentMessage;
|
|
45
83
|
//# sourceMappingURL=log-masker.d.ts.map
|
|
@@ -155,6 +155,12 @@ export interface JobExecutionOptions {
|
|
|
155
155
|
* see the dual-mode container work.
|
|
156
156
|
*/
|
|
157
157
|
credentialHelperPath?: string;
|
|
158
|
+
/**
|
|
159
|
+
* Operator opt-out from `--ignore-scripts` on the `.kici/` dependency install
|
|
160
|
+
* (`KICI_ALLOW_INSTALL_SCRIPTS`). Sourced from agent config only, so a
|
|
161
|
+
* dispatch payload or a workflow cannot re-enable lifecycle scripts.
|
|
162
|
+
*/
|
|
163
|
+
allowInstallScripts?: boolean;
|
|
158
164
|
/**
|
|
159
165
|
* Callback for relaying a provenance bundle upload request from the sandbox to
|
|
160
166
|
* the orchestrator. The sandbox runner sends `provenance.request` IPC; the
|
|
@@ -74,7 +74,7 @@ export declare function buildStepNeedsContext(declaredNeeds: readonly unknown[]
|
|
|
74
74
|
* step$.log would only set it on the function object and NOT propagate to the
|
|
75
75
|
* AsyncLocalStorage store that zx uses for ProcessPromise snapshots.
|
|
76
76
|
*/
|
|
77
|
-
export declare function buildSandboxShell(cwd: string, stepIndex: number, maskedSendFn: (msg: RunnerToAgentMessage) => void): typeof $;
|
|
77
|
+
export declare function buildSandboxShell(cwd: string, stepIndex: number, maskedSendFn: (msg: RunnerToAgentMessage) => void, signal?: AbortSignal): typeof $;
|
|
78
78
|
/**
|
|
79
79
|
* Resolve the on-the-wire event name for `ctx.emit`. Accepts either an ad-hoc
|
|
80
80
|
* event-name string or a `defineEvent()` definition object (passed by the typed
|
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
* into a deterministic gzip tarball. The tarball bytes are hashed for
|
|
7
7
|
* integrity verification on the execution-job side.
|
|
8
8
|
*
|
|
9
|
-
* The
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
9
|
+
* The returned hash is the tarball's OWN digest. The orchestrator stores the
|
|
10
|
+
* object under it and the restoring agent verifies the downloaded bytes against
|
|
11
|
+
* it, the same contract the dependency tarball has always had; a separate
|
|
12
|
+
* pointer resolves the workflow `contentHash` to it.
|
|
13
13
|
*/
|
|
14
14
|
export declare function packKiciSource(workDir: string): Promise<{
|
|
15
15
|
tarball: Buffer;
|
|
@@ -2,22 +2,37 @@
|
|
|
2
2
|
* `.kici/` source tarball restoration for execution agents.
|
|
3
3
|
*
|
|
4
4
|
* Downloads a pre-built `.kici/` source tarball from the orchestrator's cache
|
|
5
|
-
* and
|
|
5
|
+
* and installs it at `workDir/.kici` so the workflow entry point becomes
|
|
6
6
|
* importable. Mirrors the shape of `dep-restore.ts` but without the streaming
|
|
7
7
|
* optimization — source tarballs are tiny (kilobytes, not the hundreds of
|
|
8
8
|
* megabytes a `node_modules/` tarball carries).
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* `
|
|
16
|
-
* the
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
10
|
+
* Two properties this path is responsible for, both of which it previously
|
|
11
|
+
* lacked:
|
|
12
|
+
*
|
|
13
|
+
* **Verification.** `dispatch.sourceTarDigest` is the SHA-256 of the tarball's
|
|
14
|
+
* own bytes, so the download is checked before anything is extracted — the same
|
|
15
|
+
* contract `restoreDeps` has always had via `depsHash`. The older
|
|
16
|
+
* `dispatch.sourceTarHash` field carries the workflow `contentHash` instead, so
|
|
17
|
+
* it never could serve this purpose; it stays on the wire for older peers and
|
|
18
|
+
* is deliberately not used as a verification input here. When no digest is
|
|
19
|
+
* dispatched (an older orchestrator, or a source that did not come from the
|
|
20
|
+
* content-addressed cache) the restore proceeds unverified rather than failing,
|
|
21
|
+
* so a mixed-version rollout still runs.
|
|
22
|
+
*
|
|
23
|
+
* **Replacement, not overlay.** Extraction lands in a scratch directory and the
|
|
24
|
+
* result REPLACES `workDir/.kici` wholesale, save for `node_modules/` — the one
|
|
25
|
+
* directory the tarball deliberately omits, which the deps restore has already
|
|
26
|
+
* written by the time this runs. Extracting over the existing tree left any file
|
|
27
|
+
* the tarball no longer carries in place, so a helper the author deleted
|
|
28
|
+
* survived every warm-cache run and kept being imported.
|
|
29
|
+
*/
|
|
30
|
+
/**
|
|
31
|
+
* Download, verify, and install the `.kici/` source tree.
|
|
32
|
+
*
|
|
33
|
+
* @param workDir - Root of the cloned repository; `.kici` is replaced under it
|
|
34
|
+
* @param sourceTarUrl - `http://`, `https://`, or `file://` URL to the tarball
|
|
35
|
+
* @param sourceTarDigest - Expected SHA-256 of the tarball bytes, when known
|
|
21
36
|
*/
|
|
22
|
-
export declare function restoreSource(workDir: string, sourceTarUrl: string): Promise<void>;
|
|
37
|
+
export declare function restoreSource(workDir: string, sourceTarUrl: string, sourceTarDigest?: string): Promise<void>;
|
|
23
38
|
//# sourceMappingURL=source-restore.d.ts.map
|
|
@@ -34,20 +34,21 @@ export interface SdkOutputSetters {
|
|
|
34
34
|
* ESM modules by resolved URL, so importing that path yields the workflow's live
|
|
35
35
|
* singleton, not a fresh copy.
|
|
36
36
|
*
|
|
37
|
-
*
|
|
37
|
+
* Both specifiers resolve to the same module-global maps — `internal.ts` and the
|
|
38
|
+
* root barrel re-export the same `outputs.js` bindings — so the fallback below
|
|
39
|
+
* changes which entry is imported, never which singleton is mutated.
|
|
40
|
+
*
|
|
41
|
+
* Falls back to the agent's bundled setters when neither resolves (mirrors
|
|
38
42
|
* `resolveSdkSetters` in the compiler's test runner).
|
|
39
43
|
*/
|
|
40
44
|
export declare function resolveWorkflowSdkSetters(workflowFilePath: string): Promise<SdkOutputSetters>;
|
|
41
45
|
/**
|
|
42
|
-
* Compile schema version
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
* loader hook. Bumped 4 → 5 when the hash input started normalizing line
|
|
47
|
-
* endings (CRLF → LF) so a Windows agent's checked-out CRLF source matches a
|
|
48
|
-
* Linux compiler's LF source.
|
|
46
|
+
* Compile schema version, re-exported from its single definition in
|
|
47
|
+
* `@kici-dev/core/kici-source-digest`. The compiler mixes the same constant
|
|
48
|
+
* into every `contentHash` it writes, so a second copy here is exactly how a
|
|
49
|
+
* producer and its verifier drift apart.
|
|
49
50
|
*/
|
|
50
|
-
export
|
|
51
|
+
export { COMPILE_SCHEMA_VERSION } from '@kici-dev/core/kici-source-digest';
|
|
51
52
|
export declare function ensureLoaderHookRegistered(): void;
|
|
52
53
|
/**
|
|
53
54
|
* Load a workflow module by dynamic-importing its source file.
|
|
@@ -57,10 +58,12 @@ export declare function ensureLoaderHookRegistered(): void;
|
|
|
57
58
|
* `node_modules/` the same way any `tsx`-style runner would — so host-repo
|
|
58
59
|
* helpers and `@kici-dev/sdk` Just Work.
|
|
59
60
|
*
|
|
60
|
-
* When `expectedContentHash` is provided, verifies the
|
|
61
|
-
* the hash in the lock file.
|
|
62
|
-
*
|
|
63
|
-
*
|
|
61
|
+
* When `expectedContentHash` is provided, verifies the extracted `.kici/` tree
|
|
62
|
+
* matches the hash in the lock file. It re-hashes the whole tree, not the entry
|
|
63
|
+
* file alone, so an edit to an imported helper is caught — that was the gap
|
|
64
|
+
* that let a warm cache restore a stale tarball and run the OLD helper green.
|
|
65
|
+
* Drift produces a descriptive error that surfaces the baked agent SDK
|
|
66
|
+
* fingerprint (useful when debugging "is the agent running a stale build?").
|
|
64
67
|
*/
|
|
65
68
|
export declare function loadWorkflowSource(workDir: string, sourceFile: string, expectedContentHash?: string, resolvedHashFiles?: string[]): Promise<{
|
|
66
69
|
module: Record<string, unknown>;
|
|
@@ -10,10 +10,12 @@
|
|
|
10
10
|
*
|
|
11
11
|
* `nodeLinker: node-modules` makes berry lay down a real `node_modules` tree
|
|
12
12
|
* (no PnP `.pnp.cjs`), so the agent's packer / restore / sibling-walk /
|
|
13
|
-
* workflow-loader work unchanged. `enableScripts: false`
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* `--ignore-scripts`.
|
|
13
|
+
* workflow-loader work unchanged. `enableScripts: false` keeps dependency
|
|
14
|
+
* lifecycle scripts from running at all — for every install, not only one
|
|
15
|
+
* against a private registry — the same security model as npm/pnpm/classic
|
|
16
|
+
* `--ignore-scripts`. An operator opts back in with
|
|
17
|
+
* `KICI_ALLOW_INSTALL_SCRIPTS=true`, which arrives here as
|
|
18
|
+
* `ignoreScripts: false`.
|
|
17
19
|
*
|
|
18
20
|
* Reuses the same `ApplyNpmRegistryConfigArgs` / `ApplyNpmRegistryConfigResult`
|
|
19
21
|
* shapes as the npm overlay so `dep-installer` can pick either by flavor.
|